Skip to content
Closed
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
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,14 @@ jobs:
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: node tools/ci/classifyToolchains.mjs

# Always call Node so required `Node / *` checks are reported. Jobs inside
# skip when Node is unaffected; GitHub treats skipped jobs as passing.
node:
name: Node
needs: changes
if: needs.changes.outputs.node == 'true'
uses: ./.github/workflows/node.yml
with:
affected: ${{ needs.changes.outputs.node == 'true' }}

android:
name: Android
Expand Down
21 changes: 19 additions & 2 deletions .github/workflows/node.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@ name: Node

on:
workflow_call:
inputs:
affected:
description: When false, jobs skip so required Node checks still report a passing status
type: boolean
default: true
workflow_dispatch:
inputs:
affected:
description: When false, jobs skip so required Node checks still report a passing status
type: boolean
default: true

concurrency:
group: Node-${{github.ref_name}}-${{github.event_name == 'pull_request' && github.event.pull_request.number || github.sha}}
Expand All @@ -20,6 +30,7 @@ env:
jobs:
validate:
name: Validate
if: ${{ inputs.affected == true }}
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
Expand All @@ -43,6 +54,7 @@ jobs:

lint:
name: Lint
if: ${{ inputs.affected == true }}
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
Expand All @@ -63,6 +75,7 @@ jobs:

format:
name: Format
if: ${{ inputs.affected == true }}
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
Expand All @@ -78,6 +91,7 @@ jobs:

test:
name: Test
if: ${{ inputs.affected == true }}
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
Expand All @@ -93,6 +107,7 @@ jobs:

typecheck:
name: Typecheck
if: ${{ inputs.affected == true }}
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
Expand All @@ -108,6 +123,7 @@ jobs:

build:
name: Build
if: ${{ inputs.affected == true }}
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
Expand All @@ -125,7 +141,7 @@ jobs:
name: Depcheck
runs-on: ubuntu-latest
# Only run on master pushes (to cache baseline) or PRs targeting master (to compare)
if: github.ref_name == 'master' || (github.event_name == 'pull_request' && github.base_ref == 'master')
if: ${{ inputs.affected == true && (github.ref_name == 'master' || (github.event_name == 'pull_request' && github.base_ref == 'master')) }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
Expand Down Expand Up @@ -171,7 +187,7 @@ jobs:
name: Bundle Stats
runs-on: ubuntu-latest
# Only run on master pushes (to cache baseline) or PRs targeting master (to compare)
if: github.ref_name == 'master' || (github.event_name == 'pull_request' && github.base_ref == 'master')
if: ${{ inputs.affected == true && (github.ref_name == 'master' || (github.event_name == 'pull_request' && github.base_ref == 'master')) }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
Expand Down Expand Up @@ -220,6 +236,7 @@ jobs:

lint-styles:
name: Lint Styles
if: ${{ inputs.affected == true }}
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
Expand Down
13 changes: 8 additions & 5 deletions docs/ci.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# CI architecture

[`.github/workflows/ci.yml`](../.github/workflows/ci.yml) is the pull-request orchestrator. It
classifies changed paths by toolchain, then starts only the required lanes.
classifies changed paths by toolchain, then starts the native lanes that need to run. The Node
lane is always started so required checks are reported; its jobs skip when Node is unaffected.

## Toolchain tags

Expand All @@ -18,8 +19,10 @@ product surface, but CI scheduling is based on the toolchain classification.

The orchestrator determines whether Node, Gradle, or Xcode paths changed:

- Node changes call the reusable [Node workflow](../.github/workflows/node.yml). Its Linux jobs use
`nx affected` plus `toolchain:node`, so only affected Node projects with the requested target run.
- The [Node workflow](../.github/workflows/node.yml) is always called so required `Node / *`
checks are reported. When Node paths changed, its Linux jobs use `nx affected` plus
`toolchain:node`. When they did not, each Node job is skipped; GitHub treats skipped jobs as
passing, so native-only PRs are not blocked waiting for Node.
- Gradle changes call the reusable [Android workflow](../.github/workflows/android.yml), which
builds and tests the Android library and demo app with JDK 21 and the Android SDK.
- Xcode changes call the reusable [iOS workflow](../.github/workflows/ios.yml), which builds
Expand All @@ -30,8 +33,8 @@ This keeps toolchains isolated while preserving dependency-aware validation:
- A web-only change does not run React Native, Android, or iOS work.
- A change to a shared Node dependency may affect multiple dependent Node projects, such as both
web and React Native packages.
- An Android-only change runs the Gradle lane without Node or Xcode jobs.
- An iOS-only change runs the Xcode lane without Node or Gradle jobs.
- An Android-only change runs the Gradle and skipped-Node lanes without Xcode jobs.
- An iOS-only change runs the Xcode and skipped-Node lanes without Gradle jobs.
- Changes to centralized CI or Nx classification files safely enable all toolchains.

Manually dispatching `ci.yml` enables every toolchain. The reusable Android and iOS workflows can
Expand Down
4 changes: 2 additions & 2 deletions docs/nx.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ executor does not solve the problem because both Node and native projects primar

Nx 20 cannot use the tags to select `targetDefaults`, but CI already depends on them:

1. The change classifier maps a changed project root to its `toolchain:*` tag and selects the Node,
Gradle, or Xcode workflow.
1. The change classifier maps a changed project root to its `toolchain:*` tag and decides which
of the Node, Gradle, or Xcode workflows should execute work.
2. The Node workflow positively filters `nx affected` to `toolchain:node`, preventing native
`build` and `test` targets from running on Node-only Linux jobs.
3. The validator rejects missing or conflicting tags so a new project cannot silently enter the
Expand Down
Loading