diff --git a/.github/workflows/fix-size-check.yml b/.github/workflows/fix-size-check.yml new file mode 100644 index 0000000000000000000000000000000000000000..7d82fa9018bfafa6a6888e5c7251bb0321cf3166 --- /dev/null +++ b/.github/workflows/fix-size-check.yml @@ -0,0 +1,131 @@ +# One-off: retroactively apply size labels and check runs to PRs +# that failed due to the permissions ceiling bug. Delete after use. +name: Fix Size Check (one-off) + +on: + workflow_dispatch: + inputs: + pr_numbers: + description: "Comma-separated PR numbers" + required: true + type: string + +permissions: + contents: read + checks: write + pull-requests: write + issues: write + +jobs: + fix: + runs-on: ubuntu-latest + steps: + - name: Apply size labels and check runs + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + with: + script: | + const prNumbers = context.payload.inputs.pr_numbers + .split(',') + .map(n => parseInt(n.trim())) + .filter(n => !isNaN(n)); + + const IGNORED_PATTERNS = [ + /\.lock$/, + /^Cargo\.lock$/, + /pnpm-lock\.yaml$/, + /\.generated\./, + /\/fixtures\//, + /\/snapshots\//, + ]; + + const SIZE_BRACKETS = [ + ['size/S', 0, 100, '0e8a16'], + ['size/M', 100, 400, 'fbca04'], + ['size/L', 400, 800, 'e99695'], + ['size/XL', 800, Infinity, 'b60205'], + ]; + + for (const prNumber of prNumbers) { + console.log(`Processing PR #${prNumber}...`); + + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + }); + + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber, + per_page: 300, + }); + + let totalChanges = 0; + for (const file of files) { + const ignored = IGNORED_PATTERNS.some(p => p.test(file.filename)); + if (!ignored) { + totalChanges += file.additions + file.deletions; + } + } + + let sizeLabel = 'size/S'; + let labelColor = '0e8a16'; + for (const [label, min, max, color] of SIZE_BRACKETS) { + if (totalChanges >= min && totalChanges < max) { + sizeLabel = label; + labelColor = color; + break; + } + } + + // Ensure label exists + try { + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: sizeLabel, + color: labelColor, + }); + } catch (e) { + if (e.status !== 422) throw e; + } + + // Remove old size labels, add correct one + const existingLabels = (await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + })).data.map(l => l.name); + + for (const label of existingLabels.filter(l => l.startsWith('size/'))) { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + name: label, + }); + } + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + labels: [sizeLabel], + }); + + // Create passing check run + await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + name: 'check-size', + head_sha: pr.head.sha, + conclusion: 'success', + output: { + title: `PR Size: ${totalChanges} LOC (${sizeLabel})`, + summary: `Retroactively applied by fix-size-check workflow.`, + }, + }); + + console.log(`PR #${prNumber}: ${totalChanges} LOC, labeled ${sizeLabel}, check posted`); + }