Skip to content
This repository was archived by the owner on Jun 26, 2026. It is now read-only.

fix(forms): stop VM disk selection being dropped on deploy #22

fix(forms): stop VM disk selection being dropped on deploy

fix(forms): stop VM disk selection being dropped on deploy #22

Workflow file for this run

name: PR size label
on:
pull_request_target:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
concurrency:
group: pr-size-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
size:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
// Skip files that should not count as "real diff" — they are produced by tools
// or vendored, not authored by humans, and including them lies to reviewers
// about review effort:
// - lockfiles (pnpm-lock.yaml, package-lock.json, yarn.lock, bun.lockb, *.lock)
// - build / dist output checked in by accident
// - generated code trees (any path segment named `generated/`)
// - vendored deps (node_modules — should be gitignored, defence in depth)
const isIgnored = (path) =>
path === 'pnpm-lock.yaml' || path.endsWith('/pnpm-lock.yaml') ||
path === 'package-lock.json' || path.endsWith('/package-lock.json') ||
path === 'yarn.lock' || path.endsWith('/yarn.lock') ||
path === 'bun.lockb' || path.endsWith('/bun.lockb') ||
path.endsWith('.lock') ||
/(^|\/)node_modules\//.test(path) ||
/(^|\/)dist\//.test(path) ||
/(^|\/)build\//.test(path) ||
/(^|\/)generated\//.test(path);
const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
});
const lines = files
.filter((f) => !isIgnored(f.filename))
.reduce((acc, f) => acc + (f.additions || 0) + (f.deletions || 0), 0);
// Thresholds match the descriptions of size/* labels in .github/labels.yml.
const bucket =
lines <= 9 ? 'XS' :
lines <= 29 ? 'S' :
lines <= 99 ? 'M' :
lines <= 499 ? 'L' :
lines <= 999 ? 'XL' : 'XXL';
const target = `size/${bucket}`;
// Match both legacy "size:" and canonical "size/" during the migration window.
const existing = (pr.labels || []).map((l) => l.name);
const oldSizes = existing.filter((n) => n.startsWith('size/') || n.startsWith('size:'));
const alreadyTarget = oldSizes.includes(target);
// Remove every size/* label that is not the target. Tolerate 404 — concurrent
// runs or manual edits between event payload and execution can race here.
for (const name of oldSizes) {
if (name === target) continue;
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
name,
});
} catch (e) {
if (e.status !== 404) throw e;
core.info(`label ${name} already gone (404)`);
}
}
if (alreadyTarget && oldSizes.length === 1) {
core.info(`PR #${pr.number}: ${lines} lines, label already ${target}`);
return;
}
if (!alreadyTarget) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: [target],
});
}
core.info(`PR #${pr.number}: ${lines} lines -> ${target}`);