Skip to content

Add default autosave restore UX #1020

Add default autosave restore UX

Add default autosave restore UX #1020

Workflow file for this run

name: Auto-label PRs
# PR labeling has two parts:
#
# 1. `paths` job — runs actions/labeler against .github/labeler.yml to
# apply [Aspect], [Focus], [Feature], and [Type] Documentation
# labels. These have no count limit and a wide refactor can match
# many of them legitimately.
#
# 2. `package-and-type` job — applies the `[Package][...]` labels and
# a single inferred `[Type]` label. This one needs custom logic:
#
# - [Package]: ranks packages by total lines changed
# (additions + deletions, file count as tiebreaker) and applies
# at most the top 3. Without this cap, a cross-cutting change
# ends up with a wall of package labels and the signal is lost.
#
# - [Type]: parses the PR title's conventional-commit prefix
# (fix:/feat:/perf:) and applies one matching label only when
# the signal is unambiguous. We skip refactor:/chore:/test:
# because they have no clean target label.
#
# History note: an earlier version used GitHub Models (actions/ai-inference)
# to suggest labels from PR title + body + paths. That returned 403
# because GitHub Models access in Actions is gated by an org-level toggle
# we can't flip. Path + PR-title heuristics cover the structured labels
# without any external service.
on:
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review]
# Disable permissions for all available scopes by default.
# Any needed permissions should be configured at the job level.
permissions: {}
jobs:
paths:
if: github.repository == 'WordPress/wordpress-playground'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read # Required for actions/labeler to read the configuration file.
pull-requests: write # Required to apply labels to pull requests.
steps:
# Pinned to a commit SHA, not a tag: this job runs with
# pull-requests:write, so a moved tag would be a supply-chain
# foothold. Bump deliberately when upgrading.
- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
with:
configuration-path: .github/labeler.yml
sync-labels: false
package-and-type:
if: github.repository == 'WordPress/wordpress-playground'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
pull-requests: write # Required to apply labels to pull requests.
steps:
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
// Path prefix → [Package][...] label. Order matters: the
// first matching prefix wins, so longer / more specific
// prefixes must come before shorter ones (e.g. `web-service-worker`
// before `web`).
const PACKAGE_RULES = [
['packages/php-wasm/cli-util/', '[Package][@php-wasm] CLI-Util'],
['packages/php-wasm/cli/', '[Package][@php-wasm] CLI'],
['packages/php-wasm/compile/', '[Package][@php-wasm] Compile'],
['packages/php-wasm/fs-journal/', '[Package][@php-wasm] FS Journal'],
['packages/php-wasm/logger/', '[Package][@php-wasm] Logger'],
['packages/php-wasm/node/', '[Package][@php-wasm] Node'],
['packages/php-wasm/progress/', '[Package][@php-wasm] Progress'],
['packages/php-wasm/scopes/', '[Package][@php-wasm] Scopes'],
['packages/php-wasm/stream-compression/','[Package][@php-wasm] Stream Compression'],
['packages/php-wasm/universal/', '[Package][@php-wasm] Universal'],
['packages/php-wasm/util/', '[Package][@php-wasm] Util'],
['packages/php-wasm/web-service-worker/','[Package][@php-wasm] Web'],
['packages/php-wasm/web/', '[Package][@php-wasm] Web'],
['packages/php-wasm/xdebug-bridge/', '[Package][@php-wasm] Xdebug Bridge'],
['packages/playground/blueprints/', '[Package][@wp-playground] Blueprints'],
['packages/playground/cli/', '[Package][@wp-playground] CLI'],
['packages/playground/client/', '[Package][@wp-playground] Client'],
['packages/playground/common/', '[Package][@wp-playground] Common'],
['packages/playground/components/', '[Package][@wp-playground] Components'],
['packages/playground/php-cors-proxy/', '[Package][@wp-playground] CORS Proxy'],
['packages/playground/remote/', '[Package][@wp-playground] Remote'],
['packages/playground/storage/', '[Package][@wp-playground] Storage'],
['packages/playground/sync/', '[Package][@wp-playground] Sync'],
['packages/playground/website-extras/', '[Package][@wp-playground] Website'],
['packages/playground/website/', '[Package][@wp-playground] Website'],
['packages/playground/wordpress-builds/','[Package][@wp-playground] WordPress Builds'],
['packages/playground/wordpress/', '[Package][@wp-playground] WordPress'],
];
// Conventional-commit prefix → [Type] label. Only entries
// with an unambiguous target label are listed; refactor /
// chore / test / build / ci are intentionally absent.
const TYPE_RULES = [
[/^fix(\(|:)/i, '[Type] Bug'],
[/^feat(ure)?(\(|:)/i, '[Type] Enhancement'],
[/^perf(\(|:)/i, '[Type] Performance'],
[/^docs(\(|:)/i, '[Type] Documentation'],
];
const pr = context.payload.pull_request;
const files = await github.paginate(
github.rest.pulls.listFiles,
{ owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.number, per_page: 100 }
);
// Tally lines + file count per package label.
const stats = new Map();
for (const f of files) {
const rule = PACKAGE_RULES.find(([prefix]) => f.filename.startsWith(prefix));
if (!rule) continue;
const label = rule[1];
const lines = (f.additions || 0) + (f.deletions || 0);
const cur = stats.get(label) || { lines: 0, files: 0 };
stats.set(label, { lines: cur.lines + lines, files: cur.files + 1 });
}
// Rank: lines desc, then file count desc, then label name
// for stable output.
const topPackages = [...stats.entries()]
.sort(([a, sa], [b, sb]) =>
sb.lines - sa.lines ||
sb.files - sa.files ||
a.localeCompare(b)
)
.slice(0, 3)
.map(([label]) => label);
const labels = [...topPackages];
const titleMatch = TYPE_RULES.find(([re]) => re.test(pr.title));
if (titleMatch) labels.push(titleMatch[1]);
core.info(`PR title: ${pr.title}`);
core.info(`Package stats: ${JSON.stringify([...stats])}`);
core.info(`Applying labels: ${JSON.stringify(labels)}`);
if (labels.length === 0) return;
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels,
});