Configuring CI Using GitHub Actions and Nx
GitHub can track the last successful run on the main branch and use this as a reference point for the BASE. The Nx Set SHAs provides a convenient implementation of this functionality which you can drop into your existing CI config. To understand why knowing the last successful build is important for the affected command, check out the in-depth explanation in Actions's docs.
Below is an example of a GitHub setup for an Nx workspace - building and testing only what is affected. For more details on how the action is used, head over to the official docs.
1name: CI
2on:
3  push:
4    branches:
5      - main
6  pull_request:
7
8jobs:
9  main:
10    runs-on: ubuntu-latest
11    steps:
12      - uses: actions/checkout@v3
13        with:
14          fetch-depth: 0
15      - uses: nrwl/nx-set-shas@v3
16      - run: npm ci
17
18      - run: npx nx format:check
19      - run: npx nx affected -t lint --parallel=3
20      - run: npx nx affected -t test --parallel=3
21      - run: npx nx affected -t build --parallel=3
22The pr and main jobs implement the CI workflow. Setting timeout-minutes is needed only if you have very slow tasks.
If you're using this action in the context of a branch you may need to add run: "git branch --track main origin/main" before running the nx affected command since origin/main won't exist.
Distributed CI with Nx Cloud
Read more about Distributed Task Execution (DTE).
1name: CI
2on:
3  push:
4    branches:
5      - main
6  pull_request:
7
8jobs:
9  main:
10    name: Nx Cloud - Main Job
11    uses: nrwl/ci/.github/workflows/nx-cloud-main.yml@v0.13.0
12    with:
13      number-of-agents: 3
14      parallel-commands: |
15        npx nx-cloud record -- npx nx format:check
16      parallel-commands-on-agents: |
17        npx nx affected -t lint --parallel=3 & npx nx affected -t test --parallel=3 --configuration=ci & npx nx affected -t build --parallel=3
18
19  agents:
20    name: Nx Cloud - Agents
21    uses: nrwl/ci/.github/workflows/nx-cloud-agents.yml@v0.13.0
22    with:
23      number-of-agents: 3
24You can also use our ci-workflow generator to generate the workflow file.
Custom distributed CI with Nx Cloud
Our reusable GitHub workflow represents a good set of defaults that works for a large number of our users. However, reusable GitHub workflows come with their limitations.
If the existing workflow doesn't satisfy your needs you should create your custom workflow. This is what the above config roughly encapsulates:
1name: CI
2on:
3  push:
4    branches:
5      - main
6  pull_request:
7
8env:
9  NX_CLOUD_DISTRIBUTED_EXECUTION: true # this enables DTE
10  NX_CLOUD_DISTRIBUTED_EXECUTION_AGENT_COUNT: 3 # expected number of agents
11  NX_BRANCH: ${{ github.event.number || github.ref_name }}
12  NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
13  NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # this is needed if our pipeline publishes to npm
14
15jobs:
16  main:
17    name: Nx Cloud - Main Job
18    runs-on: ubuntu-latest
19    steps:
20      - uses: actions/checkout@v3
21        name: Checkout [Pull Request]
22        if: ${{ github.event_name == 'pull_request' }}
23        with:
24          # By default, PRs will be checked-out based on the Merge Commit, but we want the actual branch HEAD.
25          ref: ${{ github.event.pull_request.head.sha }}
26          # We need to fetch all branches and commits so that Nx affected has a base to compare against.
27          fetch-depth: 0
28
29      - uses: actions/checkout@v3
30        name: Checkout [Default Branch]
31        if: ${{ github.event_name != 'pull_request' }}
32        with:
33          # We need to fetch all branches and commits so that Nx affected has a base to compare against.
34          fetch-depth: 0
35
36      # Set node/npm/yarn versions using volta
37      - uses: volta-cli/action@v4
38        with:
39          package-json-path: '${{ github.workspace }}/package.json'
40
41      - name: Use the package manager cache if available
42        uses: actions/cache@v3
43        with:
44          path: ~/.npm
45          key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
46          restore-keys: |
47            ${{ runner.os }}-
48
49      - name: Install dependencies
50        run: npm ci
51
52      - name: Initialize the Nx Cloud distributed CI run
53        run: npx nx-cloud start-ci-run
54
55      - name: Run commands in parallel
56        run: |
57          pids=()
58          # list of commands to be run on main has env flag NX_CLOUD_DISTRIBUTED_EXECUTION set to false
59          NX_CLOUD_DISTRIBUTED_EXECUTION=false npx nx-cloud record -- npx nx format:check & pids+=($!)
60
61          # list of commands to be run on agents
62          npx nx affected -t lint --parallel=3 & 
63          pids+=($!)
64
65          npx nx affected -t test --parallel=3 & 
66          pids+=($!)
67
68          npx nx affected -t build --parallel=3 & 
69          pids+=($!)
70
71          # run all commands in parallel and bail if one of them fails
72          for pid in ${pids[*]}; do
73            if ! wait $pid; then
74              exit 1
75            fi
76          done
77
78          exit 0
79
80      - name: Stop all running agents for this CI run
81        # It's important that we always run this step, otherwise in the case of any failures in preceding non-Nx steps, the agents will keep running and waste billable minutes
82        if: ${{ always() }}
83        run: npx nx-cloud stop-all-agents
84
85  agents:
86    name: Agent ${{ matrix.agent }}
87    runs-on: ubuntu-latest
88    strategy:
89      matrix:
90        agent: [1, 2, 3]
91    steps:
92      - name: Checkout
93        uses: actions/checkout@v3
94
95      # Set node/npm/yarn versions using volta
96      - uses: volta-cli/action@v4
97        with:
98          package-json-path: '${{ github.workspace }}/package.json'
99
100      - name: Use the package manager cache if available
101        uses: actions/cache@v3
102        with:
103          path: ~/.npm
104          key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
105          restore-keys: |
106            ${{ runner.os }}-
107
108      - name: Install dependencies
109        run: npm ci
110
111      - name: Start Nx Agent ${{ matrix.agent }}
112        run: npx nx-cloud start-agent
113        env:
114          NX_AGENT_NAME: ${{ matrix.agent }}
115