trilium/.github/workflows/dev.yml
Elian Doran e0aa90ee8e
chore: remove the express-partial-content package
Nothing imports it any more: its only two consumers were the open-partial
routes, which now run the transport-neutral range handler in core so that
standalone gets them too.

Drops the package along with its workspace dependency, three tsconfig
project references, its CI test and Codecov steps, the coverage flag, the
Nix components entry and the two monorepo structure listings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 19:17:58 +03:00

392 lines
14 KiB
YAML

name: Dev
on:
push:
branches:
- main
- standalone
- "release/*"
pull_request:
branches:
- main
- standalone
- "release/*"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
GHCR_REGISTRY: ghcr.io
DOCKERHUB_REGISTRY: docker.io
IMAGE_NAME: ${{ github.repository}}
TEST_TAG: ${{ github.repository}}:test
permissions:
pull-requests: write # for PR comments
jobs:
test_dev:
name: Test development
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- name: Set up node & dependencies
uses: actions/setup-node@v7
with:
node-version: 24
cache: "pnpm"
- run: pnpm install --frozen-lockfile
- name: Typecheck
run: pnpm typecheck
- name: Run the client-side tests
id: test-client
run: pnpm run --filter=client test --coverage
- name: Upload client test report
uses: actions/upload-artifact@v7
if: always()
with:
name: client-test-report
path: apps/client/test-output/vitest/html/
retention-days: 30
- name: Run the server-side tests
id: test-server
run: pnpm run --filter=server test --coverage
- name: Upload server test report
uses: actions/upload-artifact@v7
if: always()
with:
name: server-test-report
path: apps/server/test-output/vitest/html/
retention-days: 30
- name: Upload client coverage to Codecov
uses: codecov/codecov-action@v7
if: ${{ !cancelled() && steps.test-client.outcome == 'success' }}
with:
files: apps/client/test-output/vitest/coverage/lcov.info
flags: client
disable_search: true
fail_ci_if_error: false
- name: Upload client test results to Codecov
uses: codecov/test-results-action@v1
if: ${{ !cancelled() && steps.test-client.outcome != 'skipped' }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: apps/client/test-output/vitest/junit.xml
flags: client
disable_search: true
fail_ci_if_error: false
- name: Upload server coverage to Codecov
uses: codecov/codecov-action@v7
if: ${{ !cancelled() && steps.test-server.outcome == 'success' }}
with:
files: apps/server/test-output/vitest/coverage/lcov.info
flags: server
disable_search: true
fail_ci_if_error: false
- name: Upload server test results to Codecov
uses: codecov/test-results-action@v1
if: ${{ !cancelled() && steps.test-server.outcome != 'skipped' }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: apps/server/test-output/vitest/junit.xml
flags: server
disable_search: true
fail_ci_if_error: false
- name: Run the standalone tests
id: test-standalone
# Runs the same trilium-core spec set as the server suite, but in
# happy-dom + sql.js WASM via BrowserSqlProvider (see
# apps/standalone/src/test_setup.ts). Catches differences
# between the Node-side and browser-side runtimes.
run: pnpm run --filter=standalone test --coverage
- name: Upload standalone coverage to Codecov
uses: codecov/codecov-action@v7
if: ${{ !cancelled() && steps.test-standalone.outcome == 'success' }}
with:
files: apps/standalone/test-output/vitest/coverage/lcov.info
flags: standalone
disable_search: true
fail_ci_if_error: false
- name: Upload standalone test results to Codecov
uses: codecov/test-results-action@v1
if: ${{ !cancelled() && steps.test-standalone.outcome != 'skipped' }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: apps/standalone/test-output/vitest/junit.xml
flags: standalone
disable_search: true
fail_ci_if_error: false
- name: Run the CKEditor 5 aggregate tests
id: test-ckeditor5
# The suite drives a real headless Chrome through webdriverio. When the browser session
# fails to start, vitest waits on it rather than erroring, so cap the step instead of
# letting it sit until the job's default timeout.
timeout-minutes: 15
run: |
export CHROMEDRIVER_PATH=$(which chromedriver || find /usr/local/share -name chromedriver -type f 2>/dev/null | head -1)
echo "Using chromedriver at: $CHROMEDRIVER_PATH"
# A chromedriver whose major version does not match the installed Chrome fails the
# session handshake, which surfaces as a hang or a mid-run disconnect rather than a
# clear error — so record both up front.
"$CHROMEDRIVER_PATH" --version || echo "could not read the chromedriver version"
(google-chrome --version || chromium --version || chromium-browser --version) 2>/dev/null \
|| echo "could not read the Chrome version"
# Browser mode keeps one page for the whole run, and v8 coverage data accumulates in it:
# measured locally, the heap reaches ~850MB by the 100th spec file with --coverage against
# ~240MB without it. That is where a CI runner's renderer gives out — the session either
# drops mid-run or stops responding. Run the suite in two shards (~60 files each, peaking
# around 500MB) and merge the blob reports afterwards, so the 100% gate is still evaluated
# over the whole suite rather than per shard.
SHARD_ARGS="--reporter=blob --coverage \
--coverage.thresholds.lines=0 --coverage.thresholds.functions=0 \
--coverage.thresholds.branches=0 --coverage.thresholds.statements=0"
pnpm run --filter=ckeditor5 test --shard=1/2 $SHARD_ARGS
pnpm run --filter=ckeditor5 test --shard=2/2 $SHARD_ARGS
pnpm run --filter=ckeditor5 test --mergeReports --coverage
- name: Upload ckeditor5 coverage to Codecov
uses: codecov/codecov-action@v7
if: ${{ !cancelled() && steps.test-ckeditor5.outcome == 'success' }}
with:
files: packages/ckeditor5/test-output/vitest/coverage/lcov.info
flags: ckeditor5
disable_search: true
fail_ci_if_error: false
- name: Upload ckeditor5 test results to Codecov
uses: codecov/test-results-action@v1
if: ${{ !cancelled() && steps.test-ckeditor5.outcome != 'skipped' }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: packages/ckeditor5/test-output/vitest/junit.xml
flags: ckeditor5
disable_search: true
fail_ci_if_error: false
- name: Run the desktop tests
id: test-desktop
run: pnpm run --filter=desktop test --coverage
- name: Upload desktop coverage to Codecov
uses: codecov/codecov-action@v7
if: ${{ !cancelled() && steps.test-desktop.outcome == 'success' }}
with:
files: apps/desktop/test-output/vitest/coverage/lcov.info
flags: desktop
disable_search: true
fail_ci_if_error: false
- name: Upload desktop test results to Codecov
uses: codecov/test-results-action@v1
if: ${{ !cancelled() && steps.test-desktop.outcome != 'skipped' }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: apps/desktop/test-output/vitest/junit.xml
flags: desktop
disable_search: true
fail_ci_if_error: false
- name: Run the commons tests
id: test-commons
run: pnpm run --filter=commons test --coverage
- name: Upload commons coverage to Codecov
uses: codecov/codecov-action@v7
if: ${{ !cancelled() && steps.test-commons.outcome == 'success' }}
with:
files: packages/commons/test-output/vitest/coverage/lcov.info
flags: commons
disable_search: true
fail_ci_if_error: false
- name: Upload commons test results to Codecov
uses: codecov/test-results-action@v1
if: ${{ !cancelled() && steps.test-commons.outcome != 'skipped' }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: packages/commons/test-output/vitest/junit.xml
flags: commons
disable_search: true
fail_ci_if_error: false
- name: Run the codemirror tests
id: test-codemirror
run: pnpm run --filter=codemirror test --coverage
- name: Upload codemirror coverage to Codecov
uses: codecov/codecov-action@v7
if: ${{ !cancelled() && steps.test-codemirror.outcome == 'success' }}
with:
files: packages/codemirror/test-output/vitest/coverage/lcov.info
flags: codemirror
disable_search: true
fail_ci_if_error: false
- name: Upload codemirror test results to Codecov
uses: codecov/test-results-action@v1
if: ${{ !cancelled() && steps.test-codemirror.outcome != 'skipped' }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: packages/codemirror/test-output/vitest/junit.xml
flags: codemirror
disable_search: true
fail_ci_if_error: false
- name: Run the highlightjs tests
id: test-highlightjs
run: pnpm run --filter=highlightjs test --coverage
- name: Upload highlightjs coverage to Codecov
uses: codecov/codecov-action@v7
if: ${{ !cancelled() && steps.test-highlightjs.outcome == 'success' }}
with:
files: packages/highlightjs/test-output/vitest/coverage/lcov.info
flags: highlightjs
disable_search: true
fail_ci_if_error: false
- name: Upload highlightjs test results to Codecov
uses: codecov/test-results-action@v1
if: ${{ !cancelled() && steps.test-highlightjs.outcome != 'skipped' }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: packages/highlightjs/test-output/vitest/junit.xml
flags: highlightjs
disable_search: true
fail_ci_if_error: false
- name: Run the pdfjs-viewer tests
id: test-pdfjs-viewer
run: pnpm run --filter=pdfjs-viewer test --coverage
- name: Upload pdfjs-viewer coverage to Codecov
uses: codecov/codecov-action@v7
if: ${{ !cancelled() && steps.test-pdfjs-viewer.outcome == 'success' }}
with:
files: packages/pdfjs-viewer/test-output/vitest/coverage/lcov.info
flags: pdfjs-viewer
disable_search: true
fail_ci_if_error: false
- name: Upload pdfjs-viewer test results to Codecov
uses: codecov/test-results-action@v1
if: ${{ !cancelled() && steps.test-pdfjs-viewer.outcome != 'skipped' }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: packages/pdfjs-viewer/test-output/vitest/junit.xml
flags: pdfjs-viewer
disable_search: true
fail_ci_if_error: false
- name: Run the rest of the tests
run: pnpm run --filter=\!client --filter=\!standalone --filter=\!server --filter=\!desktop --filter=\!commons --filter=\!ckeditor5 --filter=\!codemirror --filter=\!highlightjs --filter=\!pdfjs-viewer test
build_docker:
name: Build Docker image
runs-on: ubuntu-latest
needs:
- test_dev
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- name: Set up node & dependencies
uses: actions/setup-node@v7
with:
node-version: 24
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Update build info
run: pnpm run chore:update-build-info
- name: Trigger client build
run: pnpm client:build
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: Trigger server build
run: pnpm run server:build
- uses: docker/setup-buildx-action@v4
- uses: docker/build-push-action@v7
with:
context: apps/server
cache-from: type=gha
cache-to: type=gha,mode=max
test_docker:
name: Check Docker build
runs-on: ubuntu-latest
needs:
- build_docker
strategy:
matrix:
include:
- dockerfile: Dockerfile.alpine
- dockerfile: Dockerfile
steps:
- name: Checkout the repository
uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- name: Set up node & dependencies
uses: actions/setup-node@v7
with:
node-version: 24
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Update build info
run: pnpm run chore:update-build-info
- name: Trigger build
run: pnpm server:build
- name: Set IMAGE_NAME to lowercase
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
- name: Set TEST_TAG to lowercase
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build and export to Docker
uses: docker/build-push-action@v7
with:
context: apps/server
file: apps/server/${{ matrix.dockerfile }}
load: true
tags: ${{ env.TEST_TAG }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Validate container run output
run: |
CONTAINER_ID=$(docker run -d --log-driver=journald --rm --name trilium_local ${{ env.TEST_TAG }})
echo "Container ID: $CONTAINER_ID"
- name: Wait for the healthchecks to pass
uses: stringbean/docker-healthcheck-action@v3
with:
container: trilium_local
wait-time: 50
require-status: running
require-healthy: true
# Print the entire log of the container thus far, regardless if the healthcheck failed or succeeded
- name: Print entire log
if: always()
run: journalctl -u docker CONTAINER_NAME=trilium_local --no-pager