chore: update internal-services resources for staging #227
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: Assign PR Assignees | |
| on: | |
| pull_request_target: | |
| types: [opened, ready_for_review, synchronize, reopened] | |
| permissions: | |
| contents: read | |
| pull-requests: write # required to list PR files and to assign on PRs via the Issues API | |
| issues: write | |
| jobs: | |
| assign-assignees: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Assign internal-services assignees from CODEOWNERS | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const fs = require("fs"); | |
| const RELEASE_SERVICE_BOT = "release-service-bot"; | |
| const pr = context.payload.pull_request; | |
| if (!pr) { | |
| core.info("No pull request in event payload. Skipping."); | |
| return; | |
| } | |
| if (context.payload.action === "opened" && pr.draft) { | |
| core.info("Draft PR opened. Skipping assignment until ready_for_review."); | |
| return; | |
| } | |
| const changedFiles = await github.paginate( | |
| github.rest.pulls.listFiles, | |
| { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: pr.number, | |
| per_page: 100, | |
| } | |
| ); | |
| const isInternalServicesPR = changedFiles.some((file) => | |
| file.filename.startsWith("components/internal-services/") | |
| ); | |
| if (!isInternalServicesPR) { | |
| core.info("PR does not touch internal-services component. Skipping assignment."); | |
| return; | |
| } | |
| const codeownersPath = ".github/CODEOWNERS"; | |
| const codeowners = fs.readFileSync(codeownersPath, "utf8"); | |
| const internalServicesLine = codeowners | |
| .split("\n") | |
| .map((line) => line.trim()) | |
| .find((line) => line.startsWith("/components/internal-services/ ")); | |
| if (!internalServicesLine) { | |
| core.setFailed("Could not find /components/internal-services/ entry in .github/CODEOWNERS."); | |
| return; | |
| } | |
| const owners = internalServicesLine | |
| .split(/\s+/) | |
| .slice(1) | |
| .map((owner) => owner.replace(/^@/, "").trim()) | |
| .filter(Boolean); | |
| const excluded = new Set([ | |
| RELEASE_SERVICE_BOT, | |
| pr.user.login, | |
| ]); | |
| const existingAssignees = (pr.assignees || []).map((assignee) => assignee.login); | |
| for (const assignee of existingAssignees) { | |
| excluded.add(assignee); | |
| } | |
| const candidates = owners.filter((owner) => !excluded.has(owner)); | |
| const neededAssignees = Math.max(0, 2 - existingAssignees.length); | |
| if (neededAssignees === 0) { | |
| core.info("PR already has 2 or more assignees."); | |
| return; | |
| } | |
| if (candidates.length === 0) { | |
| core.info("No eligible internal-services CODEOWNERS assignees available."); | |
| return; | |
| } | |
| const collaboratorChecks = await Promise.all( | |
| candidates.map(async (candidate) => { | |
| try { | |
| await github.rest.repos.getCollaboratorPermissionLevel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| username: candidate, | |
| }); | |
| return candidate; | |
| } catch (error) { | |
| if (error.status === 404) { | |
| core.info(`Skipping non-collaborator assignee candidate: ${candidate}`); | |
| return null; | |
| } | |
| throw error; | |
| } | |
| }) | |
| ); | |
| const collaboratorCandidates = collaboratorChecks.filter(Boolean); | |
| if (collaboratorCandidates.length === 0) { | |
| core.info("No collaborator candidates available for assignment."); | |
| return; | |
| } | |
| const shuffled = [...collaboratorCandidates].sort(() => Math.random() - 0.5); | |
| const selected = shuffled.slice(0, neededAssignees); | |
| if (selected.length === 0) { | |
| core.info("No assignees selected."); | |
| return; | |
| } | |
| try { | |
| await github.rest.issues.addAssignees({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: pr.number, | |
| assignees: selected, | |
| }); | |
| } catch (error) { | |
| if (error.status === 422) { | |
| core.warning(`Unable to assign one or more assignees: ${error.message}`); | |
| return; | |
| } | |
| throw error; | |
| } | |
| core.info(`Assigned assignees: ${selected.join(", ")}`); |