Skip to content

Commit 8939fc6

Browse files
ZD Studiosclaude
andcommitted
ci: publish the Docker image to GHCR from Actions
Pushing to ghcr.io from a laptop needs a PAT with write:packages, which nobody should have to create and store. Actions' automatic GITHUB_TOKEN already carries that permission, so the build runs on GitHub's hardware and pushes from there. Triggers on any v* tag and on manual dispatch. Frees ~25GB of preinstalled toolchains first — the image is ~11GB and a stock runner only has ~14GB free on /, so the build would otherwise die on disk space. amd64 only: emulating arm64 under QEMU for a nine-project install blows past the job time limit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent d10f29c commit 8939fc6

1 file changed

Lines changed: 82 additions & 0 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Publish Docker image to GHCR
2+
3+
# Builds the image on GitHub's runners and pushes it to ghcr.io.
4+
#
5+
# This exists because pushing from a laptop needs a Personal Access Token with
6+
# `write:packages`. Actions gets an automatic GITHUB_TOKEN that already has it —
7+
# see `permissions:` below — so nobody has to create or store a PAT.
8+
9+
on:
10+
push:
11+
tags: ["v*"] # every release tag publishes a matching image
12+
workflow_dispatch: # ...and you can run it by hand from the Actions tab
13+
14+
env:
15+
REGISTRY: ghcr.io
16+
IMAGE_NAME: ${{ github.repository }}
17+
18+
jobs:
19+
build-and-push:
20+
runs-on: ubuntu-latest
21+
permissions:
22+
contents: read
23+
packages: write # this is what replaces the PAT
24+
25+
steps:
26+
# The image is ~11GB. A stock runner has ~14GB free on /, which is not
27+
# enough, so reclaim the preinstalled toolchains we don't use first.
28+
- name: Free up disk space
29+
run: |
30+
echo "before:"; df -h / | tail -1
31+
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
32+
/usr/local/share/boost /usr/local/lib/node_modules \
33+
/opt/hostedtoolcache/CodeQL "$AGENT_TOOLSDIRECTORY" || true
34+
sudo apt-get clean
35+
docker image prune -af || true
36+
echo "after:"; df -h / | tail -1
37+
38+
- uses: actions/checkout@v4
39+
40+
- uses: docker/setup-buildx-action@v3
41+
42+
- name: Log in to GHCR
43+
uses: docker/login-action@v3
44+
with:
45+
registry: ${{ env.REGISTRY }}
46+
username: ${{ github.actor }}
47+
password: ${{ secrets.GITHUB_TOKEN }}
48+
49+
- name: Docker metadata
50+
id: meta
51+
uses: docker/metadata-action@v5
52+
with:
53+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
54+
tags: |
55+
type=ref,event=tag
56+
type=semver,pattern={{version}}
57+
type=semver,pattern={{major}}.{{minor}}
58+
type=raw,value=latest,enable={{is_default_branch}}
59+
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
60+
61+
- name: Build and push
62+
uses: docker/build-push-action@v6
63+
with:
64+
context: .
65+
push: true
66+
tags: ${{ steps.meta.outputs.tags }}
67+
labels: ${{ steps.meta.outputs.labels }}
68+
# linux/amd64 only: this image installs nine projects, and emulating
69+
# arm64 under QEMU pushes the build past the runner's time limit.
70+
platforms: linux/amd64
71+
provenance: false
72+
cache-from: type=gha
73+
cache-to: type=gha,mode=max
74+
75+
- name: Summary
76+
run: |
77+
echo "### Image published :whale:" >> $GITHUB_STEP_SUMMARY
78+
echo '```bash' >> $GITHUB_STEP_SUMMARY
79+
echo "docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_STEP_SUMMARY
80+
echo '```' >> $GITHUB_STEP_SUMMARY
81+
echo "Make it public: repo → Packages → aios → Package settings → Change visibility" \
82+
>> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)