Carry dependencies through config commands

This commit is contained in:
2026-09-05 18:48:25 +00:00
parent 0726786016
commit 9bb203476d
3 changed files with 61 additions and 12 deletions

View File

@@ -48,7 +48,7 @@ func executeWithDependencies(args []string, stdout, stderr io.Writer, deps comma
case "clean": case "clean":
err = cleanWithDependencies(ctx, cmdArgs, stdout, deps) err = cleanWithDependencies(ctx, cmdArgs, stdout, deps)
case "config": case "config":
err = Config(ctx, cmdArgs, stdout) err = configWithDependencies(ctx, cmdArgs, stdout, deps)
default: default:
fmt.Fprintf(stderr, "unknown command: %q\n\n", cmd) fmt.Fprintf(stderr, "unknown command: %q\n\n", cmd)
printUsage(stderr) printUsage(stderr)

View File

@@ -29,6 +29,11 @@ type inspectionConfig struct {
// Config dispatches read-only pipeline configuration commands. // Config dispatches read-only pipeline configuration commands.
func Config(ctx context.Context, args []string, out io.Writer) error { func Config(ctx context.Context, args []string, out io.Writer) error {
return configWithDependencies(ctx, args, out, commandDependencies{})
}
func configWithDependencies(ctx context.Context, args []string, out io.Writer, deps commandDependencies) error {
deps = normalizeCommandDependencies(deps)
if len(args) == 0 { if len(args) == 0 {
return fmt.Errorf("config: expected subcommand: validate|show|sources|diff") return fmt.Errorf("config: expected subcommand: validate|show|sources|diff")
} }
@@ -38,11 +43,11 @@ func Config(ctx context.Context, args []string, out io.Writer) error {
} }
switch args[0] { switch args[0] {
case "validate": case "validate":
return ConfigValidate(ctx, args[1:], out) return configValidateWithDependencies(ctx, args[1:], out, deps)
case "show": case "show":
return ConfigShow(ctx, args[1:], out) return configShowWithDependencies(ctx, args[1:], out, deps)
case "sources": case "sources":
return ConfigSources(ctx, args[1:], out) return configSourcesWithDependencies(ctx, args[1:], out, deps)
case "diff": case "diff":
return ConfigDiff(ctx, args[1:], out) return ConfigDiff(ctx, args[1:], out)
default: default:
@@ -52,7 +57,11 @@ func Config(ctx context.Context, args []string, out io.Writer) error {
// ConfigValidate validates one fully resolved effective pipeline without // ConfigValidate validates one fully resolved effective pipeline without
// loading session state or constructing runtime collaborators. // loading session state or constructing runtime collaborators.
func ConfigValidate(_ context.Context, args []string, out io.Writer) error { func ConfigValidate(ctx context.Context, args []string, out io.Writer) error {
return configValidateWithDependencies(ctx, args, out, commandDependencies{})
}
func configValidateWithDependencies(_ context.Context, args []string, out io.Writer, deps commandDependencies) error {
flags, err := parseInspectionFlags("config validate", args, out) flags, err := parseInspectionFlags("config validate", args, out)
if err != nil { if err != nil {
if errors.Is(err, flag.ErrHelp) { if errors.Is(err, flag.ErrHelp) {
@@ -60,7 +69,7 @@ func ConfigValidate(_ context.Context, args []string, out io.Writer) error {
} }
return err return err
} }
resolved, err := resolveInspectionConfig(flags) resolved, err := resolveInspectionConfigWithDependencies(flags, deps)
if err != nil { if err != nil {
return fmt.Errorf("config validate: %w", err) return fmt.Errorf("config validate: %w", err)
} }
@@ -71,7 +80,11 @@ func ConfigValidate(_ context.Context, args []string, out io.Writer) error {
// ConfigShow validates and renders one fully resolved effective pipeline // ConfigShow validates and renders one fully resolved effective pipeline
// without loading session state or constructing runtime collaborators. // without loading session state or constructing runtime collaborators.
func ConfigShow(_ context.Context, args []string, out io.Writer) error { func ConfigShow(ctx context.Context, args []string, out io.Writer) error {
return configShowWithDependencies(ctx, args, out, commandDependencies{})
}
func configShowWithDependencies(_ context.Context, args []string, out io.Writer, deps commandDependencies) error {
flags, err := parseInspectionFlags("config show", args, out) flags, err := parseInspectionFlags("config show", args, out)
if err != nil { if err != nil {
if errors.Is(err, flag.ErrHelp) { if errors.Is(err, flag.ErrHelp) {
@@ -79,7 +92,7 @@ func ConfigShow(_ context.Context, args []string, out io.Writer) error {
} }
return err return err
} }
resolved, err := resolveInspectionConfig(flags) resolved, err := resolveInspectionConfigWithDependencies(flags, deps)
if err != nil { if err != nil {
return fmt.Errorf("config show: %w", err) return fmt.Errorf("config show: %w", err)
} }
@@ -93,7 +106,11 @@ func ConfigShow(_ context.Context, args []string, out io.Writer) error {
// ConfigSources validates and reports deterministic effective configuration // ConfigSources validates and reports deterministic effective configuration
// ownership without loading session state or runtime collaborators. // ownership without loading session state or runtime collaborators.
func ConfigSources(_ context.Context, args []string, out io.Writer) error { func ConfigSources(ctx context.Context, args []string, out io.Writer) error {
return configSourcesWithDependencies(ctx, args, out, commandDependencies{})
}
func configSourcesWithDependencies(_ context.Context, args []string, out io.Writer, deps commandDependencies) error {
flags, err := parseInspectionFlags("config sources", args, out) flags, err := parseInspectionFlags("config sources", args, out)
if err != nil { if err != nil {
if errors.Is(err, flag.ErrHelp) { if errors.Is(err, flag.ErrHelp) {
@@ -101,7 +118,7 @@ func ConfigSources(_ context.Context, args []string, out io.Writer) error {
} }
return err return err
} }
resolved, err := resolveInspectionConfig(flags) resolved, err := resolveInspectionConfigWithDependencies(flags, deps)
if err != nil { if err != nil {
return fmt.Errorf("config sources: %w", err) return fmt.Errorf("config sources: %w", err)
} }
@@ -150,8 +167,8 @@ func parseInspectionFlags(command string, args []string, out io.Writer) (inspect
return flags, nil return flags, nil
} }
func resolveInspectionConfig(flags inspectionFlags) (*inspectionConfig, error) { func resolveInspectionConfigWithDependencies(flags inspectionFlags, deps commandDependencies) (*inspectionConfig, error) {
pipelinePath, pipeline, err := loadPipelineConfig(flags.pipelinePath, config.PipelineLoadOptions{Profile: flags.profile.pointer()}) pipelinePath, pipeline, err := loadPipelineConfigWithDependencies(flags.pipelinePath, config.PipelineLoadOptions{Profile: flags.profile.pointer()}, deps)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -47,6 +47,38 @@ func TestConfigCommandHelpAndDispatch(t *testing.T) {
} }
} }
func TestExecuteConfigUsesInvocationPipelineLoader(t *testing.T) {
dir := t.TempDir()
pipelinePath := filepath.Join(dir, "pipeline.yml")
mustWriteTestFile(t, pipelinePath, "workspace:\n root: "+filepath.Join(dir, "workspace")+"\nwhisperx:\n transcribe_url: https://transcription.example.com/transcribe\n")
for _, subcommand := range []string{"validate", "show", "sources"} {
t.Run(subcommand, func(t *testing.T) {
calls := 0
deps := commandDependencies{
loadPipelineConfig: func(path string, opts config.PipelineLoadOptions) (*config.PipelineConfig, error) {
calls++
return config.LoadPipelineWithOptions(path, opts)
},
}
var stdout, stderr bytes.Buffer
code := executeWithDependencies(
[]string{"config", subcommand, "--config", pipelinePath},
&stdout,
&stderr,
deps,
executePlan,
)
if code != 0 {
t.Fatalf("exit code = %d, want 0; stdout=%q stderr=%q", code, stdout.String(), stderr.String())
}
if calls != 1 {
t.Fatalf("pipeline loader calls = %d, want 1", calls)
}
})
}
}
func TestConfigValidateAndShowPipelineOnlyAreSideEffectFree(t *testing.T) { func TestConfigValidateAndShowPipelineOnlyAreSideEffectFree(t *testing.T) {
dir := t.TempDir() dir := t.TempDir()
workspaceRoot := filepath.Join(dir, "workspace-does-not-exist") workspaceRoot := filepath.Join(dir, "workspace-does-not-exist")