diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..ca79ca5b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37e30ec4..66600641 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,8 +10,6 @@ name: ci # The T3 content tier asserts Pokemon Red facts; scripts/test.sh detects # data/generated/ is absent and skips it rather than failing. # -# Runs alongside release.yml, which is untouched by this file. - on: push: # Integration branch + release branch. PRs already run via pull_request @@ -24,7 +22,86 @@ concurrency: group: ci-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: + ios-changes: + name: detect iOS changes + runs-on: ubuntu-latest + outputs: + changed: ${{ steps.paths.outputs.changed }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - id: paths + env: + BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} + HEAD_SHA: ${{ github.sha }} + run: | + if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -Eq '^(mobile/ios/|scripts/build_ios\.sh$|\.github/workflows/(ci|release)\.yml$)'; then + echo "changed=true" >> "$GITHUB_OUTPUT" + else + echo "changed=false" >> "$GITHUB_OUTPUT" + fi + + ios-build: + name: iOS build + needs: ios-changes + if: needs.ios-changes.outputs.changed == 'true' + runs-on: ${{ fromJSON(github.repository == 'bryanthaboi/gen1recomp' && '["self-hosted", "macOS"]' || '"macos-latest"') }} + outputs: + ipa_url: ${{ steps.upload-ipa.outputs.artifact-url }} + steps: + - uses: actions/checkout@v4 + - name: import signing certificate + if: github.repository == 'bryanthaboi/gen1recomp' + run: | + keychain_path="$RUNNER_TEMP/gen1recomp-ci-signing.keychain-db" + ci_dir="${POKEMON_CI_DIR:-$HOME/.config/pokemon-ci}" + p12="$ci_dir/signing.p12" + passfile="$ci_dir/signing.pass" + [ -f "$p12" ] && [ -f "$passfile" ] || exit 1 + p12pw="$(cat "$passfile")" + kcpw="$(openssl rand -base64 24)" + echo "::add-mask::$kcpw" + security delete-keychain "$keychain_path" 2>/dev/null || true + security create-keychain -p "$kcpw" "$keychain_path" + security set-keychain-settings "$keychain_path" + security unlock-keychain -p "$kcpw" "$keychain_path" + security import "$p12" -P "$p12pw" -k "$keychain_path" -T /usr/bin/codesign -T /usr/bin/security + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$kcpw" "$keychain_path" >/dev/null + existing="$(security list-keychains -d user | sed -e 's/^[[:space:]]*//' -e 's/"//g')" + security list-keychains -d user -s "$keychain_path" $existing + - name: install xcbeautify + run: brew list xcbeautify >/dev/null 2>&1 || brew install xcbeautify + - name: build iOS release + env: + CANONICAL_REPOSITORY: ${{ github.repository == 'bryanthaboi/gen1recomp' }} + run: | + if [ "$CANONICAL_REPOSITORY" = true ]; then + scripts/build_ios.sh --fetch --device --release + else + scripts/build_ios.sh --fetch --release + fi + - name: upload iOS release artifact + id: upload-ipa + if: github.repository == 'bryanthaboi/gen1recomp' + uses: actions/upload-artifact@v4 + with: + name: gen1recomp-ios-ipa + path: dist/ios/gen1recomp.ipa + if-no-files-found: error + retention-days: 7 + - name: clean up signing keychain + if: ${{ always() && github.repository == 'bryanthaboi/gen1recomp' }} + run: security delete-keychain "$RUNNER_TEMP/gen1recomp-ci-signing.keychain-db" 2>/dev/null || true + headless: name: headless suites (no ROM) runs-on: ubuntu-latest diff --git a/.github/workflows/ios-artifact-comment.yml b/.github/workflows/ios-artifact-comment.yml new file mode 100644 index 00000000..7a3fe8b7 --- /dev/null +++ b/.github/workflows/ios-artifact-comment.yml @@ -0,0 +1,43 @@ +name: iOS artifact comment + +on: + workflow_run: + workflows: [ci] + types: [completed] + +permissions: + contents: read + pull-requests: write + +jobs: + comment: + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + steps: + - id: artifact + env: + GH_TOKEN: ${{ github.token }} + RUN_ID: ${{ github.event.workflow_run.id }} + HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} + HEAD_REPOSITORY: ${{ github.event.workflow_run.head_repository.full_name }} + run: | + artifact_id="$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$RUN_ID/artifacts" --jq '.artifacts[] | select(.name == "gen1recomp-ios-ipa") | .id')" + [ -n "$artifact_id" ] || exit 0 + head_owner="${HEAD_REPOSITORY%%/*}" + pr_number="$(gh api "repos/$GITHUB_REPOSITORY/pulls?state=open&head=$head_owner:$HEAD_BRANCH" --jq '.[0].number // empty')" + [ -n "$pr_number" ] || exit 0 + echo "artifact_url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$RUN_ID/artifacts/$artifact_id" >> "$GITHUB_OUTPUT" + echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT" + - name: comment iOS artifact + if: steps.artifact.outputs.pr_number != '' + uses: thollander/actions-comment-pull-request@v3 + with: + message: | + #### iOS Release IPA + + - [Download gen1recomp.ipa](${{ steps.artifact.outputs.artifact_url }}) + + Automatically generated. [View workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}) + pr-number: ${{ steps.artifact.outputs.pr_number }} + comment-tag: ios-build-result + github-token: ${{ github.token }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ca8c37e..efddc626 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,7 +42,7 @@ concurrency: jobs: release: - runs-on: [self-hosted, macOS] + runs-on: ${{ fromJSON(github.repository == 'bryanthaboi/gen1recomp' && '["self-hosted", "macOS"]' || '"macos-latest"') }} steps: # The self-hosted runner lives under the machine owner's home @@ -127,6 +127,7 @@ jobs: echo "tag=$tag" >> "$GITHUB_OUTPUT" - name: Import signing certificate into a temporary keychain + if: github.repository == 'bryanthaboi/gen1recomp' run: | set -euo pipefail KEYCHAIN_PATH="$RUNNER_TEMP/pokemon-signing.keychain-db" @@ -182,13 +183,17 @@ jobs: brew list xcbeautify >/dev/null 2>&1 || brew install xcbeautify - name: Build iOS + env: + CANONICAL_REPOSITORY: ${{ github.repository == 'bryanthaboi/gen1recomp' }} run: | set -euo pipefail - # Device Release IPA; signs with the Apple Development identity on - # the runner (auto team detection). Users on other Apple IDs still - # re-sign or build via docs/ios-install.md. - scripts/build_ios.sh --fetch --device --release \ - --version "${{ steps.ver.outputs.version }}" + if [ "$CANONICAL_REPOSITORY" = true ]; then + scripts/build_ios.sh --fetch --device --release \ + --version "${{ steps.ver.outputs.version }}" + else + scripts/build_ios.sh --fetch --release \ + --version "${{ steps.ver.outputs.version }}" + fi - name: Build Anbernic RG34XXSP port run: | @@ -198,6 +203,7 @@ jobs: ./build-rg34xxsp.sh --version "${{ steps.ver.outputs.version }}" - name: Notarize & staple macOS app + if: github.repository == 'bryanthaboi/gen1recomp' run: | set -euo pipefail ci_dir="${POKEMON_CI_DIR:-$HOME/.config/pokemon-ci}" @@ -232,6 +238,7 @@ jobs: echo "Notarized + stapled ✓" - name: Stage release assets + if: github.repository == 'bryanthaboi/gen1recomp' id: assets run: | set -euo pipefail @@ -271,6 +278,7 @@ jobs: cat "$outdir/sha256sums.txt" - name: Publish GitHub Release + if: github.repository == 'bryanthaboi/gen1recomp' env: GH_TOKEN: ${{ github.token }} run: | @@ -376,6 +384,6 @@ jobs: echo "Published release $tag" - name: Clean up signing keychain - if: always() + if: ${{ always() && github.repository == 'bryanthaboi/gen1recomp' }} run: | security delete-keychain "$RUNNER_TEMP/pokemon-signing.keychain-db" 2>/dev/null || true