• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

astronomer / astro-cli / 6d8926d3-3f19-46b0-96ee-aa659994967c

09 Oct 2025 08:49AM UTC coverage: 38.492% (+0.05%) from 38.44%
6d8926d3-3f19-46b0-96ee-aa659994967c

Pull #1954

circleci

feluelle
Add client deploy support for RE projects

- add `--client` flag to deploy command
- add `--platform` flag to deploy command
Pull Request #1954: Add client deploy support for RE projects

79 of 90 new or added lines in 3 files covered. (87.78%)

54 existing lines in 5 files now uncovered.

24107 of 62628 relevant lines covered (38.49%)

10.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.02
/cmd/software/deploy.go
1
package software
2

3
import (
4
        "errors"
5
        "fmt"
6

7
        "github.com/astronomer/astro-cli/cmd/utils"
8
        "github.com/astronomer/astro-cli/config"
9
        "github.com/astronomer/astro-cli/context"
10
        "github.com/astronomer/astro-cli/houston"
11
        "github.com/astronomer/astro-cli/pkg/git"
12
        "github.com/astronomer/astro-cli/software/deploy"
13

14
        "github.com/spf13/cobra"
15
)
16

17
var (
18
        forceDeploy      bool
19
        forcePrompt      bool
20
        saveDeployConfig bool
21

22
        ignoreCacheDeploy = false
23

24
        EnsureProjectDir                   = utils.EnsureProjectDir
25
        DeployAirflowImage                 = deploy.Airflow
26
        DagsOnlyDeploy                     = deploy.DagsOnlyDeploy
27
        UpdateDeploymentImage              = deploy.UpdateDeploymentImage
28
        isDagOnlyDeploy                    bool
29
        description                        string
30
        isImageOnlyDeploy                  bool
31
        imageName                          string
32
        runtimeVersionForImageName         string
33
        imagePresentOnRemote               bool
34
        ErrBothDagsOnlyAndImageOnlySet     = errors.New("cannot use both --dags and --image together. Run 'astro deploy' to update both your image and dags")
35
        ErrImageNameNotPassedForRemoteFlag = errors.New("--image-name is mandatory when --remote flag is passed")
36
)
37

38
var deployExample = `
39
Deployment you would like to deploy to Airflow cluster:
40

41
$ astro deploy <deployment-id>
42

43
Menu will be presented if you do not specify a deployment name:
44

45
$ astro deploy
46
`
47

48
const (
49
        registryUncommittedChanges = "Project directory has uncommmited changes, use `astro deploy <deployment-id> -f` to force deploy."
50
)
51

52
func NewDeployCmd() *cobra.Command {
21✔
53
        cmd := &cobra.Command{
21✔
54
                Use:     "deploy [DEPLOYMENT ID]",
21✔
55
                Short:   "Deploy an Airflow project",
21✔
56
                Long:    "Deploy an Airflow project to an Astronomer Cluster",
21✔
57
                Args:    cobra.MaximumNArgs(1),
21✔
58
                PreRunE: EnsureProjectDir,
21✔
59
                RunE:    deployAirflow,
21✔
60
                Example: deployExample,
21✔
61
        }
21✔
62
        cmd.Flags().BoolVarP(&forceDeploy, "force", "f", false, "Force deploy if uncommitted changes")
21✔
63
        cmd.Flags().BoolVarP(&forcePrompt, "prompt", "p", false, "Force prompt to choose target deployment")
21✔
64
        cmd.Flags().BoolVarP(&saveDeployConfig, "save", "s", false, "Save deployment in config for future deploys")
21✔
65
        cmd.Flags().BoolVarP(&ignoreCacheDeploy, "no-cache", "", false, "Do not use cache when building container image")
21✔
66
        cmd.Flags().StringVar(&workspaceID, "workspace-id", "", "workspace assigned to deployment")
21✔
67
        cmd.Flags().StringVar(&description, "description", "", "Improve traceability by attaching a description to a code deploy. If you don't provide a description, the system automatically assigns a default description based on the deploy type.")
21✔
68
        cmd.Flags().BoolVarP(&isImageOnlyDeploy, "image", "", false, "Push only an image to your Astro Deployment. This only works for Dag-only, Git-sync-based and NFS-based deployments.")
21✔
69
        cmd.Flags().StringVarP(&imageName, "image-name", "i", "", "Name of the custom image(should be present locally unless --remote is specified) to deploy")
21✔
70
        cmd.Flags().StringVar(&runtimeVersionForImageName, "runtime-version", "", "Runtime version of the image to deploy. Example - 12.1.1. Mandatory if --image-name --remote is provided")
21✔
71
        cmd.Flags().BoolVarP(&imagePresentOnRemote, "remote", "", false, "Custom image which is present on the remote registry. Can only be used with --image-name flag")
21✔
72

21✔
73
        if !context.IsCloudContext() && houston.VerifyVersionMatch(houstonVersion, houston.VersionRestrictions{GTE: "0.34.0"}) {
38✔
74
                cmd.Flags().BoolVarP(&isDagOnlyDeploy, "dags", "d", false, "Push only DAGs to your Deployment")
17✔
75
        }
17✔
76
        return cmd
21✔
77
}
78

79
func deployAirflow(cmd *cobra.Command, args []string) error {
16✔
80
        ws, err := coalesceWorkspace()
16✔
81
        if err != nil {
16✔
82
                return fmt.Errorf("failed to find a valid workspace: %w", err)
×
83
        }
×
84

85
        deploymentID := ""
16✔
86

16✔
87
        // Get release name from args, if passed
16✔
88
        if len(args) > 0 {
28✔
89
                deploymentID = args[0]
12✔
90
        }
12✔
91

92
        // Save release name in config if specified
93
        if deploymentID != "" && saveDeployConfig {
17✔
94
                err = config.CFG.ProjectDeployment.SetProjectString(deploymentID)
1✔
95
                if err != nil {
1✔
96
                        return err
×
97
                }
×
98
        }
99

100
        if git.HasUncommittedChanges("") && !forceDeploy {
16✔
101
                fmt.Println(registryUncommittedChanges)
×
102
                return nil
×
103
        }
×
104

105
        // Silence Usage as we have now validated command input
106
        cmd.SilenceUsage = true
16✔
107

16✔
108
        var byoRegistryEnabled bool
16✔
109
        var byoRegistryDomain string
16✔
110
        if description == "" {
31✔
111
                description = utils.GetDefaultDeployDescription(isDagOnlyDeploy)
15✔
112
        }
15✔
113

114
        if isImageOnlyDeploy && isDagOnlyDeploy {
17✔
115
                return ErrBothDagsOnlyAndImageOnlySet
1✔
116
        }
1✔
117

118
        if isDagOnlyDeploy {
16✔
119
                return DagsOnlyDeploy(houstonClient, ws, deploymentID, config.WorkingPath, nil, true, description)
1✔
120
        }
1✔
121

122
        if imagePresentOnRemote {
17✔
123
                if imageName == "" {
4✔
124
                        return ErrImageNameNotPassedForRemoteFlag
1✔
125
                }
1✔
126
                deploymentID, err = UpdateDeploymentImage(houstonClient, deploymentID, ws, runtimeVersionForImageName, imageName)
2✔
127
                if err != nil {
3✔
128
                        return err
1✔
129
                }
1✔
130
        } else {
11✔
131
                // Since we prompt the user to enter the deploymentID in come cases for DeployAirflowImage, reusing the same  deploymentID for DagsOnlyDeploy
11✔
132
                deploymentID, err = DeployAirflowImage(houstonClient, config.WorkingPath, deploymentID, ws, byoRegistryDomain, ignoreCacheDeploy, byoRegistryEnabled, forcePrompt, description, isImageOnlyDeploy, imageName)
11✔
133
                if err != nil {
13✔
134
                        return err
2✔
135
                }
2✔
136
        }
137

138
        // Don't deploy dags even for dags-only deployments --image is passed
139
        if isImageOnlyDeploy {
11✔
140
                fmt.Println("Dags in the project will not be deployed since --image is passed.")
1✔
141
                return nil
1✔
142
        }
1✔
143

144
        err = DagsOnlyDeploy(houstonClient, ws, deploymentID, config.WorkingPath, nil, true, description)
9✔
145
        // Don't throw the error if dag-deploy itself is disabled
9✔
146
        if errors.Is(err, deploy.ErrDagOnlyDeployDisabledInConfig) || errors.Is(err, deploy.ErrDagOnlyDeployNotEnabledForDeployment) {
9✔
UNCOV
147
                return nil
×
UNCOV
148
        }
×
149
        return err
9✔
150
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc