chore(deps): bump the test-versions group across 1 directory with 36 updates #607
Workflow file for this run
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: 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], | |
| }) | |
| } |