Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions cmd/cloud/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ func NewDeployCmd() *cobra.Command {
Long: "Deploy your project to a Deployment on Astro. This command bundles your project files into a Docker image and pushes that Docker image to Astronomer. In Deployments with Remote Execution enabled, this only updates the Orchestration Plane components (the API Server and Scheduler). For all other components, use `astro remote deploy` instead. It does not include any metadata associated with your local Airflow environment.",
Args: cobra.MaximumNArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
if cmd.Flags().Changed(imageNameFlag) {
// --image with --image-name pushes a prebuilt image only; no local
// project files (DAGs, Dockerfile) are needed, so skip the check.
if image && cmd.Flags().Changed(imageNameFlag) {
return nil
}
return EnsureProjectDir(cmd, args)
Expand Down Expand Up @@ -133,15 +135,6 @@ func deploy(cmd *cobra.Command, args []string) error {
return errors.New("cannot use both --dags and --image together. Run 'astro deploy' to update both your image and dags")
}

if cmd.Flags().Changed(imageNameFlag) {
for _, f := range []string{"dags", "dags-path", "no-dags-base-dir", "pytest", "parse", "build-secrets"} {
if cmd.Flags().Changed(f) {
return fmt.Errorf("cannot use --%s with --image-name; --image-name implies an image-only deploy", f)
}
}
image = true
}

// Save deploymentId in config if specified
if deploymentID != "" && saveDeployConfig {
err := config.CFG.ProjectDeployment.SetProjectString(deploymentID)
Expand Down
46 changes: 12 additions & 34 deletions cmd/cloud/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestDeployImage(t *testing.T) {
assert.NoError(t, err)
}

func TestDeploySkipsEnsureProjectDirWhenImageNameSet(t *testing.T) {
func TestDeployProjectDirCheckWithImageName(t *testing.T) {
testUtil.InitTestConfig(testUtil.LocalPlatform)

EnsureProjectDir = func(cmd *cobra.Command, args []string) error {
Expand All @@ -82,16 +82,22 @@ func TestDeploySkipsEnsureProjectDirWhenImageNameSet(t *testing.T) {
return nil
}

// With --image-name, the project-dir check should be skipped.
err := execDeployCmd("-f", "test-deployment-id", "--image-name", "custom-image:latest")
// --image --image-name is an explicit image-only push of a prebuilt image;
// no local project files are needed, so the check is skipped.
err := execDeployCmd("-f", "test-deployment-id", "--image", "--image-name", "custom-image:latest")
assert.NoError(t, err)

// Without --image-name, the project-dir check should still run and propagate.
// --image-name alone keeps the default image-and-dags behavior, which
// reads DAGs from the working directory and so still requires a project.
err = execDeployCmd("-f", "test-deployment-id", "--image-name", "custom-image:latest")
assert.ErrorIs(t, err, assert.AnError)

// No --image-name: check still runs and propagates.
err = execDeployCmd("-f", "test-deployment-id")
assert.ErrorIs(t, err, assert.AnError)
}

func TestDeployImageNameForcesImageOnly(t *testing.T) {
func TestDeployImageNameDoesNotForceImageOnly(t *testing.T) {
testUtil.InitTestConfig(testUtil.LocalPlatform)

EnsureProjectDir = func(cmd *cobra.Command, args []string) error { return nil }
Expand All @@ -104,34 +110,6 @@ func TestDeployImageNameForcesImageOnly(t *testing.T) {

err := execDeployCmd("-f", "test-deployment-id", "--image-name", "custom-image:latest")
assert.NoError(t, err)
assert.True(t, captured.Image, "--image-name should force image-only deploy")
assert.False(t, captured.Image, "--image-name alone must not force image-only; default deploy type is image-and-dags")
assert.Equal(t, "custom-image:latest", captured.ImageName)
}

func TestDeployImageNameRejectsIncompatibleFlags(t *testing.T) {
testUtil.InitTestConfig(testUtil.LocalPlatform)

EnsureProjectDir = func(cmd *cobra.Command, args []string) error { return nil }
DeployImage = func(deployInput cloud.InputDeploy, platformCoreClient astroplatformcore.CoreClient, coreClient astrocore.CoreClient) error {
return nil
}

cases := []struct {
name string
args []string
}{
{"dags", []string{"-f", "test-deployment-id", "--image-name", "img:1", "--dags"}},
{"dags-path", []string{"-f", "test-deployment-id", "--image-name", "img:1", "--dags-path", "./dags"}},
{"no-dags-base-dir", []string{"-f", "test-deployment-id", "--image-name", "img:1", "--no-dags-base-dir"}},
{"pytest", []string{"-f", "test-deployment-id", "--image-name", "img:1", "--pytest"}},
{"parse", []string{"-f", "test-deployment-id", "--image-name", "img:1", "--parse"}},
{"build-secrets", []string{"-f", "test-deployment-id", "--image-name", "img:1", "--build-secrets", "id=mysecret,src=secrets.txt"}},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := execDeployCmd(tc.args...)
assert.Error(t, err)
assert.Contains(t, err.Error(), "--image-name")
})
}
}