-
Notifications
You must be signed in to change notification settings - Fork 482
Fix trial forwarding issue_number to workflows that don't declare it #50638
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
a78bcb7
2cad206
e5b2819
1806365
cfb3da6
a8cf5dd
4bf44f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,7 @@ import ( | |
| "github.com/github/gh-aw/pkg/sliceutil" | ||
| "github.com/github/gh-aw/pkg/stringutil" | ||
| "github.com/github/gh-aw/pkg/workflow" | ||
| "github.com/goccy/go-yaml" | ||
| ) | ||
|
|
||
| // issuePathPattern matches the path portion of a GitHub issue URL: /owner/repo/issues/NUMBER | ||
|
|
@@ -84,7 +85,8 @@ func executeTrialRun(ctx context.Context, parsedSpecs []*WorkflowSpec, hostRepoS | |
| } | ||
|
|
||
| // Run the workflow and wait for completion (with trigger context if provided) | ||
| runID, err := triggerWorkflowRun(hostRepoSlug, parsedSpec.WorkflowName, opts.TriggerContext, opts.Verbose) | ||
| lockFilePath := filepath.Join(tempDir, constants.GetWorkflowDir(), parsedSpec.WorkflowName+".lock.yml") | ||
| runID, err := triggerWorkflowRun(hostRepoSlug, parsedSpec.WorkflowName, lockFilePath, opts.TriggerContext, opts.Verbose) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to trigger workflow run for '%s': %w", parsedSpec.WorkflowName, err) | ||
| } | ||
|
|
@@ -189,7 +191,7 @@ func executeTrialRun(ctx context.Context, parsedSpecs []*WorkflowSpec, hostRepoS | |
| return nil | ||
| } | ||
|
|
||
| func triggerWorkflowRun(repoSlug, workflowName string, triggerContext string, verbose bool) (string, error) { | ||
| func triggerWorkflowRun(repoSlug, workflowName, lockFilePath string, triggerContext string, verbose bool) (string, error) { | ||
| trialLog.Printf("Triggering workflow run: workflow=%s, repo=%s, hasTriggerContext=%v", workflowName, repoSlug, triggerContext != "") | ||
| if verbose { | ||
| fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Triggering workflow run for: "+workflowName)) | ||
|
|
@@ -201,13 +203,19 @@ func triggerWorkflowRun(repoSlug, workflowName string, triggerContext string, ve | |
| // Build the command args | ||
| args := []string{"workflow", "run", lockFileName, "--repo", repoSlug} | ||
|
|
||
| // If trigger context is provided, extract issue number and add it as input | ||
| // If trigger context is provided, extract issue number and add it as input. | ||
| // Only forward the input when the compiled workflow declares an "issue_number" | ||
| // workflow_dispatch input; otherwise gh returns HTTP 422 and the run is skipped. | ||
| if triggerContext != "" { | ||
| issueNumber := parseIssueSpec(triggerContext) | ||
| if issueNumber != "" { | ||
| args = append(args, "--field", "issue_number="+issueNumber) | ||
| if verbose { | ||
| fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Using issue number %s from trigger context", issueNumber))) | ||
| if workflowDeclaresDispatchInput(lockFilePath, "issue_number") { | ||
| args = append(args, "--field", "issue_number="+issueNumber) | ||
| if verbose { | ||
| fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Using issue number %s from trigger context", issueNumber))) | ||
| } | ||
| } else if verbose { | ||
| fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Workflow '%s' does not declare an issue_number input, running without trigger context", workflowName))) | ||
| } | ||
| } else if verbose { | ||
| fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Could not extract issue number from trigger context, running without inputs")) | ||
|
|
@@ -269,7 +277,32 @@ func parseIssueSpec(input string) string { | |
| return "" | ||
| } | ||
|
|
||
| // saveTrialResult saves a trial result to a JSON file | ||
| // workflowDeclaresDispatchInput reports whether the compiled lock file at lockFilePath | ||
| // declares the given workflow_dispatch input. It returns false if the file cannot be | ||
| // read or parsed, so that trigger-derived inputs are not forwarded to workflows whose | ||
| // workflow_dispatch schema does not declare them (which would cause an HTTP 422). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Swallowing read/parse errors as 💡 Details
Consider distinguishing "file not found" (arguably fine to fail-safe) from parse errors on an existing file (should probably surface a warning to the user even outside verbose mode, since it indicates a compiler/format problem). if verbose || err != nil {
fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Could not parse lock file %s: %v", lockFilePath, err)))
} |
||
| func workflowDeclaresDispatchInput(lockFilePath, inputName string) bool { | ||
| content, err := os.ReadFile(lockFilePath) | ||
| if err != nil { | ||
| trialLog.Printf("Failed to read lock file %s: %v", lockFilePath, err) | ||
| return false | ||
| } | ||
|
|
||
| var parsed struct { | ||
| On struct { | ||
| WorkflowDispatch struct { | ||
| Inputs map[string]any `yaml:"inputs"` | ||
| } `yaml:"workflow_dispatch"` | ||
| } `yaml:"on"` | ||
| } | ||
| if err := yaml.Unmarshal(content, &parsed); err != nil { | ||
| trialLog.Printf("Failed to parse lock file %s: %v", lockFilePath, err) | ||
| return false | ||
| } | ||
|
|
||
| _, ok := parsed.On.WorkflowDispatch.Inputs[inputName] | ||
| return ok | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| } | ||
| func saveTrialResult(filename string, result any, verbose bool) error { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [/diagnosing-bugs] The doc comment 💡 Suggested fixRestore the blank line and the comment: return ok
}
// saveTrialResult saves a trial result to a JSON file
func saveTrialResult(filename string, result any, verbose bool) error {@copilot please address this. |
||
| jsonBytes, err := json.MarshalIndent(result, "", " ") | ||
| if err != nil { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lockFileName(used to invokegh workflow run) and the caller'slockFilePath(used to inspect declared inputs) are built via two separate, unlinked expressions — a future edit to one path convention without the other will silently break input-forwarding decisions.