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
name: Release
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
env:
CARGO_TERM_COLOR: always
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
# ── 1. Build release binaries for every platform ──────────────────────────
build:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
archive: tar.gz
- target: x86_64-pc-windows-msvc
os: windows-latest
archive: zip
- target: aarch64-apple-darwin
os: macos-latest
archive: tar.gz
- target: x86_64-apple-darwin
os: macos-latest
archive: tar.gz
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build
run: cargo build --release --target ${{ matrix.target }}
- name: Package (Unix)
if: matrix.archive == 'tar.gz'
run: |
BIN=target/${{ matrix.target }}/release/ccalc
ARCHIVE=ccalc-${{ github.ref_name }}-${{ matrix.target }}.tar.gz
tar czf "$ARCHIVE" -C "$(dirname "$BIN")" "$(basename "$BIN")"
- name: Package (Windows)
if: matrix.archive == 'zip'
shell: pwsh
run: |
$bin = "target\${{ matrix.target }}\release\ccalc.exe"
$archive = "ccalc-${{ github.ref_name }}-${{ matrix.target }}.zip"
Compress-Archive -Path $bin -DestinationPath $archive
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ccalc-${{ matrix.target }}
path: ccalc-${{ github.ref_name }}-${{ matrix.target }}.*
# ── 2. Create GitHub Release and attach binaries ──────────────────────────
release:
name: Create GitHub Release
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: Extract release notes from CHANGELOG.md
id: notes
run: |
VERSION="${GITHUB_REF_NAME#v}"
# Collect all sections that start with ## [VERSION (covers +NNN sub-entries)
NOTES=$(awk "
/^## \[${VERSION}([+\]]|$)/ { found=1; next }
found && /^## \[[0-9]/ && !/^## \[${VERSION}/ { exit }
found { print }
" CHANGELOG.md | sed '/^[[:space:]]*$/{ /./!d }')
{
echo "body<<EOF"
echo "$NOTES"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Publish GitHub Release
uses: softprops/action-gh-release@v2
with:
name: ${{ github.ref_name }}
body: ${{ steps.notes.outputs.body }}
files: artifacts/*
fail_on_unmatched_files: true
# ── 3. Publish to crates.io ───────────────────────────────────────────────
publish:
name: Publish to crates.io
needs: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Publish
run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}