Repository navigation
372 lines (333 loc) · 14.9 KB
/
Copy pathunity-package.yml
File metadata and controls
372 lines (333 loc) · 14.9 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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# Build multi-platform native libraries and pack a Unity Package Manager (.tgz)
# Produces native bcsv_c_api binaries for:
# win-x64, linux-x64, linux-arm64, osx-arm64
# Then packs unity/ into a UPM-compatible .tgz tarball.
#
# Spoke of the release pipeline: build-test-archive ONLY. The .tgz is
# archived as the `unity-package` artifact; the "Release Ship" hub
# (release-publish.yml) attaches it to the GitHub Release once every spoke's
# tag run is green, and upm-branch.yml advances the `upm` branch after it.
name: Unity Package
on:
push:
tags:
# vX.Y.Z release tags only — never the CI-authored '*-upm' tags.
- 'v*.[0-9]*.[0-9]*'
- '!v*-*'
pull_request:
paths:
- 'unity/**'
- 'include/**'
- 'src/bcsv_c_api.cpp'
- 'CMakeLists.txt'
# The packing scripts decide what ships and whether it is fit to ship,
# so a change to either has to be exercised like a change to unity/.
- 'scripts/pack-unity.sh'
- 'scripts/check-unity-package.sh'
- 'scripts/run-unity-tests.sh'
- '.github/workflows/unity-package.yml'
workflow_dispatch:
concurrency:
group: unity-package-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
jobs:
# ── Build native shared library per platform ────────────────────────
build-native:
name: Native ${{ matrix.rid }}
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
# Built inside manylinux, not on the runner. A library built on
# ubuntu-latest carries that runner's glibc (2.39) and will not load
# on anything older, which for a package people install into their own
# projects is the whole ballgame. manylinux_2_28 is the same image
# pybcsv already builds its wheels in - see python/pyproject.toml - so
# it is known to compile this C++20 codebase; its GCC is 14.2.
- rid: linux-x64
os: ubuntu-latest
container: quay.io/pypa/manylinux_2_28_x86_64
lib-name: libbcsv_c_api.so
lib-dir: build
- rid: linux-arm64
os: ubuntu-24.04-arm
container: quay.io/pypa/manylinux_2_28_aarch64
lib-name: libbcsv_c_api.so
lib-dir: build
- rid: win-x64
os: windows-latest
lib-name: bcsv_c_api.dll
lib-dir: build/bin
- rid: osx-arm64
os: macos-15
lib-name: libbcsv_c_api.dylib
lib-dir: build
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
# Tags are needed so the build can verify VERSION.txt against the
# tag it claims to be. The default shallow fetch hides them.
fetch-depth: 0
- name: Trust the workspace (Linux containers)
if: matrix.container != ''
run: |
# These jobs run in a container while the workspace is created by the
# runner, so git sees a directory owned by someone else and refuses:
# "detected dubious ownership". Every git call then fails, and before
# BCSV_STRICT_VERSION existed the build quietly fell back to a stale
# VERSION.txt - that is how v1.5.12 shipped Linux natives stamped
# 1.5.11 while Windows, which runs on the bare runner, was correct.
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" describe --tags --always
- name: Install CMake and Ninja (Linux)
if: runner.os == 'Linux'
run: |
# The manylinux image ships neither, and its distro cmake predates
# what this project needs. pip carries both as wheels.
/opt/python/cp311-cp311/bin/pip install --quiet cmake ninja
echo "/opt/python/cp311-cp311/bin" >> "$GITHUB_PATH"
- name: Install Ninja (macOS)
if: runner.os == 'macOS'
run: brew install ninja
- name: Setup MSVC
if: runner.os == 'Windows'
uses: TheMrMilchmann/setup-msvc-dev@368ef7d1ee4d1171b31d4a7f67f4d954f903f5a9 # v4
with:
arch: x64
- name: Cache CMake dependencies
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: build/_deps
key: unity-native-deps-${{ matrix.rid }}-${{ hashFiles('CMakeLists.txt') }}
- name: Configure & Build (Unix)
if: runner.os != 'Windows'
run: |
# The C++ runtime is linked statically on Linux so the artifact does
# not need a matching libstdc++ on the target - built here with GCC 14
# it would otherwise demand GLIBCXX_3.4.32, far above the glibc floor.
# macOS neither needs that nor allows it: libc++ is part of the system
# and AppleClang rejects -static-libgcc outright.
EXTRA=()
if [[ "${{ runner.os }}" == "Linux" ]]; then
EXTRA+=(-DCMAKE_SHARED_LINKER_FLAGS="-static-libstdc++ -static-libgcc")
fi
cmake -G Ninja -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBCSV_WERROR=ON \
-DBCSV_STRICT_VERSION=ON \
-DBUILD_TESTS=OFF \
-DBUILD_BENCHMARKS=OFF \
-DBUILD_TOOLS=OFF \
-DBUILD_EXAMPLES=OFF \
"${EXTRA[@]}"
cmake --build build --target bcsv_c_api --parallel
- name: Configure & Build (Windows)
if: runner.os == 'Windows'
run: |
cmake -G Ninja -B build `
-DCMAKE_BUILD_TYPE=Release `
-DBCSV_WERROR=ON `
-DBCSV_STRICT_VERSION=ON `
-DBUILD_TESTS=OFF `
-DBUILD_BENCHMARKS=OFF `
-DBUILD_TOOLS=OFF `
-DBUILD_EXAMPLES=OFF `
-DCMAKE_POLICY_DEFAULT_CMP0091=NEW `
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded
cmake --build build --target bcsv_c_api --parallel
- name: Verify the built artifact
shell: bash
run: |
set -e
# One script does every artifact check (scripts/check_versions.py):
# it loads the library (catching unresolved imports a scan cannot
# see), round-trips a layout through the runtime the artifact
# carries, requires the export surface to be bcsv_* only
# (docs/adr/0007), requires self-containment (no system libstdc++
# or VC++ Redistributable), and asks the binary its version - the
# check that fails if the toolchain resolved anything other than
# what this release intends to ship.
if [[ "${{ runner.os }}" == "Linux" ]]; then
PY=/opt/python/cp311-cp311/bin/python # manylinux ships no system python3
elif command -v python3 >/dev/null 2>&1; then
PY=python3
else
PY=python # Windows runners expose python only
fi
ARGS=(--skip-manifests --self-contained --native "${{ matrix.lib-dir }}/${{ matrix.lib-name }}")
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
ARGS+=(--tag "${GITHUB_REF#refs/tags/}")
fi
"$PY" scripts/check_versions.py "${ARGS[@]}"
- name: Upload native library
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: unity-native-${{ matrix.rid }}
path: ${{ matrix.lib-dir }}/${{ matrix.lib-name }}
retention-days: 7
# ── Run the package's EditMode tests in a real editor ───────────────
#
# Opt-in: without a UNITY_LICENSE secret the job reports a notice and does
# nothing, so a fork or a repository that has not configured Unity CI is not
# broken by its presence. Configure UNITY_LICENSE (and UNITY_EMAIL /
# UNITY_PASSWORD for a Personal licence) to turn it on.
#
# Until then the same tests are run manually with
# scripts/run-unity-tests.sh <path-to-Unity-executable>
# which stages the native plugin placeholders the editor would otherwise
# delete. See the comment at the top of that script.
unity-tests:
name: Unity EditMode tests
needs: build-native
runs-on: ubuntu-latest
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
steps:
- name: Is a Unity licence configured?
id: licence
run: |
if [ -z "${UNITY_LICENSE:-}" ]; then
echo "have=false" >> "$GITHUB_OUTPUT"
echo "::notice::No UNITY_LICENSE secret; skipping the editor run. \
Run scripts/run-unity-tests.sh locally before releasing."
else
echo "have=true" >> "$GITHUB_OUTPUT"
fi
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
if: steps.licence.outputs.have == 'true'
- name: Download the linux-x64 native
if: steps.licence.outputs.have == 'true'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: unity-native-linux-x64
path: native-linux-x64
- name: Assemble a project around the package
if: steps.licence.outputs.have == 'true'
run: |
set -euo pipefail
# The editor deletes any .meta with no asset beside it, and three of
# the plugin sidecars describe binaries this job does not download.
# Placeholders keep them from being tidied away mid-run.
printf 'placeholder' > unity/Runtime/Plugins/Windows/x86_64/bcsv_c_api.dll
printf 'placeholder' > unity/Runtime/Plugins/Linux/arm64/libbcsv_c_api.so
printf 'placeholder' > unity/Runtime/Plugins/macOS/libbcsv_c_api.dylib
cp native-linux-x64/libbcsv_c_api.so unity/Runtime/Plugins/Linux/x86_64/
mkdir -p testproj/Packages testproj/Assets testproj/ProjectSettings
cat > testproj/Packages/manifest.json <<'JSON'
{
"dependencies": {
"com.bcsv.unity": "file:../../unity",
"com.unity.test-framework": "1.4.5"
},
"testables": [ "com.bcsv.unity" ]
}
JSON
- name: EditMode tests
if: steps.licence.outputs.have == 'true'
# NOT SHA-pinned, unlike every other action here. Pin it to a
# verified commit of game-ci/unity-test-runner v4 when this job is
# first enabled — a hash written without checking it is worse than
# a tag, because it looks pinned.
uses: game-ci/unity-test-runner@v4
with:
projectPath: testproj
unityVersion: 6000.0.81f1
testMode: editmode
artifactsPath: unity-test-results
- name: Publish results
if: steps.licence.outputs.have == 'true' && always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: unity-editmode-results
path: unity-test-results
retention-days: 7
# ── Pack Unity .tgz package ─────────────────────────────────────────
pack:
name: Pack .tgz
needs: build-native
runs-on: macos-15
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
- name: Download all native artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
path: native-artifacts
pattern: unity-native-*
- name: Stage native libraries into Plugins structure
run: |
cp native-artifacts/unity-native-win-x64/bcsv_c_api.dll \
unity/Runtime/Plugins/Windows/x86_64/
cp native-artifacts/unity-native-linux-x64/libbcsv_c_api.so \
unity/Runtime/Plugins/Linux/x86_64/
cp native-artifacts/unity-native-linux-arm64/libbcsv_c_api.so \
unity/Runtime/Plugins/Linux/arm64/
cp native-artifacts/unity-native-osx-arm64/libbcsv_c_api.dylib \
unity/Runtime/Plugins/macOS/
# Remove .gitkeep placeholders
find unity/Runtime/Plugins -name ".gitkeep" -delete
echo "=== Staged native libraries ==="
find unity/Runtime/Plugins -type f
- name: Resolve version from VERSION.txt
id: version
run: |
# VERSION.txt is the source of truth the natives were built from, so
# the package must carry the same number rather than re-deriving one
# from the ref. On a tag build the two are cross-checked and the job
# fails if they disagree.
RELEASE_VERSION="$(cat VERSION.txt)"
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
python3 scripts/check_versions.py --tag "${GITHUB_REF#refs/tags/}"
VERSION="$RELEASE_VERSION"
else
python3 scripts/check_versions.py
VERSION="${RELEASE_VERSION}-dev.$(date +%Y%m%d%H%M%S)"
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Package version: $VERSION"
- name: Patch package.json version
run: |
cd unity
python3 -c "
import json
with open('package.json', 'r') as f:
pkg = json.load(f)
pkg['version'] = '${{ steps.version.outputs.version }}'
with open('package.json', 'w') as f:
json.dump(pkg, f, indent=2)
f.write('\n')
print(f'Updated package.json version to: {pkg[\"version\"]}')
"
- name: Pack .tgz (UPM format)
run: |
# UPM .tgz must contain a top-level "package/" directory.
# pack-unity.sh selects what ships; check-unity-package.sh refuses to
# let the job continue if anything staged would import badly.
./scripts/pack-unity.sh staging/package
./scripts/check-unity-package.sh staging/package
TARBALL="com.bcsv.unity-${{ steps.version.outputs.version }}.tgz"
tar -czf "${TARBALL}" -C staging package
ls -lh "${TARBALL}"
echo "tarball=${TARBALL}" >> "$GITHUB_OUTPUT"
- name: Inspect package contents
run: |
TARBALL="com.bcsv.unity-${{ steps.version.outputs.version }}.tgz"
tar -tzf "${TARBALL}" | head -50
- name: Upload .tgz
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: unity-package
path: com.bcsv.unity-*.tgz
retention-days: 30
# ── Release attachment intentionally does NOT happen here ───────────
# The hub ("Release Ship", release-publish.yml) downloads the
# `unity-package` .tgz archived by this workflow's green tag run and adds
# it to the GitHub Release — together with every other channel, after the
# whole fleet is green. Keeping the .tgz at 30-day retention here is what
# lets the hub fetch it across runs.