name: E2E Tests on: push: branches: - main - all-e2e # this bypasses `fixme()` using `orRunWhenFullSuiteEnabled()` pull_request: schedule: - cron: 0 * * * * # hourly concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true permissions: contents: write pull-requests: write actions: read jobs: conditions: runs-on: ubuntu-latest outputs: significant: ${{ steps.path-changes.outputs.significant }} should-run: ${{ steps.should-run.outputs.should-run }} steps: - uses: actions/checkout@v4 - name: Fetch the base branch if: ${{ github.event_name == 'pull_request' }} run: git fetch origin ${{ github.base_ref }} --depth=1 - name: Check for path changes id: path-changes shell: bash run: | set -euo pipefail # Manual runs or push should run all tests. if [[ ${{ github.event_name }} != 'pull_request' ]]; then echo "significant=true" >> $GITHUB_OUTPUT exit 0 fi changed_files=$(git diff --name-only origin/${{ github.base_ref }}) echo "$changed_files" if grep -Evq '^README.md|^public/kcl-samples/|^rust/kcl-lib/tests/kcl_samples/' <<< "$changed_files" ; then echo "significant=true" >> $GITHUB_OUTPUT else echo "significant=false" >> $GITHUB_OUTPUT fi - name: Should run id: should-run shell: bash run: | set -euo pipefail # We should run when this is a scheduled run or if there are # significant changes in the diff. if [[ ${{ github.event_name }} == 'schedule' || ${{ steps.path-changes.outputs.significant }} == 'true' ]]; then echo "should-run=true" >> $GITHUB_OUTPUT else echo "should-run=false" >> $GITHUB_OUTPUT fi - name: Display conditions shell: bash run: | # For debugging purposes set -euo pipefail echo "GITHUB_REF: $GITHUB_REF" echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF" echo "GITHUB_BASE_REF: $GITHUB_BASE_REF" echo "significant: ${{ steps.path-changes.outputs.significant }}" echo "should-run: ${{ steps.should-run.outputs.should-run }}" prepare-wasm: # separate job on Ubuntu to build or fetch the wasm blob once on the fastest runner runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64 needs: conditions steps: - uses: actions/checkout@v4 if: needs.conditions.outputs.should-run == 'true' - id: filter if: needs.conditions.outputs.should-run == 'true' name: Check for Rust changes uses: dorny/paths-filter@v3 with: filters: | rust: - 'rust/**' - uses: actions/setup-node@v4 if: needs.conditions.outputs.should-run == 'true' with: node-version-file: '.nvmrc' cache: 'npm' - name: Install dependencies if: needs.conditions.outputs.should-run == 'true' run: npm install - name: Download Wasm Cache id: download-wasm if: ${{ needs.conditions.outputs.should-run == 'true' && github.event_name != 'schedule' && steps.filter.outputs.rust == 'false' }} uses: dawidd6/action-download-artifact@v7 continue-on-error: true with: github_token: ${{secrets.GITHUB_TOKEN}} name: wasm-bundle workflow: build-and-store-wasm.yml branch: main path: rust/kcl-wasm-lib/pkg - name: Build WASM condition id: wasm if: needs.conditions.outputs.should-run == 'true' run: | set -euox pipefail # Build wasm if this is a scheduled run, there are Rust changes, or # downloading from the wasm cache failed. if [[ ${{github.event_name}} == 'schedule' || ${{steps.filter.outputs.rust}} == 'true' || ${{steps.download-wasm.outcome}} == 'failure' ]]; then echo "should-build-wasm=true" >> $GITHUB_OUTPUT else echo "should-build-wasm=false" >> $GITHUB_OUTPUT fi - name: Use correct Rust toolchain if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }} shell: bash run: | [ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./ - name: Install rust if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }} uses: actions-rust-lang/setup-rust-toolchain@v1 with: cache: false # Configured below. - uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }} with: tool: wasm-pack - name: Rust Cache if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }} uses: Swatinem/rust-cache@v2 with: workspaces: './rust' - name: Build Wasm if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }} shell: bash run: npm run build:wasm - uses: actions/upload-artifact@v4 if: needs.conditions.outputs.should-run == 'true' with: name: prepared-wasm path: | rust/kcl-wasm-lib/pkg/kcl_wasm_lib* snapshots: name: playwright:snapshots:ubuntu runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64 needs: [conditions, prepare-wasm] steps: - uses: actions/create-github-app-token@v1 if: needs.conditions.outputs.should-run == 'true' id: app-token with: app-id: ${{ secrets.MODELING_APP_GH_APP_ID }} private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }} owner: ${{ github.repository_owner }} - uses: actions/checkout@v4 if: needs.conditions.outputs.should-run == 'true' with: token: ${{ steps.app-token.outputs.token }} - uses: actions/download-artifact@v4 if: needs.conditions.outputs.should-run == 'true' name: prepared-wasm - name: Copy prepared wasm if: needs.conditions.outputs.should-run == 'true' run: | ls -R prepared-wasm cp prepared-wasm/kcl_wasm_lib_bg.wasm public mkdir rust/kcl-wasm-lib/pkg cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg - uses: actions/setup-node@v4 if: needs.conditions.outputs.should-run == 'true' with: node-version-file: '.nvmrc' cache: 'npm' - name: Install dependencies id: deps-install if: needs.conditions.outputs.should-run == 'true' run: npm install - name: Cache Playwright Browsers if: needs.conditions.outputs.should-run == 'true' uses: actions/cache@v4 with: path: | ~/.cache/ms-playwright/ key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }} - name: Install Playwright Browsers if: needs.conditions.outputs.should-run == 'true' run: npm run playwright install --with-deps - name: build web if: needs.conditions.outputs.should-run == 'true' run: npm run tronb:vite:dev - name: Run ubuntu/chrome snapshots if: needs.conditions.outputs.should-run == 'true' uses: nick-fields/retry@v3.0.2 with: shell: bash command: npm run test:snapshots timeout_minutes: 5 max_attempts: 5 env: token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }} TAB_API_URL: ${{ secrets.TAB_API_URL }} TAB_API_KEY: ${{ secrets.TAB_API_KEY }} CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }} CI_PR_NUMBER: ${{ github.event.pull_request.number }} TARGET: web - uses: actions/upload-artifact@v4 if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }} with: name: playwright-report-ubuntu-snapshot-${{ github.sha }} path: playwright-report/ include-hidden-files: true retention-days: 30 overwrite: true - name: Check for changes if: ${{ needs.conditions.outputs.should-run == 'true' && github.ref != 'refs/heads/main' }} shell: bash id: git-check run: | git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots if git status | grep -q "Changes to be committed" then echo "modified=true" >> $GITHUB_OUTPUT else echo "modified=false" >> $GITHUB_OUTPUT fi - name: Commit changes, if any # TODO: find a more reliable way to detect visual changes if: ${{ false && needs.conditions.outputs.should-run == 'true' && steps.git-check.outputs.modified == 'true' }} shell: bash run: | git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots git config --local user.email "github-actions[bot]@users.noreply.github.com" git config --local user.name "github-actions[bot]" git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git git fetch origin echo ${{ github.head_ref }} git checkout ${{ github.head_ref }} git commit -m "A snapshot a day keeps the bugs away! 📷🐛" || true git push git push origin ${{ github.head_ref }} electron: needs: [conditions, prepare-wasm] timeout-minutes: 60 env: OS_NAME: ${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }} name: playwright:electron:${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}:${{ matrix.shardIndex }}:${{ matrix.shardTotal }} strategy: fail-fast: false matrix: # TODO: enable namespace-profile-windows-latest once available os: - "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64" # TODO: renable this when macoOS runner seem more stable # - namespace-profile-macos-6-cores - windows-latest-8-cores shardIndex: [1, 2, 3, 4] shardTotal: [4] # Disable macos and windows tests on hourly e2e tests since we only care # about server side changes. # Technique from https://github.com/joaomcteixeira/python-project-skeleton/pull/31/files isScheduled: - ${{ github.event_name == 'schedule' }} exclude: - os: namespace-profile-macos-6-cores isScheduled: true - os: windows-latest-8-cores isScheduled: true # TODO: add ref here for main and latest release tag runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 if: needs.conditions.outputs.should-run == 'true' - uses: actions/download-artifact@v4 if: needs.conditions.outputs.should-run == 'true' name: prepared-wasm - name: Copy prepared wasm if: needs.conditions.outputs.should-run == 'true' run: | ls -R prepared-wasm cp prepared-wasm/kcl_wasm_lib_bg.wasm public mkdir rust/kcl-wasm-lib/pkg cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg - uses: actions/setup-node@v4 if: needs.conditions.outputs.should-run == 'true' with: node-version-file: '.nvmrc' cache: 'npm' - name: Install dependencies id: deps-install if: needs.conditions.outputs.should-run == 'true' run: npm install - name: Cache Playwright Browsers if: needs.conditions.outputs.should-run == 'true' uses: actions/cache@v4 with: path: | ~/.cache/ms-playwright/ key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }} - name: Install Playwright Browsers if: needs.conditions.outputs.should-run == 'true' run: npm run playwright install --with-deps - name: Build web if: needs.conditions.outputs.should-run == 'true' run: npm run tronb:vite:dev - name: Start Vector if: ${{ needs.conditions.outputs.should-run == 'true' && !contains(matrix.os, 'windows') }} run: .github/ci-cd-scripts/start-vector-${{ env.OS_NAME }}.sh env: GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }} OS_NAME: ${{ env.OS_NAME }} - uses: actions/download-artifact@v4 if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }} continue-on-error: true with: name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }} path: test-results/ - name: Run playwright/electron flow (with retries) id: retry if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && steps.deps-install.outcome == 'success' }} uses: nick-fields/retry@v3.0.2 with: shell: bash command: .github/ci-cd-scripts/playwright-electron.sh ${{matrix.shardIndex}} ${{matrix.shardTotal}} ${{ env.OS_NAME }} timeout_minutes: 30 max_attempts: 9 env: FAIL_ON_CONSOLE_ERRORS: true token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} TAB_API_URL: ${{ secrets.TAB_API_URL }} TAB_API_KEY: ${{ secrets.TAB_API_KEY }} CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }} CI_PR_NUMBER: ${{ github.event.pull_request.number }} TARGET: desktop - uses: actions/upload-artifact@v4 if: ${{ needs.conditions.outputs.should-run == 'true' && always() }} with: name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }} path: test-results/ include-hidden-files: true retention-days: 30 overwrite: true - uses: actions/upload-artifact@v4 if: ${{ needs.conditions.outputs.should-run == 'true' && always() }} with: name: playwright-report-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }} path: playwright-report/ include-hidden-files: true retention-days: 30 overwrite: true