Repository navigation
173 lines (163 loc) · 7.59 KB
/
Copy pathrelease.yml
File metadata and controls
173 lines (163 loc) · 7.59 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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
name: Manual NPM Publish
on:
workflow_dispatch:
inputs:
distTag:
description: 'NPM tag (e.g. use "next" to release a test version)'
required: false
type: string
default: 'latest'
releaseType:
description: 'Release type for monorepo root (drives the v* tag)'
required: true
type: choice
options:
- patch
- minor
- major
default: 'patch'
env:
NPM_CONFIG_PROVENANCE: true
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
# The pin bump below opens a PR rather than pushing to main.
pull-requests: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: 'main'
fetch-depth: 0
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: .nvmrc
# the runner cache can hold a 24.x below the engines floor
check-latest: true
registry-url: "https://registry.npmjs.org"
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
with:
version: 10.26.1
run_install: true
- name: Git Setup
run: |
git config --global user.email "bot@webdriver.io"
git config --global user.name "WebdriverIO Release Bot"
- name: Install Dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm -r build
- name: Consume changesets
run: npx changeset version
- name: Publish
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
DIST_TAG: ${{ inputs.distTag }}
run: npx changeset publish --tag "${DIST_TAG}" --no-git-tag
- name: GitHub Release & Tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG=$(npm version ${{ inputs.releaseType }})
git push origin main
git push origin "$TAG"
gh release create "$TAG" \
--title "$TAG" \
--generate-notes \
--verify-tag
# `BACKEND_NPM_VERSION` is the backend a `pip install` user actually runs,
# and nothing derives it: the Python adapter is not in the pnpm workspace,
# so changesets never sees it. Left to a human it is remembered late —
# `check_backend_pin.py` then fails every Python CI run and blocks the
# PyPI publish until someone edits one line.
#
# Opened as a PR, never pushed to main: the new backend has to be ON npm
# for the check to pass, which is why this runs after Publish, and a pin
# is a claim about a published artifact that deserves a review.
#
# A PR raised with GITHUB_TOKEN gets no CI — GitHub suppresses workflow
# runs for events its own token raises, to stop recursion. Set
# PIN_BUMP_TOKEN (a PAT or App token) and the checks run on their own;
# without it the PR needs a nudge, which its body says.
#
# Only for a `latest` release: the pin is what a `pip install` user gets,
# and a `next` publish is a test version nobody should be moved onto.
- name: Open the Python backend pin bump
if: inputs.distTag == 'latest' || inputs.distTag == ''
env:
GITHUB_TOKEN: ${{ secrets.PIN_BUMP_TOKEN || secrets.GITHUB_TOKEN }}
PIN_FILE: packages/selenium-devtools-py/src/selenium_devtools/constants.py
run: |
set -euo pipefail
BACKEND=$(node -p "require('./packages/backend/package.json').version")
PIN=$(sed -n 's/^BACKEND_NPM_VERSION = "\(.*\)"$/\1/p' "$PIN_FILE")
if [ -z "$PIN" ]; then
echo "::error::No BACKEND_NPM_VERSION found in $PIN_FILE"
exit 1
fi
if [ "$BACKEND" = "$PIN" ]; then
echo "Backend unchanged at $PIN — nothing to bump."
exit 0
fi
# This value reaches a `sed` expression and a branch name. It comes
# from our own package.json, so this is a belt rather than a fix for
# a known hole — but a stray `/` would silently corrupt the pin.
case "$BACKEND" in
''|*[!0-9A-Za-z.+-]*)
echo "::error::Backend version is not plain semver: $BACKEND"
exit 1
;;
esac
# Only ever forward. A release that rolls the backend BACK — a revert
# on main, or a republish of an older `latest` — would otherwise open
# a PR lowering the pin onto a backend that may not serve the
# contract; `check_backend_pin.py` would reject it, after the noise.
NEWER=$(printf '%s\n%s\n' "$PIN" "$BACKEND" | sort -V | tail -1)
if [ "$NEWER" = "$PIN" ]; then
echo "Published backend $BACKEND is older than the pin $PIN — leaving it alone."
exit 0
fi
BRANCH="chore/pin-backend-$BACKEND"
FRAGMENT="packages/selenium-devtools-py/changes/pin-backend-$BACKEND.md"
# Continue the branch if it is already out there rather than recreating
# it: this step runs after `changeset publish`, so a re-run is normal,
# and by then a reviewer may have pushed to the open PR — regenerating
# `_contract.py` is the expected reason. A force push would erase that
# work, so there is none: we branch FROM the remote when it exists and
# fast-forward it.
git fetch --quiet origin "$BRANCH" 2>/dev/null || true
if git rev-parse --verify --quiet "origin/$BRANCH" >/dev/null; then
git switch -c "$BRANCH" "origin/$BRANCH"
else
git switch -c "$BRANCH"
fi
sed -i "s/^BACKEND_NPM_VERSION = .*/BACKEND_NPM_VERSION = \"$BACKEND\"/" "$PIN_FILE"
# Required, not decorative: python.yml refuses a branch that changes
# `src/` and documents nothing, so a pin-only PR would fail its own CI.
printf -- '---\npatch\n---\n\nPin the backend a `pip install` user runs to %s.\n' \
"$BACKEND" > "$FRAGMENT"
# Named explicitly because the fragment is UNTRACKED: `commit -a`
# stages modified tracked files only, so it would ship the pin without
# the fragment that makes the pin mergeable.
git add "$PIN_FILE" "$FRAGMENT"
if git diff --cached --quiet; then
echo "Branch $BRANCH already carries this bump — nothing to push."
else
git commit -m "chore(python): pin the backend to $BACKEND"
git push origin "$BRANCH"
fi
if [ "$(gh pr list --head "$BRANCH" --state open --json number --jq 'length')" != "0" ]; then
echo "A pin PR for $BACKEND is already open — left as it is."
exit 0
fi
gh pr create --base main --head "$BRANCH" \
--title "chore(python): pin the backend to $BACKEND" \
--body "$(printf '%s\n' \
"\`@wdio/devtools-backend@$BACKEND\` is published, so the version a \`pip install\` user runs can move up from $PIN." \
"" \
"Opened by the npm release. \`scripts/check_backend_pin.py\` is what decides whether this pin is serviceable — it asks the published tarball whether it carries every contract name the adapter needs, so let that check run before merging." \
"" \
"If this PR shows no checks, it was raised with \`GITHUB_TOKEN\`, which GitHub will not let start a workflow. Close and reopen it, or push an empty commit, to get CI." )"