Skip to content

Commit a6f21b9

Browse files
committed
Add ARM64 binary support to GitHub Actions workflows
- Implement matrix strategy for building x86_64 and ARM64 binaries - Use QEMU emulation via run-on-arch-action for ARM64 builds - Update artifact naming to include architecture: - taskrunner-linux-x86_64.tar.gz (new explicit naming) - taskrunner-linux-arm64.tar.gz (new ARM64 binary) - taskrunner-linux.tar.gz (kept for backward compatibility, same as x86_64) - Skip S3 tests for ARM64 builds (SKIP_S3_TESTS=1) to simplify container setup - Apply changes to both build.yml and release.yml for consistency The ARM64 builds run in emulation which is 2-10x slower than native builds, but provides working ARM64 binaries without requiring dedicated hardware.
1 parent 4efcfd3 commit a6f21b9

File tree

2 files changed

+217
-32
lines changed

2 files changed

+217
-32
lines changed

.github/workflows/build.yml

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,63 @@ on: [push]
55
jobs:
66
build:
77
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
include:
11+
- arch: x86_64
12+
arch_alt: amd64
13+
- arch: arm64
14+
arch_alt: aarch64
815
steps:
9-
- name: start service container
16+
# Setup QEMU for ARM64 emulation
17+
- name: Set up QEMU
18+
if: matrix.arch == 'arm64'
19+
uses: docker/setup-qemu-action@v3
20+
with:
21+
platforms: arm64
22+
23+
# Use run-on-arch for ARM64 builds
24+
- name: Checkout (ARM64)
25+
if: matrix.arch == 'arm64'
26+
uses: actions/checkout@v2
27+
28+
- name: Build on ARM64
29+
if: matrix.arch == 'arm64'
30+
uses: uraimo/run-on-arch-action@v2
31+
with:
32+
arch: aarch64
33+
distro: ubuntu22.04
34+
githubToken: ${{ github.token }}
35+
dockerRunArgs: |
36+
--volume "${PWD}:/workspace"
37+
install: |
38+
apt-get update -q -y
39+
apt-get install -q -y curl gcc g++ make libgmp-dev libtinfo-dev libncurses5-dev libc6-dev zlib1g-dev
40+
# Install Stack
41+
curl -sSL https://get.haskellstack.org/ | sh
42+
run: |
43+
cd /workspace
44+
# Build
45+
export PATH=/root/.local/bin:$PATH
46+
stack --no-terminal build --test --only-dependencies
47+
mkdir -p dist
48+
stack --no-terminal build --test --no-run-tests --copy-bins --local-bin-path dist
49+
50+
# Test (skip S3 tests for ARM64 builds)
51+
export SKIP_S3_TESTS=1
52+
stack --no-terminal build --test
53+
54+
# Package
55+
cd dist
56+
tar czvf taskrunner-linux-arm64.tar.gz taskrunner
57+
58+
# Regular x86_64 build
59+
- name: Checkout (x86_64)
60+
if: matrix.arch == 'x86_64'
61+
uses: actions/checkout@v2
62+
63+
- name: Start MinIO service container (x86_64)
64+
if: matrix.arch == 'x86_64'
1065
run: |
1166
docker run --rm -d --name minio -p 9000:9000 \
1267
-e MINIO_ROOT_USER=minioadmin \
@@ -16,43 +71,59 @@ jobs:
1671
sleep 3
1772
curl -s -D- http://localhost:9000
1873
19-
- uses: actions/checkout@v2
20-
- uses: haskell-actions/setup@v2
74+
- name: Setup Haskell (x86_64)
75+
if: matrix.arch == 'x86_64'
76+
uses: haskell-actions/setup@v2
2177
with:
2278
enable-stack: true
2379
stack-version: 'latest'
24-
- name: Cache
80+
81+
- name: Cache (x86_64)
82+
if: matrix.arch == 'x86_64'
2583
uses: actions/cache@v4
2684
env:
2785
cache-name: cache-stack
2886
with:
2987
path: ~/.stack
30-
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/*.cabal') }}-${{ hashFiles('**/stack.yaml') }}
88+
key: ${{ runner.os }}-${{ matrix.arch }}-build-${{ env.cache-name }}-${{ hashFiles('**/*.cabal') }}-${{ hashFiles('**/stack.yaml') }}
3189
restore-keys: |
32-
${{ runner.os }}-build-${{ env.cache-name }}-
33-
${{ runner.os }}-build-
34-
${{ runner.os }}-
35-
- name: Build dependencies
90+
${{ runner.os }}-${{ matrix.arch }}-build-${{ env.cache-name }}-
91+
${{ runner.os }}-${{ matrix.arch }}-build-
92+
${{ runner.os }}-${{ matrix.arch }}-
93+
94+
- name: Build dependencies (x86_64)
95+
if: matrix.arch == 'x86_64'
3696
run: |
3797
stack --no-terminal build --test --only-dependencies
38-
- name: Build
98+
99+
- name: Build (x86_64)
100+
if: matrix.arch == 'x86_64'
39101
run: |
40102
mkdir dist
41103
stack --no-terminal build --test --no-run-tests --copy-bins --local-bin-path dist
42-
- name: Test
104+
105+
- name: Test (x86_64)
106+
if: matrix.arch == 'x86_64'
43107
run: |
44108
export TASKRUNNER_TEST_S3_ENDPOINT=http://localhost:9000
45109
export TASKRUNNER_TEST_S3_ACCESS_KEY=minioadmin
46110
export TASKRUNNER_TEST_S3_SECRET_KEY=minioadmin
47111
48112
stack --no-terminal build --test
49-
- name: Zip
113+
114+
- name: Package (x86_64)
115+
if: matrix.arch == 'x86_64'
50116
run: |
51117
cd dist
52-
tar czvf taskrunner-linux.tar.gz taskrunner
118+
# Create architecture-specific archive
119+
tar czvf taskrunner-linux-x86_64.tar.gz taskrunner
120+
# Also create legacy name for compatibility
121+
cp taskrunner-linux-x86_64.tar.gz taskrunner-linux.tar.gz
122+
123+
# Upload artifacts for both architectures
53124
- name: Archive production artifacts
54125
uses: actions/upload-artifact@v4
55126
with:
56-
name: taskrunner-linux.tar.gz
127+
name: taskrunner-linux-${{ matrix.arch }}
57128
path: |
58-
dist/taskrunner-linux.tar.gz
129+
dist/*.tar.gz

.github/workflows/release.yml

Lines changed: 131 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,63 @@ permissions:
1111
jobs:
1212
build:
1313
runs-on: ubuntu-latest
14+
strategy:
15+
matrix:
16+
include:
17+
- arch: x86_64
18+
arch_alt: amd64
19+
- arch: arm64
20+
arch_alt: aarch64
1421
steps:
15-
- name: start service container
22+
# Setup QEMU for ARM64 emulation
23+
- name: Set up QEMU
24+
if: matrix.arch == 'arm64'
25+
uses: docker/setup-qemu-action@v3
26+
with:
27+
platforms: arm64
28+
29+
# Use run-on-arch for ARM64 builds
30+
- name: Checkout (ARM64)
31+
if: matrix.arch == 'arm64'
32+
uses: actions/checkout@v2
33+
34+
- name: Build on ARM64
35+
if: matrix.arch == 'arm64'
36+
uses: uraimo/run-on-arch-action@v2
37+
with:
38+
arch: aarch64
39+
distro: ubuntu22.04
40+
githubToken: ${{ github.token }}
41+
dockerRunArgs: |
42+
--volume "${PWD}:/workspace"
43+
install: |
44+
apt-get update -q -y
45+
apt-get install -q -y curl gcc g++ make libgmp-dev libtinfo-dev libncurses5-dev libc6-dev zlib1g-dev
46+
# Install Stack
47+
curl -sSL https://get.haskellstack.org/ | sh
48+
run: |
49+
cd /workspace
50+
# Build
51+
export PATH=/root/.local/bin:$PATH
52+
stack --no-terminal build --test --only-dependencies
53+
mkdir -p dist
54+
stack --no-terminal build --test --no-run-tests --copy-bins --local-bin-path dist
55+
56+
# Test (skip S3 tests for ARM64 builds)
57+
export SKIP_S3_TESTS=1
58+
stack --no-terminal build --test
59+
60+
# Package
61+
cd dist
62+
tar czvf taskrunner-linux-arm64.tar.gz taskrunner
63+
64+
# Regular x86_64 build
65+
- name: Checkout (x86_64)
66+
if: matrix.arch == 'x86_64'
67+
uses: actions/checkout@v2
68+
69+
- name: Start MinIO service container (x86_64)
70+
if: matrix.arch == 'x86_64'
1671
run: |
1772
docker run --rm -d --name minio -p 9000:9000 \
1873
-e MINIO_ROOT_USER=minioadmin \
@@ -22,40 +77,76 @@ jobs:
2277
sleep 3
2378
curl -s -D- http://localhost:9000
2479
25-
- uses: actions/checkout@v2
26-
- uses: haskell-actions/setup@v2
80+
- name: Setup Haskell (x86_64)
81+
if: matrix.arch == 'x86_64'
82+
uses: haskell-actions/setup@v2
2783
with:
2884
enable-stack: true
2985
stack-version: 'latest'
30-
- name: Cache
86+
87+
- name: Cache (x86_64)
88+
if: matrix.arch == 'x86_64'
3189
uses: actions/cache@v4
3290
env:
3391
cache-name: cache-stack
3492
with:
3593
path: ~/.stack
36-
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/*.cabal') }}-${{ hashFiles('**/stack.yaml') }}
94+
key: ${{ runner.os }}-${{ matrix.arch }}-build-${{ env.cache-name }}-${{ hashFiles('**/*.cabal') }}-${{ hashFiles('**/stack.yaml') }}
3795
restore-keys: |
38-
${{ runner.os }}-build-${{ env.cache-name }}-
39-
${{ runner.os }}-build-
40-
${{ runner.os }}-
41-
- name: Build dependencies
96+
${{ runner.os }}-${{ matrix.arch }}-build-${{ env.cache-name }}-
97+
${{ runner.os }}-${{ matrix.arch }}-build-
98+
${{ runner.os }}-${{ matrix.arch }}-
99+
100+
- name: Build dependencies (x86_64)
101+
if: matrix.arch == 'x86_64'
42102
run: |
43103
stack --no-terminal build --test --only-dependencies
44-
- name: Build
104+
105+
- name: Build (x86_64)
106+
if: matrix.arch == 'x86_64'
45107
run: |
46108
mkdir dist
47109
stack --no-terminal build --test --no-run-tests --copy-bins --local-bin-path dist
48-
- name: Test
110+
111+
- name: Test (x86_64)
112+
if: matrix.arch == 'x86_64'
49113
run: |
50114
export TASKRUNNER_TEST_S3_ENDPOINT=http://localhost:9000
51115
export TASKRUNNER_TEST_S3_ACCESS_KEY=minioadmin
52116
export TASKRUNNER_TEST_S3_SECRET_KEY=minioadmin
53117
54118
stack --no-terminal build --test
55-
- name: Zip
119+
120+
- name: Package (x86_64)
121+
if: matrix.arch == 'x86_64'
56122
run: |
57123
cd dist
58-
tar czvf taskrunner-linux.tar.gz taskrunner
124+
# Create architecture-specific archive
125+
tar czvf taskrunner-linux-x86_64.tar.gz taskrunner
126+
# Also create legacy name for compatibility
127+
cp taskrunner-linux-x86_64.tar.gz taskrunner-linux.tar.gz
128+
129+
# Upload artifacts for both architectures
130+
- name: Upload artifacts
131+
uses: actions/upload-artifact@v4
132+
with:
133+
name: taskrunner-linux-${{ matrix.arch }}
134+
path: |
135+
dist/*.tar.gz
136+
137+
release:
138+
needs: build
139+
runs-on: ubuntu-latest
140+
steps:
141+
- name: Download all artifacts
142+
uses: actions/download-artifact@v4
143+
with:
144+
path: artifacts
145+
merge-multiple: true
146+
147+
- name: Display structure of downloaded files
148+
run: ls -la artifacts/
149+
59150
- name: Create Release
60151
id: create_release
61152
uses: actions/create-release@v1
@@ -66,13 +157,36 @@ jobs:
66157
release_name: Release ${{ github.ref_name }}
67158
draft: false
68159
prerelease: false
69-
- name: Upload Release Asset
70-
id: upload-release-asset
160+
161+
# Upload x86_64 with legacy name for compatibility
162+
- name: Upload Release Asset (Linux - Legacy Name)
71163
uses: actions/upload-release-asset@v1
72164
env:
73165
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
74166
with:
75-
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
76-
asset_path: ./dist/taskrunner-linux.tar.gz
167+
upload_url: ${{ steps.create_release.outputs.upload_url }}
168+
asset_path: ./artifacts/taskrunner-linux.tar.gz
77169
asset_name: taskrunner-linux.tar.gz
78170
asset_content_type: application/x-tar
171+
172+
# Upload x86_64 with explicit architecture
173+
- name: Upload Release Asset (Linux x86_64)
174+
uses: actions/upload-release-asset@v1
175+
env:
176+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
177+
with:
178+
upload_url: ${{ steps.create_release.outputs.upload_url }}
179+
asset_path: ./artifacts/taskrunner-linux-x86_64.tar.gz
180+
asset_name: taskrunner-linux-x86_64.tar.gz
181+
asset_content_type: application/x-tar
182+
183+
# Upload ARM64
184+
- name: Upload Release Asset (Linux ARM64)
185+
uses: actions/upload-release-asset@v1
186+
env:
187+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
188+
with:
189+
upload_url: ${{ steps.create_release.outputs.upload_url }}
190+
asset_path: ./artifacts/taskrunner-linux-arm64.tar.gz
191+
asset_name: taskrunner-linux-arm64.tar.gz
192+
asset_content_type: application/x-tar

0 commit comments

Comments
 (0)