Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/actions/prepare-frontend-deps/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Prepare frontend dependencies
description: Build and stage generated dependencies needed by frontend packages

runs:
using: composite
steps:
- name: Build generated dependencies
shell: bash
run: |
set -euo pipefail

document_types=$(nix build .#document-types-wasm --no-link --print-out-paths)
catlog_wasm=$(nix build .#catlog-wasm-browser --no-link --print-out-paths)
api=$(nix build .#catcolabApi --no-link --print-out-paths)

rm -rf packages/document-types/pkg
mkdir -p packages/document-types/pkg
cp -R "$document_types"/. packages/document-types/pkg/

rm -rf packages/catlog-wasm/dist/pkg-browser
mkdir -p packages/catlog-wasm/dist/pkg-browser
cp -R "$catlog_wasm"/. packages/catlog-wasm/dist/pkg-browser/

rm -rf packages/backend/pkg/src
mkdir -p packages/backend/pkg/src
cp -R "$api"/src/. packages/backend/pkg/src/
118 changes: 76 additions & 42 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
id: cache-key
run: |
# Get git hash of the most recent commit affecting frontend or any of its dependencies
hash=$(git log -1 --format="%H" -- packages/frontend packages/backend/pkg packages/catlog packages/catlog-wasm packages/document-types packages/document-methods packages/ui-components Cargo.toml Cargo.lock)
hash=$(git log -1 --format="%H" -- .github/actions/prepare-frontend-deps .npmrc patches pnpm-lock.yaml pnpm-workspace.yaml build.py build-targets.json flake.nix flake.lock infrastructure/catcolab-api.nix infrastructure/ninja-target.nix packages/backend packages/catlog packages/catlog-wasm packages/document-methods packages/document-types packages/documents packages/frontend packages/logics packages/migrator packages/ui-components tools/oxlint-plugin-catcolab tools/vite-plugin-monorepo-dedupe Cargo.toml Cargo.lock rust-toolchain.toml)
echo "git-hash=${hash}" >> $GITHUB_OUTPUT
echo "Frontend git hash: ${git_hash}"

Expand All @@ -92,38 +92,40 @@ jobs:
packages/frontend/dist
key: frontend-build-${{ steps.cache-key.outputs.git-hash }}-${{ github.event_name == 'release' && 'production' || 'staging' }}

- name: Setup pnpm
- name: Install Nix
if: github.event_name == 'release' || steps.cache-frontend-build.outputs.cache-hit != 'true'
uses: pnpm/action-setup@v6
uses: cachix/install-nix-action@v25

- name: Setup NodeJS
- name: Configure Cachix
if: github.event_name == 'release' || steps.cache-frontend-build.outputs.cache-hit != 'true'
uses: actions/setup-node@v7
uses: cachix/cachix-action@v17
with:
node-version: 24
cache: "pnpm"
name: catcolab-jmoggr
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

- name: Install Rust toolchain from file
- name: Install NodeJS dependencies
if: github.event_name == 'release' || steps.cache-frontend-build.outputs.cache-hit != 'true'
uses: actions-rust-lang/setup-rust-toolchain@v2
with:
build-warnings: ""
run: nix develop .#frontend-build --command pnpm install

- name: Prepare frontend dependencies
if: github.event_name == 'release' || steps.cache-frontend-build.outputs.cache-hit != 'true'
uses: ./.github/actions/prepare-frontend-deps

- name: Generate CSS module declarations
if: github.event_name == 'release' || steps.cache-frontend-build.outputs.cache-hit != 'true'
run: nix develop .#frontend-build --command pnpm --filter ./packages/frontend run build:tcm

- name: Build for Staging
if: (github.event_name == 'push' || github.event_name == 'pull_request') && steps.cache-frontend-build.outputs.cache-hit != 'true'
run: |
pnpm install
pnpm --filter ./packages/frontend run build:deps
# Uses env from packages/frontend/.env.staging
pnpm --filter ./packages/frontend run build:staging
nix develop .#frontend-build --command pnpm --filter ./packages/frontend run build:staging

- name: Build for Production
if: github.event_name == 'release'
run: |
pnpm install
pnpm --filter ./packages/frontend run build:deps
# Uses env from packages/frontend/.env.production
pnpm --filter ./packages/frontend run build
nix develop .#frontend-build --command pnpm --filter ./packages/frontend run build

- name: Report cache status
run: |
Expand All @@ -141,25 +143,54 @@ jobs:
name: app
path: packages/frontend/dist

build_frontend_docs:
name: Build frontend docs
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
with:
fetch-depth: 0

- name: Compute cache key
id: cache-key
run: |
hash=$(git log -1 --format="%H" -- .github/actions/prepare-frontend-deps .npmrc patches pnpm-lock.yaml pnpm-workspace.yaml build.py build-targets.json flake.nix flake.lock infrastructure/catcolab-api.nix infrastructure/ninja-target.nix packages/backend packages/catlog packages/catlog-wasm packages/document-methods packages/document-types packages/documents packages/frontend packages/logics packages/migrator packages/ui-components tools/oxlint-plugin-catcolab tools/vite-plugin-monorepo-dedupe Cargo.toml Cargo.lock rust-toolchain.toml)
echo "git-hash=${hash}" >> "$GITHUB_OUTPUT"

- name: Cache frontend docs build
id: cache-frontend-docs
uses: actions/cache@v6
with:
path: packages/frontend/docs
key: frontend-docs-${{ steps.cache-key.outputs.git-hash }}

- name: Build frontend docs
- name: Install Nix
if: steps.cache-frontend-docs.outputs.cache-hit != 'true'
run: |
pnpm --filter ./packages/frontend run doc
uses: cachix/install-nix-action@v25

- name: Report frontend docs cache status
run: |
if [ "${{ steps.cache-frontend-docs.outputs.cache-hit }}" = "true" ]; then
echo "✅ Frontend docs restored from cache"
else
echo "🔨 Frontend docs built and cached"
fi
- name: Configure Cachix
if: steps.cache-frontend-docs.outputs.cache-hit != 'true'
uses: cachix/cachix-action@v17
with:
name: catcolab-jmoggr
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

- name: Install NodeJS dependencies
if: steps.cache-frontend-docs.outputs.cache-hit != 'true'
run: nix develop .#frontend-build --command pnpm install

- name: Prepare frontend dependencies
if: steps.cache-frontend-docs.outputs.cache-hit != 'true'
uses: ./.github/actions/prepare-frontend-deps

- name: Generate CSS module declarations
if: steps.cache-frontend-docs.outputs.cache-hit != 'true'
run: nix develop .#frontend-build --command pnpm --filter ./packages/frontend run build:tcm

- name: Build frontend docs
if: steps.cache-frontend-docs.outputs.cache-hit != 'true'
run: nix develop .#frontend-build --command pnpm --filter ./packages/frontend run doc

- name: Upload frontend docs
uses: actions/upload-artifact@v7
Expand Down Expand Up @@ -332,7 +363,7 @@ jobs:
id: cache-key
run: |
# Get git hash of the most recent commit affecting gaios or any of its dependencies
hash=$(git log -1 --format="%H" -- packages/gaios packages/frontend packages/backend/pkg packages/catlog packages/catlog-wasm packages/document-types packages/document-methods packages/ui-components Cargo.toml Cargo.lock)
hash=$(git log -1 --format="%H" -- .github/actions/prepare-frontend-deps .npmrc patches pnpm-lock.yaml pnpm-workspace.yaml build.py build-targets.json flake.nix flake.lock infrastructure/catcolab-api.nix infrastructure/ninja-target.nix packages/backend packages/catlog packages/catlog-wasm packages/document-methods packages/document-types packages/documents packages/frontend packages/gaios packages/logics packages/migrator packages/ui-components tools/oxlint-plugin-catcolab tools/vite-plugin-monorepo-dedupe Cargo.toml Cargo.lock rust-toolchain.toml)
echo "git-hash=${hash}" >> $GITHUB_OUTPUT
echo "Gaios git hash: ${hash}"

Expand All @@ -343,29 +374,32 @@ jobs:
path: packages/gaios/dist
key: gaios-build-${{ steps.cache-key.outputs.git-hash }}

- name: Setup pnpm
- name: Install Nix
if: steps.cache-gaios-build.outputs.cache-hit != 'true'
uses: pnpm/action-setup@v6
uses: cachix/install-nix-action@v25

- name: Setup NodeJS
- name: Configure Cachix
if: steps.cache-gaios-build.outputs.cache-hit != 'true'
uses: actions/setup-node@v7
uses: cachix/cachix-action@v17
with:
node-version: 24
cache: "pnpm"
name: catcolab-jmoggr
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

- name: Install Rust toolchain from file
- name: Install NodeJS dependencies
if: steps.cache-gaios-build.outputs.cache-hit != 'true'
uses: actions-rust-lang/setup-rust-toolchain@v2
with:
build-warnings: ""
run: nix develop .#frontend-build --command pnpm install

- name: Prepare frontend dependencies
if: steps.cache-gaios-build.outputs.cache-hit != 'true'
uses: ./.github/actions/prepare-frontend-deps

- name: Generate CSS module declarations
if: steps.cache-gaios-build.outputs.cache-hit != 'true'
run: nix develop .#frontend-build --command pnpm --filter ./packages/frontend run build:tcm

- name: Build gaios plugin
if: steps.cache-gaios-build.outputs.cache-hit != 'true'
run: |
pnpm install
pnpm --filter ./packages/gaios run build-deps
pnpm --filter ./packages/gaios run build
run: nix develop .#frontend-build --command pnpm --filter ./packages/gaios run build

- name: Report cache status
run: |
Expand Down
27 changes: 12 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,36 +92,33 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v7

- name: Setup pnpm
uses: pnpm/action-setup@v6
- name: Install Nix
uses: cachix/install-nix-action@v25

- name: Setup NodeJS
uses: actions/setup-node@v7
- name: Configure Cachix
uses: cachix/cachix-action@v17
with:
node-version: 24
cache: "pnpm"
name: catcolab-jmoggr
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

- name: Install NodeJS dependencies
run: |
pnpm install
nix develop .#frontend-build --command pnpm install

- name: Install Rust toolchain from file
uses: actions-rust-lang/setup-rust-toolchain@v2
with:
build-warnings: ""
- name: Prepare frontend dependencies
uses: ./.github/actions/prepare-frontend-deps

- name: Format/linting/import sorting
run: |
pnpm --filter "./packages/*" run build:deps
pnpm --filter "./packages/*" run ci
nix develop .#frontend-build --command pnpm --filter "./packages/*" run ci

- name: Typescript documents package tests
run: |
pnpm --filter catcolab-documents test
nix develop .#frontend-build --command pnpm --filter catcolab-documents test

- name: Typescript logic package tests
run: |
pnpm --filter catcolab-logics test
nix develop .#frontend-build --command pnpm --filter catcolab-logics test

build_nixos_system:
name: build NixOS system
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ web_modules/
.netlify
/packages/frontend/docs/
/target/
/build.ninja

# Sentry files
instrument.mjs
Expand Down
50 changes: 50 additions & 0 deletions build-targets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"document-types-wasm": {
"crate": "packages/document-types",
"command": "wasm-pack build packages/document-types",
"inputs": [
"Cargo.lock",
"Cargo.toml",
"rust-toolchain.toml",
"packages/document-types/.cargo/config.toml",
"packages/document-types/Cargo.toml",
"packages/document-types/README.md",
"packages/document-types/src"
],
"outputs": [
"packages/document-types/pkg/package.json",
"packages/document-types/pkg/catcolab_document_types.js",
"packages/document-types/pkg/catcolab_document_types_bg.js",
"packages/document-types/pkg/catcolab_document_types.d.ts",
"packages/document-types/pkg/catcolab_document_types_bg.wasm",
"packages/document-types/pkg/catcolab_document_types_bg.wasm.d.ts",
"packages/document-types/pkg/README.md"
]
},
"catlog-wasm-browser": {
"crate": "packages/catlog-wasm",
"command": "wasm-pack build packages/catlog-wasm --target browser -d dist/pkg-browser --debug",
"inputs": [
"Cargo.lock",
"Cargo.toml",
"rust-toolchain.toml",
"packages/catlog/Cargo.toml",
"packages/catlog/examples",
"packages/catlog/src",
"packages/catlog-wasm/.cargo/config.toml",
"packages/catlog-wasm/Cargo.toml",
"packages/catlog-wasm/src",
"packages/document-types/.cargo/config.toml",
"packages/document-types/Cargo.toml",
"packages/document-types/src"
],
"outputs": [
"packages/catlog-wasm/dist/pkg-browser/package.json",
"packages/catlog-wasm/dist/pkg-browser/catlog_wasm.js",
"packages/catlog-wasm/dist/pkg-browser/catlog_wasm_bg.js",
"packages/catlog-wasm/dist/pkg-browser/catlog_wasm.d.ts",
"packages/catlog-wasm/dist/pkg-browser/catlog_wasm_bg.wasm",
"packages/catlog-wasm/dist/pkg-browser/catlog_wasm_bg.wasm.d.ts"
]
}
}
76 changes: 76 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env python3

from io import StringIO
from pathlib import Path
import json
import os

import ninja
from ninja.ninja_syntax import Writer


ROOT = Path(__file__).resolve().parent
MANIFEST = ROOT / "build-targets.json"
BUILD_FILE = ROOT / "build.ninja"
BUILD_DIR = "target/ninja"

# Inputs shared by every target; changing the build definition rebuilds everything.
COMMON_INPUTS = ["build.py", "build-targets.json"]


def expand_inputs(inputs: list[str]) -> list[str]:
"""Expand directory inputs to the files they contain, as ninja needs files."""
files: set[Path] = set()
for rel in inputs:
path = ROOT / rel
if path.is_dir():
files.update(p for p in path.rglob("*") if p.is_file())
else:
files.add(path)
return sorted(p.relative_to(ROOT).as_posix() for p in files)


targets = json.loads(MANIFEST.read_text())

buffer = StringIO()
w = Writer(buffer)

w.variable("builddir", BUILD_DIR)
w.newline()

w.pool("wasm_pool", depth=1)
w.newline()

w.rule(
"wasm_pack",
command=f"mkdir -p {BUILD_DIR} && $wasm_pack_command && touch $out",
description="WASM-PACK $target_name",
pool="wasm_pool",
restat=True,
)
w.newline()

for name, target in targets.items():
stamp = f"{BUILD_DIR}/{name}.stamp"
w.build(
stamp,
"wasm_pack",
inputs=expand_inputs(COMMON_INPUTS + target["inputs"]),
implicit_outputs=target["outputs"],
variables={
"wasm_pack_command": target["command"],
"target_name": name,
},
)
w.build(name, "phony", stamp)
w.newline()

w.build("wasm", "phony", list(targets))
w.default("wasm")

contents = buffer.getvalue()
if not BUILD_FILE.exists() or BUILD_FILE.read_text() != contents:
BUILD_FILE.write_text(contents)

os.chdir(ROOT)
ninja.ninja()
Loading