Repository navigation
106 lines (95 loc) · 4.61 KB
/
Copy pathpull-requests.yml
File metadata and controls
106 lines (95 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
name: Pull request rules
on:
pull_request:
types: [opened, edited, synchronize, reopened]
branches: [dev, beta, main]
permissions:
contents: read
# An edit re-runs every job on the same commit; the newest run's results are the ones that count.
concurrency:
group: pull-request-rules-${{ github.event.pull_request.number }}
cancel-in-progress: true
# The job names are required status checks of the `dev` and `release branches` rulesets; renaming one blocks every merge.
jobs:
commits:
name: Commit messages
# A PR into dev lands as one squash commit headed by its title; a hotfix lands on main with its own commits.
if: github.base_ref == 'dev' || (github.base_ref == 'main' && github.head_ref != 'beta')
runs-on: ubuntu-latest
steps:
- name: checkout cli
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
# Only the hotfix lint into main reads history; the title path needs one commit.
fetch-depth: ${{ github.base_ref == 'dev' && 1 || 0 }}
- name: setup pnpm
uses: pnpm/action-setup@a15d269cd4658e1107c09f1fabf4cbd7bd1f308a # v4.4.0
with:
version: 11.0.8
standalone: true
- name: setup node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '24'
cache: 'pnpm'
cache-dependency-path: pnpm-lock.yaml
- name: install dependencies
run: pnpm install --frozen-lockfile
# The squash commit is the title plus the description, so both are linted as that commit: a breaking footer in the description needs ! in the title.
- name: lint the title and description
if: github.base_ref == 'dev'
env:
TITLE: ${{ github.event.pull_request.title }}
BODY: ${{ github.event.pull_request.body }}
run: printf '%s\n\n%s\n' "$TITLE" "$BODY" | pnpm exec commitlint --config .github/commitlint-pull-request.cjs --verbose
- name: lint the commits
if: github.base_ref == 'main'
env:
FROM: ${{ github.event.pull_request.base.sha }}
TO: ${{ github.event.pull_request.head.sha }}
run: pnpm exec commitlint --from "$FROM" --to "$TO" --verbose
source:
name: Promotion source
runs-on: ubuntu-latest
steps:
- name: checkout cli
if: github.base_ref != 'dev'
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
fetch-depth: 0
- name: check where the pull request comes from
env:
TARGET: ${{ github.base_ref }}
SOURCE: ${{ github.head_ref }}
SOURCE_REPO: ${{ github.event.pull_request.head.repo.full_name }}
SOURCE_SHA: ${{ github.event.pull_request.head.sha }}
REPO: ${{ github.repository }}
run: |
refuse() { echo "::error::$1"; exit 1; }
# Only exit 1 means "not an ancestor"; any other git failure ends the check with git's own message.
contains() { git merge-base --is-ancestor "$1" "$2" || { status=$?; [ "$status" -eq 1 ] && return 1; exit "$status"; }; }
if [ "$TARGET" = dev ]; then
[ "$SOURCE" != 1.x ] || refuse "1.x is never merged into dev; make the fix again on a branch cut from dev."
exit 0
fi
[ "$SOURCE_REPO" = "$REPO" ] || refuse "$TARGET takes pull requests only from branches in $REPO, not from $SOURCE_REPO."
case "$TARGET" in
beta)
[ "$SOURCE" = dev ] || refuse "$TARGET takes pull requests only from dev, not from $SOURCE."
contains origin/main "$SOURCE_SHA" ||
refuse "dev does not contain main yet, so this release would miss main's tag: merge main into dev first (the last release run on main says how)." ;;
main)
case "$SOURCE" in
dev|1.x) refuse "main takes beta or a hotfix branch cut from main, not $SOURCE." ;;
beta)
contains origin/main "$SOURCE_SHA" ||
refuse "beta does not contain main yet: merge main into dev, promote dev to beta, then promote beta." ;;
*)
unreleased=$(git rev-list --count "$SOURCE_SHA" ^origin/main)
hotfix_only=$(git rev-list --count "$SOURCE_SHA" ^origin/main ^origin/dev)
[ "$unreleased" = "$hotfix_only" ] ||
refuse "$SOURCE carries commits from dev that no beta has shipped; cut the hotfix branch from main." ;;
esac ;;
esac