diff --git a/cmd/cloud/deploy.go b/cmd/cloud/deploy.go index 3459684e3..87d50b84a 100644 --- a/cmd/cloud/deploy.go +++ b/cmd/cloud/deploy.go @@ -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) @@ -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) diff --git a/cmd/cloud/deploy_test.go b/cmd/cloud/deploy_test.go index 20088468f..6476b6361 100644 --- a/cmd/cloud/deploy_test.go +++ b/cmd/cloud/deploy_test.go @@ -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 { @@ -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 } @@ -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") - }) - } -}