AG-14314 - Generate new examples without having to restart the dev server #20351
This file contains hidden or 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: CI | |
on: | |
push: | |
branches: | |
- 'latest' | |
- 'next' | |
- 'b[0-9][0-9]?.[0-9][0-9]?.[0-9][0-9]?' | |
pull_request: | |
workflow_dispatch: | |
inputs: | |
# run_e2e: | |
# type: 'choice' | |
# required: true | |
# default: 'false' | |
# options: | |
# - 'true' | |
# - 'false' | |
clean_checkout: | |
description: 'Disable all caching' | |
type: 'choice' | |
required: true | |
default: 'false' | |
options: | |
- 'true' | |
- 'false' | |
nx_command: | |
type: 'choice' | |
required: true | |
default: 'affected' | |
options: | |
- 'affected' | |
- 'run-many' | |
env: | |
NX_NO_CLOUD: true | |
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} | |
NX_BRANCH: ${{ github.ref }} | |
BRANCH_NAME: ${{ github.head_ref || github.ref_name }} | |
AG_LIBRARY: charts | |
AG_SKIP_NATIVE_DEP_VERSION_CHECK: 1 | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref }} | |
cancel-in-progress: ${{ github.ref != 'refs/heads/latest' && github.ref != 'refs/heads/next' }} | |
jobs: | |
init: | |
runs-on: ubuntu-24.04 | |
name: Initialise Workflow | |
permissions: | |
contents: write | |
env: | |
AG_FORCE_ALL_TESTS: 1 | |
outputs: | |
nx_base: ${{ steps.setup.outputs.base }} | |
test_count: ${{ steps.matrix.outputs.test_count }} | |
test_matrix: ${{ steps.matrix.outputs.test_matrix }} | |
test_pkg_matrix: ${{ steps.matrix.outputs.pkg_matrix }} | |
e2e_matrix: ${{ steps.matrix.outputs.e2e_matrix }} | |
e2e_count: ${{ steps.matrix.outputs.e2e_count }} | |
build_type: ${{ steps.setup.outputs.type }} | |
snapshot_branch: ${{ steps.snapshot-prepare.outputs.branch }} | |
steps: | |
- name: Checkout | |
id: checkout | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Setup | |
id: setup | |
uses: ./.github/actions/setup-nx | |
with: | |
cache_mode: ${{ github.event.inputs.clean_checkout == 'true' && 'off' || 'rw' }} | |
base_ref: ${{ github.event.pull_request.base.ref || github.event.base_ref || 'latest' }} | |
- name: nx build | |
id: build | |
if: steps.setup.outcome == 'success' || steps.setup.outcome == 'skipped' | |
run: | | |
yarn nx run-many -t build --exclude tag:skip-gha-cache,all --parallel=3 | |
- name: Build examples | |
run: yarn nx run-many -t generate-examples --parallel=3 | |
- name: Calculate test matrices | |
id: matrix | |
run: | | |
if [[ "${{ github.event.inputs.nx_command || 'affected' }}" == "run-many" ]] ; then | |
count=10 | |
else | |
count=$(yarn -s nx show projects --affected --base ${{ steps.setup.outputs.base }} -t test | wc -l) | |
fi | |
matrix=$(node ./external/ag-shared/scripts/shard/calculate-shards.js eval --max 3 --ratio 1 --zero ${count}) | |
echo "test_matrix=${matrix}" >> $GITHUB_OUTPUT | |
echo "test_count=${count}" >> $GITHUB_OUTPUT | |
echo "Test matrix determined to be: ${matrix}" | |
pkg_matrix=$(node ./external/ag-shared/scripts/shard/calculate-pkg-shards.js) | |
echo "pkg_matrix=${pkg_matrix}" >> $GITHUB_OUTPUT | |
echo "Package test matrix determined to be: ${pkg_matrix}" | |
e2e_nx_count=$(yarn -s nx show projects --affected --base ${{ steps.setup.outputs.base }} -t test:e2e | wc -l) | |
if [[ ${e2e_nx_count} -gt 0 ]] ; then | |
e2e_count=$(cd packages/ag-charts-website/ ; npx playwright test --list | grep -v '!!!SKIPPED!!!' | wc -l) | |
else | |
e2e_count=0 | |
fi | |
e2e_matrix=$(node ./external/ag-shared/scripts/shard/calculate-shards.js eval --max 8 ${e2e_count}) | |
echo "e2e_matrix=${e2e_matrix}" >> $GITHUB_OUTPUT | |
echo "e2e_count=${e2e_count}" >> $GITHUB_OUTPUT | |
echo "E2E matrix determined to be: ${e2e_matrix}" | |
- name: Prepare Snapshot Branch | |
uses: ./.github/actions/snapshot-prepare | |
id: snapshot-prepare | |
- name: Perist build outputs | |
if: always() | |
uses: actions/upload-artifact@v4 | |
with: | |
name: e2e-init-outputs | |
path: | | |
dist/ | |
packages/*/dist/ | |
external/*/dist/ | |
build_lint: | |
runs-on: ubuntu-24.04 | |
name: Build & Lint | |
needs: init | |
outputs: | |
build: ${{ steps.build.outcome || '' }} | |
lint: ${{ steps.lint.outcome || '' }} | |
format: ${{ steps.format.outcome || '' }} | |
steps: | |
- name: Checkout | |
id: checkout | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Fetch Refs | |
run: | | |
git fetch origin --depth 1 latest next | |
git fetch origin --depth 1 tag latest-success next-success | |
- name: Setup | |
id: setup | |
uses: ./.github/actions/setup-nx | |
with: | |
cache_mode: ro | |
base_ref: ${{ github.event.pull_request.base.ref || github.event.base_ref }} | |
- name: nx format:check | |
id: format | |
if: steps.setup.outcome == 'success' || steps.setup.outcome == 'skipped' | |
run: | | |
if [[ "${{ github.event.inputs.nx_command || 'affected' }}" == "run-many" ]] ; then | |
yarn nx format:check --all | |
else | |
yarn nx format:check --base ${{ steps.setup.outputs.base }} | |
fi | |
- name: nx lint | |
id: lint | |
if: steps.setup.outcome == 'success' || steps.setup.outcome == 'skipped' | |
run: yarn nx ${{ github.event.inputs.nx_command || 'affected' }} -t lint --parallel=3 --exclude all | |
- name: nx build | |
id: build | |
if: steps.setup.outcome == 'success' || steps.setup.outcome == 'skipped' | |
run: | | |
yarn nx ${{ github.event.inputs.nx_command || 'affected' }} -t build --parallel=3 --exclude all | |
- name: nx generate | |
id: generate | |
if: steps.setup.outcome == 'success' || steps.setup.outcome == 'skipped' | |
run: yarn nx ${{ github.event.inputs.nx_command || 'affected' }} -t generate | |
- name: nx run-many -t validate-examples | |
if: steps.setup.outcome == 'success' || steps.setup.outcome == 'skipped' | |
run: yarn nx ${{ github.event.inputs.nx_command || 'affected' }} -t validate-examples --parallel=3 --exclude all | |
test: | |
runs-on: ubuntu-24.04 | |
name: Unit & Integration Tests (${{ matrix.shard }}/${{ strategy.job-total }}) | |
permissions: | |
contents: write | |
needs: init | |
if: needs.init.outputs.test_count > 0 | |
strategy: | |
fail-fast: false | |
matrix: ${{ fromJson(needs.init.outputs.test_matrix )}} | |
env: | |
NX_PARALLEL: 1 | |
NX_BASE: ${{ needs.init.outputs.nx_base }} | |
steps: | |
- name: Checkout | |
id: checkout | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Fetch Refs | |
run: | | |
git fetch origin --depth 1 latest next | |
git fetch origin --depth 1 tag latest-success next-success | |
- name: Setup | |
id: setup | |
uses: ./.github/actions/setup-nx | |
with: | |
cache_mode: ro | |
base_ref: ${{ github.event.pull_request.base.ref || github.event.base_ref }} | |
- name: nx test | |
if: matrix.shard != 0 | |
id: test | |
run: yarn nx ${{ github.event.inputs.nx_command || 'affected' }} -t test --configuration=ci --exclude tag:no-sharding --exclude all --shard=${{ matrix.shard }}/$((${{ strategy.job-total }} - 1)) | |
- name: nx test (non-sharded) | |
if: matrix.shard == 0 | |
id: test-no-shard | |
run: yarn nx ${{ github.event.inputs.nx_command || 'affected' }} -t test --configuration=ci --exclude '*,!tag:no-sharding' | |
- name: nx benchmark | |
if: matrix.shard == 0 | |
id: benchmark | |
run: yarn nx ${{ github.event.inputs.nx_command || 'affected' }} -t benchmark --configuration=ci --exclude all | |
- name: nx pack:verify | |
if: matrix.shard == 0 | |
id: pack-verify | |
run: yarn nx ${{ github.event.inputs.nx_command || 'affected' }} -t pack:verify | |
- name: Snapshot Branch | |
uses: ./.github/actions/snapshot-branch | |
with: | |
path: packages/ag-charts-{community,enterprise}/{benchmarks,src}/ | |
source_branch: ${{ github.head_ref || 'latest' }} | |
branch: ${{ needs.init.outputs.snapshot_branch }} | |
type: test (shard ${{matrix.shard}}) | |
- name: Perist test results | |
if: always() | |
uses: actions/upload-artifact@v4 | |
with: | |
name: test-results-${{matrix.shard}} | |
path: | | |
reports/ | |
packages/**/__diff_output__/* | |
e2e: | |
runs-on: ubuntu-latest | |
name: E2E Tests (${{ matrix.shard }}/${{ strategy.job-total }}) | |
permissions: | |
contents: write | |
needs: init | |
if: needs.init.outputs.e2e_count > 0 | |
strategy: | |
fail-fast: false | |
matrix: ${{ fromJson(needs.init.outputs.e2e_matrix )}} | |
env: | |
NX_BASE: ${{ needs.init.outputs.nx_base }} | |
AG_FORCE_ALL_TESTS: 1 | |
steps: | |
- name: Checkout | |
id: checkout | |
uses: actions/checkout@v4 | |
- name: Restore Init Build Outputs | |
uses: actions/download-artifact@v4 | |
with: | |
name: e2e-init-outputs | |
- name: Setup | |
id: setup | |
uses: ./.github/actions/setup-nx | |
with: | |
yarn_postinstall: no-install | |
nx_restore: false # Restored in previous step. | |
cache_mode: ro | |
base_ref: ${{ github.event.pull_request.base.ref || github.event.base_ref }} | |
- name: nx test:e2e | |
id: test | |
run: | | |
cd packages/ag-charts-website/ | |
./playwright.sh --host test -u --shard=${{ matrix.shard }}/${{ strategy.job-total }} | |
timeout-minutes: 15 | |
- name: Snapshot Branch | |
uses: ./.github/actions/snapshot-branch | |
with: | |
path: packages/ag-charts-website/e2e/ | |
source_branch: ${{ github.head_ref || 'latest' }} | |
branch: ${{ needs.init.outputs.snapshot_branch }} | |
type: test:e2e (shard ${{matrix.shard}}) | |
- name: Perist test results | |
if: always() | |
uses: actions/upload-artifact@v4 | |
with: | |
name: test-results-e2e-shard-${{matrix.shard}} | |
path: | | |
reports/ | |
fw_pkg_test: | |
runs-on: ubuntu-24.04 | |
name: Framework Package Tests (${{ matrix.framework }}) | |
permissions: | |
contents: write | |
needs: init | |
strategy: | |
fail-fast: false | |
matrix: ${{ fromJson(needs.init.outputs.test_pkg_matrix )}} | |
if: (needs.init.outputs.build_type == 'latest' || needs.init.outputs.build_type == 'release') | |
env: | |
NX_BASE: ${{ needs.init.outputs.nx_base }} | |
steps: | |
- name: Checkout | |
id: checkout | |
if: matrix.framework != 'none' | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Fetch Refs | |
if: matrix.framework != 'none' | |
run: | | |
git fetch origin --depth 1 latest next | |
git fetch origin --depth 1 tag latest-success next-success | |
- name: Setup | |
id: setup | |
if: matrix.framework != 'none' | |
uses: ./.github/actions/setup-nx | |
with: | |
cache_mode: ro | |
base_ref: ${{ github.event.pull_request.base.ref || github.event.base_ref }} | |
- name: nx package:test | |
id: package-test | |
if: matrix.framework != 'none' | |
run: yarn nx run-many -t test:package -p ${{ matrix.framework }}-package-tests --configuration=update | |
- name: Snapshot Branch | |
if: matrix.framework != 'none' | |
uses: ./.github/actions/snapshot-branch | |
with: | |
path: tests/*-package-tests/e2e/*-snapshots/ | |
source_branch: ${{ github.head_ref || 'latest' }} | |
branch: ${{ needs.init.outputs.snapshot_branch }} | |
type: ${{ matrix.framework }}-package-tests:test:package | |
report: | |
runs-on: ubuntu-24.04 | |
permissions: | |
contents: write | |
pull-requests: write | |
needs: [init, build_lint, test, e2e, sonarqube, fw_pkg_test] | |
if: cancelled() != true | |
steps: | |
- name: Checkout | |
id: checkout | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Fetch Refs | |
run: | | |
git fetch origin --depth 1 latest next | |
git fetch origin --depth 1 tag latest-success | |
- uses: actions/download-artifact@v4 | |
with: | |
path: test-results/ | |
- name: Snapshot Notify | |
id: snapshot-notify | |
uses: ./.github/actions/snapshot-notify | |
with: | |
branch: ${{ needs.init.outputs.snapshot_branch }} | |
github_token: ${{ secrets.GITHUB_TOKEN }} | |
slack_webhook: ${{ secrets.SLACK_WEBHOOK }} | |
- name: Merge JUnit Report XMLs | |
run: | | |
yarn global add junit-report-merger | |
reports=$(find test-results/ -name \*.xml -type f -exec basename \{\} \; | sort | uniq) | |
mkdir -p reports/ | |
echo "$reports" | (while read name ; do | |
yarn exec -s jrm reports/${name} "test-results/**/${name}" | |
done) | |
- name: Test Report | |
uses: dorny/test-reporter@v1 | |
if: needs.test.result == 'success' || needs.test.result == 'failure' | |
id: testReport | |
continue-on-error: true | |
with: | |
name: 'Tests Results' | |
path: reports/*.xml | |
reporter: jest-junit | |
- name: Check last job status | |
id: lastJobStatus | |
if: always() | |
run: | | |
WORKFLOW_STATUS="success" | |
if [[ "${{steps.snapshot-notify.outputs.updated}}" == 'true' ]] ; then | |
WORKFLOW_STATUS="failure" | |
elif [[ "${{ needs.build_lint.result }}" == "failure" ]] ; then | |
WORKFLOW_STATUS="failure" | |
elif [ "${{ needs.init.result }}" == "failure" ] ; then | |
WORKFLOW_STATUS="failure" | |
elif [ "${{ needs.test.result }}" == "failure" ] ; then | |
WORKFLOW_STATUS="failure" | |
elif [ "${{ needs.e2e.result }}" == "failure" ] ; then | |
WORKFLOW_STATUS="failure" | |
elif [ "${{ needs.fw_pkg_test.result }}" == "failure" ] ; then | |
WORKFLOW_STATUS="failure" | |
elif [ "${{ needs.sonarqube.result }}" == "failure" ] ; then | |
WORKFLOW_STATUS="partial" | |
fi | |
echo "workflowStatus=${WORKFLOW_STATUS}" >> $GITHUB_OUTPUT | |
LAST_WORKFLOW_STATUS=$(gh run list --workflow .github/workflows/ci.yml -b ${{ github.ref_name }} | grep -oh "completed.*" | grep -v "cancelled" | head -1 | awk '{print $2}') | |
if [ "$GITHUB_RUN_ATTEMPT" -ge 2 ]; then | |
# Handle re-run cases - there is no way to query the previous run status, so we assume the most | |
# common scenario will be re-run after failure. | |
LAST_WORKFLOW_STATUS="failure" | |
fi | |
if [ "$LAST_WORKFLOW_STATUS" != "$WORKFLOW_STATUS" ]; then | |
echo "status changed from $LAST_WORKFLOW_STATUS to $WORKFLOW_STATUS" | |
echo "changedState=true" >> $GITHUB_OUTPUT | |
else | |
echo "status is still $WORKFLOW_STATUS" | |
echo "changedState=false" >> $GITHUB_OUTPUT | |
fi | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- name: Commit History | |
id: commits | |
if: always() && job.status != 'cancelled' && (github.ref == 'refs/heads/latest' || github.ref == 'refs/heads/next') && steps.lastJobStatus.outputs.changedState == 'true' | |
run: | | |
GIT_LOG=$(git log HEAD ^${{ needs.init.outputs.nx_base }} --format="%an (%h) %s") | |
echo "GIT_LOG<<EOF" >> $GITHUB_ENV | |
echo "$GIT_LOG" >> $GITHUB_ENV | |
echo "EOF" >> $GITHUB_ENV | |
- name: Tag Latest Successful Commit | |
if: success() && (github.ref == 'refs/heads/latest' || github.ref == 'refs/heads/next') && steps.lastJobStatus.outputs.workflowStatus != 'failure' | |
uses: EndBug/latest-tag@latest | |
with: | |
ref: ${{ github.ref_name }}-success | |
description: Latest commit to pass GitHub Actions workflow on ${{ github.ref_name }} branch. | |
- name: Slack Notification | |
uses: rtCamp/action-slack-notify@v2 | |
if: always() && job.status != 'cancelled' && (github.ref == 'refs/heads/latest' || github.ref == 'refs/heads/next') && steps.lastJobStatus.outputs.changedState == 'true' | |
env: | |
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} | |
SLACK_COLOR: ${{ steps.lastJobStatus.outputs.workflowStatus != 'failure' && 'success' || 'failure' }} | |
SLACK_ICON: https://avatars.slack-edge.com/2020-11-25/1527503386626_319578f21381f9641cd8_192.png | |
SLACK_USERNAME: ag-charts CI | |
SLACK_FOOTER: '' | |
SLACK_MESSAGE: > | |
Build: ${{ needs.build_lint.outputs.build == 'success' && '✅' || needs.build_lint.outputs.build == 'failure' && '❌' || 'NA' }} | |
Lint: ${{ needs.build_lint.outputs.lint == 'success' && '✅' || needs.build_lint.outputs.lint == 'failure' && '❌' || 'NA' }} | |
Format: ${{ needs.build_lint.outputs.format == 'success' && '✅' || needs.build_lint.outputs.format == 'failure' && '❌' || 'NA' }} | |
Test: ${{ needs.test.result == 'success' && '✅' || needs.test.result == 'failure' && '❌' || 'NA' }} | |
E2E: ${{ needs.e2e.result == 'success' && '✅' || needs.e2e.result == 'failure' && '❌' || 'NA' }} | |
FW Pkg: ${{ needs.fw_pkg_test.result == 'success' && '✅' || needs.fw_pkg_test.result == 'failure' && '❌' || 'NA' }} | |
Sonar: ${{ needs.sonarqube.result == 'success' && '✅' || needs.sonarqube.result == 'failure' && '❌' || 'NA' }} | |
*Changes:* | |
${{ env.GIT_LOG }} | |
- name: Fail job if workflow failed | |
if: success() && steps.lastJobStatus.outputs.workflowStatus == 'failure' | |
run: | | |
echo "Workflow failed, failing the build." | |
exit 1 | |
sonarqube: | |
runs-on: ubuntu-24.04 | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
# Disabling shallow clones is recommended for improving the relevancy of reporting | |
fetch-depth: 0 | |
- name: SonarQube Scan | |
uses: sonarsource/sonarqube-scan-action@master | |
with: | |
args: > | |
-Dsonar.qualitygate.wait=true | |
env: | |
SONAR_TOKEN: ${{ secrets.SONAR_LOGIN }} | |
SONAR_HOST_URL: https://sonarcloud.io |