-
Notifications
You must be signed in to change notification settings - Fork 19
Introduce merge PR workflow #518
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: dev
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,151 @@ | ||||||||||||||||||||||||||||||||||||||||
| name: 'Combine PRs' | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| # Controls when the action will run - in this case triggered manually | ||||||||||||||||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||||||||||||
| branchPrefix: | ||||||||||||||||||||||||||||||||||||||||
| description: 'Branch prefix to find combinable PRs based on' | ||||||||||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||||||||||
| default: 'dependabot' | ||||||||||||||||||||||||||||||||||||||||
| mustBeGreen: | ||||||||||||||||||||||||||||||||||||||||
| description: 'Only combine PRs that are green (status is success). Set to false if repo does not run checks' | ||||||||||||||||||||||||||||||||||||||||
| type: boolean | ||||||||||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||||||||||
| default: true | ||||||||||||||||||||||||||||||||||||||||
| combineBranchName: | ||||||||||||||||||||||||||||||||||||||||
| description: 'Name of the branch to combine PRs into' | ||||||||||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||||||||||
| default: 'combine-prs-branch' | ||||||||||||||||||||||||||||||||||||||||
| ignoreLabel: | ||||||||||||||||||||||||||||||||||||||||
| description: 'Exclude PRs with this label' | ||||||||||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||||||||||
| default: 'nocombine' | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||||||||||
| # This workflow contains a single job called "combine-prs" | ||||||||||||||||||||||||||||||||||||||||
| combine-prs: | ||||||||||||||||||||||||||||||||||||||||
| # The type of runner that the job will run on | ||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| # Steps represent a sequence of tasks that will be executed as part of the job | ||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||
| - uses: actions/github-script@v6 | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
| - uses: actions/github-script@v6 | |
| - uses: actions/github-script@v7 |
Copilot
AI
Apr 3, 2026
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.
commit.statusCheckRollup can be null (e.g., no checks configured, checks disabled, or insufficient permissions), and commits.nodes can be empty. Accessing .state without guarding will throw and fail the workflow. Add a defensive check and treat missing/unknown rollup state as non-green (or skip with a clear message).
| const [{ commit }] = result.repository.pullRequest.commits.nodes; | |
| const state = commit.statusCheckRollup.state | |
| console.log('Validating status: ' + state); | |
| if(state != 'SUCCESS') { | |
| console.log('Discarding ' + branch + ' with status ' + state); | |
| statusOK = false; | |
| const commitNodes = result.repository.pullRequest.commits.nodes || []; | |
| const latestCommitNode = commitNodes.length > 0 ? commitNodes[0] : null; | |
| const commit = latestCommitNode ? latestCommitNode.commit : null; | |
| const state = commit && commit.statusCheckRollup ? commit.statusCheckRollup.state : null; | |
| if (!state) { | |
| console.log('Discarding ' + branch + ' because no status check rollup state is available'); | |
| statusOK = false; | |
| } else { | |
| console.log('Validating status: ' + state); | |
| if(state != 'SUCCESS') { | |
| console.log('Discarding ' + branch + ' with status ' + state); | |
| statusOK = false; | |
| } |
Copilot
AI
Apr 3, 2026
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.
baseBranch / baseBranchSHA are set from whichever matching PR is processed last. If matching PRs target different base branches, the combined branch/PR base becomes nondeterministic and merges can be incorrect. Validate that all selected PRs share the same pull.base.ref (and fail/skip otherwise) before proceeding.
Copilot
AI
Apr 3, 2026
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.
baseBranchSHA is taken from pull.base.sha (the base SHA recorded on the PR), which may be stale compared to the current tip of the base branch. Creating the combined branch from an old SHA can increase conflicts and produce an out-of-date combined PR. Prefer resolving the current base branch head SHA via git.getRef (or equivalent) once the base branch is determined.
Copilot
AI
Apr 3, 2026
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 PR description says the workflow can merge into a new or existing combined branch, but the implementation fails the run if the branch already exists. Consider supporting an existing branch (e.g., reset it to the chosen base SHA, or allow reusing it) instead of hard-failing on createRef errors.
Copilot
AI
Apr 3, 2026
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.
repos.merge uses head: branch where branch is pull.head.ref. This fails for PRs from forks because the API expects head as owner:ref in that case. Use pull.head.label or construct ${pull.head.repo.owner.login}:${pull.head.ref} when pull.head.repo.full_name !== context.repo.owner + '/' + context.repo.repo.
Copilot
AI
Apr 3, 2026
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 workflow always creates a combined PR even if every merge failed (so combinedPRs is empty). That produces a noisy PR with no combined content. Consider failing early (or skipping PR creation) when combinedPRs.length === 0, and include the merge error messages in the output/PR body to aid debugging.
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 25 days ago
In general, the fix is to add an explicit permissions block to the workflow (either at the root or under the specific job) that grants only the scopes required for the actions performed. This documents the workflow’s needs and prevents it from silently inheriting overly broad defaults.
For this specific workflow in .github/workflows/merge-prs.yml, the script reads and writes pull requests and branches. The write operations include creating a branch (git.createRef), merging branches (repos.merge), and creating a pull request (pulls.create). These operations require at least:
contents: write(for creating refs/branches and merging)pull-requests: write(for creating pull requests)
To fix the issue without changing existing behavior, add a permissions section at the job level for combine-prs, right under runs-on: ubuntu-latest. This keeps the permissions scoped only to that job, rather than globally for all jobs in the workflow. The block should look like:
permissions:
contents: write
pull-requests: writeNo additional imports, methods, or other structural changes are necessary, because this is entirely a YAML configuration change.
-
Copy modified lines R30-R32
| @@ -27,6 +27,9 @@ | ||
| combine-prs: | ||
| # The type of runner that the job will run on | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
|
|
||
| # Steps represent a sequence of tasks that will be executed as part of the job | ||
| steps: |
Copilot
AI
Apr 3, 2026
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.
Creating the PR unconditionally with a fixed title/head/base will fail if an open PR already exists for the same head → base (GitHub typically allows only one open PR per head/base). Consider checking for an existing PR for combineBranchName and updating it (or closing/replacing) instead of always calling pulls.create.
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.
This workflow creates branches and opens PRs but doesn’t declare any
permissions:. With the default restrictedGITHUB_TOKENpermissions (or org-level hardening),git.createRef,repos.merge, andpulls.createcan fail. Add explicit least-privilege permissions (e.g.,contents: writeandpull-requests: write) at the workflow or job level so the action is reliable across repo settings.