feat(c4-beta): experimental structurizr-inspired C4 diagram type (RFC prototype) #20917
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: E2E | |
| on: | |
| push: | |
| branches: | |
| - develop | |
| - master | |
| - release/** | |
| pull_request: | |
| merge_group: | |
| concurrency: ${{ github.workflow }}-${{ github.ref }} | |
| permissions: | |
| contents: read | |
| env: | |
| # For PRs and MergeQueues, the target commit is used, and for push events to non-develop branches, github.event.previous is used if available. Otherwise, 'develop' is used. | |
| targetHash: >- | |
| ${{ | |
| github.event.pull_request.base.sha || | |
| github.event.merge_group.base_sha || | |
| ( | |
| ( | |
| (github.event_name == 'push' && github.ref == 'refs/heads/develop') || | |
| github.event.before == '0000000000000000000000000000000000000000' | |
| ) && 'develop' | |
| ) || | |
| github.event.before | |
| }} | |
| RUN_VISUAL_TEST: >- | |
| ${{ github.repository == 'mermaid-js/mermaid' && (github.event_name != 'pull_request' || !startsWith(github.head_ref, 'renovate/')) }} | |
| jobs: | |
| cache: | |
| runs-on: ubuntu-latest | |
| container: | |
| image: cypress/browsers:node-20.16.0-chrome-127.0.6533.88-1-ff-128.0.3-edge-127.0.2651.74-1 | |
| options: --user 1001 | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 | |
| with: | |
| node-version-file: '.node-version' | |
| - name: Cache snapshots | |
| id: cache-snapshot | |
| uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 | |
| with: | |
| path: ./cypress/snapshots | |
| key: ${{ runner.os }}-snapshots-${{ env.targetHash }} | |
| # If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots. | |
| - name: Switch to base branch | |
| if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }} | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| ref: ${{ env.targetHash }} | |
| - name: Install dependencies | |
| if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }} | |
| uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16 | |
| with: | |
| # just perform install | |
| runTests: false | |
| - name: Calculate bundle size | |
| if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true'}} | |
| run: | | |
| pnpm run build:viz | |
| mkdir -p cypress/snapshots/stats/base | |
| mv stats cypress/snapshots/stats/base | |
| # Detect which diagram(s) the PR touches and determine the minimal set of | |
| # Cypress specs to run. | |
| detect-scope: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| spec_pattern: ${{ steps.scope.outputs.spec_pattern }} | |
| matrix: ${{ steps.scope.outputs.matrix }} | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| # Need enough history to diff against the base commit. | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 | |
| with: | |
| node-version-file: '.node-version' | |
| - name: Detect e2e scope | |
| id: scope | |
| run: | | |
| # Kill-switch: set the repo variable E2E_SCOPE_BY_DIAGRAM to 'false' | |
| # to disable scoping. Scoping is ON by default so that fork PRs | |
| # (where repository variables are unavailable) still benefit from it. | |
| if [ "${E2E_SCOPE_BY_DIAGRAM}" = "false" ]; then | |
| echo "spec_pattern=" >> "$GITHUB_OUTPUT" | |
| echo "matrix=[1,2,3,4,5]" >> "$GITHUB_OUTPUT" | |
| echo "[detect-scope] Scoping disabled via kill-switch — full suite." | |
| exit 0 | |
| fi | |
| BASE="${{ env.targetHash }}" | |
| # For direct pushes to the main development branch, always run the | |
| # full suite (no PR diff to scope against). | |
| if [ "$BASE" = "develop" ] || [ "$BASE" = "master" ]; then | |
| echo "spec_pattern=" >> "$GITHUB_OUTPUT" | |
| echo "matrix=[1,2,3,4,5]" >> "$GITHUB_OUTPUT" | |
| echo "[detect-scope] Direct push to ${BASE} — full suite." | |
| exit 0 | |
| fi | |
| # Fetch the target branch so we can find the true merge-base. | |
| git fetch origin develop --depth=1 2>/dev/null || true | |
| MERGE_BASE=$(git merge-base HEAD origin/develop 2>/dev/null || echo "") | |
| if [ -z "$MERGE_BASE" ]; then | |
| echo "spec_pattern=" >> "$GITHUB_OUTPUT" | |
| echo "matrix=[1,2,3,4,5]" >> "$GITHUB_OUTPUT" | |
| echo "[detect-scope] Could not determine merge-base — full suite." | |
| exit 0 | |
| fi | |
| echo "[detect-scope] merge-base: ${MERGE_BASE}" | |
| # Get changed files and run the detection script. | |
| SPEC=$(git diff --name-only "$MERGE_BASE" HEAD 2>/dev/null \ | |
| | node scripts/e2e-diagram-scope.mjs \ | |
| || echo "") | |
| # Check and set required no of containers to run | |
| if [ "$SPEC" = "SKIP" ]; then | |
| echo "spec_pattern=SKIP" >> "$GITHUB_OUTPUT" | |
| echo "matrix=[1]" >> "$GITHUB_OUTPUT" | |
| echo "[detect-scope] Only docs/ignorable files changed — e2e can be skipped." | |
| elif [ -n "$SPEC" ]; then | |
| echo "spec_pattern=${SPEC}" >> "$GITHUB_OUTPUT" | |
| echo "matrix=[1]" >> "$GITHUB_OUTPUT" | |
| echo "[detect-scope] Scoped to: ${SPEC}" | |
| else | |
| echo "spec_pattern=" >> "$GITHUB_OUTPUT" | |
| echo "matrix=[1,2,3,4,5]" >> "$GITHUB_OUTPUT" | |
| echo "[detect-scope] Cannot scope — full suite." | |
| fi | |
| echo "[detect-scope] matrix output: $(grep '^matrix=' "$GITHUB_OUTPUT" | tail -1)" | |
| env: | |
| # Scoping is ON by default. To disable, set this repository variable | |
| # to 'false' (GitHub → Settings → Secrets and variables → Actions → Variables). | |
| # Using == 'false' (instead of == 'true') ensures fork PRs — where | |
| # repository variables are not exposed — still get scoped runs. | |
| E2E_SCOPE_BY_DIAGRAM: "${{ vars.E2E_SCOPE_BY_DIAGRAM == 'false' && 'false' || 'true' }}" | |
| e2e: | |
| # Skip the entire e2e job when only docs/ignorable files changed. | |
| if: needs.detect-scope.outputs.spec_pattern != 'SKIP' | |
| runs-on: ubuntu-latest | |
| container: | |
| image: cypress/browsers:node-20.16.0-chrome-127.0.6533.88-1-ff-128.0.3-edge-127.0.2651.74-1 | |
| options: --user 1001 | |
| needs: [cache, detect-scope] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| containers: ${{ fromJSON(needs.detect-scope.outputs.matrix) }} | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 | |
| # uses version from "packageManager" field in package.json | |
| - name: Setup Node.js | |
| uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 | |
| with: | |
| node-version-file: '.node-version' | |
| # These cached snapshots are downloaded, providing the reference snapshots. | |
| - name: Cache snapshots | |
| id: cache-snapshot | |
| uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 | |
| with: | |
| path: ./cypress/snapshots | |
| key: ${{ runner.os }}-snapshots-${{ env.targetHash }} | |
| - name: Install dependencies | |
| uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16 | |
| with: | |
| runTests: false | |
| - name: Output size diff | |
| if: ${{ matrix.containers == 1 }} | |
| run: | | |
| pnpm run build:viz | |
| mv stats cypress/snapshots/stats/head | |
| echo '## Bundle size difference' >> "$GITHUB_STEP_SUMMARY" | |
| echo '' >> "$GITHUB_STEP_SUMMARY" | |
| npx tsx scripts/size.ts >> "$GITHUB_STEP_SUMMARY" | |
| # Install NPM dependencies, cache them correctly | |
| # and run all Cypress tests (or a scoped subset when detect-scope fires). | |
| - name: Cypress run | |
| uses: cypress-io/github-action@108b8684ae52e735ff7891524cbffbcd4be5b19f # v6.7.16 | |
| id: cypress | |
| with: | |
| install: false | |
| start: pnpm run dev:coverage | |
| wait-on: 'http://localhost:9000' | |
| browser: chrome | |
| # When detect-scope produced a pattern, run only those specs. | |
| spec: ${{ needs.detect-scope.outputs.spec_pattern }} | |
| # Disable recording if we don't have an API key | |
| # e.g. if this action was run from a fork | |
| record: ${{ env.RUN_VISUAL_TEST == 'true' && secrets.CYPRESS_RECORD_KEY != '' }} | |
| env: | |
| # For scoped runs (only a subset of specs executed), mark the Argos | |
| # build as a "subset build". | |
| ARGOS_SUBSET: "${{ needs.detect-scope.outputs.spec_pattern != '' }}" | |
| ARGOS_PARALLEL: ${{ env.RUN_VISUAL_TEST == 'true' }} | |
| ARGOS_PARALLEL_TOTAL: ${{ env.RUN_VISUAL_TEST == 'true' && strategy.job-total || 1 }} | |
| ARGOS_PARALLEL_INDEX: ${{ env.RUN_VISUAL_TEST == 'true' && matrix.containers || 1 }} | |
| CYPRESS_COMMIT: ${{ github.sha }} | |
| CYPRESS_RECORD_KEY: ${{ env.RUN_VISUAL_TEST == 'true' && secrets.CYPRESS_RECORD_KEY || ''}} | |
| SPLIT: ${{ strategy.job-total }} | |
| SPLIT_INDEX: ${{ strategy.job-index }} | |
| SPLIT_FILE: 'cypress/timings.json' | |
| VITEST_COVERAGE: true | |
| - name: Upload Coverage to Codecov | |
| uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1 | |
| # Run step only pushes to develop and pull_requests | |
| if: ${{ steps.cypress.conclusion == 'success' && (github.event_name == 'pull_request' || github.ref == 'refs/heads/develop')}} | |
| with: | |
| files: coverage/cypress/lcov.info | |
| flags: e2e | |
| name: mermaid-codecov | |
| fail_ci_if_error: false | |
| verbose: true | |
| token: 6845cc80-77ee-4e17-85a1-026cd95e0766 | |
| e2e-required: | |
| if: always() | |
| needs: [detect-scope, e2e] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Verify e2e outcome | |
| env: | |
| E2E_RESULT: ${{ needs.e2e.result }} | |
| SCOPE_RESULT: ${{ needs.detect-scope.result }} | |
| SPEC_PATTERN: ${{ needs.detect-scope.outputs.spec_pattern }} | |
| run: | | |
| echo "detect-scope result: ${SCOPE_RESULT}" | |
| echo "detect-scope spec_pattern: ${SPEC_PATTERN}" | |
| echo "e2e result: ${E2E_RESULT}" | |
| case "${E2E_RESULT}" in | |
| success|skipped) | |
| echo "OK — required check satisfied." | |
| ;; | |
| *) | |
| echo "FAIL — e2e matrix did not complete successfully." | |
| exit 1 | |
| ;; | |
| esac |