1+ name : Build & Push - Release
2+ # Automatically builds/pushes multi-platform release images when a GitHub Release is published
3+
4+ on :
5+ release :
6+ types :
7+ - published
8+ workflow_dispatch :
9+
10+ jobs :
11+ # --------------------------------------------------------------------------------
12+ # JOB 1: Build Intel (amd64) on GitHub Runners
13+ # --------------------------------------------------------------------------------
14+ build-amd64 :
15+ runs-on : ubuntu-latest
16+ steps :
17+ - name : Checkout code
18+ uses : actions/checkout@v4
19+
20+ # --- 1. Calculate Variables ---
21+ - name : Set repo name to lowercase
22+ run : echo "LOWER_REPO_NAME=$(echo ${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
23+
24+ # --- 2. Logins ---
25+ - name : DockerHub Login
26+ uses : docker/login-action@v3
27+ with :
28+ username : ${{ secrets.DOCKERHUB_USERNAME }}
29+ password : ${{ secrets.DOCKERHUB_PA_TOKEN }}
30+
31+ - name : GitHub Container Registry Login
32+ uses : docker/login-action@v3
33+ with :
34+ registry : ghcr.io
35+ username : ${{ github.repository_owner }}
36+ password : ${{ secrets.GITHUB_TOKEN }}
37+
38+ # --- 3. Build & Push (Digest Only) ---
39+ - name : Set up Docker Buildx
40+ uses : docker/setup-buildx-action@v3
41+
42+ - name : Build and push by digest
43+ id : build
44+ uses : docker/build-push-action@v6
45+ with :
46+ provenance : false
47+ context : .
48+ platforms : linux/amd64
49+ # CACHE STRATEGY: Use GitHub Actions Cache (Ephemeral Runner)
50+ cache-from : type=gha
51+ cache-to : type=gha,mode=max
52+ outputs : |
53+ type=image,name=${{ secrets.DOCKERHUB_USERNAME }}/calibre-web-automated,push-by-digest=true,name-canonical=true,push=true
54+ type=image,name=ghcr.io/${{ github.repository_owner }}/${{ env.LOWER_REPO_NAME }},push-by-digest=true,name-canonical=true,push=true
55+ build-args : |
56+ BUILD_DATE=${{ github.event.repository.updated_at }}
57+ VERSION=${{ github.event.release.tag_name }}
58+
59+ # --- 4. Export Digest ---
60+ - name : Export digest
61+ run : |
62+ mkdir -p /tmp/digests
63+ digest="${{ steps.build.outputs.digest }}"
64+ touch "/tmp/digests/${digest#sha256:}"
65+
66+ - name : Upload digest
67+ uses : actions/upload-artifact@v4
68+ with :
69+ name : digests-amd64
70+ path : /tmp/digests/*
71+ if-no-files-found : error
72+ retention-days : 1
73+
74+ # --------------------------------------------------------------------------------
75+ # JOB 2: Build ARM (arm64 Only) on Oracle Runner
76+ # --------------------------------------------------------------------------------
77+ build-arm :
78+ # Use your self-hosted runner labels here
79+ runs-on : [self-hosted, linux, ARM64]
80+ steps :
81+ - name : Checkout code
82+ uses : actions/checkout@v4
83+
84+ # --- 1. Calculate Variables ---
85+ - name : Set repo name to lowercase
86+ run : echo "LOWER_REPO_NAME=$(echo ${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
87+
88+ # --- 2. Logins ---
89+ - name : DockerHub Login
90+ uses : docker/login-action@v3
91+ with :
92+ username : ${{ secrets.DOCKERHUB_USERNAME }}
93+ password : ${{ secrets.DOCKERHUB_PA_TOKEN }}
94+
95+ - name : GitHub Container Registry Login
96+ uses : docker/login-action@v3
97+ with :
98+ registry : ghcr.io
99+ username : ${{ github.repository_owner }}
100+ password : ${{ secrets.GITHUB_TOKEN }}
101+
102+ # --- 3. Build & Push (Digest Only) ---
103+ - uses : docker/setup-buildx-action@v3
104+
105+ - name : Build and push by digest
106+ id : build
107+ uses : docker/build-push-action@v6
108+ with :
109+ provenance : false
110+ context : .
111+ platforms : linux/arm64
112+ # CACHE STRATEGY: Use Local Disk Cache (Persistent Oracle Runner)
113+ cache-from : type=local,src=/tmp/.buildx-cache
114+ cache-to : type=local,dest=/tmp/.buildx-cache-new,mode=max
115+ outputs : |
116+ type=image,name=${{ secrets.DOCKERHUB_USERNAME }}/calibre-web-automated,push-by-digest=true,name-canonical=true,push=true
117+ type=image,name=ghcr.io/${{ github.repository_owner }}/${{ env.LOWER_REPO_NAME }},push-by-digest=true,name-canonical=true,push=true
118+ build-args : |
119+ BUILD_DATE=${{ github.event.repository.updated_at }}
120+ VERSION=${{ github.event.release.tag_name }}
121+
122+ # --- 4. Rotate Cache (Prevent Infinite Growth) ---
123+ - name : Move cache
124+ run : |
125+ rm -rf /tmp/.buildx-cache
126+ mv /tmp/.buildx-cache-new /tmp/.buildx-cache
127+
128+ # --- 5. Export Digest ---
129+ - name : Export digest
130+ run : |
131+ mkdir -p /tmp/digests
132+ digest="${{ steps.build.outputs.digest }}"
133+ touch "/tmp/digests/${digest#sha256:}"
134+
135+ - name : Upload digest
136+ uses : actions/upload-artifact@v4
137+ with :
138+ name : digests-arm
139+ path : /tmp/digests/*
140+ if-no-files-found : error
141+ retention-days : 1
142+
143+ # --- 6. Janitor: Clean up Docker Garbage ---
144+ - name : Prune Docker Garbage
145+ if : always() # Run even if build fails to keep disk clean
146+ run : |
147+ echo "Pruning dangling images..."
148+ docker image prune -f
149+ echo "Pruning old build cache (older than 1 week)..."
150+ docker builder prune -f --filter "until=168h"
151+
152+ # --------------------------------------------------------------------------------
153+ # JOB 3: Merge & Tag (Runs on GitHub)
154+ # --------------------------------------------------------------------------------
155+ merge :
156+ runs-on : ubuntu-latest
157+ needs : [build-amd64, build-arm]
158+ steps :
159+ - name : Checkout code
160+ uses : actions/checkout@v4
161+
162+ - name : Set repo name to lowercase
163+ run : echo "LOWER_REPO_NAME=$(echo ${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
164+
165+ # --- 1. Define Release Tags ---
166+ - name : Determine Docker Tags
167+ id : tag
168+ run : |
169+ # Use the Release Tag (e.g., v3.0.0)
170+ echo "RELEASE_TAG=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
171+
172+ # Fallback if workflow_dispatch was used (manual trigger)
173+ if [ -z "${{ github.event.release.tag_name }}" ]; then
174+ echo "RELEASE_TAG=manual-build" >> $GITHUB_ENV
175+ fi
176+
177+ # --- 2. Logins ---
178+ - name : DockerHub Login
179+ uses : docker/login-action@v3
180+ with :
181+ username : ${{ secrets.DOCKERHUB_USERNAME }}
182+ password : ${{ secrets.DOCKERHUB_PA_TOKEN }}
183+
184+ - name : GitHub Container Registry Login
185+ uses : docker/login-action@v3
186+ with :
187+ registry : ghcr.io
188+ username : ${{ github.repository_owner }}
189+ password : ${{ secrets.GITHUB_TOKEN }}
190+
191+ # --- 3. Merge Digests ---
192+ - name : Download digests
193+ uses : actions/download-artifact@v4
194+ with :
195+ path : /tmp/digests
196+ pattern : digests-*
197+ merge-multiple : true
198+
199+ - name : Set up Docker Buildx
200+ uses : docker/setup-buildx-action@v3
201+
202+ - name : Create manifest list and push
203+ working-directory : /tmp/digests
204+ run : |
205+ # 1. Push to DockerHub (Specific Tag + Latest)
206+ docker buildx imagetools create \
207+ -t ${{ secrets.DOCKERHUB_USERNAME }}/calibre-web-automated:${{ env.RELEASE_TAG }} \
208+ -t ${{ secrets.DOCKERHUB_USERNAME }}/calibre-web-automated:latest \
209+ $(printf '${{ secrets.DOCKERHUB_USERNAME }}/calibre-web-automated@sha256:%s ' *)
210+
211+ # 2. Push to GHCR (Specific Tag + Latest)
212+ docker buildx imagetools create \
213+ -t ghcr.io/${{ github.repository_owner }}/${{ env.LOWER_REPO_NAME }}:${{ env.RELEASE_TAG }} \
214+ -t ghcr.io/${{ github.repository_owner }}/${{ env.LOWER_REPO_NAME }}:latest \
215+ $(printf 'ghcr.io/${{ github.repository_owner }}/${{ env.LOWER_REPO_NAME }}@sha256:%s ' *)
0 commit comments