fix: make Android contract sync idempotent #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Sync catalog contract to Android | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - backend/worker/contract/** | |
| - release/train.json | |
| - scripts/resolve-contract-source-commit.sh | |
| - scripts/sync-android-contract.sh | |
| - scripts/test-sync-android-contract.sh | |
| - scripts/verify-release.sh | |
| - .github/workflows/contract-sync-android.yml | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| sync: | |
| name: Open Android contract snapshot PR | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| env: | |
| ANDROID_REPOSITORY: LamPPKK/Smart-Movie-Android | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Verify the canonical contract and release manifest | |
| run: ./scripts/verify-release.sh | |
| - name: Resolve the canonical contract commit | |
| id: contract_source | |
| run: | | |
| set -euo pipefail | |
| contract_commit="$(./scripts/resolve-contract-source-commit.sh)" | |
| echo "commit=$contract_commit" >> "$GITHUB_OUTPUT" | |
| - name: Check whether Android main already matches | |
| id: sync_state | |
| env: | |
| CONTRACT_COMMIT: ${{ steps.contract_source.outputs.commit }} | |
| run: | | |
| set -euo pipefail | |
| android_dir="$RUNNER_TEMP/android-smartmovie-check" | |
| git clone --depth 1 "https://github.com/$ANDROID_REPOSITORY.git" "$android_dir" | |
| ./scripts/sync-android-contract.sh "$android_dir" "$CONTRACT_COMMIT" | |
| if [[ -n "$(git -C "$android_dir" status --porcelain -- catalog-contract release/train.json)" ]]; then | |
| echo 'required=true' >> "$GITHUB_OUTPUT" | |
| else | |
| echo 'required=false' >> "$GITHUB_OUTPUT" | |
| echo 'Android main already contains this contract snapshot.' | |
| fi | |
| - name: Require the least-privilege cross-repository token | |
| if: steps.sync_state.outputs.required == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.ANDROID_CONTRACT_SYNC_TOKEN }} | |
| run: | | |
| if [[ -z "$GH_TOKEN" ]]; then | |
| echo "ANDROID_CONTRACT_SYNC_TOKEN must allow Contents and Pull requests on $ANDROID_REPOSITORY." >&2 | |
| exit 1 | |
| fi | |
| - name: Check out and update the Android repository | |
| if: steps.sync_state.outputs.required == 'true' | |
| env: | |
| ANDROID_DIR: ${{ runner.temp }}/android-smartmovie | |
| CONTRACT_COMMIT: ${{ steps.contract_source.outputs.commit }} | |
| GH_TOKEN: ${{ secrets.ANDROID_CONTRACT_SYNC_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| gh auth setup-git | |
| gh repo clone "$ANDROID_REPOSITORY" "$ANDROID_DIR" | |
| cd "$ANDROID_DIR" | |
| branch="contract-sync-${CONTRACT_COMMIT:0:12}" | |
| if git ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1; then | |
| git fetch origin "$branch" | |
| git switch -C "$branch" "origin/$branch" | |
| else | |
| git switch -c "$branch" | |
| fi | |
| "$GITHUB_WORKSPACE/scripts/sync-android-contract.sh" "$ANDROID_DIR" "$CONTRACT_COMMIT" | |
| - name: Open or refresh the Android pull request | |
| if: steps.sync_state.outputs.required == 'true' | |
| env: | |
| ANDROID_DIR: ${{ runner.temp }}/android-smartmovie | |
| CONTRACT_COMMIT: ${{ steps.contract_source.outputs.commit }} | |
| GH_TOKEN: ${{ secrets.ANDROID_CONTRACT_SYNC_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| cd "$ANDROID_DIR" | |
| branch="contract-sync-${CONTRACT_COMMIT:0:12}" | |
| git config user.name "smartmovie-contract-bot" | |
| git config user.email "actions@users.noreply.github.com" | |
| if [[ -n "$(git status --porcelain)" ]]; then | |
| git add catalog-contract release/train.json | |
| git commit -m "chore: sync catalog contract ${CONTRACT_COMMIT:0:12}" | |
| git push --set-upstream origin "$branch" | |
| elif ! git ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1; then | |
| echo "Android main already contains this contract snapshot." | |
| exit 0 | |
| fi | |
| if [[ -z "$(gh pr list --repo "$ANDROID_REPOSITORY" --head "$branch" --json url --jq '.[0].url')" ]]; then | |
| gh pr create \ | |
| --repo "$ANDROID_REPOSITORY" \ | |
| --base main \ | |
| --head "$branch" \ | |
| --title "chore: sync SmartMovie catalog contract" \ | |
| --body "Automated snapshot of the canonical catalog contract from LamPPKK/Smart-Movie-iOS@$CONTRACT_COMMIT. Merge only after Android and desktop conformance CI passes." | |
| fi |