Skip to content

Commit 410ea39

Browse files
sinelawclaude
andcommitted
Add musl builds without plugins for static Linux binaries
Add a custom local-artifacts-jobs workflow that builds x86_64 and aarch64 musl targets with --no-default-features to disable plugins. This produces fully static Linux binaries that don't require glibc. The musl builds are named with "no-plugins" suffix to distinguish them from the regular glibc builds that include plugin support. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 2b72b5c commit 410ea39

3 files changed

Lines changed: 104 additions & 1 deletion

File tree

.github/workflows/musl-builds.yml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Musl static builds without plugins support.
2+
# These builds use --no-default-features to disable the plugins feature,
3+
# which requires dynamic linking that musl doesn't support.
4+
# Kept outside the cargo-dist managed release.yml so it won't be overwritten.
5+
name: Musl Builds
6+
7+
on:
8+
# Allow dist to call this as a reusable workflow during release.
9+
workflow_call:
10+
inputs:
11+
plan:
12+
required: true
13+
type: string
14+
# Manual runs for debugging.
15+
workflow_dispatch:
16+
17+
jobs:
18+
build-musl:
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
include:
23+
- target: x86_64-unknown-linux-musl
24+
runner: ubuntu-22.04
25+
- target: aarch64-unknown-linux-musl
26+
runner: ubuntu-22.04
27+
runs-on: ${{ matrix.runner }}
28+
env:
29+
PLAN: ${{ inputs.plan }}
30+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31+
steps:
32+
- uses: actions/checkout@v4
33+
with:
34+
persist-credentials: false
35+
submodules: recursive
36+
37+
- name: Install Rust toolchain
38+
uses: dtolnay/rust-toolchain@stable
39+
with:
40+
targets: ${{ matrix.target }}
41+
42+
- name: Install musl tools
43+
run: |
44+
sudo apt-get update
45+
sudo apt-get install -y musl-tools
46+
# For aarch64 cross-compilation
47+
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-musl" ]; then
48+
# Install cross for easier cross-compilation
49+
cargo install cross --git https://github.com/cross-rs/cross
50+
fi
51+
52+
- name: Build release binary (no plugins)
53+
run: |
54+
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-musl" ]; then
55+
cross build --release --target ${{ matrix.target }} --no-default-features
56+
else
57+
cargo build --release --target ${{ matrix.target }} --no-default-features
58+
fi
59+
60+
- name: Get version from Cargo.toml
61+
id: version
62+
run: |
63+
VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
64+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
65+
66+
- name: Create archive
67+
run: |
68+
# cargo-dist expects tarballs with contents nested under a root dir
69+
ARCHIVE_NAME="fresh-editor-no-plugins-${{ matrix.target }}"
70+
mkdir -p "${ARCHIVE_NAME}"
71+
cp target/${{ matrix.target }}/release/fresh "${ARCHIVE_NAME}/"
72+
cp README.md LICENSE "${ARCHIVE_NAME}/" 2>/dev/null || true
73+
74+
# Create tarball (cargo-dist format: nested under root dir with same name)
75+
tar -czvf "${ARCHIVE_NAME}.tar.gz" "${ARCHIVE_NAME}"
76+
77+
# Create checksum
78+
sha256sum "${ARCHIVE_NAME}.tar.gz" > "${ARCHIVE_NAME}.tar.gz.sha256"
79+
80+
# Show what we built
81+
ls -la "${ARCHIVE_NAME}.tar.gz"*
82+
83+
- name: Upload artifacts
84+
uses: actions/upload-artifact@v4
85+
with:
86+
name: artifacts-musl-no-plugins-${{ matrix.target }}
87+
path: |
88+
fresh-editor-no-plugins-${{ matrix.target }}.tar.gz
89+
fresh-editor-no-plugins-${{ matrix.target }}.tar.gz.sha256

.github/workflows/release.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,21 @@ jobs:
165165
${{ steps.cargo-dist.outputs.paths }}
166166
${{ env.BUILD_MANIFEST_NAME }}
167167
168+
custom-musl-builds:
169+
needs:
170+
- plan
171+
if: ${{ needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload' }}
172+
uses: ./.github/workflows/musl-builds.yml
173+
with:
174+
plan: ${{ needs.plan.outputs.val }}
175+
secrets: inherit
176+
168177
# Build and package all the platform-agnostic(ish) things
169178
build-global-artifacts:
170179
needs:
171180
- plan
172181
- build-local-artifacts
182+
- custom-musl-builds
173183
runs-on: "ubuntu-22.04"
174184
env:
175185
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -216,6 +226,7 @@ jobs:
216226
needs:
217227
- plan
218228
- build-local-artifacts
229+
- custom-musl-builds
219230
uses: ./.github/workflows/linux-packages.yml
220231
with:
221232
plan: ${{ needs.plan.outputs.val }}
@@ -225,10 +236,11 @@ jobs:
225236
needs:
226237
- plan
227238
- build-local-artifacts
239+
- custom-musl-builds
228240
- build-global-artifacts
229241
- custom-linux-packages
230242
# Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine)
231-
if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-linux-packages.result == 'skipped' || needs.custom-linux-packages.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
243+
if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-linux-packages.result == 'skipped' || needs.custom-linux-packages.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') && (needs.custom-musl-builds.result == 'skipped' || needs.custom-musl-builds.result == 'success') }}
232244
env:
233245
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
234246
runs-on: "ubuntu-22.04"

dist-workspace.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ include = ["plugins/"]
2121
npm-scope = "@fresh-editor"
2222
# Global artifacts jobs to run in CI
2323
global-artifacts-jobs = ["./linux-packages"]
24+
# Local artifacts jobs to run in CI
25+
local-artifacts-jobs = ["./musl-builds"]
2426
# A GitHub repo to push Homebrew formulas to
2527
tap = "sinelaw/homebrew-fresh"
2628
# Publish jobs to run in CI

0 commit comments

Comments
 (0)