diff --git a/.gitea/workflows/android-build.yml b/.gitea/workflows/android-build.yml index 1ab38e4..fa2233d 100644 --- a/.gitea/workflows/android-build.yml +++ b/.gitea/workflows/android-build.yml @@ -13,8 +13,37 @@ jobs: runs-on: ubuntu-latest steps: + # ── 0. Deduplication gate ───────────────────────────────────────────────── + # On this Gitea runner version the same push event is dispatched to + # multiple workers, creating duplicate runs. This step detects when a + # newer run for the same commit already exists and sets skip=true so all + # subsequent steps are no-ops, letting the duplicate finish in ~5 s. + - name: Dedup gate + id: dedup + env: + TOKEN: ${{ secrets.PACKAGE_TOKEN }} + run: | + CURRENT="${{ github.run_id }}" + HIGHEST=$(curl -sf \ + "https://git.sal.giize.com/api/v1/repos/mozempk/scopone/actions/runs?limit=50" \ + -H "Authorization: token $TOKEN" | python3 -c " + import sys,json + runs=json.load(sys.stdin).get('workflow_runs',[]) + sha='${{ github.sha }}' + same=[r['id'] for r in runs if r['head_sha']==sha] + print(max(same) if same else $CURRENT) + " 2>/dev/null || echo "$CURRENT") + if [[ "$CURRENT" -lt "$HIGHEST" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Superseded by run $HIGHEST — skipping all build steps." + else + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "Latest run ($CURRENT) — proceeding." + fi + # ── 1. Source ──────────────────────────────────────────────────────────── - name: Checkout + if: steps.dedup.outputs.skip != 'true' uses: actions/checkout@v4 with: # Full history + tags required for the changelog step. @@ -22,6 +51,7 @@ jobs: # ── 2. Java ────────────────────────────────────────────────────────────── - name: Set up JDK 21 + if: steps.dedup.outputs.skip != 'true' uses: actions/setup-java@v4 with: distribution: temurin @@ -29,6 +59,7 @@ jobs: # ── 3. Node.js ─────────────────────────────────────────────────────────── - name: Set up Node 22 + if: steps.dedup.outputs.skip != 'true' uses: actions/setup-node@v4 with: node-version: '22' @@ -36,6 +67,7 @@ jobs: # ── 4. Android SDK ─────────────────────────────────────────────────────── - name: Install Android SDK command-line tools + if: steps.dedup.outputs.skip != 'true' run: | SDK_DIR="$HOME/android-sdk" echo "ANDROID_HOME=$SDK_DIR" >> "$GITHUB_ENV" @@ -54,6 +86,7 @@ jobs: echo "$SDK_DIR/platform-tools" >> "$GITHUB_PATH" - name: Accept SDK licenses & install platform/build-tools + if: steps.dedup.outputs.skip != 'true' run: | # { yes || true } absorbs the SIGPIPE that 'yes' gets when sdkmanager closes # stdin after accepting all prompts — avoids exit-code 141 under 'pipefail'. @@ -65,6 +98,7 @@ jobs: # ── 5. Caches ──────────────────────────────────────────────────────────── - name: Cache Gradle files + if: steps.dedup.outputs.skip != 'true' uses: actions/cache@v4 with: path: | @@ -75,9 +109,11 @@ jobs: # ── 6. JS build ────────────────────────────────────────────────────────── - name: Install JS dependencies + if: steps.dedup.outputs.skip != 'true' run: npm ci - name: Build web assets + if: steps.dedup.outputs.skip != 'true' env: # Embed the CI run number as the app's build identifier so the # in-app update check can compare against Gitea release tags. @@ -85,14 +121,15 @@ jobs: run: npm run build # ── 7. Capacitor sync ──────────────────────────────────────────────────── - - name: Capacitor sync android - run: npx cap sync android + - name: Capacitor sync android if: steps.dedup.outputs.skip != 'true' run: npx cap sync android # ── 8. Android build ───────────────────────────────────────────────────── - name: Make gradlew executable + if: steps.dedup.outputs.skip != 'true' run: chmod +x android/gradlew - name: Build Debug APK + if: steps.dedup.outputs.skip != 'true' working-directory: android run: | # Retry up to 3 times to survive transient network errors when the @@ -103,6 +140,7 @@ jobs: done - name: Build Release APK (unsigned — no signing key required) + if: steps.dedup.outputs.skip != 'true' working-directory: android run: | for attempt in 1 2 3; do @@ -111,8 +149,7 @@ jobs: done # ── 9. Upload APKs as workflow artifacts ───────────────────────────────── - - name: Upload APKs as artifacts - uses: actions/upload-artifact@v3 + - name: Upload APKs as artifacts if: steps.dedup.outputs.skip != 'true' uses: actions/upload-artifact@v3 with: name: scopone-android-${{ github.run_number }} path: | @@ -121,8 +158,7 @@ jobs: retention-days: 30 # ── 10. Publish to Gitea generic package registry ──────────────────────── - - name: Publish APKs to Gitea package registry - env: + - name: Publish APKs to Gitea package registry if: steps.dedup.outputs.skip != 'true' env: TOKEN: ${{ secrets.PACKAGE_TOKEN }} run: | set -euo pipefail @@ -159,6 +195,7 @@ jobs: # scopes. If the PAT lacks write:repository the curl will return 403 and # the step will fail — update the PAT scopes on the Gitea web UI. - name: Create Gitea release + if: steps.dedup.outputs.skip != 'true' env: TOKEN: ${{ secrets.PACKAGE_TOKEN }} run: |