Skip to content
Merged
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
163 changes: 163 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1

jobs:
# Frontend Quality Gates
frontend:
name: Frontend Quality
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 9

- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- name: Setup pnpm cache
uses: actions/cache@v4
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Install dependencies
run: pnpm install

- name: TypeScript type check
run: pnpm typecheck

- name: ESLint
run: pnpm lint

- name: Run tests
run: pnpm test:coverage

- name: Upload coverage reports
uses: codecov/codecov-action@v4
with:
files: ./coverage/lcov.info
flags: frontend
fail_ci_if_error: false

# Rust Backend Quality Gates
backend:
name: Rust Quality
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- name: Cache Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
src-tauri/target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-

- name: Check formatting
working-directory: src-tauri
run: cargo fmt --check

- name: Clippy
working-directory: src-tauri
run: cargo clippy -- -D warnings

- name: Install cargo-tarpaulin
run: cargo install cargo-tarpaulin

- name: Run tests with coverage
working-directory: src-tauri
run: cargo tarpaulin --out Xml --fail-under 80 --verbose

- name: Build check
working-directory: src-tauri
run: cargo build

# Build verification (ensures app can be built)
build-check:
name: Build Verification
runs-on: macos-latest
needs: [frontend, backend]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 9

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable

- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
src-tauri/target/
node_modules/
key: ${{ runner.os }}-build-${{ hashFiles('**/Cargo.lock', '**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-build-

- name: Install frontend dependencies
run: pnpm install

- name: Build frontend
run: pnpm build

- name: Build Tauri app (debug)
run: pnpm tauri build --debug
env:
TAURI_SIGNING_PRIVATE_KEY: ""
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ""
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,5 @@ src-tauri/icons/icon.ico
*.deb
*.AppImage
*.msi
.zenflow/
GEMINI.md
43 changes: 40 additions & 3 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,60 @@
import js from "@eslint/js";
import tseslint from "typescript-eslint";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import globals from "globals";

export default tseslint.config(
{ ignores: ["dist", "src-tauri"] },
{ ignores: ["dist", "src-tauri", "coverage"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
globals: {
...globals.browser,
...globals.node,
},
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
// React hooks rules
...reactHooks.configs.recommended.rules,
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],

// React refresh
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],

// TypeScript strict rules
"@typescript-eslint/no-unused-vars": [
"error",
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
],
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-non-null-assertion": "warn",

// General code quality
"no-console": ["warn", { allow: ["warn", "error"] }],
"no-debugger": "error",
"no-duplicate-imports": "error",
"no-unused-expressions": "error",
"prefer-const": "error",
"eqeqeq": ["error", "always"],
},
},
// Test files - relaxed rules
{
files: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}", "**/test/**/*.{ts,tsx}"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"no-console": "off",
},
}
);
24 changes: 21 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,18 @@
"build": "tsc && vite build",
"preview": "vite preview",
"tauri": "tauri",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"typecheck": "tsc --noEmit"
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"test:ui": "vitest --ui",
"lint:rust": "cd src-tauri && cargo clippy -- -D warnings",
"fmt:rust": "cd src-tauri && cargo fmt --check",
"test:rust": "cd src-tauri && cargo test",
"quality:rust": "pnpm fmt:rust && pnpm lint:rust && pnpm test:rust",
"quality": "pnpm typecheck && pnpm lint && pnpm test && pnpm quality:rust"
},
"dependencies": {
"react": "^19.1.0",
Expand All @@ -33,6 +43,14 @@
"@eslint/js": "^9.17.0",
"typescript-eslint": "^8.19.1",
"eslint-plugin-react-hooks": "^5.1.0",
"globals": "^15.14.0"
"eslint-plugin-react-refresh": "^0.4.16",
"globals": "^15.14.0",
"vitest": "^2.1.8",
"@vitest/coverage-v8": "^2.1.8",
"@vitest/ui": "^2.1.8",
"@testing-library/react": "^16.1.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/user-event": "^14.5.2",
"jsdom": "^25.0.1"
}
}
Loading