61b3f29bc5
Dependabot pushes in-repo branches, so its PRs pass the fork guard and the per-PR OTA job runs — but GitHub withholds repo secrets from Dependabot- triggered runs, so EXPO_TOKEN is empty and the job fails at "Setup Expo project". Result: a red check on every dependabot PR (fails closed, nothing reaches AWS, but it's noise on an unrelated PR). Exclude bot authors via user.type. This keeps the fork guard as the trust boundary and does not reintroduce the author_association check, which wrongly skipped private org members' PRs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
328 lines
12 KiB
YAML
328 lines
12 KiB
YAML
# Credit for fingerprint action https://github.com/expo/expo
|
||
# https://github.com/expo/expo/blob/main/.github/workflows/pr-labeler.yml
|
||
---
|
||
name: PR Tests
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
pull_request:
|
||
types: [opened, synchronize]
|
||
|
||
concurrency:
|
||
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
# Permissions are granted per-job below; anything unlisted defaults to none.
|
||
# pull-requests: write is needed by sticky-pull-request-comment to post the
|
||
# bundle-size and fingerprint diffs
|
||
permissions: {}
|
||
|
||
# denis release tag in bluesky-social/tango whose linux-amd64 binary the PR OTA
|
||
# job downloads. Bump this one line to roll denis.
|
||
env:
|
||
DENIS_RELEASE_TAG: denis-v0.1.1
|
||
|
||
jobs:
|
||
# Populate this from main so every PR can restore the same trusted baseline.
|
||
webpack-analyzer-base:
|
||
runs-on: ubuntu-24.04
|
||
if: ${{ github.event_name == 'push' }}
|
||
permissions:
|
||
contents: read
|
||
steps:
|
||
- name: ⬇️ Checkout
|
||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||
|
||
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
|
||
|
||
- name: 🔧 Setup Node
|
||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||
with:
|
||
node-version-file: package.json
|
||
cache: pnpm
|
||
|
||
- name: ⬇️ Get base stats from cache
|
||
id: get-base-stats
|
||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||
with:
|
||
path: stats.json
|
||
key: stats-base-main-${{ github.sha }}
|
||
|
||
- name: 🔦 Generate stats file for base commit
|
||
if: ${{ !steps.get-base-stats.outputs.cache-hit }}
|
||
run: |
|
||
pnpm install
|
||
pnpm intl:build
|
||
pnpm generate-webpack-stats-file
|
||
|
||
- name: ⬆️ Save base stats to cache
|
||
if: ${{ !steps.get-base-stats.outputs.cache-hit }}
|
||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||
with:
|
||
path: stats.json
|
||
key: stats-base-main-${{ github.sha }}
|
||
|
||
webpack-analyzer:
|
||
runs-on: ubuntu-24.04
|
||
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.event_name == 'pull_request'}}
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
steps:
|
||
- name: ⬇️ Checkout
|
||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
|
||
|
||
- name: 🔧 Setup Node
|
||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||
with:
|
||
node-version-file: package.json
|
||
cache: pnpm
|
||
|
||
- name: Ensure tracking relevant branches and checkout base
|
||
env:
|
||
HEAD_REF: ${{ github.head_ref }}
|
||
BASE_REF: ${{ github.base_ref }}
|
||
run: |
|
||
git checkout $HEAD_REF
|
||
git checkout $BASE_REF
|
||
|
||
- name: Get the base commit
|
||
id: base-commit
|
||
env:
|
||
BASE_REF: ${{ github.base_ref }}
|
||
run: echo base-commit=$(git log -n 1 $BASE_REF --pretty=format:'%H') >> "$GITHUB_OUTPUT"
|
||
|
||
- name: Merge PR commit
|
||
env:
|
||
HEAD_REF: ${{ github.head_ref }}
|
||
run: |
|
||
# Have to set a git config for the merge to work
|
||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||
git config --global user.name "github-actions[bot]"
|
||
git merge --no-edit $HEAD_REF
|
||
pnpm install
|
||
pnpm intl:build
|
||
|
||
- name: 🔦 Generate stats file for PR
|
||
run: |
|
||
pnpm generate-webpack-stats-file
|
||
mv stats.json ../stats-new.json
|
||
|
||
- name: ⬇️ Get base stats from cache
|
||
id: get-base-stats
|
||
# Restore-only prevents PR-scoped fallback builds from creating caches.
|
||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||
with:
|
||
path: stats.json
|
||
key: stats-base-main-${{ steps.base-commit.outputs.base-commit }}
|
||
|
||
- name: Restore to base commit
|
||
if: ${{ !steps.get-base-stats.outputs.cache-hit }}
|
||
env:
|
||
BASE_COMMIT: ${{ steps.base-commit.outputs.base-commit }}
|
||
run: |
|
||
git reset "$BASE_COMMIT"
|
||
git restore .
|
||
|
||
- name: 🔦 Generate stats file from base commit
|
||
if: ${{ !steps.get-base-stats.outputs.cache-hit }}
|
||
run: |
|
||
pnpm install
|
||
pnpm intl:build
|
||
pnpm generate-webpack-stats-file
|
||
|
||
- name: % Get diff
|
||
id: get-diff
|
||
uses: NejcZdovc/bundle-size-diff@5321de41d2d62a7b0f4d6e60f59d1280a0034160 # v1.1.0
|
||
with:
|
||
base_path: "stats.json"
|
||
pr_path: "../stats-new.json"
|
||
excluded_assets: "(.+).chunk.js|(.+).js.map|(.+).json|(.+).png|(.+).svg|(.+).webp|(.+).jpg|(.+).ico"
|
||
|
||
- name: 💬 Drop a comment
|
||
uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5
|
||
with:
|
||
header: bundle-diff
|
||
message: |
|
||
| Old size | New size | Diff |
|
||
|----------|----------|-----------------------|
|
||
| ${{ steps.get-diff.outputs.base_file_string }} | ${{ steps.get-diff.outputs.pr_file_string }} | ${{ steps.get-diff.outputs.diff_file_string }} (${{ steps.get-diff.outputs.percent }}%) |
|
||
---
|
||
|
||
fingerprint-native:
|
||
runs-on: ubuntu-22.04
|
||
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.event_name == 'pull_request'}}
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
steps:
|
||
- name: ⬇️ Checkout
|
||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||
with:
|
||
fetch-depth: 100
|
||
|
||
- name: ⬇️ Fetch commits from base branch
|
||
run: git fetch origin main:main --depth 100
|
||
if: github.event_name == 'pull_request'
|
||
|
||
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
|
||
|
||
- name: 🔧 Setup Node
|
||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||
with:
|
||
node-version-file: package.json
|
||
cache: pnpm
|
||
|
||
- name: 📷 Check fingerprint and install dependencies
|
||
id: fingerprint
|
||
timeout-minutes: 5
|
||
uses: bluesky-social/github-actions/fingerprint-native@b5556913e4aef3964cfd5936d0add3fc0d809bdb # v0.2.0
|
||
with:
|
||
profile: pull-request
|
||
|
||
- name: 💬 Drop a comment
|
||
uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5
|
||
if: ${{ steps.fingerprint.outputs.includes-changes }}
|
||
with:
|
||
header: fingerprint-diff
|
||
message: |
|
||
The Pull Request introduced fingerprint changes against the base commit:
|
||
<details><summary>Fingerprint diff</summary>
|
||
|
||
```json
|
||
${{ steps.fingerprint.outputs.diff }}
|
||
```
|
||
|
||
</details>
|
||
|
||
---
|
||
*Generated by [PR labeler](https://github.com/expo/expo/actions/workflows/pr-labeler.yml) 🤖*
|
||
|
||
- name: 💬 Delete comment
|
||
uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5
|
||
if: ${{ !steps.fingerprint.outputs.includes-changes }}
|
||
with:
|
||
header: fingerprint-diff
|
||
delete: true
|
||
|
||
- name: 🏷️ Label as fingerprint changed
|
||
if: ${{ steps.fingerprint.outputs.includes-changes }}
|
||
env:
|
||
GH_TOKEN: ${{ github.token }}
|
||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||
run: |
|
||
gh pr edit "$PR_NUMBER" --add-label "bot: fingerprint changed" || true
|
||
|
||
- name: 🏷️ Remove fingerprint changed label
|
||
if: ${{ !steps.fingerprint.outputs.includes-changes }}
|
||
env:
|
||
GH_TOKEN: ${{ github.token }}
|
||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||
run: |
|
||
gh pr edit "$PR_NUMBER" --remove-label "bot: fingerprint changed" || true
|
||
|
||
# Automatic per-PR OTA preview, published to the pull-request-<N> channel on
|
||
# denis. Replaces the old `@github-actions ota` comment trigger. Gated to
|
||
# same-repo PRs (fork guard): a branch can only exist in this repo if someone
|
||
# with write access pushed it, so an outside contributor (who can only open a
|
||
# PR from a fork) never runs this job with the denis publish role in scope.
|
||
# This matches the fork-guard gate the other jobs in this workflow use;
|
||
# author_association is deliberately NOT checked (it can't identify a private
|
||
# org member and would skip their PRs).
|
||
#
|
||
# Bot authors are excluded: Dependabot pushes in-repo branches, so it passes
|
||
# the fork guard, but GitHub withholds repo secrets from Dependabot-triggered
|
||
# runs. EXPO_TOKEN is then empty and the job fails at setup — a red check on
|
||
# every dependabot PR. There is no OTA preview worth publishing for a
|
||
# dependency bump anyway.
|
||
publish-pr-ota:
|
||
name: Publish PR OTA to denis
|
||
runs-on: ubuntu-latest
|
||
if: >-
|
||
github.event_name == 'pull_request' &&
|
||
github.event.pull_request.head.repo.full_name == github.repository &&
|
||
github.event.pull_request.user.type != 'Bot'
|
||
concurrency:
|
||
group: pr-ota-${{ github.event.pull_request.number }}
|
||
cancel-in-progress: true
|
||
permissions:
|
||
id-token: write
|
||
contents: read
|
||
steps:
|
||
- name: ⬇️ Checkout
|
||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||
with:
|
||
ref: ${{ github.event.pull_request.head.sha }}
|
||
|
||
- name: 🛠️ Setup Expo project
|
||
uses: ./.github/actions/setup-expo-project
|
||
with:
|
||
expo-token: ${{ secrets.EXPO_TOKEN }}
|
||
|
||
- name: 🔤 Compile translations
|
||
uses: ./.github/actions/compile-i18n
|
||
|
||
- name: ✏️ Write environment variables
|
||
id: env
|
||
uses: ./.github/actions/write-env
|
||
with:
|
||
env-token: ${{ secrets.ENV_TOKEN }}
|
||
sentry-dsn: ${{ secrets.SENTRY_DSN }}
|
||
bitdrift-api-key: ${{ secrets.BITDRIFT_API_KEY }}
|
||
gcp-project-id: ${{ secrets.EXPO_PUBLIC_GCP_PROJECT_ID }}
|
||
google-services-token: ${{ secrets.GOOGLE_SERVICES_TOKEN }}
|
||
expo-public-env: testflight
|
||
|
||
- name: 🏗️ Create Bundle
|
||
run: >
|
||
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
|
||
SENTRY_RELEASE=${{ steps.env.outputs.release-version }}
|
||
SENTRY_DIST=${{ steps.env.outputs.bundle-identifier }}
|
||
pnpm export
|
||
|
||
- name: ☁️ Configure AWS credentials (denis, PR-scoped)
|
||
uses: aws-actions/configure-aws-credentials@254c19bd240aabef8777f48595e9d2d7b972184b # v6.2.1
|
||
with:
|
||
role-to-assume: arn:aws:iam::007404326489:role/denis-ci-publish-pr
|
||
aws-region: us-east-2
|
||
# Defense-in-depth: the base role is already scoped to pr/*, but narrow
|
||
# this session further to just THIS PR's prefix so a bug can't write to
|
||
# another PR's objects or the prod tree.
|
||
inline-session-policy: |-
|
||
{
|
||
"Version": "2012-10-17",
|
||
"Statement": [
|
||
{
|
||
"Effect": "Allow",
|
||
"Action": ["s3:PutObject", "s3:DeleteObject"],
|
||
"Resource": "arn:aws:s3:::bsky-denis-ota-prod/pr/${{ github.event.pull_request.number }}/*"
|
||
},
|
||
{
|
||
"Effect": "Allow",
|
||
"Action": "s3:ListBucket",
|
||
"Resource": "arn:aws:s3:::bsky-denis-ota-prod",
|
||
"Condition": {
|
||
"StringLike": { "s3:prefix": "pr/${{ github.event.pull_request.number }}/*" }
|
||
}
|
||
}
|
||
]
|
||
}
|
||
|
||
- name: ⬇️ Setup denis CLI
|
||
uses: ./.github/actions/setup-denis
|
||
with:
|
||
release-tag: ${{ env.DENIS_RELEASE_TAG }}
|
||
app-id: ${{ vars.SYNC_INTERNAL_APP_ID }}
|
||
private-key: ${{ secrets.SYNC_INTERNAL_PK }}
|
||
|
||
- name: 🚀 Publish OTA to denis (S3)
|
||
run: pnpm use-build-number bash scripts/denisPublish.sh
|
||
env:
|
||
RUNTIME_VERSION: ''
|
||
CHANNEL_NAME: pull-request-${{ github.event.pull_request.number }}
|