-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5d2cbbd
Showing
7 changed files
with
527 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
name: Nx Cloud Agents | ||
|
||
on: | ||
workflow_call: | ||
inputs: | ||
number-of-agents: | ||
required: true | ||
type: number | ||
node-version: | ||
required: false | ||
type: string | ||
yarn-version: | ||
required: false | ||
type: string | ||
npm-version: | ||
required: false | ||
type: string | ||
install-command: | ||
required: false | ||
type: string | ||
|
||
env: | ||
NX_CLOUD_DISTRIBUTED_EXECUTION: true | ||
|
||
jobs: | ||
set-agents: | ||
runs-on: ubuntu-latest | ||
name: Init | ||
outputs: | ||
matrix: ${{ steps.set-matrix.outputs.matrix }} | ||
steps: | ||
- id: set-matrix | ||
# Turn the number-of-agents input into a JSON structure which is compatible with a Github job matrix strategy | ||
run: | | ||
AGENTS_JSON_ARRAY=$(node -e "console.log(JSON.stringify(Array.from(new Array(${{ inputs.number-of-agents }})).map((_, i) => i + 1)));") | ||
echo $AGENTS_JSON_ARRAY | ||
echo "::set-output name=matrix::$AGENTS_JSON_ARRAY" | ||
# Intentionally using capital letter in order to make the Github UI for the matrix look better | ||
Run: | ||
needs: set-agents | ||
runs-on: ubuntu-latest | ||
name: Agent ${{ matrix.agent }} | ||
strategy: | ||
matrix: | ||
agent: | ||
- ${{fromJson(needs.set-agents.outputs.matrix)}} | ||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
# Set node/npm/yarn versions using volta, with optional overrides provided by the consumer | ||
- uses: volta-cli/action@fdf4cf319494429a105efaa71d0e5ec67f338c6e | ||
with: | ||
node-version: '${{ inputs.node-version }}' | ||
npm-version: '${{ inputs.npm-version }}' | ||
yarn-version: '${{ inputs.yarn-version }}' | ||
|
||
- name: Print node/npm/yarn versions | ||
id: print-versions | ||
run: | | ||
node --version | ||
npm --version | ||
yarn --version || true | ||
echo "::set-output name=use_yarn::$([[ -f ./yarn.lock ]] && echo "true" || echo "false")" | ||
- name: Get node version for cache key | ||
id: cache-key | ||
run: echo "::set-output name=node_version::$(node --version)" | ||
|
||
- name: Use the node_modules cache if available [npm] | ||
if: steps.print-versions.outputs.use_yarn != 'true' | ||
uses: actions/cache@v2 | ||
with: | ||
path: ~/.npm | ||
key: ${{ runner.os }}-node-${{ steps.cache-key.outputs.node_version }}-${{ hashFiles('**/package-lock.json') }} | ||
restore-keys: | | ||
${{ runner.os }}-node-${{ steps.cache-key.outputs.node_version }}- | ||
- name: Get yarn cache directory path | ||
if: steps.print-versions.outputs.use_yarn == 'true' | ||
id: yarn-cache-dir-path | ||
run: echo "::set-output name=dir::$(yarn cache dir)" | ||
|
||
- name: Use the node_modules cache if available [yarn] | ||
if: steps.print-versions.outputs.use_yarn == 'true' | ||
uses: actions/cache@v2 | ||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) | ||
with: | ||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }} | ||
key: ${{ runner.os }}-node-${{ steps.yarn-cache-dir-path.outputs.node_version }}-yarn-${{ hashFiles('**/yarn.lock') }} | ||
restore-keys: | | ||
${{ runner.os }}-node-${{ steps.yarn-cache-dir-path.outputs.node_version }}-yarn- | ||
- name: Install dependencies | ||
run: | | ||
if [ -n "${{ inputs.install-command }}" ]; then | ||
echo "Running custom install-command: ${{ inputs.install-command }}" | ||
${{ inputs.install-command }} | ||
elif [ "${{ steps.print-versions.outputs.use_yarn }}" == "true" ]; then | ||
echo "Running yarn install --frozen-lockfile" | ||
yarn install --frozen-lockfile | ||
else | ||
echo "Running npm ci" | ||
npm ci | ||
fi | ||
- name: Start Nx Agent ${{ matrix.agent }} | ||
run: npx nx-cloud start-agent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
name: Nx Cloud Main | ||
|
||
on: | ||
workflow_call: | ||
inputs: | ||
init-commands: | ||
required: false | ||
type: string | ||
final-commands: | ||
required: false | ||
type: string | ||
parallel-commands: | ||
required: false | ||
type: string | ||
parallel-commands-on-agents: | ||
required: false | ||
type: string | ||
node-version: | ||
required: false | ||
type: string | ||
yarn-version: | ||
required: false | ||
type: string | ||
npm-version: | ||
required: false | ||
type: string | ||
install-command: | ||
required: false | ||
type: string | ||
main-branch-name: | ||
required: false | ||
type: string | ||
default: main | ||
|
||
env: | ||
NX_CLOUD_DISTRIBUTED_EXECUTION: true | ||
NX_BRANCH: ${{ github.event.number || github.ref_name }} | ||
|
||
jobs: | ||
main: | ||
runs-on: ubuntu-latest | ||
# The name of the job which will invoke this one is expected to be "Nx Cloud - Main Job", and whatever we call this will be appended | ||
# to that one after a forward slash, so we keep this one intentionally short to produce "Nx Cloud - Main Job / Run" in the Github UI | ||
name: Run | ||
steps: | ||
- uses: actions/checkout@v2 | ||
name: Checkout [Pull Request] | ||
if: ${{ github.event_name == 'pull_request' }} | ||
with: | ||
# By default, PRs will be checked-out based on the Merge Commit, but we want the actual branch HEAD. | ||
ref: ${{ github.event.pull_request.head.sha }} | ||
# We need to fetch all branches and commits so that Nx affected has a base to compare against. | ||
fetch-depth: 0 | ||
|
||
- uses: actions/checkout@v2 | ||
name: Checkout [Default Branch] | ||
if: ${{ github.event_name != 'pull_request' }} | ||
with: | ||
# We need to fetch all branches and commits so that Nx affected has a base to compare against. | ||
fetch-depth: 0 | ||
|
||
- name: Derive appropriate SHAs for base and head for `nx affected` commands | ||
uses: nrwl/nx-set-shas@v2 | ||
with: | ||
main-branch-name: ${{ inputs.main-branch-name }} | ||
|
||
# Set node/npm/yarn versions using volta, with optional overrides provided by the consumer | ||
- uses: volta-cli/action@fdf4cf319494429a105efaa71d0e5ec67f338c6e | ||
with: | ||
node-version: '${{ inputs.node-version }}' | ||
npm-version: '${{ inputs.npm-version }}' | ||
yarn-version: '${{ inputs.yarn-version }}' | ||
|
||
- name: Print node/npm/yarn versions | ||
id: print-versions | ||
run: | | ||
node --version | ||
npm --version | ||
yarn --version || true | ||
echo "::set-output name=use_yarn::$([[ -f ./yarn.lock ]] && echo "true" || echo "false")" | ||
- name: Get node version for cache key | ||
id: cache-key | ||
run: echo "::set-output name=node_version::$(node --version)" | ||
|
||
- name: Use the node_modules cache if available [npm] | ||
if: steps.print-versions.outputs.use_yarn != 'true' | ||
uses: actions/cache@v2 | ||
with: | ||
path: ~/.npm | ||
key: ${{ runner.os }}-node-${{ steps.cache-key.outputs.node_version }}-${{ hashFiles('**/package-lock.json') }} | ||
restore-keys: | | ||
${{ runner.os }}-node-${{ steps.cache-key.outputs.node_version }}- | ||
- name: Get yarn cache directory path | ||
if: steps.print-versions.outputs.use_yarn == 'true' | ||
id: yarn-cache-dir-path | ||
run: echo "::set-output name=dir::$(yarn cache dir)" | ||
|
||
- name: Use the node_modules cache if available [yarn] | ||
if: steps.print-versions.outputs.use_yarn == 'true' | ||
uses: actions/cache@v2 | ||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) | ||
with: | ||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }} | ||
key: ${{ runner.os }}-node-${{ steps.yarn-cache-dir-path.outputs.node_version }}-yarn-${{ hashFiles('**/yarn.lock') }} | ||
restore-keys: | | ||
${{ runner.os }}-node-${{ steps.yarn-cache-dir-path.outputs.node_version }}-yarn- | ||
- name: Install dependencies | ||
run: | | ||
if [ -n "${{ inputs.install-command }}" ]; then | ||
echo "Running custom install-command: ${{ inputs.install-command }}" | ||
${{ inputs.install-command }} | ||
elif [ "${{ steps.print-versions.outputs.use_yarn }}" == "true" ]; then | ||
echo "Running yarn install --frozen-lockfile" | ||
yarn install --frozen-lockfile | ||
else | ||
echo "Running npm ci" | ||
npm ci | ||
fi | ||
# An unfortunate side-effect of the way reusable workflows work is that by the time they are pulled into the "caller" | ||
# repo, they are effectively completely embedded in that context. This means that we cannot reference any files which | ||
# are local to this repo which defines the workflow, and we therefore need to work around this by embedding the contents | ||
# of the shell utilities for executing commands into the workflow directly. | ||
- name: Create command utils | ||
uses: actions/github-script@v6 | ||
with: | ||
script: | | ||
const { writeFileSync } = require('fs'); | ||
const runCommandsInParallelScript = ` | ||
# Extract the provided commands from the stringified JSON array. | ||
IFS=$'\n' read -d '' -a userCommands < <((jq -c -r '.[]') <<<"$1") | ||
# Invoke the provided commands in parallel and collect their exit codes. | ||
pids=() | ||
for userCommand in "\${userCommands[@]}"; do | ||
eval "$userCommand" & pids+=($!) | ||
done | ||
# If any one of the invoked commands exited with a non-zero exit code, exit the whole thing with code 1. | ||
for pid in \${pids[*]}; do | ||
if ! wait $pid; then | ||
exit 1 | ||
fi | ||
done | ||
# All the invoked commands must have exited with code zero. | ||
exit 0 | ||
`; | ||
writeFileSync('./.github/workflows/run-commands-in-parallel.sh', runCommandsInParallelScript); | ||
- name: Prepare command utils | ||
run: chmod +x ./.github/workflows/run-commands-in-parallel.sh | ||
|
||
- name: Initialize the Nx Cloud distributed CI run | ||
run: npx nx-cloud start-ci-run | ||
|
||
# The good thing about the multi-line string input for sequential commands is that we can simply forward it on as is to the bash shell and it will behave | ||
# how we want it to in terms of quote escaping, variable assignment etc | ||
- name: Run any configured init-commands sequentially | ||
if: ${{ inputs.init-commands != '' }} | ||
shell: bash | ||
run: | | ||
${{ inputs.init-commands }} | ||
- name: Process parallel commands configuration | ||
uses: actions/github-script@v6 | ||
id: parallel_commands_config | ||
env: | ||
PARALLEL_COMMANDS: ${{ inputs.parallel-commands }} | ||
PARALLEL_COMMANDS_ON_AGENTS: ${{ inputs.parallel-commands-on-agents }} | ||
with: | ||
# For the ones configured for main, explicitly set NX_CLOUD_DISTRIBUTED_EXECUTION to false, taking into account commands chained with && | ||
# within the strings. In order to properly escape single quotes we need to do some manual replacing and escaping so that the commands | ||
# are forwarded onto the run-commands-in-parallel.sh script appropriately. | ||
script: | | ||
const parallelCommandsOnMainStr = process.env.PARALLEL_COMMANDS || ''; | ||
const parallelCommandsOnAgentsStr = process.env.PARALLEL_COMMANDS_ON_AGENTS || ''; | ||
const parallelCommandsOnMain = parallelCommandsOnMainStr | ||
.split('\n') | ||
.map(command => command.trim()) | ||
.filter(command => command.length > 0) | ||
.map(s => s.replace(/'/g, '%27')); | ||
const parallelCommandsOnAgents = parallelCommandsOnAgentsStr | ||
.split('\n') | ||
.map(command => command.trim()) | ||
.filter(command => command.length > 0) | ||
.map(s => s.replace(/'/g, '%27')); | ||
const formattedArrayOfCommands = [ | ||
...parallelCommandsOnMain.map(s => s | ||
.split(' && ') | ||
.map(s => `NX_CLOUD_DISTRIBUTED_EXECUTION=false ${s}`) | ||
.join(' && ') | ||
), | ||
...parallelCommandsOnAgents, | ||
]; | ||
const stringifiedEncodedArrayOfCommands = JSON.stringify(formattedArrayOfCommands) | ||
.replace(/%27/g, "'\\''"); | ||
return stringifiedEncodedArrayOfCommands | ||
result-encoding: string | ||
|
||
- name: Run any configured parallel commands on main and agent jobs | ||
run: ./.github/workflows/run-commands-in-parallel.sh '${{ steps.parallel_commands_config.outputs.result }}' | ||
shell: bash | ||
|
||
# The good thing about the multi-line string input for sequential commands is that we can simply forward it on as is to the bash shell and it will behave | ||
# how we want it to in terms of quote escaping, variable assignment etc | ||
- name: Run any configured final-commands sequentially | ||
if: ${{ inputs.final-commands != '' }} | ||
shell: bash | ||
run: | | ||
${{ inputs.final-commands }} | ||
- name: Stop all running agents for this CI run | ||
# 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 | ||
if: ${{ always() }} | ||
run: npx nx-cloud stop-all-agents |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
name: "Publish" | ||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
publish: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- uses: jameshenry/publish-shell-action@v1 | ||
with: | ||
github-token: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Notes to Admins | ||
|
||
In order to publish a new version of the action, simply update the "version" in the package.json and merge into the main branch. | ||
|
||
The workflow at ./github/workflows/publish.yml will apply the new version in the form of tags, which is all that is needed to publish an Action. | ||
|
||
Example of tags applied: | ||
|
||
- Let's say that the new version you have applied is `1.2.3`. | ||
- The commit will be tagged with `v1.2.3` as you would expect, but it will also be tagged with `v1.2` and `v1`. This is so that we are effectively moving the "head" of these major and minor versions up to the latest patch release which is relevant to them, meaning users can have workflows which specify only `v1` or `v1.2` and always be ensured that they are receiving the latest and greatest. |
Oops, something went wrong.