Skip to content

Test #58303 (the "automatically assign a PR assignee" PR) #28

Test #58303 (the "automatically assign a PR assignee" PR)

Test #58303 (the "automatically assign a PR assignee" PR) #28

name: Assign Committer
on:
# Important security note: Do NOT use `actions/checkout`
# or any other method for checking out the pull request's source code.
# This is because the pull request's source code is untrusted, but the
# GITHUB_TOKEN has write permissions (because of the `on: pull_request_target` event).
#
# Quoting from the GitHub Docs:
# > For workflows that are triggered by the pull_request_target event, the GITHUB_TOKEN is granted
# > read/write repository permission unless the permissions key is specified and the workflow can access secrets,
# > even when it is triggered from a fork.
# >
# > Although the workflow runs in the context of the base of the pull request,
# > you should make sure that you do not check out, build, or run untrusted code from the pull request with this event.
#
# Source: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request_target
#
# See also: https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/
pull_request_target:
types: [opened, reopened, ready_for_review]
# Permissions for the `GITHUB_TOKEN`:
permissions:
pull-requests: write # Needed in order to assign a user as the PR assignee
jobs:
assign-reviewer:
runs-on: ubuntu-latest
if: ${{ github.event.pull_request.draft != true }}
steps:
# Important security note: As discussed above, do NOT use `actions/checkout`
# or any other method for checking out the pull request's source code.
# This is because the pull request's source code is untrusted, but the
# GITHUB_TOKEN has write permissions (because of the `on: pull_request_target` event).
- name: Add Assignee
# We pin all third-party actions to a full length commit SHA
# https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-third-party-actions
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
retries: 5 # retry GitHub API requests up to 5 times, with exponential backoff
retry-exempt-status-codes: 403
script: |
if (context.payload.pull_request.assignees.length === 0) {
const prAuthor = context.payload.pull_request.user.login;
// Check if the PR is opened by a collaborator on the repo (aka a committer)
// We use the /repos/{owner}/{repo}/collaborators/{username} endpoint to avoid
// neeing org scope permissions
const { data: isCollaborator } = await github.rest.repos.checkCollaborator({
owner: context.repo.owner,
repo: context.repo.repo,
username: prAuthor,
});
if (isCollaborator) {
// The PR author is a committer, so we skip assigning them
console.log(`Skipping PR authored by committer: ${prAuthor}`);
return;
}
// Load the list of assignable reviewres the JuliaLang/pr-assignment repo
// at https://github.com/JuliaLang/pr-assignment/blob/main/users.txt
// NOTE to reviewers: If you want to be assigned to new PRs, please add your
// GitHub username to that file
// Load file contents
const { data: fileContents } = await github.rest.repos.getContent({
owner: 'JuliaLang',
repo: 'pr-assignment',
filepath: 'users.txt',
ref: 'main',
});
// Find lines that match ^(@[a-zA-Z0-9]+)(\s*#.*)?\n$ and extract the usernames
const reviewer_candidates = fileContents
.split('\n')
.map(line => line.match(/^(@[a-zA-Z0-9]+)(\s*#.*)?\n$/))
.filter(match => match !== null)
.map(match => match[1].substring(1)); // Remove the @ symbol
// Assign random committer
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
assignees: reviewer_candidates[Math.floor(Math.random()*reviewer_candidates.length)],
});
// Add the "pr review" label
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
labels: ['status: waiting for PR reviewer'],
});
}
}