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

astronomer / astro-cli / 3594e26d-8682-4297-8627-84e8d776b975

27 Oct 2025 08:29PM UTC coverage: 38.52% (+0.01%) from 38.51%
3594e26d-8682-4297-8627-84e8d776b975

Pull #1968

circleci

ronidelacruz-astro
Merge branch 'fix-verbosity-issue' of github.com:astronomer/astro-cli into fix-verbosity-issue
Pull Request #1968: Verbosity flag provides no extra information (#1501)

15 of 20 new or added lines in 3 files covered. (75.0%)

46 existing lines in 2 files now uncovered.

24148 of 62689 relevant lines covered (38.52%)

10.75 hits per line

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

92.86
/software/workspace/workspace.go
1
package workspace
2

3
import (
4
        "errors"
5
        "fmt"
6
        "io"
7
        "strconv"
8

9
        "github.com/astronomer/astro-cli/config"
10
        "github.com/astronomer/astro-cli/houston"
11
        "github.com/astronomer/astro-cli/pkg/input"
12
        "github.com/astronomer/astro-cli/pkg/logger"
13
        "github.com/astronomer/astro-cli/pkg/printutil"
14
)
15

16
type workspacePaginationOptions struct {
17
        pageSize      int
18
        pageNumber    int
19
        quit          bool
20
        userSelection int
21
}
22

23
type workspaceSelection struct {
24
        id   string
25
        quit bool
26
        err  error
27
}
28

29
const (
30
        defaultWorkspacePaginationOptions      = "f. first p. previous n. next q. quit\n> "
31
        workspacePaginationWithoutNextOptions  = "f. first p. previous q. quit\n> "
32
        workspacePaginationWithNextQuitOptions = "n. next q. quit\n> "
33
        workspacePaginationWithQuitOptions     = "q. quit\n> "
34
)
35

36
var errInvalidWorkspaceKey = errors.New("invalid workspace selection")
37

38
var errWorkspaceContextNotSet = errors.New("current workspace context not set, you can switch to a workspace with \n\tastro workspace switch WORKSPACEID")
39

40
func newTableOut() *printutil.Table {
13✔
41
        return &printutil.Table{
13✔
42
                Padding:        []int{44, 50},
13✔
43
                DynamicPadding: true,
13✔
44
                Header:         []string{"NAME", "ID"},
13✔
45
                ColorRowCode:   [2]string{"\033[1;32m", "\033[0m"},
13✔
46
        }
13✔
47
}
13✔
48

49
// Create a workspace
50
func Create(label, desc string, client houston.ClientInterface, out io.Writer) error {
2✔
51
        w, err := houston.Call(client.CreateWorkspace)(houston.CreateWorkspaceRequest{Label: label, Description: desc})
2✔
52
        if err != nil {
3✔
53
                return err
1✔
54
        }
1✔
55

56
        tab := newTableOut()
1✔
57
        tab.AddRow([]string{w.Label, w.ID}, false)
1✔
58
        tab.SuccessMsg = "\n Successfully created workspace"
1✔
59
        tab.Print(out)
1✔
60

1✔
61
        return nil
1✔
62
}
63

64
// List all workspaces
65
func List(client houston.ClientInterface, out io.Writer) error {
3✔
66
        ws, err := houston.Call(client.ListWorkspaces)(nil)
3✔
67
        if err != nil {
4✔
68
                logger.Debugf("Failed to fetch workspaces: %v", err)
1✔
69
                return err
1✔
70
        }
1✔
71
        logger.Debugf("Successfully retrieved %d workspace(s)", len(ws))
2✔
72

2✔
73
        c, err := config.GetCurrentContext()
2✔
74
        if err != nil {
2✔
NEW
75
                logger.Debugf("Failed to get current context: %v", err)
×
76
                return err
×
77
        }
×
78
        logger.Debugf("Current context - Workspace: %s", c.Workspace)
2✔
79

2✔
80
        tab := newTableOut()
2✔
81
        for i := range ws {
8✔
82
                w := ws[i]
6✔
83
                name := w.Label
6✔
84
                workspace := w.ID
6✔
85

6✔
86
                var color bool
6✔
87

6✔
88
                if c.Workspace == w.ID {
7✔
89
                        color = true
1✔
90
                        logger.Debugf("Workspace '%s' (ID: %s) is the current workspace", name, workspace)
1✔
91
                } else {
6✔
92
                        color = false
5✔
93
                }
5✔
94
                tab.AddRow([]string{name, workspace}, color)
6✔
95
        }
96

97
        tab.Print(out)
2✔
98

2✔
99
        return nil
2✔
100
}
101

102
// Delete a workspace by id
103
func Delete(id string, client houston.ClientInterface, out io.Writer) error {
2✔
104
        _, err := houston.Call(client.DeleteWorkspace)(id)
2✔
105
        if err != nil {
3✔
106
                return err
1✔
107
        }
1✔
108

109
        // TODO remove tab print until houston properly returns attrs on delete
110
        // tab.AddRow([]string{w.Label, w.Id}, false)
111
        // tab.SuccessMsg = "\n Successfully deleted workspace"
112
        // tab.Print()
113
        fmt.Fprintln(out, "\n Successfully deleted workspace")
1✔
114

1✔
115
        return nil
1✔
116
}
117

118
// GetCurrentWorkspace gets the current workspace set in context config
119
// Returns a string representing the current workspace and an error if it doesn't exist
120
func GetCurrentWorkspace() (string, error) {
3✔
121
        c, err := config.GetCurrentContext()
3✔
122
        if err != nil {
4✔
123
                return "", err
1✔
124
        }
1✔
125

126
        if c.Workspace == "" {
3✔
127
                return "", errWorkspaceContextNotSet
1✔
128
        }
1✔
129

130
        return c.Workspace, nil
1✔
131
}
132

133
var GetWorkspaceSelectionID = func(client houston.ClientInterface, out io.Writer) (string, error) {
2✔
134
        tab := printutil.Table{
2✔
135
                Padding:        []int{5, 44, 50},
2✔
136
                DynamicPadding: true,
2✔
137
                Header:         []string{"#", "NAME", "ID"},
2✔
138
                ColorRowCode:   [2]string{"\033[1;32m", "\033[0m"},
2✔
139
        }
2✔
140

2✔
141
        var c config.Context
2✔
142
        c, err := config.GetCurrentContext()
2✔
143
        if err != nil {
2✔
144
                return "", err
×
145
        }
×
146

147
        ws, err := houston.Call(client.ListWorkspaces)(c.Organization)
2✔
148
        if err != nil {
2✔
149
                return "", err
×
150
        }
×
151

152
        deployMap := map[string]houston.Workspace{}
2✔
153
        for i := range ws {
6✔
154
                index := i + 1
4✔
155

4✔
156
                color := c.Workspace == ws[i].ID
4✔
157
                tab.AddRow([]string{strconv.Itoa(index), ws[i].Label, ws[i].ID}, color)
4✔
158

4✔
159
                deployMap[strconv.Itoa(index)] = ws[i]
4✔
160
        }
4✔
161
        tab.Print(out)
2✔
162
        choice := input.Text("\n> ")
2✔
163
        selected, ok := deployMap[choice]
2✔
164
        if !ok {
3✔
165
                return "", errInvalidWorkspaceKey
1✔
166
        }
1✔
167

168
        return selected.ID, nil
1✔
169
}
170

171
// workspacesPromptPaginatedOption Show pagination option based on page size and total record
172
var workspacesPromptPaginatedOption = func(pageSize, pageNumber, totalRecord int) workspacePaginationOptions {
4✔
173
        for {
8✔
174
                gotoOptionMessage := defaultWorkspacePaginationOptions
4✔
175
                gotoOptions := make(map[string]workspacePaginationOptions)
4✔
176
                gotoOptions["f"] = workspacePaginationOptions{pageSize: pageSize, quit: false, pageNumber: 0, userSelection: 0}
4✔
177
                gotoOptions["p"] = workspacePaginationOptions{pageSize: pageSize, quit: false, pageNumber: pageNumber - 1, userSelection: 0}
4✔
178
                gotoOptions["n"] = workspacePaginationOptions{pageSize: pageSize, quit: false, pageNumber: pageNumber + 1, userSelection: 0}
4✔
179
                gotoOptions["q"] = workspacePaginationOptions{pageSize: pageSize, quit: true, pageNumber: pageNumber, userSelection: 0}
4✔
180

4✔
181
                if totalRecord < pageSize {
7✔
182
                        delete(gotoOptions, "n")
3✔
183
                        gotoOptionMessage = workspacePaginationWithoutNextOptions
3✔
184
                }
3✔
185

186
                if pageNumber == 0 {
8✔
187
                        delete(gotoOptions, "p")
4✔
188
                        delete(gotoOptions, "f")
4✔
189
                        gotoOptionMessage = workspacePaginationWithNextQuitOptions
4✔
190
                }
4✔
191

192
                if pageNumber == 0 && totalRecord < pageSize {
7✔
193
                        gotoOptionMessage = workspacePaginationWithQuitOptions
3✔
194
                }
3✔
195

196
                in := input.Text("\n\nPlease select one of the following options or enter index to select the row.\n" + gotoOptionMessage)
4✔
197
                value, found := gotoOptions[in]
4✔
198
                i, err := strconv.ParseInt(in, 10, 8) //nolint:mnd
4✔
199

4✔
200
                if found {
7✔
201
                        return value
3✔
202
                } else if err == nil && int(i) > pageSize*pageNumber {
5✔
203
                        userSelection := gotoOptions["q"]
1✔
204
                        userSelection.userSelection = int(i) - pageSize*pageNumber
1✔
205
                        return userSelection
1✔
206
                }
1✔
207
                fmt.Print("\nInvalid option")
×
208
        }
209
}
210

211
func getWorkspaceSelection(pageSize, pageNumber int, client houston.ClientInterface, out io.Writer) workspaceSelection {
9✔
212
        tab := newTableOut()
9✔
213
        tab.GetUserInput = true
9✔
214
        var ws []houston.Workspace
9✔
215
        var err error
9✔
216

9✔
217
        if pageSize > 0 {
12✔
218
                ws, err = houston.Call(client.PaginatedListWorkspaces)(houston.PaginatedListWorkspaceRequest{PageSize: pageSize, PageNumber: pageNumber})
3✔
219
        } else {
9✔
220
                ws, err = houston.Call(client.ListWorkspaces)(nil)
6✔
221
        }
6✔
222
        if err != nil {
10✔
223
                return workspaceSelection{id: "", quit: false, err: err}
1✔
224
        }
1✔
225

226
        c, err := config.GetCurrentContext()
8✔
227
        if err != nil {
9✔
228
                return workspaceSelection{id: "", quit: false, err: err}
1✔
229
        }
1✔
230

231
        for i := range ws {
28✔
232
                w := ws[i]
21✔
233
                name := w.Label
21✔
234
                workspace := w.ID
21✔
235

21✔
236
                var color bool
21✔
237

21✔
238
                if c.Workspace == w.ID {
21✔
239
                        color = true
×
240
                } else {
21✔
241
                        color = false
21✔
242
                }
21✔
243
                tab.AddRow([]string{name, workspace}, color)
21✔
244
        }
245

246
        tabPrintErr := tab.PrintWithPageNumber(pageNumber*pageSize, out)
7✔
247
        if tabPrintErr != nil {
7✔
248
                return workspaceSelection{id: "", quit: false, err: fmt.Errorf("unable to print with page number: %w", tabPrintErr)}
×
249
        }
×
250
        totalRecords := len(ws)
7✔
251

7✔
252
        if pageSize > 0 {
10✔
253
                selectedOption := workspacesPromptPaginatedOption(pageSize, pageNumber, totalRecords)
3✔
254
                if selectedOption.quit {
6✔
255
                        if selectedOption.userSelection == 0 {
5✔
256
                                return workspaceSelection{id: "", quit: true, err: nil}
2✔
257
                        }
2✔
258
                        return workspaceSelection{id: ws[selectedOption.userSelection-1].ID, quit: false, err: nil}
1✔
259
                }
260
                return getWorkspaceSelection(selectedOption.pageSize, selectedOption.pageNumber, client, out)
×
261
        }
262

263
        in := input.Text("\n> ")
4✔
264
        i, err := strconv.ParseInt(in, 10, 64) //nolint:mnd
4✔
265
        if err != nil {
6✔
266
                return workspaceSelection{id: "", quit: false, err: fmt.Errorf("cannot parse %s to int: %w", in, err)}
2✔
267
        }
2✔
268
        return workspaceSelection{id: ws[i-1].ID, quit: false, err: nil}
2✔
269
}
270

271
// Switch switches workspaces
272
func Switch(id string, pageSize int, client houston.ClientInterface, out io.Writer) error {
4✔
273
        if id == "" {
7✔
274
                workspaceSelection := getWorkspaceSelection(pageSize, 0, client, out)
3✔
275

3✔
276
                if workspaceSelection.quit {
4✔
277
                        return nil
1✔
278
                }
1✔
279
                if workspaceSelection.err != nil {
3✔
280
                        return workspaceSelection.err
1✔
281
                }
1✔
282

283
                id = workspaceSelection.id
1✔
284
        }
285
        // validate workspace
286
        _, err := houston.Call(client.ValidateWorkspaceID)(id)
2✔
287
        if err != nil {
3✔
288
                return fmt.Errorf("workspace id is not valid: %w", err)
1✔
289
        }
1✔
290

291
        c, err := config.GetCurrentContext()
1✔
292
        if err != nil {
1✔
293
                return err
×
294
        }
×
295

296
        c.Workspace = id
1✔
297
        err = c.SetContext()
1✔
298
        if err != nil {
1✔
299
                return err
×
300
        }
×
301

302
        err = config.PrintCurrentSoftwareContext(out)
1✔
303
        return err
1✔
304
}
305

306
// Update an astronomer workspace
307
func Update(id string, client houston.ClientInterface, out io.Writer, args map[string]string) error {
2✔
308
        // validate workspace
2✔
309
        w, err := houston.Call(client.UpdateWorkspace)(houston.UpdateWorkspaceRequest{WorkspaceID: id, Args: args})
2✔
310
        if err != nil {
3✔
311
                return err
1✔
312
        }
1✔
313

314
        tab := newTableOut()
1✔
315
        tab.AddRow([]string{w.Label, w.ID}, false)
1✔
316
        tab.SuccessMsg = "\n Successfully updated workspace"
1✔
317
        tab.Print(out)
1✔
318

1✔
319
        return nil
1✔
320
}
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

© 2025 Coveralls, Inc