chore(deps): update to latest #6379
Workflow file for this run
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: Demos Visual Tests | |
| concurrency: | |
| group: wf-${{github.event.pull_request.number || github.sha}}-${{github.workflow}} | |
| cancel-in-progress: true | |
| on: | |
| pull_request: | |
| paths-ignore: | |
| - 'apps/**/*.md' | |
| merge_group: | |
| workflow_dispatch: | |
| env: | |
| NX_SKIP_NX_CACHE: ${{ contains(github.event.pull_request.labels.*.name, 'skip-cache') && 'true' || 'false' }} | |
| RUN_TESTS: true | |
| jobs: | |
| check-should-run: | |
| name: Check if tests should run | |
| runs-on: ubuntu-latest | |
| outputs: | |
| should-run: ${{ steps.check.outputs.should-run }} | |
| steps: | |
| - name: Check RUN_TESTS flag | |
| id: check | |
| run: echo "should-run=${{ env.RUN_TESTS }}" >> $GITHUB_OUTPUT | |
| get-changes: | |
| runs-on: ubuntu-latest | |
| needs: check-should-run | |
| if: github.event_name == 'pull_request' && needs.check-should-run.outputs.should-run == 'true' | |
| name: Get changed demos | |
| timeout-minutes: 5 | |
| outputs: | |
| has-changed-demos: ${{ steps.check-changes.outputs.has-changed-demos }} | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Get changed files | |
| uses: DevExpress/github-actions/get-changed-files@v1 | |
| with: | |
| gh-token: ${{ secrets.GITHUB_TOKEN }} | |
| paths: 'apps/demos/Demos/**/*' | |
| output: apps/demos/changed-files.json | |
| - name: Display changed files | |
| id: check-changes | |
| run: | | |
| HAS_CHANGED="false" | |
| if [ -f "apps/demos/changed-files.json" ]; then | |
| DEMO_COUNT=$(jq length apps/demos/changed-files.json) | |
| echo "Found changed-files.json" | |
| echo "Content of changed-files.json:" | |
| cat apps/demos/changed-files.json | |
| echo "Number of changed files: $DEMO_COUNT" | |
| if [ "$DEMO_COUNT" -gt 0 ]; then | |
| HAS_CHANGED="true" | |
| fi | |
| else | |
| echo "changed-files.json not found" | |
| fi | |
| echo "has-changed-demos=${HAS_CHANGED}" >> $GITHUB_OUTPUT | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: changed-demos | |
| path: apps/demos/changed-files.json | |
| retention-days: 1 | |
| determine-framework-tests-scope: | |
| runs-on: ubuntu-latest | |
| name: Determine scope for framework tests | |
| needs: [check-should-run, get-changes] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| (needs.get-changes.result == 'success' || needs.get-changes.result == 'skipped') | |
| outputs: | |
| framework-tests-scope: ${{ steps.determine.outputs.framework-tests-scope }} | |
| steps: | |
| - name: Determine framework tests scope | |
| id: determine | |
| run: | | |
| if [ "${{ github.event_name }}" != "pull_request" ] || [ "${{ contains(github.event.pull_request.labels.*.name, 'force all tests') }}" = "true" ]; then | |
| echo "Framework tests scope: all demos" | |
| echo "framework-tests-scope=all" >> $GITHUB_OUTPUT | |
| elif [ "${{ needs.get-changes.outputs.has-changed-demos }}" = "true" ]; then | |
| echo "Framework tests scope: changed demos" | |
| echo "framework-tests-scope=changed" >> $GITHUB_OUTPUT | |
| else | |
| echo "Framework tests NOT needed" | |
| echo "framework-tests-scope=none" >> $GITHUB_OUTPUT | |
| fi | |
| determine-jquery-test-matrix: | |
| runs-on: ubuntu-latest | |
| name: Determine jQuery test matrix | |
| needs: [check-should-run, determine-framework-tests-scope] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.determine-framework-tests-scope.result == 'success' | |
| outputs: | |
| matrix: ${{ steps.matrix.outputs.matrix }} | |
| steps: | |
| - name: Build matrix | |
| id: matrix | |
| run: | | |
| base_matrix=$(cat <<'JSON' | |
| [ | |
| { "STRATEGY": "screenshots", "THEME": "material.blue.light", "CONSTEL": "jquery(1/3)" }, | |
| { "STRATEGY": "screenshots", "THEME": "material.blue.light", "CONSTEL": "jquery(2/3)" }, | |
| { "STRATEGY": "screenshots", "THEME": "material.blue.light", "CONSTEL": "jquery(3/3)" }, | |
| { "STRATEGY": "screenshots", "THEME": "fluent.blue.light", "CONSTEL": "jquery(1/3)" }, | |
| { "STRATEGY": "screenshots", "THEME": "fluent.blue.light", "CONSTEL": "jquery(2/3)" }, | |
| { "STRATEGY": "screenshots", "THEME": "fluent.blue.light", "CONSTEL": "jquery(3/3)" }, | |
| { "STRATEGY": "accessibility", "THEME": "material.blue.light", "CONSTEL": "jquery" }, | |
| { "STRATEGY": "accessibility", "THEME": "fluent.blue.light", "CONSTEL": "jquery" } | |
| ] | |
| JSON | |
| ) | |
| dark_accessibility_matrix=$(cat <<'JSON' | |
| [ | |
| { "STRATEGY": "accessibility", "THEME": "material.blue.dark", "CONSTEL": "jquery" }, | |
| { "STRATEGY": "accessibility", "THEME": "fluent.blue.dark", "CONSTEL": "jquery" } | |
| ] | |
| JSON | |
| ) | |
| matrix=$(jq -c -n \ | |
| --argjson base "$base_matrix" \ | |
| --argjson darkAccessibility "$dark_accessibility_matrix" \ | |
| --arg frameworkTestsScope "${{ needs.determine-framework-tests-scope.outputs.framework-tests-scope }}" \ | |
| '{ include: ($base + (if $frameworkTestsScope != "none" then $darkAccessibility else [] end)) }') | |
| echo "matrix=$matrix" >> $GITHUB_OUTPUT | |
| build-devextreme: | |
| runs-on: devextreme-shr2 | |
| name: Build DevExtreme | |
| needs: [check-should-run, determine-framework-tests-scope] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.determine-framework-tests-scope.result == 'success' | |
| env: | |
| NODE_OPTIONS: --max-old-space-size=8192 | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache@v5 | |
| name: Setup pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-cache | |
| - name: Lookup nx cache | |
| id: lookup-nx-cache | |
| uses: actions/cache/restore@v5 | |
| with: | |
| path: | | |
| .nx/cache | |
| .nx/workspace-data/*.db | |
| .nx/workspace-data/*.db-wal | |
| .nx/workspace-data/*.db-shm | |
| key: ${{ runner.os }}-nx-v2-${{ github.workflow }}-${{ github.job }}-${{ github.sha }} | |
| restore-keys: | | |
| ${{ runner.os }}-nx-v2-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}- | |
| ${{ runner.os }}-nx-v2-${{ github.workflow }}-${{ github.job }}- | |
| ${{ runner.os }}-nx-v2- | |
| lookup-only: true | |
| - name: Show nx cache status | |
| shell: bash | |
| run: | | |
| echo "Nx cache lookup exact hit: ${{ steps.lookup-nx-cache.outputs.cache-hit }}" | |
| echo "Nx cache primary key: ${{ steps.lookup-nx-cache.outputs.cache-primary-key }}" | |
| echo "Nx cache matched key: ${{ steps.lookup-nx-cache.outputs.cache-matched-key }}" | |
| if [ -z "${{ steps.lookup-nx-cache.outputs.cache-matched-key }}" ]; then | |
| echo "Nx cache lookup: miss" | |
| elif [ "${{ steps.lookup-nx-cache.outputs.cache-hit }}" = "true" ]; then | |
| echo "Nx cache lookup: exact hit" | |
| else | |
| echo "Nx cache lookup: partial hit via restore-keys" | |
| fi | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Setup nx cache | |
| id: setup-nx-cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| .nx/cache | |
| .nx/workspace-data/*.db | |
| .nx/workspace-data/*.db-wal | |
| .nx/workspace-data/*.db-shm | |
| key: ${{ runner.os }}-nx-v2-${{ github.workflow }}-${{ github.job }}-${{ github.sha }} | |
| restore-keys: | | |
| ${{ runner.os }}-nx-v2-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}- | |
| ${{ runner.os }}-nx-v2-${{ github.workflow }}-${{ github.job }}- | |
| ${{ runner.os }}-nx-v2- | |
| - name: DevExtreme - Build | |
| if: needs.determine-framework-tests-scope.outputs.framework-tests-scope == 'none' | |
| shell: bash | |
| run: | | |
| pnpm exec nx build devextreme-scss | |
| pnpm exec nx build devextreme -c testing | |
| - name: DevExtreme - Build-all | |
| if: needs.determine-framework-tests-scope.outputs.framework-tests-scope != 'none' | |
| run: pnpm nx all:build-testing workflows | |
| - name: Zip artifacts (for jQuery tests) | |
| working-directory: ./packages/devextreme | |
| run: | | |
| 7z a -tzip -mx3 -mmt2 artifacts.zip artifacts ../devextreme-scss/scss/bundles | |
| - name: Upload build artifacts (for jQuery tests) | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: devextreme-artifacts-jquery | |
| path: ./packages/devextreme/artifacts.zip | |
| retention-days: 1 | |
| - name: Move packages | |
| if: needs.determine-framework-tests-scope.outputs.framework-tests-scope != 'none' | |
| run: | | |
| mv ./packages/devextreme/artifacts/npm/devextreme/*.tgz ./devextreme-installer.tgz | |
| mv ./packages/devextreme/artifacts/npm/devextreme-dist/*.tgz ./devextreme-dist-installer.tgz | |
| mv ./packages/devextreme-angular/npm/dist/*.tgz ./devextreme-angular-installer.tgz | |
| mv ./packages/devextreme-react/npm/*.tgz ./devextreme-react-installer.tgz | |
| mv ./packages/devextreme-vue/npm/*.tgz ./devextreme-vue-installer.tgz | |
| - name: Copy build artifacts | |
| if: needs.determine-framework-tests-scope.outputs.framework-tests-scope != 'none' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: devextreme-sources | |
| path: | | |
| devextreme-installer.tgz | |
| devextreme-dist-installer.tgz | |
| devextreme-angular-installer.tgz | |
| devextreme-react-installer.tgz | |
| devextreme-vue-installer.tgz | |
| retention-days: 1 | |
| build-demos: | |
| runs-on: devextreme-shr2 | |
| name: Build Demos Bundles | |
| timeout-minutes: 30 | |
| needs: [check-should-run, determine-framework-tests-scope, build-devextreme] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.determine-framework-tests-scope.result == 'success' && | |
| needs.determine-framework-tests-scope.outputs.framework-tests-scope != 'none' && | |
| needs.build-devextreme.result == 'success' | |
| env: | |
| NODE_OPTIONS: --max-old-space-size=8192 | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - name: Download devextreme sources | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-sources | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache/restore@v5 | |
| name: Restore pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-cache | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Install tgz | |
| working-directory: apps/demos | |
| run: pnpm add --ignore-workspace --allow-build=core-js --allow-build=inferno devextreme-aspnet-data@5.1.0 devextreme-aspnet-data-nojquery@5.1.0 ../../devextreme-installer.tgz ../../devextreme-dist-installer.tgz ../../devextreme-react-installer.tgz ../../devextreme-vue-installer.tgz ../../devextreme-angular-installer.tgz && rm -f pnpm-workspace.yaml pnpm-lock.yaml | |
| # - name: Build wrappers | |
| # run: pnpm exec nx run-many -t pack -p devextreme-angular devextreme-react devetreme-vue | |
| # - name: Link wrappers packages | |
| # run: pnpm install --frozen-lockfile | |
| - name: Prepare bundles | |
| working-directory: apps/demos | |
| run: pnpm exec nx prepare-bundles | |
| - name: Demos - Run tsc | |
| working-directory: apps/demos | |
| run: pnpm exec tsc --noEmit | |
| - name: Copy build artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: devextreme-bundles | |
| path: | | |
| apps/demos/bundles/ | |
| retention-days: 1 | |
| lint: | |
| name: Check TS and lint code base | |
| needs: [check-should-run, determine-framework-tests-scope, build-devextreme] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.determine-framework-tests-scope.result == 'success' && | |
| needs.determine-framework-tests-scope.outputs.framework-tests-scope != 'none' && | |
| needs.build-devextreme.result == 'success' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Download artifacts | |
| if: github.event_name == 'pull_request' | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: changed-demos | |
| path: apps/demos | |
| continue-on-error: true | |
| - name: Download devextreme sources | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-sources | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache/restore@v5 | |
| name: Restore pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-cache | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Install tgz | |
| working-directory: apps/demos | |
| run: pnpm add --ignore-workspace --allow-build=core-js --allow-build=inferno devextreme-aspnet-data@5.1.0 devextreme-aspnet-data-nojquery@5.1.0 ../../devextreme-installer.tgz ../../devextreme-dist-installer.tgz ../../devextreme-react-installer.tgz ../../devextreme-vue-installer.tgz ../../devextreme-angular-installer.tgz && rm -f pnpm-workspace.yaml pnpm-lock.yaml | |
| - name: Demos - Check Vue TS | |
| id: ts_vue | |
| continue-on-error: true | |
| working-directory: apps/demos | |
| run: pnpm run ts-check-vue | |
| # - name: Run check TS for Angular | |
| # working-directory: apps/demos | |
| # run: pnpm run ts-check-ng | |
| - name: Demos - Check React TS | |
| id: ts_react | |
| continue-on-error: true | |
| working-directory: apps/demos | |
| run: pnpm run ts-check-react | |
| - name: Run lint on all demos | |
| id: lint_all | |
| if: needs.determine-framework-tests-scope.outputs.framework-tests-scope == 'all' | |
| continue-on-error: true | |
| working-directory: apps/demos | |
| env: | |
| DEBUG: 'eslint:cli-engine,stylelint:standalone' | |
| NODE_OPTIONS: --max-old-space-size=8192 | |
| run: pnpm exec nx lint | |
| - name: Run lint on changed demos | |
| id: lint_changed | |
| if: needs.determine-framework-tests-scope.outputs.framework-tests-scope == 'changed' | |
| continue-on-error: true | |
| working-directory: apps/demos | |
| env: | |
| DEBUG: 'eslint:cli-engine,stylelint:standalone' | |
| run: | | |
| pnpm exec nx lint-non-demos | |
| if [ -f "changed-files.json" ]; then | |
| echo "Running lint-demos on changed files" | |
| CHANGED_DEMOS=$(jq -r '.[].filename' changed-files.json \ | |
| | grep '^apps/demos/Demos/' \ | |
| | sed 's|^apps/demos/||' \ | |
| | while read f; do | |
| [ -f "$f" ] && echo "$f" | |
| done \ | |
| | tr '\n' ' ') | |
| if [ ! -z "$CHANGED_DEMOS" ]; then | |
| echo "Changed demo files: $CHANGED_DEMOS" | |
| pnpm run eslint $CHANGED_DEMOS | |
| else | |
| echo "No demo files changed, skipping lint-demos" | |
| fi | |
| else | |
| echo "changed-files.json not found" | |
| pnpm run lint-demos | |
| fi | |
| - name: Check TS and lint results | |
| if: always() | |
| env: | |
| TS_VUE_OUTCOME: ${{ steps.ts_vue.outcome }} | |
| TS_REACT_OUTCOME: ${{ steps.ts_react.outcome }} | |
| LINT_ALL_OUTCOME: ${{ steps.lint_all.outcome }} | |
| LINT_CHANGED_OUTCOME: ${{ steps.lint_changed.outcome }} | |
| run: | | |
| failed=0 | |
| for check in \ | |
| "Demos - Check Vue TS:$TS_VUE_OUTCOME" \ | |
| "Demos - Check React TS:$TS_REACT_OUTCOME" \ | |
| "Run lint on all demos:$LINT_ALL_OUTCOME" \ | |
| "Run lint on changed demos:$LINT_CHANGED_OUTCOME"; do | |
| name="${check%%:*}" | |
| outcome="${check#*:}" | |
| if [ "$outcome" = "failure" ]; then | |
| echo "::error::$name failed" | |
| failed=1 | |
| fi | |
| done | |
| exit "$failed" | |
| check-generated-demos-changed: | |
| name: Check generated demos (changed only) | |
| runs-on: devextreme-shr2 | |
| timeout-minutes: 10 | |
| needs: [check-should-run, get-changes, build-devextreme, determine-framework-tests-scope] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.determine-framework-tests-scope.result == 'success' && | |
| needs.determine-framework-tests-scope.outputs.framework-tests-scope == 'changed' && | |
| needs.build-devextreme.result == 'success' | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Download changed demos | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: changed-demos | |
| path: apps/demos | |
| continue-on-error: true | |
| - name: Detect changed React TS demos | |
| id: changed-react-demos | |
| working-directory: apps/demos | |
| run: | | |
| if [ ! -f "changed-files.json" ]; then | |
| echo "changed-files.json not found, skipping generated JS demos check" | |
| echo "has-react-demos=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| jq -r '.[].filename' changed-files.json \ | |
| | grep '/React/' \ | |
| | grep -E '\.tsx?$' \ | |
| | sed 's|^apps/demos/||' \ | |
| | sed -E 's|/[^/]*\.tsx?$||' \ | |
| | sort \ | |
| | uniq > changed-react-demos.txt || true | |
| if [ -s changed-react-demos.txt ]; then | |
| echo "Changed React demos:" | |
| cat changed-react-demos.txt | |
| echo "has-react-demos=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "No React demos found in changed files, skipping conversion" | |
| echo "has-react-demos=false" >> $GITHUB_OUTPUT | |
| fi | |
| - uses: pnpm/action-setup@v6 | |
| if: steps.changed-react-demos.outputs.has-react-demos == 'true' | |
| with: | |
| run_install: false | |
| - name: Use Node.js | |
| if: steps.changed-react-demos.outputs.has-react-demos == 'true' | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - name: Download devextreme sources | |
| if: steps.changed-react-demos.outputs.has-react-demos == 'true' | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-sources | |
| - name: Get pnpm store directory | |
| if: steps.changed-react-demos.outputs.has-react-demos == 'true' | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache/restore@v5 | |
| if: steps.changed-react-demos.outputs.has-react-demos == 'true' | |
| name: Restore pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-cache | |
| - name: Install dependencies | |
| if: steps.changed-react-demos.outputs.has-react-demos == 'true' | |
| run: pnpm install --frozen-lockfile | |
| - name: Install tgz | |
| if: steps.changed-react-demos.outputs.has-react-demos == 'true' | |
| working-directory: apps/demos | |
| run: pnpm add --ignore-workspace --allow-build=core-js --allow-build=inferno devextreme-aspnet-data@5.1.0 devextreme-aspnet-data-nojquery@5.1.0 ../../devextreme-installer.tgz ../../devextreme-dist-installer.tgz ../../devextreme-react-installer.tgz ../../devextreme-vue-installer.tgz ../../devextreme-angular-installer.tgz && rm -f pnpm-workspace.yaml pnpm-lock.yaml | |
| - name: Prepare JS | |
| if: steps.changed-react-demos.outputs.has-react-demos == 'true' | |
| working-directory: apps/demos | |
| run: pnpm run prepare-js | |
| - name: Check generated JS demos | |
| if: steps.changed-react-demos.outputs.has-react-demos == 'true' | |
| working-directory: apps/demos | |
| run: | | |
| echo "Running convert-to-js on changed files only" | |
| xargs -r pnpm run convert-to-js < changed-react-demos.txt | |
| git add ./Demos -N | |
| if git diff --exit-code . ':!package.json' ; then | |
| echo "Generated JS demos are up-to-date" | |
| else | |
| echo "Generated JS demos are outdated. Execute 'pnpm run convert-to-js split' and commit changes." | |
| echo "If you see another diff, ensure that extra listed files have LF endings." | |
| exit 1 | |
| fi | |
| check-generated-demos-all: | |
| name: Check generated demos | |
| runs-on: devextreme-shr2 | |
| timeout-minutes: 15 | |
| needs: [check-should-run, build-devextreme, determine-framework-tests-scope] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.determine-framework-tests-scope.result == 'success' && | |
| needs.determine-framework-tests-scope.outputs.framework-tests-scope == 'all' && | |
| needs.build-devextreme.result == 'success' | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| run_install: false | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - name: Download devextreme sources | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-sources | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache/restore@v5 | |
| name: Restore pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-cache | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Install tgz | |
| working-directory: apps/demos | |
| run: pnpm add --ignore-workspace --allow-build=core-js --allow-build=inferno devextreme-aspnet-data@5.1.0 devextreme-aspnet-data-nojquery@5.1.0 ../../devextreme-installer.tgz ../../devextreme-dist-installer.tgz ../../devextreme-react-installer.tgz ../../devextreme-vue-installer.tgz ../../devextreme-angular-installer.tgz && rm -f pnpm-workspace.yaml pnpm-lock.yaml | |
| - name: Prepare JS | |
| working-directory: apps/demos | |
| run: pnpm run prepare-js | |
| - name: Check generated JS demos | |
| working-directory: apps/demos | |
| run: | | |
| echo "Running convert-to-js" | |
| pnpm run convert-to-js | |
| git add ./Demos -N | |
| if git diff --exit-code . ':!package.json' ; then | |
| echo "Generated JS demos are up-to-date" | |
| else | |
| echo "Generated JS demos are outdated. Execute 'pnpm run convert-to-js' and commit changes." | |
| echo "If you see another diff, ensure that extra listed files have LF endings." | |
| exit 1 | |
| fi | |
| testcafe-jquery: | |
| needs: [check-should-run, build-devextreme, determine-framework-tests-scope, determine-jquery-test-matrix] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.determine-framework-tests-scope.result == 'success' && | |
| needs.determine-jquery-test-matrix.result == 'success' && | |
| needs.build-devextreme.result == 'success' | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.determine-jquery-test-matrix.outputs.matrix) }} | |
| env: | |
| ACCESSIBILITY_TESTCAFE_REPORT_PATH: "accessibility_testcafe_report" | |
| runs-on: devextreme-shr2 | |
| name: ${{ matrix.CONSTEL }}-${{ matrix.STRATEGY }}-${{ matrix.THEME }} | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-artifacts-jquery | |
| path: ./packages/devextreme | |
| - name: Unpack artifacts | |
| working-directory: ./packages/devextreme | |
| run: 7z x artifacts.zip -aoa | |
| - name: Setup Chrome | |
| uses: ./.github/actions/setup-chrome | |
| with: | |
| chrome-version: '149.0.7827.114' | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache/restore@v5 | |
| name: Restore pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-cache | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Set Roboto font directory | |
| if: contains(matrix.THEME, 'material') | |
| run: echo "ROBOTO_FONT_DIR=${HOME}/.local/share/fonts/roboto" >> $GITHUB_ENV | |
| - name: Cache Roboto font | |
| if: contains(matrix.THEME, 'material') | |
| id: cache-roboto | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ env.ROBOTO_FONT_DIR }} | |
| key: roboto-font-${{ runner.os }}-8b0a1d0f5983c89bc2b93f1b5fb55f9e252744b5 | |
| - name: Install Roboto font for Material theme | |
| if: contains(matrix.THEME, 'material') && steps.cache-roboto.outputs.cache-hit != 'true' | |
| env: | |
| GOOGLE_FONTS_COMMIT: 8b0a1d0f5983c89bc2b93f1b5fb55f9e252744b5 | |
| ROBOTO_SHA256: d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134 | |
| run: | | |
| echo "Installing Roboto font from google/fonts (pinned commit)..." | |
| mkdir -p "$ROBOTO_FONT_DIR" | |
| BASE_URL="https://raw.githubusercontent.com/google/fonts/${GOOGLE_FONTS_COMMIT}/ofl/roboto" | |
| curl -fsSL "${BASE_URL}/Roboto%5Bwdth%2Cwght%5D.ttf" -o /tmp/Roboto.ttf | |
| echo "${ROBOTO_SHA256} /tmp/Roboto.ttf" | sha256sum -c - | |
| mv /tmp/Roboto.ttf "$ROBOTO_FONT_DIR/" | |
| echo "Roboto font installed" | |
| - name: Refresh font cache | |
| if: contains(matrix.THEME, 'material') | |
| run: fc-cache -f > /dev/null 2>&1 | |
| - name: Run Web Server | |
| run: python -m http.server 8080 & | |
| - name: Set Chrome flags | |
| id: chrome-flags | |
| run: | | |
| BASE_FLAGS="chrome:headless --window-size=1200,800 --disable-gpu --no-sandbox --disable-dev-shm-usage --disable-partial-raster --disable-skia-runtime-opts --run-all-compositor-stages-before-draw --disable-new-content-rendering-timeout --disable-threaded-animation --disable-threaded-scrolling --disable-checker-imaging --disable-image-animation-resync --use-gl=swiftshader --disable-features=PaintHolding --js-flags=--random-seed=2147483647" | |
| # For Material theme, enable better font rendering to avoid instability | |
| if [[ "${{ matrix.THEME }}" != *"material"* ]]; then | |
| BASE_FLAGS="$BASE_FLAGS --font-render-hinting=none --disable-font-subpixel-positioning" | |
| fi | |
| echo "flags=$BASE_FLAGS" >> $GITHUB_OUTPUT | |
| - name: Run TestCafe tests (jQuery) | |
| shell: bash | |
| working-directory: apps/demos | |
| env: | |
| NODE_OPTIONS: --max-old-space-size=8192 | |
| STRATEGY: ${{ matrix.STRATEGY }} | |
| CHANGEDFILEINFOSPATH: changed-files.json | |
| BROWSERS: ${{ steps.chrome-flags.outputs.flags }} | |
| #DEBUG: hammerhead:*,testcafe:* | |
| CONCURRENCY: 4 | |
| TCQUARANTINE: true | |
| CONSTEL: ${{ matrix.CONSTEL }} | |
| THEME: ${{ matrix.THEME }} | |
| # DISABLE_DEMO_TEST_SETTINGS: all # Uncomment to ignore all the visualtestrc.json settings | |
| # DISABLE_DEMO_TEST_SETTINGS: ignore # Uncomment to ignore the `ignore` field | |
| # DISABLE_DEMO_TEST_SETTINGS: comparison-options # Uncomment to ignore the `comparison-options` field | |
| CI_ENV: true # The `ignore` field in the visualtestrc.json should be disabled when running test locally | |
| run: pnpm exec nx test-testcafe | |
| - name: Show accessibility warnings | |
| if: matrix.STRATEGY == 'accessibility' | |
| working-directory: apps/demos | |
| run: | | |
| if [ -f "$ACCESSIBILITY_TESTCAFE_REPORT_PATH" ]; then | |
| message=$(cat $ACCESSIBILITY_TESTCAFE_REPORT_PATH) | |
| echo "::warning ::$message" | |
| else | |
| echo "Accessibility report not found. Skipping warning generation." | |
| fi | |
| - name: Sanitize job name | |
| if: ${{ failure() }} | |
| run: echo "JOB_NAME=$(echo "${{ matrix.CONSTEL }}-${{ matrix.THEME }}" | tr '/' '-')" >> $GITHUB_ENV | |
| - name: Copy screenshots artifacts | |
| if: failure() && matrix.STRATEGY == 'screenshots' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: screenshots-${{ env.JOB_NAME }} | |
| path: ${{ github.workspace }}/apps/demos/testing/artifacts/compared-screenshots/**/* | |
| if-no-files-found: ignore | |
| - name: Copy accessibility report | |
| if: matrix.STRATEGY == 'accessibility' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: accessibility-reports-${{ env.JOB_NAME }}-${{ matrix.THEME }} | |
| path: apps/demos/testing/artifacts/axe-reports/* | |
| if-no-files-found: ignore | |
| testcafe-frameworks-all: | |
| needs: [check-should-run, determine-framework-tests-scope, build-demos] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.determine-framework-tests-scope.result == 'success' && | |
| needs.determine-framework-tests-scope.outputs.framework-tests-scope == 'all' && | |
| needs.build-demos.result == 'success' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| CONSTEL: [ | |
| react(1/3), | |
| react(2/3), | |
| react(3/3), | |
| vue(1/5), | |
| vue(2/5), | |
| vue(3/5), | |
| vue(4/5), | |
| vue(5/5), | |
| angular(1/10), | |
| angular(2/10), | |
| angular(3/10), | |
| angular(4/10), | |
| angular(5/10), | |
| angular(6/10), | |
| angular(7/10), | |
| angular(8/10), | |
| angular(9/10), | |
| angular(10/10), | |
| ] | |
| THEME: ['fluent.blue.light'] | |
| runs-on: devextreme-shr2 | |
| name: ${{ matrix.CONSTEL }}-screenshots-${{ matrix.THEME }} | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Setup Chrome | |
| uses: ./.github/actions/setup-chrome | |
| with: | |
| chrome-version: '149.0.7827.114' | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - name: Download devextreme sources | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-sources | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache/restore@v5 | |
| name: Restore pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-cache | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Install tgz | |
| working-directory: apps/demos | |
| run: pnpm add --ignore-workspace --allow-build=core-js --allow-build=inferno devextreme-aspnet-data@5.1.0 devextreme-aspnet-data-nojquery@5.1.0 ../../devextreme-installer.tgz ../../devextreme-dist-installer.tgz ../../devextreme-react-installer.tgz ../../devextreme-vue-installer.tgz ../../devextreme-angular-installer.tgz && rm -f pnpm-workspace.yaml pnpm-lock.yaml | |
| - name: Prepare JS | |
| working-directory: apps/demos | |
| run: pnpm run prepare-js | |
| - name: Update bundles config | |
| working-directory: apps/demos | |
| run: pnpm exec gulp update-config | |
| - name: Create bundles dir | |
| run: mkdir -p apps/demos/bundles | |
| - name: Download bundles artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-bundles | |
| path: apps/demos/bundles | |
| - name: Run Web Server | |
| run: | | |
| python -m http.server 8080 & | |
| - name: Check runner resources | |
| run: | | |
| echo "CPU cores: $(nproc)" | |
| echo "Memory: $(free -h)" | |
| echo "Disk: $(df -h)" | |
| - name: Set concurrency based on framework | |
| id: set-concurrency | |
| run: | | |
| if [[ "${{ matrix.CONSTEL }}" == react* ]]; then | |
| echo "concurrency=4" >> $GITHUB_OUTPUT | |
| elif [[ "${{ matrix.CONSTEL }}" == vue* ]]; then | |
| echo "concurrency=3" >> $GITHUB_OUTPUT | |
| elif [[ "${{ matrix.CONSTEL }}" == angular* ]]; then | |
| echo "concurrency=3" >> $GITHUB_OUTPUT | |
| else | |
| echo "concurrency=2" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Run TestCafe tests | |
| shell: bash | |
| working-directory: apps/demos | |
| env: | |
| NODE_OPTIONS: --max-old-space-size=8192 | |
| BROWSERS: chrome:headless --window-size=1200,800 --disable-gpu --no-sandbox --disable-dev-shm-usage --disable-partial-raster --disable-skia-runtime-opts --run-all-compositor-stages-before-draw --disable-new-content-rendering-timeout --disable-threaded-animation --disable-threaded-scrolling --disable-checker-imaging --disable-image-animation-resync --use-gl=swiftshader --disable-features=PaintHolding --js-flags=--random-seed=2147483647 --font-render-hinting=none --disable-font-subpixel-positioning | |
| # DEBUG: hammerhead:*,testcafe:* | |
| CONCURRENCY: ${{ steps.set-concurrency.outputs.concurrency }} | |
| TCQUARANTINE: true | |
| CONSTEL: ${{ matrix.CONSTEL }} | |
| THEME: ${{ matrix.THEME }} | |
| # DISABLE_DEMO_TEST_SETTINGS: all # Uncomment to ignore all the visualtestrc.json settings | |
| # DISABLE_DEMO_TEST_SETTINGS: ignore # Uncomment to ignore the `ignore` field | |
| # DISABLE_DEMO_TEST_SETTINGS: comparison-options # Uncomment to ignore the `comparison-options` field | |
| CI_ENV: true # The `ignore` field in the visualtestrc.json should be disabled when running test locally | |
| run: pnpm exec nx test-testcafe | |
| - name: Sanitize job name | |
| if: ${{ failure() }} | |
| run: echo "JOB_NAME=$(echo "${{ matrix.CONSTEL }}-${{ matrix.THEME }}" | tr '/' '-')" >> $GITHUB_ENV | |
| - name: Copy screenshots artifacts | |
| if: ${{ failure() }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: screenshots-${{ env.JOB_NAME }} | |
| path: ${{ github.workspace }}/apps/demos/testing/artifacts/compared-screenshots/**/* | |
| if-no-files-found: ignore | |
| testcafe-frameworks-changed: | |
| needs: [check-should-run, determine-framework-tests-scope, build-demos] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.determine-framework-tests-scope.result == 'success' && | |
| needs.determine-framework-tests-scope.outputs.framework-tests-scope == 'changed' && | |
| needs.build-demos.result == 'success' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| CONSTEL: [react, vue, angular] | |
| THEME: ['fluent.blue.light'] | |
| runs-on: devextreme-shr2 | |
| name: ${{ matrix.CONSTEL }}-screenshots-${{ matrix.THEME }} | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Setup Chrome | |
| uses: ./.github/actions/setup-chrome | |
| with: | |
| chrome-version: '149.0.7827.114' | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - name: Download devextreme sources | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-sources | |
| - name: Download changed demos | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: changed-demos | |
| path: apps/demos | |
| continue-on-error: true | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache/restore@v5 | |
| name: Restore pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-cache | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Install tgz | |
| working-directory: apps/demos | |
| run: pnpm add --ignore-workspace --allow-build=core-js --allow-build=inferno devextreme-aspnet-data@5.1.0 devextreme-aspnet-data-nojquery@5.1.0 ../../devextreme-installer.tgz ../../devextreme-dist-installer.tgz ../../devextreme-react-installer.tgz ../../devextreme-vue-installer.tgz ../../devextreme-angular-installer.tgz && rm -f pnpm-workspace.yaml pnpm-lock.yaml | |
| - name: Prepare JS | |
| working-directory: apps/demos | |
| run: pnpm run prepare-js | |
| - name: Update bundles config | |
| working-directory: apps/demos | |
| run: pnpm exec gulp update-config | |
| - name: Create bundles dir | |
| run: mkdir -p apps/demos/bundles | |
| - name: Download bundles artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-bundles | |
| path: apps/demos/bundles | |
| - name: Download changes artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: changed-demos | |
| path: apps/demos | |
| - name: Run Web Server | |
| run: | | |
| python -m http.server 8080 & | |
| python -m http.server 8081 & | |
| python -m http.server 8082 & | |
| python -m http.server 8083 & | |
| - name: Run TestCafe tests | |
| shell: bash | |
| working-directory: apps/demos | |
| env: | |
| CHANGEDFILEINFOSPATH: changed-files.json | |
| BROWSERS: chrome:headless --window-size=1200,800 --disable-gpu --no-sandbox --disable-dev-shm-usage --disable-partial-raster --disable-skia-runtime-opts --run-all-compositor-stages-before-draw --disable-new-content-rendering-timeout --disable-threaded-animation --disable-threaded-scrolling --disable-checker-imaging --disable-image-animation-resync --use-gl=swiftshader --disable-features=PaintHolding --js-flags=--random-seed=2147483647 --font-render-hinting=none --disable-font-subpixel-positioning | |
| # DEBUG: hammerhead:*,testcafe:* | |
| CONCURRENCY: 1 | |
| TCQUARANTINE: true | |
| CONSTEL: ${{ matrix.CONSTEL }} | |
| THEME: ${{ matrix.THEME }} | |
| # DISABLE_DEMO_TEST_SETTINGS: all # Uncomment to ignore all the visualtestrc.json settings | |
| # DISABLE_DEMO_TEST_SETTINGS: ignore # Uncomment to ignore the `ignore` field | |
| # DISABLE_DEMO_TEST_SETTINGS: comparison-options # Uncomment to ignore the `comparison-options` field | |
| CI_ENV: true # The `ignore` field in the visualtestrc.json should be disabled when running test locally | |
| run: pnpm exec nx test-testcafe | |
| - name: Sanitize job name | |
| if: ${{ failure() }} | |
| run: echo "JOB_NAME=$(echo "${{ matrix.CONSTEL }}-${{ matrix.THEME }}" | tr '/' '-')" >> $GITHUB_ENV | |
| - name: Copy screenshots artifacts | |
| if: ${{ failure() }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: screenshots-${{ env.JOB_NAME }} | |
| path: ${{ github.workspace }}/apps/demos/testing/artifacts/compared-screenshots/**/* | |
| if-no-files-found: ignore | |
| merge-artifacts: | |
| runs-on: ubuntu-latest | |
| needs: [testcafe-jquery, testcafe-frameworks-all, testcafe-frameworks-changed] | |
| if: always() && (needs.testcafe-jquery.result == 'failure' || needs.testcafe-frameworks-all.result == 'failure' || needs.testcafe-frameworks-changed.result == 'failure') | |
| steps: | |
| - name: Merge jQuery screenshot artifacts | |
| if: needs.testcafe-jquery.result == 'failure' | |
| uses: actions/upload-artifact/merge@v7 | |
| continue-on-error: true | |
| with: | |
| name: screenshots-jquery | |
| pattern: screenshots-jquery* | |
| delete-merged: true | |
| - name: Merge React screenshot artifacts | |
| if: needs.testcafe-frameworks-all.result == 'failure' || needs.testcafe-frameworks-changed.result == 'failure' | |
| uses: actions/upload-artifact/merge@v7 | |
| continue-on-error: true | |
| with: | |
| name: screenshots-react | |
| pattern: screenshots-react* | |
| delete-merged: true | |
| - name: Merge Vue screenshot artifacts | |
| if: needs.testcafe-frameworks-all.result == 'failure' || needs.testcafe-frameworks-changed.result == 'failure' | |
| uses: actions/upload-artifact/merge@v7 | |
| continue-on-error: true | |
| with: | |
| name: screenshots-vue | |
| pattern: screenshots-vue* | |
| delete-merged: true | |
| - name: Merge Angular screenshot artifacts | |
| if: needs.testcafe-frameworks-all.result == 'failure' || needs.testcafe-frameworks-changed.result == 'failure' | |
| uses: actions/upload-artifact/merge@v7 | |
| continue-on-error: true | |
| with: | |
| name: screenshots-angular | |
| pattern: screenshots-angular* | |
| delete-merged: true | |
| - name: Merge jQuery accessibility reports | |
| if: needs.testcafe-jquery.result == 'failure' | |
| uses: actions/upload-artifact/merge@v7 | |
| continue-on-error: true | |
| with: | |
| name: accessibility-reports-jquery | |
| pattern: accessibility-reports-* | |
| delete-merged: true | |
| csp-check-jquery: | |
| name: CSP check (jQuery) | |
| needs: [check-should-run, build-devextreme] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.build-devextreme.result == 'success' | |
| runs-on: devextreme-shr2 | |
| timeout-minutes: 60 | |
| env: | |
| CSP_USE_BUNDLED: '0' | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-artifacts-jquery | |
| path: ./packages/devextreme | |
| - name: Unpack artifacts | |
| working-directory: ./packages/devextreme | |
| run: 7z x artifacts.zip -aoa | |
| - name: Setup Chrome | |
| uses: ./.github/actions/setup-chrome | |
| with: | |
| chrome-version: '149.0.7827.114' | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache/restore@v5 | |
| name: Restore pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-cache | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Start CSP Server | |
| run: node apps/demos/utils/server/csp-server.js 8080 & | |
| - name: Run CSP Check | |
| working-directory: apps/demos | |
| env: | |
| CSP_FRAMEWORKS: jQuery | |
| CHROME_PATH: google-chrome-stable | |
| run: node utils/server/csp-check.js | |
| - name: Upload CSP report | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: csp-violations-jquery | |
| path: apps/demos/csp-reports/ | |
| if-no-files-found: ignore | |
| csp-check-frameworks: | |
| name: ${{ matrix.SHARD_TOTAL == 1 && format('CSP check ({0})', matrix.FRAMEWORK) || format('CSP check ({0} {1}/{2})', matrix.FRAMEWORK, matrix.SHARD_INDEX, matrix.SHARD_TOTAL) }} | |
| needs: [check-should-run, determine-framework-tests-scope, build-devextreme] | |
| if: | | |
| always() && | |
| needs.check-should-run.outputs.should-run == 'true' && | |
| needs.determine-framework-tests-scope.result == 'success' && | |
| needs.determine-framework-tests-scope.outputs.framework-tests-scope != 'none' && | |
| needs.build-devextreme.result == 'success' | |
| strategy: | |
| fail-fast: false | |
| # Angular AOT bundling is slow, so it is split into parallel shards | |
| # (CSP_SHARD_*, round-robin in csp-bundle-angular.js). React/Vue stay light. | |
| matrix: | |
| include: | |
| - { FRAMEWORK: React, SHARD_INDEX: 1, SHARD_TOTAL: 2 } | |
| - { FRAMEWORK: React, SHARD_INDEX: 2, SHARD_TOTAL: 2 } | |
| - { FRAMEWORK: Vue, SHARD_INDEX: 1, SHARD_TOTAL: 2 } | |
| - { FRAMEWORK: Vue, SHARD_INDEX: 2, SHARD_TOTAL: 2 } | |
| - { FRAMEWORK: Angular, SHARD_INDEX: 1, SHARD_TOTAL: 3 } | |
| - { FRAMEWORK: Angular, SHARD_INDEX: 2, SHARD_TOTAL: 3 } | |
| - { FRAMEWORK: Angular, SHARD_INDEX: 3, SHARD_TOTAL: 3 } | |
| runs-on: devextreme-shr2 | |
| timeout-minutes: 60 | |
| env: | |
| CSP_USE_BUNDLED: '1' | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Download devextreme sources | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: devextreme-sources | |
| - name: Setup Chrome | |
| uses: ./.github/actions/setup-chrome | |
| with: | |
| chrome-version: '149.0.7827.114' | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache/restore@v5 | |
| name: Restore pnpm cache | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-cache | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Install tgz | |
| working-directory: apps/demos | |
| run: pnpm add --ignore-workspace --allow-build=core-js --allow-build=inferno devextreme-aspnet-data@5.1.0 devextreme-aspnet-data-nojquery@5.1.0 ../../devextreme-installer.tgz ../../devextreme-dist-installer.tgz ../../devextreme-react-installer.tgz ../../devextreme-vue-installer.tgz ../../devextreme-angular-installer.tgz && rm -f pnpm-workspace.yaml pnpm-lock.yaml | |
| # Bundle production-style pages only when the CSP check is configured to | |
| # read csp-bundled-demos; otherwise the checker uses SystemJS dev demos. | |
| - name: Bundle demos for CSP check | |
| if: env.CSP_USE_BUNDLED == '1' || env.CSP_USE_BUNDLED == 'true' | |
| working-directory: apps/demos | |
| env: | |
| CSP_SHARD_INDEX: ${{ matrix.SHARD_INDEX }} | |
| CSP_SHARD_TOTAL: ${{ matrix.SHARD_TOTAL }} | |
| run: node utils/server/csp-bundle.js --framework=${{ matrix.FRAMEWORK }} | |
| - name: Start CSP Server | |
| run: node apps/demos/utils/server/csp-server.js 8080 & | |
| - name: Run CSP Check | |
| working-directory: apps/demos | |
| env: | |
| CSP_FRAMEWORKS: ${{ matrix.FRAMEWORK }} | |
| CHROME_PATH: google-chrome-stable | |
| CSP_SHARD_INDEX: ${{ matrix.SHARD_INDEX }} | |
| CSP_SHARD_TOTAL: ${{ matrix.SHARD_TOTAL }} | |
| run: node utils/server/csp-check.js | |
| - name: Upload CSP report | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: csp-violations-${{ matrix.FRAMEWORK }}${{ matrix.SHARD_TOTAL != 1 && format('-shard{0}', matrix.SHARD_INDEX) || '' }} | |
| path: apps/demos/csp-reports/ | |
| if-no-files-found: ignore | |
| csp-report-summary: | |
| name: CSP Violations Summary | |
| runs-on: ubuntu-latest | |
| needs: [check-should-run, csp-check-jquery, csp-check-frameworks] | |
| if: always() && needs.check-should-run.outputs.should-run == 'true' | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Get sources | |
| uses: actions/checkout@v6 | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: '.node-version' | |
| - name: Download all CSP reports | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: csp-violations-* | |
| path: csp-reports-all | |
| merge-multiple: true | |
| continue-on-error: true | |
| - name: Summarize CSP violations | |
| run: | | |
| mkdir -p apps/demos/csp-reports | |
| echo "## CSP Violations Report" >> $GITHUB_STEP_SUMMARY | |
| echo '' >> $GITHUB_STEP_SUMMARY | |
| GRAND_TOTAL=0 | |
| for report in csp-reports-all/csp-violations-*.jsonl; do | |
| [ -f "$report" ] || continue | |
| FRAMEWORK=$(basename "$report" | sed 's/csp-violations-//;s/\.jsonl//') | |
| cp "$report" "apps/demos/csp-reports/" | |
| if [ -s "$report" ]; then | |
| COUNT=$(wc -l < "$report" | tr -d ' ') | |
| GRAND_TOTAL=$((GRAND_TOTAL + COUNT)) | |
| echo "### ⚠️ ${FRAMEWORK}: ${COUNT} violation(s)" >> $GITHUB_STEP_SUMMARY | |
| echo '' >> $GITHUB_STEP_SUMMARY | |
| echo '<details>' >> $GITHUB_STEP_SUMMARY | |
| echo '<summary>Show detailed report</summary>' >> $GITHUB_STEP_SUMMARY | |
| echo '' >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| CSP_REPORT_FILE="$report" node apps/demos/utils/server/csp-report-summary.js >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo '' >> $GITHUB_STEP_SUMMARY | |
| echo '</details>' >> $GITHUB_STEP_SUMMARY | |
| echo '' >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "### ✅ ${FRAMEWORK}: No violations" >> $GITHUB_STEP_SUMMARY | |
| echo '' >> $GITHUB_STEP_SUMMARY | |
| fi | |
| done | |
| if [ "$GRAND_TOTAL" -eq 0 ]; then | |
| echo "✅ No CSP violations detected across all frameworks." | |
| else | |
| echo "⚠️ Total: $GRAND_TOTAL CSP violation(s)" | |
| fi | |
| - name: Upload merged CSP reports | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: csp-violations-report | |
| path: apps/demos/csp-reports/ | |
| if-no-files-found: ignore |