Skip to content

Commit 9f92277

Browse files
authored
ci: migrate to native multi-arch builds and GHCR (#287)
- Replace QEMU-based multi-arch with native ARM64 runners (ubuntu-24.04-arm) - Add GitHub Container Registry (ghcr.io) as primary registry - Keep Docker Hub push (deprecated, will be removed later) - Use digest-based builds with manifest merge (nsenter pattern) - Set releases as stable (prerelease: false) - Remove unused paths-ignore and branch triggers from release workflow
1 parent 291b33f commit 9f92277

File tree

1 file changed

+150
-88
lines changed

1 file changed

+150
-88
lines changed

.github/workflows/release.yaml

Lines changed: 150 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,12 @@ name: Release
22

33
on:
44
push:
5-
branches:
6-
- master
7-
- main
85
tags:
96
- '[0-9]+.[0-9]+.[0-9]+'
10-
paths-ignore:
11-
- 'docs/**'
12-
- 'deploy/**'
13-
- 'examples/**'
14-
- 'test/**'
15-
- '*.md'
16-
- '*.yaml'
177

188
jobs:
9+
# Build and test Go binaries
1910
build:
20-
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
2111
runs-on: ubuntu-latest
2212
permissions:
2313
contents: read
@@ -26,38 +16,31 @@ jobs:
2616
uses: actions/checkout@v4
2717
with:
2818
fetch-depth: 0
19+
2920
- name: Set Up Go
3021
uses: actions/setup-go@v5
3122
with:
3223
go-version: '1.26'
3324
cache: true
3425
cache-dependency-path: go.sum
26+
3527
- name: Run Lint and Test Coverage
36-
shell: bash
3728
run: |
3829
make lint
3930
make test-coverage
31+
4032
- name: Upload Coverage to Codecov
4133
uses: codecov/codecov-action@v5
4234
with:
4335
files: ".cover/coverage.xml"
4436
token: ${{ secrets.CODECOV_TOKEN }}
37+
4538
- name: Build Release Binaries
4639
env:
4740
GOPROXY: https://proxy.golang.org
4841
CGO_ENABLED: 0
49-
run: |
50-
make release
51-
- name: Debug Directory Contents
52-
run: |
53-
echo "Current working directory:"
54-
pwd
55-
echo "Listing contents of .bin/ recursively:"
56-
find .bin/ -type f -ls || echo "No files found in .bin/"
57-
echo "Directory structure:"
58-
ls -laR .bin/ || echo "Directory .bin/ is empty or does not exist"
59-
echo "Testing glob expansion:"
60-
ls .bin/* || echo "Glob .bin/* found no files"
42+
run: make release
43+
6144
- name: Upload Build Artifacts
6245
uses: actions/upload-artifact@v4
6346
with:
@@ -67,10 +50,148 @@ jobs:
6750
compression-level: 6
6851
include-hidden-files: true
6952

53+
# Build Docker images natively per architecture (no QEMU)
54+
docker-build:
55+
strategy:
56+
matrix:
57+
include:
58+
- platform: linux/amd64
59+
runner: ubuntu-24.04
60+
- platform: linux/arm64
61+
runner: ubuntu-24.04-arm
62+
runs-on: ${{ matrix.runner }}
63+
permissions:
64+
contents: read
65+
packages: write
66+
steps:
67+
- name: Checkout Code
68+
uses: actions/checkout@v4
69+
with:
70+
fetch-depth: 0
71+
72+
- name: Get Short SHA
73+
id: short_sha
74+
run: echo "sha=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
75+
76+
- name: Set up Docker Buildx
77+
uses: docker/setup-buildx-action@v3
78+
79+
- name: Login to GitHub Container Registry
80+
uses: docker/login-action@v3
81+
with:
82+
registry: ghcr.io
83+
username: ${{ github.actor }}
84+
password: ${{ secrets.GITHUB_TOKEN }}
85+
86+
- name: Login to Docker Hub
87+
uses: docker/login-action@v3
88+
with:
89+
username: ${{ secrets.DOCKER_ACCOUNT }}
90+
password: ${{ secrets.DOCKER_TOKEN }}
91+
92+
- name: Build and push by digest (GHCR)
93+
id: build-ghcr
94+
uses: docker/build-push-action@v6
95+
with:
96+
file: docker/Dockerfile
97+
context: .
98+
build-args: |
99+
BRANCH=${{ github.ref_name }}
100+
COMMIT=${{ steps.short_sha.outputs.sha }}
101+
SKIP_TESTS=true
102+
platforms: ${{ matrix.platform }}
103+
outputs: type=image,name=ghcr.io/${{ github.repository }},push-by-digest=true,name-canonical=true,push=true
104+
cache-from: type=gha,scope=${{ matrix.platform }}
105+
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}
106+
provenance: false
107+
108+
- name: Build and push by digest (Docker Hub)
109+
id: build-hub
110+
uses: docker/build-push-action@v6
111+
with:
112+
file: docker/Dockerfile
113+
context: .
114+
build-args: |
115+
BRANCH=${{ github.ref_name }}
116+
COMMIT=${{ steps.short_sha.outputs.sha }}
117+
SKIP_TESTS=true
118+
platforms: ${{ matrix.platform }}
119+
outputs: type=image,name=${{ secrets.DOCKER_ORG }}/pumba,push-by-digest=true,name-canonical=true,push=true
120+
cache-from: type=gha,scope=${{ matrix.platform }}
121+
provenance: false
122+
123+
- name: Export digests
124+
run: |
125+
mkdir -p /tmp/digests/ghcr /tmp/digests/hub
126+
ghcr_digest="${{ steps.build-ghcr.outputs.digest }}"
127+
hub_digest="${{ steps.build-hub.outputs.digest }}"
128+
touch "/tmp/digests/ghcr/${ghcr_digest#sha256:}"
129+
touch "/tmp/digests/hub/${hub_digest#sha256:}"
130+
131+
- name: Upload digests
132+
uses: actions/upload-artifact@v4
133+
with:
134+
name: digests-${{ matrix.runner }}
135+
path: /tmp/digests
136+
if-no-files-found: error
137+
retention-days: 1
138+
139+
# Merge multi-arch manifests
140+
docker-merge:
141+
runs-on: ubuntu-latest
142+
needs: docker-build
143+
permissions:
144+
contents: read
145+
packages: write
146+
steps:
147+
- name: Download digests
148+
uses: actions/download-artifact@v4
149+
with:
150+
path: /tmp/digests
151+
pattern: digests-*
152+
merge-multiple: true
153+
154+
- name: Set up Docker Buildx
155+
uses: docker/setup-buildx-action@v3
156+
157+
- name: Login to GitHub Container Registry
158+
uses: docker/login-action@v3
159+
with:
160+
registry: ghcr.io
161+
username: ${{ github.actor }}
162+
password: ${{ secrets.GITHUB_TOKEN }}
163+
164+
- name: Login to Docker Hub
165+
uses: docker/login-action@v3
166+
with:
167+
username: ${{ secrets.DOCKER_ACCOUNT }}
168+
password: ${{ secrets.DOCKER_TOKEN }}
169+
170+
- name: Create and push manifest (GHCR)
171+
working-directory: /tmp/digests/ghcr
172+
run: |
173+
printf 'ghcr.io/${{ github.repository }}@sha256:%s\n' * > /tmp/ghcr-sources.txt
174+
docker buildx imagetools create \
175+
-t "ghcr.io/${{ github.repository }}:${{ github.ref_name }}" \
176+
-t "ghcr.io/${{ github.repository }}:latest" \
177+
$(cat /tmp/ghcr-sources.txt)
178+
179+
- name: Create and push manifest (Docker Hub)
180+
working-directory: /tmp/digests/hub
181+
run: |
182+
printf '${{ secrets.DOCKER_ORG }}/pumba@sha256:%s\n' * > /tmp/hub-sources.txt
183+
docker buildx imagetools create \
184+
-t "${{ secrets.DOCKER_ORG }}/pumba:${{ github.ref_name }}" \
185+
-t "${{ secrets.DOCKER_ORG }}/pumba:latest" \
186+
$(cat /tmp/hub-sources.txt)
187+
188+
- name: Inspect GHCR image
189+
run: docker buildx imagetools inspect "ghcr.io/${{ github.repository }}:${{ github.ref_name }}"
190+
191+
# Create GitHub Release
70192
create-release:
71-
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
72193
name: Create GitHub Release
73-
needs: [ build ]
194+
needs: [build, docker-merge]
74195
runs-on: ubuntu-latest
75196
permissions:
76197
contents: write
@@ -79,81 +200,22 @@ jobs:
79200
uses: actions/checkout@v4
80201
with:
81202
fetch-depth: 0
203+
82204
- name: Download Artifacts
83205
uses: actions/download-artifact@v4
84206
with:
85207
name: pumba-binaries
86208
path: ${{ github.workspace }}/.bin/
209+
87210
- name: Create GitHub Release
88211
uses: ncipollo/release-action@v1
89212
with:
90213
token: ${{ secrets.GITHUB_TOKEN }}
91214
tag: ${{ github.ref_name }}
92215
name: Release ${{ github.ref_name }}
93-
body: "Automated release for ${{ github.ref_name }}"
94216
generateReleaseNotes: true
95-
prerelease: true
217+
prerelease: false
96218
artifacts: ${{ github.workspace }}/.bin/*
97219
allowUpdates: false
98220
commit: ${{ github.sha }}
99221
draft: false
100-
removeArtifacts: false
101-
replacesArtifacts: true
102-
103-
push-docker:
104-
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
105-
name: Push Docker Image
106-
runs-on: ubuntu-latest
107-
permissions:
108-
contents: read
109-
packages: write
110-
steps:
111-
- name: Checkout Code
112-
uses: actions/checkout@v4
113-
with:
114-
fetch-depth: 0
115-
- name: Get Tag Name
116-
id: get_tag
117-
run: echo "git_tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
118-
- name: Get Short SHA
119-
id: short_sha
120-
run: echo "sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
121-
- name: Set Up Docker Buildx
122-
uses: docker/setup-buildx-action@v3
123-
with:
124-
driver: docker-container
125-
platforms: linux/amd64,linux/arm64
126-
- name: Set Up QEMU
127-
uses: docker/setup-qemu-action@v3
128-
with:
129-
platforms: linux/amd64,linux/arm64
130-
- name: Login to Docker Registry
131-
uses: docker/login-action@v3
132-
with:
133-
username: ${{ secrets.DOCKER_ACCOUNT }}
134-
password: ${{ secrets.DOCKER_TOKEN }}
135-
- name: Build Metadata
136-
id: meta
137-
uses: docker/metadata-action@v5
138-
with:
139-
images: ${{ secrets.DOCKER_ORG }}/pumba
140-
tags: |
141-
type=semver,pattern={{version}}
142-
type=raw,value=latest
143-
- name: Build and Push Docker Image
144-
uses: docker/build-push-action@v6
145-
with:
146-
file: docker/Dockerfile
147-
context: .
148-
build-args: |
149-
BRANCH=${{ github.ref_name }}
150-
COMMIT=${{ steps.short_sha.outputs.sha }}
151-
SKIP_TESTS=true
152-
platforms: linux/amd64,linux/arm64
153-
push: true
154-
tags: ${{ steps.meta.outputs.tags }}
155-
labels: ${{ steps.meta.outputs.labels }}
156-
cache-from: type=gha
157-
cache-to: type=gha,mode=max
158-
provenance: true
159-
sbom: true

0 commit comments

Comments
 (0)