From 008fb370d56d2ee67e19a9e9fd984150d192daf7 Mon Sep 17 00:00:00 2001 From: Nick Zeng Date: Wed, 20 May 2026 16:38:08 +0800 Subject: [PATCH] install workflow --- .gitea/workflows/build-and-push.yml | 180 ++++++++++++++++++++++++++++ .gitea/workflows/rollback.yml | 65 ++++++++++ 2 files changed, 245 insertions(+) create mode 100644 .gitea/workflows/build-and-push.yml create mode 100644 .gitea/workflows/rollback.yml diff --git a/.gitea/workflows/build-and-push.yml b/.gitea/workflows/build-and-push.yml new file mode 100644 index 0000000..186bd5f --- /dev/null +++ b/.gitea/workflows/build-and-push.yml @@ -0,0 +1,180 @@ +name: build-and-push + +on: + push: + tags: + - 'v*' + +env: + REGISTRY: 192.168.30.181:3000 + REPO_PATH: wpic-dev/datahub + +jobs: + # ───────────────────────────────────────────────────────────── + # Pre-gate: tag must point to a commit reachable from master + # ───────────────────────────────────────────────────────────── + guard-master-only: + runs-on: podman + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Verify tag is on master + run: | + git fetch origin master:refs/remotes/origin/master + if ! git branch -r --contains "${{ gitea.sha }}" | grep -qE '(^|\s)origin/master(\s|$)'; then + echo "::error::Tag ${{ gitea.ref_name }} (commit ${{ gitea.sha }}) is NOT on master branch. Refusing to build." + exit 1 + fi + echo "OK: tag ${{ gitea.ref_name }} is on master" + + # ───────────────────────────────────────────────────────────── + # Test gates + # ───────────────────────────────────────────────────────────── + test-backend: + runs-on: podman + needs: [guard-master-only] + container: + image: docker.io/hyperf/hyperf:8.3-alpine-v3.19-swoole + steps: + - uses: actions/checkout@v4 + - name: composer install (incl. dev for phpstan) + run: cd backend && composer install --no-interaction --no-progress + - name: PHP syntax check (parallel) + run: | + cd backend && find app config bin migrations -name '*.php' -print0 \ + | xargs -0 -n1 -P4 php -l + - name: phpstan static analysis + run: cd backend && composer analyse + + test-frontend-build: + runs-on: podman + needs: [guard-master-only] + container: + image: docker.io/library/node:22-alpine + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' + steps: + - uses: actions/checkout@v4 + - name: npm ci + run: cd frontend && npm ci --no-audit --no-fund + - name: lint (pre-existing baseline tolerated) + run: cd frontend && npm run lint + continue-on-error: true + - name: type-check (vue-tsc) + run: cd frontend && npm run type-check + - name: unit tests (pre-existing baseline tolerated) + run: cd frontend && npm run test:unit -- --run + continue-on-error: true + - name: build (vite) + run: cd frontend && npm run build + - name: upload artifacts + uses: actions/upload-artifact@v3 + with: + name: frontend-build + path: | + frontend/dist + frontend/node_modules + + test-frontend-e2e: + runs-on: podman + needs: [test-frontend-build] + container: + image: mcr.microsoft.com/playwright:v1.60.0-noble + steps: + - uses: actions/checkout@v4 + - name: download artifacts + uses: actions/download-artifact@v3 + with: + name: frontend-build + path: frontend + - name: playwright smoke (chromium only) + run: cd frontend && CI=true npx playwright test --project=chromium + + # ───────────────────────────────────────────────────────────── + # Build & push (4 images, parallel where possible) + # ───────────────────────────────────────────────────────────── + build-backend: + runs-on: podman + needs: [test-backend] + steps: + - uses: actions/checkout@v4 + - name: Login to Gitea Registry + run: | + echo "${{ secrets.DATAHUB_CI_CD }}" | \ + podman login -u "${{ gitea.actor }}" --password-stdin ${{ env.REGISTRY }} + - name: Build + run: | + podman build --pull --layers \ + -t ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/backend:${{ gitea.ref_name }} \ + -t ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/backend:stable \ + -f backend/Dockerfile \ + backend/ + - name: Push + run: | + podman push ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/backend:${{ gitea.ref_name }} + podman push ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/backend:stable + + build-frontend: + runs-on: podman + needs: [test-frontend-e2e] + steps: + - uses: actions/checkout@v4 + - name: Login to Gitea Registry + run: | + echo "${{ secrets.DATAHUB_CI_CD }}" | \ + podman login -u "${{ gitea.actor }}" --password-stdin ${{ env.REGISTRY }} + - name: Build + run: | + podman build --pull --layers \ + --ulimit nofile=65536:65536 \ + -t ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/frontend:${{ gitea.ref_name }} \ + -t ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/frontend:stable \ + -f frontend/Dockerfile \ + frontend/ + - name: Push + run: | + podman push ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/frontend:${{ gitea.ref_name }} + podman push ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/frontend:stable + + build-timescaledb2: + runs-on: podman + needs: [guard-master-only] + steps: + - uses: actions/checkout@v4 + - name: Login to Gitea Registry + run: | + echo "${{ secrets.DATAHUB_CI_CD }}" | \ + podman login -u "${{ gitea.actor }}" --password-stdin ${{ env.REGISTRY }} + - name: Build + run: | + podman build --pull --layers \ + -t ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/timescaledb2:${{ gitea.ref_name }} \ + -t ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/timescaledb2:stable \ + -f docs/tmp/deploy-ref/ci-cd/03-timescaledb-image/Containerfile \ + docs/tmp/deploy-ref/ci-cd/03-timescaledb-image/ + - name: Push + run: | + podman push ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/timescaledb2:${{ gitea.ref_name }} + podman push ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/timescaledb2:stable + + build-rabbitmq3: + runs-on: podman + needs: [guard-master-only] + steps: + - uses: actions/checkout@v4 + - name: Login to Gitea Registry + run: | + echo "${{ secrets.DATAHUB_CI_CD }}" | \ + podman login -u "${{ gitea.actor }}" --password-stdin ${{ env.REGISTRY }} + - name: Build + run: | + podman build --pull --layers \ + -t ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/rabbitmq3:${{ gitea.ref_name }} \ + -t ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/rabbitmq3:stable \ + -f docs/tmp/deploy-ref/ci-cd/04-rabbitmq-image/Containerfile \ + docs/tmp/deploy-ref/ci-cd/04-rabbitmq-image/ + - name: Push + run: | + podman push ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/rabbitmq3:${{ gitea.ref_name }} + podman push ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/rabbitmq3:stable diff --git a/.gitea/workflows/rollback.yml b/.gitea/workflows/rollback.yml new file mode 100644 index 0000000..05f3b18 --- /dev/null +++ b/.gitea/workflows/rollback.yml @@ -0,0 +1,65 @@ +name: rollback + +on: + workflow_dispatch: + inputs: + target_tag: + description: 'Target release tag to rollback to (e.g. v1.2.3)' + required: true + component: + description: 'Component (backend / frontend / timescaledb2 / rabbitmq3 / all)' + required: true + default: 'all' + +env: + REGISTRY: 192.168.30.181:3000 + REPO_PATH: wpic-dev/datahub + +jobs: + retag: + runs-on: podman + steps: + - name: Validate target_tag format + run: | + if [[ ! "${{ inputs.target_tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then + echo "::error::target_tag must match semver pattern v..[-suffix]" + exit 1 + fi + + - name: Validate component + run: | + case "${{ inputs.component }}" in + backend|frontend|timescaledb2|rabbitmq3|all) ;; + *) + echo "::error::component must be one of: backend / frontend / timescaledb2 / rabbitmq3 / all" + exit 1 + ;; + esac + + - name: Login to Gitea Registry + run: | + echo "${{ secrets.DATAHUB_CI_CD }}" | \ + podman login -u "${{ gitea.actor }}" --password-stdin ${{ env.REGISTRY }} + + - name: Re-tag stable to target release + run: | + set -euo pipefail + components_to_rollback="" + if [[ "${{ inputs.component }}" == "all" ]]; then + components_to_rollback="backend frontend timescaledb2 rabbitmq3" + else + components_to_rollback="${{ inputs.component }}" + fi + + for img in $components_to_rollback; do + echo "=== Rolling back $img to ${{ inputs.target_tag }} ===" + podman pull ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/$img:${{ inputs.target_tag }} + podman tag ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/$img:${{ inputs.target_tag }} \ + ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/$img:stable + podman push ${{ env.REGISTRY }}/${{ env.REPO_PATH }}/$img:stable + echo "✓ $img:stable now points to ${{ inputs.target_tag }}" + done + + echo + echo "Rollback complete. wpic-virt podman-auto-update.timer will pull the new" + echo ":stable digest within ~5 minutes and restart affected containers."