Skip to content

add-wizard: offer schedule frequency selection for scheduled workflows#19709

Open
Copilot wants to merge 14 commits intomainfrom
copilot/add-frequency-options-scheduler
Open

add-wizard: offer schedule frequency selection for scheduled workflows#19709
Copilot wants to merge 14 commits intomainfrom
copilot/add-frequency-options-scheduler

Conversation

Copy link
Contributor

Copilot AI commented Mar 5, 2026

gh aw add-wizard had no way to change the schedule of a workflow being added — users got whatever frequency was baked into the upstream workflow.

Changes

Schedule detection (add_interactive_schedule.go)

  • detectWorkflowScheduleInfo — extracts the raw schedule expression from frontmatter, handling both simple string form (on: daily) and map form (on: {schedule: [{cron: ...}], workflow_dispatch: null}). Skips multi-trigger workflows (e.g. on: schedule + push) to avoid clobbering unrelated triggers.
  • classifyScheduleFrequency — maps any schedule expression to hourly | 3-hourly | daily | weekly | monthly | custom, covering friendly strings (daily, every 3h), FUZZY placeholders (FUZZY:DAILY * * *), and standard cron patterns.
  • buildScheduleOptions — constructs the ordered huh select list; the current frequency is placed first and marked (current). Custom/unrecognised schedules get a Custom: <expr> (keep existing) option as the default.
  • selectScheduleFrequency — wizard step: presents the form, and on a changed selection rewrites wf.Content / wf.SourceInfo.Content in memory before the PR is created. No-op when user picks the same frequency or "Custom".

Wizard integration (add_interactive_orchestrator.go)

  • Inserts selectScheduleFrequency() as step 7b in RunAddInteractive, after file enumeration and before the confirmation prompt.

Frequency → expression mapping

Selection Written to on:
Hourly every 1h
Every 3 hours every 3h
Daily daily
Weekly weekly
Monthly 0 0 1 * *
Custom / unchanged (no change)

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw --local 64/pkg/tool/linux_amd64/vet git rev-�� --show-toplevel QX/ympLdpf_SIHeLx8ALucz/ItF6Ey0Q-tests /usr/bin/git te &#39;**/*.cjs&#39; &#39;*git .cfg x_amd64/link git (http block)
  • https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha --get l /usr/bin/git ../pkg/workflow/git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha -unreachable=false /tmp/go-build1158601089/b264/vet.cfg /opt/hostedtoolcache/uv/0.10.8/x86_64/bash (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --verify main 64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel x_amd64/vet /usr/bin/git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git tants.go tants_test.go 64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/compile /usr/bin/git g_.a 8601089/b251/vetrev-parse .cfg git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha XFJrOcRib (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha tags/v5 (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git HEAD .cfg 64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel 64/pkg/tool/linu--json /usr/bin/git git status --porgit (http block)
  • https://api.github.com/repos/actions/download-artifact/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/download-artifact/git/ref/tags/v8 --jq .object.sha se 8601089/b010/vet.cfg ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/download-artifact/git/ref/tags/v8 --jq .object.sha se 8601089/b234/vet.cfg ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/download-artifact/git/ref/tags/v8 --jq .object.sha t0 m0s 8601089/b292/vet.cfg assifyScheduleFrgit (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -c=4 -nolocalimports -importcfg /tmp/go-build3677500810/b385/importcfg -embedcfg /tmp/go-build3677500810/b385/embedcfg -pack (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha on&#39; --ignore-path ../../../.pret.prettierignore (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha /tmp/gh-aw-test-runs/20260305-095513-12636/test-3102792710/.github/workflows config /usr/bin/git remote.origin.urgit (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha --show-toplevel (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha 7500810/b386/_pkg_.a .cfg 7500810/b386=&gt; -p bracelet/x/exp/grev-parse -lang=go1.17 /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -ato�� tructions-test-2759340695/.github/workflows -buildtags /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -errorsas -ifaceassert -nilfunc 7500810/b386/importcfg (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v7
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/-errorsas (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha te &#39;../../../**/*.json&#39; &#39;!../../../pkg/workflow/js/**/*.json&#39; ---p --noheadings .cfg (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha on rkflow/js/**/*.json x_amd64/compile erignore (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 --local 64/pkg/tool/linux_amd64/vet nore (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 --local 64/pkg/tool/linux_amd64/vet nore (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 --local 64/pkg/tool/linux_amd64/vet nore (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 --local x_amd64/link nore (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 les 64/pkg/tool/linux_amd64/vet nore (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 --local 64/pkg/tool/linux_amd64/vet nore (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 --local 64/pkg/tool/linu-nolocalimports nore (http block)
  • https://api.github.com/repos/github/gh-aw/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100 (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha --local .cfg 64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq .object.sha (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v2.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha ./../pkg/workflo-errorsas (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v3.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq .object.sha (http block)
  • https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha --local .cfg 64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/nonexistent/repo/actions/runs/12345
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion nore (http block)
  • https://api.github.com/repos/owner/repo/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 0/x64/bin/git (http block)
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo -importcfg /tmp/go-build103549757/b123/importcfg -pack /home/REDACTED/work/gh-aw/gh-aw/pkg/cli/access_log.go /home/REDACTED/work/gh-aw/gh-aw/pkg/cli/actionlint.go (http block)
  • https://api.github.com/repos/owner/repo/contents/file.md
    • Triggering command: /tmp/go-build3677500810/b383/cli.test /tmp/go-build3677500810/b383/cli.test -test.testlogfile=/tmp/go-build3677500810/b383/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true (http block)
  • https://api.github.com/repos/test-owner/test-repo/actions/secrets
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name (http block)
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name --show-toplevel eutil.test /usr/bin/git se 8601089/b097/vetrev-parse ache/go/1.25.0/x--show-toplevel git rev-�� --show-toplevel ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet /usr/bin/git se 8601089/b270/vetrev-parse ache/go/1.25.0/x--show-toplevel git (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>gh aw add-wizard for scheduled workflow should offer choice of frequencies</issue_title>
<issue_description>gh aw add-wizard on a scheduled workflow should offer a choice of hourly/3-hourly, daily, weekly, monthly triggers

It should default to whatever is in the workflow

The workflow frontmatter should be adjusted carefully and reliably to reflect the choice. Unless the choice was the default in which case no change made.

Sometimes the frontmatter will have a custom schedule not corresponding to the above, in which case "Custom" should be listed as a choice. </issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.



✨ PR Review Safe Output Test - Run 22718413768

💥 [THE END] — Illustrated by Smoke Claude ·

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>
Copilot AI changed the title [WIP] Add frequency options for scheduled workflow wizard add-wizard: offer schedule frequency selection for scheduled workflows Mar 5, 2026
Copilot finished work on behalf of dsyme March 5, 2026 10:05
@dsyme dsyme marked this pull request as ready for review March 6, 2026 19:15
Copilot AI review requested due to automatic review settings March 6, 2026 19:15
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new gh aw add-wizard step to detect scheduled workflows and let users choose a standard schedule frequency (hourly/3-hourly/daily/weekly/monthly) while preparing the PR.

Changes:

  • Introduces schedule detection/classification + interactive selection, and applies the selected schedule to in-memory workflow content before PR creation.
  • Integrates the new schedule-selection step into the interactive add orchestrator flow.
  • Adds unit tests for schedule classification/detection and option-building.
  • Updates the create_pull_request safe-output handler (context guarding, run URL construction, footer args, and permission-denied handling).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
pkg/cli/add_interactive_schedule.go Adds schedule detection/classification, builds select options, and attempts to rewrite frontmatter based on user choice.
pkg/cli/add_interactive_schedule_test.go Adds unit tests for schedule frequency classification, schedule detection, and option ordering.
pkg/cli/add_interactive_orchestrator.go Inserts the schedule-frequency selection step into the wizard flow.
actions/setup/js/create_pull_request.cjs Adjusts PR creation handler behavior around context usage, footer generation, run URL construction, and permission-denied flow.
Comments suppressed due to low confidence (1)

actions/setup/js/create_pull_request.cjs:727

  • The same manual runUrl construction is duplicated in the git-push failure fallback path. Consider factoring this back to the shared buildWorkflowRunUrl helper (and/or a local function) to avoid divergence and to ensure the URL always targets the workflow-run repo even when repoParts is a different target repo.
        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}`;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +982 to +994
// Check if the error is the specific "GitHub actions is not permitted to create or approve pull requests" error
if (errorMessage.includes("GitHub Actions is not permitted to create or approve pull requests")) {
core.error("Permission error: GitHub Actions is not permitted to create or approve pull requests");

// Branch has already been pushed - create a fallback issue with a link to create the PR via GitHub UI
const githubServer = process.env.GITHUB_SERVER_URL || "https://github.com";
// Encode branch name path segments individually to preserve '/' while encoding other special characters
const encodedBase = baseBranch.split("/").map(encodeURIComponent).join("/");
const encodedHead = branchName.split("/").map(encodeURIComponent).join("/");
const createPrUrl = `${githubServer}/${repoParts.owner}/${repoParts.repo}/compare/${encodedBase}...${encodedHead}?expand=1&title=${encodeURIComponent(title)}`;

// Read patch content for preview
let patchPreview = "";
if (patchFilePath && fs.existsSync(patchFilePath)) {
const patchContent = fs.readFileSync(patchFilePath, "utf8");
patchPreview = generatePatchPreview(patchContent);
}

const fallbackBody =
`${body}\n\n---\n\n` +
`> [!NOTE]\n` +
`> This was originally intended as a pull request, but GitHub Actions is not permitted to create or approve pull requests in this repository.\n` +
`> The changes have been pushed to branch \`${branchName}\`.\n` +
`>\n` +
`> **[Click here to create the pull request](${createPrUrl})**\n\n` +
`To fix the permissions issue, go to **Settings** → **Actions** → **General** and enable **Allow GitHub Actions to create and approve pull requests**.` +
patchPreview;

try {
const { data: issue } = await githubClient.rest.issues.create({
owner: repoParts.owner,
repo: repoParts.repo,
title: title,
body: fallbackBody,
labels: mergeFallbackIssueLabels(labels),
});

core.info(`Created fallback issue #${issue.number}: ${issue.html_url}`);

await updateActivationComment(github, context, core, issue.html_url, issue.number, "issue");

return {
success: true,
fallback_used: true,
issue_number: issue.number,
issue_url: issue.html_url,
branch_name: branchName,
repo: itemRepo,
};
} catch (issueError) {
const error = `Failed to create pull request (permission denied) and failed to create fallback issue. PR error: ${errorMessage}. Issue error: ${issueError instanceof Error ? issueError.message : String(issueError)}`;
core.error(error);
return {
success: false,
error,
error_type: "permission_denied",
};
}
// 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",
};
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the permission-denied behavior from “create fallback issue and return success” to “set an output and return failure”. That’s a significant behavior change and appears unrelated to the PR’s stated goal (add-wizard schedule selection). If the workflow expects a fallback issue for traceability/activation-comment updates, this will break that flow; either restore the previous fallback behavior or update the surrounding workflow/jobs and PR description to reflect the new failure-handling contract.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gh aw add-wizard for scheduled workflow should offer choice of frequencies

3 participants