diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..f592306 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,103 @@ +name: Build and Push + +# Off-infra build (ADR-0002). Canonical repo is Forgejo viktor/broker-sync, which +# push-mirrors here; this workflow builds on GitHub-hosted runners, pushes the +# image to GHCR, then signals the Woodpecker deploy pipeline (repo 0) +# to roll the cluster — the homelab never sees build IO or registry pushes. +# +# Committed on the FORGEJO side (the mirror is one-way; commits made on GitHub +# are overwritten by the next sync). Generated by infra/scripts/offinfra-onboard. +on: + push: + branches: [master] + workflow_dispatch: {} + +permissions: + contents: read + packages: write + +jobs: + lint-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + with: + python-version: "3.12" + - name: Lint + type-check + test + run: | + pip install --no-cache-dir "poetry==1.8.4" + poetry install --no-interaction --no-root + poetry run ruff check . + poetry run mypy broker_sync tests + poetry run pytest -q + + build: + needs: lint-and-test + runs-on: ubuntu-latest + outputs: + image_tag: ${{ steps.meta.outputs.sha }} + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 # full history + tags so svu sees the last vX.Y.Z + fetch-tags: true + # Auto-semver (svu): tag-only, pushed to CANONICAL Forgejo (GitHub tags + # would be wiped by the next mirror sync). Best-effort: never blocks the build. + - name: Compute + tag semver (svu) + env: + FORGEJO_GIT_TOKEN: ${{ secrets.FORGEJO_GIT_TOKEN }} + run: | + set +e + git config user.email "ci@viktorbarzin.me" + git config user.name "broker-sync-ci" + git config --global --add safe.directory "$GITHUB_WORKSPACE" + curl -sSL https://github.com/caarlos0/svu/releases/download/v3.4.1/svu_3.4.1_linux_amd64.tar.gz | tar -xz svu + CUR=$(./svu current 2>/dev/null) + NEXT=$(./svu next 2>/dev/null) + echo "svu current=[$CUR] next=[$NEXT]" + if [ -n "$NEXT" ] && [ "$NEXT" != "$CUR" ]; then + git tag "$NEXT" 2>/dev/null + git push "https://viktor:${FORGEJO_GIT_TOKEN}@forgejo.viktorbarzin.me/viktor/broker-sync.git" "$NEXT" && echo "pushed tag $NEXT to forgejo" || echo "tag push failed (non-blocking)" + fi + exit 0 + - uses: docker/setup-buildx-action@v4 + - uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - id: meta + run: echo "sha=$(echo ${{ github.sha }} | cut -c1-8)" >> "$GITHUB_OUTPUT" + - uses: docker/build-push-action@v7 + with: + context: . + push: true + platforms: linux/amd64 + # Single-manifest images (no provenance/SBOM attestation children) so + # registry retention can never orphan index children (ADR-0002). + provenance: false + tags: | + ghcr.io/viktorbarzin/wealthfolio-sync:${{ steps.meta.outputs.sha }} + ghcr.io/viktorbarzin/wealthfolio-sync:latest + cache-from: type=gha + cache-to: type=gha,mode=max + # Keep the newest ~10 versions on ghcr (latest rides the newest one). + - name: ghcr retention (keep 10) + uses: actions/delete-package-versions@v5 + continue-on-error: true + with: + package-name: wealthfolio-sync + package-type: container + min-versions-to-keep: 10 + + notify-failure: + needs: [lint-and-test, build] + if: failure() + runs-on: ubuntu-latest + steps: + - name: Slack notify + run: | + curl -sf -X POST -H 'Content-Type: application/json' \ + -d "{\"text\":\":rotating_light: broker-sync off-infra build FAILED: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\"}" \ + "${{ secrets.SLACK_WEBHOOK }}" || true diff --git a/.woodpecker/build.yml b/.woodpecker/build.yml deleted file mode 100644 index 423ea0c..0000000 --- a/.woodpecker/build.yml +++ /dev/null @@ -1,45 +0,0 @@ -when: - event: push - branch: [main, master] - -clone: - git: - image: woodpeckerci/plugin-git - settings: - attempts: 5 - backoff: 10s - -steps: - - name: lint-and-test - image: python:3.12-slim - commands: - - pip install --no-cache-dir "poetry==1.8.4" - - poetry install --no-interaction --no-root - - poetry run ruff check . - - poetry run mypy broker_sync tests - - poetry run pytest -q - - - name: build-and-push - image: woodpeckerci/plugin-docker-buildx - depends_on: - - lint-and-test - settings: - # Image name is `wealthfolio-sync` to match the deployment in - # infra/stacks/wealthfolio/main.tf (CronJob `wealthfolio-sync`). - # The repo is called `broker-sync` because the source covers - # multiple brokers (Trading 212, Schwab, Fidelity, IMAP-CSV) — - # we just happen to publish it under the wealthfolio name since - # that's the consumer stack. - repo: - - forgejo.viktorbarzin.me/viktor/wealthfolio-sync - logins: - - registry: forgejo.viktorbarzin.me - username: - from_secret: forgejo_user - password: - from_secret: forgejo_push_token - dockerfile: Dockerfile - context: . - auto_tag: true - platforms: - - linux/amd64