name: Project CI on: push: branches: - master pull_request: workflow_dispatch: permissions: contents: read env: CI: 'true' CARGO_INCREMENTAL: '0' CARGO_HTTP_MULTIPLEXING: 'false' CARGO_NET_RETRY: '10' CARGO_TERM_COLOR: always NPM_CONFIG_AUDIT: 'false' NPM_CONFIG_FETCH_RETRIES: '10' NPM_CONFIG_FETCH_RETRY_FACTOR: '2' NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT: '60000' NPM_CONFIG_FETCH_RETRY_MINTIMEOUT: '2000' NPM_CONFIG_FUND: 'false' NPM_CONFIG_PREFER_OFFLINE: 'true' RUSTUP_AUTO_INSTALL: '0' RUSTC_WRAPPER: '' CARGO_BUILD_RUSTC_WRAPPER: '' jobs: repository-checks: name: Repository checks runs-on: genarrative-ci steps: - name: Checkout full history from Gitea env: GENARRATIVE_GITEA_FETCH_DEPTH: '0' GENARRATIVE_GITEA_TOKEN: ${{ github.token }} run: genarrative-gitea-checkout - name: Validate preinstalled CI job image and sandbox run: GENARRATIVE_GITEA_CI_CHECK_RUNTIME=1 bash scripts/check-gitea-ci-job-image.sh - name: Resolve comparison base shell: bash run: | set -euo pipefail base_ref="$(node -e ' const fs = require("node:fs"); const event = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH, "utf8")); process.stdout.write(event.pull_request?.base?.sha ?? event.before ?? ""); ')" if [[ -n "${base_ref}" && ! "${base_ref}" =~ ^0+$ ]]; then git cat-file -e "${base_ref}^{commit}" 2>/dev/null || { echo "comparison base commit is unavailable: ${base_ref}" >&2 exit 1 } else base_ref="$(git merge-base HEAD origin/master 2>/dev/null || git rev-parse HEAD)" fi resolved_base_ref="$(git rev-parse --verify "${base_ref}^{commit}" 2>/dev/null || true)" head_ref="$(git rev-parse HEAD)" if [[ "${resolved_base_ref}" == "${head_ref}" ]]; then resolved_base_ref="$(git rev-parse --verify HEAD^ 2>/dev/null || true)" fi if [[ -z "${resolved_base_ref}" ]]; then echo 'comparison base must resolve to a commit distinct from HEAD.' >&2 exit 1 fi base_ref="${resolved_base_ref}" if [[ "${GITHUB_EVENT_NAME:-}" == 'pull_request' ]] \ && ! git merge-base --is-ancestor "${base_ref}" HEAD; then echo 'pull request head does not contain the latest base commit; update the branch and rerun CI.' >&2 exit 1 fi echo "SPACETIME_SCHEMA_BASE_REF=${base_ref}" >> "${GITHUB_ENV}" - name: Install npm dependencies run: bash scripts/ci-npm-ci-with-retry.sh - name: Run repository checks run: npm run check:repository-ci frontend-tests: name: Frontend tests runs-on: genarrative-ci steps: - name: Checkout source from Gitea env: GENARRATIVE_GITEA_FETCH_DEPTH: '1' GENARRATIVE_GITEA_TOKEN: ${{ github.token }} run: genarrative-gitea-checkout - name: Validate preinstalled CI job image and sandbox run: GENARRATIVE_GITEA_CI_CHECK_RUNTIME=1 bash scripts/check-gitea-ci-job-image.sh - name: Install npm dependencies run: bash scripts/ci-npm-ci-with-retry.sh - name: Run frontend and script tests run: npm run test - name: Run BgFilter worker smoke harness tests run: npm run bgfilter-worker:smoke-test - name: Validate production health patrol behavior run: npm run check:production-health-patrol - name: Validate production API release behavior run: npm run check:production-api-release - name: Validate production API deploy behavior run: npm run check:production-api-deploy backend-tests: name: Backend tests runs-on: genarrative-ci steps: - name: Checkout full history from Gitea env: GENARRATIVE_GITEA_FETCH_DEPTH: '0' GENARRATIVE_GITEA_TOKEN: ${{ github.token }} run: genarrative-gitea-checkout - name: Validate preinstalled CI job image and sandbox run: GENARRATIVE_GITEA_CI_CHECK_RUNTIME=1 bash scripts/check-gitea-ci-job-image.sh - name: Resolve comparison base shell: bash run: | set -euo pipefail base_ref="$(node -e ' const fs = require("node:fs"); const event = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH, "utf8")); process.stdout.write(event.pull_request?.base?.sha ?? event.before ?? ""); ')" if [[ -n "${base_ref}" && ! "${base_ref}" =~ ^0+$ ]]; then git cat-file -e "${base_ref}^{commit}" 2>/dev/null || { echo "comparison base commit is unavailable: ${base_ref}" >&2 exit 1 } else base_ref="$(git merge-base HEAD origin/master 2>/dev/null || git rev-parse HEAD)" fi resolved_base_ref="$(git rev-parse --verify "${base_ref}^{commit}" 2>/dev/null || true)" head_ref="$(git rev-parse HEAD)" if [[ "${resolved_base_ref}" == "${head_ref}" ]]; then resolved_base_ref="$(git rev-parse --verify HEAD^ 2>/dev/null || true)" fi if [[ -z "${resolved_base_ref}" ]]; then echo 'comparison base must resolve to a commit distinct from HEAD.' >&2 exit 1 fi base_ref="${resolved_base_ref}" if [[ "${GITHUB_EVENT_NAME:-}" == 'pull_request' ]] \ && ! git merge-base --is-ancestor "${base_ref}" HEAD; then echo 'pull request head does not contain the latest base commit; update the branch and rerun CI.' >&2 exit 1 fi echo "SPACETIME_SCHEMA_BASE_REF=${base_ref}" >> "${GITHUB_ENV}" - name: Install npm dependencies run: bash scripts/ci-npm-ci-with-retry.sh - name: Prepare server-rs Rust dependencies shell: bash run: | set -euo pipefail for attempt in $(seq 1 5); do if cargo fetch --locked \ --target x86_64-unknown-linux-gnu \ --manifest-path server-rs/Cargo.toml; then break fi if [[ "${attempt}" -eq 5 ]]; then echo 'server-rs Cargo dependency fetch failed after 5 attempts.' >&2 exit 1 fi sleep $((attempt * 2)) done - name: Check server-rs boundaries run: npm run check:server-rs-ddd - name: Run server-rs workspace tests run: cargo test --locked --workspace --exclude spacetime-module --no-fail-fast --manifest-path server-rs/Cargo.toml - name: Run SpacetimeDB module unit tests run: cargo test --locked -p spacetime-module --no-fail-fast --manifest-path server-rs/Cargo.toml - name: Check api-server targets run: cargo check --locked -p api-server --all-targets --manifest-path server-rs/Cargo.toml - name: Check SpacetimeDB module run: cargo check --locked -p spacetime-module --manifest-path server-rs/Cargo.toml native-shell-tests: name: Native shell tests runs-on: genarrative-ci steps: - name: Checkout full history from Gitea env: GENARRATIVE_GITEA_FETCH_DEPTH: '0' GENARRATIVE_GITEA_TOKEN: ${{ github.token }} run: genarrative-gitea-checkout - name: Validate preinstalled CI job image and sandbox run: GENARRATIVE_GITEA_CI_CHECK_RUNTIME=1 bash scripts/check-gitea-ci-job-image.sh - name: Install npm dependencies run: bash scripts/ci-npm-ci-with-retry.sh - name: Prepare native Rust dependencies shell: bash run: | set -euo pipefail for manifest_path in \ server-rs/Cargo.toml \ apps/desktop-shell/src-tauri/Cargo.toml \ apps/ai-game-creator-shell/src-tauri/Cargo.toml; do for attempt in $(seq 1 5); do if cargo fetch --locked \ --target x86_64-unknown-linux-gnu \ --manifest-path "${manifest_path}"; then break fi if [[ "${attempt}" -eq 5 ]]; then echo "Cargo dependency fetch failed after 5 attempts: ${manifest_path}" >&2 exit 1 fi sleep $((attempt * 2)) done done - name: Run native shell gates run: npm run check:native-shells - name: Ensure native lockfiles are unchanged run: git diff --exit-code -- apps/desktop-shell/src-tauri/Cargo.lock apps/ai-game-creator-shell/src-tauri/Cargo.lock