Repository navigation
738 lines (658 loc) · 30.9 KB
/
Copy pathbuild.yml
File metadata and controls
738 lines (658 loc) · 30.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
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
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
name: Build
# Build + package (cpack) on each platform, uploaded as workflow
# artifacts. This does NOT install or run anything -- see test.yml, which
# runs the three regression suites.
#
# (This header used to say that installing and running the GUI apps needed
# "a lot more complexity than a build-and-package health check warrants".
# That turned out to be `apt install xvfb` plus letting the app wrapper
# start its own services, so test.yml does it now. The parser and dialog
# suites need neither a display nor services and run on every push in
# about three minutes.)
# Packaging itself needs neither: cpack just archives already-built
# binaries, no display involved. The goal is early, continuous signal on
# "does this even compile (and package) here", especially for platforms
# nobody is routinely building on locally.
#
# RPM packages built here are real .rpm artifacts, but incomplete ones --
# CPACK_RPM_PACKAGE_REQUIRES (the RPM equivalent of the existing
# CPACK_DEBIAN_PACKAGE_DEPENDS) isn't set yet, so the package won't
# auto-pull its runtime deps (apache2 equivalent, mosquitto, wx python
# bindings, ...) the way the .deb does. Worth fixing before treating
# these as real release artifacts, not before treating them as "does
# cpack's RPM generator work at all here" signal.
#
# Target platforms and why:
# - Debian: what the primary maintainer actually develops on.
# - Ubuntu: most popular desktop/CI Linux distro.
# - RHEL family: what a lot of institutional/cluster environments run.
# GitHub Actions has no real RHEL runner (needs a subscription), so
# this uses Rocky Linux -- a bug-for-bug free rebuild of RHEL from
# the same sources, the standard stand-in for "does this work on
# RHEL" in CI that doesn't have a Red Hat subscription to spend.
# - WSL2: NOT a separate job. WSL2 runs a real Linux kernel with a real
# distro userland (Ubuntu by default) on top of it -- there's no
# separate "WSL2 build" to test, the Ubuntu/Debian jobs below already
# cover it directly. The one WSL2-relevant wrinkle, filename
# case-collisions (#40), is actually a non-issue for WSL2 specifically
# (its ext4-backed filesystem is case-sensitive like any other Linux
# disk) -- it only bites on a native-Windows checkout or a default
# case-insensitive macOS volume.
# - macOS: tracks GitHub #3 (currently expected to fail -- see the job
# below for why).
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
inputs:
only:
description: "Run just this job (debian, vendored-inventor, ubuntu, rocky, fedora, macos, windows); empty runs all"
required: false
default: ""
# One run per branch. Without this every push starts a full run and none
# of them cancel the older ones, so a run of quick pushes leaves a dozen
# stale runs competing for the same runners -- which is exactly what
# happened on 2026-09-23: nine pushes in a day, eleven jobs each, and CI
# stopped completing anything for six hours. A superseded run tells you
# nothing a newer one will not.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
debian:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.only == '' || inputs.only == 'debian' }}
name: Debian (apt, containerized)
runs-on: ubuntu-latest
# Bounded so a hung job cannot hold a runner slot for GitHub's
# 6-hour default; see the concurrency note above.
timeout-minutes: 90
container: debian:trixie
steps:
- name: Install build dependencies
run: |
apt-get update
apt-get install -y \
build-essential gfortran cmake ninja-build \
libwxgtk3.2-dev libxerces-c-dev libgl-dev libglu1-mesa-dev \
libgtk-3-dev libx11-dev libice-dev libxt-dev libjpeg-dev \
libmosquitto-dev mosquitto-dev libaprutil1-dev mosquitto git dpkg-dev file libssh-dev libssl-dev \
python3 libcoin-dev libegl-dev libxc-dev libeigen3-dev
- uses: actions/checkout@v4
- name: Configure
run: cmake -G Ninja -B build-cmake -DECCE_REQUIRE_LIBSSH=ON
- name: Build
# -k 0: report every failing file, not only the first few.
run: cmake --build build-cmake -- -k 0
- name: Package
working-directory: build-cmake
run: cpack -G DEB
- name: No build paths in the packages
run: tests/packaging/no-build-paths.sh "$GITHUB_WORKSPACE" build-cmake/*.deb
# ecce-qm is in the client package, stripped, and gives ORCA's energies.
- name: ecce-qm in the package
run: |
d=$(mktemp -d)
ls -l build-cmake/*.deb
dpkg-deb -x build-cmake/ecce-client_*.deb "$d"
q=$(find "$d" -path '*/bin/ecce-qm')
test -n "$q"
file "$q" || true
python3 tests/qm/package_check.py "$q" "$(dirname "$q")/../data/admin/basissets" --max-mb 40
- uses: actions/upload-artifact@v4
with:
name: ecce-debian-trixie-deb
path: build-cmake/*.deb
# Build only, no packaging: keeps the vendored Inventor core
# (-DECCE_USE_COIN=OFF, #166) compiling for the one release it stays a
# fallback.
vendored-inventor:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.only == '' || inputs.only == 'vendored-inventor' }}
name: Debian, vendored Inventor viewer (build only)
runs-on: ubuntu-latest
timeout-minutes: 90
container: debian:trixie
steps:
- name: Install build dependencies
run: |
apt-get update
apt-get install -y \
build-essential gfortran cmake ninja-build python3 \
libwxgtk3.2-dev libxerces-c-dev libgl-dev libglu1-mesa-dev \
libgtk-3-dev libx11-dev libice-dev libxt-dev libjpeg-dev \
libmosquitto-dev mosquitto-dev libaprutil1-dev mosquitto git dpkg-dev file libssh-dev
- uses: actions/checkout@v4
- name: Configure
run: cmake -G Ninja -B build-oiv -DECCE_USE_COIN=OFF -DECCE_REQUIRE_LIBSSH=ON
- name: Build
run: cmake --build build-oiv
ubuntu:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.only == '' || inputs.only == 'ubuntu' }}
name: Ubuntu (apt)
runs-on: ubuntu-latest
# Bounded so a hung job cannot hold a runner slot for GitHub's
# 6-hour default; see the concurrency note above.
timeout-minutes: 90
steps:
- uses: actions/checkout@v4
- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential gfortran cmake ninja-build \
libwxgtk3.2-dev libxerces-c-dev libgl-dev libglu1-mesa-dev \
libgtk-3-dev libx11-dev libice-dev libxt-dev libjpeg-dev \
libmosquitto-dev mosquitto-dev libaprutil1-dev mosquitto git dpkg-dev libssh-dev libssl-dev \
python3 libcoin-dev libegl-dev libxc-dev libeigen3-dev
- name: Configure
run: cmake -G Ninja -B build-cmake -DECCE_REQUIRE_LIBSSH=ON
- name: Build
# -k 0: report every failing file, not only the first few.
run: cmake --build build-cmake -- -k 0
- name: Package
working-directory: build-cmake
run: cpack -G DEB
- name: No build paths in the packages
run: tests/packaging/no-build-paths.sh "$GITHUB_WORKSPACE" build-cmake/*.deb
# ecce-qm is in the client package, stripped, and gives ORCA's energies.
- name: ecce-qm in the package
run: |
d=$(mktemp -d)
ls -l build-cmake/*.deb
dpkg-deb -x build-cmake/ecce-client_*.deb "$d"
q=$(find "$d" -path '*/bin/ecce-qm')
test -n "$q"
file "$q" || true
python3 tests/qm/package_check.py "$q" "$(dirname "$q")/../data/admin/basissets" --max-mb 40
- uses: actions/upload-artifact@v4
with:
name: ecce-ubuntu-latest-deb
path: build-cmake/*.deb
rocky:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.only == '' || inputs.only == 'rocky' }}
name: Rocky Linux (dnf, RHEL family, containerized)
runs-on: ubuntu-latest
# Bounded so a hung job cannot hold a runner slot for GitHub's
# 6-hour default; see the concurrency note above.
timeout-minutes: 90
container: rockylinux:9
steps:
- name: Install build dependencies
run: |
dnf install -y epel-release 'dnf-command(config-manager)'
# ninja-build and a few -devel packages live in the CodeReady
# Builder repo, not EPEL itself -- EPEL's own release package
# prints a reminder about this ("Many EPEL packages require the
# CRB repository... /usr/bin/crb enable") but doesn't enable it
# automatically.
dnf config-manager --set-enabled crb
dnf install -y \
gcc gcc-c++ gcc-gfortran make cmake ninja-build git rpm-build \
wxGTK-devel xerces-c-devel \
mesa-libGL-devel mesa-libGLU-devel \
gtk3-devel libX11-devel libICE-devel libXt-devel libjpeg-turbo-devel \
mosquitto-devel apr-util-devel mosquitto libssh-devel openssl-devel \
Coin4-devel mesa-libEGL-devel python3
# actions/checkout doesn't work reliably inside an arbitrary
# container image (no git-installed-as-a-prereq guarantee, and the
# container user often isn't the checkout action's expected uid) --
# install git above first, then check out manually instead.
- name: Check out source
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git clone --depth 1 --branch "${GITHUB_REF_NAME}" \
"https://github.com/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE" \
|| git clone --depth 1 "https://github.com/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE"
- name: Configure
working-directory: ${{ github.workspace }}
run: cmake -G Ninja -B build-cmake -DECCE_REQUIRE_LIBSSH=ON
- name: Build
working-directory: ${{ github.workspace }}
# -k 0: report every failing file, not only the first few.
run: cmake --build build-cmake -- -k 0
- name: Package
working-directory: ${{ github.workspace }}/build-cmake
run: cpack -G RPM
- name: No build paths in the packages
run: |
command -v cpio >/dev/null || dnf install -y cpio
tests/packaging/no-build-paths.sh "$GITHUB_WORKSPACE" build-cmake/*.rpm
- name: ecce-qm in the client rpm
run: |
w=$PWD
d=$(mktemp -d)
ls -l "$w"/build-cmake/*.rpm
(cd "$d" && rpm2cpio "$w"/build-cmake/ecce-client-*.x86_64.rpm | cpio -idm 2>/dev/null)
q=$(find "$d" -path '*/bin/ecce-qm')
test -n "$q"
ls -l "$q"
python3 tests/qm/package_check.py "$q" "$(dirname "$q")/../data/admin/basissets" --max-mb 40
- uses: actions/upload-artifact@v4
with:
name: ecce-rockylinux9-rpm
path: build-cmake/*.rpm
fedora:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.only == '' || inputs.only == 'fedora' }}
name: Fedora (dnf, containerized)
runs-on: ubuntu-latest
# Bounded so a hung job cannot hold a runner slot for GitHub's
# 6-hour default; see the concurrency note above.
timeout-minutes: 90
container: fedora:latest
steps:
- name: Install build dependencies
run: |
dnf install -y \
gcc gcc-c++ gcc-gfortran make cmake ninja-build git rpm-build \
wxGTK-devel xerces-c-devel \
mesa-libGL-devel mesa-libGLU-devel \
gtk3-devel libX11-devel libICE-devel libXt-devel libjpeg-turbo-devel \
mosquitto-devel apr-util-devel mosquitto libssh-devel openssl-devel \
Coin4-devel mesa-libEGL-devel python3 libxc-devel eigen3-devel
- name: Check out source
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git clone --depth 1 --branch "${GITHUB_REF_NAME}" \
"https://github.com/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE" \
|| git clone --depth 1 "https://github.com/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE"
- name: Configure
working-directory: ${{ github.workspace }}
run: cmake -G Ninja -B build-cmake -DECCE_REQUIRE_LIBSSH=ON
- name: Build
working-directory: ${{ github.workspace }}
# -k 0: report every failing file, not only the first few.
run: cmake --build build-cmake -- -k 0
- name: Package
working-directory: ${{ github.workspace }}/build-cmake
run: cpack -G RPM
- name: No build paths in the packages
run: |
command -v cpio >/dev/null || dnf install -y cpio
tests/packaging/no-build-paths.sh "$GITHUB_WORKSPACE" build-cmake/*.rpm
- name: ecce-qm in the client rpm
run: |
w=$PWD
d=$(mktemp -d)
ls -l "$w"/build-cmake/*.rpm
(cd "$d" && rpm2cpio "$w"/build-cmake/ecce-client-*.x86_64.rpm | cpio -idm 2>/dev/null)
q=$(find "$d" -path '*/bin/ecce-qm')
test -n "$q"
ls -l "$q"
python3 tests/qm/package_check.py "$q" "$(dirname "$q")/../data/admin/basissets" --max-mb 40
- uses: actions/upload-artifact@v4
with:
name: ecce-fedora-latest-rpm
path: build-cmake/*.rpm
macos:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.only == '' || inputs.only == 'macos' }}
name: macOS (${{ matrix.arch }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: macos-latest, arch: arm64, target: "11.0", experimental: false }
# Catalina: the oldest macOS many 2012-2014 Intel Macs can run.
- { os: macos-15-intel, arch: x86_64, target: "10.15", experimental: true }
env:
# Oldest macOS the app is built for (#133). Our code and every
# bundled library are built to this; the minimum-macOS step fails
# the job on any Mach-O above it.
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.target }}
ECCE_DEPS: /Users/runner/ecce-deps
# Bounded so a hung job cannot hold a runner slot for GitHub's
# 6-hour default; see the concurrency note above.
timeout-minutes: 90
# Known-unsupported today (GitHub #3) -- ECCE's offscreen-rendering
# path (src/inv/dbso/SoOffscreenRenderer.inc) calls raw Xlib/GLX
# (XOpenDisplay/glXCreateContext), which has no macOS-native
# equivalent (Cocoa/NSOpenGL, or GLX only via XQuartz). This job is
# here to track the gap with a real, current compile log instead of
# nothing -- it's expected to fail until #3 gets real porting work,
# not a sign the workflow itself is broken.
# x86_64 may fail until it is proven; arm64 must be green.
continue-on-error: ${{ matrix.experimental }}
steps:
- uses: actions/checkout@v4
- name: Install build tools
# Only tools: the libraries come from build-deps.sh, because
# Homebrew bottles are built for the runner's own macOS.
run: brew install cmake ninja pkgconf gcc bash
- name: Cache libraries built for macOS ${{ env.MACOSX_DEPLOYMENT_TARGET }}
id: deps
uses: actions/cache/restore@v4
with:
path: ${{ env.ECCE_DEPS }}
key: macos-deps-${{ matrix.arch }}-${{ env.MACOSX_DEPLOYMENT_TARGET }}-${{ hashFiles('packaging/macos/build-deps.sh') }}
- name: Build libraries (wxWidgets, Coin, Xerces, Mosquitto, libssh, OpenSSL)
if: steps.deps.outputs.cache-hit != 'true'
run: packaging/macos/build-deps.sh "$ECCE_DEPS"
- name: Save the libraries
if: steps.deps.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ${{ env.ECCE_DEPS }}
key: ${{ steps.deps.outputs.cache-primary-key }}
- name: Configure
# ECCE_HOME_DIR/ECCE_WRAPPER_DESTINATION point the install at a
# staging tree inside the workspace for the run step below.
# Homebrew's prefixes are ignored so nothing is picked up from
# them by accident.
run: |
export PATH="$ECCE_DEPS/bin:$PATH"
export PKG_CONFIG_LIBDIR="$ECCE_DEPS/lib/pkgconfig"
cmake -G Ninja -B build-cmake -DECCE_USE_COIN=ON \
-DCMAKE_OSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET" \
-DCMAKE_PREFIX_PATH="$ECCE_DEPS" \
-DCMAKE_IGNORE_PREFIX_PATH="/opt/homebrew;/usr/local" \
-DCMAKE_MAKE_PROGRAM="$(command -v ninja)" -DPKG_CONFIG_EXECUTABLE="$(command -v pkg-config)" \
-DCMAKE_Fortran_COMPILER="$(ls $(brew --prefix)/bin/gfortran-* | head -1)" \
-DFREETYPE_UNQUALIFIED_INCLUDE_DIR="$ECCE_DEPS/include/freetype2/freetype" \
-DFREETYPE_ROOT_INCLUDE_DIR="$ECCE_DEPS/include/freetype2" \
-DECCE_HOME_DIR="$PWD/stage/ecce" -DECCE_WRAPPER_DESTINATION="$PWD/stage/bin" \
-DCMAKE_INSTALL_PREFIX="$PWD/stage/ecce"
- name: Build
# -k 0: report every failing file, not only the first few.
run: cmake --build build-cmake -- -k 0
# The GROMACS study's scripts on Homebrew's gmx (docs/GROMACS.md).
# They need no build, so this runs whatever the build did; it is
# allowed to fail until it has been seen to pass on a runner.
- name: GROMACS MD study suite
continue-on-error: true
timeout-minutes: 15
env:
ECCE_GROMACS_REQUIRE: '1'
run: |
brew install gromacs
tests/gromacs_md/run_tests.py -v
# The editor and terminal commands macOS gets by default (#133).
- name: Editor and terminal commands
run: cd build-cmake && ctest -R '^(editor_command|macos_terminal)$' --output-on-failure
# Does it run? (#133) Starts the installed apps on the runner's
# logged-in desktop and screenshots them. Allowed to fail; the
# verdict is in the summary and the "macos-run" artifact.
- name: Install to a staging prefix and run
continue-on-error: true
timeout-minutes: 25
run: |
export PATH="$ECCE_DEPS/sbin:$ECCE_DEPS/bin:$PATH"
cmake --install build-cmake
rc=0; tests/macos/run.sh stage macos-run || rc=$?
cat macos-run/summary.txt >> "$GITHUB_STEP_SUMMARY"
exit $rc
- uses: actions/upload-artifact@v4
if: always()
with:
name: macos-run-${{ matrix.arch }}
path: macos-run/
if-no-files-found: ignore
# ECCE.app in a .dmg (#133), then the start test again on a copy of
# the app taken out of the mounted image, away from the build tree.
# The two steps below fail the job when they fail. The job itself
# is continue-on-error (the native build is still experimental), so
# the workflow stays green but the job and these steps show red and
# the summary says FAILED.
- name: Package ECCE.app
run: |
export PATH="$ECCE_DEPS/bin:$PATH"
packaging/macos/make-app.sh stage dist
# ECCE.app runs from wherever it is put (#133): no installed script
# may name the runner's build tree or library prefix.
- name: No build paths in ECCE.app
run: tests/packaging/no-build-paths.sh /Users/runner dist/ECCE.app
# Oldest macOS the bundle can run on (#133): the step fails when any
# Mach-O needs more than the deployment target or is not this runner's arch.
- name: Minimum macOS of every Mach-O in the app
run: |
mkdir -p minos
app=$(mktemp -d)
mnt=$(mktemp -d)
hdiutil attach dist/ECCE-*.dmg -mountpoint "$mnt" -nobrowse -quiet
cp -R "$mnt/ECCE.app" "$app/"
hdiutil detach "$mnt" -quiet
python3 packaging/macos/minos.py "$app/ECCE.app" minos/minos.txt \
--floor "$MACOSX_DEPLOYMENT_TARGET" --arch "${{ matrix.arch }}" > /dev/null || rc=$?
echo "runner: $(sw_vers -productVersion) $(uname -m)" >> minos/minos.txt
{ echo '### Minimum macOS (ECCE.app)'; echo '```';
sed -n '/^Mach-O files/,$p' minos/minos.txt; echo '```'; } >> "$GITHUB_STEP_SUMMARY"
exit ${rc:-0}
- name: ecce-qm in the app
run: |
mnt=$(mktemp -d)
hdiutil attach dist/ECCE-*.dmg -mountpoint "$mnt" -nobrowse -quiet
q="$mnt/ECCE.app/Contents/Resources/ecce/bin/ecce-qm"
test -x "$q"
python3 tests/qm/package_check.py "$q" "$mnt/ECCE.app/Contents/Resources/ecce/data/admin/basissets" --max-mb 40 | tee -a "$GITHUB_STEP_SUMMARY" || rc=$?
hdiutil detach "$mnt" -quiet
exit ${rc:-0}
- name: Run the packaged app
if: always() && hashFiles('dist/*.dmg') != ''
timeout-minutes: 25
run: |
pkill -f "$PWD/stage" || true
mnt=$(mktemp -d)
hdiutil attach dist/ECCE-*.dmg -mountpoint "$mnt" -nobrowse -quiet
appdir=$(mktemp -d)
cp -R "$mnt/ECCE.app" "$appdir/"
hdiutil detach "$mnt" -quiet
# The build tree and the staging prefix must not be needed.
mv build-cmake build-cmake.gone
mv stage stage.gone
rc=0
# -remote against stand-in server ports, ECCE_HOME found by the wrappers.
tests/macos/remote-reach.sh "$appdir/ECCE.app/Contents/Resources" || rc=1
ECCE_APP="$appdir/ECCE.app" tests/macos/run.sh "$appdir/ECCE.app/Contents/Resources" macos-app-run || rc=$?
cat macos-app-run/summary.txt >> "$GITHUB_STEP_SUMMARY"
exit $rc
- name: Summary on failure
if: failure()
run: echo '### macOS packaging FAILED (see the failed step above)' >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-artifact@v4
if: always()
with:
name: ECCE-macos-dmg-${{ matrix.arch }}
path: |
dist/*.dmg
minos/minos.txt
if-no-files-found: ignore
- uses: actions/upload-artifact@v4
if: always()
with:
name: macos-app-run-${{ matrix.arch }}
path: macos-app-run/
if-no-files-found: ignore
# Windows client (#133), experimental: MSYS2 UCRT64 toolchain, the same
# package set as tests/windows/README.md. Never turns the workflow red.
windows:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.only == '' || inputs.only == 'windows' }}
name: Windows (MSYS2 UCRT64)
runs-on: windows-latest
timeout-minutes: 120
continue-on-error: true
steps:
# LF in the checkout: fixtures and shell scripts must not get CRLF.
- run: git config --global core.autocrlf false
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: false
cache: true
install: >-
base git
mingw-w64-ucrt-x86_64-apr-util mingw-w64-ucrt-x86_64-ccache mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-coin mingw-w64-ucrt-x86_64-freetype
mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-gcc-fortran
mingw-w64-ucrt-x86_64-glib2 mingw-w64-ucrt-x86_64-libjpeg-turbo
mingw-w64-ucrt-x86_64-libssh mingw-w64-ucrt-x86_64-mosquitto
mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-pkgconf
mingw-w64-ucrt-x86_64-python mingw-w64-ucrt-x86_64-wxwidgets3.2-msw
mingw-w64-ucrt-x86_64-xerces-c
# The build is ~20 minutes cold; ccache makes a rerun after a small
# change a few.
- uses: actions/cache@v4
with:
path: .ccache
key: ccache-windows-${{ github.run_id }}
restore-keys: ccache-windows-
- name: Configure
shell: msys2 {0}
env:
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_MAXSIZE: 600M
run: |
cmake -G Ninja -B build -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=Release -DECCE_REQUIRE_LIBSSH=ON \
-DECCE_HOME_DIR="$PWD/stage/ecce" -DCMAKE_INSTALL_PREFIX="$PWD/stage/ecce"
- name: Build
shell: msys2 {0}
env:
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_MAXSIZE: 600M
# -k 0: report every failing file, not only the first few.
run: cmake --build build -- -k 0
- name: Tests
id: tests
shell: msys2 {0}
continue-on-error: true
run: |
cd build
ctest -R 'transport_process|fragreaders|fragreaders_de|parsers' --output-on-failure --timeout 600 \
| tee ../ctest.log
exit "${PIPESTATUS[0]}"
- name: Install to a staging tree
shell: msys2 {0}
run: |
cmake --install build > install.log 2>&1 || { tail -30 install.log; exit 1; }
ls stage/ecce stage/ecce/bin
# The shell the job scripts run with, next to the apps (#133).
- name: Bundle the POSIX shell
shell: msys2 {0}
run: packaging/windows/bundle-shell.sh "$PWD/stage/ecce" "$(cygpath -m /)"
# MinGW runtime DLLs and the broker, then Perl and Python, so the tree
# runs with no MSYS2 on the machine.
- name: Bundle the runtime
shell: msys2 {0}
run: |
packaging/windows/bundle-runtime.sh "$PWD/stage/ecce"
cp packaging/windows/ecce.cmd packaging/windows/ecce.vbs packaging/windows/make-shortcuts.ps1 stage/ecce/
- name: Download cache (Strawberry Perl, Python, wxPython)
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/ecce-dl
key: windows-tools-${{ hashFiles('packaging/windows/bundle-tools.ps1') }}
- name: Bundle Perl and Python
shell: pwsh
run: packaging/windows/bundle-tools.ps1 -Install stage\ecce -Cache "$env:RUNNER_TEMP\ecce-dl"
- name: Zip the install tree
shell: pwsh
run: |
$v = (Get-Content data/client/config/Version -TotalCount 1).Trim()
New-Item -ItemType Directory -Force dist | Out-Null
Compress-Archive -Path stage\ecce -DestinationPath "dist\ECCE-windows-$v.zip"
Get-ChildItem dist | Format-Table Name, Length
$d = "$env:RUNNER_TEMP\unpacked"
Remove-Item -Recurse -Force $d -ErrorAction SilentlyContinue
Expand-Archive "dist\ECCE-windows-$v.zip" $d
"unpacked: $((Get-ChildItem $d -Recurse -File | Measure-Object Length -Sum).Sum / 1MB) MB" | Tee-Object -Append $env:GITHUB_STEP_SUMMARY
Get-ChildItem "$d\ecce" | Format-Table Name
# launchjob is a test driver, not part of the package.
Copy-Item build\launchjob.exe "$d\ecce\bin\"
- name: ecce-qm in the zip
shell: pwsh
run: |
$r = "$env:RUNNER_TEMP\unpacked\ecce"
$env:Path = "$env:SystemRoot\System32;$env:SystemRoot"
& "$r\python\python3.exe" tests/qm/package_check.py "$r\bin\ecce-qm.exe" "$r\data\admin\basissets" --max-mb 40 2>&1 | Tee-Object -Append $env:GITHUB_STEP_SUMMARY
exit $LASTEXITCODE
# Local job end to end from the unpacked zip, with System32 as the only
# PATH outside it (tests/windows/launch_local.py): no MSYS2 involved.
- name: Local jobs (complete, cancel)
id: localjobs
shell: pwsh
continue-on-error: true
run: |
$r = "$env:RUNNER_TEMP\unpacked\ecce"
New-Item -ItemType Directory -Force localjobs | Out-Null
$sys = "$env:SystemRoot\System32;$env:SystemRoot"
$env:Path = $sys
$env:WINTEST_HOME = $r
$env:WINTEST_BASE_PATH = "$r\bin;$r\usr\bin;$r\python;$r\strawberry\perl\site\bin;$r\strawberry\perl\bin;$r\strawberry\c\bin;$sys"
$env:Path = $env:WINTEST_BASE_PATH
& "$r\usr\bin\bash.exe" -c 'echo "$PATH"; command -v mosquitto mosquitto_sub perl python3; ls -l "$ECCE_HOME/bin/mosquitto.exe"' 2>&1 | Tee-Object localjobs\probe.log
$env:Path = $sys
$rc = 0
foreach ($c in "complete", "cancel") {
& "$r\python\python3.exe" tests/windows/launch_local.py $c --build "$r\bin" --state "$PWD\localjobs\state-$c" 2>&1 | Tee-Object "localjobs\$c.log"
"$c rc=$LASTEXITCODE" | Tee-Object -Append localjobs\summary.txt
if ($LASTEXITCODE -ne 0) { $rc = 1 }
}
Get-Content localjobs\summary.txt >> $env:GITHUB_STEP_SUMMARY
exit $rc
# Does it run? (#133) Starts the unpacked apps on the runner's desktop
# (PATH: the package and System32 only) and screenshots them. Allowed
# to fail; see summary.txt.
- name: Start the apps
id: apps
shell: pwsh
continue-on-error: true
timeout-minutes: 20
run: |
$env:Path = "$env:SystemRoot\System32;$env:SystemRoot"
tests\windows\ci-run.ps1 -Stage "$env:RUNNER_TEMP\unpacked" -Out windows-run
Get-Content windows-run\summary.txt >> $env:GITHUB_STEP_SUMMARY
# Per-user MSI (no admin) from the same tree, installed and tested.
- name: Build the MSI
id: msi
shell: pwsh
continue-on-error: true
run: |
dotnet tool install --global wix --version 5.0.2
wix extension add -g WixToolset.Util.wixext/5.0.2
$v = (Get-Content data/client/config/Version -TotalCount 1).Trim()
packaging/windows/make-msi.ps1 -Tree stage\ecce -Version $v -Out "dist\ECCE-windows-$v.msi" | Tee-Object -Append $env:GITHUB_STEP_SUMMARY
- name: Test the MSI (install, run, uninstall)
id: msitest
if: steps.msi.outcome == 'success'
shell: pwsh
continue-on-error: true
run: |
tests\windows\msi-test.ps1 -Msi (Get-ChildItem dist\*.msi).FullName -Launchjob build\launchjob.exe -Out msi-run
$e = $LASTEXITCODE
Get-Content msi-run\summary.txt >> $env:GITHUB_STEP_SUMMARY
exit $e
- uses: actions/upload-artifact@v4
if: always()
with:
name: ECCE-windows-msi
path: dist/*.msi
if-no-files-found: ignore
- uses: actions/upload-artifact@v4
if: always()
with:
name: ECCE-windows-zip
path: dist/*.zip
if-no-files-found: ignore
- uses: actions/upload-artifact@v4
if: always()
with:
name: windows-run
path: |
windows-run/
localjobs/
msi-run/
ctest.log
install.log
if-no-files-found: ignore
# continue-on-error steps show green; say what really happened, and
# fail this (experimental) job when any of them did.
- name: Verdict
if: always()
shell: bash
run: |
{ echo '### Windows'
echo "- ctest: ${{ steps.tests.outcome }}"
echo "- local jobs: ${{ steps.localjobs.outcome }}"
echo "- start the apps: ${{ steps.apps.outcome }}"
echo "- msi build: ${{ steps.msi.outcome }}, msi test: ${{ steps.msitest.outcome }}"; } >> "$GITHUB_STEP_SUMMARY"
[ "${{ steps.tests.outcome }}${{ steps.localjobs.outcome }}${{ steps.apps.outcome }}" = successsuccesssuccess ] && [ "${{ steps.msi.outcome }}${{ steps.msitest.outcome }}" = successsuccess ]