From 6e28094ab3ac9cbbd2a132500103c961f6ba040d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 03:54:06 +0000 Subject: [PATCH 1/3] Initial plan From 96a67b03abeefd88cd3ac9ea42ae8f9f3da3579e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 03:59:35 +0000 Subject: [PATCH 2/3] chore: initial plan for run command input improvements Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/release.lock.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 13f87d03054..6ef2e6246ac 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -23,7 +23,7 @@ # # Build, test, and release gh-aw extension, then generate and prepend release highlights # -# gh-aw-metadata: {"schema_version":"v2","frontmatter_hash":"1ccf2823ac9575a51b506e9740499861d2c0506df37325368f5ef93408b4e946","strict":true} +# gh-aw-metadata: {"schema_version":"v2","frontmatter_hash":"b918f755e5c3b4dc485791181f519e9049725493a23f4fda44af27dadb5982d1","strict":true} name: "Release" "on": From 1465f1c5c05c0a5cc3be17670b1bf59bc69ba9c3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 04:07:52 +0000 Subject: [PATCH 3/3] feat: improve run command output for missing workflow inputs - Show `gh aw run -F =` syntax hint in error - Ignore required inputs that have a default value (treat as optional) - Show default values in the valid inputs list - Sort inputs alphabetically in valid inputs display - Add tests for new behavior including negative assertions Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/run_input_validation_test.go | 64 +++++++++++++++++++++++++--- pkg/cli/run_workflow_validation.go | 33 +++++++++++--- 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/pkg/cli/run_input_validation_test.go b/pkg/cli/run_input_validation_test.go index a7b774ca035..c07f1b36da2 100644 --- a/pkg/cli/run_input_validation_test.go +++ b/pkg/cli/run_input_validation_test.go @@ -116,11 +116,12 @@ jobs: func TestValidateWorkflowInputs(t *testing.T) { tests := []struct { - name string - lockContent string - providedInputs []string - expectError bool - errorContains []string // strings that should be in the error message + name string + lockContent string + providedInputs []string + expectError bool + errorContains []string // strings that should be in the error message + errorNotContains []string // strings that should NOT be in the error message }{ { name: "all required inputs provided", @@ -159,7 +160,53 @@ jobs: `, providedInputs: []string{}, expectError: true, - errorContains: []string{"Missing required input(s)", "issue_url"}, + errorContains: []string{"Missing required input(s)", "issue_url", "gh aw run test-workflow -F issue_url="}, + }, + { + name: "required input with default value - should not error when missing", + lockContent: `name: "Test Workflow" +on: + workflow_dispatch: + inputs: + release_type: + description: 'Release type' + required: true + default: patch + type: string +jobs: + test: + runs-on: ubuntu-latest + steps: + - run: echo "test" +`, + providedInputs: []string{}, + expectError: false, + }, + { + name: "required input with default shown in valid inputs list", + lockContent: `name: "Test Workflow" +on: + workflow_dispatch: + inputs: + missing_required: + description: 'Must be set' + required: true + type: string + defaulted: + description: 'Has a default' + required: true + default: patch + type: string +jobs: + test: + runs-on: ubuntu-latest + steps: + - run: echo "test" +`, + providedInputs: []string{}, + expectError: true, + errorContains: []string{"Missing required input(s)", "missing_required", "default: patch"}, + errorNotContains: []string{"gh aw run test-workflow -F defaulted="}, }, { name: "typo in input name", @@ -290,6 +337,11 @@ jobs: t.Errorf("Expected error to contain '%s', but got: %s", expected, errStr) } } + for _, notExpected := range tt.errorNotContains { + if strings.Contains(errStr, notExpected) { + t.Errorf("Expected error NOT to contain '%s', but got: %s", notExpected, errStr) + } + } } } else { if err != nil { diff --git a/pkg/cli/run_workflow_validation.go b/pkg/cli/run_workflow_validation.go index b9d8bf3dc09..b768065d8b9 100644 --- a/pkg/cli/run_workflow_validation.go +++ b/pkg/cli/run_workflow_validation.go @@ -186,10 +186,10 @@ func validateWorkflowInputs(markdownPath string, providedInputs []string) error } } - // Check for required inputs that are missing + // Check for required inputs that are missing (ignore inputs with a default value) var missingInputs []string for inputName, inputDef := range workflowInputs { - if inputDef.Required { + if inputDef.Required && inputDef.Default == nil { if _, exists := providedInputsMap[inputName]; !exists { missingInputs = append(missingInputs, inputName) } @@ -231,18 +231,39 @@ func validateWorkflowInputs(markdownPath string, providedInputs []string) error // Add helpful information about valid inputs if len(workflowInputs) > 0 { var inputDescriptions []string - for name, def := range workflowInputs { + sortedNames := slices.Sorted(maps.Keys(workflowInputs)) + for _, name := range sortedNames { + def := workflowInputs[name] required := "" - if def.Required { + if def.Required && def.Default == nil { required = " (required)" } desc := "" if def.Description != "" { desc = ": " + def.Description } - inputDescriptions = append(inputDescriptions, fmt.Sprintf(" %s%s%s", name, required, desc)) + defaultStr := "" + if def.Default != nil { + defaultStr = fmt.Sprintf(" [default: %s]", def.GetDefaultAsString()) + } + inputDescriptions = append(inputDescriptions, fmt.Sprintf(" %s%s%s%s", name, required, desc, defaultStr)) + } + + // Derive the workflow name for the syntax hint + workflowName := strings.TrimSuffix(filepath.Base(markdownPath), ".md") + var syntaxExamples []string + for _, name := range sortedNames { + def := workflowInputs[name] + if def.Required && def.Default == nil { + syntaxExamples = append(syntaxExamples, fmt.Sprintf(" gh aw run %s -F %s=", workflowName, name)) + } + } + + validInputsMsg := "\nValid inputs:\n" + strings.Join(inputDescriptions, "\n") + if len(syntaxExamples) > 0 { + validInputsMsg += "\n\nTo set required inputs, use:\n" + strings.Join(syntaxExamples, "\n") } - errorParts = append(errorParts, "\nValid inputs:\n"+strings.Join(inputDescriptions, "\n")) + errorParts = append(errorParts, validInputsMsg) } return fmt.Errorf("%s", strings.Join(errorParts, "\n\n"))