ci: nx-cloud feature toggle #202
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
name: Pull request (nx-cloud enabled) | |
on: | |
pull_request: | |
types: | |
- opened | |
- synchronize | |
- labeled | |
workflow_dispatch: {} | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.event.number || github.ref }} | |
cancel-in-progress: true | |
defaults: | |
run: | |
shell: bash | |
permissions: | |
contents: read | |
pull-requests: read | |
actions: read | |
env: | |
NODE_OPTIONS: --max-old-space-size=8192 | |
COMPOSE_HTTP_TIMEOUT: 180 | |
GITHUB_ACTIONS_CACHE_URL: https://cache.dev01.devland.is/ | |
MAX_JOBS: 3 | |
MAX_TASKS_PER_AGENT: 10 | |
MAX_AGENTS: 8 | |
BRANCH_NAME: ${{ github.head_ref || github.ref_name }} | |
NX_BRANCH: ${{ github.head_ref || github.ref_name }} | |
NX_VERBOSE_LOGGING: true | |
SKIP_NODEJS_CACHE: ${{ contains(github.event.pull_request.labels.*.name, 'skip-nodejs-cache') }} | |
NX_CLOUD_DISTRIBUTED_EXECUTION: true | |
NX_CLOUD_DISTRIBUTED_EXECUTION_STOP_AGENTS_ON_FAILURE: true | |
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} | |
jobs: | |
pre-checks: | |
name: Check if job should run | |
runs-on: ec2-runners | |
container: | |
image: public.ecr.aws/m3u4c4h9/island-is/actions-runner-public:latest | |
outputs: | |
should-run: ${{ steps.check.outputs.should-run }} | |
steps: | |
- name: check if nx-cloud label is set | |
id: check | |
run: | | |
echo github.head_ref: ${{ github.head_ref }} | |
echo github.ref_name: ${{ github.ref_name }} | |
echo NX_BRANCH: ${NX_BRANCH} | |
USE_NX_CLOUD=$(echo '${{ toJson(github.event.pull_request.labels) }}' | jq '.[] | select(.name == "nx-cloud")? | any' | grep -q true && echo "true" || echo "false") | |
echo "should-run=$USE_NX_CLOUD" >> $GITHUB_OUTPUT | |
prepare: | |
runs-on: ec2-runners | |
container: | |
image: public.ecr.aws/m3u4c4h9/island-is/actions-runner-public:latest | |
# GitHub's default timeout is 360 minutes | |
timeout-minutes: 360 | |
outputs: | |
node-modules-hash: ${{ steps.calculate_node_modules_hash.outputs.node-modules-hash }} | |
generated-files-cache-key: ${{ steps.calculate_generated_files_cache_key.outputs.generated-files-cache-key }} | |
matrix: ${{ steps.set-matrix.outputs.matrix }} | |
affected: ${{ steps.set-matrix.outputs.affected }} | |
nx-base: ${{ steps.set-sha.outputs.base }} | |
nx-head: ${{ steps.set-sha.outputs.head }} | |
needs: | |
- pre-checks | |
if: needs.pre-checks.outputs.should-run == 'true' | |
steps: | |
- uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
- name: Keep PR run event | |
uses: actions/upload-artifact@v2 | |
with: | |
name: pr-event | |
path: event.json | |
retention-days: 60 | |
- name: Find sha for NX | |
id: set-sha | |
uses: nrwl/nx-set-shas@v3 | |
with: | |
error-on-no-successful-workflow: 'true' # break hard | |
last-successful-event: 'pull-request' | |
workflow-id: 'pullrequest' # use legacy workflow to get more chance of hits | |
- name: Export sha for NX | |
id: export-sha | |
run: | | |
BASE_SHA=${{ steps.set-sha.outputs.base }} | |
HEAD_SHA=${{ steps.set-sha.outputs.head }} | |
echo "{\"base_sha\": \"$BASE_SHA\", \"head_sha\":\"$HEAD_SHA\"}" > event.json | |
- uses: actions/setup-node@v3 | |
with: | |
node-version: '18.8.0' | |
- name: Calculate cache key for node_modules | |
id: calculate_node_modules_hash | |
run: | | |
PACKAGE_JSON_HASH=$(cat package.json | jq '{resolutions,dependencies,devDependencies}' | sha1sum -t | cut -f1 -d" ") | |
echo "PACKAGE_JSON_HASH: $PACKAGE_JSON_HASH" | |
NODE_MODULES_HASH=${{ runner.os }}-${{ hashFiles('yarn.lock') }}-$PACKAGE_JSON_HASH | |
echo "node-modules-hash: $NODE_MODULES_HASH" | |
echo "node-modules-hash=$NODE_MODULES_HASH" >> $GITHUB_OUTPUT | |
- name: Calculate cache keys for generated files | |
id: calculate_generated_files_cache_key | |
run: | | |
export HASH=${{ hashFiles('scripts/schemas.js', 'libs/cms/src/lib/generated/contentfulTypes.d.ts', 'apps/air-discount-scheme/web/i18n/withLocale.tsx', 'apps/air-discount-scheme/web/components/AppLayout/AppLayout.tsx', 'apps/air-discount-scheme/web/components/Header/Header.tsx', 'apps/air-discount-scheme/web/screens/**.tsx', 'apps/**/codegen.yml', 'libs/**/codegen.yml', 'apps/**/*.model.ts', 'libs/**/*.model.ts', 'apps/**/*.enum.ts', 'libs/**/*.enum.ts', 'apps/**/queries/**/*.tsx?', 'libs/**/queries/**/*.tsx?', 'libs/**/mutations/**/*.tsx?', 'libs/**/fragments/**/*.tsx?' , 'apps/**/*.resolver.ts', 'libs/**/*.resolver.ts', 'apps/**/*.service.ts', 'libs/**/*.service.ts', 'apps/**/*.dto.ts', 'libs/**/*.dto.ts', 'apps/**/*.input.ts', 'libs/**/*.input.ts', 'apps/**/*.module.ts', 'libs/**/*.module.ts', 'apps/**/*.controller.ts', 'libs/**/*.controller.ts', 'apps/**/*.union.ts', 'libs/**/*.union.ts', 'apps/**/*.graphql.ts', 'apps/judicial-system/**/*.graphql', 'libs/**/*.graphql.ts', 'libs/**/*.graphql') }} | |
GENERATED_FILES_CACHE_KEY=${{ runner.os }}-$HASH-files-generated | |
echo "GENERATED_FILES_CACHE_KEY: $GENERATED_FILES_CACHE_KEY" | |
echo "generated-files-cache-key=$GENERATED_FILES_CACHE_KEY" >> $GITHUB_OUTPUT | |
- name: Cache for NodeJS dependencies - host OS | |
id: node-modules | |
continue-on-error: true | |
uses: ./.github/actions/cache | |
with: | |
path: node_modules | |
key: ${{ steps.calculate_node_modules_hash.outputs.node-modules-hash }}-yarn | |
- name: Check cache success | |
run: '[[ "${{ steps.node-modules.outputs.success }}" != "false" ]] || exit 1' | |
- name: Cache for generated files | |
id: generated-files-cache | |
continue-on-error: true | |
uses: ./.github/actions/cache | |
with: | |
path: generated_files.tar.gz | |
key: ${{ steps.calculate_generated_files_cache_key.outputs.generated-files-cache-key }} | |
- name: Check cache success | |
run: '[[ "${{ steps.generated-files-cache.outputs.success }}" != "false" ]] || exit 1' | |
- name: Building NodeJS dependencies | |
if: steps.node-modules.outputs.cache-hit != 'true' || env.SKIP_NODEJS_CACHE == 'true' | |
run: ./scripts/ci/10_prepare-host-deps.sh | |
- name: Generate schemas | |
if: steps.generated-files-cache.outputs.cache-hit != 'true' | |
run: | | |
node --version | |
tar zcvf generated_files.tar.gz $(./scripts/ci/get-files-touched-by.sh yarn schemas --skip-cache | xargs realpath --relative-to $(pwd)) | |
- name: Calculate NX agent count | |
id: set-matrix | |
shell: bash | |
# Turn the number-of-agents input into a JSON structure which is compatible with a Github job matrix strategy | |
run: | | |
NX_AFFECTED_PROJECTS_COUNT=$(npx nx print-affected --base=$BASE --head=$HEAD --select=projects | tr ',' ' ' | wc -w) | |
AGENTS_COUNT=$(node ./scripts/ci/_num_agents.js $NX_AFFECTED_PROJECTS_COUNT $MAX_AGENTS ${MAX_TASKS_PER_AGENT:-$MAX_JOBS} | jq -r '.chunksCount') | |
AGENTS_JSON_ARRAY=$(node -e "console.log(JSON.stringify(Array.from(new Array($AGENTS_COUNT)).map((_, i) => i + 1)));") | |
echo "affected projects count: $NX_AFFECTED_PROJECTS_COUNT" | |
echo "agents count: $AGENTS_COUNT" | |
echo "agents json: $AGENTS_JSON_ARRAY" | |
echo "matrix=$AGENTS_JSON_ARRAY" >> $GITHUB_OUTPUT | |
echo "affected=$NX_AFFECTED_PROJECTS_COUNT" >> $GITHUB_OUTPUT | |
nx-cloud-agent: | |
needs: | |
- prepare | |
env: | |
BASE: ${{ needs.prepare.outputs.nx-base }} | |
HEAD: ${{ needs.prepare.outputs.nx-head }} | |
runs-on: ec2-runners | |
container: | |
image: public.ecr.aws/m3u4c4h9/island-is/actions-runner-public:latest | |
timeout-minutes: 30 | |
strategy: | |
matrix: | |
agent: | |
- ${{fromJson(needs.prepare.outputs.matrix)}} | |
defaults: | |
run: | |
working-directory: ${{ github.workspace }} | |
shell: bash | |
if: needs.prepare.outputs.affected > 0 | |
steps: | |
- uses: actions/checkout@v3 | |
- name: Setup yarn | |
run: npm install -g yarn | |
- name: Cache for NodeJS dependencies - host OS | |
id: node-modules | |
continue-on-error: true | |
uses: ./.github/actions/cache | |
with: | |
path: node_modules | |
key: ${{ needs.prepare.outputs.node-modules-hash }}-yarn | |
- name: Check cache success | |
run: '[[ "${{ steps.node-modules.outputs.success }}" != "false" ]] || exit 1' | |
- name: Cache for generated files | |
id: generated-files-cache | |
continue-on-error: true | |
uses: ./.github/actions/cache | |
with: | |
path: generated_files.tar.gz | |
key: ${{ needs.prepare.outputs.generated-files-cache-key }} | |
- name: Check cache success | |
run: '[[ "${{ steps.generated-files-cache.outputs.success }}" != "false" ]] || exit 1' | |
- name: Untar generated files | |
run: tar zxvf generated_files.tar.gz | |
- name: Start Nx Agent ${{ matrix.agent }} | |
run: npx nx-cloud start-agent | |
env: | |
NX_AGENT_NAME: ${{matrix.agent}} | |
nx-cloud-main: | |
needs: | |
- prepare | |
env: | |
NX_BASE: ${{ needs.prepare.outputs.nx-base }} | |
NX_HEAD: ${{ needs.prepare.outputs.nx-head }} | |
runs-on: ec2-runners | |
container: | |
image: public.ecr.aws/m3u4c4h9/island-is/actions-runner-public:latest | |
timeout-minutes: 30 | |
defaults: | |
run: | |
working-directory: ${{ github.workspace }} | |
shell: bash | |
if: needs.prepare.outputs.affected > 0 | |
steps: | |
- uses: actions/checkout@v3 | |
name: Checkout [Pull Request] | |
if: ${{ github.event_name == 'pull_request' }} | |
with: | |
fetch-depth: 0 | |
- name: Setup yarn | |
run: npm install -g yarn | |
- name: Cache for NodeJS dependencies - host OS | |
id: node-modules | |
continue-on-error: true | |
uses: ./.github/actions/cache | |
with: | |
path: node_modules | |
key: ${{ needs.prepare.outputs.node-modules-hash }}-yarn | |
- name: Check cache success | |
run: '[[ "${{ steps.node-modules.outputs.success }}" != "false" ]] || exit 1' | |
- name: Cache for generated files | |
id: generated-files-cache | |
continue-on-error: true | |
uses: ./.github/actions/cache | |
with: | |
path: generated_files.tar.gz | |
key: ${{ needs.prepare.outputs.generated-files-cache-key }} | |
- name: Check cache success | |
run: '[[ "${{ steps.generated-files-cache.outputs.success }}" != "false" ]] || exit 1' | |
- name: Untar generated files | |
run: tar zxvf generated_files.tar.gz | |
- name: Start NX ci run | |
run: npx nx-cloud start-ci-run -stop-agents-after=build | |
- name: Run NX targets | |
run: | | |
source ./scripts/ci/_common.sh | |
pids=() | |
npx nx affected -t lint --parallel=$MAX_JOBS & pids+=($!) | |
npx nx affected -t test --parallel=$MAX_JOBS & pids+=($!) | |
npx nx affected -t build --parallel=$MAX_JOBS --configuration=production & pids+=($!) | |
for pid in ${pids[*]}; do | |
if ! wait $pid; then | |
exit 1 | |
fi | |
done | |
exit 0 | |
- name: Stop all running agents for this CI run | |
if: ${{ always() }} | |
run: npx nx-cloud stop-all-agents | |
# check-matrix: | |
# runs-on: ec2-runners | |
# container: | |
# image: public.ecr.aws/m3u4c4h9/island-is/actions-runner-public:latest | |
# needs: [nx] | |
# outputs: | |
# matrix: ${{ steps.matrix.outputs.matrix }} | |
# steps: | |
# - uses: actions/download-artifact@v3 | |
# - run: | | |
# echo "Check matrix" | |
# matrix="$(cat */matrix | jq -c --slurp .)" | |
# echo "matrix: $matrix" | |
# echo "::set-output name=matrix::$matrix" | |
# id: matrix | |
# TODO: trying to dynamically get the the matrix result output, unfinished | |
# success: | |
# if: always() | |
# name: 'Success ${{ matrix.includes.nx-target }}' | |
# runs-on: ec2-runners | |
# needs: | |
# - check-matrix | |
# container: | |
# image: public.ecr.aws/m3u4c4h9/island-is/actions-runner-public:latest | |
# strategy: | |
# fail-fast: false | |
# matrix: | |
# target: ${{ fromJSON(needs.check-matrix.outputs.nx-target) }} | |
# steps: | |
# - name: Check nx success | |
# run: '[[ ${{ toJSON(needs.nx.result) }} != "failure" ]] || exit 1' | |
# - name: Announce success | |
# run: echo "${{ toJSON(needs.nx) }} is successful" |