Skip to content

Commit a001791

Browse files
ci: establish development tooling and CI baseline (issue #17)
1 parent 16c2a5e commit a001791

File tree

6 files changed

+91
-3
lines changed

6 files changed

+91
-3
lines changed

.github/workflows/ci.yml

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
- main
88

99
jobs:
10-
test:
10+
web-quality:
1111
runs-on: ubuntu-latest
1212
steps:
1313
- name: Checkout
@@ -27,5 +27,42 @@ jobs:
2727
- name: Install dependencies
2828
run: pnpm install --frozen-lockfile
2929

30-
- name: Run unit tests
31-
run: pnpm test
30+
- name: Run lint + test + build (web)
31+
run: pnpm run ci:web
32+
33+
rust-quality:
34+
runs-on: ubuntu-latest
35+
steps:
36+
- name: Checkout
37+
uses: actions/checkout@v4
38+
39+
- name: Setup pnpm
40+
uses: pnpm/action-setup@v4
41+
with:
42+
version: 10.30.3
43+
44+
- name: Setup Node.js
45+
uses: actions/setup-node@v4
46+
with:
47+
node-version: 24
48+
cache: pnpm
49+
50+
- name: Install dependencies
51+
run: pnpm install --frozen-lockfile
52+
53+
- name: Setup Rust toolchain
54+
uses: dtolnay/rust-toolchain@stable
55+
with:
56+
components: rustfmt, clippy
57+
58+
- name: Install Linux dependencies for Tauri
59+
run: |
60+
sudo apt-get update
61+
sudo apt-get install -y \
62+
libwebkit2gtk-4.1-dev \
63+
libappindicator3-dev \
64+
librsvg2-dev \
65+
patchelf
66+
67+
- name: Run fmt + lint + test (rust)
68+
run: pnpm run ci:rust

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@ Tauri 2 + React/TypeScript desktop foundation for managing MCP and Skills across
1717
- Desktop production build: `pnpm tauri:build`
1818
- TypeScript lint + typecheck: `pnpm run lint:ts`
1919
- Rust lint: `pnpm run lint:rust`
20+
- Rust format check: `pnpm run fmt:rust`
21+
- Rust unit tests: `pnpm run test:rust`
2022
- Full lint checks: `pnpm run lint`
2123
- Pre-commit verification (lint + unit tests): `pnpm check`
2224
- Unit tests: `pnpm test`
25+
- CI-equivalent web gate: `pnpm run ci:web`
26+
- CI-equivalent rust gate: `pnpm run ci:rust`
27+
- Full CI-equivalent gate: `pnpm run ci`
2328

2429
## Project Structure
2530

@@ -40,5 +45,6 @@ Tauri 2 + React/TypeScript desktop foundation for managing MCP and Skills across
4045
- The frontend command runner calls typed placeholder backend commands: `detect_clients`, `list_resources`, and `mutate_resource`.
4146
- Command responses use a shared envelope (`ok`, `data`, `error`, `meta`) with lifecycle and operation metadata.
4247
- Backend commands are thin boundaries and delegate to `AdapterService` through `AdapterRegistry`.
48+
- CI runs separate `web-quality` and `rust-quality` jobs on pull requests and pushes to `main`.
4349
- `src-tauri/tauri.conf.json` is configured to use `pnpm` for both dev and build hooks.
4450
- `scripts/ensure-tauri-icon.mjs` generates the required Tauri icon in clean environments.

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@
1212
"pretauri:dev": "pnpm run ensure:tauri-icon && pnpm dev",
1313
"pretauri:build": "pnpm run ensure:tauri-icon && pnpm build",
1414
"typecheck": "tsc --noEmit",
15+
"fmt:rust": "cargo fmt --manifest-path src-tauri/Cargo.toml -- --check",
16+
"test:rust": "cargo test --manifest-path src-tauri/Cargo.toml",
1517
"lint:ts": "pnpm run typecheck && biome check .",
1618
"lint:rust": "pnpm run ensure:tauri-icon && cargo clippy --workspace --all-targets --manifest-path src-tauri/Cargo.toml -- -D warnings",
1719
"lint": "pnpm run lint:ts && pnpm run lint:rust",
1820
"check": "pnpm run lint && pnpm test",
21+
"ci:web": "pnpm run lint:ts && pnpm test && pnpm run build",
22+
"ci:rust": "pnpm run ensure:tauri-icon && pnpm run fmt:rust && pnpm run lint:rust && pnpm run test:rust",
23+
"ci": "pnpm run ci:web && pnpm run ci:rust",
1924
"dev": "vite",
2025
"build": "pnpm run typecheck && vite build",
2126
"preview": "vite preview",

rust-toolchain.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[toolchain]
2+
channel = "stable"
3+
profile = "minimal"
4+
components = ["clippy", "rustfmt"]

tests/ci-baseline.test.mjs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import assert from "node:assert/strict";
2+
import { readFileSync } from "node:fs";
3+
import test from "node:test";
4+
5+
const ciWorkflow = readFileSync(new URL("../.github/workflows/ci.yml", import.meta.url), "utf8");
6+
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
7+
const rustToolchain = readFileSync(new URL("../rust-toolchain.toml", import.meta.url), "utf8");
8+
9+
test("ci workflow defines separate web and rust quality jobs", () => {
10+
assert.match(ciWorkflow, /^\s{2}web-quality:/m);
11+
assert.match(ciWorkflow, /^\s{2}rust-quality:/m);
12+
assert.match(ciWorkflow, /run: pnpm run ci:web/);
13+
assert.match(ciWorkflow, /run: pnpm run ci:rust/);
14+
});
15+
16+
test("ci workflow installs node and rust toolchains deterministically", () => {
17+
assert.match(ciWorkflow, /node-version: 24/);
18+
assert.match(ciWorkflow, /uses: dtolnay\/rust-toolchain@stable/);
19+
assert.match(ciWorkflow, /components: rustfmt, clippy/);
20+
});
21+
22+
test("package scripts expose ci entry points for local reproduction", () => {
23+
assert.equal(typeof packageJson.scripts["ci:web"], "string");
24+
assert.equal(typeof packageJson.scripts["ci:rust"], "string");
25+
assert.equal(typeof packageJson.scripts.ci, "string");
26+
});
27+
28+
test("rust toolchain file pins baseline channel and required components", () => {
29+
assert.match(rustToolchain, /^channel = "stable"$/m);
30+
assert.match(rustToolchain, /^components = \["clippy", "rustfmt"\]$/m);
31+
});

tests/tauri-bootstrap.test.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ test("package scripts expose desktop and frontend bootstrap commands", () => {
2424
assert.equal(typeof packageJson.scripts["pretauri:dev"], "string");
2525
assert.equal(typeof packageJson.scripts["pretauri:build"], "string");
2626
assert.equal(typeof packageJson.scripts.typecheck, "string");
27+
assert.equal(typeof packageJson.scripts["fmt:rust"], "string");
28+
assert.equal(typeof packageJson.scripts["test:rust"], "string");
2729
assert.equal(typeof packageJson.scripts["lint:ts"], "string");
2830
assert.equal(typeof packageJson.scripts["lint:rust"], "string");
2931
assert.equal(typeof packageJson.scripts.lint, "string");
3032
assert.equal(typeof packageJson.scripts.check, "string");
33+
assert.equal(typeof packageJson.scripts["ci:web"], "string");
34+
assert.equal(typeof packageJson.scripts["ci:rust"], "string");
35+
assert.equal(typeof packageJson.scripts.ci, "string");
3136
assert.ok(packageJson.scripts["lint:ts"].includes("biome check ."));
3237
assert.ok(packageJson.scripts["lint:rust"].includes("ensure:tauri-icon"));
3338
});

0 commit comments

Comments
 (0)