name: Frontend Check on: pull_request: workflow_dispatch: permissions: contents: read pull-requests: read env: HUSKY: 0 jobs: frontend: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - name: Check frontend changes id: check_frontend uses: dorny/paths-filter@v4 with: filters: | frontend: - 'src/**' - '**/*.js' - '**/*.ts' - '**/*.tsx' - '**/*.css' - '**/*.scss' - '**/*.json' - '**/*.md' - 'package.json' - 'pnpm-lock.yaml' - 'pnpm-workspace.yaml' - 'knip.json' - 'eslint.config.ts' - 'tsconfig.json' - 'vite.config.*' - name: Skip if no frontend changes if: steps.check_frontend.outputs.frontend != 'true' run: echo "No frontend changes, skipping frontend checks." - name: Install pnpm if: steps.check_frontend.outputs.frontend == 'true' uses: pnpm/action-setup@v6 with: run_install: false - uses: actions/setup-node@v7 if: steps.check_frontend.outputs.frontend == 'true' with: node-version: '24.22.1' cache: 'pnpm' - name: Restore pnpm cache if: steps.check_frontend.outputs.frontend == 'true' uses: actions/cache@v6 with: path: ~/.pnpm-store key: "pnpm-shared-stable-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}" restore-keys: | pnpm-shared-stable-${{ runner.os }}- - run: pnpm install --frozen-lockfile if: steps.check_frontend.outputs.frontend == 'true' - name: Run Prettier check if: steps.check_frontend.outputs.frontend == 'true' run: pnpm format:check - name: Run ESLint if: steps.check_frontend.outputs.frontend == 'true' run: pnpm lint - name: Run TypeScript typecheck if: steps.check_frontend.outputs.frontend == 'true' run: pnpm typecheck - name: Run tests if: steps.check_frontend.outputs.frontend == 'true' run: pnpm test - name: Run Knip if: steps.check_frontend.outputs.frontend == 'true' run: pnpm knip:check - name: Architecture gates (listen/emit only in the event bus, invoke only in services) if: steps.check_frontend.outputs.frontend == 'true' run: node scripts/check-architecture.mjs listen emit invoke contract-parity: runs-on: ubuntu-26.04 steps: - uses: actions/checkout@v7 - name: Check contract inputs id: check_inputs uses: dorny/paths-filter@v4 with: filters: scripts/contract-inputs.json - name: Skip if contract inputs unchanged if: steps.check_inputs.outputs.contract != 'true' run: echo "No contract inputs changed, skipping parity check." - name: Install Rust Stable if: steps.check_inputs.outputs.contract == 'true' uses: dtolnay/rust-toolchain@master with: toolchain: stable - name: Rust Cache if: steps.check_inputs.outputs.contract == 'true' uses: Swatinem/rust-cache@v2 with: prefix-key: 'v1-rust' key: 'rust-shared-stable-ubuntu-22.04-x86_64-unknown-linux-gnu-contract' workspaces: | . -> target cache-all-crates: true cache-workspace-crates: true - name: Install dependencies if: steps.check_inputs.outputs.contract == 'true' run: | sudo apt-get update sudo apt-get install -y libxslt1.1 libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf - name: Install pnpm if: steps.check_inputs.outputs.contract == 'true' uses: pnpm/action-setup@v6 with: run_install: false - uses: actions/setup-node@v7 if: steps.check_inputs.outputs.contract == 'true' with: node-version: '24.22.1' cache: 'pnpm' - run: pnpm install --frozen-lockfile if: steps.check_inputs.outputs.contract == 'true' - name: Provision sidecar placeholders for tauri-build if: steps.check_inputs.outputs.contract == 'true' run: | mkdir -p src-tauri/sidecar src-tauri/resources dist touch dist/index.html for bin in clash-verge-service clash-verge-service-install clash-verge-service-uninstall verge-mihomo verge-mihomo-alpha; do touch "src-tauri/sidecar/${bin}-x86_64-unknown-linux-gnu" done - name: Check generated contract without changing the checkout if: steps.check_inputs.outputs.contract == 'true' run: pnpm gen:contract --check