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 --configuration=ci 21 - run: npx nx affected -t build --parallel=3 22

The pr and main jobs implement the CI workflow. Setting timeout-minutes is needed only if you have very slow tasks.

Tracking the origin branch

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 24

You 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 10 NX_CLOUD_DISTRIBUTED_EXECUTION_AGENT_COUNT: 3 11 NX_BRANCH: ${{ github.event.number || github.ref_name }} 12 NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} 13 NX_CLOUD_AUTH_TOKEN: ${{ secrets.NX_CLOUD_AUTH_TOKEN }} 14 NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 15 16jobs: 17 main: 18 name: Nx Cloud - Main Job 19 runs-on: ubuntu-latest 20 steps: 21 - uses: actions/checkout@v3 22 name: Checkout [Pull Request] 23 if: ${{ github.event_name == 'pull_request' }} 24 with: 25 # By default, PRs will be checked-out based on the Merge Commit, but we want the actual branch HEAD. 26 ref: ${{ github.event.pull_request.head.sha }} 27 # We need to fetch all branches and commits so that Nx affected has a base to compare against. 28 fetch-depth: 0 29 30 - uses: actions/checkout@v3 31 name: Checkout [Default Branch] 32 if: ${{ github.event_name != 'pull_request' }} 33 with: 34 # We need to fetch all branches and commits so that Nx affected has a base to compare against. 35 fetch-depth: 0 36 37 # Set node/npm/yarn versions using volta 38 - uses: volta-cli/action@v4 39 with: 40 package-json-path: '${{ github.workspace }}/package.json' 41 42 - name: Use the package manager cache if available 43 uses: actions/cache@v3 44 with: 45 path: ~/.npm 46 key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} 47 restore-keys: | 48 ${{ runner.os }}- 49 50 - name: Install dependencies 51 run: npm ci 52 53 - name: Initialize the Nx Cloud distributed CI run 54 run: npx nx-cloud start-ci-run 55 56 - name: Run commands in parallel 57 run: | 58 pids=() 59 # list of commands to be run on main has env flag NX_CLOUD_DISTRIBUTED_EXECUTION set to false 60 NX_CLOUD_DISTRIBUTED_EXECUTION=false npx nx-cloud record -- npx nx format:check & pids+=($!) 61 62 # list of commands to be run on agents 63 npx nx affected -t lint --parallel=3 & 64 pids+=($!) 65 66 npx nx affected -t test --parallel=3 --configuration=ci & 67 pids+=($!) 68 69 npx nx affected -t build --parallel=3 & 70 pids+=($!) 71 72 # run all commands in parallel and bail if one of them fails 73 for pid in ${pids[*]}; do 74 if ! wait $pid; then 75 exit 1 76 fi 77 done 78 79 exit 0 80 81 - name: Stop all running agents for this CI run 82 # 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 83 if: ${{ always() }} 84 run: npx nx-cloud stop-all-agents 85 86 agents: 87 name: Agent ${{ matrix.agent }} 88 runs-on: ubuntu-latest 89 strategy: 90 matrix: 91 agent: [1, 2, 3] 92 steps: 93 - name: Checkout 94 uses: actions/checkout@v3 95 96 # Set node/npm/yarn versions using volta 97 - uses: volta-cli/action@v4 98 with: 99 package-json-path: '${{ github.workspace }}/package.json' 100 101 - name: Use the package manager cache if available 102 uses: actions/cache@v3 103 with: 104 path: ~/.npm 105 key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} 106 restore-keys: | 107 ${{ runner.os }}- 108 109 - name: Install dependencies 110 run: npm ci 111 112 - name: Start Nx Agent ${{ matrix.agent }} 113 run: npx nx-cloud start-agent 114 env: 115 NX_AGENT_NAME: ${{ matrix.agent }} 116