From 1c84e6cb4b76e2a002a195c1c8613bc52ab9b4ec Mon Sep 17 00:00:00 2001 From: Thien Trung Vuong Date: Wed, 2 Sep 2026 20:39:42 +0000 Subject: [PATCH] feat(cli): select the spec editor --- docs/user/reference/cli/azldev_component.md | 3 +- .../reference/cli/azldev_component_add.md | 1 + .../reference/cli/azldev_component_build.md | 1 + .../reference/cli/azldev_component_changed.md | 1 + .../cli/azldev_component_diff-sources.md | 1 + .../reference/cli/azldev_component_history.md | 1 + .../reference/cli/azldev_component_list.md | 1 + .../cli/azldev_component_prepare-sources.md | 1 + .../reference/cli/azldev_component_query.md | 1 + .../reference/cli/azldev_component_render.md | 1 + .../reference/cli/azldev_component_update.md | 1 + docs/user/reference/config/overlays.md | 8 +- internal/app/azldev/cmds/component/build.go | 11 +- .../app/azldev/cmds/component/component.go | 1 + .../app/azldev/cmds/component/diffsources.go | 9 +- .../azldev/cmds/component/preparesources.go | 11 +- internal/app/azldev/cmds/component/render.go | 21 ++-- .../app/azldev/cmds/component/speceditor.go | 90 ++++++++++++++++ .../component/speceditor_internal_test.go | 100 ++++++++++++++++++ .../TestMCPServerMode_1.snap.json | 16 +++ 20 files changed, 266 insertions(+), 14 deletions(-) create mode 100644 internal/app/azldev/cmds/component/speceditor.go create mode 100644 internal/app/azldev/cmds/component/speceditor_internal_test.go diff --git a/docs/user/reference/cli/azldev_component.md b/docs/user/reference/cli/azldev_component.md index 525c63a71..b50e012af 100644 --- a/docs/user/reference/cli/azldev_component.md +++ b/docs/user/reference/cli/azldev_component.md @@ -16,7 +16,8 @@ components defined in the project configuration. ### Options ``` - -h, --help help for component + -h, --help help for component + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) ``` ### Options inherited from parent commands diff --git a/docs/user/reference/cli/azldev_component_add.md b/docs/user/reference/cli/azldev_component_add.md index bce63e5ed..d37c5ba41 100644 --- a/docs/user/reference/cli/azldev_component_add.md +++ b/docs/user/reference/cli/azldev_component_add.md @@ -45,6 +45,7 @@ azldev component add [flags] --permissive-config do not fail on unknown fields in TOML config files -C, --project string path to Azure Linux project -q, --quiet only enable minimal output + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) -v, --verbose enable verbose output ``` diff --git a/docs/user/reference/cli/azldev_component_build.md b/docs/user/reference/cli/azldev_component_build.md index 2086f683a..9eca66555 100644 --- a/docs/user/reference/cli/azldev_component_build.md +++ b/docs/user/reference/cli/azldev_component_build.md @@ -76,6 +76,7 @@ azldev component build [flags] --permissive-config do not fail on unknown fields in TOML config files -C, --project string path to Azure Linux project -q, --quiet only enable minimal output + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) -v, --verbose enable verbose output ``` diff --git a/docs/user/reference/cli/azldev_component_changed.md b/docs/user/reference/cli/azldev_component_changed.md index ce88bd3fe..6f47c132e 100644 --- a/docs/user/reference/cli/azldev_component_changed.md +++ b/docs/user/reference/cli/azldev_component_changed.md @@ -72,6 +72,7 @@ azldev component changed [flags] --permissive-config do not fail on unknown fields in TOML config files -C, --project string path to Azure Linux project -q, --quiet only enable minimal output + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) -v, --verbose enable verbose output ``` diff --git a/docs/user/reference/cli/azldev_component_diff-sources.md b/docs/user/reference/cli/azldev_component_diff-sources.md index afd471ac7..6ed7b6eaa 100644 --- a/docs/user/reference/cli/azldev_component_diff-sources.md +++ b/docs/user/reference/cli/azldev_component_diff-sources.md @@ -39,6 +39,7 @@ azldev component diff-sources [flags] --permissive-config do not fail on unknown fields in TOML config files -C, --project string path to Azure Linux project -q, --quiet only enable minimal output + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) -v, --verbose enable verbose output ``` diff --git a/docs/user/reference/cli/azldev_component_history.md b/docs/user/reference/cli/azldev_component_history.md index 00c58cd58..01c50c93a 100644 --- a/docs/user/reference/cli/azldev_component_history.md +++ b/docs/user/reference/cli/azldev_component_history.md @@ -65,6 +65,7 @@ azldev component history [flags] --permissive-config do not fail on unknown fields in TOML config files -C, --project string path to Azure Linux project -q, --quiet only enable minimal output + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) -v, --verbose enable verbose output ``` diff --git a/docs/user/reference/cli/azldev_component_list.md b/docs/user/reference/cli/azldev_component_list.md index 2900def00..3bff150eb 100644 --- a/docs/user/reference/cli/azldev_component_list.md +++ b/docs/user/reference/cli/azldev_component_list.md @@ -54,6 +54,7 @@ azldev component list [flags] --permissive-config do not fail on unknown fields in TOML config files -C, --project string path to Azure Linux project -q, --quiet only enable minimal output + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) -v, --verbose enable verbose output ``` diff --git a/docs/user/reference/cli/azldev_component_prepare-sources.md b/docs/user/reference/cli/azldev_component_prepare-sources.md index 590286e75..b0a1385c6 100644 --- a/docs/user/reference/cli/azldev_component_prepare-sources.md +++ b/docs/user/reference/cli/azldev_component_prepare-sources.md @@ -59,6 +59,7 @@ azldev component prepare-sources [flags] --permissive-config do not fail on unknown fields in TOML config files -C, --project string path to Azure Linux project -q, --quiet only enable minimal output + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) -v, --verbose enable verbose output ``` diff --git a/docs/user/reference/cli/azldev_component_query.md b/docs/user/reference/cli/azldev_component_query.md index 688fdc35e..8c8ffa0c2 100644 --- a/docs/user/reference/cli/azldev_component_query.md +++ b/docs/user/reference/cli/azldev_component_query.md @@ -57,6 +57,7 @@ azldev component query [flags] --permissive-config do not fail on unknown fields in TOML config files -C, --project string path to Azure Linux project -q, --quiet only enable minimal output + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) -v, --verbose enable verbose output ``` diff --git a/docs/user/reference/cli/azldev_component_render.md b/docs/user/reference/cli/azldev_component_render.md index 1ded12dec..3a3d8ad7b 100644 --- a/docs/user/reference/cli/azldev_component_render.md +++ b/docs/user/reference/cli/azldev_component_render.md @@ -79,6 +79,7 @@ azldev component render [flags] --permissive-config do not fail on unknown fields in TOML config files -C, --project string path to Azure Linux project -q, --quiet only enable minimal output + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) -v, --verbose enable verbose output ``` diff --git a/docs/user/reference/cli/azldev_component_update.md b/docs/user/reference/cli/azldev_component_update.md index 911445799..4e9d6fe0a 100644 --- a/docs/user/reference/cli/azldev_component_update.md +++ b/docs/user/reference/cli/azldev_component_update.md @@ -77,6 +77,7 @@ azldev component update [flags] --permissive-config do not fail on unknown fields in TOML config files -C, --project string path to Azure Linux project -q, --quiet only enable minimal output + --spec-editor editor Select the RPM spec editor (legacy or experimental) (default legacy) -v, --verbose enable verbose output ``` diff --git a/docs/user/reference/config/overlays.md b/docs/user/reference/config/overlays.md index 3ab187916..20ba23c18 100644 --- a/docs/user/reference/config/overlays.md +++ b/docs/user/reference/config/overlays.md @@ -10,7 +10,13 @@ Overlays are defined within a component's configuration in your TOML config file ### Spec Overlays -These overlays modify `.spec` files using the structured spec parser, allowing precise targeting of tags and sections. +These overlays modify `.spec` files using the component command's `--spec-editor` option. The default `legacy` editor is line-oriented; `--spec-editor experimental` selects the structural editor, which preserves conditional and section structure. + +#### Known Limitations + +With the structural editor, content after a conditional wrapper's `%endif` cannot always be statically attributed to a section declared inside that wrapper. A scoped overlay may therefore not reach that content; use a narrowly anchored whole-spec `spec-search-replace` overlay instead. + +Sections generated by macros are unavailable to both editors because azldev does not evaluate RPM macros while editing specs. | Type | Description | Required Fields | |------|-------------|-----------------| diff --git a/internal/app/azldev/cmds/component/build.go b/internal/app/azldev/cmds/component/build.go index 60aed20f0..ceb2fe63e 100644 --- a/internal/app/azldev/cmds/component/build.go +++ b/internal/app/azldev/cmds/component/build.go @@ -25,6 +25,7 @@ import ( ) type ComponentBuildOptions struct { + componentCommandOptions ComponentFilter components.ComponentFilter ContinueOnError bool @@ -88,7 +89,9 @@ func NewBuildCmd() *cobra.Command { BuildEnvPolicy: BuildEnvPreserveOnFailure, } - cmd := &cobra.Command{ + var cmd *cobra.Command + + cmd = &cobra.Command{ Use: "build", Short: "Build packages for components", Long: `Build RPM packages for one or more components using mock. @@ -121,6 +124,7 @@ builds can consume.`, azldev component build --local-repo-with-publish ./base/out -p liba -p libb`, RunE: azldev.RunFuncWithExtraArgs(func(env *azldev.Env, args []string) (interface{}, error) { options.ComponentFilter.ComponentNamePatterns = append(options.ComponentFilter.ComponentNamePatterns, args...) + options.SpecEditor = specEditorFromCommand(cmd) return SelectAndBuildComponents(env, options) }), @@ -280,7 +284,10 @@ func buildComponent( preparerOpts = append(preparerOpts, sources.WithMockProcessor(mockProcessor)) - sourcePreparer, err := sources.NewPreparer(sourceManager, env.FS(), env, env, preparerOpts...) + sourcePreparer, err := sources.NewPreparer(sourceManager, env.FS(), env, env, append( + preparerOpts, + sources.WithSpecEditor(options.specEditorMode()), + )...) if err != nil { return ComponentBuildResults{}, fmt.Errorf("failed to create source preparer for component %q:\n%w", component.GetName(), err) diff --git a/internal/app/azldev/cmds/component/component.go b/internal/app/azldev/cmds/component/component.go index 9cfee2ea3..64d1a5bd0 100644 --- a/internal/app/azldev/cmds/component/component.go +++ b/internal/app/azldev/cmds/component/component.go @@ -22,6 +22,7 @@ Use subcommands to add, list, query, build, and prepare sources for components defined in the project configuration.`, } + addSpecEditorOption(cmd) app.AddTopLevelCommand(cmd) addOnAppInit(app, cmd) buildOnAppInit(app, cmd) diff --git a/internal/app/azldev/cmds/component/diffsources.go b/internal/app/azldev/cmds/component/diffsources.go index 8047bd9fe..347a08576 100644 --- a/internal/app/azldev/cmds/component/diffsources.go +++ b/internal/app/azldev/cmds/component/diffsources.go @@ -23,6 +23,7 @@ import ( // DiffSourcesOptions holds the options for the diff-sources command. type DiffSourcesOptions struct { + componentCommandOptions ComponentFilter components.ComponentFilter OutputFile string @@ -36,7 +37,9 @@ func diffSourcesOnAppInit(_ *azldev.App, parentCmd *cobra.Command) { func NewDiffSourcesCmd() *cobra.Command { var options DiffSourcesOptions - cmd := &cobra.Command{ + var cmd *cobra.Command + + cmd = &cobra.Command{ Use: "diff-sources", Short: "Show the diff that overlays apply to a component's sources", Long: `Computes a unified diff showing the changes that overlays apply to a @@ -44,6 +47,7 @@ component's sources. Fetches the sources once, copies them, then applies overlays to the copy and displays the resulting diff between the two trees.`, RunE: azldev.RunFuncWithExtraArgs(func(env *azldev.Env, args []string) (interface{}, error) { options.ComponentFilter.ComponentNamePatterns = append(args, options.ComponentFilter.ComponentNamePatterns...) + options.SpecEditor = specEditorFromCommand(cmd) return DiffComponentSources(env, &options) }), @@ -98,7 +102,8 @@ func DiffComponentSources(env *azldev.Env, options *DiffSourcesOptions) (interfa } preparer, err := sources.NewPreparer(sourceManager, env.FS(), env, env, - sources.WithUpstreamProvenance(sources.FedoraDistTag(distro.Ref.Name, distro.Version.ReleaseVer))) + sources.WithUpstreamProvenance(sources.FedoraDistTag(distro.Ref.Name, distro.Version.ReleaseVer)), + sources.WithSpecEditor(options.specEditorMode())) if err != nil { return nil, fmt.Errorf("failed to create source preparer:\n%w", err) } diff --git a/internal/app/azldev/cmds/component/preparesources.go b/internal/app/azldev/cmds/component/preparesources.go index ac48bdcac..22d3ed83b 100644 --- a/internal/app/azldev/cmds/component/preparesources.go +++ b/internal/app/azldev/cmds/component/preparesources.go @@ -17,6 +17,7 @@ import ( ) type PrepareSourcesOptions struct { + componentCommandOptions ComponentFilter components.ComponentFilter OutputDir string @@ -34,7 +35,9 @@ func prepareOnAppInit(_ *azldev.App, sourceCmd *cobra.Command) { func NewPrepareSourcesCmd() *cobra.Command { var options PrepareSourcesOptions - cmd := &cobra.Command{ + var cmd *cobra.Command + + cmd = &cobra.Command{ Use: "prepare-sources", Aliases: []string{"prep-sources"}, Short: "Prepare buildable sources for components", @@ -53,6 +56,7 @@ Only one component may be selected at a time.`, azldev component prep-sources -p curl -o ./build/work/scratch/curl --skip-overlays --force`, RunE: azldev.RunFuncWithExtraArgs(func(env *azldev.Env, args []string) (interface{}, error) { options.ComponentFilter.ComponentNamePatterns = append(args, options.ComponentFilter.ComponentNamePatterns...) + options.SpecEditor = specEditorFromCommand(cmd) return nil, PrepareComponentSources(env, &options) }), @@ -132,7 +136,10 @@ func PrepareComponentSources(env *azldev.Env, options *PrepareSourcesOptions) er preparerOpts := buildPreparerOptions(env, distro, options) - preparer, err := sources.NewPreparer(sourceManager, env.FS(), env, env, preparerOpts...) + preparer, err := sources.NewPreparer(sourceManager, env.FS(), env, env, append( + preparerOpts, + sources.WithSpecEditor(options.specEditorMode()), + )...) if err != nil { return fmt.Errorf("failed to create source preparer:\n%w", err) } diff --git a/internal/app/azldev/cmds/component/render.go b/internal/app/azldev/cmds/component/render.go index 163da0dd9..97fde2225 100644 --- a/internal/app/azldev/cmds/component/render.go +++ b/internal/app/azldev/cmds/component/render.go @@ -19,6 +19,7 @@ import ( "github.com/microsoft/azure-linux-dev-tools/internal/app/azldev/core/sources" "github.com/microsoft/azure-linux-dev-tools/internal/global/opctx" "github.com/microsoft/azure-linux-dev-tools/internal/providers/sourceproviders" + "github.com/microsoft/azure-linux-dev-tools/internal/rpm/spec" "github.com/microsoft/azure-linux-dev-tools/internal/utils/dirdiff" "github.com/microsoft/azure-linux-dev-tools/internal/utils/fileperms" "github.com/microsoft/azure-linux-dev-tools/internal/utils/fileutils" @@ -29,6 +30,7 @@ import ( // RenderOptions holds the options for the render command. type RenderOptions struct { + componentCommandOptions ComponentFilter components.ComponentFilter OutputDir string OutputDirExplicit bool // True when --output-dir was explicitly passed on the CLI. @@ -88,6 +90,7 @@ valid with -a.`, RunE: azldev.RunFuncWithExtraArgs(func(env *azldev.Env, args []string) (interface{}, error) { options.ComponentFilter.ComponentNamePatterns = append(args, options.ComponentFilter.ComponentNamePatterns...) options.OutputDirExplicit = cmd.Flags().Changed("output-dir") + options.SpecEditor = specEditorFromCommand(cmd) return RenderComponents(env, &options) }), @@ -204,7 +207,7 @@ func RenderComponents(env *azldev.Env, options *RenderOptions) ([]*RenderResult, results := make([]*RenderResult, len(componentList)) // ── Phase 1: Parallel source preparation ── - prepared := parallelPrepare(env, mockProcessor, componentList, stagingDir, options.OutputDir, results) + prepared := parallelPrepare(env, mockProcessor, componentList, stagingDir, options, results) // ── Phase 2: Batch mock processing ── mockResultMap := batchMockProcess(env, mockProcessor, stagingDir, prepared) @@ -386,7 +389,7 @@ func parallelPrepare( mockProcessor *sources.MockProcessor, comps []components.Component, stagingDir string, - outputDir string, + options *RenderOptions, results []*RenderResult, ) []*preparedComponent { progressEvent := env.StartEvent("Preparing component sources", "count", len(comps)) @@ -406,7 +409,8 @@ func parallelPrepare( // workerEnv (captured) is the effective context for this call chain; // the parmap-supplied ctx is identical and unused here. //nolint:contextcheck // env carries the ctx - return prepareOneComponent(workerEnv, mockProcessor, comp, stagingDir, outputDir) + return prepareOneComponent( + workerEnv, mockProcessor, comp, stagingDir, options.OutputDir, options.specEditorMode()) }, ) @@ -418,7 +422,7 @@ func parallelPrepare( // Worker never started — ctx ended before parmap reached it. compName := comps[idx].GetName() - compOutputDir, nameErr := components.RenderedSpecDir(outputDir, compName) + compOutputDir, nameErr := components.RenderedSpecDir(options.OutputDir, compName) if nameErr != nil { compOutputDir = "(invalid)" } @@ -453,6 +457,7 @@ func prepareOneComponent( comp components.Component, stagingDir string, outputDir string, + specEditor spec.EditorMode, ) prepResult { componentName := comp.GetName() @@ -467,7 +472,7 @@ func prepareOneComponent( }} } - prep, err := prepareComponentSources(env, mockProcessor, comp, stagingDir) + prep, err := prepareComponentSources(env, mockProcessor, comp, stagingDir, specEditor) if err != nil { slog.Error("Failed to prepare component sources", "component", componentName, "error", err) @@ -493,6 +498,7 @@ func prepareComponentSources( mockProcessor *sources.MockProcessor, comp components.Component, stagingDir string, + specEditor spec.EditorMode, ) (*preparedComponent, error) { componentName := comp.GetName() @@ -531,7 +537,10 @@ func prepareComponentSources( sources.WithMockProcessor(mockProcessor), } - preparer, err := sources.NewPreparer(sourceManager, env.FS(), env, env, preparerOpts...) + preparer, err := sources.NewPreparer(sourceManager, env.FS(), env, env, append( + preparerOpts, + sources.WithSpecEditor(specEditor), + )...) if err != nil { return nil, fmt.Errorf("creating source preparer for %#q:\n%w", componentName, err) } diff --git a/internal/app/azldev/cmds/component/speceditor.go b/internal/app/azldev/cmds/component/speceditor.go new file mode 100644 index 000000000..6c4467c09 --- /dev/null +++ b/internal/app/azldev/cmds/component/speceditor.go @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +package component + +import ( + "fmt" + + "github.com/microsoft/azure-linux-dev-tools/internal/rpm/spec" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const ( + specEditorLegacy = "legacy" + specEditorExperimental = "experimental" +) + +// componentCommandOptions are shared by component subcommands that edit specs. +type componentCommandOptions struct { + SpecEditor spec.EditorMode +} + +func (o componentCommandOptions) specEditorMode() spec.EditorMode { + if o.SpecEditor == "" { + return spec.EditorLegacy + } + + return o.SpecEditor +} + +type specEditorFlagValue struct { + mode spec.EditorMode +} + +var _ pflag.Value = (*specEditorFlagValue)(nil) + +func newSpecEditorFlagValue() *specEditorFlagValue { + return &specEditorFlagValue{mode: spec.EditorLegacy} +} + +func (v *specEditorFlagValue) String() string { + if v.mode == spec.EditorStructural { + return specEditorExperimental + } + + return specEditorLegacy +} + +func (v *specEditorFlagValue) Set(value string) error { + switch value { + case specEditorLegacy: + v.mode = spec.EditorLegacy + case specEditorExperimental: + v.mode = spec.EditorStructural + default: + return fmt.Errorf( + "unsupported RPM spec editor %#q; expected %#q or %#q", + value, specEditorLegacy, specEditorExperimental, + ) + } + + return nil +} + +func (v *specEditorFlagValue) Type() string { + return "editor" +} + +func addSpecEditorOption(cmd *cobra.Command) { + cmd.PersistentFlags().Var( + newSpecEditorFlagValue(), + "spec-editor", + "Select the RPM spec editor (legacy or experimental)", + ) +} + +func specEditorFromCommand(cmd *cobra.Command) spec.EditorMode { + flag := cmd.Flags().Lookup("spec-editor") + if flag == nil { + return spec.EditorLegacy + } + + value, ok := flag.Value.(*specEditorFlagValue) + if !ok { + return spec.EditorLegacy + } + + return value.mode +} diff --git a/internal/app/azldev/cmds/component/speceditor_internal_test.go b/internal/app/azldev/cmds/component/speceditor_internal_test.go new file mode 100644 index 000000000..f85125336 --- /dev/null +++ b/internal/app/azldev/cmds/component/speceditor_internal_test.go @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +package component + +import ( + "testing" + + "github.com/microsoft/azure-linux-dev-tools/internal/rpm/spec" + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestComponentCommandOptionsDefaultsToLegacy(t *testing.T) { + assert.Equal(t, spec.EditorLegacy, componentCommandOptions{}.specEditorMode()) +} + +func TestSpecEditorOptionDefaultsToLegacy(t *testing.T) { + editor, err := executeSpecEditorTestCommand(t, "render") + + require.NoError(t, err) + assert.Equal(t, spec.EditorLegacy, editor) +} + +func TestSpecEditorOptionParsesLegacy(t *testing.T) { + editor, err := executeSpecEditorTestCommand(t, "render", "--spec-editor", specEditorLegacy) + + require.NoError(t, err) + assert.Equal(t, spec.EditorLegacy, editor) +} + +func TestSpecEditorOptionParsesExperimental(t *testing.T) { + editor, err := executeSpecEditorTestCommand(t, "render", "--spec-editor", specEditorExperimental) + + require.NoError(t, err) + assert.Equal(t, spec.EditorStructural, editor) +} + +func TestSpecEditorOptionDoesNotLeakBetweenCommands(t *testing.T) { + experimental, err := executeSpecEditorTestCommand(t, "render", "--spec-editor", specEditorExperimental) + require.NoError(t, err) + assert.Equal(t, spec.EditorStructural, experimental) + + legacy, err := executeSpecEditorTestCommand(t, "render") + require.NoError(t, err) + assert.Equal(t, spec.EditorLegacy, legacy) +} + +func TestSpecEditorOptionRejectsUnsupportedValuesWithoutFallback(t *testing.T) { + executed := false + root := &cobra.Command{Use: "component"} + addSpecEditorOption(root) + root.AddCommand(&cobra.Command{ + Use: "render", + RunE: func(_ *cobra.Command, _ []string) error { + executed = true + + return nil + }, + }) + root.SetArgs([]string{"render", "--spec-editor", "structural"}) + + err := root.Execute() + + require.Error(t, err) + require.ErrorContains(t, err, "unsupported RPM spec editor `structural`; expected `legacy` or `experimental`") + assert.False(t, executed) +} + +func TestSpecEditorOptionRoutesToRelevantComponentCommands(t *testing.T) { + for _, command := range []string{"render", "build", "prepare-sources", "diff-sources"} { + t.Run(command, func(t *testing.T) { + editor, err := executeSpecEditorTestCommand(t, command, "--spec-editor", specEditorExperimental) + + require.NoError(t, err) + assert.Equal(t, spec.EditorStructural, editor) + }) + } +} + +func executeSpecEditorTestCommand(t *testing.T, command string, args ...string) (spec.EditorMode, error) { + t.Helper() + + var editor spec.EditorMode + + root := &cobra.Command{Use: "component"} + addSpecEditorOption(root) + root.AddCommand(&cobra.Command{ + Use: command, + RunE: func(cmd *cobra.Command, _ []string) error { + editor = specEditorFromCommand(cmd) + + return nil + }, + }) + root.SetArgs(append([]string{command}, args...)) + + return editor, root.Execute() +} diff --git a/scenario/__snapshots__/TestMCPServerMode_1.snap.json b/scenario/__snapshots__/TestMCPServerMode_1.snap.json index 02459314b..22c56748e 100755 --- a/scenario/__snapshots__/TestMCPServerMode_1.snap.json +++ b/scenario/__snapshots__/TestMCPServerMode_1.snap.json @@ -83,6 +83,10 @@ "description": "only enable minimal output", "type": "boolean" }, + "spec-editor": { + "description": "Select the RPM spec editor (legacy or experimental)", + "type": "string" + }, "spec-path": { "description": "Spec path", "type": "string" @@ -185,6 +189,10 @@ "description": "skip lock file consistency checks", "type": "boolean" }, + "spec-editor": { + "description": "Select the RPM spec editor (legacy or experimental)", + "type": "string" + }, "spec-path": { "description": "Spec path", "type": "string" @@ -280,6 +288,10 @@ "description": "How to report rows for components that share a TOML file with others: show (keep row, count is coarse), omit (drop row).", "type": "string" }, + "spec-editor": { + "description": "Select the RPM spec editor (legacy or experimental)", + "type": "string" + }, "spec-path": { "description": "Spec path", "type": "string" @@ -365,6 +377,10 @@ "description": "only enable minimal output", "type": "boolean" }, + "spec-editor": { + "description": "Select the RPM spec editor (legacy or experimental)", + "type": "string" + }, "spec-path": { "description": "Spec path", "type": "string"