Compare commits

...
2 Commits
Author SHA1 Message Date
Lucas RayanandClaude Sonnet 5.5 1aac8be531 ci: create a Gitea release when a v* tag is pushed
CI / Lint de idioma (R9) (push) Successful in 4s
CI / TypeScript (auth) (push) Successful in 3m4s
CI / TypeScript (storage) (push) Successful in 14s
CI / Go (protocols) (push) Successful in 4m21s
CI / Trivy (dependências, segredos e Dockerfiles) (push) Successful in 11s
CI / Imagem (auth) (push) Successful in 10s
CI / Testes (webmail) (push) Successful in 52s
CI / Imagem (migrations) (push) Successful in 5s
CI / Imagem (protocols) (push) Successful in 6s
CI / Imagem (rspamd) (push) Successful in 5s
CI / Imagem (storage) (push) Successful in 8s
CI / Imagem (webmail) (push) Successful in 8s
CI / Stack completa (push) Failing after 4s
The Release workflow only ever published container images; there was no entry
under Releases. The new job runs after every image is published and writes the
image list and the commit log since the previous tag.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 11:22:08 -03:00
Lucas RayanandClaude Sonnet 5.5 5d4e7147ce ci: cache what is rebuilt on every run
npm and Go module caches, the embedded Postgres binaries, Trivy's database, and
the daemon's own layer cache for image builds. The webmail Next build is no
longer run a second time outside the Dockerfile.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 10:07:21 -03:00
2 changed files with 82 additions and 18 deletions

No files matched your search

+42 -18
View File
@@ -70,6 +70,17 @@ jobs:
docker rm "$cid" >/dev/null
exit "$status"
- run: go vet ./...
# Module and build caches live under the unprivileged user's home, which
# setup-go's cache does not cover, and the embedded Postgres binaries are
# otherwise downloaded again by every test that starts one.
- uses: actions/cache@v4
with:
path: |
/home/tester/go/pkg/mod
/home/tester/.cache/go-build
/home/tester/.embedded-postgres-go
key: go-tester-${{ runner.arch }}-${{ hashFiles('services/protocols/go.sum') }}
restore-keys: go-tester-${{ runner.arch }}-
# The end-to-end suites start an embedded Postgres, and initdb refuses to
# run as root, which is what a job container is. Run the tests as a
# throwaway unprivileged user (GitHub's hosted runners already are one).
@@ -78,7 +89,7 @@ jobs:
TEST_DATABASE_URL: postgres://lambdamail_test:lambdamail_test@localhost:5432/lambdamail_test?sslmode=disable
run: |
id tester >/dev/null 2>&1 || useradd -m -u 1001 tester
chown -R tester:tester "$GITHUB_WORKSPACE"
chown -R tester:tester "$GITHUB_WORKSPACE" /home/tester
runuser -u tester -- env "HOME=/home/tester" "PATH=$PATH" \
"TEST_DATABASE_URL=$TEST_DATABASE_URL" go test ./... -v
@@ -105,7 +116,10 @@ jobs:
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with: { node-version: "20" }
with:
node-version: "20"
cache: npm
cache-dependency-path: services/auth/package-lock.json
# The auth suite asserts against real rows: password verification,
# lockout, TOTP replay and recovery-code consumption are all decided in
# the database, so a mock would prove nothing.
@@ -139,13 +153,16 @@ jobs:
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with: { node-version: "20" }
with:
node-version: "20"
cache: npm
cache-dependency-path: services/storage/package-lock.json
- run: npm install
- run: npm run lint
- run: npm test
webmail-build:
name: Build (webmail)
name: Testes (webmail)
runs-on: ubuntu-latest
defaults:
run:
@@ -153,11 +170,15 @@ jobs:
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with: { node-version: "20" }
with:
node-version: "20"
cache: npm
cache-dependency-path: services/webmail/package-lock.json
- run: npm install
- run: npm run lint
- run: npm test
- run: npm run build
# No `npm run build` here: the webmail image job runs the same Next build
# inside its Dockerfile, so building it twice only doubles the wait.
security:
name: Trivy (dependências, segredos e Dockerfiles)
@@ -174,7 +195,7 @@ jobs:
# which on Gitea is not GitHub.
- name: Repositório
run: |
cid=$(docker create --network host -w /src aquasec/trivy:0.70.0 \
cid=$(docker create --network host -v trivy-cache:/root/.cache/ -w /src aquasec/trivy:0.70.0 \
fs --scanners vuln,secret,misconfig --severity HIGH,CRITICAL --exit-code 1 \
--skip-dirs services/auth/node_modules,services/storage/node_modules,services/webmail/node_modules,services/webmail/.next .)
docker cp . "$cid:/src"
@@ -195,7 +216,7 @@ jobs:
# scanner something people learn to skip.
- name: Repositório (MEDIUM, informativo)
run: |
cid=$(docker create --network host -w /src aquasec/trivy:0.70.0 \
cid=$(docker create --network host -v trivy-cache:/root/.cache/ -w /src aquasec/trivy:0.70.0 \
fs --scanners vuln,secret --severity MEDIUM --exit-code 0 \
--skip-dirs services/auth/node_modules,services/storage/node_modules,services/webmail/node_modules,services/webmail/.next .)
docker cp . "$cid:/src"
@@ -214,18 +235,21 @@ jobs:
steps:
- uses: actions/checkout@v7
- uses: docker/setup-buildx-action@v4
# Built but not pushed: this proves each Dockerfile still works on every
# branch, while publishing stays in release.yml.
#
# Plain `docker build` on purpose. setup-buildx would start a fresh
# BuildKit container per job and throw its layer cache away; the daemon's
# own builder keeps the cache in the runner's persistent volume, and the
# "Stack completa" job reuses it for the same Dockerfiles.
- name: Build
uses: docker/build-push-action@v7
with:
context: ${{ (matrix.service == 'migrations' || matrix.service == 'rspamd') && '.' || format('services/{0}', matrix.service) }}
file: services/${{ matrix.service }}/Dockerfile
push: false
load: true
tags: lambdamail-${{ matrix.service }}:ci
run: |
case '${{ matrix.service }}' in
migrations|rspamd) context=. ;;
*) context=services/${{ matrix.service }} ;;
esac
docker build -f services/${{ matrix.service }}/Dockerfile \
-t lambdamail-${{ matrix.service }}:ci "$context"
# Scanned only for the images whose contents we author. migrations and
# rspamd add .sql and .conf files to an upstream image and nothing else,
@@ -236,7 +260,7 @@ jobs:
- name: Trivy na imagem
if: matrix.service != 'migrations' && matrix.service != 'rspamd'
run: |
docker run --rm --network host -e DOCKER_HOST=tcp://127.0.0.1:2375 aquasec/trivy:0.70.0 \
docker run --rm --network host -v trivy-cache:/root/.cache/ -e DOCKER_HOST=tcp://127.0.0.1:2375 aquasec/trivy:0.70.0 \
image --severity HIGH,CRITICAL --exit-code 1 lambdamail-${{ matrix.service }}:ci
compose-up:
+40
View File
@@ -165,3 +165,43 @@ jobs:
echo "${{ steps.meta.outputs.tags }}"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
# Cria a entrada em "Releases" do repositório. Só roda quando uma tag v* é
# enviada, depois que todas as imagens foram publicadas. Usa o token do próprio
# Actions, então não precisa de segredo extra.
gitea-release:
name: Cria a release no Gitea
needs: [publish, prepare]
if: startsWith(gitea.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Release
env:
TAG: ${{ gitea.ref_name }}
TOKEN: ${{ gitea.token }}
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
NAMESPACE: ${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}
run: |
prev=$(git describe --tags --abbrev=0 "$TAG^" 2>/dev/null || true)
range=${prev:+$prev..}$TAG
{
echo "## Imagens"
echo
echo '```'
for s in protocols auth storage webmail migrations rspamd; do
echo "$NAMESPACE/$s:${TAG#v}"
done
echo '```'
echo
echo "## Mudanças${prev:+ desde $prev}"
echo
git log --no-merges --format='- %s (%h)' "$range"
} > notes.md
pre=false; case "$TAG" in *-*) pre=true ;; esac
jq -n --arg tag "$TAG" --arg name "LambdaMail ${TAG#v}" --rawfile body notes.md --argjson pre "$pre" \
'{tag_name:$tag, name:$name, body:$body, prerelease:$pre}' > release.json
curl -fsS -X POST "$API/releases" -H "Authorization: token $TOKEN" \
-H 'Content-Type: application/json' -d @release.json