diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml
deleted file mode 100644
index 5850c7f6d..000000000
--- a/.forgejo/workflows/ci.yml
+++ /dev/null
@@ -1,291 +0,0 @@
-# GENERATED BY: cargo xtask ci
-# DO NOT EDIT - edit xtask/src/ci.rs instead
-
----
-name: CI
-"on":
- push:
- tags:
- - v*
- branches:
- - main
- pull_request:
- branches:
- - main
- workflow_dispatch: {}
-permissions:
- contents: read
-env:
- CARGO_TERM_COLOR: always
-jobs:
- forgejo-linux-x64:
- name: Forgejo linux-x64
- runs-on:
- - linux-x86_64-trusted
- container:
- image: "code.vixen.rs/vixen/vixen-ci:latest"
- volumes:
- - "/srv/ci/cache/dodeca:/srv/ci/cache/dodeca"
- timeout-minutes: 90
- env:
- HOME: /srv/ci/cache/dodeca/home
- CARGO_HOME: /srv/ci/cache/dodeca/cargo
- CARGO_INCREMENTAL: "1"
- FORGEJO_TOKEN: ${{ github.token }}
- RUST_BACKTRACE: "1"
- steps:
- - name: Prepare Vixen CI
- run: vixen-ci prepare
- env:
- DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
- - name: Checkout
- run: vixen-ci checkout
- - name: Prepare stable source
- run: |-
- vixen-ci stable-src dodeca-linux-x64 \
- --exclude=/crates/dodeca-devtools/pkg/ \
- --exclude=/crates/dodeca-search-wasm/pkg/
- export STABLE_SRC="$HOME/.cache/vixen/dodeca-linux-x64-src"
- export CARGO_TARGET_DIR="$HOME/.cache/vixen/dodeca-linux-x64-target"
- cd "$STABLE_SRC"
- rm -rf target
- ln -s "$CARGO_TARGET_DIR" target
-
- echo "STABLE_SRC=$STABLE_SRC"
- echo "CARGO_TARGET_DIR=$CARGO_TARGET_DIR"
- - name: Build and test
- run: |
- set -euo pipefail
- cd "$STABLE_SRC"
- cargo xtask ci-forgejo --check
-
- rustup target add wasm32-unknown-unknown
- if ! command -v wasm-pack >/dev/null 2>&1; then
- cargo install wasm-pack --locked
- fi
- npm install -g pnpm
- scripts/build-browser-assets.sh
- cargo nextest run
- cargo xtask integration
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- export DODECA_RELEASE_VERSION="${GITHUB_REF_NAME}"
- fi
- cargo build --release
- actual="$(target/release/ddc --version)"
- echo "$actual"
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- expected="ddc ${GITHUB_REF_NAME#v}"
- if [[ "$actual" != "$expected" ]]; then
- echo "Expected '$expected', got '$actual'" >&2
- exit 1
- fi
- fi
- rm -rf dist
- mkdir -p dist
- cp target/release/ddc dist/
- chmod +x dist/ddc
- #!/bin/bash
- set -euo pipefail
-
- echo 'Verifying all required artifacts exist in dist/'
- missing=0
-
- if [[ ! -x dist/ddc ]]; then
- echo '❌ MISSING: ddc'
- missing=1
- else
- echo '✓ ddc'
- fi
-
- if [[ $missing -eq 1 ]]; then
- echo ''
- echo 'ERROR: Some required binaries are missing!'
- echo 'This usually means a ddc build job failed or artifact upload was incomplete.'
- exit 1
- fi
-
- echo ''
- echo 'All artifacts verified.'
-
- DODECA_BIN="$STABLE_SRC/target/release/ddc" \
- bash -lc 'cd "$STABLE_SRC/browser-tests" && npm ci && npx playwright install chromium --with-deps && npm test'
- shell: bash
- - name: Assemble archive
- run: |-
- set -euo pipefail
- cd "$STABLE_SRC"
- bash scripts/assemble-archive.sh x86_64-unknown-linux-gnu
- mkdir -p "$GITHUB_WORKSPACE/dist"
- cp "dodeca-x86_64-unknown-linux-gnu.tar.xz" "$GITHUB_WORKSPACE/dist/"
- ls -la "$GITHUB_WORKSPACE/dist/"
- shell: bash
- - name: Upload artifact
- uses: "https://data.forgejo.org/actions/upload-artifact@v3"
- with:
- name: build-linux-x64
- path: dist/dodeca-x86_64-unknown-linux-gnu.tar.xz
- forgejo-macos-arm64:
- name: Forgejo macos-arm64
- runs-on:
- - mac
- timeout-minutes: 90
- env:
- CARGO_INCREMENTAL: "0"
- FORGEJO_TOKEN: ${{ github.token }}
- RUST_BACKTRACE: "1"
- steps:
- - name: Install vixen-ci
- run: |-
- mkdir -p "$RUNNER_TEMP/vixen-ci"
- curl -fsSL https://vixen-misc.s3-website.fr-par.scw.cloud/vixen-ci/latest/vixen-ci -o "$RUNNER_TEMP/vixen-ci/vixen-ci"
- chmod +x "$RUNNER_TEMP/vixen-ci/vixen-ci"
- echo "$RUNNER_TEMP/vixen-ci" >> "$GITHUB_PATH"
- - name: Prepare Vixen CI
- run: vixen-ci prepare
- env:
- DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
- - name: Checkout
- run: vixen-ci checkout
- - name: Rust toolchain
- run: vixen-ci rust-toolchain
- - name: Install nextest
- run: vixen-ci nextest
- - name: Check rsync
- run: rsync --version >/dev/null
- - name: Prepare stable source
- run: |-
- vixen-ci stable-src dodeca-macos-arm64 \
- --exclude=/crates/dodeca-devtools/pkg/ \
- --exclude=/crates/dodeca-search-wasm/pkg/
- export STABLE_SRC="$HOME/.cache/vixen/dodeca-macos-arm64-src"
- export CARGO_TARGET_DIR="$HOME/.cache/vixen/dodeca-macos-arm64-target"
- cd "$STABLE_SRC"
- rm -rf target
- ln -s "$CARGO_TARGET_DIR" target
- rm -rf "$CARGO_TARGET_DIR"/release/incremental "$CARGO_TARGET_DIR"/debug/incremental
-
- echo "STABLE_SRC=$STABLE_SRC"
- echo "CARGO_TARGET_DIR=$CARGO_TARGET_DIR"
- - name: Build and test
- run: |+
- set -euo pipefail
- cd "$STABLE_SRC"
-
- rustup target add wasm32-unknown-unknown
- if ! command -v wasm-pack >/dev/null 2>&1; then
- cargo install wasm-pack --locked
- fi
- command -v pnpm >/dev/null 2>&1 || npm install -g pnpm || corepack enable || true
- scripts/build-browser-assets.sh
- cargo nextest run
- cargo xtask integration
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- export DODECA_RELEASE_VERSION="${GITHUB_REF_NAME}"
- fi
- cargo build --release
- actual="$(target/release/ddc --version)"
- echo "$actual"
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- expected="ddc ${GITHUB_REF_NAME#v}"
- if [[ "$actual" != "$expected" ]]; then
- echo "Expected '$expected', got '$actual'" >&2
- exit 1
- fi
- fi
- rm -rf dist
- mkdir -p dist
- cp target/release/ddc dist/
- chmod +x dist/ddc
- #!/bin/bash
- set -euo pipefail
-
- echo 'Verifying all required artifacts exist in dist/'
- missing=0
-
- if [[ ! -x dist/ddc ]]; then
- echo '❌ MISSING: ddc'
- missing=1
- else
- echo '✓ ddc'
- fi
-
- if [[ $missing -eq 1 ]]; then
- echo ''
- echo 'ERROR: Some required binaries are missing!'
- echo 'This usually means a ddc build job failed or artifact upload was incomplete.'
- exit 1
- fi
-
- echo ''
- echo 'All artifacts verified.'
-
- shell: bash
- - name: Assemble archive
- run: |-
- set -euo pipefail
- cd "$STABLE_SRC"
- if ! command -v xz >/dev/null 2>&1 && command -v brew >/dev/null 2>&1; then
- HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install xz
- fi
- bash scripts/assemble-archive.sh aarch64-apple-darwin
- mkdir -p "$GITHUB_WORKSPACE/dist"
- cp "dodeca-aarch64-apple-darwin.tar.xz" "$GITHUB_WORKSPACE/dist/"
- ls -la "$GITHUB_WORKSPACE/dist/"
- shell: bash
- - name: Upload artifact
- uses: "https://data.forgejo.org/actions/upload-artifact@v3"
- with:
- name: build-macos-arm64
- path: dist/dodeca-aarch64-apple-darwin.tar.xz
- publish:
- name: Publish release
- runs-on:
- - linux-x86_64-trusted
- container:
- image: "code.vixen.rs/vixen/vixen-ci:latest"
- volumes:
- - "/srv/ci/cache/dodeca:/srv/ci/cache/dodeca"
- timeout-minutes: 30
- needs:
- - forgejo-linux-x64
- - forgejo-macos-arm64
- if: "startsWith(github.ref, 'refs/tags/')"
- env:
- HOME: /srv/ci/cache/dodeca/home
- FORGEJO_TOKEN: ${{ github.token }}
- steps:
- - name: Checkout repository
- run: |-
- mkdir -p "$GITHUB_WORKSPACE"
- cd "$GITHUB_WORKSPACE"
- git init -q
- git remote remove origin 2>/dev/null || true
- git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
- git -c http.extraHeader="Authorization: token ${FORGEJO_TOKEN}" fetch --depth 1 origin "${GITHUB_SHA}"
- git checkout -q --detach FETCH_HEAD
- shell: bash
- - name: Download artifact
- uses: "https://data.forgejo.org/actions/download-artifact@v3"
- with:
- name: build-linux-x64
- path: dist
- - name: Download artifact
- uses: "https://data.forgejo.org/actions/download-artifact@v3"
- with:
- name: build-macos-arm64
- path: dist
- - name: Flatten artifact directories
- run: find dist -mindepth 2 -type f -exec mv -t dist {} + 2>/dev/null || true; find dist -mindepth 1 -type d -empty -delete 2>/dev/null || true
- - name: List artifacts
- run: ls -la dist/
- - name: Prepare release artifacts
- run: bash scripts/release.sh
- shell: bash
- - name: Publish to object storage
- run: "bash scripts/publish-release.sh \"${GITHUB_REF_NAME}\""
- shell: bash
- env:
- AWS_ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY_ID }}
- AWS_SECRET_ACCESS_KEY: ${{ secrets.ACCESS_SECRET_KEY }}
- AWS_DEFAULT_REGION: fr-par
- AWS_EC2_METADATA_DISABLED: "true"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0e6f1a3f8..b98e63903 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,12 +1,7 @@
-# GENERATED BY: cargo xtask ci
-# DO NOT EDIT - edit xtask/src/ci.rs instead
-
----
name: CI
-"on":
+
+on:
push:
- tags:
- - v*
branches:
- main
pull_request:
@@ -15,453 +10,34 @@ name: CI
merge_group:
branches:
- main
- workflow_dispatch: {}
-permissions:
- contents: read
-env:
- CARGO_TERM_COLOR: always
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
- check-ci:
- name: Check CI up to date
- runs-on:
- - bearcove-ubuntu-24.04
- timeout-minutes: 10
+ check:
+ name: Check
+ runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Install Rust
- uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - name: Rust cache
- uses: Swatinem/rust-cache@v2
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@stable
+ - uses: Swatinem/rust-cache@v2
with:
cache-on-failure: "true"
- cache-targets: "false"
- - name: Check CI files are up to date
- run: cargo xtask ci-github --check && cargo xtask ci-forgejo --check
+ - name: Check
+ run: cargo check --workspace --all-targets
+
clippy:
name: Clippy
- runs-on:
- - bearcove-ubuntu-24.04
- timeout-minutes: 30
- continue-on-error: true
+ runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Install Rust
- uses: dtolnay/rust-toolchain@master
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@stable
with:
- toolchain: stable
components: clippy
- targets: wasm32-unknown-unknown
- - name: Rust cache
- uses: Swatinem/rust-cache@v2
+ - uses: Swatinem/rust-cache@v2
with:
cache-on-failure: "true"
- cache-targets: "true"
- name: Clippy
- run: cargo clippy --all-features --all-targets -- -D warnings
- check-macos:
- name: Check macOS
- runs-on:
- - macos-15
- timeout-minutes: 30
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Install Rust
- uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - name: Rust cache
- uses: Swatinem/rust-cache@v2
- with:
- cache-on-failure: "true"
- cache-targets: "true"
- cache-bin: "false"
- - name: Check macOS
- run: cargo check --workspace --all-targets
- check-windows:
- name: Check Windows
- runs-on:
- - windows-latest
- timeout-minutes: 30
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Install Rust
- uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - name: Rust cache
- uses: Swatinem/rust-cache@v2
- with:
- cache-on-failure: "true"
- cache-targets: "true"
- - name: Check Windows
- run: cargo check --workspace --all-targets
- build-ddc-linux-x64:
- name: Build ddc (linux-x64)
- runs-on:
- - bearcove-ubuntu-24.04
- timeout-minutes: 30
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Install Rust
- uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: "20"
- - name: Install wasm-pack
- uses: jetli/wasm-pack-action@v0.4.0
- with:
- version: latest
- - name: Rust cache
- uses: Swatinem/rust-cache@v2
- with:
- cache-on-failure: "true"
- cache-targets: "true"
- - name: Install pnpm
- run: npm install -g pnpm
- - name: Build ddc
- run: |-
- set -euo pipefail
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- export DODECA_RELEASE_VERSION="${GITHUB_REF_NAME}"
- fi
- cargo build --release --bin ddc --verbose
- actual="$(target/release/ddc --version)"
- echo "$actual"
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- expected="ddc ${GITHUB_REF_NAME#v}"
- if [[ "$actual" != "$expected" ]]; then
- echo "Expected '$expected', got '$actual'" >&2
- exit 1
- fi
- fi
- shell: bash
- - name: Test ddc
- run: |-
- set -euo pipefail
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- export DODECA_RELEASE_VERSION="${GITHUB_REF_NAME}"
- fi
- cargo test --release --bin ddc
- shell: bash
- - name: Build browser assets
- run: |-
- set -euo pipefail
- scripts/build-browser-assets.sh
- shell: bash
- - name: Prepare ddc dist
- run: |-
- set -euo pipefail
- rm -rf dist
- mkdir -p dist
- cp target/release/ddc dist/ddc
- chmod +x dist/ddc
- scripts/stage-browser-assets.sh dist/dodeca-assets
- DODECA_ASSETS_DIR=dist/dodeca-assets dist/ddc assets --packaged --fail
- ls -laR dist
- shell: bash
- - name: Upload artifact
- uses: actions/upload-artifact@v4
- with:
- name: ddc-linux-x64
- path: dist
- integration-linux-x64:
- name: Integration (linux-x64)
- runs-on:
- - bearcove-ubuntu-24.04
- timeout-minutes: 30
- needs:
- - build-ddc-linux-x64
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Install Rust
- uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - name: Rust cache
- uses: Swatinem/rust-cache@v2
- with:
- cache-on-failure: "true"
- cache-targets: "true"
- - name: Build integration-tests
- run: cargo build --package integration-tests
- - name: Download ddc
- uses: actions/download-artifact@v4
- with:
- name: ddc-linux-x64
- path: dist
- - name: Prepare artifacts
- run: chmod +x dist/ddc && ls -la dist/
- - name: Verify artifacts
- run: |
- #!/bin/bash
- set -euo pipefail
-
- echo 'Verifying all required artifacts exist in dist/'
- missing=0
-
- if [[ ! -x dist/ddc ]]; then
- echo '❌ MISSING: ddc'
- missing=1
- else
- echo '✓ ddc'
- fi
-
- if [[ $missing -eq 1 ]]; then
- echo ''
- echo 'ERROR: Some required binaries are missing!'
- echo 'This usually means a ddc build job failed or artifact upload was incomplete.'
- exit 1
- fi
-
- echo ''
- echo 'All artifacts verified.'
- - name: Run integration tests
- run: cargo xtask integration --no-build
- env:
- DODECA_BIN: ${{ github.workspace }}/dist/ddc
- DODECA_TEST_FIXTURES_DIR: ${{ github.workspace }}/crates/integration-tests/fixtures
- browser-tests-linux-x64:
- name: Browser Tests (linux-x64)
- runs-on:
- - bearcove-ubuntu-24.04
- timeout-minutes: 30
- needs:
- - build-ddc-linux-x64
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Download ddc
- uses: actions/download-artifact@v4
- with:
- name: ddc-linux-x64
- path: dist
- - name: Prepare artifacts
- run: chmod +x dist/ddc && ls -la dist/
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: "20"
- - name: Install browser test dependencies
- run: cd browser-tests && npm ci && npx playwright install chromium --with-deps
- - name: Run browser tests
- run: cd browser-tests && npm test
- env:
- DODECA_BIN: ${{ github.workspace }}/dist/ddc
- package-linux-x64:
- name: Package (linux-x64)
- runs-on:
- - bearcove-ubuntu-24.04
- timeout-minutes: 30
- if: "startsWith(github.ref, 'refs/tags/')"
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Install Rust
- uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: "20"
- - name: Install wasm-pack
- uses: jetli/wasm-pack-action@v0.4.0
- with:
- version: latest
- - name: Rust cache
- uses: Swatinem/rust-cache@v2
- with:
- cache-on-failure: "true"
- cache-targets: "true"
- - name: Install pnpm
- run: npm install -g pnpm
- - name: Build browser assets
- run: |-
- set -euo pipefail
- scripts/build-browser-assets.sh
- shell: bash
- - name: Build ddc
- run: |-
- set -euo pipefail
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- export DODECA_RELEASE_VERSION="${GITHUB_REF_NAME}"
- fi
- cargo build --release --bin ddc --verbose
- actual="$(target/release/ddc --version)"
- echo "$actual"
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- expected="ddc ${GITHUB_REF_NAME#v}"
- if [[ "$actual" != "$expected" ]]; then
- echo "Expected '$expected', got '$actual'" >&2
- exit 1
- fi
- fi
- shell: bash
- - name: Assemble archive
- run: bash scripts/assemble-archive.sh x86_64-unknown-linux-gnu
- - name: Upload artifact
- uses: actions/upload-artifact@v4
- with:
- name: build-linux-x64
- path: dodeca-x86_64-unknown-linux-gnu.tar.xz
- package-macos-arm64:
- name: Package (macos-arm64)
- runs-on:
- - blacksmith-12vcpu-macos-15
- timeout-minutes: 30
- if: "startsWith(github.ref, 'refs/tags/')"
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Install Rust
- uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: "20"
- - name: Install wasm-pack
- uses: jetli/wasm-pack-action@v0.4.0
- with:
- version: latest
- - name: Install pnpm
- run: npm install -g pnpm
- - name: Build browser assets
- run: |-
- set -euo pipefail
- scripts/build-browser-assets.sh
- shell: bash
- - name: Build ddc
- run: |-
- set -euo pipefail
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- export DODECA_RELEASE_VERSION="${GITHUB_REF_NAME}"
- fi
- cargo build --release --bin ddc --verbose
- actual="$(target/release/ddc --version)"
- echo "$actual"
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- expected="ddc ${GITHUB_REF_NAME#v}"
- if [[ "$actual" != "$expected" ]]; then
- echo "Expected '$expected', got '$actual'" >&2
- exit 1
- fi
- fi
- shell: bash
- - name: Install xz (macOS)
- run: if ! command -v xz >/dev/null 2>&1 && command -v brew >/dev/null 2>&1; then HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install xz; fi
- - name: Assemble archive
- run: bash scripts/assemble-archive.sh aarch64-apple-darwin
- - name: Upload artifact
- uses: actions/upload-artifact@v4
- with:
- name: build-macos-arm64
- path: dodeca-aarch64-apple-darwin.tar.xz
- package-windows-x64:
- name: Package (windows-x64)
- runs-on:
- - blacksmith-8vcpu-windows-2025
- timeout-minutes: 30
- if: "startsWith(github.ref, 'refs/tags/')"
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Install Rust
- uses: dtolnay/rust-toolchain@master
- with:
- toolchain: stable
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: "20"
- - name: Install wasm-pack
- uses: jetli/wasm-pack-action@v0.4.0
- with:
- version: latest
- - name: Install pnpm
- run: npm install -g pnpm
- - name: Build browser assets
- run: |-
- set -euo pipefail
- scripts/build-browser-assets.sh
- shell: bash
- - name: Build ddc
- run: |-
- set -euo pipefail
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- export DODECA_RELEASE_VERSION="${GITHUB_REF_NAME}"
- fi
- cargo build --release --bin ddc --verbose
- actual="$(target/release/ddc --version)"
- echo "$actual"
- if [[ "${GITHUB_REF_TYPE:-}" == "tag" && -n "${GITHUB_REF_NAME:-}" ]]; then
- expected="ddc ${GITHUB_REF_NAME#v}"
- if [[ "$actual" != "$expected" ]]; then
- echo "Expected '$expected', got '$actual'" >&2
- exit 1
- fi
- fi
- shell: bash
- - name: Assemble archive
- run: bash scripts/assemble-archive.sh x86_64-pc-windows-msvc
- - name: Upload artifact
- uses: actions/upload-artifact@v4
- with:
- name: build-windows-x64
- path: dodeca-x86_64-pc-windows-msvc.zip
- release:
- name: Release
- runs-on:
- - ubuntu-latest
- timeout-minutes: 30
- needs:
- - integration-linux-x64
- - package-linux-x64
- - package-macos-arm64
- - package-windows-x64
- if: "startsWith(github.ref, 'refs/tags/')"
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
- permissions:
- contents: write
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: Download all artifacts
- uses: actions/download-artifact@v4
- with:
- path: dist
- pattern: build-*
- merge-multiple: "true"
- - name: List artifacts (before flatten)
- run: ls -laR dist/
- - name: Flatten artifact directories
- run: find dist -mindepth 2 -type f -exec mv -t dist {} + 2>/dev/null || true; find dist -mindepth 1 -type d -empty -delete 2>/dev/null || true
- - name: List artifacts (after flatten)
- run: ls -la dist/
- - name: Create GitHub Release
- run: |-
- shopt -s nullglob
- # Rename install.sh to dodeca-installer.sh for the release
- cp install.sh dist/dodeca-installer.sh
- gh release create "${{ github.ref_name }}" \
- --title "dodeca ${{ github.ref_name }}" \
- --generate-notes \
- dist/*.tar.xz dist/*.zip dist/dodeca-installer.sh
- shell: bash
- - name: Update Homebrew tap
- run: "bash scripts/update-homebrew.sh \"${{ github.ref_name }}\""
- shell: bash
+ run: cargo clippy --workspace --all-targets --all-features -- -D warnings
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index ca1fa75be..c0b0b542f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -148,7 +148,7 @@ version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -159,7 +159,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -2817,7 +2817,7 @@ checksum = "ad5208a115eaba24916f7456929832e310a81518c641f93fee4f89aa93aa3675"
dependencies = [
"cfg-if",
"libc",
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -3171,7 +3171,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -3225,9 +3225,9 @@ dependencies = [
[[package]]
name = "facet"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd3e58a40571ddd336865ec9643ea43d5cf93c35ae4f5ad5d903dc4e427a2e03"
+checksum = "db275d3c6e1957f362cd2a965caa699fe3134a1c78b1b696a8da8cfa60e101c5"
dependencies = [
"autocfg",
"facet-core",
@@ -3236,9 +3236,9 @@ dependencies = [
[[package]]
name = "facet-core"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2c2ad271d54e76358f179bc5f75483c4ed025d1009a8599f299ac7bee99dbdd"
+checksum = "7d33c21739c2d68ab096cdc48baf1bcebfbcc82496b96fddcb93aa96cd29775b"
dependencies = [
"autocfg",
"bytes",
@@ -3249,23 +3249,24 @@ dependencies = [
"impls",
"indexmap",
"smallvec 1.15.2",
+ "taxon",
"tendril",
]
[[package]]
name = "facet-default"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7aa9e2bfb168e7c767d8808435fcb358d0d2e244cd75f5da09e850afd1e4fff7"
+checksum = "98884f7816ad7ac64e8db286a1ec7a3a154805177f9dfd21f60b9b8a28c9309b"
dependencies = [
"facet",
]
[[package]]
name = "facet-dessert"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39aaece2ca1e5aad3e2bee0f4fea23ae0a11eb5a0b88bb265ec09c39d580aac5"
+checksum = "6ccdcd3b144d86fa7fc1780d344bb3581e9d050bf731cd4fbbfa155349993488"
dependencies = [
"facet-core",
"facet-reflect",
@@ -3273,9 +3274,9 @@ dependencies = [
[[package]]
name = "facet-dom"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfd84b5e49e5863eb584244f1582c6cdbc8cd474b79e881ff2fcf0a15a80c452"
+checksum = "696c50ca00ab9fd5b15fd86e5f884d6dd260e35ad0df6bed1f77a2d889c4aa2b"
dependencies = [
"facet-core",
"facet-dessert",
@@ -3287,18 +3288,18 @@ dependencies = [
[[package]]
name = "facet-error"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "175f8aab2cbd354a829214f7f033c5dff59c60b66848fc833116a4dabcc7f7c6"
+checksum = "a134040058e341c2b1e681bea278922d0ff3c5572c88dbc565111e7dc626e238"
dependencies = [
"facet",
]
[[package]]
name = "facet-format"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64c612924dc3d45853f81e9cfafc513f3ec0be5982f943a7945f49f2492effb1"
+checksum = "3c75a4fe14aef3c11614dc018e0c33ed3ac93bc7a8e6c006e0ffa0f7eb715685"
dependencies = [
"facet-core",
"facet-dessert",
@@ -3320,22 +3321,21 @@ dependencies = [
[[package]]
name = "facet-json"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82902c758e29af6599f852dd783206697fd33383fa499b07bdcddbd8eb1ef4d0"
+checksum = "91b8be2433eba7a2df5cb744714cb62d9ecee4db09722436d6acf68a921723cf"
dependencies = [
"facet",
"facet-core",
"facet-format",
"facet-reflect",
- "weavy",
]
[[package]]
name = "facet-macro-parse"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a43cd88c3df76b7606194a059973aea078940de8cc442dca7c327f51bbc014"
+checksum = "9bc6dce04d6069e36e8dcdf1699f2650b566eb6dbdfc479342be8ccf2758a4c3"
dependencies = [
"facet-macro-types",
"proc-macro2",
@@ -3344,9 +3344,9 @@ dependencies = [
[[package]]
name = "facet-macro-types"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dce57ed093067e4a3a1ab42c8c84eec1a25af7726d43a22e390734b29b947ec"
+checksum = "863542bfe7eae71ef32d8a4ba6490d9cfa282545ba56afc82d4ed94fba91a9ca"
dependencies = [
"proc-macro2",
"quote",
@@ -3355,18 +3355,18 @@ dependencies = [
[[package]]
name = "facet-macros"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ae8b8eb7169a41245f31bda2912a3c7d33e0efa7269c0c8847b54377e31ff68"
+checksum = "269a10f70d4ce2a6c26c54238627f1878e78668d695198dc3206279271d68595"
dependencies = [
"facet-macros-impl",
]
[[package]]
name = "facet-macros-impl"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d7d66574a47f07e87058ce6e429a7be58fd77c7686e572cb1f85d8a6a840c6"
+checksum = "48789395fedf755c16222693bf6b77870e36b71625f38793c8a06bb3f86845ef"
dependencies = [
"facet-macro-parse",
"facet-macro-types",
@@ -3378,18 +3378,18 @@ dependencies = [
[[package]]
name = "facet-path"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a21c558bfb27bf957ead130a3b7e5ea2dee7ccbfb31a524053f061efa164d6f"
+checksum = "f6f9587a5b882492c2c250c1f0020fc2f238d26e33bc8a90f953537c4a6eb95d"
dependencies = [
"facet-core",
]
[[package]]
name = "facet-postcard"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e8128786bb21103302ddb23f8aa532724d28111982c201a4951700ef8bbd807"
+checksum = "ad2c4fc880a32955708f97c544684afcc2ca18218513309e08da49ea4f168c39"
dependencies = [
"facet-core",
"facet-format",
@@ -3400,9 +3400,9 @@ dependencies = [
[[package]]
name = "facet-pretty"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dbcf41fe256543a1cdc8a75b3ef130100fbe4a7e180b20472d5601e03349d5b"
+checksum = "87e9fdb0a7bd353b20035c1fadf237d2778e06d19fd2537d5a71c8a8919f8aa0"
dependencies = [
"facet-core",
"facet-reflect",
@@ -3412,9 +3412,9 @@ dependencies = [
[[package]]
name = "facet-reflect"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8486d2a82dcb2a1bdca472c2cdc513d0feacda3af2ffd50fb9e04f8dedda8735"
+checksum = "7a94d748ff98faa8b281580dd759af7b10cc5914603af776fcb58bca9f6d72d7"
dependencies = [
"facet-core",
"facet-path",
@@ -3424,15 +3424,15 @@ dependencies = [
[[package]]
name = "facet-singularize"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ad2f8eb61bc1f8e7d1b2e3f31ce3d0ac07b9c6bb7479c4d5ba490b2deeffce9"
+checksum = "ec34b284a001b4b8125a9c8377964e701a2bb69b05e18e42d1f3cb2716efeeaa"
[[package]]
name = "facet-solver"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5c800eb08ef5e1f18ffafcddf40da5d9ea3c86b8f0486f6ee077b0a3d497812"
+checksum = "dbf7661c49144bf0b2f87a9a2088dce873838034734fa749da41d461ce9bad9b"
dependencies = [
"facet-core",
"facet-reflect",
@@ -3460,9 +3460,9 @@ dependencies = [
[[package]]
name = "facet-svg"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73e97325017feea9dd9679bd66c4cd9fe475eab1b425f000b09d07d86ec3ac05"
+checksum = "7cd81ba08b177a9227471e62847a9ac058226a5a50d37597bd294050aba3a11f"
dependencies = [
"facet",
"facet-xml",
@@ -3493,9 +3493,9 @@ dependencies = [
[[package]]
name = "facet-toml"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ec563b4a7628e54a1d22b7e3750b2da21721e938f5caf12e63e8347ee33bf92"
+checksum = "ebfe86659e1a96f72ff123f037ebc5e6dadb09109fac14ab81d0a68d8e319996"
dependencies = [
"facet-core",
"facet-format",
@@ -3505,9 +3505,9 @@ dependencies = [
[[package]]
name = "facet-value"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfc5a08618f541594700de7dc032054e04368c06029682d61ab43683d18f5232"
+checksum = "408ab3eed05a33bf14d75ec0419e883eb67f6aabad7a79be9cb6d1513ff42b65"
dependencies = [
"facet-core",
"facet-format",
@@ -3517,9 +3517,9 @@ dependencies = [
[[package]]
name = "facet-xml"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ffe45cbe59194f92392f45450b2c6925dd2cdbcdbd8da32315b43f1e7f2b6b"
+checksum = "71ef04c56f505ccf7049677faeb95f3d6b34be3ee74497b6f35ec8b5785d3c0f"
dependencies = [
"facet",
"facet-core",
@@ -3530,9 +3530,9 @@ dependencies = [
[[package]]
name = "facet-yaml"
-version = "0.50.0-rc.5"
+version = "0.50.0-rc.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01124fed8eb53318eba11476e2a47335f5a5581d7df23baa3db78541bd0cfcd4"
+checksum = "adcfb72818c7cd7f71f76cf7a03353bb36bd81cbb9c3bcdc2be99c93e8661365"
dependencies = [
"facet",
"facet-core",
@@ -3580,9 +3580,9 @@ dependencies = [
[[package]]
name = "figue"
-version = "5.0.0-rc.5"
+version = "5.0.0-rc.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d683110c41f61f23e580c2f11887cfd2667a75388dbbc551b0fec025d3f6aaa8"
+checksum = "aee1188934c6b32dfa1aea490c9bcb1acdcc914db2cabc42d1cb0fcfdb8e8064"
dependencies = [
"ariadne 0.6.0",
"camino",
@@ -3606,9 +3606,9 @@ dependencies = [
[[package]]
name = "figue-attrs"
-version = "5.0.0-rc.5"
+version = "5.0.0-rc.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfb26d9b503638fe61b04ef7d76d0d53f39993549948c0267e05094185b6b808"
+checksum = "8abaae62355b1223346bb0df83239e1697a42d238b8d2f2fa261414e25708f0e"
dependencies = [
"facet",
]
@@ -4781,7 +4781,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
dependencies = [
"hermit-abi",
"libc",
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -5521,7 +5521,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -7406,7 +7406,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -7463,7 +7463,7 @@ dependencies = [
"security-framework",
"security-framework-sys",
"webpki-root-certs",
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -7917,7 +7917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
dependencies = [
"libc",
- "windows-sys 0.61.2",
+ "windows-sys 0.60.2",
]
[[package]]
@@ -8283,6 +8283,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3a6bfce3d99adfa72d24750a61f782f3036a81e7f86d8841ee1326deaebd171"
+[[package]]
+name = "taxon"
+version = "0.2.0-rc.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acccfbd01e7cf4c7ea384b46df6ba3afb934ad88abd247f92998249854de968"
+dependencies = [
+ "blake3",
+]
+
[[package]]
name = "tempfile"
version = "3.27.0"
@@ -8293,7 +8302,7 @@ dependencies = [
"getrandom 0.4.2",
"once_cell",
"rustix",
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -8344,7 +8353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
dependencies = [
"rustix",
- "windows-sys 0.61.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -9733,7 +9742,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -10135,16 +10144,10 @@ checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
name = "xtask"
version = "0.0.0"
dependencies = [
- "camino",
"dodeca-protocol",
- "eyre",
"facet",
- "facet-yaml",
"figue",
- "fs-err",
- "indexmap",
"owo-colors",
- "structstruck",
"vox-codegen",
]
diff --git a/Cargo.toml b/Cargo.toml
index 2d92cc964..65237f6eb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -79,17 +79,17 @@ hotmeal-wasm = { path = "libs/hotmeal/hotmeal-wasm" }
cstree = { version = "0.14.0", features = ["derive"] }
divan = { package = "codspeed-divan-compat", version = "4.7.0" }
-facet = { version = "0.50.0-rc.5", features = ["camino"] }
-facet-core = "0.50.0-rc.5"
+facet = { version = "0.50.0-rc.7", features = ["camino"] }
+facet-core = "0.50.0-rc.7"
facet-hash = { version = "0.50.0-rc.5", features = ["jit"] }
-facet-reflect = "0.50.0-rc.5"
-facet-default = "0.50.0-rc.5"
-facet-format = "0.50.0-rc.5"
-facet-json = "0.50.0-rc.5"
-facet-postcard = "0.50.0-rc.5"
-facet-toml = "0.50.0-rc.5"
-facet-value = "0.50.0-rc.5"
-facet-yaml = "0.50.0-rc.5"
+facet-reflect = "0.50.0-rc.7"
+facet-default = "0.50.0-rc.7"
+facet-format = "0.50.0-rc.7"
+facet-json = "0.50.0-rc.7"
+facet-postcard = "0.50.0-rc.7"
+facet-toml = "0.50.0-rc.7"
+facet-value = "0.50.0-rc.7"
+facet-yaml = "0.50.0-rc.7"
gingembre = { path = "libs/gingembre", version = "0.0.1" }
gingembre-syntax = { path = "libs/gingembre-syntax", version = "0.0.1" }
diff --git a/DEVELOP.md b/DEVELOP.md
index d894ca843..2541ff863 100644
--- a/DEVELOP.md
+++ b/DEVELOP.md
@@ -29,23 +29,24 @@ Building the browser assets requires:
- `pnpm` — installed automatically via `npm install -g pnpm` when missing
- the `wasm32-unknown-unknown` Rust target (added by `build-browser-assets.sh`)
-## CI Workflow Generation
+## CI Workflow
-The release workflow and installer script are generated from Rust code, not hand-written YAML.
+CI is a hand-written, minimal GitHub Actions workflow: `.github/workflows/ci.yml`
+runs `cargo check` and `cargo clippy` on Blacksmith 2-core Linux runners for
+pushes/pull requests/merge-group on `main`. Full and private pipelines run on
+Buildkite/own infrastructure.
-```sh
-# Regenerate .github/workflows/release.yml and install.sh
-cargo xtask ci
+The installer scripts (`install.sh` / `install.ps1`) are generated from Rust code
+in `xtask/src/installer.rs`, not hand-written:
-# Check if generated files are up to date (used in CI)
-cargo xtask ci --check
+```sh
+# Regenerate the installers
+cargo xtask generate-installer install.sh
+cargo xtask generate-ps1-installer install.ps1
```
-The source of truth is `xtask/src/ci.rs`. Edit that file to change:
-- Build targets
-- Processor crates
-- Workflow steps
-- Installer script
+The source of truth for the installer scripts is `xtask/src/installer.rs`
+(`RELEASE_BASE_URL`). Edit that file to change the installer generation.
## Release Process
diff --git a/README.md.in b/README.md.in
deleted file mode 100644
index 6c7ceb407..000000000
--- a/README.md.in
+++ /dev/null
@@ -1,91 +0,0 @@
-A fully incremental static site generator.
-
-## Philosophy
-
-**Dev mode = Production mode.** Unlike other static site generators that take shortcuts
-in development (skipping minification, using original asset paths, etc.), dodeca serves
-exactly what you'll get in production: cache-busted URLs, minified HTML, subsetted fonts,
-responsive images—the works. Even font subsetting runs in dev!
-
-This is possible because dodeca uses picante for incremental computation. Every
-transformation is a cached query. Change a file and only the affected queries re-run.
-First page load builds what's needed; subsequent requests are instant.
-
-**Custom template engine.** Dodeca includes its own Jinja-like template engine. This gives
-you the power of a real language (conditionals, loops, variable interpolation) without
-the complexity of learning a new syntax. The engine includes rich diagnostics with
-line/column information for template errors.
-
-**Plugin architecture.** Dodeca's plugin system (via the `plugcard` crate) allows extending
-the build pipeline without modifying the core. Image optimization, CSS processing, syntax
-highlighting, and more can be plugged in independently.
-
-## Getting Started
-
-Install dodeca:
-
-The recommended way to install dodeca is the install script, which fetches prebuilt binaries from object storage. Releases ship the `ddc` binary plus a set of helper binaries (`ddc-cell-*`) used for things like image processing, Sass, search indexing, etc.
-
-```bash
-curl --proto '=https' --tlsv1.2 -LsSf https://bearcove-dist.s3.fr-par.scw.cloud/dodeca/install.sh | sh
-```
-
-Supported by the installer:
-- macOS (Apple Silicon / `arm64`)
-- Linux (`x86_64`)
-
-After that, you can create a new site:
-
-```bash
-ddc init my-site
-cd my-site
-ddc serve
-```
-
-This starts a development server at `http://localhost:8080` with live reload.
-
-## Key Features
-
-- **Incremental builds**: Only affected files are re-processed on changes
-- **Cache-busted URLs**: Assets get unique names based on content hash
-- **Image optimization**: Built-in image processing with responsive variants
-- **Font subsetting**: Automatically subset fonts to used characters
-- **HTML minification**: Minify HTML in production builds
-- **Template engine**: Powerful, easy-to-learn Jinja-like templates
-- **Code execution**: Execute code samples and capture output
-- **Link checking**: Verify all links in your site
-- **Extensible**: Plugin system for custom transformations
-
-## Structure
-
-The dodeca workspace includes:
-
-- **dodeca**: Main SSG binary (`ddc` CLI)
-- **gingembre**: Template engine with rich diagnostics
-- **plugcard**: Plugin system for extending the build pipeline
-- **dodeca-\***: Individual plugins for various transformations
-- **livereload-client**: WASM client for live reload in development
-
-## Development
-
-Build everything:
-
-```bash
-cargo xtask build
-```
-
-Run tests:
-
-```bash
-cargo test --workspace
-```
-
-Build the documentation:
-
-```bash
-cargo doc --workspace --no-deps --open
-```
-
-## Contributing
-
-Contributions are welcome! Please open issues and pull requests on GitHub.
diff --git a/RELEASING.md b/RELEASING.md
index 0d108c410..24c925336 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -86,6 +86,7 @@ website endpoint or retire the tap.
- `website.yml` (GitHub Pages docs deploy) is unrelated to releases — it just
installs the published binary via the curl installer and builds the docs site.
-- The installer download source lives in `xtask/src/ci.rs`
+- The installer download source lives in `xtask/src/installer.rs`
(`RELEASE_BASE_URL`); `install.sh` / `install.ps1` are generated from it
- (`cargo xtask ci-github`, `cargo xtask generate-ps1-installer install.ps1`).
+ (`cargo xtask generate-installer install.sh`,
+ `cargo xtask generate-ps1-installer install.ps1`).
diff --git a/crates/dodeca-authoring-lsp/src/authoring_lsp.rs b/crates/dodeca-authoring-lsp/src/authoring_lsp.rs
index 168ace6b9..07d6d986b 100644
--- a/crates/dodeca-authoring-lsp/src/authoring_lsp.rs
+++ b/crates/dodeca-authoring-lsp/src/authoring_lsp.rs
@@ -2494,14 +2494,12 @@ pub fn diagnostic_for_reference(
format!("source file '{source_target}' not found"),
));
};
- match missing_anchor_message(project, route, fragment) {
- Some(message) => (
- AuthoringDiagnosticKind::Anchor,
- Some(route.clone()),
- message,
- ),
- None => return None,
- }
+ let message = missing_anchor_message(project, route, fragment)?;
+ (
+ AuthoringDiagnosticKind::Anchor,
+ Some(route.clone()),
+ message,
+ )
} else if reference.kind == MarkdownReferenceKind::Image
|| is_likely_static_file(target_without_fragment)
{
@@ -2522,10 +2520,9 @@ pub fn diagnostic_for_reference(
Some(target_route.clone()),
format!("route '{target_route}' not found"),
)
- } else if let Some(message) = missing_anchor_message(project, &target_route, fragment) {
- (AuthoringDiagnosticKind::Anchor, Some(target_route), message)
} else {
- return None;
+ let message = missing_anchor_message(project, &target_route, fragment)?;
+ (AuthoringDiagnosticKind::Anchor, Some(target_route), message)
}
};
diff --git a/crates/dodeca-config/README.md.in b/crates/dodeca-config/README.md.in
deleted file mode 100644
index 3469df25d..000000000
--- a/crates/dodeca-config/README.md.in
+++ /dev/null
@@ -1,7 +0,0 @@
-Configuration types for the dodeca static site generator.
-
-This crate provides the shared config structures consumed by the main `dodeca` binary
-and related tooling. It defines the schema and serialization formats used to parse
-project configuration files.
-
-Most users should interact with these types through the `dodeca` CLI.
\ No newline at end of file
diff --git a/crates/dodeca-debug/README.md.in b/crates/dodeca-debug/README.md.in
deleted file mode 100644
index 5fca5f050..000000000
--- a/crates/dodeca-debug/README.md.in
+++ /dev/null
@@ -1,12 +0,0 @@
-## dodeca-debug
-
-Low-level debug utilities used across the dodeca workspace.
-
-This crate hosts small, platform-focused helpers (for example, OS-specific
-introspection or debugging primitives) that don’t belong in higher-level
-crates.
-
-### Status
-
-Internal crate used by the workspace. Not intended for direct consumption.
-
diff --git a/crates/dodeca-devtools/README.md.in b/crates/dodeca-devtools/README.md.in
deleted file mode 100644
index 68d8f407b..000000000
--- a/crates/dodeca-devtools/README.md.in
+++ /dev/null
@@ -1,7 +0,0 @@
-`dodeca-devtools` is the WebAssembly browser runtime for dodeca DevTools.
-
-It handles live DOM patching, CSS reload, route subscriptions, dead-link
-actions, and open-in-editor actions during `ddc serve`. The visible DevTools UI
-is the TypeScript bundle under `crates/dodeca/devtools-ui`.
-
-This crate is part of the Dodeca workspace.
diff --git a/crates/dodeca-protocol/README.md.in b/crates/dodeca-protocol/README.md.in
deleted file mode 100644
index ff41eb873..000000000
--- a/crates/dodeca-protocol/README.md.in
+++ /dev/null
@@ -1,17 +0,0 @@
-## dodeca-protocol
-
-Shared protocol types for dodeca devtools. This crate contains the data structures
-and serialization formats used by the devtools runtime and the live reload client.
-
-### What this crate is for
-
-- Defining stable protocol types shared across dodeca components
-- Encoding and decoding messages for devtools communication
-- Keeping compatibility boundaries explicit and versioned
-
-### When to use it
-
-Use `dodeca-protocol` when you need to serialize or interpret messages exchanged
-between dodeca devtools components (e.g. host <-> client).
-
-This crate is internal to the dodeca workspace and is not intended for standalone use.
\ No newline at end of file
diff --git a/crates/dodeca-sandbox/README.md.in b/crates/dodeca-sandbox/README.md.in
deleted file mode 100644
index 233b996de..000000000
--- a/crates/dodeca-sandbox/README.md.in
+++ /dev/null
@@ -1,15 +0,0 @@
-Cross-platform process sandboxing for dodeca.
-
-This crate provides the sandboxing layer used by dodeca to run untrusted or isolated processes
-with platform-specific backends.
-
-## Features
-
-- Cross-platform API with OS-specific implementations.
-- Linux support via `hakoniwa`.
-- Focused, minimal surface area for secure process execution.
-
-## Status
-
-This crate is internal to the dodeca workspace and is not published.
-
diff --git a/crates/dodeca/README.md.in b/crates/dodeca/README.md.in
deleted file mode 100644
index 67bccc9c0..000000000
--- a/crates/dodeca/README.md.in
+++ /dev/null
@@ -1,29 +0,0 @@
-Dodeca is a fully incremental static site generator.
-
-## Overview
-
-This crate provides the `ddc` CLI and the core runtime that powers Dodeca’s build
-pipeline, including cells, hot-reload, and devtools integration.
-
-## Features
-
-- Incremental builds with fine‑grained caching
-- Cell-based pipeline for content processing
-- Live reload and devtools support
-- Cross-platform and workspace-friendly
-
-## Usage
-
-Install from the workspace:
-
-- `cargo install --path crates/dodeca`
-
-Run on a site directory:
-
-- `ddc serve /path/to/site`
-- `ddc build /path/to/site`
-
-## Workspace
-
-This crate is part of the `dodeca` workspace. Most users should interact with
-the `ddc` CLI rather than depending on this crate directly.
\ No newline at end of file
diff --git a/crates/dodeca/src/config.rs b/crates/dodeca/src/config.rs
index 1ca556150..6c01ffd72 100644
--- a/crates/dodeca/src/config.rs
+++ b/crates/dodeca/src/config.rs
@@ -709,10 +709,7 @@ fn discover_source_config(
});
return source.map(|s| (current.to_owned(), s));
}
- match current.parent() {
- Some(parent) => current = parent,
- None => return None,
- }
+ current = current.parent()?;
}
}
diff --git a/crates/dodeca/src/error_pages.rs b/crates/dodeca/src/error_pages.rs
index d93915657..0f06bb334 100644
--- a/crates/dodeca/src/error_pages.rs
+++ b/crates/dodeca/src/error_pages.rs
@@ -428,7 +428,7 @@ fn format_source_context(
if loc.filename.starts_with('/') {
// Absolute path - make it a zed:// link
// Note: zed://file/ expects path without leading slash
- let zed_url = format!("zed://file{}:{}:{}", &loc.filename, error_line, error_col);
+ let zed_url = format!("zed://file{}:{}:{}", loc.filename, error_line, error_col);
html.push_str(&format!(
r#"{}"#,
html_escape::encode_text(&zed_url),
diff --git a/crates/dodeca/src/theme_resolver.rs b/crates/dodeca/src/theme_resolver.rs
index 8f5f7083f..05b1ad5a9 100644
--- a/crates/dodeca/src/theme_resolver.rs
+++ b/crates/dodeca/src/theme_resolver.rs
@@ -184,9 +184,9 @@ mod tests {
// Print sample to verify format (only in --nocapture mode)
println!("\n=== Light theme CSS sample (first 200 chars) ===");
- println!("{}", &light_css.chars().take(200).collect::());
+ println!("{}", light_css.chars().take(200).collect::());
println!("\n=== Dark theme CSS sample (first 200 chars) ===");
- println!("{}", &dark_css.chars().take(200).collect::());
+ println!("{}", dark_css.chars().take(200).collect::());
}
#[test]
diff --git a/crates/integration-tests/README.md.in b/crates/integration-tests/README.md.in
deleted file mode 100644
index 50520e980..000000000
--- a/crates/integration-tests/README.md.in
+++ /dev/null
@@ -1,15 +0,0 @@
-## Integration tests
-
-This crate contains the end-to-end and integration test harness for the dodeca workspace.
-It’s a binary crate used during development and CI to validate the full system.
-
-### What it includes
-
-- CLI-driven integration tests
-- Fixture setup and teardown
-- Network and process orchestration helpers
-
-### When to use it
-
-Run this crate when you want to verify cross-crate behavior or ensure the full stack works
-as expected before publishing or deploying.
diff --git a/crates/livereload-client/README.md.in b/crates/livereload-client/README.md.in
deleted file mode 100644
index 460ab7cf0..000000000
--- a/crates/livereload-client/README.md.in
+++ /dev/null
@@ -1,14 +0,0 @@
-# livereload-client
-
-WASM client for dodeca live reload. It connects to the devtools server, receives DOM patch messages, and applies them in the browser to update pages without a full reload.
-
-## What it does
-
-- Opens a websocket connection to dodeca devtools
-- Receives patch messages encoded with `dodeca-protocol`
-- Applies DOM patches using `hotmeal-wasm`
-
-## Usage
-
-This crate is built and bundled by the workspace tooling; you typically don’t depend on it directly.
-
diff --git a/hooks/pre-commit b/hooks/pre-commit
index 89eaa9ac9..cd6b77550 100755
--- a/hooks/pre-commit
+++ b/hooks/pre-commit
@@ -2,9 +2,3 @@
set -euo pipefail
captain
-
-# Regenerate CI workflow files and stage them.
-# This ensures ci.yml always reflects the current set of cells/crates.
-cargo xtask ci-github
-cargo xtask ci-forgejo
-git add .github/workflows/ci.yml .forgejo/workflows/ci.yml install.sh
diff --git a/libs/gingembre-syntax/src/ast.rs b/libs/gingembre-syntax/src/ast.rs
index 31599298d..441b34bc7 100644
--- a/libs/gingembre-syntax/src/ast.rs
+++ b/libs/gingembre-syntax/src/ast.rs
@@ -410,8 +410,10 @@ impl DictLit {
.filter_map(|c| Expr::cast(c.clone()))
.collect();
exprs
- .chunks_exact(2)
- .map(|c| (c[0].clone(), c[1].clone()))
+ .as_chunks::<2>()
+ .0
+ .iter()
+ .map(|[key, value]| (key.clone(), value.clone()))
.collect()
}
}
diff --git a/libs/gingembre/README.md.in b/libs/gingembre/README.md.in
deleted file mode 100644
index 4305e6a70..000000000
--- a/libs/gingembre/README.md.in
+++ /dev/null
@@ -1,6 +0,0 @@
-`gingembre` is a Jinja-like template engine with rich error diagnostics.
-
-It supports template inheritance, macros, filters, and lazy data resolution,
-and is used by dodeca for all HTML templating.
-
-This crate is part of the Dodeca workspace.
diff --git a/libs/hotmeal/Cargo.toml b/libs/hotmeal/Cargo.toml
index 27955bbd0..9b1667eb7 100644
--- a/libs/hotmeal/Cargo.toml
+++ b/libs/hotmeal/Cargo.toml
@@ -13,10 +13,10 @@ homepage = "https://github.com/bearcove/hotmeal"
[workspace.dependencies]
# Facet dependencies
-facet = "0.50.0-rc.5"
-facet-error = "0.50.0-rc.5"
-facet-json = "0.50.0-rc.5"
-facet-testhelpers = "0.50.0-rc.5"
+facet = "0.50.0-rc.7"
+facet-error = "0.50.0-rc.7"
+facet-json = "0.50.0-rc.7"
+facet-testhelpers = "0.50.0-rc.7"
# Local crates
cinereus = { path = "cinereus", version = "3.0.0-rc.0" }
@@ -24,7 +24,7 @@ hotmeal = { path = "hotmeal", version = "3.0.0-rc.0" }
hotmeal-server = { path = "hotmeal-server", version = "3.0.0-rc.0" }
# Serialization
-facet-postcard = "0.50.0-rc.5"
+facet-postcard = "0.50.0-rc.7"
# RPC
vox = { version = "0.10.0-rc.5", default-features = false, features = ["runtime"] }
diff --git a/libs/hotmeal/README.md.in b/libs/hotmeal/README.md.in
deleted file mode 100644
index 278f320bc..000000000
--- a/libs/hotmeal/README.md.in
+++ /dev/null
@@ -1,5 +0,0 @@
-hotmeal is an HTML toolkit based on facet, html5ever, and cinereus (for diff-patching).
-
-It allows patching HTML documents into a DOM the way browsers would do, manipulating the DOM,
-re-serializing the DOM, but also generating patches you can apply in an actual browser, for
-live-reloading.
diff --git a/libs/hotmeal/cinereus/README.md.in b/libs/hotmeal/cinereus/README.md.in
deleted file mode 100644
index d5b763eae..000000000
--- a/libs/hotmeal/cinereus/README.md.in
+++ /dev/null
@@ -1,9 +0,0 @@
-GumTree-style tree diffing with Chawathe edit script generation.
-
-This crate provides a generic tree diffing algorithm based on the GumTree approach:
-
-1. **Top-down matching**: Finds identical subtrees by hash
-2. **Bottom-up matching**: Matches remaining nodes by structural similarity
-3. **Chawathe edit script**: Generates minimal INSERT, DELETE, UPDATE, and MOVE operations
-
-Used by [hotmeal](https://github.com/bearcove/hotmeal) for HTML diffing.
diff --git a/libs/hotmeal/hotmeal-wasm/README.md.in b/libs/hotmeal/hotmeal-wasm/README.md.in
deleted file mode 100644
index 68fdc889a..000000000
--- a/libs/hotmeal/hotmeal-wasm/README.md.in
+++ /dev/null
@@ -1,26 +0,0 @@
-# hotmeal-wasm
-
-WebAssembly bindings for hotmeal HTML toolkit.
-
-Provides browser-side HTML parsing, DOM diffing, and patch application for use in JavaScript/TypeScript applications.
-
-## Features
-
-- Parse HTML strings into DOM trees
-- Compute minimal patches between two HTML documents
-- Apply patches to update the DOM efficiently
-- Works with any JavaScript framework or vanilla JS
-
-## Usage
-
-```javascript
-import init, { parse_html, diff_html, apply_patches } from 'hotmeal-wasm';
-
-await init();
-
-const old_html = '
Hello
';
-const new_html = '
World
';
-
-const patches = diff_html(old_html, new_html);
-// Apply patches to your DOM...
-```
diff --git a/libs/hotmeal/hotmeal/README.md.in b/libs/hotmeal/hotmeal/README.md.in
deleted file mode 100644
index 218a891b5..000000000
--- a/libs/hotmeal/hotmeal/README.md.in
+++ /dev/null
@@ -1,27 +0,0 @@
-# hotmeal
-
-HTML toolkit with arena-based DOM, html5ever parsing, tree diffing, and serialization.
-
-## Features
-
-- **HTML5 Parsing**: Full HTML5 tree construction via html5ever with error recovery
-- **Arena-based DOM**: Efficient arena-allocated tree with zero-copy parsing
-- **Tree Diffing**: GumTree/Chawathe algorithm via cinereus for efficient DOM patches
-- **Serialization**: HTML output with proper escaping and formatting
-
-## Usage
-
-```rust
-use hotmeal::{parse_body, diff::{diff, apply_patches}};
-
-// Parse HTML
-let old = parse_body("
Hello
");
-let new = parse_body("
World
");
-
-// Compute patches
-let patches = hotmeal::diff::diff(&old, &new).expect("diffing should succeed");
-
-// Apply patches to transform old into new
-let mut old_diff: hotmeal::diff::Element = (&old).into();
-hotmeal::diff::apply_patches(&mut old_diff, &patches).expect("patches should apply");
-```
diff --git a/libs/hotmeal/hotmeal/fuzz/browser-proto/Cargo.toml b/libs/hotmeal/hotmeal/fuzz/browser-proto/Cargo.toml
index 2981fdaef..2f514d179 100644
--- a/libs/hotmeal/hotmeal/fuzz/browser-proto/Cargo.toml
+++ b/libs/hotmeal/hotmeal/fuzz/browser-proto/Cargo.toml
@@ -6,6 +6,6 @@ edition = "2024"
[dependencies]
vox = { version = "0.10.0-rc.5", default-features = false, features = ["runtime"] }
-facet = "0.50.0-rc.5"
-facet-postcard = "0.50.0-rc.5"
+facet = "0.50.0-rc.7"
+facet-postcard = "0.50.0-rc.7"
hotmeal = { path = "../.." }
diff --git a/libs/marq/README.md.in b/libs/marq/README.md.in
deleted file mode 100644
index fc8848681..000000000
--- a/libs/marq/README.md.in
+++ /dev/null
@@ -1,14 +0,0 @@
-# marq
-
-Markdown processing (based on pulldown-cmark), recognizes
-[tracey](https://github.com/bearcove/tracey) rules, uses
-[arborium](https://github.com/bearcove/arborium) for syntax highlighting,
-[aasvg-rs](https://github.com/bearcove/aasvg-rs) and
-[pikru](https://github.com/bearcove/pikru) for diagrams.
-
-Supports wiki-style links (`[[Target]]`, `[[Target|label]]`) through a
-`WikiLinkResolver`, so applications can resolve them against their own page
-index while marq handles the Markdown syntax.
-
-Used by [dodeca](https://github.com/bearcove/dodeca) and
-[tracey](https://github.com/bearcove/tracey)
diff --git a/libs/marq/src/render.rs b/libs/marq/src/render.rs
index 8702309cf..3280001d8 100644
--- a/libs/marq/src/render.rs
+++ b/libs/marq/src/render.rs
@@ -786,7 +786,7 @@ fn parse_emphasis_shortcode(input: &str) -> (String, Vec<(String, String)>) {
let args = rest.strip_suffix(')').unwrap_or(rest);
let mut pairs = Vec::new();
- let mut chars = args.char_indices().peekable();
+ let chars = args.char_indices().peekable();
// Split into `key = value` items, honoring quotes so a quoted value can hold commas.
let mut item = String::new();
let mut in_quotes = false;
@@ -806,7 +806,7 @@ fn parse_emphasis_shortcode(input: &str) -> (String, Vec<(String, String)>) {
pairs.push((item.to_string(), String::new()));
}
};
- while let Some((_, c)) = chars.next() {
+ for (_, c) in chars {
match c {
'"' => {
in_quotes = !in_quotes;
@@ -831,9 +831,11 @@ fn parse_emphasis_shortcode(input: &str) -> (String, Vec<(String, String)>) {
/// (with the leading `:` removed) and the remaining blockquote events as a body to be
/// rendered — the marker paragraph itself is dropped. `events` is the full blockquote
/// run, `[Start(BlockQuote), … , End(BlockQuote)]`.
-fn extract_body_shortcode<'a>(
- events: &[(Event<'a>, Range)],
-) -> Option<(String, Vec<(Event<'a>, Range)>)> {
+/// A body shortcode match: the marker text (leading `:` removed) and the
+/// remaining blockquote events as a body to be rendered.
+type BodyShortcode<'a> = (String, Vec<(Event<'a>, Range)>);
+
+fn extract_body_shortcode<'a>(events: &[(Event<'a>, Range)]) -> Option> {
// events[0] is Start(BlockQuote); the first paragraph must open with an emphasis.
if !matches!(events.first(), Some((Event::Start(Tag::BlockQuote(_)), _))) {
return None;
diff --git a/libs/pikru/Cargo.toml b/libs/pikru/Cargo.toml
index a70adf947..f10bac568 100644
--- a/libs/pikru/Cargo.toml
+++ b/libs/pikru/Cargo.toml
@@ -36,7 +36,7 @@ ariadne = "0.6"
pest = "2.8.4"
pest_derive = "2.8.4"
# SVG DOM generation and XML serialization
-facet-svg = { version = "0.50.0-rc.5" }
+facet-svg = { version = "0.50.0-rc.7" }
# Debug logging (only emits when RUST_LOG is set) - optional
tracing = { version = "0.1.43", optional = true }
# Derive macro for custom error types
diff --git a/libs/pikru/README.md.in b/libs/pikru/README.md.in
deleted file mode 100644
index eca19b722..000000000
--- a/libs/pikru/README.md.in
+++ /dev/null
@@ -1,58 +0,0 @@
-A Rust implementation of [pikchr](https://pikchr.org/), a PIC-like diagram
-markup language for creating technical diagrams that generates SVG.
-
-## Usage
-
-```rust
-let svg = pikru::pikchr(r#"box "Hello" arrow box "World""#).unwrap();
-assert!(svg.contains("