forked from xmppo/node-expat
-
Notifications
You must be signed in to change notification settings - Fork 1
203 lines (186 loc) · 7.1 KB
/
prebuild.yml
File metadata and controls
203 lines (186 loc) · 7.1 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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
name: prebuild
on:
push:
branches: [master, main]
pull_request:
workflow_dispatch:
# Least-privilege default: matrix jobs only need to read the repo to clone.
# The `release` job overrides this below with `contents: write` for upload.
permissions:
contents: read
# Node versions to produce prebuilds for. One .tar.gz per ABI per
# (platform, arch, libc) combination is produced. On consumer install,
# prebuild-install downloads only the asset matching the consumer's runtime.
env:
NODE_TARGETS: "24.15.0 26.1.0"
jobs:
prebuild:
name: ${{ matrix.id }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
# darwin-x64 is cross-compiled from a macos-14 (arm64) runner because
# macos-13 runners have very limited capacity. Apple Silicon clang
# produces x86_64 binaries natively when asked with --arch x64.
- id: darwin-x64
runner: macos-14
arch: x64
- id: darwin-arm64
runner: macos-14
- id: linux-x64-glibc
runner: ubuntu-latest
- id: linux-x64-musl
runner: ubuntu-latest
musl: true
- id: linux-arm64-glibc
runner: ubuntu-24.04-arm
- id: linux-arm64-musl
runner: ubuntu-24.04-arm
musl: true
- id: win32-x64
runner: windows-latest
# GitHub's native ARM64 Windows runner. Free on public repos; private
# repos may need "larger runners" enabled in org settings.
- id: win32-arm64
runner: windows-11-arm
steps:
- uses: actions/checkout@v5
- name: Set up Node (non-musl jobs)
if: ${{ !matrix.musl }}
uses: actions/setup-node@v5
with:
node-version: '24'
- name: Install npm deps (non-musl)
if: ${{ !matrix.musl }}
run: npm ci --ignore-scripts
- name: Build prebuilds for all target ABIs (non-musl)
if: ${{ !matrix.musl }}
shell: bash
env:
MATRIX_ARCH: ${{ matrix.arch }}
run: |
set -euo pipefail
args=""
for v in $NODE_TARGETS; do
args="$args -t $v"
done
# --tag-libc adds glibc/musl suffix on linux assets so prebuild-install
# can pick the right one on the consumer side. On other platforms it
# is a no-op.
args="$args --tag-libc"
# --strip relies on the binutils `strip` tool which isn't shipped on
# Windows runners. Skip it there; debug symbols stay in the .node
# binary, which is fine functionally (just larger).
if [ "${RUNNER_OS:-}" != "Windows" ]; then
args="$args --strip"
fi
# When MATRIX_ARCH is set (e.g. cross-compiling darwin-x64 from an
# arm64 runner), forward it to node-gyp via prebuild's --arch.
if [ -n "${MATRIX_ARCH:-}" ]; then
args="$args --arch $MATRIX_ARCH"
fi
npx prebuild $args
# Musl path runs inside docker rather than using `container:`, because
# GitHub Actions JavaScript actions can't run in Alpine containers on
# ARM64 runners. Doing the whole build inside `docker run` sidesteps
# that limitation and keeps the x64/arm64 musl steps identical.
- name: Build musl prebuilds via Alpine docker
if: ${{ matrix.musl }}
shell: bash
run: |
set -euo pipefail
docker run --rm \
-v "$PWD":/work -w /work \
-e NODE_TARGETS="$NODE_TARGETS" \
node:24-alpine sh -c '
set -e
apk add --no-cache python3 make g++ git tar
npm ci --ignore-scripts
args=""
for v in $NODE_TARGETS; do
args="$args -t $v"
done
npx prebuild $args --strip --tag-libc
'
- name: Verify each tarball contains a .node binary
shell: bash
run: |
set -euo pipefail
ls -la prebuilds/
shopt -s nullglob
tarballs=(prebuilds/*.tar.gz)
if [ ${#tarballs[@]} -eq 0 ]; then
echo "ERROR: no prebuilds produced" >&2
exit 1
fi
for f in "${tarballs[@]}"; do
echo "--- $f ---"
tar -tzf "$f"
tar -tzf "$f" | grep -q '\.node$' || { echo "ERROR: no .node file in $f" >&2; exit 1; }
done
- uses: actions/upload-artifact@v7
with:
name: prebuilds-${{ matrix.id }}
path: prebuilds/*.tar.gz
if-no-files-found: error
retention-days: 30
# Release flow: only fires on push to master, only after every matrix
# job succeeded, and only when the package.json version on the new
# commit does not yet have a matching `v<version>` tag on origin.
# That makes the release a function of "merged version bump to master"
# — no manual tagging required.
release:
name: auto-release on version bump
needs: prebuild
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v5
- name: Read version from package.json
id: version
run: |
set -euo pipefail
v=$(node -p "require('./package.json').version")
echo "version=$v" >> "$GITHUB_OUTPUT"
echo "tag=v$v" >> "$GITHUB_OUTPUT"
echo "Detected package version: $v (target tag: v$v)"
- name: Check whether tag already exists on origin
id: check_tag
run: |
set -euo pipefail
tag="${{ steps.version.outputs.tag }}"
if git ls-remote --tags origin "refs/tags/$tag" | grep -q .; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "Tag $tag already exists on origin — nothing to release."
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "Tag $tag does not exist yet — will create release."
fi
- name: Download all prebuild artifacts
if: steps.check_tag.outputs.exists == 'false'
uses: actions/download-artifact@v8
with:
pattern: prebuilds-*
path: artifacts
merge-multiple: true
- name: List downloaded assets
if: steps.check_tag.outputs.exists == 'false'
run: ls -la artifacts/
- name: Create tag and Release, upload assets
if: steps.check_tag.outputs.exists == 'false'
uses: softprops/action-gh-release@v2
with:
# softprops/action-gh-release creates the tag itself when given
# `tag_name` + `target_commitish`. It uses GITHUB_TOKEN, so the
# resulting tag push does NOT re-trigger this workflow (GH's
# rule: events from GITHUB_TOKEN don't cascade).
tag_name: ${{ steps.version.outputs.tag }}
target_commitish: ${{ github.sha }}
name: ${{ steps.version.outputs.tag }}
files: artifacts/*.tar.gz
generate_release_notes: true
fail_on_unmatched_files: true