build: enable latest TS and ES features #36
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: 'ticketing CI' | |
on: | |
push: | |
branches: | |
- main | |
paths-ignore: | |
- README.md | |
- docs/*.md | |
- '**/CHANGELOG.md' | |
# auto-generated | |
- 'apps/**/openapi.json' | |
- 'apps/**/package*.json' | |
- 'libs/ng/shared/data-access/src/lib/generated/**' | |
pull_request: | |
branches: | |
- main | |
types: | |
- ready_for_review | |
- opened | |
- reopened | |
- synchronize | |
paths-ignore: | |
- README.md | |
- docs/*.md | |
- '**/CHANGELOG.md' | |
# auto-generated | |
- 'apps/**/openapi.json' | |
- 'apps/**/package*.json' | |
release: | |
types: | |
- published | |
- edited | |
env: | |
NODE_VERSION: 16.x | |
NODE_OPTIONS: --max_old_space_size=6144 | |
CI_WORKFLOW: ci.yaml | |
CD_WORKFLOW: cd.yaml | |
BUILD_FOLDER: dist | |
BUILD_ARTIFACTS: build | |
COVERAGE_FOLDER: coverage | |
COVERAGE_ARTIFACTS: coverage | |
COVERAGE_APPS_UNIT_TESTS_ARTIFACTS: libs-unit-coverage | |
COVERAGE_APPS_E2E_TESTS_ARTIFACTS: apps-e2e-coverage | |
COVERAGE_LIBS_UNIT_TESTS_ARTIFACTS: apps-unit-coverage | |
COVERAGE_APPS_UNIT_TESTS_FOLDER: coverage/apps/unit | |
COVERAGE_APPS_E2E_TESTS_FOLDER: coverage/apps/e2e | |
COVERAGE_LIBS_UNIT_TESTS_FOLDER: coverage/libs | |
NX_CLOUD_DISTRIBUTED_EXECUTION: true | |
NX_DISTRIBUTED_TASK_EXECUTION: true | |
NX_VERBOSE_LOGGING: true | |
NX_CLOUD_DISTRIBUTED_EXECUTION_STOP_AGENTS_ON_FAILURE: false | |
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} | |
NX_MAX_AGENTS: ${{ vars.NX_MAX_AGENTS || 8 }} | |
STEP_SET_FETCH_REF: 'Set fetch-ref' | |
STEP_SETUP_PROJECT: 'Setup node, checkout and install project dependencies' | |
# test jobs env. variables | |
NODE_ENV: ${{ vars.NODE_ENV || 'local' }} | |
LOG_LEVEL: ${{ vars.LOG_LEVEL || 'warn' }} | |
GLOBAL_API_PREFIX: api | |
JWT_ISSUER: ${{ secrets.JWT_ISSUER }} | |
JWT_ALGORITHM: ${{ secrets.JWT_ALGORITHM }} | |
JWT_EXPIRES_IN: ${{ secrets.JWT_EXPIRES_IN }} | |
JWT_PUBLIC_KEY: ${{ secrets.JWT_PUBLIC_KEY }} | |
JWT_PRIVATE_KEY: ${{ secrets.JWT_PRIVATE_KEY }} | |
SESSION_KEY: ${{ secrets.SESSION_KEY }} | |
STRIPE_PUBLISHABLE_KEY: ${{ secrets.STRIPE_PUBLISHABLE_KEY }} | |
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }} | |
STRIPE_ENDPOINT_SECRET: ${{ secrets.STRIPE_ENDPOINT_SECRET }} | |
PROXY_SERVER_URLS: http://localhost | |
FRONTEND_URL: http://localhost | |
AUTH_SERVICE_PORT: 3000 | |
EXPIRATION_SERVICE_PORT: 3030 | |
ORDERS_SERVICE_PORT: 3020 | |
PAYMENTS_SERVICE_PORT: 3040 | |
TICKETS_SERVICE_PORT: 3010 | |
FRONTEND_PORT: 4200 | |
NATS_URL: http://localhost:4222 | |
NATS_CLUSTER_ID: ticketing | |
MONGODB_URI: mongodb://localhost:27017 | |
REDIS_URL: redis://localhost:6379 | |
jobs: | |
# INIT | |
init: | |
runs-on: ubuntu-latest | |
if: github.event_name == 'release' || github.event_name == 'push' || !github.event.pull_request.draft | |
timeout-minutes: 10 | |
steps: | |
- name: ${{ env.STEP_SET_FETCH_REF }} | |
id: fetch-ref | |
uses: haya14busa/action-cond@v1 | |
with: | |
cond: ${{ github.ref == 'refs/head/main' }} | |
if_true: ${{ github.ref }} | |
if_false: ${{ github.event.pull_request.head.ref }} | |
# Needed as long as we use local actions | |
- uses: actions/checkout@v4 | |
with: | |
ref: ${{ steps.fetch-ref.outputs.value }} | |
# init dependencies cache so that next jobs can start faster | |
- name: ${{ env.STEP_SETUP_PROJECT }} | |
id: setup | |
uses: ./.github/actions/checkout-and-yarn | |
with: | |
fetch-depth: 0 | |
fetch-ref: ${{ steps.fetch-ref.outputs.value }} | |
node-version: ${{ env.NODE_VERSION }} | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Get branch names | |
id: branch-name | |
uses: tj-actions/branch-names@v7 | |
- name: Get current version | |
id: package-version | |
uses: martinbeentjes/[email protected] | |
- name: Derive appropriate SHAs for base and head for `nx affected` commands | |
id: set-shas | |
uses: | |
nrwl/nx-set-shas@v3 | |
# get commits count and increment by 1 for safety | |
- name: Find depth of NX_BASE | |
id: commit-depth | |
run: | | |
depth=$(git rev-list HEAD ^${{ steps.set-shas.outputs.base }} --count) | |
depth=$((depth + 1)) | |
echo "BASE_DEPTH=$depth" >> $GITHUB_ENV | |
echo "depth=$depth" >> $GITHUB_OUTPUT | |
# set value to current version on release event or to an autogenerated tag | |
- name: Set tag | |
id: tag | |
run: | | |
if [[ "${{ github.event_name }}" == "release" ]]; then | |
echo "value=$(echo v${{ steps.package-version.outputs.current-version }})" >> $GITHUB_OUTPUT | |
fi | |
- name: List affected apps since previous workflow run | |
id: check-apps | |
run: echo "affected=$(yarn affected:apps --base=${{ steps.set-shas.outputs.base }} --plain)" >> $GITHUB_OUTPUT | |
- name: List affected libs since previous workflow run | |
id: check-libs | |
run: echo "affected=$(yarn affected:libs --base=${{ steps.set-shas.outputs.base }} --plain)" >> $GITHUB_OUTPUT | |
# check if any app is affected between this commit and the previous successful workflow run commit | |
- name: Check if any app was affected since previous workflow run | |
id: has-apps-affected | |
run: echo "value=$([[ -z '${{ steps.check-apps.outputs.affected }}' ]] && echo 'false' || echo 'true')" >> $GITHUB_OUTPUT | |
# check if any lib is affected between this commit and the previous successful workflow run commit | |
- name: Check if any lib was affected since previous workflow run | |
id: has-libs-affected | |
run: echo "value=$([[ -z '${{ steps.check-libs.outputs.affected }}' ]] && echo 'false' || echo 'true')" >> $GITHUB_OUTPUT | |
# check if any project is affected between this commit and the previous successful workflow run commit | |
- name: Check if any project was affected | |
id: has-projects-affected | |
run: | | |
if [[ "${{ steps.check-apps.outputs.affected }}" == "" && "${{ steps.check-libs.outputs.affected }}" == "" ]]; then | |
echo "value=false" >> $GITHUB_OUTPUT | |
else | |
echo "value=true" >> $GITHUB_OUTPUT | |
fi | |
# Run comparisons between latest successful workflow commit and current commit | |
- name: Check if OpenAPI specs have changed | |
id: open-api | |
run: echo "has-changed=$(yarn git:check-diff --silent -- -b ${{ steps.set-shas.outputs.base }} -p 'apps/**/openapi.json')" >> $GITHUB_OUTPUT | |
- name: Check if package.json has changed | |
id: package-json | |
run: echo "has-changed=$(yarn git:check-diff --silent -- -b ${{ steps.set-shas.outputs.base }} -p 'package.json')" >> $GITHUB_OUTPUT | |
- name: Check if regenerate job should be run | |
id: regenerate | |
run: | | |
if [[ ${{ steps.branch-name.outputs.current_branch }} != 'main' ]] && \ | |
[[ ${{ steps.open-api.outputs.has-changed }} =~ "true" ]] || \ | |
[[ ${{ steps.package-json.outputs.has-changed }} =~ "true" ]]; then | |
echo "should-run=true" >> $GITHUB_OUTPUT | |
else | |
echo "should-run=false" >> $GITHUB_OUTPUT | |
fi | |
# dynamically set number of Nx agents to start | |
- name: Count number of Nx Cloud agents required | |
id: nx-cloud-agents | |
env: | |
AFFECTED_APPS: ${{ steps.check-apps.outputs.affected || '' }} | |
MAX_AGENTS: ${{ env.NX_MAX_AGENTS }} | |
run: | | |
if [[ "${{ github.event_name }}" == "release" ]]; then | |
count=$(node --eval " | |
const maxAgents = +process.env.MAX_AGENTS; | |
const count = Math.round(maxAgents); | |
console.log(count);" | |
) | |
else | |
count=$(yarn get:apps | node --eval " | |
const apps = require('fs').readFileSync(0).toString().trim().split(','); | |
const affectedApps = process.env.AFFECTED_APPS.split(',').map(e => e.trim()) || [] | |
const maxAgents = +process.env.MAX_AGENTS; | |
const count = Math.round(maxAgents * (affectedApps.length / apps.length)) || 1; | |
console.log(count);" | |
) | |
fi | |
echo "count=$count" >> $GITHUB_OUTPUT | |
echo "matrix=$(echo $count | node --eval " | |
const length = parseInt(require('fs').readFileSync(0).toString().trim()); | |
const result = JSON.stringify([...Array(length)].map((e, i) => i + 1)); | |
console.log(result);" | |
)" >> $GITHUB_OUTPUT | |
- name: Show outputs | |
run: | | |
echo "event name: ${{ github.event_name }}" | |
echo "affected apps: ${{ steps.check-apps.outputs.affected }}" | |
echo "affected libs: ${{ steps.check-libs.outputs.affected }}" | |
echo "current-branch: ${{ steps.branch-name.outputs.current_branch }}" | |
echo "should-update-models: ${{ steps.open-api.outputs.has-changed }}" | |
echo "should-update-packages: ${{ steps.package-json.outputs.has-changed }}" | |
echo "should-run-regenerate: ${{ steps.regenerate.outputs.should-run }}" | |
- name: Create job summary | |
run: | | |
echo "## CI initialized! :rocket: " >> $GITHUB_STEP_SUMMARY | |
echo "- base commit SHA: ${{ steps.set-shas.outputs.base }}" >> $GITHUB_STEP_SUMMARY | |
echo "- head commit SHA: ${{ steps.set-shas.outputs.head }}" >> $GITHUB_STEP_SUMMARY | |
echo "- base commit depth: ${{ steps.commit-depth.outputs.depth }}" >> $GITHUB_STEP_SUMMARY | |
echo "- current branch: ${{ steps.branch-name.outputs.current_branch }}" >> $GITHUB_STEP_SUMMARY | |
echo "- current version: ${{ steps.package-version.outputs.current-version }}" >> $GITHUB_STEP_SUMMARY | |
echo "- tag: ${{ steps.tag.outputs.value }}" >> $GITHUB_STEP_SUMMARY | |
echo "- affected apps: ${{ steps.check-apps.outputs.affected }}" >> $GITHUB_STEP_SUMMARY | |
echo "- affected libs: ${{ steps.check-libs.outputs.affected }}" >> $GITHUB_STEP_SUMMARY | |
echo "- Nx agents count: ${{ steps.nx-cloud-agents.outputs.count }}" >> $GITHUB_STEP_SUMMARY | |
outputs: | |
fetch-ref: ${{ steps.fetch-ref.outputs.value }} | |
base: ${{ steps.set-shas.outputs.base }} | |
head: ${{ steps.set-shas.outputs.head }} | |
base-depth: ${{ steps.commit-depth.outputs.depth}} | |
current-branch: ${{ steps.branch-name.outputs.current_branch }} | |
should-update-models: ${{ steps.open-api.outputs.has-changed }} | |
should-update-packages: ${{ steps.package-json.outputs.has-changed }} | |
should-run-regenerate: ${{ steps.regenerate.outputs.should-run }} | |
deps-cache-hit: ${{ steps.setup.outputs.cache-hit }} | |
affected-apps: ${{ steps.check-apps.outputs.affected }} | |
affected-libs: ${{ steps.check-libs.outputs.affected }} | |
projects-affected: ${{ steps.has-projects-affected.outputs.value }} | |
agents-count: ${{ steps.nx-cloud-agents.outputs.count }} | |
agents-matrix: ${{ steps.nx-cloud-agents.outputs.matrix }} | |
job-status: ${{ job.status }} | |
# REGENERATE | |
regenerate: | |
needs: init | |
runs-on: ubuntu-latest | |
if: | | |
needs.init.outputs.should-run-regenerate == 'true' | |
&& needs.init.outputs.current-branch != 'main' | |
&& github.event_name != 'release' | |
&& (github.event_name == 'push' || !github.event.pull_request.draft) | |
timeout-minutes: 5 | |
env: | |
NX_BASE: ${{ needs.init.outputs.base }} | |
NX_HEAD: ${{ needs.init.outputs.head }} | |
BASE_DEPTH: ${{ needs.init.outputs.base-depth }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
ref: ${{ needs.init.outputs.fetch-ref }} | |
- name: ${{ env.STEP_SETUP_PROJECT }} | |
id: setup | |
uses: ./.github/actions/checkout-and-yarn | |
with: | |
fetch-depth: 0 | |
fetch-ref: ${{ needs.init.outputs.fetch-ref }} | |
node-version: ${{ env.NODE_VERSION }} | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Derive appropriate SHAs for base and head for `nx affected` commands | |
uses: nrwl/nx-set-shas@v3 | |
- name: Regenerate backend apps package.json | |
if: needs.init.outputs.should-update-packages == 'true' | |
run: NX_CLOUD_DISTRIBUTED_EXECUTION=false yarn refresh-pkg-json | |
- name: Regenerate frontend models | |
if: needs.init.outputs.should-update-models == 'true' | |
run: yarn ng:openapi | |
- name: Run prettier | |
if: needs.init.outputs.should-update-models == 'true' | |
run: npx nx format:write --projects=shared-ng-open-api | |
- name: Add, commit and push backend package.json | |
if: needs.init.outputs.should-update-packages == 'true' | |
id: commit-pkg | |
uses: stefanzweifel/git-auto-commit-action@v4 | |
with: | |
commit_message: 'chore: regenerate backend package*.json [skip ci]' | |
file_pattern: 'apps/**/package*.json' | |
commit_options: '--no-verify' | |
- if: steps.commit-pkg.outputs.changes_detected == 'true' | |
run: echo "BASE_DEPTH=$((${{ env.BASE_DEPTH }} + 1))" >> $GITHUB_ENV | |
- name: Add, commit and push generated models | |
if: needs.init.outputs.should-update-models == 'true' | |
id: commit-ng-models | |
uses: stefanzweifel/git-auto-commit-action@v4 | |
with: | |
commit_message: 'chore: regenerate frontend models [skip ci]' | |
file_pattern: 'libs/ng/shared/open-api/src/lib/generated/*' | |
commit_options: '--no-verify' | |
- if: steps.commit-ng-models.outputs.changes_detected == 'true' | |
run: echo "BASE_DEPTH=$((${{ env.BASE_DEPTH }} + 1))" >> $GITHUB_ENV | |
- name: Cancel workflow on failure | |
if: failure() | |
uses: andymckay/[email protected] | |
outputs: | |
base-depth: ${{ env.BASE_DEPTH }} | |
job-status: ${{ job.status }} | |
# AGENTS | |
agents: | |
runs-on: ubuntu-latest | |
needs: [init, regenerate] | |
if: | | |
!failure() && !cancelled() && | |
needs.init.outputs.projects-affected == 'true' && | |
(github.event_name == 'release' || github.event_name == 'push' || !github.event.pull_request.draft) | |
name: Agent | |
timeout-minutes: 15 | |
env: | |
NX_CLOUD_DISTRIBUTED_EXECUTION_AGENT_COUNT: ${{ needs.init.outputs.agents-count }} | |
services: | |
mongo: | |
image: mongo | |
ports: | |
- 27017:27017 | |
strategy: | |
matrix: | |
# number of agents proportional to number of affected projects | |
agent: ${{ fromJSON(needs.init.outputs.agents-matrix) }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
ref: ${{ needs.init.outputs.fetch-ref }} | |
- name: ${{ env.STEP_SETUP_PROJECT }} | |
id: setup | |
uses: ./.github/actions/checkout-and-yarn | |
with: | |
fetch-ref: ${{ needs.init.outputs.fetch-ref }} | |
node-version: ${{ env.NODE_VERSION }} | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Start Nx Agent ${{ matrix.agent }} | |
run: npx nx-cloud start-agent | |
main: | |
runs-on: ubuntu-latest | |
needs: [init, regenerate] | |
if: | | |
!failure() && !cancelled() && | |
needs.init.outputs.projects-affected == 'true' && | |
(github.event_name == 'release' || github.event_name == 'push' || !github.event.pull_request.draft) | |
services: | |
nats-streaming: | |
image: ghcr.io/getlarge/ticketing/nats-streaming:latest | |
credentials: | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
ports: | |
- '4222:4222' | |
- '8222:8222' | |
auth-mongo: | |
image: mongo | |
ports: | |
- 27017:27017 | |
orders-mongo: | |
image: mongo | |
ports: | |
- 27018:27017 | |
tickets-mongo: | |
image: mongo | |
ports: | |
- 27019:27017 | |
payments-mongo: | |
image: mongo | |
ports: | |
- 27020:27017 | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
ref: ${{ needs.init.outputs.fetch-ref }} | |
- name: Compute Git fetch depth | |
id: fetch-depth | |
run: echo "value=${{ needs.regenerate.outputs.base-depth || needs.init.outputs.base-depth }}" >> $GITHUB_OUTPUT | |
- name: ${{ env.STEP_SETUP_PROJECT }} | |
id: setup | |
uses: ./.github/actions/checkout-and-yarn | |
with: | |
# fetch-depth: ${{ steps.fetch-depth.outputs.value }} | |
fetch-depth: 0 | |
fetch-ref: ${{ needs.init.outputs.fetch-ref }} | |
node-version: ${{ env.NODE_VERSION }} | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Derive appropriate SHAs for base and head for `nx affected` commands | |
uses: nrwl/nx-set-shas@v3 | |
- run: npx nx-cloud start-ci-run | |
- name: Get Nx apps to build | |
id: build-apps | |
run: | | |
if [[ "${{ github.event_name }}" == "release" ]]; then | |
echo "list=$(yarn get:apps)" >> $GITHUB_OUTPUT | |
else | |
echo "list=$(yarn affected:apps | tr -d ' ')" >> $GITHUB_OUTPUT | |
fi | |
- name: Run verifications for affected apps | |
uses: jameshenry/parallel-bash-commands@v1 | |
with: | |
cmd1: npx nx affected --target=lint --parallel=4 --exclude=workspace --verbose | |
cmd2: npx nx affected --target=test --parallel=4 --exclude=workspace --ci --verbose | |
cmd3: npx nx run-many --target=build --parallel=4 --projects=${{ steps.build-apps.outputs.list }} --verbose | |
# running e2e tests in parallel create conflicts in DB | |
# cmd4: NX_CLOUD_DISTRIBUTED_EXECUTION=false yarn affected:e2e:backend --ci --verbose | |
- name: Stop Nx agents | |
if: always() | |
run: npx nx-cloud stop-all-agents | |
- name: Upload build output | |
uses: actions/upload-artifact@v3 | |
with: | |
name: ${{ env.BUILD_ARTIFACTS }} | |
path: ${{ env.BUILD_FOLDER }} | |
retention-days: 5 | |
- name: Check libs coverage reports existence | |
id: check-libs-coverage | |
uses: andstor/file-existence-action@v2 | |
with: | |
files: ${{ env.COVERAGE_LIBS_UNIT_TESTS_FOLDER }} | |
- name: Upload libs unit tests coverage reports | |
if: steps.check-libs-coverage.outputs.files_exists == 'true' | |
uses: actions/upload-artifact@v3 | |
with: | |
name: ${{ env.COVERAGE_LIBS_UNIT_TESTS_ARTIFACTS }} | |
path: ${{ env.COVERAGE_LIBS_UNIT_TESTS_FOLDER }} | |
retention-days: 1 | |
- name: Check apps coverage reports existence | |
id: check-apps-coverage | |
uses: andstor/file-existence-action@v2 | |
with: | |
files: ${{ env.COVERAGE_APPS_UNIT_TESTS_FOLDER }} | |
- name: Upload apps unit tests coverage reports | |
if: steps.check-apps-coverage.outputs.files_exists == 'true' | |
uses: actions/upload-artifact@v3 | |
with: | |
name: ${{ env.COVERAGE_APPS_UNIT_TESTS_ARTIFACTS }} | |
path: ${{ env.COVERAGE_APPS_UNIT_TESTS_FOLDER }} | |
retention-days: 1 | |
- name: Check coverage reports existence | |
uses: andstor/file-existence-action@v2 | |
id: check-coverage | |
with: | |
files: ${{ env.COVERAGE_APPS_E2E_TESTS_FOLDER }} | |
- name: Upload apps e2e tests coverage reports | |
if: ${{ steps.check-coverage.outputs.files_exists == 'true' }} | |
uses: actions/upload-artifact@v3 | |
with: | |
name: ${{ env.COVERAGE_APPS_E2E_TESTS_ARTIFACTS }} | |
path: ${{ env.COVERAGE_APPS_E2E_TESTS_FOLDER }} | |
retention-days: 1 | |
- name: Cancel workflow on failure | |
if: failure() | |
uses: andymckay/[email protected] | |
outputs: | |
has-apps-coverage: ${{ steps.check-apps-coverage.outputs.files_exists }} | |
has-libs-coverage: ${{ steps.check-libs-coverage.outputs.files_exists }} | |
fetch-ref: ${{ needs.init.outputs.fetch-ref }} |