-
Notifications
You must be signed in to change notification settings - Fork 0
640 lines (620 loc) · 27.2 KB
/
Copy pathci.yml
File metadata and controls
640 lines (620 loc) · 27.2 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
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
# The acceptance gate, on GitHub Actions (PLAN.md §13.7, M12c).
#
# verify the TypeScript workspace: build, typecheck, tests, schemas/ drift
# java the Spoon extractor's own suite
# java-native the GraalVM binary — ONE JOB PER OS, because native-image
# drives the host linker and cannot cross-compile the way
# `dotnet publish -r <rid>` can. Each job builds AND smoke-tests
# on its own runner, so the matrix is five jobs, not 5+5
# csharp-test the Roslyn extractor's own suite (per-line schema validation included)
# csharp-publish one self-contained single-file binary per RID, from ONE Linux host
# csharp-smoke each binary runs on a runner of ITS OWN OS and must reproduce
# the committed fixture snapshot byte for byte — the cross-OS gate
# the plan could only delegate to a laptop under GitLab
# typescript-smoke the bundled TypeScript extractor on a runner of each OS must
# reproduce its fixture snapshot byte for byte (PLAN.md §14.7):
# Windows paths, CRLF checkouts, case-insensitive walks
# release on a v* tag, the five binaries attached to a GitHub Release,
# and the TypeScript extractor published to npm when NPM_TOKEN is set
#
# `test.sh` and `build.sh` are the same gate on a developer machine; CI calls
# them where it can so the two cannot disagree about what "green" means.
name: ci
on:
push:
branches: [main]
tags: ["v*"]
pull_request:
permissions:
contents: read
env:
DOTNET_CLI_TELEMETRY_OPTOUT: "1"
DOTNET_NOLOGO: "1"
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: "1"
jobs:
verify:
name: typescript workspace
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm -r build
- run: pnpm -r typecheck
- run: pnpm -r test
# schemas/ is a committed artifact: regenerating must be a no-op.
- run: pnpm run gen:schemas
- run: git diff --exit-code schemas/ || (echo "schemas/ is stale — run pnpm run gen:schemas and commit" && exit 1)
# The website — the landing page at / and the documentation at /docs/, one
# Hugo site (Hextra vendored as a git submodule) — built with the same pinned
# Hugo version a developer runs locally. Independent of the Node toolchain.
website:
name: website (hugo)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1
- uses: peaceiris/actions-hugo@v3
with:
hugo-version: "0.165.0"
extended: true
- run: cd website && hugo --minify --gc
- uses: actions/upload-artifact@v4
with:
name: website
path: website/public
retention-days: 7
java:
name: java extractor
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
cache: maven
- run: cd extractors/java && ./mvnw -B test
# native-image is an AOT compiler plus the host's linker: a macOS binary needs a
# macOS runner. That is the whole reason this matrix is shaped differently from
# csharp-publish/csharp-smoke — there is no build-once-ship-five here, so each
# job builds its own RID and immediately proves it on the OS it was built for.
java-native:
name: java native ${{ matrix.rid }}
needs: java
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-latest, rid: linux-x64, exe: codegraph-java }
- { os: ubuntu-24.04-arm, rid: linux-arm64, exe: codegraph-java }
- { os: macos-latest, rid: osx-arm64, exe: codegraph-java }
- { os: macos-15-intel, rid: osx-x64, exe: codegraph-java }
- { os: windows-latest, rid: win-x64, exe: codegraph-java.exe }
steps:
# The snapshot is compared byte for byte, so a Windows checkout must not
# rewrite line endings.
- run: git config --global core.autocrlf false
- uses: actions/checkout@v4
# Brings native-image AND, on Windows, the MSVC toolchain it links with.
- uses: graalvm/setup-graalvm@v1
with:
java-version: "25"
distribution: graalvm-community
github-token: ${{ secrets.GITHUB_TOKEN }}
cache: maven
# The same flags a developer's `./build.sh --java --native` uses — one
# definition of what a released binary is.
- shell: bash
run: ./build.sh --java --native --skip-install --no-auto-install
# The gate: the BINARY, not `java -jar`, re-extracts the fixture corpus and
# must reproduce the committed snapshot. This is the only check that
# exercises the image's platform-library path — no java.home, no VM class
# library, the embedded ct.sym reference.
#
# Exactly ONE field is machine-specific: the header's `root`, the absolute
# path the run was pointed at — `D:\a\codegraph\...` on Windows, where
# matching a POSIX path found nothing and the whole matrix went red on
# char 137. So the field is rewritten wherever it points, and a guard first
# asserts it really named the fixture corpus — matched without naming a
# separator at all, which is what made the first attempt Windows-blind. Every
# other byte must match — file paths inside the model are already forced to
# forward slashes by Anchors.relativize, precisely so this holds.
- shell: bash
run: |
bin="extractors/java/dist/${{ matrix.rid }}/${{ matrix.exe }}"
chmod +x "$bin"
"$bin" --help > /dev/null
"$bin" --src fixtures/java/src --out out.jsonl --progress plain
head -1 out.jsonl | grep -qE '"root":"[^"]*fixtures[^"]*java[^"]*src"' \
|| { echo "the header's root does not name the fixture corpus"; head -c 200 out.jsonl; exit 1; }
sed '1s|"root":"[^"]*"|"root":"fixtures/java/src"|' out.jsonl | cmp - fixtures/java/expected/model.jsonl
echo "the native binary reproduces the snapshot on ${{ matrix.os }}"
- uses: actions/upload-artifact@v4
with:
name: codegraph-java-${{ matrix.rid }}
path: extractors/java/dist/${{ matrix.rid }}/
if-no-files-found: error
retention-days: 14
csharp-test:
name: csharp extractor
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
global-json-file: extractors/csharp/global.json
- run: cd extractors/csharp && dotnet test -c Release --nologo
csharp-publish:
name: publish ${{ matrix.rid }}
needs: csharp-test
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
rid: [linux-x64, linux-arm64, osx-x64, osx-arm64, win-x64]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
global-json-file: extractors/csharp/global.json
# The same flags a developer's `./build.sh --csharp` uses — one definition.
- run: ./build.sh --csharp --rid ${{ matrix.rid }} --skip-install --no-auto-install
- uses: actions/upload-artifact@v4
with:
name: codegraph-csharp-${{ matrix.rid }}
path: extractors/csharp/dist/${{ matrix.rid }}/
if-no-files-found: error
retention-days: 14
csharp-smoke:
name: smoke ${{ matrix.rid }} on ${{ matrix.os }}
needs: csharp-publish
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-latest, rid: linux-x64, exe: codegraph-csharp }
- { os: ubuntu-24.04-arm, rid: linux-arm64, exe: codegraph-csharp }
- { os: macos-latest, rid: osx-arm64, exe: codegraph-csharp }
- { os: macos-15-intel, rid: osx-x64, exe: codegraph-csharp }
- { os: windows-latest, rid: win-x64, exe: codegraph-csharp.exe }
steps:
# The snapshot is compared byte for byte: a Windows checkout must not
# rewrite its line endings (.gitattributes says so too — belt and braces).
- run: git config --global core.autocrlf false
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: codegraph-csharp-${{ matrix.rid }}
path: bin
# Nothing is installed on this runner for the extractor: the binary
# carries the runtime, Roslyn and the BCL. Run from the repo root with
# the RELATIVE --src the snapshot was made with (the typed path is the
# header's `root`).
- shell: bash
run: |
chmod +x "bin/${{ matrix.exe }}"
"bin/${{ matrix.exe }}" --version
"bin/${{ matrix.exe }}" --src fixtures/csharp/src --out out.jsonl --progress plain
cmp out.jsonl fixtures/csharp/expected/model.jsonl
echo "byte-identical on ${{ matrix.os }}"
typescript-smoke:
name: typescript extractor on ${{ matrix.os }}
needs: verify
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- run: git config --global core.autocrlf false
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --filter codegraph-typescript build
# The BUILT bundle, from the repo root with the RELATIVE --src the
# snapshot was made with; `typescript` resolves from the workspace
# install because the bundle leaves it external (its lib files must sit
# beside it). `cmp` is the whole cross-OS gate: the model is bytes.
- shell: bash
run: |
node extractors/typescript/dist/cli.js --version
node extractors/typescript/dist/cli.js --src fixtures/typescript/src --out out.jsonl --progress plain
cmp out.jsonl fixtures/typescript/expected/model.jsonl
echo "byte-identical on ${{ matrix.os }}"
elixir-test:
name: elixir extractor
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
version-file: extractors/elixir/.tool-versions
version-type: strict
# The same gate a developer's `./test.sh --elixir` runs: mix test, then
# the built escript must reproduce the fixture snapshot byte for byte.
- run: ./build.sh --elixir --skip-install --no-auto-install
- run: ./test.sh --elixir --skip-install --no-auto-install --no-schemas
elixir-smoke:
name: elixir extractor on ${{ matrix.os }}
needs: elixir-test
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- run: git config --global core.autocrlf false
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
version-file: extractors/elixir/.tool-versions
version-type: strict
# The escript, from the repo root with the RELATIVE --src the snapshot
# was made with; `cmp` is the whole cross-OS gate: the model is bytes.
# (`escript` runs the file on every OS; the bash wrapper is Unix-only.)
- shell: bash
run: |
cd extractors/elixir && mix local.hex --force --if-missing && mix escript.build && cd ../..
escript extractors/elixir/dist/codegraph-elixir --version
escript extractors/elixir/dist/codegraph-elixir --src fixtures/elixir/src --out out.jsonl --progress plain
cmp out.jsonl fixtures/elixir/expected/model.jsonl
echo "byte-identical on ${{ matrix.os }}"
elixir-native:
name: elixir native binary on ${{ matrix.os }}
needs: elixir-test
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
version-file: extractors/elixir/.tool-versions
version-type: strict
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
# The same steps a developer's `./build.sh --elixir --native` runs; the
# Burrito binary must reproduce the snapshot like the escript does.
- run: ./build.sh --elixir --native --skip-install --no-auto-install
- run: ./test.sh --elixir --skip-install --no-auto-install --no-schemas
- uses: actions/upload-artifact@v4
with:
name: codegraph-elixir-${{ matrix.os }}
path: extractors/elixir/dist/*/
if-no-files-found: error
retention-days: 14
hex-publish:
name: hex publish codegraph_elixir
if: startsWith(github.ref, 'refs/tags/v')
needs: [elixir-test, elixir-smoke]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: erlef/setup-beam@v1
with:
version-file: extractors/elixir/.tool-versions
version-type: strict
# `mix codegraph.trace` for any project that adds the dependency
# (PLAN.md §16.7). Skipped, not failed, when the repository holds no
# HEX_API_KEY: the GitHub release is the release; Hex is the convenience.
- name: publish
if: env.HEX_API_KEY != ''
env:
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
run: cd extractors/elixir && mix local.hex --force && mix hex.publish --yes
# The single-executable codegraph image (PLAN.md §15.3): the CLI, the daemon
# and both frontends folded into a copy of the runner's Node. No
# cross-compilation — the image IS the Node that builds it — so one job per
# runner, the Java native job's shape. The gates are scripts/sea-smoke.mjs:
# --version from the embedded package.json, `analyze` byte-identical to the
# ESM build, and `serve --app` answering the page from the image's assets.
sea:
name: single-executable ${{ matrix.rid }}
needs: verify
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-latest, rid: linux-x64, exe: codegraph }
- { os: ubuntu-24.04-arm, rid: linux-arm64, exe: codegraph }
- { os: macos-latest, rid: osx-arm64, exe: codegraph }
- { os: macos-15-intel, rid: osx-x64, exe: codegraph }
- { os: windows-latest, rid: win-x64, exe: codegraph.exe }
steps:
- run: git config --global core.autocrlf false
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
# The same steps a developer's `./build.sh --ts --sea` runs — one definition.
- shell: bash
run: ./build.sh --ts --sea --skip-install --no-auto-install
- shell: bash
run: node packages/cli/scripts/sea-smoke.mjs "packages/cli/dist-sea/${{ matrix.rid }}/${{ matrix.exe }}"
- uses: actions/upload-artifact@v4
with:
name: codegraph-cli-${{ matrix.rid }}
path: packages/cli/dist-sea/${{ matrix.rid }}/
if-no-files-found: error
retention-days: 14
# The desktop shell (PLAN.md §15.4): the discovery crate's tests, and the
# Tauri crate compiled and tested with its sidecar in place — on the
# platforms that carry a WebKit (Linux needs the WebKitGTK packages; macOS
# has WebKit). Not a bundle, not a signature: that is M14d's `desktop` job.
desktop:
name: desktop shell on ${{ matrix.os }}
needs: sea
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-latest, rid: linux-x64 }
- { os: macos-latest, rid: osx-arm64 }
steps:
- uses: actions/checkout@v4
- if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev patchelf
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: apps/desktop
- uses: actions/setup-node@v4
with:
node-version: 22
- uses: actions/download-artifact@v4
with:
name: codegraph-cli-${{ matrix.rid }}
path: packages/cli/dist-sea/${{ matrix.rid }}
- run: node apps/desktop/scripts/sidecar.mjs --rid ${{ matrix.rid }}
- run: cargo fmt --all --check
working-directory: apps/desktop
- run: cargo test --workspace
working-directory: apps/desktop
# The desktop bundle (PLAN.md §15.5, M14d): `tauri build` per macOS
# architecture — no universal binary, the sidecar is per triple. With the
# Apple credentials in the repository's secrets the sidecar and the app are
# signed with hardened runtime and the entitlements, and Tauri notarizes;
# without them the job still bundles (ad hoc) so a fork or a PR proves the
# bundling, and the signed-only assertions are skipped, not faked.
desktop-bundle:
name: desktop bundle ${{ matrix.rid }}
needs: [sea, desktop]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: macos-latest, rid: osx-arm64, triple: aarch64-apple-darwin }
- { os: macos-15-intel, rid: osx-x64, triple: x86_64-apple-darwin }
env:
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: apps/desktop
- uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- uses: actions/download-artifact@v4
with:
name: codegraph-cli-${{ matrix.rid }}
path: packages/cli/dist-sea/${{ matrix.rid }}
- run: node apps/desktop/scripts/sidecar.mjs --rid ${{ matrix.rid }}
# The Developer ID certificate, into a throwaway keychain the runner forgets.
- name: import the signing certificate
if: env.APPLE_SIGNING_IDENTITY != ''
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
run: |
set -euo pipefail
keychain="$RUNNER_TEMP/codegraph.keychain-db"
password="$(openssl rand -hex 16)"
echo "$APPLE_CERTIFICATE" | base64 --decode > "$RUNNER_TEMP/certificate.p12"
security create-keychain -p "$password" "$keychain"
security set-keychain-settings -lut 21600 "$keychain"
security unlock-keychain -p "$password" "$keychain"
security import "$RUNNER_TEMP/certificate.p12" -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$keychain"
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$password" "$keychain"
security list-keychain -d user -s "$keychain" login.keychain-db
# The sidecar signed by hand with the entitlements BEFORE bundling: the
# plan (§15.5) says not to assume the bundler applies them to sidecars.
- name: sign the sidecar with the JIT entitlements
if: env.APPLE_SIGNING_IDENTITY != ''
run: |
codesign --force --options runtime --timestamp \
--entitlements apps/desktop/src-tauri/entitlements.plist \
--sign "$APPLE_SIGNING_IDENTITY" \
"apps/desktop/src-tauri/binaries/codegraph-${{ matrix.triple }}"
codesign --verify --verbose=2 "apps/desktop/src-tauri/binaries/codegraph-${{ matrix.triple }}"
# Tauri signs the bundle with APPLE_SIGNING_IDENTITY and notarizes with
# APPLE_ID / APPLE_PASSWORD / APPLE_TEAM_ID when they are set; unset, it
# signs ad hoc and skips notarization. `app` is requested alongside `dmg`
# because the bundler deletes an .app it only built as the DMG's input,
# and the assertions below inspect the .app. Cargo's target directory is
# the workspace's (apps/desktop/target), not the crate's.
- name: tauri build
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: pnpm --filter @codegraph/desktop exec tauri build --bundles app,dmg --target ${{ matrix.triple }}
# The two assertions §15.5 names for the first signed build, as CI facts.
- name: assess the signed app
if: env.APPLE_SIGNING_IDENTITY != ''
run: |
set -euo pipefail
app="$(find apps/desktop/target/${{ matrix.triple }}/release/bundle/macos -maxdepth 1 -name '*.app' | head -1)"
codesign --verify --deep --strict --verbose=2 "$app"
codesign --display --entitlements - "$app/Contents/MacOS/codegraph" | grep -q allow-jit
spctl --assess --type execute --verbose=2 "$app"
- name: name the DMG after its RID
run: |
set -euo pipefail
version="$(node -p "require('./apps/desktop/src-tauri/tauri.conf.json').version")"
mkdir -p out
cp apps/desktop/target/${{ matrix.triple }}/release/bundle/dmg/*.dmg "out/Codegraph-${version}-${{ matrix.rid }}.dmg"
ls -la out
- uses: actions/upload-artifact@v4
with:
name: codegraph-desktop-${{ matrix.rid }}
path: out/
if-no-files-found: error
retention-days: 14
release:
name: github release
if: startsWith(github.ref, 'refs/tags/v')
needs: [verify, java, java-native, csharp-smoke, typescript-smoke, elixir-smoke, elixir-native, sea, desktop, desktop-bundle, npm-publish]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
pattern: codegraph-*
path: artifacts
- name: name each binary after its RID and attach it
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
mkdir -p release
for extractor in csharp java; do
for dir in artifacts/codegraph-$extractor-*; do
rid="${dir#artifacts/codegraph-$extractor-}"
for f in "$dir"/codegraph-$extractor*; do
case "$f" in
*.exe) cp "$f" "release/codegraph-$extractor-$rid.exe" ;;
*) cp "$f" "release/codegraph-$extractor-$rid" ;;
esac
done
done
done
# The single-executable codegraph image, one per RID: `codegraph-<rid>`.
for dir in artifacts/codegraph-cli-*; do
rid="${dir#artifacts/codegraph-cli-}"
for f in "$dir"/codegraph*; do
case "$f" in
*.exe) cp "$f" "release/codegraph-$rid.exe" ;;
*) cp "$f" "release/codegraph-$rid" ;;
esac
done
done
# The Elixir native binary: its artifacts are named by runner OS and hold
# `<rid>/codegraph-elixir`, so the RID is the directory's name.
for dir in artifacts/codegraph-elixir-*; do
[ -d "$dir" ] || continue
for f in "$dir"/*/codegraph-elixir*; do
[ -f "$f" ] || continue
rid="$(basename "$(dirname "$f")")"
case "$f" in
*.exe) cp "$f" "release/codegraph-elixir-$rid.exe" ;;
*) cp "$f" "release/codegraph-elixir-$rid" ;;
esac
done
done
# The desktop app: two DMGs, already named Codegraph-<version>-<rid>.dmg.
for dir in artifacts/codegraph-desktop-*; do
[ -d "$dir" ] && cp "$dir"/*.dmg release/
done
(cd release && sha256sum * > SHA256SUMS)
gh release create "${GITHUB_REF_NAME}" --generate-notes --title "codegraph ${GITHUB_REF_NAME}" release/* \
|| gh release upload "${GITHUB_REF_NAME}" release/* --clobber
# The tap (PLAN.md §15.5): the cask and the formulae rendered from this
# release's SHA256SUMS and pushed to defsquare/homebrew-tap with a deploy
# key. Generated, never edited by hand. Skipped, not failed, when the
# repository holds no HOMEBREW_TAP_DEPLOY_KEY. The codegraph-typescript
# formula needs the npm tarball's sum, so it is rendered only when the
# npm publish happened (the registry answers for this version).
- name: render and push the Homebrew tap
if: env.HOMEBREW_TAP_DEPLOY_KEY != ''
env:
HOMEBREW_TAP_DEPLOY_KEY: ${{ secrets.HOMEBREW_TAP_DEPLOY_KEY }}
HOMEBREW_TAP_REPO: ${{ vars.HOMEBREW_TAP_REPO || 'defsquare/homebrew-tap' }}
run: |
set -euo pipefail
version="${GITHUB_REF_NAME#v}"
npm_sha=""
if curl -fsSL "https://registry.npmjs.org/codegraph-typescript/-/codegraph-typescript-${version}.tgz" -o ts.tgz; then
npm_sha="$(sha256sum ts.tgz | cut -d' ' -f1)"
fi
node scripts/homebrew/render.mjs --version "$version" --sums release/SHA256SUMS \
${npm_sha:+--npm-sha256 "$npm_sha"} --out tap
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "$HOMEBREW_TAP_DEPLOY_KEY" > ~/.ssh/tap_deploy_key && chmod 600 ~/.ssh/tap_deploy_key
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
export GIT_SSH_COMMAND="ssh -i ~/.ssh/tap_deploy_key -o IdentitiesOnly=yes"
git clone --depth 1 "git@github.com:${HOMEBREW_TAP_REPO}.git" tap-checkout
cp -R tap/. tap-checkout/
cd tap-checkout
git config user.name "codegraph release"
git config user.email "release@codegraph.dev"
git add -A
git commit -m "codegraph ${version}" || { echo "tap already at ${version}"; exit 0; }
git push origin HEAD
npm-publish:
name: npm publish codegraph-typescript
if: startsWith(github.ref, 'refs/tags/v')
needs: [verify, typescript-smoke]
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
registry-url: https://registry.npmjs.org
- run: pnpm install --frozen-lockfile
- run: pnpm --filter codegraph-typescript build
# `npx codegraph-typescript` for anyone with Node 22 (PLAN.md §14.7).
# Skipped, not failed, when the repository holds no NPM_TOKEN: the
# GitHub release above is the release; npm is the convenience.
- name: publish with provenance
if: env.NPM_TOKEN != ''
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: cd extractors/typescript && pnpm publish --provenance --access public --no-git-checks