Merge ci/reuse-images: tags and docs-only merges reuse the published images
Release / Namespace das imagens (push) Successful in 1s
Release / Plano (reaproveitar as imagens?) (push) Successful in 4s
Release / ci (push) Skipped
Release / Build auth (linux/amd64) (push) Skipped
Release / Build migrations (linux/amd64) (push) Skipped
Release / Build protocols (linux/amd64) (push) Skipped
Release / Build rspamd (linux/amd64) (push) Skipped
Release / Build storage (linux/amd64) (push) Skipped
Release / Build webmail (linux/amd64) (push) Skipped
Release / Build auth (linux/arm64) (push) Skipped
Release / Build migrations (linux/arm64) (push) Skipped
Release / Build protocols (linux/arm64) (push) Skipped
Release / Build rspamd (linux/arm64) (push) Skipped
Release / Build storage (linux/arm64) (push) Skipped
Release / Build webmail (linux/arm64) (push) Skipped
Release / Publica auth (push) Successful in 20s
Release / Publica migrations (push) Successful in 20s
Release / Publica rspamd (push) Successful in 21s
Release / Publica protocols (push) Successful in 22s
Release / Publica webmail (push) Successful in 20s
Release / Publica storage (push) Successful in 21s
Release / Cria a release no Gitea (push) Skipped

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas RayanandClaude Sonnet 5.5 committed 2026-10-30 12:20:51 -03:00
commit 1bcbe4d774
4 files changed
+79 -14

No files matched your search

+55 -7
View File
@@ -18,8 +18,46 @@ env:
REGISTRY: git.lucasrguerra.dev.br
jobs:
# Nothing is published unless the full suite passes first.
# The images are built from services/, migrations/ and config/ and nothing
# else, so those three trees identify them. When an image for the same trees
# is already in the registry (a docs-only merge, a workflow change, or a tag on
# a commit that was just released), there is nothing to build: the new tags
# are pointed at the existing manifest. This is what keeps tagging a release
# from compiling the webmail a second time.
plan:
name: Plano (reaproveitar as imagens?)
runs-on: ubuntu-latest
outputs:
inputs: ${{ steps.plan.outputs.inputs }}
reuse: ${{ steps.plan.outputs.reuse }}
steps:
- uses: actions/checkout@v7
- id: plan
env:
REGISTRY: ${{ env.REGISTRY }}
REPO: ${{ gitea.repository }}
run: |
inputs=$(git rev-parse HEAD:services HEAD:migrations HEAD:config | sha256sum | cut -c1-16)
ns="${REPO,,}"
reuse=true
for s in protocols auth storage webmail migrations rspamd; do
token=$(curl -fsS "https://$REGISTRY/v2/token?service=container_registry&scope=repository:$ns/$s:pull" | jq -r .token)
code=$(curl -s -o /dev/null -w '%{http_code}' -I \
-H "Authorization: Bearer $token" \
-H 'Accept: application/vnd.oci.image.index.v1+json,application/vnd.docker.distribution.manifest.list.v2+json' \
"https://$REGISTRY/v2/$ns/$s/manifests/inputs-$inputs")
echo "$s: inputs-$inputs -> HTTP $code"
[ "$code" = 200 ] || reuse=false
done
echo "inputs=$inputs" >> "$GITHUB_OUTPUT"
echo "reuse=$reuse" >> "$GITHUB_OUTPUT"
echo "reuse the published images: $reuse"
# Nothing is published unless the full suite passes first. Skipped when the
# images are reused: the same trees already went through it.
ci:
needs: plan
if: ${{ needs.plan.outputs.reuse != 'true' }}
uses: ./.gitea/workflows/ci.yml
# Registry paths must be lowercase, and this repository is "lucasrguerra/LambdaMail".
@@ -42,7 +80,8 @@ jobs:
# magnitude slower.
build:
name: Build ${{ matrix.service }} (${{ matrix.platform }})
needs: [ci, prepare]
needs: [plan, ci, prepare]
if: ${{ needs.plan.outputs.reuse != 'true' }}
runs-on: ${{ matrix.runner }}
permissions:
contents: read
@@ -104,7 +143,9 @@ jobs:
publish:
name: Publica ${{ matrix.service }}
needs: [build, prepare]
needs: [plan, build, prepare]
# build is skipped, not successful, when the images are reused.
if: ${{ !cancelled() && needs.plan.result == 'success' && needs.prepare.result == 'success' && (needs.build.result == 'success' || needs.plan.outputs.reuse == 'true') }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -141,13 +182,20 @@ jobs:
type=sha,format=long
# Joins both architectures under one manifest list, so `docker pull`
# resolves to the right one automatically.
- name: Cria o manifesto multi-arquitetura
# resolves to the right one automatically. The inputs-<hash> tag is what
# lets a later run recognise these images and skip the build.
- name: Aplica as tags
run: |
image='${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}'
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}') \
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}')
inputs='${{ needs.plan.outputs.inputs }}'
if [ '${{ needs.plan.outputs.reuse }}' = true ]; then
# Same manifest under new names: no layer is read or written.
docker buildx imagetools create $tags "$image:inputs-$inputs"
else
docker buildx imagetools create $tags -t "$image:inputs-$inputs" \
"$image:build-${{ gitea.sha }}-amd64" "$image:build-${{ gitea.sha }}-arm64"
fi
- name: Confere o resultado
run: |
+3 -1
View File
@@ -87,7 +87,9 @@ remain are listed in the README under
`git.lucasrguerra.dev.br/lucasrguerra/lambdamail/<service>` and the `v*` tag
creates a release with notes. See [docs/RELEASING.md](docs/RELEASING.md).
- CI caches npm, Go modules, the embedded Postgres, Trivy's database and image
layers.
layers. Release recognises images it already published for the same sources
(`inputs-<hash>` tag), so a documentation change or a version tag never
rebuilds them.
- One `.env.example` for development and production, and `scripts/init-env.sh`
to create `.env` with random secrets (`make env`). It replaces
`.env.production.example`.
+3 -1
View File
@@ -87,7 +87,9 @@ Gitea. O que ainda falta está no README, em
`git.lucasrguerra.dev.br/lucasrguerra/lambdamail/<serviço>`, e a tag `v*` cria
uma release com notas. Veja [docs/RELEASING.md](docs/RELEASING.md).
- O CI guarda em cache o npm, os módulos Go, o Postgres embutido, o banco do
Trivy e as camadas das imagens.
Trivy e as camadas das imagens. O Release reconhece imagens que já publicou
para os mesmos fontes (tag `inputs-<hash>`), então uma mudança de documentação
ou uma tag de versão nunca as reconstrói.
- Um único `.env.example` para desenvolvimento e produção, e o
`scripts/init-env.sh` para criar o `.env` com segredos aleatórios
(`make env`). Ele substitui o `.env.production.example`.
+18 -5
View File
@@ -11,10 +11,22 @@ the Oracle server.
| Workflow | Runs on | Does |
| :--- | :--- | :--- |
| `ci.yml` | every push and pull request | language lint, Go and TypeScript suites against a real Postgres, webmail tests, a Trivy scan of the repository and of each image, and the whole stack brought up with compose |
| `release.yml` | a push to `main`, a `v*` tag, or by hand | runs `ci.yml` again, builds the six images for `linux/amd64` and `linux/arm64`, publishes them, and on a tag creates the release |
| `release.yml` | a push to `main`, a `v*` tag, or by hand | builds the six images for `linux/amd64` and `linux/arm64` after `ci.yml` passes, publishes them, and on a tag creates the release |
Nothing is published unless the full suite passes first.
### Images are reused, not rebuilt
The images are built from `services/`, `migrations/` and `config/` and nothing
else. `release.yml` hashes those three trees (the `inputs-<hash>` tag) and asks
the registry whether images for that hash already exist. If they do, it skips
the CI run and the build and only points the new tags (`latest`, `sha-<commit>`,
the version) at the existing manifests, which takes about a minute.
So these never recompile anything: a documentation or workflow change merged
to `main`, and a version tag pushed on a commit whose images were just
published. A change under the three trees rebuilds everything, as it should.
Images go to the Gitea registry, one package per service:
```
@@ -39,10 +51,11 @@ logging in.
git push gitea v1.2.3
```
The tag triggers `release.yml` once more. It republishes the images under
`1.2.3`, `1.2` and `1` (layers are cached, so this is quick) and creates the
entry under **Releases** with the image list and the commit log since the
previous tag. A tag with a hyphen (`v1.3.0-rc.1`) is marked as a pre-release.
The tag triggers `release.yml` once more. Because the commit was already
released from `main`, the images are reused: it adds the tags `1.2.3`, `1.2` and
`1` to them without building, and creates the entry under **Releases** with the
image list and the commit log since the previous tag. Tagging a commit whose
`main` run has not finished (or never ran) builds it from scratch. A tag with a hyphen (`v1.3.0-rc.1`) is marked as a pre-release.
Versions follow [Semantic Versioning](https://semver.org/): a change to a
migration, a required environment variable, or a published port is at least a