Skip to content

Commit f798abb

Browse files
committed
ci(release): full coin x platform release matrix with per-coin gating
One workflow packages all five coin binaries (btc, ltc[+doge aux], dgb, dash, bch) on Linux x86_64, macOS arm64 and Windows x86_64 at tag time, emitting per-coin archives plus a single SHA256SUMS, matching the v0.1.x-alpha release asset shape. Each cell gates on entrypoint presence (src/c2pool/main_<coin>.cpp + src/impl/<coin>, same gate as coin-matrix.yml) and all matrices are fail-fast:false, so a red coin (e.g. btc pending the web_server retype) never blocks the other coins from packaging. Tags + workflow_dispatch only — PR-time coverage stays in coin-matrix.yml. On tags the checksums job creates a DRAFT release; publishing remains a manual operator action. macOS universal (arm64+x86_64 lipo) is a flagged follow-up on this workflow; v1 ships the proven brew arm64 path.
1 parent 48dd2bc commit f798abb

1 file changed

Lines changed: 397 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 397 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,397 @@
1+
name: Release matrix
2+
3+
# V36 ship packaging (integrator dispatch 2026-06-10): one workflow builds
4+
# every coin binary on every platform at tag time and emits a single
5+
# SHA256SUMS, matching the v0.1.x-alpha release shape
6+
# (c2pool-<coin>-<version>-<platform>.{tar.gz,zip} + SHA256SUMS).
7+
#
8+
# Coins: btc, ltc (carries doge merged-mining aux — no separate doge
9+
# binary), dgb, dash, bch. Each coin×platform cell gates on source
10+
# presence (same entrypoint gate as coin-matrix.yml: the real entrypoint
11+
# src/c2pool/main_<coin>.cpp, not src/impl/<coin>/main — see PR #66) and
12+
# every matrix is fail-fast:false, so one red coin never blocks the other
13+
# coins' packages. This implements the ship decouple: a red btc cell
14+
# still lets ltc/dash/doge/dgb/bch package.
15+
#
16+
# macOS: v1 ships arm64 (the proven brew path from build.yml — GitHub
17+
# only provides ARM runners). The universal (arm64+x86_64 lipo) artifact
18+
# needs x86_64 deps on the arm64 runner — dual Conan profile cross-build
19+
# planned as a follow-up iteration on this workflow before tag time.
20+
#
21+
# Triggers: tags only, plus workflow_dispatch for a full-matrix dry run
22+
# from any ref. PR-time per-coin coverage stays in coin-matrix.yml; this
23+
# workflow is intentionally NOT wired to pull_request (15 cells).
24+
#
25+
# Publishing: the checksums job assembles all packages and, on tags,
26+
# creates a DRAFT GitHub release. Publishing the draft is a manual
27+
# operator action — CI never publishes.
28+
29+
on:
30+
push:
31+
tags: ['v*']
32+
workflow_dispatch:
33+
34+
concurrency:
35+
group: release-${{ github.ref }}
36+
cancel-in-progress: false
37+
38+
permissions:
39+
contents: read
40+
41+
jobs:
42+
# ════════════════════════════════════════════════════════════════════════════
43+
# Linux x86_64 (Ubuntu 24.04, GCC 13, Conan) — one cell per coin
44+
# ════════════════════════════════════════════════════════════════════════════
45+
linux:
46+
name: ${{ matrix.coin }} package (Linux x86_64)
47+
runs-on: ubuntu-24.04
48+
strategy:
49+
fail-fast: false
50+
matrix:
51+
coin: [btc, ltc, dgb, dash, bch]
52+
steps:
53+
- uses: actions/checkout@v6
54+
55+
- name: Resolve version
56+
id: ver
57+
run: |
58+
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
59+
echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
60+
else
61+
echo "version=0.0.0-${GITHUB_SHA:0:8}" >> "$GITHUB_OUTPUT"
62+
fi
63+
64+
- name: Check source presence
65+
id: presence
66+
run: |
67+
if [ -f "src/c2pool/main_${{ matrix.coin }}.cpp" ] && [ -d "src/impl/${{ matrix.coin }}" ]; then
68+
echo "exists=1" >> "$GITHUB_OUTPUT"
69+
echo "::notice::c2pool-${{ matrix.coin }} source present — packaging."
70+
else
71+
echo "exists=0" >> "$GITHUB_OUTPUT"
72+
echo "::warning::c2pool-${{ matrix.coin }} source not on this ref — no ${{ matrix.coin }} Linux package will be produced."
73+
fi
74+
75+
- name: Install system dependencies
76+
if: steps.presence.outputs.exists == '1'
77+
run: |
78+
sudo apt-get update -qq
79+
sudo apt-get install -y --no-install-recommends \
80+
g++ cmake make libleveldb-dev libsecp256k1-dev
81+
82+
- uses: actions/setup-python@v6
83+
if: steps.presence.outputs.exists == '1'
84+
with: { python-version: '3.12' }
85+
86+
- name: Install Conan 2
87+
if: steps.presence.outputs.exists == '1'
88+
run: pip install "conan>=2.0,<3.0"
89+
90+
- name: Detect Conan profile
91+
if: steps.presence.outputs.exists == '1'
92+
run: |
93+
conan profile detect --force
94+
sed -i 's/compiler.cppstd=.*/compiler.cppstd=20/' "$(conan profile path default)"
95+
96+
- name: Restore Conan cache
97+
if: steps.presence.outputs.exists == '1'
98+
uses: actions/cache@v5
99+
with:
100+
path: ~/.conan2
101+
key: conan2-ubuntu24-gcc13-${{ matrix.coin }}-${{ hashFiles('conanfile.txt') }}
102+
restore-keys: |
103+
conan2-ubuntu24-gcc13-${{ matrix.coin }}-
104+
conan2-ubuntu24-gcc13-
105+
106+
- name: Conan install
107+
if: steps.presence.outputs.exists == '1'
108+
run: |
109+
conan install . \
110+
--build=missing \
111+
--output-folder=build_${{ matrix.coin }} \
112+
--settings=build_type=Release
113+
114+
- name: Configure
115+
if: steps.presence.outputs.exists == '1'
116+
run: |
117+
cmake -S . -B build_${{ matrix.coin }} \
118+
-DCMAKE_TOOLCHAIN_FILE=build_${{ matrix.coin }}/conan_toolchain.cmake \
119+
-DCMAKE_BUILD_TYPE=Release
120+
121+
- name: Build c2pool-${{ matrix.coin }}
122+
if: steps.presence.outputs.exists == '1'
123+
run: cmake --build build_${{ matrix.coin }} --target c2pool-${{ matrix.coin }} -j$(nproc)
124+
125+
- name: Smoke test (--help)
126+
if: steps.presence.outputs.exists == '1'
127+
run: |
128+
BIN=build_${{ matrix.coin }}/src/c2pool/c2pool-${{ matrix.coin }}
129+
file "$BIN"
130+
"$BIN" --help 2>&1 | head -5 || true
131+
132+
- name: Package
133+
if: steps.presence.outputs.exists == '1'
134+
run: |
135+
VERSION="${{ steps.ver.outputs.version }}"
136+
COIN="${{ matrix.coin }}"
137+
PKG="c2pool-${COIN}-${VERSION}-linux-x86_64"
138+
mkdir -p "${PKG}/lib" "${PKG}/config" "${PKG}/web-static" "${PKG}/explorer"
139+
cp "build_${COIN}/src/c2pool/c2pool-${COIN}" "${PKG}/"
140+
strip "${PKG}/c2pool-${COIN}"
141+
for lib in libleveldb.so.1 libsecp256k1.so.2 libsnappy.so.1; do
142+
found=$(find /usr/lib -name "${lib}*" -type f 2>/dev/null | head -1)
143+
[ -n "$found" ] && cp "$found" "${PKG}/lib/"
144+
done
145+
cp start.sh "${PKG}/" && chmod +x "${PKG}/start.sh"
146+
cp config/c2pool_mainnet.yaml "${PKG}/config/c2pool_mainnet.yaml.example" || true
147+
cp config/c2pool_testnet.yaml "${PKG}/config/" || true
148+
cp -r web-static/* "${PKG}/web-static/"
149+
cp explorer/explorer.py "${PKG}/explorer/"
150+
tar czf "${PKG}.tar.gz" "${PKG}/"
151+
152+
- name: Upload package
153+
if: steps.presence.outputs.exists == '1'
154+
uses: actions/upload-artifact@v7
155+
with:
156+
name: pkg-linux-${{ matrix.coin }}
157+
path: c2pool-*-linux-x86_64.tar.gz
158+
159+
# ════════════════════════════════════════════════════════════════════════════
160+
# macOS arm64 (Apple Silicon; universal lipo is a follow-up — see header)
161+
# ════════════════════════════════════════════════════════════════════════════
162+
macos:
163+
name: ${{ matrix.coin }} package (macOS arm64)
164+
runs-on: macos-14
165+
strategy:
166+
fail-fast: false
167+
matrix:
168+
coin: [btc, ltc, dgb, dash, bch]
169+
steps:
170+
- uses: actions/checkout@v6
171+
172+
- name: Resolve version
173+
id: ver
174+
run: |
175+
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
176+
echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
177+
else
178+
echo "version=0.0.0-${GITHUB_SHA:0:8}" >> "$GITHUB_OUTPUT"
179+
fi
180+
181+
- name: Check source presence
182+
id: presence
183+
run: |
184+
if [ -f "src/c2pool/main_${{ matrix.coin }}.cpp" ] && [ -d "src/impl/${{ matrix.coin }}" ]; then
185+
echo "exists=1" >> "$GITHUB_OUTPUT"
186+
else
187+
echo "exists=0" >> "$GITHUB_OUTPUT"
188+
echo "::warning::c2pool-${{ matrix.coin }} source not on this ref — no ${{ matrix.coin }} macOS package will be produced."
189+
fi
190+
191+
- name: Install dependencies
192+
if: steps.presence.outputs.exists == '1'
193+
run: brew install cmake boost leveldb secp256k1 nlohmann-json yaml-cpp
194+
195+
- name: Configure
196+
if: steps.presence.outputs.exists == '1'
197+
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
198+
199+
- name: Build c2pool-${{ matrix.coin }}
200+
if: steps.presence.outputs.exists == '1'
201+
run: cmake --build build --target c2pool-${{ matrix.coin }} -j$(sysctl -n hw.ncpu)
202+
203+
- name: Smoke test (--help)
204+
if: steps.presence.outputs.exists == '1'
205+
run: |
206+
BIN=build/src/c2pool/c2pool-${{ matrix.coin }}
207+
file "$BIN"
208+
"$BIN" --help 2>&1 | head -5 || true
209+
210+
- name: Package
211+
if: steps.presence.outputs.exists == '1'
212+
run: |
213+
VERSION="${{ steps.ver.outputs.version }}"
214+
COIN="${{ matrix.coin }}"
215+
PKG="c2pool-${COIN}-${VERSION}-macos-arm64"
216+
mkdir -p "${PKG}/lib" "${PKG}/config" "${PKG}/web-static" "${PKG}/explorer"
217+
cp "build/src/c2pool/c2pool-${COIN}" "${PKG}/"
218+
strip "${PKG}/c2pool-${COIN}"
219+
for dylib in $(otool -L "${PKG}/c2pool-${COIN}" | grep "/opt/homebrew" | awk '{print $1}'); do
220+
base=$(basename "$dylib")
221+
cp "$dylib" "${PKG}/lib/${base}"
222+
install_name_tool -change "$dylib" "@executable_path/lib/${base}" "${PKG}/c2pool-${COIN}"
223+
done
224+
for lib in "${PKG}"/lib/*.dylib; do
225+
for ref in $(otool -L "$lib" | grep "/opt/homebrew" | awk '{print $1}'); do
226+
base=$(basename "$ref")
227+
[ -f "${PKG}/lib/${base}" ] && install_name_tool -change "$ref" "@executable_path/lib/${base}" "$lib"
228+
done
229+
install_name_tool -id "@executable_path/lib/$(basename $lib)" "$lib"
230+
done
231+
cp start.sh "${PKG}/" && chmod +x "${PKG}/start.sh"
232+
cp config/c2pool_mainnet.yaml "${PKG}/config/c2pool_mainnet.yaml.example" || true
233+
cp -r web-static/* "${PKG}/web-static/"
234+
cp explorer/explorer.py "${PKG}/explorer/"
235+
zip -r "${PKG}.zip" "${PKG}/"
236+
237+
- name: Upload package
238+
if: steps.presence.outputs.exists == '1'
239+
uses: actions/upload-artifact@v7
240+
with:
241+
name: pkg-macos-${{ matrix.coin }}
242+
path: c2pool-*-macos-arm64.zip
243+
244+
# ════════════════════════════════════════════════════════════════════════════
245+
# Windows x86_64 (MSVC 2022, Conan)
246+
# ════════════════════════════════════════════════════════════════════════════
247+
windows:
248+
name: ${{ matrix.coin }} package (Windows x86_64)
249+
runs-on: windows-2022
250+
strategy:
251+
fail-fast: false
252+
matrix:
253+
coin: [btc, ltc, dgb, dash, bch]
254+
steps:
255+
- uses: actions/checkout@v6
256+
257+
- name: Resolve version
258+
id: ver
259+
shell: bash
260+
run: |
261+
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
262+
echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
263+
else
264+
echo "version=0.0.0-${GITHUB_SHA:0:8}" >> "$GITHUB_OUTPUT"
265+
fi
266+
267+
- name: Check source presence
268+
id: presence
269+
shell: bash
270+
run: |
271+
if [ -f "src/c2pool/main_${{ matrix.coin }}.cpp" ] && [ -d "src/impl/${{ matrix.coin }}" ]; then
272+
echo "exists=1" >> "$GITHUB_OUTPUT"
273+
else
274+
echo "exists=0" >> "$GITHUB_OUTPUT"
275+
echo "::warning::c2pool-${{ matrix.coin }} source not on this ref — no ${{ matrix.coin }} Windows package will be produced."
276+
fi
277+
278+
- uses: actions/setup-python@v6
279+
if: steps.presence.outputs.exists == '1'
280+
with: { python-version: '3.12' }
281+
282+
- name: Install Conan 2
283+
if: steps.presence.outputs.exists == '1'
284+
run: pip install "conan>=2.0,<3.0"
285+
286+
- name: Detect Conan profile
287+
if: steps.presence.outputs.exists == '1'
288+
run: |
289+
conan profile detect --force
290+
$profile = conan profile path default
291+
(Get-Content $profile) -replace 'compiler.cppstd=14','compiler.cppstd=20' | Set-Content $profile
292+
293+
- name: Restore Conan cache
294+
if: steps.presence.outputs.exists == '1'
295+
uses: actions/cache@v5
296+
with:
297+
path: ~/.conan2
298+
key: conan2-windows-msvc194-${{ hashFiles('conanfile.txt') }}
299+
300+
- name: Conan install
301+
if: steps.presence.outputs.exists == '1'
302+
run: conan install . --build=missing --output-folder=build_ci
303+
304+
- name: Build secp256k1
305+
if: steps.presence.outputs.exists == '1'
306+
run: |
307+
git clone https://github.com/bitcoin-core/secp256k1 secp256k1-src
308+
cmake -B secp256k1-src/build -S secp256k1-src -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="${env:GITHUB_WORKSPACE}/secp256k1" -DSECP256K1_BUILD_TESTS=OFF -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF -DSECP256K1_BUILD_BENCHMARK=OFF -DSECP256K1_BUILD_EXAMPLES=OFF
309+
cmake --build secp256k1-src/build --config Release
310+
cmake --install secp256k1-src/build --config Release
311+
312+
- name: Configure
313+
if: steps.presence.outputs.exists == '1'
314+
shell: cmd
315+
run: cmake -S . -B build_ci -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=build_ci/conan_toolchain.cmake -DCMAKE_PREFIX_PATH="%GITHUB_WORKSPACE%/secp256k1" -DCMAKE_CXX_FLAGS="/D_WIN32_WINNT=0x0A00"
316+
317+
- name: Build c2pool-${{ matrix.coin }}
318+
if: steps.presence.outputs.exists == '1'
319+
shell: cmd
320+
run: cmake --build build_ci --target c2pool-${{ matrix.coin }} --config Release -j %NUMBER_OF_PROCESSORS%
321+
322+
- name: Smoke test (--help)
323+
if: steps.presence.outputs.exists == '1'
324+
run: |
325+
Copy-Item "${env:GITHUB_WORKSPACE}/secp256k1/bin/libsecp256k1-6.dll" build_ci/src/c2pool/Release/
326+
build_ci/src/c2pool/Release/c2pool-${{ matrix.coin }}.exe --help 2>&1 | Select-Object -First 5
327+
328+
- name: Package
329+
if: steps.presence.outputs.exists == '1'
330+
run: |
331+
$VERSION = "${{ steps.ver.outputs.version }}"
332+
$COIN = "${{ matrix.coin }}"
333+
$PKG = "c2pool-${COIN}-${VERSION}-windows-x86_64"
334+
New-Item -ItemType Directory -Path "${PKG}/lib","${PKG}/config","${PKG}/web-static","${PKG}/explorer" -Force
335+
Copy-Item "build_ci/src/c2pool/Release/c2pool-${COIN}.exe" "${PKG}/"
336+
# DLL must be next to exe for Windows DLL search path (portable ZIP)
337+
# Also copy to lib/ for Inno Setup installer compatibility
338+
Copy-Item "${env:GITHUB_WORKSPACE}/secp256k1/bin/libsecp256k1-6.dll" "${PKG}/"
339+
Copy-Item "${env:GITHUB_WORKSPACE}/secp256k1/bin/libsecp256k1-6.dll" "${PKG}/lib/"
340+
Copy-Item start.bat "${PKG}/"
341+
Copy-Item -Recurse web-static/* "${PKG}/web-static/"
342+
Copy-Item explorer/explorer.py "${PKG}/explorer/"
343+
Copy-Item config/c2pool_mainnet.yaml "${PKG}/config/c2pool_mainnet.yaml.example"
344+
Copy-Item config/c2pool_testnet.yaml "${PKG}/config/" -ErrorAction SilentlyContinue
345+
Compress-Archive -Path "${PKG}" -DestinationPath "${PKG}.zip"
346+
347+
- name: Upload package
348+
if: steps.presence.outputs.exists == '1'
349+
uses: actions/upload-artifact@v7
350+
with:
351+
name: pkg-windows-${{ matrix.coin }}
352+
path: c2pool-*-windows-x86_64.zip
353+
354+
# ════════════════════════════════════════════════════════════════════════════
355+
# Aggregate: single SHA256SUMS over every produced package; on tags,
356+
# attach everything to a DRAFT release (operator publishes manually).
357+
# if: always() — runs even when some coin cells are red or skipped, so a
358+
# red btc never blocks the other coins' packages from shipping.
359+
# ════════════════════════════════════════════════════════════════════════════
360+
checksums:
361+
name: SHA256SUMS + draft release
362+
runs-on: ubuntu-24.04
363+
needs: [linux, macos, windows]
364+
if: always()
365+
permissions:
366+
contents: write
367+
steps:
368+
- name: Download all packages
369+
uses: actions/download-artifact@v7
370+
with:
371+
pattern: pkg-*
372+
merge-multiple: true
373+
path: dist
374+
375+
- name: Generate SHA256SUMS
376+
working-directory: dist
377+
run: |
378+
ls -l
379+
sha256sum * > SHA256SUMS
380+
cat SHA256SUMS
381+
382+
- name: Upload SHA256SUMS
383+
uses: actions/upload-artifact@v7
384+
with:
385+
name: SHA256SUMS
386+
path: dist/SHA256SUMS
387+
388+
- name: Create draft release
389+
if: startsWith(github.ref, 'refs/tags/v')
390+
env:
391+
GH_TOKEN: ${{ github.token }}
392+
run: |
393+
gh release create "${GITHUB_REF_NAME}" \
394+
--draft \
395+
--title "c2pool ${GITHUB_REF_NAME}" \
396+
--notes "Draft assembled by release.yml — operator reviews and publishes manually." \
397+
dist/*

0 commit comments

Comments
 (0)