Skip to content

fix(deps): update dependency prosemirror-history to v1.5.1 #5271

fix(deps): update dependency prosemirror-history to v1.5.1

fix(deps): update dependency prosemirror-history to v1.5.1 #5271

Workflow file for this run

name: CI
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# ===========================================
# Lint - Check code formatting
# ===========================================
lint:
name: Lint
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Check code formatting
run: bun run lint
# ===========================================
# Unit Tests - Shared Packages (Vitest)
# ===========================================
test-packages:
name: Unit Tests (Shared Packages)
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Run shared package tests with coverage
run: cd packages/inkweld-prosemirror && bun run test:coverage
- name: Run inkweld-presence tests with coverage
run: cd packages/inkweld-presence && bun run test:coverage
- name: Upload packages coverage
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: packages-coverage
path: packages/inkweld-prosemirror/coverage/lcov.info
retention-days: 1
- name: Upload presence package coverage
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: presence-coverage
path: packages/inkweld-presence/coverage/lcov.info
retention-days: 1
# ===========================================
# Unit Tests - Frontend (Vitest) - Sharded across parallel runners
# ===========================================
# `ng test` has no --shard flag, so frontend/scripts/test-shard.mjs deals
# the spec files round-robin across the matrix and passes each shard's list
# via --include. Unsharded this was the longest job in the workflow (~18m);
# 2 shards (~9m each) bring it in line with the e2e jobs; 3 ran ~5-6m,
# shorter than the e2e shards, so the extra runner bought no wall-clock. Each shard emits an lcov.info
# covering the whole tree, so per-shard thresholds are disabled (the `shard`
# configuration in angular.json) and enforced on the merged report in the
# frontend-coverage job below.
test-frontend:
name: Unit Tests (Frontend) - Shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2]
shardTotal: [2]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: "24"
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Show Node.js version
run: node --version && bun --version
- name: Run frontend tests (shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
run: cd frontend && NODE_OPTIONS="--max-old-space-size=8192" npm run test:shard -- ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload frontend coverage shard
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: frontend-coverage-shard-${{ matrix.shardIndex }}
path: frontend/coverage/inkweld-frontend/lcov.info
retention-days: 1
# ===========================================
# Frontend Coverage - merge shards + enforce thresholds
# ===========================================
frontend-coverage:
name: Unit Tests (Frontend) - Coverage
runs-on: ubuntu-latest
permissions:
contents: read
needs: [test-frontend]
# Merge whatever shards produced coverage even if a shard's tests failed,
# so SonarCloud still gets a report; skip only on cancellation.
if: ${{ !cancelled() }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: "24"
- name: Download coverage shards
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: frontend-coverage-shard-*
path: frontend/coverage/shards
- name: Merge coverage and check thresholds
run: cd frontend && node scripts/merge-lcov.mjs --out coverage/inkweld-frontend/lcov.info coverage/shards/*/lcov.info
- name: Upload frontend coverage
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: frontend-coverage
path: frontend/coverage/inkweld-frontend/lcov.info
retention-days: 1
# ===========================================
# Unit Tests - Backend (Bun)
# ===========================================
test-backend:
name: Unit Tests (Backend)
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Run backend tests
run: cd backend && DB_DATABASE=":memory:" USER_APPROVAL_REQUIRED="false" bun run test:coverage
- name: Upload backend coverage
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: backend-coverage
path: backend/coverage/lcov.info
retention-days: 1
# ===========================================
# SonarCloud Analysis
# ===========================================
sonarcloud:
name: SonarCloud Code Analysis
runs-on: ubuntu-latest
permissions:
contents: read
needs: [frontend-coverage, test-backend, test-packages]
# Run even when the test jobs fail (partial coverage is still worth
# scanning), but NOT when the run is cancelled - `always()` would also
# match cancellations, and a superseded run's coverage artifacts never
# get uploaded, so the scan would report 0% coverage on new code and post
# a false quality gate failure to the PR.
# Also skip SonarCloud analysis for Renovate dependency PRs (machine-generated).
if: ${{ !cancelled() && !startsWith(github.head_ref, 'renovate/') }}
# Configure the 15-minute wait timer on the sonarcloud-analysis environment.
environment:
name: sonarcloud-analysis
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
- name: Download frontend coverage
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: frontend-coverage
path: frontend/coverage/inkweld-frontend
continue-on-error: true
- name: Download backend coverage
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: backend-coverage
path: backend/coverage
continue-on-error: true
- name: Download packages coverage
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: packages-coverage
path: packages/inkweld-prosemirror/coverage
continue-on-error: true
- name: Download presence package coverage
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: presence-coverage
path: packages/inkweld-presence/coverage
continue-on-error: true
- name: SonarCloud Scan
uses: SonarSource/sonarqube-scan-action@ba9859eae8dd6bd29e412f25ddbbef3d032000f4 # v8
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ===========================================
# E2E Tests - Sharded across parallel runners
# ===========================================
# The heavier e2e jobs are split with Playwright's --shard=N/T flag using a
# GitHub Actions matrix so test files are evenly distributed across runners.
# Wall-clock time drops roughly 1/N at the cost of N runners' worth of
# compute (each shard re-runs setup).
#
# Shard counts were tuned against historical job durations: Docker ~15m,
# Wrangler ~13m at 2 shards (now 3), Online ~11m. Local (~8m) and
# Screenshots (~9m) are left unsharded - Local because the savings don't
# justify the extra runner, and
# Screenshots because it is driven by the docs build rather than
# `playwright test` directly and must run sequentially for visual
# consistency.
# Local E2E Tests (24 spec files - unsharded; ~8m on the runner)
e2e-local:
name: E2E Tests (Local)
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: "24"
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Get installed Playwright version
id: playwright-version
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT
working-directory: frontend
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }}
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: cd frontend && ./node_modules/.bin/playwright install --with-deps chromium
- name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: cd frontend && ./node_modules/.bin/playwright install-deps chromium
- name: Build frontend
run: cd frontend && npm run build
- name: Run local e2e tests
run: cd frontend && npm run e2e:local:ci
env:
E2E_MODE: prod
- name: Upload Playwright reports
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: failure()
with:
name: playwright-report-local
path: frontend/playwright-report/
retention-days: 7
- name: Upload Playwright test results (traces, screenshots, videos)
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
# `always()` rather than `failure()`: a test that failed once and passed
# on retry leaves the job green, but its first-attempt trace/screenshot
# (trace: 'retain-on-first-failure') is what we need to debug the flake.
# On a clean run the directory is empty and nothing is uploaded.
if: always()
with:
name: playwright-test-results-local
path: frontend/test-results/
retention-days: 7
if-no-files-found: ignore
# Online E2E Tests (22 spec files - 2 shards)
e2e-online:
name: E2E Tests (Online) - Shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2]
shardTotal: [2]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: "24"
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Get installed Playwright version
id: playwright-version
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT
working-directory: frontend
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }}
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: cd frontend && ./node_modules/.bin/playwright install --with-deps chromium
- name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: cd frontend && ./node_modules/.bin/playwright install-deps chromium
- name: Build frontend
run: cd frontend && npm run build
- name: Run online e2e tests (shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
run: cd frontend && npm run e2e:online:ci -- --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
env:
E2E_MODE: prod
- name: Upload Playwright reports
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: failure()
with:
name: playwright-report-online-shard-${{ matrix.shardIndex }}
path: frontend/playwright-report/
retention-days: 7
- name: Upload Playwright test results (traces, screenshots, videos)
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
# `always()` rather than `failure()`: a test that failed once and passed
# on retry leaves the job green, but its first-attempt trace/screenshot
# (trace: 'retain-on-first-failure') is what we need to debug the flake.
# On a clean run the directory is empty and nothing is uploaded.
if: always()
with:
name: playwright-test-results-online-shard-${{ matrix.shardIndex }}
path: frontend/test-results/
retention-days: 7
if-no-files-found: ignore
# Wrangler E2E Tests (22 spec files - 3 shards; the slowest e2e job at 2)
e2e-wrangler:
name: E2E Tests (Wrangler) - Shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3]
shardTotal: [3]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: "24"
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Get installed Playwright version
id: playwright-version
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT
working-directory: frontend
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }}
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: cd frontend && ./node_modules/.bin/playwright install --with-deps chromium
- name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: cd frontend && ./node_modules/.bin/playwright install-deps chromium
- name: Copy wrangler.toml for CI
run: cp backend/wrangler.toml.example backend/wrangler.toml
- name: Initialize local D1 database
run: cd backend && bun run init:d1-local
- name: Build frontend
run: cd frontend && npm run build
- name: Run wrangler e2e tests (shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
# Retries once in CI like the other e2e jobs (see the `retries` note in
# playwright.wrangler.config.ts). A backend crash still fails the shard:
# every test after it fails on the retry too. A one-off flake passes on
# retry and leaves its first-attempt trace in the test-results artifact.
run: cd frontend && npm run e2e:wrangler:ci -- --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
env:
E2E_MODE: prod
# Where the wrangler backend's stdout/stderr is tee'd (see
# playwright.wrangler.config.ts). Uploaded as an artifact on failure
# so a native workerd crash stack is preserved for investigation.
# Note: the webServer runs with cwd ../backend, so this must be
# absolute to land in a stable, project-owned location.
WRANGLER_LOG_FILE: ${{ github.workspace }}/wrangler-backend.log
# wrangler's own diagnostic log records what the console's empty
# "[ERROR]" line hides. When a transient ProxyWorker disconnect
# ("Network connection lost.") kills `wrangler dev` mid-run — see
# cloudflare/workers-sdk#15317 — the real cause only shows up at
# debug level in this file. Redirected into the workspace so it can
# be uploaded as an artifact instead of staying in the runner home.
WRANGLER_LOG: debug
WRANGLER_LOG_PATH: ${{ github.workspace }}/wrangler-debug-logs
- name: Upload Playwright reports
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: failure()
with:
name: playwright-report-wrangler-shard-${{ matrix.shardIndex }}
path: frontend/playwright-report/
retention-days: 7
- name: Upload Playwright test results (traces, screenshots, videos)
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
# `always()` rather than `failure()`: a test that failed once and passed
# on retry leaves the job green, but its first-attempt trace/screenshot
# (trace: 'retain-on-first-failure') is what we need to debug the flake.
# On a clean run the directory is empty and nothing is uploaded.
if: always()
with:
name: playwright-test-results-wrangler-shard-${{ matrix.shardIndex }}
path: frontend/test-results/
retention-days: 7
if-no-files-found: ignore
- name: Upload wrangler backend log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: failure()
with:
name: wrangler-backend-log-shard-${{ matrix.shardIndex }}
path: wrangler-backend.log
retention-days: 7
- name: Upload wrangler diagnostic log
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: failure()
with:
name: wrangler-diag-log-shard-${{ matrix.shardIndex }}
path: wrangler-debug-logs/
retention-days: 7
if-no-files-found: warn
# Docker E2E Tests (22 spec files - 2 shards)
# Note: each shard rebuilds the Docker image in globalSetup, so the per-job
# cost is high. We deliberately keep this at 2 shards to avoid blowing up
# compute usage.
e2e-docker:
name: E2E Tests (Docker) - Shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2]
shardTotal: [2]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: "24"
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Get installed Playwright version
id: playwright-version
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT
working-directory: frontend
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }}
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: cd frontend && ./node_modules/.bin/playwright install --with-deps chromium
- name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: cd frontend && ./node_modules/.bin/playwright install-deps chromium
- name: Run Docker e2e tests (shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
run: cd frontend && npm run e2e:docker:ci -- --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload Playwright reports
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: failure()
with:
name: playwright-report-docker-shard-${{ matrix.shardIndex }}
path: frontend/playwright-report/
retention-days: 7
- name: Upload Playwright test results (traces, screenshots, videos)
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
# `always()` rather than `failure()`: a test that failed once and passed
# on retry leaves the job green, but its first-attempt trace/screenshot
# (trace: 'retain-on-first-failure') is what we need to debug the flake.
# On a clean run the directory is empty and nothing is uploaded.
if: always()
with:
name: playwright-test-results-docker-shard-${{ matrix.shardIndex }}
path: frontend/test-results/
retention-days: 7
if-no-files-found: ignore
# ===========================================
# E2E Tests - Screenshots (via docs build)
# ===========================================
# Not sharded: this job builds the docs site, which runs the screenshot
# tests as a side effect. The tests must run sequentially to produce
# consistent visual output.
e2e-screenshots:
name: E2E Tests (Screenshots)
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: "24"
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json
- name: Cache Bun dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Get installed Playwright version
id: playwright-version
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT
working-directory: frontend
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }}
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: cd frontend && ./node_modules/.bin/playwright install --with-deps chromium
- name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: cd frontend && ./node_modules/.bin/playwright install-deps chromium
- name: Build docs (runs screenshot e2e tests)
run: cd docs/site && bun run build
- name: Upload Playwright reports
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: failure()
with:
name: playwright-report-screenshots
path: frontend/playwright-report/
retention-days: 7
# ===========================================
# Build and Push Dev Docker Image (Multi-arch)
# ===========================================
# Pre-build frontend on AMD64 (output is platform-agnostic)
docker-frontend-build:
name: Build Frontend for Docker
runs-on: ubuntu-latest
permissions:
contents: read
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs:
[
lint,
test-frontend,
frontend-coverage,
test-backend,
test-packages,
e2e-local,
e2e-online,
e2e-wrangler,
e2e-docker,
e2e-screenshots,
]
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version-file: package.json
- name: Install dependencies
# Workspace-root install so the @inkweld/prosemirror peer deps
# (prosemirror-model, yjs) are available for the shared package
# consumed by the frontend build.
run: bun install --frozen-lockfile
- name: Build frontend
run: cd frontend && bun run build
- name: Compress WASM files
run: cd frontend && node scripts/compress-wasm.js
- name: Upload frontend dist
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: frontend-dist
path: frontend/dist
retention-days: 1
# Build AMD64 image
docker-dev-amd64:
name: Build Docker (amd64)
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
needs: [docker-frontend-build]
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Download frontend dist
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: frontend-dist
path: frontend/dist
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image (amd64)
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7
with:
context: .
file: Dockerfile
push: true
platforms: linux/amd64
tags: ghcr.io/${{ github.repository_owner }}/inkweld:dev-amd64
build-args: FRONTEND_PREBUILT=true
cache-from: type=gha,scope=amd64
cache-to: type=gha,mode=max,scope=amd64
provenance: false
# Build ARM64 image on native ARM runner
docker-dev-arm64:
name: Build Docker (arm64)
runs-on: ubuntu-26.04-arm
permissions:
contents: read
packages: write
needs: [docker-frontend-build]
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Download frontend dist
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: frontend-dist
path: frontend/dist
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image (arm64)
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7
with:
context: .
file: Dockerfile
push: true
platforms: linux/arm64
tags: ghcr.io/${{ github.repository_owner }}/inkweld:dev-arm64
build-args: FRONTEND_PREBUILT=true
cache-from: type=gha,scope=arm64
cache-to: type=gha,mode=max,scope=arm64
provenance: false
# Create multi-arch manifest
docker-dev-manifest:
name: Create Docker Manifest
runs-on: ubuntu-latest
permissions:
packages: write
needs: [docker-dev-amd64, docker-dev-arm64]
steps:
- name: Log in to GitHub Container Registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push multi-arch manifest
run: |
docker manifest create ghcr.io/${{ github.repository_owner }}/inkweld:dev \
ghcr.io/${{ github.repository_owner }}/inkweld:dev-amd64 \
ghcr.io/${{ github.repository_owner }}/inkweld:dev-arm64
docker manifest push ghcr.io/${{ github.repository_owner }}/inkweld:dev