name: CI on: pull_request: push: branches: [main] schedule: - cron: "0 3 * * 1" workflow_dispatch: permissions: contents: read jobs: # Static analysis. Also the only job that runs on the weekly schedule, so newly published # Semgrep registry rules are applied to main even when nothing is pushed. security: runs-on: bongbetic-ci timeout-minutes: 15 container: image: docker.io/semgrep/semgrep:1.178.0 steps: - name: Checkout run: | git init -q . && git remote add origin "${{ gitea.server_url }}/${{ gitea.repository }}.git" \ && git -c http.extraheader="Authorization: token ${{ gitea.token }}" fetch -q --depth=1 origin "${{ gitea.sha }}" \ && git checkout -q FETCH_HEAD - name: Semgrep run: semgrep scan --config p/default --config p/owasp-top-ten --metrics off --error lint: if: gitea.event_name != 'schedule' runs-on: bongbetic-ci timeout-minutes: 20 steps: - name: Checkout run: | git init -q . && git remote add origin "${{ gitea.server_url }}/${{ gitea.repository }}.git" \ && git -c http.extraheader="Authorization: token ${{ gitea.token }}" fetch -q --depth=1 origin "${{ gitea.sha }}" \ && git checkout -q FETCH_HEAD - name: Install dependencies run: npm ci - name: Typecheck run: npx tsc --noEmit - name: ESLint run: npx eslint . - name: Rust format check # rustfmt only. clippy is deliberately not run: it needs the webkit2gtk/gtk system libraries # and a full compile of the Tauri crate, which is too heavy for the shared CI host. working-directory: src-tauri run: | base=https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu curl --proto '=https' --tlsv1.2 -sSfO "$base/rustup-init" -O "$base/rustup-init.sha256" sha256sum -c rustup-init.sha256 chmod +x rustup-init ./rustup-init -y --no-modify-path --profile minimal --default-toolchain 1.99.0 -c rustfmt rm -f rustup-init rustup-init.sha256 "$HOME/.cargo/bin/cargo" fmt --check - name: Duplicate code (jscpd) run: npx --yes jscpd@4.3.0 e2e: if: gitea.event_name != 'schedule' runs-on: bongbetic-ci timeout-minutes: 25 container: # Keep this tag in step with the @playwright/test version in package.json. image: mcr.microsoft.com/playwright:v1.63.0-noble env: CI: "true" steps: - name: Checkout run: | git init -q . && git remote add origin "${{ gitea.server_url }}/${{ gitea.repository }}.git" \ && git -c http.extraheader="Authorization: token ${{ gitea.token }}" fetch -q --depth=1 origin "${{ gitea.sha }}" \ && git checkout -q FETCH_HEAD - name: Install dependencies run: npm ci - name: Build run: npm run build - name: Playwright smoke tests run: npx playwright test # Advisory only: never blocks a merge. ai-review: if: gitea.event_name == 'pull_request' runs-on: bongbetic-ci timeout-minutes: 10 continue-on-error: true container: image: docker.io/pragent/pr-agent:0.47.0 env: config__git_provider: gitea gitea__url: https://git.bongbetic.com gitea__personal_access_token: ${{ secrets.PR_AGENT_GITEA_TOKEN }} openrouter__key: ${{ secrets.OPENROUTER_API_KEY }} config__model: ${{ vars.PR_AGENT_MODEL || 'openrouter/anthropic/claude-sonnet-5' }} # PR-Agent needs this for OpenRouter models it has no built-in context window for. config__custom_model_max_tokens: "200000" steps: - name: PR-Agent review run: | if [ -z "$gitea__personal_access_token" ] || [ -z "$openrouter__key" ]; then echo "::notice::PR-Agent secrets not configured; skipping AI review." exit 0 fi pr-agent --pr_url="${{ gitea.event.pull_request.html_url }}" review