Commit 8d08f343c9

8d08f343c930f556c6ab016be9d00b23f1e516e3

parent: 47bfe56e72

Verified · cmc

cmc <hello@cleberg.net> · 2026-07-15 07:55 UTC

ci: publish multi-arch image to GHCR on release tags

Build and push linux/amd64 + linux/arm64 images to
ghcr.io/zerolabsco/skunky-art on every v* tag, with a signed provenance
attestation. The Dockerfile cross-compiles from $BUILDPLATFORM, so the
arm64 image builds without QEMU emulation.

Default both compose examples to the published image and keep `build: .`
commented out for building from a checkout, and extend dependabot to the
github-actions and docker ecosystems.

Layout: unified · split

.github/dependabot.yml +10
@@ -9,3 +9,13 @@ updates:
99 directory: "/" # Location of package manifests
1010 schedule:
1111 interval: "weekly"
12
13 - package-ecosystem: "github-actions"
14 directory: "/"
15 schedule:
16 interval: "weekly"
17
18 - package-ecosystem: "docker"
19 directory: "/"
20 schedule:
21 interval: "weekly"
.github/workflows/release.yml added +71
@@ -0,0 +1,71 @@
1name: Release image
2
3on:
4 push:
5 tags:
6 - "v*"
7 workflow_dispatch:
8
9env:
10 REGISTRY: ghcr.io
11 IMAGE_NAME: ${{ github.repository }}
12
13jobs:
14 publish:
15 runs-on: ubuntu-latest
16 permissions:
17 contents: read
18 packages: write
19 id-token: write
20 attestations: write
21 steps:
22 - name: Checkout
23 uses: actions/checkout@v4
24
25 # The Dockerfile cross-compiles with Go's GOOS/GOARCH from $BUILDPLATFORM,
26 # so no QEMU emulation is needed for the arm64 image.
27 - name: Set up Buildx
28 uses: docker/setup-buildx-action@v3
29
30 - name: Log in to ${{ env.REGISTRY }}
31 uses: docker/login-action@v3
32 with:
33 registry: ${{ env.REGISTRY }}
34 username: ${{ github.actor }}
35 password: ${{ secrets.GITHUB_TOKEN }}
36
37 - name: Derive tags and labels
38 id: meta
39 uses: docker/metadata-action@v5
40 with:
41 images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
42 # A semver tag v1.3.4 publishes 1.3.4, 1.3, 1 and latest.
43 # A manual run from a branch publishes only that branch name, so
44 # dispatching from main never moves the latest tag.
45 tags: |
46 type=semver,pattern={{version}}
47 type=semver,pattern={{major}}.{{minor}}
48 type=semver,pattern={{major}}
49 type=ref,event=branch
50 labels: |
51 org.opencontainers.image.title=SkunkyArt
52 org.opencontainers.image.description=An alternative frontend for DeviantArt that works entirely without JavaScript
53
54 - name: Build and push
55 id: build
56 uses: docker/build-push-action@v6
57 with:
58 context: .
59 platforms: linux/amd64,linux/arm64
60 push: true
61 tags: ${{ steps.meta.outputs.tags }}
62 labels: ${{ steps.meta.outputs.labels }}
63 cache-from: type=gha
64 cache-to: type=gha,mode=max
65
66 - name: Attest build provenance
67 uses: actions/attest-build-provenance@v2
68 with:
69 subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
70 subject-digest: ${{ steps.build.outputs.digest }}
71 push-to-registry: true
README.md +11
@@ -20,6 +20,17 @@ can also add the `-ldflags "-w -s"` argument (GCCGO has a different name for it
2020
2121`go build -tags embed -ldflags "-w -s"`
2222
23## Docker
24Prebuilt multi-arch images (`linux/amd64`, `linux/arm64`) are published to GHCR
25on every release tag:
26
27`docker pull ghcr.io/zerolabsco/skunky-art:latest`
28
29Each release is tagged `1.3.3`, `1.3`, `1` and `latest`; pin an exact version if
30you want reproducible upgrades. `compose.example.yaml` uses this image by
31default and keeps a commented-out `build: .` for building from a checkout.
32`compose.vpn_example.yml` does the same, plus an optional VPN egress sidecar.
33
2334## Setup
2435The sample config is in the `config.example.json` file. For custom config, use
2536the `--config` option.
compose.example.yaml +6 −1
@@ -2,7 +2,12 @@ services:
22 skunkyart:
33 container_name: skunkyart
44 restart: unless-stopped
5 build: .
5 # Published multi-arch image (linux/amd64, linux/arm64). Pin a release tag
6 # (e.g. :1.3.3) instead of :latest if you want reproducible upgrades.
7 image: ghcr.io/zerolabsco/skunky-art:latest
8 # To build from this checkout instead, comment out `image:` above and
9 # uncomment the line below, then `docker compose up -d --build`.
10 #build: .
611 ports:
712 - "127.0.0.1:3003:3003"
813 security_opt:
compose.vpn_example.yml +5 −1
@@ -48,7 +48,11 @@ services:
4848 skunkyart:
4949 container_name: skunkyart
5050 restart: unless-stopped
51 build: .
51 # Published multi-arch image; pin a release tag (e.g. :1.3.3) for
52 # reproducible upgrades. To build from this checkout instead, comment out
53 # `image:` and uncomment `build:`, then `docker compose up -d --build`.
54 image: ghcr.io/zerolabsco/skunky-art:latest
55 #build: .
5256 ports:
5357 - "127.0.0.1:3003:3003"
5458 security_opt: