Skip to content

Commit 4c556a1

Browse files
committed
[actions] add workflow to update nodejs.org nvm version
Ref: nodejs/nodejs.org#8628
1 parent 62387b8 commit 4c556a1

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed

.github/workflows/nodejs-org.yml

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
name: 'Update nodejs.org'
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
workflow_dispatch:
8+
inputs:
9+
version:
10+
description: 'nvm version tag (e.g., v0.40.4). Defaults to latest release.'
11+
required: false
12+
default: ''
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
update-nodejs-org:
19+
if: github.repository == 'nvm-sh/nvm' && github.actor == 'ljharb'
20+
permissions:
21+
contents: none
22+
name: 'Create PR to nodejs/nodejs.org'
23+
runs-on: ubuntu-latest
24+
steps:
25+
- name: Harden Runner
26+
uses: step-security/harden-runner@v2
27+
with:
28+
allowed-endpoints:
29+
github.com:443
30+
api.github.com:443
31+
32+
- name: Extract and validate version
33+
id: version
34+
run: |
35+
set -euo pipefail
36+
37+
INPUT_VERSION="${{ inputs.version }}"
38+
39+
if [ -n "${INPUT_VERSION}" ]; then
40+
TAG="${INPUT_VERSION}"
41+
elif [ "${GITHUB_REF_TYPE}" = "tag" ]; then
42+
TAG="${GITHUB_REF#refs/tags/}"
43+
else
44+
TAG="$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name')"
45+
fi
46+
47+
if ! printf '%s\n' "${TAG}" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
48+
echo "::notice::Tag '${TAG}' does not match expected format vX.Y.Z, skipping"
49+
exit 0
50+
fi
51+
52+
printf 'tag=%s\n' "${TAG}" >> "${GITHUB_OUTPUT}"
53+
env:
54+
GH_TOKEN: ${{ github.token }}
55+
56+
- name: Set up fork and branch
57+
if: steps.version.outputs.tag
58+
id: fork
59+
run: |
60+
set -euo pipefail
61+
62+
BRANCH="nvm-${{ steps.version.outputs.tag }}"
63+
64+
gh repo fork nodejs/nodejs.org --clone=false 2>&1 || true
65+
FORK_OWNER="$(gh api user --jq '.login')"
66+
67+
DEFAULT_BRANCH="$(gh api repos/nodejs/nodejs.org --jq '.default_branch')"
68+
UPSTREAM_SHA="$(gh api "repos/nodejs/nodejs.org/git/ref/heads/${DEFAULT_BRANCH}" --jq '.object.sha')"
69+
70+
# Create or reset branch on fork to upstream HEAD
71+
if ! gh api "repos/${FORK_OWNER}/nodejs.org/git/refs" \
72+
-f "ref=refs/heads/${BRANCH}" \
73+
-f "sha=${UPSTREAM_SHA}" > /dev/null 2>&1; then
74+
gh api "repos/${FORK_OWNER}/nodejs.org/git/refs/heads/${BRANCH}" \
75+
-X PATCH \
76+
-f "sha=${UPSTREAM_SHA}" \
77+
-f "force=true" > /dev/null
78+
fi
79+
80+
printf 'fork_owner=%s\n' "${FORK_OWNER}" >> "${GITHUB_OUTPUT}"
81+
printf 'branch=%s\n' "${BRANCH}" >> "${GITHUB_OUTPUT}"
82+
env:
83+
GH_TOKEN: ${{ secrets.NODEJS_ORG_TOKEN }}
84+
85+
- name: Update nvm version in English snippet
86+
if: steps.version.outputs.tag
87+
id: update
88+
run: |
89+
set -euo pipefail
90+
91+
NEW_VERSION="${{ steps.version.outputs.tag }}"
92+
FORK_OWNER="${{ steps.fork.outputs.fork_owner }}"
93+
BRANCH="${{ steps.fork.outputs.branch }}"
94+
FILE_PATH="apps/site/snippets/en/download/nvm.bash"
95+
PATTERN='nvm-sh/nvm/v[0-9]+\.[0-9]+\.[0-9]+/install\.sh'
96+
REPLACEMENT="nvm-sh/nvm/${NEW_VERSION}/install.sh"
97+
98+
# Get file content via API
99+
FILE_RESPONSE="$(gh api "repos/${FORK_OWNER}/nodejs.org/contents/${FILE_PATH}?ref=${BRANCH}")"
100+
FILE_SHA="$(printf '%s' "${FILE_RESPONSE}" | jq -r '.sha')"
101+
printf '%s' "${FILE_RESPONSE}" | jq -r '.content' | base64 -d > "${RUNNER_TEMP}/nvm.bash"
102+
103+
# Validate exactly 1 match
104+
MATCH_COUNT="$(grep -cE "${PATTERN}" "${RUNNER_TEMP}/nvm.bash" || true)"
105+
106+
if [ "${MATCH_COUNT}" -eq 0 ]; then
107+
echo "::error::No nvm version pattern found in ${FILE_PATH}"
108+
exit 1
109+
fi
110+
111+
if [ "${MATCH_COUNT}" -ne 1 ]; then
112+
echo "::error::Expected exactly 1 nvm version match in ${FILE_PATH}, found ${MATCH_COUNT}"
113+
exit 1
114+
fi
115+
116+
# Replace and check for changes
117+
cp "${RUNNER_TEMP}/nvm.bash" "${RUNNER_TEMP}/nvm.bash.orig"
118+
sed -i -E "s|${PATTERN}|${REPLACEMENT}|g" "${RUNNER_TEMP}/nvm.bash"
119+
120+
if cmp -s "${RUNNER_TEMP}/nvm.bash" "${RUNNER_TEMP}/nvm.bash.orig"; then
121+
echo "::notice::English snippet already has version ${NEW_VERSION}"
122+
exit 0
123+
fi
124+
125+
if ! grep -qF "${REPLACEMENT}" "${RUNNER_TEMP}/nvm.bash"; then
126+
echo "::error::Replacement verification failed in ${FILE_PATH}"
127+
exit 1
128+
fi
129+
130+
# Update file via GitHub API (avoids git push workflow scope requirement)
131+
NEW_CONTENT_B64="$(base64 -w 0 < "${RUNNER_TEMP}/nvm.bash")"
132+
gh api "repos/${FORK_OWNER}/nodejs.org/contents/${FILE_PATH}" \
133+
-X PUT \
134+
-f "message=meta: bump nvm to ${NEW_VERSION}" \
135+
-f "content=${NEW_CONTENT_B64}" \
136+
-f "sha=${FILE_SHA}" \
137+
-f "branch=${BRANCH}" \
138+
-f "committer[name]=github-actions[bot]" \
139+
-f "committer[email]=41898282+github-actions[bot]@users.noreply.github.com" > /dev/null
140+
141+
printf 'updated=true\n' >> "${GITHUB_OUTPUT}"
142+
env:
143+
GH_TOKEN: ${{ secrets.NODEJS_ORG_TOKEN }}
144+
145+
- name: Create pull request
146+
if: steps.update.outputs.updated
147+
run: |
148+
set -euo pipefail
149+
150+
NEW_VERSION="${{ steps.version.outputs.tag }}"
151+
FORK_OWNER="${{ steps.fork.outputs.fork_owner }}"
152+
BRANCH="${{ steps.fork.outputs.branch }}"
153+
154+
BODY="Updates the English nvm install snippet to [\`${NEW_VERSION}\`](https://github.com/nvm-sh/nvm/releases/tag/${NEW_VERSION}). The translation system handles other locales.
155+
156+
Ref: https://github.com/nodejs/nodejs.org/issues/8628"
157+
158+
gh pr create \
159+
--repo nodejs/nodejs.org \
160+
--head "${FORK_OWNER}:${BRANCH}" \
161+
--title "meta: bump nvm to ${NEW_VERSION}" \
162+
--body "${BODY}"
163+
env:
164+
GH_TOKEN: ${{ secrets.NODEJS_ORG_TOKEN }}

0 commit comments

Comments
 (0)