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
name: Publish
on:
push:
tags:
jobs:
verify-version:
name: Verify version consistency
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Extract tag version
id: tag
run: echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
- name: Check Cargo.toml version matches tag
run: |
TAG_VERSION="${{ steps.tag.outputs.version }}"
CARGO_VERSION=$(grep -oP '^version\s*=\s*"\K[^"]+' Cargo.toml | head -1)
if [ "$CARGO_VERSION" != "$TAG_VERSION" ]; then
echo "::error::Cargo.toml version ($CARGO_VERSION) != tag ($TAG_VERSION)"
exit 1
fi
echo "Version matches tag v$TAG_VERSION"
publish-crates:
name: Publish to crates.io
runs-on: ubuntu-latest
timeout-minutes: 15
needs: verify-version
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Publish libnoa to crates.io
env:
CRATES_IO_API_TOKEN: ${{ secrets.CRATES_IO_API_TOKEN }}
run: |
if [ -z "$CRATES_IO_API_TOKEN" ]; then
echo "::error::CRATES_IO_API_TOKEN secret is not configured"
echo "Please set it in: Settings > Secrets and variables > Actions > Repository secrets"
exit 1
fi
cargo login "$CRATES_IO_API_TOKEN"
cargo publish -p libnoa --allow-dirty -v
build-release:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
needs: verify-version
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
artifact: noa-linux-x86_64
ext: tar.gz
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
artifact: noa-linux-aarch64
ext: tar.gz
- target: x86_64-apple-darwin
os: macos-latest
artifact: noa-macos-x86_64
ext: tar.gz
- target: aarch64-apple-darwin
os: macos-latest
artifact: noa-macos-aarch64
ext: tar.gz
- target: x86_64-pc-windows-msvc
os: windows-latest
artifact: noa-windows-x86_64
ext: zip
- target: aarch64-pc-windows-msvc
os: windows-latest
artifact: noa-windows-aarch64
ext: zip
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Configure cross-compilation (Linux ARM64)
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
mkdir -p .cargo
cat >> .cargo/config.toml <<EOF
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
EOF
- name: Install NASM (Windows)
if: runner.os == 'Windows'
uses: ilammy/setup-nasm@v1
- name: Set up MSVC ARM64 target (Windows ARM64)
if: matrix.target == 'aarch64-pc-windows-msvc'
uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64_arm64
- name: Build
run: cargo build --release --target ${{ matrix.target }}
- name: Package binaries (Unix)
if: runner.os != 'Windows'
run: |
mkdir -p dist
cp target/${{ matrix.target }}/release/noa dist/
cp target/${{ matrix.target }}/release/noa-server dist/ 2>/dev/null || true
cd dist
tar czf ${{ matrix.artifact }}.tar.gz noa noa-server
- name: Package binaries (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path dist
Copy-Item "target/${{ matrix.target }}/release/noa.exe" "dist/"
if (Test-Path "target/${{ matrix.target }}/release/noa-server.exe") {
Copy-Item "target/${{ matrix.target }}/release/noa-server.exe" "dist/"
}
$files = @("dist/noa.exe")
if (Test-Path "dist/noa-server.exe") {
$files += "dist/noa-server.exe"
}
Compress-Archive -Path $files -DestinationPath "dist/${{ matrix.artifact }}.zip"
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: dist/${{ matrix.artifact }}.${{ matrix.ext }}
github-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: false
- name: Collect artifacts
run: |
mkdir -p release-assets
find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' \) -exec cp {} release-assets/ \;
ls -la release-assets/
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
files: |
release-assets/*.tar.gz
release-assets/*.zip