Skip to content

chore(deps): bump the test-versions group across 1 directory with 36 updates #607

chore(deps): bump the test-versions group across 1 directory with 36 updates

chore(deps): bump the test-versions group across 1 directory with 36 updates #607

Workflow file for this run

name: Pull Request Title
on:
pull_request_target:
types: [opened, edited, reopened]
branches:
- "master"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
conventional-commit:
runs-on: ubuntu-latest
permissions:
pull-requests: write
env:
# Shared between both steps. Must stay portable across bash ERE and JS
# regex (no lookarounds, named groups, or other JS-only features).
# Revert PRs nest the reverted commit's type, e.g. `revert: feat(api): undo X`,
# so the semver label can track the magnitude of the original change.
PR_TITLE_PATTERN: '^(revert(!)?: )?(feat|fix|docs|style|refactor|perf|test|bench|build|ci|chore)(\(([^)]+)\))?(!)?: .+'
steps:
- name: Validate PR title against Conventional Commits
if: github.event.action != 'edited' || github.event.changes.title != null
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
if [[ ! "$PR_TITLE" =~ $PR_TITLE_PATTERN ]]; then
echo "::error::PR title does not follow Conventional Commits format."
echo "Got: $PR_TITLE"
echo "Expected: <type>(<scope>)?(!)?: <subject>"
echo " revert(!)?: <type>(<scope>)?(!)?: <subject> (for reverts)"
echo "Allowed types: feat, fix, docs, style, refactor, perf, test, bench, build, ci, chore"
echo "Revert PRs must embed the original commit's type so the semver impact can"
echo "be determined (e.g. 'revert: feat(scope): original title')."
echo "Reverts of reverts re-apply the original change, so use the original"
echo "title (e.g. 'feat: x', not 'revert: revert: feat: x')."
exit 1
fi
echo "PR title OK: $PR_TITLE"
- name: Sync labels with PR title
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const pattern = new RegExp(process.env.PR_TITLE_PATTERN)
const parse = (title) => {
const m = (title || '').match(pattern)
if (!m) return {}
const isRevert = !!m[1]
return {
type: isRevert ? 'revert' : m[3],
revertedType: isRevert ? m[3] : undefined,
scope: m[5],
breaking: m[2] === '!' || m[6] === '!',
}
}
// For reverts, the semver bump tracks the magnitude of the change
// being undone, parsed from the nested type in the title.
const semverFor = ({ type, revertedType, breaking }) => {
if (!type) return undefined
if (breaking) return 'semver-major'
const effective = type === 'revert' ? revertedType : type
if (effective === 'feat') return 'semver-minor'
return 'semver-patch'
}
const pr = context.payload.pull_request
const next = parse(pr.title)
// Prefetch all existing repo labels once to avoid per-label API calls.
const repoLabels = new Set()
for await (const page of github.paginate.iterator(github.rest.issues.listLabelsForRepo, { ...context.repo, per_page: 100 })) {
for (const label of page.data) repoLabels.add(label.name)
}
// Returns the set of labels derived from a parsed title.
// Type and scope are only added if they exist in the repo.
const titledLabels = (parsed) => {
const labels = new Set()
if (!parsed.type) return labels
if (repoLabels.has(parsed.type)) labels.add(parsed.type)
if (parsed.scope && repoLabels.has(parsed.scope)) labels.add(parsed.scope)
const semver = semverFor(parsed)
if (semver) labels.add(semver)
return labels
}
const nextLabels = titledLabels(next)
const current = new Set((pr.labels || []).map(l => l.name))
// When the title changes, remove labels from the old title that no
// longer apply so stale type/scope/semver labels don't linger.
const titleChanged = context.payload.action === 'edited' &&
context.payload.changes?.title?.from != null
const toRemove = new Set()
if (titleChanged) {
const prev = parse(context.payload.changes.title.from)
for (const label of titledLabels(prev)) {
if (!nextLabels.has(label)) toRemove.add(label)
}
}
const desired = new Set([...current].filter(l => !toRemove.has(l)))
for (const label of nextLabels) desired.add(label)
const unchanged = current.size === desired.size && [...current].every(l => desired.has(l))
if (!unchanged) {
await github.rest.issues.setLabels({
...context.repo,
issue_number: pr.number,
labels: [...desired],
})
}