From 4749595316acfff7838541b6e173cf207ea94c42 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Jun 2026 23:25:46 +0000 Subject: [PATCH 1/3] Review and document --action-tag and --gh-aw-ref: fix help texts, add mutual exclusivity Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- cmd/gh-aw/main.go | 40 +++++++++++++++++++++++++++---- pkg/cli/compile_compiler_setup.go | 20 ++++++++++------ pkg/cli/compile_config.go | 4 ++-- pkg/cli/compile_validation.go | 2 +- 4 files changed, 52 insertions(+), 14 deletions(-) diff --git a/cmd/gh-aw/main.go b/cmd/gh-aw/main.go index d9a47544516..ca03915e3fe 100644 --- a/cmd/gh-aw/main.go +++ b/cmd/gh-aw/main.go @@ -249,6 +249,32 @@ The --dependabot flag generates dependency manifests when dependencies are detec - Cannot be used with specific workflow files or custom --dir - Only processes workflows in the default .github/workflows directory +Action mode controls how gh-aw action scripts are referenced in compiled workflows. +Three flags govern this and only one should be used at a time: + + --action-mode + Explicit mode selection. Values: + dev Local paths (./actions/...). For developing inside the gh-aw repo. + release SHA-pinned refs from github/gh-aw (e.g. github/gh-aw/actions/setup@). + The SHA is derived from the binary version or from --action-tag. + action SHA-pinned refs from the github/gh-aw-actions repository. + Used by release binaries. Can be combined with --action-tag to pin a version. + Auto-detected from the binary build type when not set. + + --action-tag + Pin to a specific SHA or version tag (e.g. v1, v1.2.3, abc123...). + Implies --action-mode release unless --action-mode action is also specified. + The value is used as-is; branch names are NOT resolved. Use --gh-aw-ref to + pin to a branch by resolving it to its current commit SHA first. + + --gh-aw-ref + Resolve a branch name, tag, or SHA from github/gh-aw to its full commit SHA + at compile time and pin the compiled workflow to that immutable SHA. + Equivalent to --action-mode release --action-tag . + Branch and tag names are resolved via the GitHub API. + Cannot be combined with --action-tag or --action-mode. + Use this when E2E-testing compiled workflows against a specific gh-aw revision. + Examples: ` + string(constants.CLIExtensionPrefix) + ` compile # Compile all Markdown files ` + string(constants.CLIExtensionPrefix) + ` compile ci-doctor # Compile a specific workflow @@ -259,7 +285,9 @@ Examples: ` + string(constants.CLIExtensionPrefix) + ` compile --watch ci-doctor # Watch and auto-compile ` + string(constants.CLIExtensionPrefix) + ` compile --trial --logical-repo owner/repo # Compile for trial mode ` + string(constants.CLIExtensionPrefix) + ` compile --dependabot # Generate Dependabot manifests - ` + string(constants.CLIExtensionPrefix) + ` compile --dependabot --force # Force overwrite existing dependabot.yml`, + ` + string(constants.CLIExtensionPrefix) + ` compile --dependabot --force # Force overwrite existing dependabot.yml + ` + string(constants.CLIExtensionPrefix) + ` compile --gh-aw-ref main # Pin workflows to current HEAD of github/gh-aw main + ` + string(constants.CLIExtensionPrefix) + ` compile --action-tag v1.2.3 # Pin workflows to a specific release tag`, RunE: func(cmd *cobra.Command, args []string) error { engineOverride, _ := cmd.Flags().GetString("engine") actionMode, _ := cmd.Flags().GetString("action-mode") @@ -697,10 +725,10 @@ Use "` + string(constants.CLIExtensionPrefix) + ` help all" to show help for all // Add AI flag to compile and add commands compileCmd.Flags().StringP("engine", "e", "", "Override AI engine (copilot, claude, codex, gemini, crush)") - compileCmd.Flags().String("action-mode", "", "Action script inlining mode (inline, dev, release). Auto-detected if not specified") - compileCmd.Flags().String("action-tag", "", "Override action SHA or tag for actions/setup (overrides action-mode to release). Accepts full SHA or tag name") + compileCmd.Flags().String("action-mode", "", "How gh-aw action scripts are referenced in compiled workflows: 'dev' uses local paths (for developing gh-aw itself), 'release' emits SHA-pinned remote refs from github/gh-aw, 'action' uses the github/gh-aw-actions repository. Auto-detected from the binary build type if not specified") + compileCmd.Flags().String("action-tag", "", "Pin compiled workflows to a specific version of gh-aw actions. Accepts a full 40-character commit SHA or a version tag (e.g. v1, v1.2.3). Sets --action-mode to 'release' unless --action-mode action is also specified. Cannot be combined with --gh-aw-ref; use --gh-aw-ref when you want to resolve a branch or tag name to its current SHA") compileCmd.Flags().String("actions-repo", "", "Override the external actions repository used in action mode (default: github/gh-aw-actions)") - compileCmd.Flags().String("gh-aw-ref", "", "Compile workflows to reference github/gh-aw at the given branch, tag, or SHA (e.g. main, my-feature, abc123). Branch and tag names are resolved to their commit SHA at compile time so the baked-in ref is immutable. Convenience alias for --action-mode release --action-tag . Use this to E2E-test workflows compiled by an external repo against a specific gh-aw revision.") + compileCmd.Flags().String("gh-aw-ref", "", "Pin compiled workflows to a specific branch, tag, or commit SHA of github/gh-aw (e.g. main, my-feature, abc123). Branch and tag names are resolved to their full commit SHA at compile time so the baked-in ref is immutable. Equivalent to --action-mode release --action-tag . Cannot be combined with --action-tag or --action-mode. Use this to E2E-test workflows against a specific gh-aw revision") compileCmd.Flags().Bool("validate", false, "Enable GitHub Actions workflow schema validation, container image validation, and action SHA validation") compileCmd.Flags().BoolP("watch", "w", false, "Watch for changes to workflow files and recompile automatically") compileCmd.Flags().StringP("dir", "d", "", "Workflow directory (default: .github/workflows)") @@ -739,6 +767,10 @@ Use "` + string(constants.CLIExtensionPrefix) + ` help all" to show help for all _ = err } compileCmd.MarkFlagsMutuallyExclusive("dir", "workflows-dir") + // --gh-aw-ref is a convenience alias for --action-mode release --action-tag ; + // combining it with either of those flags leads to one silently overwriting the other. + compileCmd.MarkFlagsMutuallyExclusive("gh-aw-ref", "action-tag") + compileCmd.MarkFlagsMutuallyExclusive("gh-aw-ref", "action-mode") // Register completions for compile command compileCmd.ValidArgsFunction = cli.CompleteWorkflowNames diff --git a/pkg/cli/compile_compiler_setup.go b/pkg/cli/compile_compiler_setup.go index f5853e752ec..6cdc88fed3b 100644 --- a/pkg/cli/compile_compiler_setup.go +++ b/pkg/cli/compile_compiler_setup.go @@ -19,7 +19,7 @@ // // Configuration: // - configureCompilerFlags() - Sets validation, strict mode, trial mode flags -// - setupActionMode() - Configures action script inlining mode +// - setupActionMode() - Configures how gh-aw action scripts are referenced (--action-mode / --action-tag / --gh-aw-ref) // - setupRepositoryContext() - Sets repository slug for schedule scattering // // These functions abstract compiler setup, allowing the main compile @@ -195,14 +195,20 @@ func configureCompilerFlags(compiler *workflow.Compiler, config CompileConfig) { } } -// setupActionMode configures the action script inlining mode +// setupActionMode configures how gh-aw action scripts are referenced in compiled workflows. +// Priority order when both actionTag and actionMode are provided (after --gh-aw-ref resolution): +// - actionTag != "" → pin to that SHA/tag; use ActionModeRelease unless actionMode is explicitly "action" +// - actionMode != "" → honour the explicit mode +// - neither set → auto-detect from the binary build type via DetectActionMode func setupActionMode(compiler *workflow.Compiler, actionMode string, actionTag string) { compileCompilerSetupLog.Printf("Setting up action mode: %s, actionTag: %s", actionMode, actionTag) - // If actionTag is specified, it pins the version used in action/release references. - // When --action-mode action is explicitly set alongside --action-tag, honour the explicit - // action mode so that the external actions repo (--actions-repo) is also respected. - // Without an explicit action mode, --action-tag still defaults to release mode (original behaviour). + // --action-tag pins the version used in action/release references. + // When --action-mode action is also explicitly set, honour it so that the + // external actions repo (--actions-repo) is respected too. + // Otherwise --action-tag implies release mode. + // Note: --gh-aw-ref is mutually exclusive with both flags and resolves to a + // full SHA before calling this function, so there is no double-set risk here. if actionTag != "" { compiler.SetActionTag(actionTag) if actionMode == string(workflow.ActionModeAction) { @@ -210,7 +216,7 @@ func setupActionMode(compiler *workflow.Compiler, actionMode string, actionTag s compiler.SetActionMode(workflow.ActionModeAction) compileCompilerSetupLog.Printf("Action mode set to: action with tag/SHA: %s", actionTag) } else { - compileCompilerSetupLog.Printf("--action-tag specified (%s), overriding to release mode", actionTag) + compileCompilerSetupLog.Printf("--action-tag specified (%s), defaulting to release mode", actionTag) compiler.SetActionMode(workflow.ActionModeRelease) compileCompilerSetupLog.Printf("Action mode set to: release with tag/SHA: %s", actionTag) } diff --git a/pkg/cli/compile_config.go b/pkg/cli/compile_config.go index 901c3ccb27e..55495bd3ecd 100644 --- a/pkg/cli/compile_config.go +++ b/pkg/cli/compile_config.go @@ -27,8 +27,8 @@ type CompileConfig struct { RunnerGuard bool // Run runner-guard taint analysis scanner on generated .lock.yml files JSONOutput bool // Output validation results as JSON ShowAllErrors bool // Display all prioritized errors instead of the default top five - ActionMode string // Action script inlining mode: inline, dev, or release - ActionTag string // Override action SHA or tag for actions/setup (overrides action-mode to release) + ActionMode string // Action script inlining mode: dev, release, or action. Auto-detected if empty. + ActionTag string // Pin action refs to this SHA or version tag (e.g. v1, abc123…). Sets release mode unless ActionMode is already "action". Mutually exclusive with GHAwRef at the CLI layer. ActionsRepo string // Override the external actions repository (default: github/gh-aw-actions) Stats bool // Display statistics table sorted by file size FailFast bool // Stop at first error instead of collecting all errors diff --git a/pkg/cli/compile_validation.go b/pkg/cli/compile_validation.go index 94573bd4efc..073b1329c3b 100644 --- a/pkg/cli/compile_validation.go +++ b/pkg/cli/compile_validation.go @@ -228,7 +228,7 @@ func validateActionModeConfig(actionMode string) error { mode := workflow.ActionMode(actionMode) if !mode.IsValid() { - return fmt.Errorf("invalid action mode '%s'. Must be 'dev', 'release', 'script', or 'action'", actionMode) + return fmt.Errorf("invalid action mode '%s'. Must be 'dev', 'release', or 'action'", actionMode) } return nil From 6d976c63b285dbfd30fcd1e244ae8e87ae84ce50 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Jun 2026 23:26:34 +0000 Subject: [PATCH 2/3] Use lowercase 'not' for consistent documentation style Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- cmd/gh-aw/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gh-aw/main.go b/cmd/gh-aw/main.go index ca03915e3fe..42f41144cae 100644 --- a/cmd/gh-aw/main.go +++ b/cmd/gh-aw/main.go @@ -264,7 +264,7 @@ Three flags govern this and only one should be used at a time: --action-tag Pin to a specific SHA or version tag (e.g. v1, v1.2.3, abc123...). Implies --action-mode release unless --action-mode action is also specified. - The value is used as-is; branch names are NOT resolved. Use --gh-aw-ref to + The value is used as-is; branch names are not resolved. Use --gh-aw-ref to pin to a branch by resolving it to its current commit SHA first. --gh-aw-ref From d11d8c027f69dee8021ebb459e74813d3f714fac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 01:22:49 +0000 Subject: [PATCH 3/3] fix compile flag/docs consistency and add mutual-exclusion regression test Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- cmd/gh-aw/main.go | 7 ++++--- cmd/gh-aw/main_help_text_test.go | 29 +++++++++++++++++++++++++++++ pkg/cli/compile_compiler_setup.go | 8 ++++---- pkg/cli/compile_config.go | 4 ++-- pkg/cli/compile_validation.go | 2 ++ 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/cmd/gh-aw/main.go b/cmd/gh-aw/main.go index 42f41144cae..6e4625c467f 100644 --- a/cmd/gh-aw/main.go +++ b/cmd/gh-aw/main.go @@ -250,7 +250,8 @@ The --dependabot flag generates dependency manifests when dependencies are detec - Only processes workflows in the default .github/workflows directory Action mode controls how gh-aw action scripts are referenced in compiled workflows. -Three flags govern this and only one should be used at a time: +Three flags govern this. --gh-aw-ref is mutually exclusive with the other two; +--action-tag and --action-mode may be combined (e.g. --action-mode action --action-tag v1.2.3): --action-mode Explicit mode selection. Values: @@ -262,7 +263,7 @@ Three flags govern this and only one should be used at a time: Auto-detected from the binary build type when not set. --action-tag - Pin to a specific SHA or version tag (e.g. v1, v1.2.3, abc123...). + Pin to a specific SHA or version tag (e.g. v1, v1.2.3, ). Implies --action-mode release unless --action-mode action is also specified. The value is used as-is; branch names are not resolved. Use --gh-aw-ref to pin to a branch by resolving it to its current commit SHA first. @@ -726,7 +727,7 @@ Use "` + string(constants.CLIExtensionPrefix) + ` help all" to show help for all // Add AI flag to compile and add commands compileCmd.Flags().StringP("engine", "e", "", "Override AI engine (copilot, claude, codex, gemini, crush)") compileCmd.Flags().String("action-mode", "", "How gh-aw action scripts are referenced in compiled workflows: 'dev' uses local paths (for developing gh-aw itself), 'release' emits SHA-pinned remote refs from github/gh-aw, 'action' uses the github/gh-aw-actions repository. Auto-detected from the binary build type if not specified") - compileCmd.Flags().String("action-tag", "", "Pin compiled workflows to a specific version of gh-aw actions. Accepts a full 40-character commit SHA or a version tag (e.g. v1, v1.2.3). Sets --action-mode to 'release' unless --action-mode action is also specified. Cannot be combined with --gh-aw-ref; use --gh-aw-ref when you want to resolve a branch or tag name to its current SHA") + compileCmd.Flags().String("action-tag", "", "Pin compiled workflows to a specific version of gh-aw actions. Accepts a full commit SHA or a version tag (e.g. v1, v1.2.3). Sets --action-mode to 'release' unless --action-mode action is also specified. Cannot be combined with --gh-aw-ref; use --gh-aw-ref when you want to resolve a branch or tag name to its current SHA") compileCmd.Flags().String("actions-repo", "", "Override the external actions repository used in action mode (default: github/gh-aw-actions)") compileCmd.Flags().String("gh-aw-ref", "", "Pin compiled workflows to a specific branch, tag, or commit SHA of github/gh-aw (e.g. main, my-feature, abc123). Branch and tag names are resolved to their full commit SHA at compile time so the baked-in ref is immutable. Equivalent to --action-mode release --action-tag . Cannot be combined with --action-tag or --action-mode. Use this to E2E-test workflows against a specific gh-aw revision") compileCmd.Flags().Bool("validate", false, "Enable GitHub Actions workflow schema validation, container image validation, and action SHA validation") diff --git a/cmd/gh-aw/main_help_text_test.go b/cmd/gh-aw/main_help_text_test.go index c8492a88cef..6df80690702 100644 --- a/cmd/gh-aw/main_help_text_test.go +++ b/cmd/gh-aw/main_help_text_test.go @@ -38,3 +38,32 @@ func TestCompileShowAllFlagHelpText(t *testing.T) { require.NotNil(t, showAllFlag, "compile command should define --show-all") assert.Equal(t, "Display all prioritized compilation errors instead of the default top five", showAllFlag.Usage) } + +func TestCompileGhAwRefMutuallyExclusiveFlags(t *testing.T) { + tests := []struct { + name string + args []string + }{ + { + name: "gh-aw-ref with action-tag", + args: []string{"compile", "--gh-aw-ref", "main", "--action-tag", "v1.2.3"}, + }, + { + name: "gh-aw-ref with action-mode", + args: []string{"compile", "--gh-aw-ref", "main", "--action-mode", "dev"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rootCmd.SetArgs(tt.args) + t.Cleanup(func() { + rootCmd.SetArgs([]string{}) + }) + + err := rootCmd.Execute() + require.Error(t, err) + assert.Contains(t, err.Error(), "if any flags in the group", "expected mutually exclusive flag-group error") + }) + } +} diff --git a/pkg/cli/compile_compiler_setup.go b/pkg/cli/compile_compiler_setup.go index 6cdc88fed3b..0a21397c7ad 100644 --- a/pkg/cli/compile_compiler_setup.go +++ b/pkg/cli/compile_compiler_setup.go @@ -196,10 +196,10 @@ func configureCompilerFlags(compiler *workflow.Compiler, config CompileConfig) { } // setupActionMode configures how gh-aw action scripts are referenced in compiled workflows. -// Priority order when both actionTag and actionMode are provided (after --gh-aw-ref resolution): -// - actionTag != "" → pin to that SHA/tag; use ActionModeRelease unless actionMode is explicitly "action" -// - actionMode != "" → honour the explicit mode -// - neither set → auto-detect from the binary build type via DetectActionMode +// Priority order (after --gh-aw-ref resolution): +// - actionTag != "" → pin to that SHA/tag; use ActionModeRelease unless actionMode is explicitly "action" +// - actionTag == "" && actionMode != "" → honour the explicit mode +// - neither set → auto-detect from the binary build type via DetectActionMode func setupActionMode(compiler *workflow.Compiler, actionMode string, actionTag string) { compileCompilerSetupLog.Printf("Setting up action mode: %s, actionTag: %s", actionMode, actionTag) diff --git a/pkg/cli/compile_config.go b/pkg/cli/compile_config.go index 55495bd3ecd..a0eeb6ecae9 100644 --- a/pkg/cli/compile_config.go +++ b/pkg/cli/compile_config.go @@ -27,8 +27,8 @@ type CompileConfig struct { RunnerGuard bool // Run runner-guard taint analysis scanner on generated .lock.yml files JSONOutput bool // Output validation results as JSON ShowAllErrors bool // Display all prioritized errors instead of the default top five - ActionMode string // Action script inlining mode: dev, release, or action. Auto-detected if empty. - ActionTag string // Pin action refs to this SHA or version tag (e.g. v1, abc123…). Sets release mode unless ActionMode is already "action". Mutually exclusive with GHAwRef at the CLI layer. + ActionMode string // How action scripts are referenced: dev, release, or action. Auto-detected if empty. + ActionTag string // Pin action refs to this SHA or version tag (e.g. v1, ). Sets release mode unless ActionMode is already "action". Mutually exclusive with GHAwRef at the CLI layer. ActionsRepo string // Override the external actions repository (default: github/gh-aw-actions) Stats bool // Display statistics table sorted by file size FailFast bool // Stop at first error instead of collecting all errors diff --git a/pkg/cli/compile_validation.go b/pkg/cli/compile_validation.go index 073b1329c3b..fe79d0f991b 100644 --- a/pkg/cli/compile_validation.go +++ b/pkg/cli/compile_validation.go @@ -228,6 +228,8 @@ func validateActionModeConfig(actionMode string) error { mode := workflow.ActionMode(actionMode) if !mode.IsValid() { + // ActionModeScript is intentionally excluded from this user-facing error: + // it remains internal and is not advertised as a CLI-supported mode. return fmt.Errorf("invalid action mode '%s'. Must be 'dev', 'release', or 'action'", actionMode) }