-
Notifications
You must be signed in to change notification settings - Fork 0
[codex] add safe automerge workflow #2
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
base: master
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| name: codex autopmerge | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| types: [opened, synchronize, reopened, ready_for_review, labeled] | ||
|
|
||
| jobs: | ||
| codex-automerge: | ||
| name: Enable or apply Codex auto-merge | ||
| runs-on: ubuntu-latest | ||
| if: >- | ||
| github.event.pull_request.draft == false && | ||
| contains(github.event.pull_request.labels.*.name, 'automerge') && | ||
| (github.event.sender.login == 'chatgpt-codex-connector' || startsWith(github.event.pull_request.head.ref, 'codex/')) | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| checks: read | ||
| actions: read | ||
| steps: | ||
| - name: Evaluate file changes and apply merge | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const denylist = [ | ||
| '**/*wrangler*.{json,toml}', | ||
| '**/.github/workflows/**', | ||
| '**/src/**/stripe*', | ||
| '**/src/**/payments*', | ||
| '**/src/**/auth*', | ||
| '**/src/**/sessions*', | ||
| '**/src/**/worker/**/env*', | ||
| '**/routing/**', | ||
| '**/redirect', | ||
| '**/canonical', | ||
| '**/migrations/**', | ||
| '**/*.sql', | ||
| ]; | ||
|
|
||
| const { owner, repo } = context.repo; | ||
| const pull_number = context.payload.pull_request.number; | ||
|
|
||
| function globToRegex(glob) { | ||
| let out = String(glob) | ||
| .replace(/[.+^${}()|[\]\]/g, '\\$&') | ||
| .replace(/\{([^}]+)\}/g, (_m, alts) => `(?:${alts.split(',').join('|')})`) | ||
| .replace(/\*\*/g, '.*') | ||
| .replace(/\*/g, '[^/]*') | ||
|
Comment on lines
+48
to
+49
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 replacement order in Useful? React with 👍 / 👎. |
||
| .replace(/\?/g, '.'); | ||
| return new RegExp(`^${out}$`); | ||
| } | ||
|
|
||
| function isDenied(path) { | ||
| return denylist.some((pattern) => globToRegex(pattern).test(path)); | ||
| } | ||
|
|
||
| const files = await github.paginate(github.rest.pulls.listFiles, { | ||
| owner, | ||
| repo, | ||
| pull_number, | ||
| per_page: 100, | ||
| }); | ||
|
|
||
| const denied = files.filter((f) => isDenied(f.filename)); | ||
| if (denied.length) { | ||
| console.log(`Codex safe-merge skipped: denied file changes detected. files=${denied.map((f) => f.filename).join(', ')}`); | ||
| return; | ||
| } | ||
|
|
||
| let pr = await github.rest.pulls.get({ owner, repo, pull_number }).then((res) => res.data); | ||
|
|
||
| try { | ||
| await github.rest.pulls.enablePullRequestAutoMerge({ | ||
| owner, | ||
| repo, | ||
| pull_number, | ||
| merge_method: 'squash', | ||
| }); | ||
| console.log('Enabled GitHub PR auto-merge (squash).'); | ||
| return; | ||
| } catch (err) { | ||
| const code = err.status || err.statusCode || 0; | ||
| console.log(`Auto-merge unavailable (${code}): ${err.message}`); | ||
|
|
||
| if (![422, 405, 403].includes(code)) { | ||
| throw err; | ||
| } | ||
| } | ||
|
|
||
| pr = await github.rest.pulls.get({ owner, repo, pull_number }).then((res) => res.data); | ||
| if (!pr.mergeable) { | ||
| console.log('PR is not mergeable, skipping fallback merge.'); | ||
| return; | ||
| } | ||
| if (pr.mergeable_state !== 'clean') { | ||
| console.log(`Branch protections/check state not clean (${pr.mergeable_state}), skipping fallback merge.`); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| await github.rest.pulls.merge({ | ||
| owner, | ||
| repo, | ||
| pull_number, | ||
| merge_method: 'squash', | ||
| }); | ||
| console.log('Fallback merge via API completed.'); | ||
| } catch (err) { | ||
| const message = err.message || String(err); | ||
| console.log(`Fallback merge failed: ${message}`); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # Codex PR Workflow | ||
|
|
||
| ## Labels | ||
| - `codex-ready`: reviewed by a human (optional). | ||
| - `automerge`: safe to automerge (docs-only changes, UI copy, styling, non-sensitive bugfixes). | ||
|
|
||
| ## Auto-merge policy | ||
| - Label `automerge` to trigger this workflow. | ||
| - PR must be ready for review (not draft). | ||
| - PR author must be `chatgpt-codex-connector` or branch must start with `codex/`. | ||
|
|
||
| ### Never auto-merge | ||
| The workflow exits without automerging when files match any denylist pattern: | ||
| - `**/*wrangler*.{json,toml}` | ||
| - `**/.github/workflows/**` | ||
| - `**/src/**/stripe*` | ||
| - `**/src/**/payments*` | ||
| - `**/src/**/auth*` | ||
| - `**/src/**/sessions*` | ||
| - `**/src/**/worker/**/env*` | ||
| - `**/routing/**` | ||
| - `**/redirect` | ||
| - `**/canonical` | ||
| - `**/migrations/**` | ||
| - `**/*.sql` | ||
|
|
||
| ### Merge behavior | ||
| - `pull_request_target` workflow scans changed files on `opened`, `synchronize`, `reopened`, `ready_for_review`, and `labeled` events. | ||
| - If no denylist matches, it enables GitHub auto-merge (`squash`) for the PR. | ||
| - If repository auto-merge is disabled, it falls back to API merge only when mergeability is clean. | ||
|
|
||
| ## PR title format | ||
| Use `[codex]` prefix so these PRs are searchable across the portfolio: | ||
|
|
||
| - `[codex] add safe automerge workflow` | ||
|
|
||
| ## Scope | ||
| This file documents workflow behavior only. The workflow does not make runtime code changes. |
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.
The
globToRegexhelper currently contains an invalid JavaScript regex (/[.+^${}()|[\]\]/g), which causes aSyntaxErrorwhenactions/github-scriptevaluates the step, so this workflow job fails before it can evaluate file changes or enable auto-merge for any PR.Useful? React with 👍 / 👎.