Skip to content

Pull Request Labeler #32784

Pull Request Labeler

Pull Request Labeler #32784

Workflow file for this run

name: "Pull Request Labeler"
# Multi-purpose PR labeling flow.
# This workflow consumes workflow_run events from dedicated PR producer workflows
# and applies labels in a metadata-only privileged context.
on:
workflow_run:
workflows: ["PR event trigger", "Check if translation is required"]
types: [completed]
jobs:
# Collects PR metadata once for PR event trigger runs.
# Outputs are reused by specialized labeling jobs below.
pr-metadata:
# Security invariant: keep this workflow_run job metadata-only.
# Do not checkout or execute content from PR branches in this privileged context.
if: >-
${{ github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.name == 'PR event trigger' }}
outputs:
pr-number: ${{ steps.pr.outputs.number }}
is-external: ${{ steps.association.outputs.is_external }}
permissions:
actions: read
pull-requests: read
runs-on: ubuntu-latest
steps:
- name: Download PR metadata artifact
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 #v4
with:
name: pr-metadata
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}
path: .
- name: Read PR number from artifact
id: pr
run: |
pr_number="$(cat pr-number)"
echo "number=${pr_number}" >> "$GITHUB_OUTPUT"
- name: Read PR author
id: pr_author
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd #v8.0.0
with:
github-token: ${{ github.token }}
script: |
const prNumber = Number('${{ steps.pr.outputs.number }}');
const { data: pullRequest } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
const username = pullRequest.user?.login;
if (!username) {
core.setFailed('PR payload has no user.login');
return;
}
core.setOutput('username', username);
- id: generate-token
name: Generate an access token
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 #v2
with:
app-id: ${{ vars.EXTERNAL_PR_LABELER_APP_ID }}
private-key: ${{ secrets.EXTERNAL_PR_LABELER_PK }}
- name: Check if author is an org member
id: association
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd #v8.0.0
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
const username = '${{ steps.pr_author.outputs.username }}';
let isExternal = false;
try {
await github.request('GET /orgs/{org}/members/{username}', {
org: context.repo.owner,
username,
});
// 204: user is a member
isExternal = false;
} catch (error) {
if (error.status === 404) {
// 404: user is not a member
isExternal = true;
} else {
throw error;
}
}
core.setOutput('is_external', isExternal ? 'true' : 'false');
- name: Debug external classification
if: ${{ runner.debug == '1' }}
run: |
echo "PR author: ${{ steps.pr_author.outputs.username }}"
echo "is_external: ${{ steps.association.outputs.is_external }}"
# Applies path-based labels from .github/labeler.yml.
path-labeler:
# Security invariant: keep this workflow_run job metadata-only.
# Do not checkout or execute content from PR branches in this privileged context.
needs: pr-metadata
if: needs.pr-metadata.result == 'success'
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b #v6.0.1
with:
pr-number: "${{ needs.pr-metadata.outputs.pr-number }}"
configuration-path: .github/labeler.yml
# Applies the community label to external contributors.
external-pr-labeler:
# Security invariant: keep this workflow_run job metadata-only.
# Do not checkout or execute content from PR branches in this privileged context.
needs: pr-metadata
if: needs.pr-metadata.result == 'success' && needs.pr-metadata.outputs.is-external == 'true'
permissions:
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: Label external PRs
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd #v8.0.0
with:
script: |
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: Number('${{ needs.pr-metadata.outputs.pr-number }}'),
labels: ['community'],
});
# Applies or removes needs-translation based on translation producer
# (check_translations.yml) result artifact.
translation-labeler:
# Security invariant: keep this workflow_run job metadata-only.
# Do not checkout or execute content from PR branches in this privileged context.
if: >-
${{ github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.name == 'Check if translation is required' }}
runs-on: ubuntu-latest
permissions:
actions: read
pull-requests: write
steps:
- name: Download translation result artifact
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 #v4
with:
name: translation-check-result
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}
path: .
- name: Read translation result
id: translation
run: |
pr_number="$(grep -E '^pr_number=' translation-result | cut -d= -f2)"
needs_translation="$(grep -E '^needs_translation=' translation-result | cut -d= -f2)"
echo "pr_number=${pr_number}" >> "$GITHUB_OUTPUT"
echo "needs_translation=${needs_translation}" >> "$GITHUB_OUTPUT"
- name: Add needs-translation label
if: steps.translation.outputs.needs_translation == 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd #v8.0.0
with:
script: |
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: Number('${{ steps.translation.outputs.pr_number }}'),
labels: ['needs-translation'],
});
- name: Remove needs-translation label
if: steps.translation.outputs.needs_translation != 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd #v8.0.0
with:
script: |
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: Number('${{ steps.translation.outputs.pr_number }}'),
name: 'needs-translation',
});
} catch (error) {
if (error.status !== 404) {
throw error;
}
}