neiam
/diogramos
diogramos
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
ci: publish the image to the forge's own registry too
fd1515b · Gabriel Morell · 2026-09-16 03:03
Message
{commit_body(@commit)}
Files changed
modified
.github/workflows/ci.yml
+56
−4
@@ -77,6 +77,54 @@ jobs:
| 77 | 77 | - uses: actions/checkout@v4 |
| 78 | 78 | - uses: docker/setup-buildx-action@v3 |
| 79 | 79 | |
| 80 | + # The forge's own registry, when this is running on one. Unlike the | |
| 81 | + # three public registries below it needs no stored credentials: the | |
| 82 | + # per-job token is already authorized to push to this repository's | |
| 83 | + # own image path and nowhere else. | |
| 84 | + # | |
| 85 | + # `vars.CI_REGISTRY` is what says whether there is one -- on a forge | |
| 86 | + # that doesn't set it, or on GitHub, every forge step below drops | |
| 87 | + # out and the public registries are unaffected. | |
| 88 | + - name: Resolve the forge registry | |
| 89 | + id: forge | |
| 90 | + env: | |
| 91 | + CI_REGISTRY: ${{ vars.CI_REGISTRY }} | |
| 92 | + run: | | |
| 93 | + set -euo pipefail | |
| 94 | + | |
| 95 | + images=( | |
| 96 | + "ghcr.io/$GITHUB_REPOSITORY" | |
| 97 | + "docker.io/neiam/diogramos" | |
| 98 | + "quay.io/neiam/diogramos" | |
| 99 | + ) | |
| 100 | + | |
| 101 | + if [ -n "${CI_REGISTRY:-}" ]; then | |
| 102 | + forge_image="$CI_REGISTRY/$GITHUB_REPOSITORY" | |
| 103 | + echo "publishing to the forge registry at $forge_image" | |
| 104 | + | |
| 105 | + images+=("$forge_image") | |
| 106 | + echo "registry=$CI_REGISTRY" >> "$GITHUB_OUTPUT" | |
| 107 | + echo "image=$forge_image" >> "$GITHUB_OUTPUT" | |
| 108 | + else | |
| 109 | + echo "No CI_REGISTRY variable set -- skipping the forge registry." | |
| 110 | + fi | |
| 111 | + | |
| 112 | + { | |
| 113 | + echo "images<<IMAGES_EOF" | |
| 114 | + printf '%s\n' "${images[@]}" | |
| 115 | + echo "IMAGES_EOF" | |
| 116 | + } >> "$GITHUB_OUTPUT" | |
| 117 | + | |
| 118 | + # The token endpoint ignores the username but login-action requires | |
| 119 | + # it to be non-empty. | |
| 120 | + - name: Log in to the forge registry | |
| 121 | + if: steps.forge.outputs.registry != '' && github.event_name != 'pull_request' | |
| 122 | + uses: docker/login-action@v3 | |
| 123 | + with: | |
| 124 | + registry: ${{ steps.forge.outputs.registry }} | |
| 125 | + username: gitgud-actions | |
| 126 | + password: ${{ github.token }} | |
| 127 | + | |
| 80 | 128 | # GHCR uses the built-in token. Docker Hub and Quay creds come from |
| 81 | 129 | # org-wide secrets (DOCKERHUB_USER/DOCKERHUB_TOKEN, QUAY_USERNAME/QUAY_TOKEN). |
| 82 | 130 | - name: Log in to GHCR |
@@ -106,10 +154,7 @@ jobs:
| 106 | 154 | - id: meta |
| 107 | 155 | uses: docker/metadata-action@v5 |
| 108 | 156 | with: |
| 109 | − images: | | |
| 110 | − ghcr.io/${{ github.repository }} | |
| 111 | − docker.io/neiam/diogramos | |
| 112 | − quay.io/neiam/diogramos | |
| 157 | + images: ${{ steps.forge.outputs.images }} | |
| 113 | 158 | tags: | |
| 114 | 159 | type=ref,event=branch |
| 115 | 160 | type=ref,event=pr |
@@ -118,6 +163,11 @@ jobs:
| 118 | 163 | type=sha |
| 119 | 164 | type=raw,value=latest,enable={{is_default_branch}} |
| 120 | 165 | |
| 166 | + # The layer cache lives in the forge registry alongside the image. | |
| 167 | + # `type=gha` is not an option here: the forge's RunnerJwt carries no | |
| 168 | + # `ac` claim, so the Actions cache service rejects it. Writing the | |
| 169 | + # cache is gated on a real push -- a pull request's token can read | |
| 170 | + # that path but not write it. | |
| 121 | 171 | - uses: docker/build-push-action@v6 |
| 122 | 172 | with: |
| 123 | 173 | context: . |
@@ -125,3 +175,5 @@ jobs:
| 125 | 175 | push: ${{ github.event_name != 'pull_request' }} |
| 126 | 176 | tags: ${{ steps.meta.outputs.tags }} |
| 127 | 177 | labels: ${{ steps.meta.outputs.labels }} |
| 178 | + cache-from: ${{ steps.forge.outputs.image != '' && format('type=registry,ref={0}:buildcache', steps.forge.outputs.image) || '' }} | |
| 179 | + cache-to: ${{ steps.forge.outputs.image != '' && github.event_name != 'pull_request' && format('type=registry,ref={0}:buildcache,mode=max', steps.forge.outputs.image) || '' }} |
modified
README.md
+9
−0
@@ -45,6 +45,8 @@ mix run -e 'Diogramos.Release.init("you@example.com", "a strong password")'
| 45 | 45 | |
| 46 | 46 | CI publishes a multi-registry image on every push to `master`: |
| 47 | 47 | |
| 48 | +- the forge's own registry, `$CI_REGISTRY/neiam/diogramos`, when the repository | |
| 49 | + is hosted on one that sets `CI_REGISTRY` | |
| 48 | 50 | - `ghcr.io/neiam/diogramos` |
| 49 | 51 | - `docker.io/neiam/diogramos` |
| 50 | 52 | - `quay.io/neiam/diogramos` |
@@ -52,6 +54,13 @@ CI publishes a multi-registry image on every push to `master`:
| 52 | 54 | Tags: `latest` (default branch), `vX.Y.Z` + `X.Y` (git tags), the branch name, |
| 53 | 55 | and the commit SHA. |
| 54 | 56 | |
| 57 | +The forge registry is the one that needs no setup: the per-job `github.token` | |
| 58 | +is already authorized to push to that repository's own image path and nowhere | |
| 59 | +else, so there is no secret to create. The three public registries need | |
| 60 | +`GHCR_TOKEN`, `DOCKERHUB_USER`/`DOCKERHUB_TOKEN` and | |
| 61 | +`QUAY_USERNAME`/`QUAY_TOKEN`; each login is skipped on pull requests, and a | |
| 62 | +missing `CI_REGISTRY` simply drops the forge registry from the list. | |
| 63 | + | |
| 55 | 64 | ```sh |
| 56 | 65 | docker pull ghcr.io/neiam/diogramos:latest |
| 57 | 66 |
Parents: e7d9f29