Skip to content

feat(web): add global footer and button-style nav #77

feat(web): add global footer and button-style nav

feat(web): add global footer and button-style nav #77

Workflow file for this run

# .github/workflows/guardian.yml
#
# Sidecoin Monorepo CI Suite
# Runs on every push/PR to master across all packages.
#
# IMPORTANT: All cargo commands use --locked to ensure deterministic
# builds from the committed Cargo.lock. Without --locked, Cargo may
# resolve newer transitive dependencies (e.g. tauri-runtime) that
# introduce breaking trait changes and fail compilation.
name: Sidecoin CI Suite
on:
push:
branches: ["master"]
pull_request:
branches: ["master"]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Force any remaining JavaScript actions onto the Node.js 24 runtime.
# After replacing pnpm/action-setup (corepack) and wrangler-action
# (npx wrangler) below, the only Node-20 action left is the transitive
# actions/github-script pulled in by codecov-action — which we cannot
# version-pin directly. This flag keeps it running on Node 24 so it does
# not break after the Sept 16 2026 Node-20 removal. Drop once codecov
# ships a Node 24 release.
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
guardian:
name: desktop-client (${{ matrix.platform }})
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
env:
WEBVIEW2_LINK_STATIC: "1"
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt, llvm-tools-preview
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
key: ${{ runner.os }}-v2
workspaces: "./packages/desktop/src-tauri -> target"
- name: Install Linux dependencies
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libappindicator3-dev \
librsvg2-dev \
patchelf \
xvfb \
webkit2gtk-driver
cargo install tauri-driver
- name: Install Frontend dependencies
run: pnpm install --frozen-lockfile
# ── Shared ──────────────────────────────────────────────
- name: Type-check Shared
run: pnpm --filter @sidecoin/shared build
# ── Desktop — Placeholder Dist ──────────────────────────
#
# Tauri's generate_context!() proc macro validates that
# frontendDist ("../dist") exists at compile time. This
# placeholder must exist BEFORE any cargo command that
# compiles the Tauri app (clippy, build, llvm-cov, etc.).
# It is replaced by the real frontend build later.
# ────────────────────────────────────────────────────────
- name: Create Placeholder Dist
shell: bash
run: mkdir -p packages/desktop/dist && touch packages/desktop/dist/index.html
# ── Desktop — Rust Quality Gates ────────────────────────
- name: Check Rust Formatting
working-directory: packages/desktop/src-tauri
run: cargo fmt --all -- --check
- name: Clippy Lint
working-directory: packages/desktop/src-tauri
run: cargo clippy --locked --all-features --lib -- -D warnings
# ── Desktop — Build ─────────────────────────────────────
- name: Generate Types (Specta)
shell: bash
working-directory: packages/desktop/src-tauri
run: |
cargo run --locked --bin export_types
node -e "
const fs = require('fs');
const path = require('path');
const f = path.join('..', 'src', 'bindings.ts');
if (fs.existsSync(f)) {
const content = fs.readFileSync(f, 'utf8');
if (!content.startsWith('//@ts-nocheck')) {
fs.writeFileSync(f, '//@ts-nocheck\n' + content);
}
}
"
- name: Build Desktop Frontend
run: pnpm --filter @sidecoin/desktop exec vite build
- name: Build Tauri App
working-directory: packages/desktop/src-tauri
run: cargo build --locked
# ── Desktop — Tests ─────────────────────────────────────
- name: Run Rust Unit Tests (with coverage)
if: matrix.platform != 'windows-latest'
working-directory: packages/desktop/src-tauri
shell: bash
run: cargo llvm-cov --locked --all-features --lib --lcov --output-path lcov-rust.info
- name: Run Desktop Frontend Tests
run: pnpm --filter @sidecoin/desktop test
- name: Run Desktop Type Check
run: pnpm --filter @sidecoin/desktop exec vue-tsc --noEmit --skipLibCheck
# ── Desktop — E2E ───────────────────────────────────────
- name: Run E2E Tests
if: matrix.platform == 'ubuntu-latest'
continue-on-error: true
env:
CI: true
GDK_BACKEND: x11
WEBKIT_DISABLE_COMPOSITING_MODE: "1"
shell: bash
run: xvfb-run --auto-servernum pnpm --filter @sidecoin/desktop test:e2e
# ── Coverage Upload ─────────────────────────────────────
- name: Verify coverage file exists
if: matrix.platform == 'ubuntu-latest'
working-directory: packages/desktop/src-tauri
shell: bash
run: |
if [ -f lcov-rust.info ]; then
echo "✅ Coverage file found ($(wc -l < lcov-rust.info) lines)"
head -5 lcov-rust.info
else
echo "❌ Coverage file NOT found"
ls -la
exit 1
fi
- name: Upload Rust Coverage
if: matrix.platform == 'ubuntu-latest'
uses: codecov/codecov-action@v5
with:
files: packages/desktop/src-tauri/lcov-rust.info
flags: rust
fail_ci_if_error: false
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload Desktop Frontend Coverage
if: matrix.platform == 'ubuntu-latest'
uses: codecov/codecov-action@v5
with:
files: packages/desktop/coverage/lcov.info
flags: desktop-frontend
fail_ci_if_error: false
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
# ── Wallet (standalone, labeled job) ─────────────────────
#
# Pure TS/Vite — runs once on ubuntu (no Rust/matrix needed).
# Appears as its own "wallet" entry in the Actions sidebar so
# a failure here is immediately distinguishable from the
# desktop/web/mobile/api legs. Builds @sidecoin/shared first
# (wallet depends on it). deploy-wallet gates on this job.
#
# Test runs with --coverage.reporter=lcov so the v8 provider
# emits coverage/lcov.info for the Codecov upload below. lcov
# is NOT a default vitest reporter, so it must be requested
# explicitly on the CLI (keeps local `pnpm test` coverage-free).
# The `--` separator forwards the flags to vitest rather than
# letting pnpm try to parse them as its own options.
# ─────────────────────────────────────────────────────────
wallet:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Build Wallet
run: pnpm --filter @sidecoin/wallet build
- name: Test Wallet
run: pnpm --filter @sidecoin/wallet test -- --coverage --coverage.reporter=lcov
- name: Type-check Wallet
run: pnpm --filter @sidecoin/wallet type-check
- name: Upload Wallet Coverage
uses: codecov/codecov-action@v5
with:
files: packages/wallet/coverage/lcov.info
flags: wallet
fail_ci_if_error: false
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
# ── Mobile (standalone, labeled job) ─────────────────────
#
# React Native / Jest — runs once on ubuntu (no Rust/matrix
# needed). Appears as its own "mobile" entry in the Actions
# sidebar so a failure here is immediately distinguishable
# from the desktop/web/api legs.
#
# Builds @sidecoin/shared first: the App test imports
# @sidecoin/shared/chain and @sidecoin/shared/sidechains.
# ─────────────────────────────────────────────────────────
mobile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Test Mobile
run: pnpm --filter @sidecoin/mobile test
# ── Web — Landing Site (standalone, labeled job) ─────────
#
# Pure TS/Vite — runs once on ubuntu. Appears as its own
# "web" entry in the Actions sidebar. Builds @sidecoin/shared
# first (web depends on it), then builds + tests the site.
# deploy-web gates on this job.
# ─────────────────────────────────────────────────────────
web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Build Web
run: pnpm --filter @sidecoin/web build
- name: Test Web
run: pnpm --filter @sidecoin/web test
# ── API adapter + client (standalone, labeled job) ───────
#
# Pure TS — runs once on ubuntu (no Rust/matrix needed).
# Appears as its own "api" entry in the Actions sidebar so
# a failure here is immediately distinguishable from the
# desktop/web/wallet legs. Each named step (Test/Type-check)
# pinpoints exactly which check broke.
# ─────────────────────────────────────────────────────────
api:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Test API client
run: pnpm --filter @sidecoin/api-client test
- name: Type-check API client
run: pnpm --filter @sidecoin/api-client typecheck
- name: Test API adapter
run: pnpm --filter @sidecoin/api test
- name: Type-check API adapter
run: pnpm --filter @sidecoin/api typecheck
# ── Cloudflare Pages — Landing Site ──────────────────────
#
# Deploys on every push to master after all CI jobs pass.
# PRs do NOT deploy — only merged commits to master.
# ─────────────────────────────────────────────────────────
deploy-web:
needs: web
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Build Web
run: pnpm --filter @sidecoin/web build
- name: Deploy to Cloudflare Pages
run: npx wrangler pages deploy packages/web/dist --project-name=sidecoin --commit-dirty=true
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
# ── Cloudflare Pages — Wallet App ────────────────────────
deploy-wallet:
needs: wallet
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Build Wallet
run: pnpm --filter @sidecoin/wallet build
- name: Deploy to Cloudflare Pages
run: npx wrangler pages deploy packages/wallet/dist --project-name=sidecoin-wallet --commit-dirty=true
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
# ── Cloudflare Workers — API Adapter (GATED) ─────────────
#
# Worker deploy (wrangler deploy), NOT Pages. Gated behind a
# GitHub Environment ("production-api") with required reviewers:
# this job pauses for manual approval before the adapter ships.
# Deploys only on push to master, after the api job passes.
# ─────────────────────────────────────────────────────────
deploy-api:
needs: api
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
environment:
name: production-api
url: https://sidecoin.app
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Deploy Worker
run: npx wrangler deploy
working-directory: packages/api
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}