name: Release on: push: tags: - 'v*' permissions: contents: write jobs: release: # Production releases use the repository's standard Linux runner label. # The Gitea act_runner must advertise ubuntu-latest before tagging. runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Validate release tag id: release_meta run: | GITEA_REF_NAME=${GITHUB_REF_NAME:-} if [ -z "$GITEA_REF_NAME" ]; then GITEA_REF_NAME=${GITHUB_REF#refs/tags/}; fi if [ -z "$GITEA_REF_NAME" ] || [ "$GITEA_REF_NAME" = "$GITHUB_REF" ]; then GITEA_REF_NAME=$(git tag --points-at HEAD | awk '/^v[0-9A-Za-z][0-9A-Za-z._+-]*$/{print; exit}') fi VERSION=${GITEA_REF_NAME#v} test "$GITEA_REF_NAME" = "v$VERSION" ./scripts/check-semver.sh "$VERSION" GITEA_SHA=$(git rev-parse HEAD) test "$(git rev-parse "refs/tags/$GITEA_REF_NAME^{commit}")" = "$GITEA_SHA" test -z "$(git ls-files --others --exclude-standard)" git diff --quiet --ignore-space-at-eol --ignore-cr-at-eol \ || { printf 'Release checkout has non-whitespace tracked changes:\n' >&2; git diff --stat >&2; exit 1; } { printf 'version=%s\n' "$VERSION" printf 'ref=%s\n' "$GITEA_REF_NAME" printf 'revision=%s\n' "$GITEA_SHA" } >> "$GITHUB_OUTPUT" - uses: actions/setup-java@v4 with: distribution: temurin java-version: '17' cache: maven - uses: actions/setup-node@v4 with: node-version: '22' cache: npm cache-dependency-path: frontend/package-lock.json - name: Verify backend env: RELEASE_VERSION: ${{ steps.release_meta.outputs.version }} run: ./backend/mvnw -f backend/pom.xml -Drevision="$RELEASE_VERSION" test - name: Verify frontend working-directory: frontend run: | HUSKY=0 npm ci npm run lint -- --no-fix npm run stylelint npm test npm run audit:dependencies npm run build if [ "${RUNNER_OS:-Linux}" = macOS ]; then npx playwright install chromium else npx playwright install --with-deps chromium fi npm run test:e2e npm run test:dist - name: Verify release contracts and scripts run: | ./scripts/check-openapi.sh openapi.yaml ./scripts/test-install-fixture.sh ./scripts/test-git-install-fixture.sh ./scripts/test-update-fixture.sh ./scripts/test-baota-start-fixture.sh ./scripts/test-purge-fixture.sh ./scripts/test-gitea-publish-fixture.sh shellcheck deploy/install.sh deploy/install-from-git.sh deploy/update.sh deploy/baota-start.sh deploy/baota-init.sh \ deploy/purge.sh \ scripts/check-semver.sh \ scripts/package-release.sh scripts/publish-gitea-release.sh \ scripts/generate-release-key.sh scripts/test-install-fixture.sh \ scripts/test-git-install-fixture.sh \ scripts/test-update-fixture.sh scripts/test-gitea-publish-fixture.sh \ scripts/test-baota-start-fixture.sh scripts/test-purge-fixture.sh \ scripts/verify-release.sh - name: Build and sign release assets env: RELEASE_SIGNING_KEY_B64: ${{ secrets.RELEASE_SIGNING_KEY_B64 }} RELEASE_VERSION: ${{ steps.release_meta.outputs.version }} KAIDI_TRUSTED_RELEASE_PUBLIC_KEY_SHA256: ${{ vars.KAIDI_RELEASE_PUBLIC_KEY_SHA256 }} KAIDI_RELEASE_NOTES: Kaidi Finance ${{ steps.release_meta.outputs.ref }} KAIDI_SOURCE_REVISION: ${{ steps.release_meta.outputs.revision }} KAIDI_SOURCE_REF: ${{ steps.release_meta.outputs.ref }} KAIDI_SOURCE_DIRTY: 'false' run: | test -n "$RELEASE_SIGNING_KEY_B64" trap 'shred -u "$RUNNER_TEMP/release-key.pem" 2>/dev/null || rm -f "$RUNNER_TEMP/release-key.pem"' EXIT if base64 --decode /dev/null 2>&1; then printf '%s' "$RELEASE_SIGNING_KEY_B64" | base64 --decode > "$RUNNER_TEMP/release-key.pem" else printf '%s' "$RELEASE_SIGNING_KEY_B64" | base64 -D > "$RUNNER_TEMP/release-key.pem" fi chmod 600 "$RUNNER_TEMP/release-key.pem" KAIDI_RELEASE_SIGNING_KEY="$RUNNER_TEMP/release-key.pem" \ ./scripts/package-release.sh "$RELEASE_VERSION" - name: Verify signed release assets env: KAIDI_TRUSTED_RELEASE_PUBLIC_KEY_SHA256: ${{ vars.KAIDI_RELEASE_PUBLIC_KEY_SHA256 }} KAIDI_EXPECTED_SOURCE_REVISION: ${{ steps.release_meta.outputs.revision }} KAIDI_EXPECTED_SOURCE_REF: ${{ steps.release_meta.outputs.ref }} KAIDI_EXPECTED_SOURCE_DIRTY: 'false' run: ./scripts/verify-release.sh dist/release - name: Publish Gitea release env: GITEA_TOKEN: ${{ secrets.RELEASE_GITEA_TOKEN }} # Gitea's runner leaves github.server_url/repository empty on some # host-mode tag events; keep the release destination explicit. GITEA_SERVER_URL: https://git.awaioi.com GITEA_REPOSITORY: ERP-Team/kaidi GITEA_REF_NAME: ${{ steps.release_meta.outputs.ref }} GITEA_SHA: ${{ steps.release_meta.outputs.revision }} run: ./scripts/publish-gitea-release.sh - name: Upload Playwright report after failure if: failure() uses: actions/upload-artifact@v4 with: name: playwright-report-${{ github.run_id }} path: frontend/playwright-report if-no-files-found: ignore retention-days: 7