ci: add Gitea Actions workflows

This commit is contained in:
2026-04-25 18:20:14 +02:00
parent b9654d7a7c
commit 709588302c
2 changed files with 195 additions and 0 deletions

101
.gitea/workflows/build.yml Normal file
View File

@@ -0,0 +1,101 @@
name: Build and Push
on:
push:
branches: [main]
# Don't rebuild on doc-only or CI-config-only changes
paths-ignore:
- 'README.md'
- '.gitea/**'
- 'deploy/**'
workflow_dispatch:
env:
REGISTRY: registry.c5ai.ch
IMAGE: pieced/pieced-portal
jobs:
build:
# 'self-hosted' matches the label our act_runner registers with.
# 'ubuntu-latest' would work too because we configure both labels in the
# runner config, but self-hosted makes intent explicit.
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Determine next patch version
id: version
# Reads tags from the registry's OCI Distribution v2 API, filters to
# strict semver (skips 'latest', 'dev', '<sha>-dirty', etc.), picks the
# highest with version-sort, and bumps the patch component. If nothing
# numeric exists yet (fresh registry), starts at 0.1.0.
run: |
set -euo pipefail
tags_json=$(curl -sf -u "${{ secrets.REGISTRY_USERNAME }}:${{ secrets.REGISTRY_PASSWORD }}" \
"https://${REGISTRY}/v2/${IMAGE}/tags/list")
highest=$(echo "$tags_json" \
| jq -r '.tags // [] | .[]' \
| grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \
| sort -V \
| tail -n1 || true)
if [ -z "$highest" ]; then
next="0.1.0"
echo "No semver tags found — starting at $next"
else
major=$(echo "$highest" | cut -d. -f1)
minor=$(echo "$highest" | cut -d. -f2)
patch=$(echo "$highest" | cut -d. -f3)
next="${major}.${minor}.$((patch + 1))"
echo "Highest existing: $highest → next: $next"
fi
echo "version=${next}" >> "$GITHUB_OUTPUT"
- name: Login to registry
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" \
| docker login "${REGISTRY}" -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
- name: Build and push image
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
docker build \
--pull \
-t "${REGISTRY}/${IMAGE}:${VERSION}" \
-t "${REGISTRY}/${IMAGE}:latest" \
.
docker push "${REGISTRY}/${IMAGE}:${VERSION}"
docker push "${REGISTRY}/${IMAGE}:latest"
- name: Tag git commit with version
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
git config user.name "pieced-ci"
git config user.email "ci@pieced.ch"
git tag -a "v${VERSION}" -m "Release ${VERSION}"
# Use CI_TOKEN explicitly so we can push a tag (the workflow's
# default token may or may not have push scope depending on Gitea
# actions config — explicit token avoids ambiguity).
git push \
"https://oauth2:${{ secrets.CI_TOKEN }}@git.c5ai.ch/pieced/pieced-portal.git" \
"v${VERSION}"
- name: Summary
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
{
echo "## Build complete: ${VERSION}"
echo
echo "**Image:** \`${REGISTRY}/${IMAGE}:${VERSION}\`"
echo
echo "Run the **Deploy to GitOps** workflow to roll this version out."
} >> "$GITHUB_STEP_SUMMARY"

View File

@@ -0,0 +1,94 @@
name: Deploy to GitOps
# Manually triggered. Bumps the image tag in pieced-gitops so ArgoCD rolls
# the new version out. Does not build anything itself — the build workflow
# is the only thing that creates and pushes images.
on:
workflow_dispatch:
inputs:
version:
description: 'Version to deploy (e.g. 0.1.5). Must already exist in the registry.'
required: true
type: string
env:
REGISTRY: registry.c5ai.ch
IMAGE: pieced/pieced-portal
GITOPS_REPO: admin/pieced-gitops
GITOPS_FILE: apps/portal/deployment.yaml
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Verify image exists in registry
# Fail fast if the user typed a version that was never built. Catches
# typos before we touch the gitops repo.
run: |
set -euo pipefail
status=$(curl -sf -o /dev/null -w '%{http_code}' \
-u "${{ secrets.REGISTRY_USERNAME }}:${{ secrets.REGISTRY_PASSWORD }}" \
"https://${REGISTRY}/v2/${IMAGE}/manifests/${{ inputs.version }}" \
|| true)
if [ "$status" != "200" ]; then
echo "::error::Image ${REGISTRY}/${IMAGE}:${{ inputs.version }} not found (HTTP $status)"
exit 1
fi
echo "Confirmed: ${REGISTRY}/${IMAGE}:${{ inputs.version }} exists."
- name: Checkout pieced-gitops
uses: actions/checkout@v4
with:
repository: ${{ env.GITOPS_REPO }}
token: ${{ secrets.CI_TOKEN }}
path: gitops
# We need history to commit + push back; default fetch-depth: 1 is fine
# for a single commit but force a clean shallow clone:
fetch-depth: 1
- name: Update image tag
working-directory: gitops
env:
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
file="${GITOPS_FILE}"
if [ ! -f "$file" ]; then
echo "::error::$file not found in gitops repo"
exit 1
fi
# Anchored to the full image path to avoid accidentally rewriting
# any unrelated 'image:' line that might appear later.
sed -i -E \
"s|(image: ${REGISTRY}/${IMAGE}:)[^[:space:]]+|\1${VERSION}|" \
"$file"
echo "--- diff ---"
git --no-pager diff "$file" || true
- name: Commit and push
working-directory: gitops
env:
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
if git diff --quiet; then
echo "No changes — image tag was already ${VERSION}."
exit 0
fi
git config user.name "pieced-ci"
git config user.email "ci@pieced.ch"
git add "${GITOPS_FILE}"
git commit -m "Bump pieced-portal to ${VERSION}"
git push
- name: Summary
env:
VERSION: ${{ inputs.version }}
run: |
{
echo "## Deployed: pieced-portal ${VERSION}"
echo
echo "ArgoCD will sync within its refresh interval."
echo "Watch with: \`kubectl get app -n argocd portal -w\`"
} >> "$GITHUB_STEP_SUMMARY"