Skip to content

Commit 68022b2

Browse files
committed
refactor: simplify config threading
1 parent e794909 commit 68022b2

File tree

5 files changed

+66
-124
lines changed

5 files changed

+66
-124
lines changed

pkg/cmd/build.go

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,15 @@ type BuildTargetInfo struct {
2929
status stainless.BuildTargetStatus
3030
}
3131

32-
// parseTargetPaths processes target flags to extract target:path syntax
32+
// parseTargetPaths processes target flags to extract target:path syntax with workspace config
3333
// Returns a map of target names to their custom paths
34-
func parseTargetPaths() map[string]string {
34+
func parseTargetPaths(workspaceConfig WorkspaceConfig) map[string]string {
3535
targetPaths := make(map[string]string)
3636

37-
// First, check workspace configuration for target paths
38-
var config WorkspaceConfig
39-
found, err := config.Find()
40-
if err == nil && found && config.Targets != nil {
41-
for targetName, targetConfig := range config.Targets {
42-
if targetConfig.OutputPath != "" {
43-
targetPaths[targetName] = targetConfig.OutputPath
44-
}
37+
// Check workspace configuration for target paths if loaded
38+
for targetName, targetConfig := range workspaceConfig.Targets {
39+
if targetConfig.OutputPath != "" {
40+
targetPaths[targetName] = targetConfig.OutputPath
4541
}
4642
}
4743

@@ -446,26 +442,13 @@ var buildsCompare = cli.Command{
446442
}
447443

448444
func handleBuildsCreate(ctx context.Context, cmd *cli.Command) error {
449-
targetPaths := parseTargetPaths()
450-
451-
// Check workspace config for targets
452-
var config WorkspaceConfig
453-
hasWorkspaceTargets := false
454-
found, err := config.Find()
455-
if err == nil && found && config.Targets != nil && len(config.Targets) > 0 {
456-
hasWorkspaceTargets = true
457-
// Merge workspace target paths with command line target paths
458-
for targetName, targetConfig := range config.Targets {
459-
if _, exists := targetPaths[targetName]; !exists && targetConfig.OutputPath != "" {
460-
targetPaths[targetName] = targetConfig.OutputPath
461-
}
462-
}
463-
}
464-
465445
cc, err := getAPICommandContextWithWorkspaceDefaults(cmd)
466446
if err != nil {
467447
return err
468448
}
449+
450+
// Parse target paths using cached workspace config
451+
targetPaths := parseTargetPaths(cc.workspaceConfig)
469452
buildGroup := Info("Creating build...")
470453
params := stainless.BuildNewParams{}
471454
res, err := cc.client.Builds.New(
@@ -488,8 +471,8 @@ func handleBuildsCreate(ctx context.Context, cmd *cli.Command) error {
488471
}
489472

490473
// Pull if explicitly set via --pull flag, or if workspace has configured targets and --pull wasn't explicitly set to false
491-
shouldPull := cmd.Bool("pull") || (hasWorkspaceTargets && !cmd.IsSet("pull"))
492-
474+
shouldPull := cmd.Bool("pull") || (cc.HasWorkspaceTargets() && !cmd.IsSet("pull"))
475+
493476
if shouldPull {
494477
pullGroup := Info("Downloading build outputs...")
495478
if err := pullBuildOutputs(context.TODO(), cc.client, *res, targetPaths, &pullGroup); err != nil {
@@ -779,9 +762,10 @@ func handleBuildsCompare(ctx context.Context, cmd *cli.Command) error {
779762
// getAPICommandWithWorkspaceDefaults applies workspace defaults before initializing API command
780763
func getAPICommandContextWithWorkspaceDefaults(cmd *cli.Command) (*apiCommandContext, error) {
781764
cc := getAPICommandContext(cmd)
782-
var config WorkspaceConfig
783-
found, err := config.Find()
784-
if err == nil && found {
765+
766+
// Use cached workspace config if available
767+
if cc.workspaceConfig.ConfigPath != "" {
768+
config := cc.workspaceConfig
785769
// Get the directory containing the workspace config file
786770
configDir := filepath.Dir(config.ConfigPath)
787771

@@ -805,5 +789,5 @@ func getAPICommandContextWithWorkspaceDefaults(cmd *cli.Command) (*apiCommandCon
805789
jsonflag.Mutate(jsonflag.Body, "revision.openapi\\.stainless\\.yml.content", string(content))
806790
}
807791
}
808-
return cc, err
792+
return cc, nil
809793
}

pkg/cmd/dev.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,6 @@ var devCommand = cli.Command{
172172
}
173173

174174
func runDevMode(ctx context.Context, cmd *cli.Command) error {
175-
projectName := GetProjectName(cmd, "project")
176-
if projectName == "" {
177-
return fmt.Errorf("project name is required")
178-
}
179-
180175
cc, err := getAPICommandContextWithWorkspaceDefaults(cmd)
181176
if err != nil {
182177
return err
@@ -213,11 +208,10 @@ func runDevMode(ctx context.Context, cmd *cli.Command) error {
213208
// Phase 2: Language selection
214209
var selectedTargets []string
215210

216-
// Try to find workspace config for intelligent defaults
217-
var config WorkspaceConfig
218-
config.Find()
211+
// Use cached workspace config for intelligent defaults
212+
config := cc.workspaceConfig
219213

220-
targetInfo := getAvailableTargetInfo(ctx, cc.client, projectName, config)
214+
targetInfo := getAvailableTargetInfo(ctx, cc.client, cmd.String("project"), config)
221215
targetOptions := targetInfoToOptions(targetInfo)
222216

223217
targetForm := huh.NewForm(
@@ -248,7 +242,7 @@ func runDevMode(ctx context.Context, cmd *cli.Command) error {
248242

249243
// Phase 3: Start build and monitor progress in a loop
250244
for {
251-
err := runDevBuild(ctx, cc, projectName, selectedBranch, targets)
245+
err := runDevBuild(ctx, cc, cmd.String("project"), selectedBranch, targets)
252246
if err != nil {
253247
if errors.Is(err, ErrUserCancelled) {
254248
return nil

pkg/cmd/mcp.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ var mcpCommand = cli.Command{
2424
func handleMCP(ctx context.Context, cmd *cli.Command) error {
2525
args := []string{"-y", "@stainless-api/mcp@latest"}
2626

27+
cc := getAPICommandContext(cmd)
28+
2729
if cmd.Args().Len() > 0 {
2830
args = append(args, cmd.Args().Slice()...)
2931
}
@@ -39,10 +41,8 @@ func handleMCP(ctx context.Context, cmd *cli.Command) error {
3941
}
4042

4143
// Set STAINLESS_PROJECT from workspace config if available
42-
var config WorkspaceConfig
43-
found, err := config.Find()
44-
if err == nil && found && config.Project != "" {
45-
env = append(env, fmt.Sprintf("STAINLESS_PROJECT=%s", config.Project))
44+
if cc.workspaceConfig.Project != "" {
45+
env = append(env, fmt.Sprintf("STAINLESS_PROJECT=%s", cc.workspaceConfig.Project))
4646
}
4747

4848
npmCmd := exec.CommandContext(ctx, "npx", args...)

pkg/cmd/util.go

Lines changed: 27 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ func getDefaultRequestOptions(cmd *cli.Command) []option.RequestOption {
6868
}
6969

7070
type apiCommandContext struct {
71-
client stainless.Client
72-
cmd *cli.Command
71+
client stainless.Client
72+
cmd *cli.Command
73+
workspaceConfig WorkspaceConfig
7374
}
7475

7576
func (c apiCommandContext) AsMiddleware() option.Middleware {
@@ -170,7 +171,30 @@ func (c apiCommandContext) AsMiddleware() option.Middleware {
170171

171172
func getAPICommandContext(cmd *cli.Command) *apiCommandContext {
172173
client := stainless.NewClient(getDefaultRequestOptions(cmd)...)
173-
return &apiCommandContext{client, cmd}
174+
175+
// Load workspace config if available
176+
var workspaceConfig WorkspaceConfig
177+
workspaceConfig.Find() // ConfigPath will be set if found
178+
179+
return &apiCommandContext{client, cmd, workspaceConfig}
180+
}
181+
182+
// HasWorkspaceTargets returns true if workspace config has configured targets
183+
func (c *apiCommandContext) HasWorkspaceTargets() bool {
184+
return c.workspaceConfig.ConfigPath != "" && c.workspaceConfig.Targets != nil && len(c.workspaceConfig.Targets) > 0
185+
}
186+
187+
// GetWorkspaceTargetPaths returns a map of target names to their output paths from workspace config
188+
func (c *apiCommandContext) GetWorkspaceTargetPaths() map[string]string {
189+
targetPaths := make(map[string]string)
190+
if c.workspaceConfig.ConfigPath != "" && c.workspaceConfig.Targets != nil {
191+
for targetName, targetConfig := range c.workspaceConfig.Targets {
192+
if targetConfig.OutputPath != "" {
193+
targetPaths[targetName] = targetConfig.OutputPath
194+
}
195+
}
196+
}
197+
return targetPaths
174198
}
175199

176200
func serializeQuery(params []byte) url.Values {
@@ -294,58 +318,3 @@ func ColorizeJSON(input string, w io.Writer) string {
294318
}
295319
return string(pretty.Color(pretty.Pretty([]byte(input)), nil))
296320
}
297-
298-
// GetProjectName returns the project name from the command line flag or workspace config
299-
func GetProjectName(cmd *cli.Command, flagName string) string {
300-
// First check if the flag was provided
301-
projectName := cmd.String(flagName)
302-
if projectName != "" {
303-
return projectName
304-
}
305-
306-
// Otherwise, try to get from workspace config
307-
var config WorkspaceConfig
308-
found, err := config.Find()
309-
if err == nil && found && config.Project != "" {
310-
// Log that we're using the workspace config if in interactive mode
311-
if isTerminal(os.Stdout) {
312-
Property("project", config.Project+" (from workspace)")
313-
}
314-
return config.Project
315-
}
316-
317-
return ""
318-
}
319-
320-
// CheckInteractiveAndInitWorkspace checks if running in interactive mode and prompts to init workspace if needed
321-
func CheckInteractiveAndInitWorkspace(cmd *cli.Command, projectName string) {
322-
// Only run in interactive mode with a terminal
323-
if !isTerminal(os.Stdout) {
324-
return
325-
}
326-
327-
// Check if workspace config exists
328-
var config WorkspaceConfig
329-
found, _ := config.Find()
330-
if found {
331-
return
332-
}
333-
334-
// Prompt user to initialize workspace
335-
var answer string
336-
fmt.Fprintf(os.Stderr, "%s Would you like to initialize a workspace config with project '%s'? [y/N] ", au.BrightYellow("?"), projectName)
337-
fmt.Scanln(&answer)
338-
339-
if strings.ToLower(answer) == "y" || strings.ToLower(answer) == "yes" {
340-
config, err := NewWorkspaceConfig(projectName, "", "")
341-
if err != nil {
342-
Error("Failed to create workspace config: %v", err)
343-
return
344-
}
345-
if err := config.Save(); err != nil {
346-
Error("Failed to save workspace config: %v", err)
347-
return
348-
}
349-
Success("Workspace initialized with project: %s", projectName)
350-
}
351-
}

pkg/cmd/workspace.go

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,9 @@ func findStainlessConfig() string {
281281
}
282282

283283
func handleWorkspaceStatus(ctx context.Context, cmd *cli.Command) error {
284-
// Look for workspace configuration
285-
var config WorkspaceConfig
286-
found, err := config.Find()
287-
if err != nil {
288-
return fmt.Errorf("error searching for workspace config: %v", err)
289-
}
284+
cc := getAPICommandContext(cmd)
290285

291-
if !found {
286+
if cc.workspaceConfig.ConfigPath == "" {
292287
group := Warn("No workspace configuration found")
293288
group.Info("Run 'stl workspace init' to initialize a workspace in this directory.")
294289
return nil
@@ -301,36 +296,36 @@ func handleWorkspaceStatus(ctx context.Context, cmd *cli.Command) error {
301296
}
302297

303298
// Get relative path from cwd to config file
304-
relPath, err := filepath.Rel(cwd, config.ConfigPath)
299+
relPath, err := filepath.Rel(cwd, cc.workspaceConfig.ConfigPath)
305300
if err != nil {
306-
relPath = config.ConfigPath // fallback to absolute path
301+
relPath = cc.workspaceConfig.ConfigPath // fallback to absolute path
307302
}
308303

309304
group := Success("Workspace configuration found")
310305
group.Property("path", relPath)
311-
group.Property("project", config.Project)
306+
group.Property("project", cc.workspaceConfig.Project)
312307

313-
if config.OpenAPISpec != "" {
308+
if cc.workspaceConfig.OpenAPISpec != "" {
314309
// Check if OpenAPI spec file exists
315-
configDir := filepath.Dir(config.ConfigPath)
316-
specPath := filepath.Join(configDir, config.OpenAPISpec)
310+
configDir := filepath.Dir(cc.workspaceConfig.ConfigPath)
311+
specPath := filepath.Join(configDir, cc.workspaceConfig.OpenAPISpec)
317312
if _, err := os.Stat(specPath); err == nil {
318-
group.Property("openapi_spec", config.OpenAPISpec)
313+
group.Property("openapi_spec", cc.workspaceConfig.OpenAPISpec)
319314
} else {
320-
group.Property("openapi_spec", config.OpenAPISpec+" (not found)")
315+
group.Property("openapi_spec", cc.workspaceConfig.OpenAPISpec+" (not found)")
321316
}
322317
} else {
323318
group.Property("openapi_spec", "(not configured)")
324319
}
325320

326-
if config.StainlessConfig != "" {
321+
if cc.workspaceConfig.StainlessConfig != "" {
327322
// Check if Stainless config file exists
328-
configDir := filepath.Dir(config.ConfigPath)
329-
stainlessPath := filepath.Join(configDir, config.StainlessConfig)
323+
configDir := filepath.Dir(cc.workspaceConfig.ConfigPath)
324+
stainlessPath := filepath.Join(configDir, cc.workspaceConfig.StainlessConfig)
330325
if _, err := os.Stat(stainlessPath); err == nil {
331-
group.Property("stainless_config", config.StainlessConfig)
326+
group.Property("stainless_config", cc.workspaceConfig.StainlessConfig)
332327
} else {
333-
group.Property("stainless_config", config.StainlessConfig+" (not found)")
328+
group.Property("stainless_config", cc.workspaceConfig.StainlessConfig+" (not found)")
334329
}
335330
} else {
336331
group.Property("stainless_config", "(not configured)")

0 commit comments

Comments
 (0)