Skip to content

Commit eca0e60

Browse files
committed
feat: add cross-platform packaging and release automation
- Add GitHub Actions workflow for automated releases - Create .deb, .rpm, AppImage, .dmg, and .msi packages - Generate shell completions and manpages in build.rs - Add platform-specific icons from rustnet3.svg - Include eBPF dependencies for Linux packages - Support Windows 32-bit and 64-bit builds - Extract shared CLI module to prevent duplication
1 parent b642205 commit eca0e60

20 files changed

Lines changed: 1244 additions & 60 deletions

File tree

.github/workflows/release.yml

Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v[0-9]+.[0-9]+.[0-9]+"
7+
workflow_dispatch:
8+
9+
env:
10+
RUST_BACKTRACE: 1
11+
RUSTNET_ASSET_DIR: assets
12+
13+
jobs:
14+
build-release:
15+
name: build-release
16+
runs-on: ${{ matrix.os }}
17+
strategy:
18+
matrix:
19+
build:
20+
- linux-aarch64-gnu
21+
- linux-aarch64-musl
22+
- linux-armv7-gnueabihf
23+
- linux-armv7-musleabihf
24+
- linux-x64-gnu
25+
- linux-x64-musl
26+
- macos-aarch64
27+
- macos-x64
28+
- windows-x64-msvc
29+
- windows-x86-msvc
30+
include:
31+
- os: ubuntu-latest # default
32+
- cargo: cargo # default; overwrite with `cross` if necessary
33+
- build: linux-aarch64-gnu
34+
target: aarch64-unknown-linux-gnu
35+
cargo: cross
36+
- build: linux-aarch64-musl
37+
target: aarch64-unknown-linux-musl
38+
cargo: cross
39+
- build: linux-armv7-gnueabihf
40+
target: armv7-unknown-linux-gnueabihf
41+
cargo: cross
42+
- build: linux-armv7-musleabihf
43+
target: armv7-unknown-linux-musleabihf
44+
cargo: cross
45+
- build: linux-x64-gnu
46+
target: x86_64-unknown-linux-gnu
47+
- build: linux-x64-musl
48+
target: x86_64-unknown-linux-musl
49+
- build: macos-aarch64
50+
os: macos-14
51+
target: aarch64-apple-darwin
52+
- build: macos-x64
53+
os: macos-14
54+
target: x86_64-apple-darwin
55+
- build: windows-x64-msvc
56+
os: windows-latest
57+
target: x86_64-pc-windows-msvc
58+
- build: windows-x86-msvc
59+
os: windows-latest
60+
target: i686-pc-windows-msvc
61+
62+
steps:
63+
- name: Checkout repository
64+
uses: actions/checkout@v4
65+
66+
- name: Install Linux dependencies
67+
if: matrix.os == 'ubuntu-latest'
68+
run: |
69+
sudo apt-get update -y
70+
sudo apt-get install -y libpcap-dev libelf-dev clang llvm
71+
72+
- name: Install Rust
73+
uses: dtolnay/rust-toolchain@stable
74+
with:
75+
toolchain: stable
76+
targets: ${{ matrix.target }}
77+
78+
- name: Install cross
79+
if: matrix.cargo == 'cross'
80+
uses: taiki-e/cache-cargo-install-action@v2
81+
with:
82+
tool: cross
83+
git: https://github.com/cross-rs/cross.git
84+
rev: 085092c
85+
86+
- name: Build release binary
87+
shell: bash
88+
env:
89+
RUSTFLAGS: "-C strip=symbols"
90+
run: |
91+
mkdir -p "$RUSTNET_ASSET_DIR"
92+
# build.rs will handle Npcap SDK download on Windows
93+
${{ matrix.cargo }} build --verbose --release --target ${{ matrix.target }}
94+
95+
- name: Create release archive
96+
shell: bash
97+
env:
98+
RUSTNET_BIN: ${{ contains(matrix.os, 'windows') && 'rustnet.exe' || 'rustnet' }}
99+
run: |
100+
staging="rustnet-${{ github.ref_name }}-${{ matrix.target }}"
101+
mkdir -p "$staging"
102+
103+
# Copy binary
104+
cp "target/${{ matrix.target }}/release/$RUSTNET_BIN" "$staging/"
105+
106+
# Copy assets if they exist
107+
if [ -d "$RUSTNET_ASSET_DIR" ]; then
108+
cp -r "$RUSTNET_ASSET_DIR" "$staging/"
109+
fi
110+
111+
# Copy documentation
112+
cp README.md "$staging/"
113+
cp LICENSE "$staging/" 2>/dev/null || true
114+
115+
# Create archive
116+
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
117+
7z a "$staging.zip" "$staging"
118+
echo "ASSET=$staging.zip" >> $GITHUB_ENV
119+
else
120+
tar czf "$staging.tar.gz" "$staging"
121+
echo "ASSET=$staging.tar.gz" >> $GITHUB_ENV
122+
fi
123+
124+
- name: Upload build artifacts
125+
uses: actions/upload-artifact@v4
126+
with:
127+
name: build-${{ matrix.target }}
128+
path: ${{ env.ASSET }}
129+
if-no-files-found: error
130+
131+
create-release:
132+
name: create-release
133+
runs-on: ubuntu-latest
134+
needs: build-release
135+
steps:
136+
- name: Checkout repository
137+
uses: actions/checkout@v4
138+
139+
- name: Download all artifacts
140+
uses: actions/download-artifact@v4
141+
with:
142+
path: artifacts
143+
144+
- name: Create Release
145+
env:
146+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
147+
run: |
148+
# Create the release
149+
gh release create ${{ github.ref_name }} \
150+
--title "Release ${{ github.ref_name }}" \
151+
--draft \
152+
--generate-notes
153+
154+
# Upload all build artifacts
155+
for artifact in artifacts/build-*/rustnet-*; do
156+
gh release upload ${{ github.ref_name }} "$artifact"
157+
done
158+
159+
package-installers:
160+
name: package-installers
161+
runs-on: ubuntu-latest
162+
needs: create-release
163+
steps:
164+
- name: Checkout repository
165+
uses: actions/checkout@v4
166+
167+
- name: Download build artifacts
168+
uses: actions/download-artifact@v4
169+
with:
170+
path: artifacts
171+
172+
- name: Install dependencies
173+
run: |
174+
sudo apt-get update -y
175+
sudo apt-get install -y libpcap-dev libelf-dev clang llvm
176+
177+
- name: Install Rust and tools
178+
uses: dtolnay/rust-toolchain@stable
179+
with:
180+
targets: x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf
181+
182+
- name: Install packaging tools
183+
run: |
184+
cargo install cargo-deb cargo-generate-rpm
185+
186+
- name: Package Debian packages
187+
run: |
188+
mkdir -p installers
189+
for arch in amd64 arm64 armhf; do
190+
case $arch in
191+
amd64) target="x86_64-unknown-linux-gnu" ;;
192+
arm64) target="aarch64-unknown-linux-gnu" ;;
193+
armhf) target="armv7-unknown-linux-gnueabihf" ;;
194+
esac
195+
196+
# Extract binary from artifact
197+
tar -xzf "artifacts/build-$target/rustnet-${{ github.ref_name }}-$target.tar.gz"
198+
mkdir -p "target/$target/release"
199+
cp "rustnet-${{ github.ref_name }}-$target/rustnet" "target/$target/release/"
200+
201+
# Create deb package
202+
cargo deb --no-build --no-strip --target $target
203+
mv "target/$target/debian"/*.deb "installers/Rustnet_LinuxDEB_$arch.deb"
204+
205+
# Clean up for next iteration
206+
rm -rf "rustnet-${{ github.ref_name }}-$target" "target/$target"
207+
done
208+
209+
- name: Package RPM packages
210+
run: |
211+
for arch in x86_64 aarch64; do
212+
target="$arch-unknown-linux-gnu"
213+
214+
# Extract binary from artifact
215+
tar -xzf "artifacts/build-$target/rustnet-${{ github.ref_name }}-$target.tar.gz"
216+
mkdir -p "target/$target/release"
217+
cp "rustnet-${{ github.ref_name }}-$target/rustnet" "target/$target/release/"
218+
219+
# Fix library linking if needed
220+
patchelf --replace-needed libpcap.so.0.8 libpcap.so.1 "target/$target/release/rustnet" 2>/dev/null || true
221+
222+
# Create rpm package
223+
cargo generate-rpm --target $target
224+
mv "target/$target/generate-rpm"/*.rpm "installers/Rustnet_LinuxRPM_$arch.rpm"
225+
226+
# Clean up for next iteration
227+
rm -rf "rustnet-${{ github.ref_name }}-$target" "target/$target"
228+
done
229+
230+
- name: Upload installer packages
231+
env:
232+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
233+
run: |
234+
# Upload all installer packages
235+
for installer in installers/*; do
236+
gh release upload ${{ github.ref_name }} "$installer"
237+
done
238+
239+
package-macos:
240+
name: package-macos
241+
runs-on: macos-latest
242+
needs: create-release
243+
strategy:
244+
matrix:
245+
include:
246+
- arch: Intel
247+
target: x86_64-apple-darwin
248+
- arch: AppleSilicon
249+
target: aarch64-apple-darwin
250+
steps:
251+
- name: Checkout repository
252+
uses: actions/checkout@v4
253+
254+
- name: Install packaging tools
255+
run: |
256+
cargo install toml-cli
257+
brew install create-dmg
258+
259+
- name: Download build artifact
260+
uses: actions/download-artifact@v4
261+
with:
262+
name: build-${{ matrix.target }}
263+
path: artifacts
264+
265+
- name: Package for macOS
266+
run: |
267+
# Extract binary
268+
tar -xzf "artifacts/rustnet-${{ github.ref_name }}-${{ matrix.target }}.tar.gz"
269+
270+
# Get version and update plist
271+
VERSION=$(toml get Cargo.toml package.version --raw)
272+
sed -i'.bak' -e "s/0\.0\.0/${VERSION}/g" -e "s/fffffff/${GITHUB_SHA:0:7}/g" resources/packaging/macos/Info.plist
273+
274+
# Create app bundle
275+
mkdir -p "Rustnet.app/Contents/"{MacOS,Resources}
276+
cp resources/packaging/macos/Info.plist "Rustnet.app/Contents/"
277+
cp resources/packaging/macos/graphics/rustnet.icns "Rustnet.app/Contents/Resources/"
278+
cp "rustnet-${{ github.ref_name }}-${{ matrix.target }}/rustnet" "Rustnet.app/Contents/MacOS/"
279+
cp resources/packaging/macos/wrapper.sh "Rustnet.app/Contents/MacOS/"
280+
chmod +x "Rustnet.app/Contents/MacOS/"{rustnet,wrapper.sh}
281+
282+
# Create DMG
283+
create-dmg \
284+
--volname "Rustnet Installer" \
285+
--background "resources/packaging/macos/graphics/dmg_bg.png" \
286+
--window-pos 200 120 \
287+
--window-size 900 450 \
288+
--icon-size 100 \
289+
--app-drop-link 620 240 \
290+
--icon "Rustnet.app" 300 240 \
291+
--hide-extension "Rustnet.app" \
292+
"Rustnet_macOS_${{ matrix.arch }}.dmg" \
293+
"Rustnet.app"
294+
295+
- name: Upload macOS package
296+
env:
297+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
298+
run: |
299+
gh release upload ${{ github.ref_name }} "Rustnet_macOS_${{ matrix.arch }}.dmg"
300+
301+
package-windows:
302+
name: package-windows
303+
runs-on: windows-latest
304+
needs: create-release
305+
strategy:
306+
matrix:
307+
include:
308+
- arch: 32-bit
309+
target: i686-pc-windows-msvc
310+
- arch: 64-bit
311+
target: x86_64-pc-windows-msvc
312+
steps:
313+
- name: Checkout repository
314+
uses: actions/checkout@v4
315+
316+
- name: Install dependencies
317+
shell: powershell
318+
run: |
319+
Write-Host "::group::WiX Toolset"
320+
Invoke-WebRequest `
321+
-Uri "https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip" `
322+
-OutFile "$env:TEMP\wix-binaries.zip" -Verbose
323+
Expand-Archive -LiteralPath "$env:TEMP\wix-binaries.zip" -DestinationPath "$env:TEMP\wix" -Verbose
324+
Set-Item -Path env:Path -Value "$env:Path;$env:TEMP\wix"
325+
Write-Host "::endgroup::"
326+
327+
- name: Install Rust and tools
328+
uses: dtolnay/rust-toolchain@stable
329+
with:
330+
targets: ${{ matrix.target }}
331+
332+
- name: Install packaging tools
333+
run: cargo install cargo-wix
334+
335+
- name: Download build artifact
336+
uses: actions/download-artifact@v4
337+
with:
338+
name: build-${{ matrix.target }}
339+
path: artifacts
340+
341+
- name: Package for Windows
342+
shell: powershell
343+
run: |
344+
# Extract binary
345+
Expand-Archive -LiteralPath "artifacts\rustnet-${{ github.ref_name }}-${{ matrix.target }}.zip" -DestinationPath .
346+
New-Item -ItemType Directory -Path "target\${{ matrix.target }}\release" -Force
347+
Move-Item -Path "rustnet-${{ github.ref_name }}-${{ matrix.target }}\rustnet.exe" -Destination "target\${{ matrix.target }}\release\"
348+
349+
# Create MSI package
350+
cargo wix --no-build --nocapture --target ${{ matrix.target }}
351+
Move-Item -Path "target\wix\rustnet-monitor*.msi" -Destination "Rustnet_Windows_${{ matrix.arch }}.msi"
352+
353+
- name: Upload Windows package
354+
env:
355+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
356+
run: |
357+
gh release upload ${{ github.ref_name }} "Rustnet_Windows_${{ matrix.arch }}.msi"

0 commit comments

Comments
 (0)