Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,68 +6,136 @@
pull_request:

jobs:
# Docs-only pull requests skip the heavy work. The workflow still triggers on every PR, because
# its jobs are required status checks and a paths-ignore would leave them pending forever.
# Instead this job decides, and the jobs below still run (and report) but skip their heavy
# steps, passing in seconds. Only a pull_request run can skip: push, merge_group, schedule,
# workflow_dispatch and workflow_call always run in full. So does anything unexpected (git
# error, empty diff, this job failing). The patterns live in scripts/docs-only-changes.sh.
changes:
runs-on: ubuntu-latest
outputs:
docs_only: ${{ steps.decide.outputs.docs_only }}
steps:
- name: Checkout
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
fetch-depth: 0 # the diff needs the base branch and the merge base

- name: Decide whether this is a docs-only change
id: decide
env:
EVENT: ${{ github.event_name }}
BASE_REF: ${{ github.base_ref }}
run: |
set -uo pipefail
if [ "$EVENT" != "pull_request" ]; then
echo "Event '$EVENT': full run."
echo "docs_only=false" >> "$GITHUB_OUTPUT"
exit 0
fi
# --no-renames: a file moved into docs/ shows as delete + add, so it still counts as code.
if ! files="$(git -c core.quotePath=false diff --name-only --no-renames "origin/$BASE_REF...HEAD")"; then
echo "::warning::Could not list changed files against origin/$BASE_REF; running everything."
echo "docs_only=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Changed files:"; printf '%s\n' "$files" | sed 's/^/ /'
verdict="$(printf '%s\n' "$files" | bash scripts/docs-only-changes.sh)" || verdict=""
[ "$verdict" = "docs_only=true" ] || verdict="docs_only=false"
echo "$verdict" >> "$GITHUB_OUTPUT"

library:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
name: Lint · Typecheck · Build · Codegen
needs: changes
if: ${{ !cancelled() }}
runs-on: ubuntu-latest
steps:
- name: Docs-only change — skipped
if: needs.changes.outputs.docs_only == 'true'
run: echo "::notice title=library::docs-only change — skipped"

- uses: actions/checkout@v4
if: needs.changes.outputs.docs_only != 'true'

- uses: actions/setup-node@v4
if: needs.changes.outputs.docs_only != 'true'
with:
node-version: 20
cache: npm

- name: Install dependencies
if: needs.changes.outputs.docs_only != 'true'
run: npm ci

- name: Lint
if: needs.changes.outputs.docs_only != 'true'
run: npm run lint

- name: Typecheck
if: needs.changes.outputs.docs_only != 'true'
run: npm run typecheck

- name: Build package (react-native-builder-bob)
if: needs.changes.outputs.docs_only != 'true'
run: npm run prepare

- name: Validate native codegen spec
if: needs.changes.outputs.docs_only != 'true'
run: node node_modules/react-native/scripts/generate-codegen-artifacts.js -p . -o "${RUNNER_TEMP}/codegen" -t all

example-android:
name: Example · JS + Android build
needs: changes
if: ${{ !cancelled() }}
runs-on: ubuntu-latest
steps:
- name: Docs-only change — skipped
if: needs.changes.outputs.docs_only == 'true'
run: echo "::notice title=example-android::docs-only change — skipped"

- uses: actions/checkout@v4
if: needs.changes.outputs.docs_only != 'true'

- uses: actions/setup-node@v4
if: needs.changes.outputs.docs_only != 'true'
with:
node-version: 20
cache: npm

- uses: actions/setup-java@v4
if: needs.changes.outputs.docs_only != 'true'
with:
distribution: temurin
java-version: 17

- name: Set up Gradle cache
if: needs.changes.outputs.docs_only != 'true'
uses: gradle/actions/setup-gradle@v4

- name: Install library dependencies
if: needs.changes.outputs.docs_only != 'true'
run: npm ci

- name: Install example dependencies
if: needs.changes.outputs.docs_only != 'true'
working-directory: example
run: npm install --no-audit --no-fund

- name: Typecheck example
if: needs.changes.outputs.docs_only != 'true'
working-directory: example
run: npx tsc --noEmit

- name: Bundle JS (Android + iOS)
if: needs.changes.outputs.docs_only != 'true'
working-directory: example
run: |
npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output "${RUNNER_TEMP}/android.bundle" --assets-dest "${RUNNER_TEMP}/android-assets"
npx react-native bundle --platform ios --dev false --entry-file index.js --bundle-output "${RUNNER_TEMP}/ios.bundle" --assets-dest "${RUNNER_TEMP}/ios-assets"

- name: Build debug APK
if: needs.changes.outputs.docs_only != 'true'
working-directory: example/android
run: ./gradlew :app:assembleDebug --no-daemon
42 changes: 42 additions & 0 deletions .github/workflows/ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,50 @@
pull_request:

jobs:
# Docs-only pull requests skip the heavy work. The workflow still triggers on every PR, because
# its jobs are required status checks and a paths-ignore would leave them pending forever.
# Instead this job decides, and the jobs below still run (and report) but skip their heavy
# steps, passing in seconds. Only a pull_request run can skip: push, merge_group, schedule,
# workflow_dispatch and workflow_call always run in full. So does anything unexpected (git
# error, empty diff, this job failing). The patterns live in scripts/docs-only-changes.sh.
changes:
runs-on: ubuntu-latest
outputs:
docs_only: ${{ steps.decide.outputs.docs_only }}
steps:
- name: Checkout
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
fetch-depth: 0 # the diff needs the base branch and the merge base

- name: Decide whether this is a docs-only change
id: decide
env:
EVENT: ${{ github.event_name }}
BASE_REF: ${{ github.base_ref }}
run: |
set -uo pipefail
if [ "$EVENT" != "pull_request" ]; then
echo "Event '$EVENT': full run."
echo "docs_only=false" >> "$GITHUB_OUTPUT"
exit 0
fi
# --no-renames: a file moved into docs/ shows as delete + add, so it still counts as code.
if ! files="$(git -c core.quotePath=false diff --name-only --no-renames "origin/$BASE_REF...HEAD")"; then
echo "::warning::Could not list changed files against origin/$BASE_REF; running everything."
echo "docs_only=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Changed files:"; printf '%s\n' "$files" | sed 's/^/ /'
verdict="$(printf '%s\n' "$files" | bash scripts/docs-only-changes.sh)" || verdict=""
[ "$verdict" = "docs_only=true" ] || verdict="docs_only=false"
echo "$verdict" >> "$GITHUB_OUTPUT"

ios:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
name: Build example (iOS simulator)
needs: changes
if: ${{ !cancelled() && needs.changes.outputs.docs_only != 'true' }}
runs-on: macos-15
steps:
- uses: actions/checkout@v4
Expand Down
45 changes: 45 additions & 0 deletions scripts/docs-only-changes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
#
# Decide whether a change set is docs-only, so CI can skip its heavy steps on a pull request that
# cannot affect them. Reads changed paths (one per line, repo-relative, as printed by
# `git diff --name-only --no-renames`) on stdin and prints exactly one line:
# docs_only=true every path is documentation
# docs_only=false at least one path is not, or the list is empty (fail safe: run everything)
#
# Documentation means: **/*.md docs/** LICENSE* .github/ISSUE_TEMPLATE/**
# .github/pull_request_template.md
# Matching is case-sensitive on purpose: anything unexpected runs the full suite.
#
# git diff --name-only --no-renames origin/main...HEAD | bash scripts/docs-only-changes.sh
#
# Exit codes: 0 always when stdin was read (the answer is on stdout), 2 usage error.
set -uo pipefail

if [ "$#" -ne 0 ]; then
echo "usage: <paths on stdin> | bash scripts/docs-only-changes.sh" >&2
exit 2
fi

seen=0
while IFS= read -r path || [ -n "$path" ]; do
path="${path%$'\r'}"
[ -z "$path" ] && continue
seen=$((seen + 1))
case "$path" in
*.md | docs/* | LICENSE* | .github/ISSUE_TEMPLATE/* | .github/pull_request_template.md) ;;
*)
echo "not docs: $path" >&2
echo "docs_only=false"
exit 0
;;
esac
done

if [ "$seen" -eq 0 ]; then
echo "no changed files listed; treating as a code change" >&2
echo "docs_only=false"
exit 0
fi

echo "all $seen changed file(s) are docs" >&2
echo "docs_only=true"
Loading