Conversation
When adding a scheduled workflow via `gh aw add-wizard`, the wizard now
detects the schedule trigger and offers a choice of standard frequencies:
hourly, every 3 hours, daily, weekly, or monthly.
- The form defaults to the workflow's existing schedule.
- Custom schedules (not matching a standard frequency) are shown as a
"Custom: <expr> (keep existing)" option which is the default.
- If the user selects the same frequency or "Custom", the frontmatter is
left unchanged.
- For multi-trigger workflows (schedule + other triggers), the selector is
skipped to avoid losing other triggers.
New files:
pkg/cli/add_interactive_schedule.go - detection & selection logic
pkg/cli/add_interactive_schedule_test.go - unit tests
Changed files:
pkg/cli/add_interactive_orchestrator.go - calls selectScheduleFrequency
as step 7b in RunAddInteractive
Co-authored-by: dsyme <7204669+dsyme@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds an “agentic workflow repo-assist” workflow and extends the interactive add flow with a schedule-frequency wizard to detect and optionally rewrite scheduled workflow frontmatter. Also adjusts PR creation scripting to harden context access and simplify footer/run URL generation.
Changes:
- Add schedule detection/classification + interactive schedule-frequency selection with unit tests.
- Wire the new schedule step into the interactive orchestrator.
- Add
repo-assistworkflow markdown and adjust PR creation JS (run URL building, permission-denied handling, footer inputs).
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/cli/add_interactive_schedule.go | Implements schedule detection/classification and an interactive frequency selector that updates workflow frontmatter. |
| pkg/cli/add_interactive_schedule_test.go | Adds tests covering schedule classification, detection, and option ordering/labels. |
| pkg/cli/add_interactive_orchestrator.go | Invokes the new schedule-frequency step during interactive add. |
| actions/setup/js/create_pull_request.cjs | Adjusts context guarding, run URL construction, footer generation inputs, and permission-denied behavior. |
| .github/workflows/repo-assist.md | Adds the new “repo-assist” agentic workflow definition and instructions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Update the workflow content in memory. | ||
| // For multi-trigger on: maps, update the "schedule" sub-field to preserve other triggers. | ||
| // For simple on: strings, update the "on" field directly. | ||
| updateField := "on" | ||
| if detection.IsMultiTrigger { | ||
| updateField = "schedule" | ||
| } | ||
| updatedContent, err := UpdateFieldInFrontmatter(content, updateField, newExpr) |
There was a problem hiding this comment.
When on: is a map (even if it only contains schedule + workflow_dispatch), updating updateField := \"on\" will replace the entire on: map with a string and drop workflow_dispatch (and any other keys). Also, setting updateField = \"schedule\" risks writing a top-level schedule key instead of updating on.schedule unless UpdateFieldInFrontmatter supports nested updates. Consider detecting whether on is a map and always updating the nested on.schedule value (preserving other triggers), e.g., by updating the parsed frontmatter structure and re-serializing, or by extending UpdateFieldInFrontmatter to accept a nested path like on.schedule.
| // Schedule as string shorthand (e.g., "schedule: daily") | ||
| if schedStr, ok := schedValue.(string); ok { | ||
| return scheduleDetection{ | ||
| RawExpr: schedStr, | ||
| Frequency: classifyScheduleFrequency(schedStr), | ||
| IsUpdatable: true, | ||
| IsMultiTrigger: isMultiTrigger, | ||
| } | ||
| } | ||
|
|
||
| // Schedule as array (e.g., "schedule:\n - cron: daily") | ||
| if schedArray, ok := schedValue.([]any); ok && len(schedArray) > 0 { | ||
| if item, ok := schedArray[0].(map[string]any); ok { | ||
| if cronVal, ok := item["cron"].(string); ok { | ||
| return scheduleDetection{ | ||
| RawExpr: cronVal, | ||
| Frequency: classifyScheduleFrequency(cronVal), | ||
| IsUpdatable: true, | ||
| IsMultiTrigger: isMultiTrigger, | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Unlike the on: <string> case (which validates via parser.ParseSchedule), the on: { schedule: ... } cases don’t validate that schedStr / cronVal are actually parseable schedules before marking the workflow as updatable. This can create false positives and offer the wizard for invalid/misconfigured values. Suggest mirroring the string-path behavior by calling parser.ParseSchedule (or an equivalent validator) before returning IsUpdatable: true for both the shorthand string and the cron: array forms.
| const runId = context.runId; | ||
| const githubServer = process.env.GITHUB_SERVER_URL || "https://github.com"; | ||
| const runUrl = context.payload.repository ? `${context.payload.repository.html_url}/actions/runs/${runId}` : `${githubServer}/${repoParts.owner}/${repoParts.repo}/actions/runs/${runId}`; |
There was a problem hiding this comment.
The run URL construction logic is duplicated. To reduce drift and keep edge-case handling consistent, extract this into a small helper (e.g., buildRunUrl(context, repoParts)), and reuse it in both places.
| const runId = context.runId; | ||
| const githubServer = process.env.GITHUB_SERVER_URL || "https://github.com"; | ||
| const runUrl = context.payload.repository ? `${context.payload.repository.html_url}/actions/runs/${runId}` : `${githubServer}/${repoParts.owner}/${repoParts.repo}/actions/runs/${runId}`; |
There was a problem hiding this comment.
The run URL construction logic is duplicated. To reduce drift and keep edge-case handling consistent, extract this into a small helper (e.g., buildRunUrl(context, repoParts)), and reuse it in both places.
| // Set output variable for conclusion job to handle | ||
| core.setOutput( | ||
| "error_message", | ||
| "GitHub Actions is not permitted to create or approve pull requests. Please enable 'Allow GitHub Actions to create and approve pull requests' in repository settings: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#preventing-github-actions-from-creating-or-approving-pull-requests" | ||
| ); | ||
| return { | ||
| success: false, | ||
| error: errorMessage, | ||
| error_type: "permission_denied", | ||
| }; |
There was a problem hiding this comment.
This removes the prior behavior that created a fallback issue (with a ready-to-use compare/create-PR link) when PR creation is permission-denied, and instead relies on a downstream 'conclusion job' consuming error_message. In this PR, no corresponding consumer is shown, so repositories hitting this error may lose the previous self-serve remediation path. Consider either (a) keeping the fallback issue creation behind fallbackAsIssue, or (b) also outputting the key fields needed to recreate the prior UX (e.g., create_pr_url, branch_name, base_branch, title) and ensuring this PR includes the conclusion-job handling.
Add agentic workflow repo-assist