diff --git a/cmd/transform/transform.go b/cmd/transform/transform.go index 95080bcd..99eef938 100644 --- a/cmd/transform/transform.go +++ b/cmd/transform/transform.go @@ -214,6 +214,7 @@ func (o *Options) run() error { } var instructionStages []string + var instructionPluginStages []string var instructionStageOptionals map[string]map[string]string if o.InstructionsFile != "" { instructionsFilePath, err := filepath.Abs(o.InstructionsFile) @@ -226,7 +227,8 @@ func (o *Options) run() error { log.Errorf("Failed to load instructions file %q: %v", instructionsFilePath, err) return err } - instructionStages = internalTransform.GenerateStageDirNames(cfg.StageNames()) + instructionPluginStages = cfg.StageNames() + instructionStages = internalTransform.GenerateStageDirNames(instructionPluginStages) instructionStageOptionals, err = cfg.StageOptionals() if err != nil { return fmt.Errorf("invalid instructions file %q: %w", instructionsFilePath, err) @@ -290,7 +292,7 @@ func (o *Options) run() error { log.Errorf("Failed to reconcile instruction stages: %v", err) return err } - for _, stageName := range instructionStages { + for i, stageName := range instructionStages { stageDir := filepath.Join(transformDir, stageName) _, err := os.Stat(stageDir) stageExists := err == nil @@ -310,7 +312,9 @@ func (o *Options) run() error { Stages: []string{stageName}, } log.Infof("Running stage: %s", stageName) - if err := o.runStageWithCleanup(orchestrator, selector, stageDir, !stageExists, log); err != nil { + stageOrchestrator := *orchestrator + stageOrchestrator.StageOptionalFlags = stageOptionalsForPlugin(instructionStageOptionals, instructionPluginStages[i]) + if err := o.runStageWithCleanup(&stageOrchestrator, selector, stageDir, !stageExists, log); err != nil { log.Errorf("Failed to run stage %q: %v", stageName, err) return err } @@ -388,6 +392,16 @@ func (o *Options) run() error { return nil } +// stageOptionalsForPlugin restricts instruction optionals to the plugin being +// run because instructions stages are executed individually. +func stageOptionalsForPlugin(optionals map[string]map[string]string, pluginName string) map[string]map[string]string { + flags, ok := optionals[pluginName] + if !ok { + return nil + } + return map[string]map[string]string{pluginName: flags} +} + // parseStageOptionals parses --stage-optionals values from "StageName=JSON" format // into a map of stage name to optional flags. func parseStageOptionals(values []string) (map[string]map[string]string, error) { diff --git a/cmd/transform/transform_test.go b/cmd/transform/transform_test.go index 9e5bef98..e6614239 100644 --- a/cmd/transform/transform_test.go +++ b/cmd/transform/transform_test.go @@ -1253,6 +1253,63 @@ func TestRun_InstructionsFileAndStageOptionalsConflict(t *testing.T) { } } +func TestStageOptionalsForPlugin(t *testing.T) { + optionals := map[string]map[string]string{ + "KubernetesPlugin": {"strip-default-rbac": "true"}, + "OpenShiftPlugin": {"strip-default-cabundle": "true"}, + } + + tests := []struct { + name string + plugin string + expected map[string]map[string]string + }{ + { + name: "returns only KubernetesPlugin optionals", + plugin: "KubernetesPlugin", + expected: map[string]map[string]string{ + "KubernetesPlugin": {"strip-default-rbac": "true"}, + }, + }, + { + name: "returns only OpenShiftPlugin optionals", + plugin: "OpenShiftPlugin", + expected: map[string]map[string]string{ + "OpenShiftPlugin": {"strip-default-cabundle": "true"}, + }, + }, + { + name: "returns nil for stage without optionals", + plugin: "CustomEdits", + expected: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := stageOptionalsForPlugin(optionals, tt.plugin) + if len(got) != len(tt.expected) { + t.Fatalf("expected %d stage optionals, got %d: %v", len(tt.expected), len(got), got) + } + for stage, expectedFlags := range tt.expected { + gotFlags, ok := got[stage] + if !ok { + t.Errorf("missing optionals for stage %q", stage) + continue + } + if len(gotFlags) != len(expectedFlags) { + t.Errorf("stage %q: expected %d flags, got %d", stage, len(expectedFlags), len(gotFlags)) + } + for key, expectedValue := range expectedFlags { + if gotFlags[key] != expectedValue { + t.Errorf("stage %q flag %q: expected %q, got %q", stage, key, expectedValue, gotFlags[key]) + } + } + } + }) + } +} + func TestValidate_MissingExportDir_FailsBeforeRun(t *testing.T) { tmpDir := t.TempDir() transformDir := filepath.Join(tmpDir, "transform")