feat: add privacy-first Codex to OKF migration #1929
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Auto-label Bounties and PRs | |
| # Automatically assigns incremental "Bounty #N" labels to bounty issues. | |
| # Also labels any pull request that references a bounty issue with the | |
| # specific "Bounty #N" label from the issue. | |
| on: | |
| issues: | |
| types: [opened, edited] | |
| pull_request_target: | |
| types: [opened, edited, synchronize, reopened] | |
| concurrency: | |
| group: bounty-labeling | |
| cancel-in-progress: false | |
| permissions: | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| label: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Apply bounty labels | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| function extractSpecificBountyLabel(labels) { | |
| for (const label of labels) { | |
| const name = typeof label === "string" ? label : label.name; | |
| if (/^bounty\s*#?\d+/i.test(name)) { | |
| return name; | |
| } | |
| } | |
| return null; | |
| } | |
| async function ensureLabelExists(name) { | |
| try { | |
| await github.rest.issues.getLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| name, | |
| }); | |
| } catch (error) { | |
| if (error.status === 404) { | |
| // A palette of visually distinct colors | |
| const palette = [ | |
| "b60205", // red | |
| "0e8a16", // green | |
| "fbca04", // yellow | |
| "1d76db", // blue | |
| "5319e7", // purple | |
| "d93f0b", // orange | |
| "006b75", // teal | |
| "c5def5", // light blue | |
| "f9d0c4", // light pink | |
| "d4c5f9", // light purple | |
| ]; | |
| // Extract bounty number to deterministically pick a color | |
| const match = name.match(/\d+/); | |
| const num = match ? parseInt(match[0], 10) : 0; | |
| const color = palette[num % palette.length]; | |
| core.info(`Creating missing label "${name}" with color ${color}.`); | |
| try { | |
| await github.rest.issues.createLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| name, | |
| color, | |
| }); | |
| } catch (createError) { | |
| // Another concurrent run may create the same label first. | |
| if (createError.status !== 422) { | |
| throw createError; | |
| } | |
| } | |
| } else { | |
| throw new Error(`Failed to check label "${name}": ${error.message}`); | |
| } | |
| } | |
| } | |
| async function findOpenPrsReferencingIssue(issueNumber) { | |
| const prs = await github.paginate(github.rest.pulls.list, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: "open", | |
| per_page: 100, | |
| }); | |
| const refPattern = new RegExp(`#${issueNumber}(?!\\d)`); | |
| return prs.filter((pr) => { | |
| const text = `${pr.title}\n${pr.body ?? ""}`; | |
| return refPattern.test(text); | |
| }); | |
| } | |
| async function applyLabelsToPr(prNumber, labels) { | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| labels, | |
| }); | |
| } | |
| async function labelIssue(issue) { | |
| const isMaintainer = ["OWNER", "MEMBER", "COLLABORATOR"].includes(issue.author_association); | |
| const hasBountyInTitle = /bounty/i.test(issue.title); | |
| if (!isMaintainer || !hasBountyInTitle) { | |
| return null; | |
| } | |
| const existingSpecificBounty = extractSpecificBountyLabel(issue.labels); | |
| if (existingSpecificBounty) { | |
| return existingSpecificBounty; | |
| } | |
| const allLabels = await github.paginate(github.rest.issues.listLabelsForRepo, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| per_page: 100 | |
| }); | |
| let maxBountyNum = 0; | |
| for (const label of allLabels) { | |
| const match = label.name.match(/^bounty\s*#?(\d+)/i); | |
| if (match) { | |
| const num = parseInt(match[1], 10); | |
| if (num > maxBountyNum) { | |
| maxBountyNum = num; | |
| } | |
| } | |
| } | |
| const nextBountyNumber = maxBountyNum + 1; | |
| const newLabel = `Bounty #${nextBountyNumber}`; | |
| await ensureLabelExists(newLabel); | |
| core.info(`Issue #${issue.number}: applying label ${newLabel}`); | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| labels: [newLabel], | |
| }); | |
| return newLabel; | |
| } | |
| async function labelPr(pr) { | |
| const text = `${pr.title}\n${pr.body ?? ""}`; | |
| const issueNumbers = new Set( | |
| [...text.matchAll(/#(\d+)/g)].map((m) => parseInt(m[1], 10)) | |
| ); | |
| if (issueNumbers.size === 0) { | |
| core.info(`PR #${pr.number}: no issue references found.`); | |
| return; | |
| } | |
| const bountyLabels = new Set(); | |
| for (const number of issueNumbers) { | |
| try { | |
| const { data: issue } = await github.rest.issues.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: number, | |
| }); | |
| // Skip if the referenced number is actually a PR, not an issue. | |
| if (issue.pull_request) continue; | |
| // Skip closed issues so only "active" bounties apply. | |
| if (issue.state !== "open") continue; | |
| const existingSpecificBounty = extractSpecificBountyLabel(issue.labels); | |
| if (existingSpecificBounty) bountyLabels.add(existingSpecificBounty); | |
| } catch (error) { | |
| core.info(`PR #${pr.number}: could not read issue #${number}: ${error?.message ?? String(error)}`); | |
| } | |
| } | |
| if (bountyLabels.size === 0) { | |
| core.info(`PR #${pr.number}: no referenced issue(s) carry a bounty label.`); | |
| return; | |
| } | |
| for (const name of bountyLabels) { | |
| await ensureLabelExists(name); | |
| } | |
| core.info(`PR #${pr.number}: applying labels: ${[...bountyLabels].join(", ")}`); | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| labels: [...bountyLabels], | |
| }); | |
| } | |
| if (context.eventName === "issues") { | |
| const bountyLabel = await labelIssue(context.payload.issue); | |
| if (bountyLabel) { | |
| const referencingPrs = await findOpenPrsReferencingIssue(context.payload.issue.number); | |
| for (const pr of referencingPrs) { | |
| core.info(`Issue #${context.payload.issue.number}: propagating ${bountyLabel} to PR #${pr.number}`); | |
| await ensureLabelExists(bountyLabel); | |
| await applyLabelsToPr(pr.number, [bountyLabel]); | |
| } | |
| } | |
| } else { | |
| await labelPr(context.payload.pull_request); | |
| } |