Initial Scaffolding #3
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: | |
| branches: [ master, develop ] | |
| types: [ opened, synchronize, reopened ] | |
| env: | |
| RUST_VERSION: '1.85' | |
| BUN_VERSION: 'latest' | |
| jobs: | |
| validate-branch: | |
| name: Validate Branch Model | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Validate branching model | |
| run: | | |
| SOURCE_BRANCH="${{ github.head_ref }}" | |
| TARGET_BRANCH="${{ github.base_ref }}" | |
| echo "Source branch: $SOURCE_BRANCH" | |
| echo "Target branch: $TARGET_BRANCH" | |
| validate_branch() { | |
| case "$SOURCE_BRANCH" in | |
| enhancement/*) | |
| if [ "$TARGET_BRANCH" != "develop" ]; then | |
| echo "❌ Enhancement branches can only target 'develop', not '$TARGET_BRANCH'" | |
| exit 1 | |
| fi | |
| ;; | |
| feature/*) | |
| if [ "$TARGET_BRANCH" != "develop" ]; then | |
| echo "❌ Feature branches can only target 'develop', not '$TARGET_BRANCH'" | |
| exit 1 | |
| fi | |
| ;; | |
| fix/*) | |
| if [ "$TARGET_BRANCH" != "develop" ]; then | |
| echo "❌ Fix branches can only target 'develop', not '$TARGET_BRANCH'" | |
| exit 1 | |
| fi | |
| ;; | |
| hotfix/*) | |
| if [ "$TARGET_BRANCH" != "master" ]; then | |
| echo "❌ Hotfix branches can only target 'master', not '$TARGET_BRANCH'" | |
| exit 1 | |
| fi | |
| ;; | |
| release/*) | |
| if [ "$TARGET_BRANCH" != "master" ]; then | |
| echo "❌ Release branches can only target 'master', not '$TARGET_BRANCH'" | |
| exit 1 | |
| fi | |
| MERGE_BASE=$(git merge-base origin/develop HEAD) | |
| DEVELOP_HEAD=$(git rev-parse origin/develop) | |
| if [ "$MERGE_BASE" != "$DEVELOP_HEAD" ]; then | |
| echo "❌ Release branches must be created from the latest 'develop' branch" | |
| exit 1 | |
| fi | |
| ;; | |
| *) | |
| echo "❌ Invalid branch name '$SOURCE_BRANCH'. Must follow pattern:" | |
| echo " - enhancement/name (→ develop)" | |
| echo " - feature/name (→ develop)" | |
| echo " - fix/name (→ develop)" | |
| echo " - hotfix/name (→ master)" | |
| echo " - release/yyyy-mm-dd (develop → master)" | |
| exit 1 | |
| ;; | |
| esac | |
| echo "✅ Quiver loves your PR: $SOURCE_BRANCH → $TARGET_BRANCH" | |
| } | |
| validate_branch | |
| code-quality-frontend: | |
| name: Code Quality - Frontend | |
| runs-on: ubuntu-latest | |
| needs: validate-branch | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: ${{ env.BUN_VERSION }} | |
| - name: Cache Bun dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.bun/install/cache | |
| node_modules | |
| key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }} | |
| restore-keys: | | |
| ${{ runner.os }}-bun- | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Format check | |
| run: | | |
| bun run prettier --check "src/**/*.{ts,tsx,js,jsx}" | |
| if [ $? -ne 0 ]; then | |
| echo "❌ Code is not properly formatted. Please run 'make fmt-frontend'" | |
| exit 1 | |
| fi | |
| echo "✅ Code formatting is correct" | |
| - name: Lint check | |
| run: | | |
| bun run eslint "src/**/*.{ts,tsx,js,jsx}" | |
| echo "✅ Linting passed" | |
| - name: Type checking | |
| run: | | |
| bun run tsc --noEmit | |
| echo "✅ Type checking passed" | |
| - name: Security audit | |
| run: | | |
| bun audit | |
| echo "✅ Security audit passed" | |
| code-quality-rust: | |
| name: Code Quality - Rust | |
| runs-on: ubuntu-latest | |
| needs: validate-branch | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev \ | |
| build-essential \ | |
| curl \ | |
| wget \ | |
| file \ | |
| libssl-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev | |
| - name: Set up Rust | |
| uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| with: | |
| toolchain: ${{ env.RUST_VERSION }} | |
| components: rustfmt, clippy | |
| - name: Cache Cargo dependencies | |
| 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: Format check | |
| run: | | |
| cd src-tauri | |
| cargo fmt --check | |
| if [ $? -ne 0 ]; then | |
| echo "❌ Rust code is not properly formatted. Please run 'make fmt-rust'" | |
| exit 1 | |
| fi | |
| echo "✅ Rust formatting is correct" | |
| - name: Clippy check | |
| run: | | |
| cd src-tauri | |
| cargo clippy -- -D warnings | |
| echo "✅ Clippy checks passed" | |
| - name: Security audit | |
| run: | | |
| cargo install cargo-audit | |
| cd src-tauri | |
| cargo audit | |
| echo "✅ Security audit passed" | |
| build-frontend: | |
| name: Build - Frontend | |
| runs-on: ubuntu-latest | |
| needs: [code-quality-frontend, code-quality-rust] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: ${{ env.BUN_VERSION }} | |
| - name: Cache Bun dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.bun/install/cache | |
| node_modules | |
| key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }} | |
| restore-keys: | | |
| ${{ runner.os }}-bun- | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Build frontend | |
| run: bun run build | |
| - name: Verify build output | |
| run: | | |
| if [ ! -d "dist" ]; then | |
| echo "❌ dist/ folder not found after build" | |
| exit 1 | |
| fi | |
| echo "✅ Frontend built successfully" | |
| ls -la dist/ | |
| build-tauri: | |
| name: Build - Tauri | |
| runs-on: ubuntu-latest | |
| needs: [code-quality-frontend, code-quality-rust] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev \ | |
| build-essential \ | |
| curl \ | |
| wget \ | |
| file \ | |
| libssl-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev | |
| - name: Set up Rust | |
| uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| with: | |
| toolchain: ${{ env.RUST_VERSION }} | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: ${{ env.BUN_VERSION }} | |
| - name: Cache Cargo dependencies | |
| 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: Install frontend dependencies | |
| run: bun install | |
| - name: Build Tauri backend | |
| run: | | |
| cd src-tauri | |
| cargo build --release | |
| - name: Verify binary | |
| run: | | |
| if [ ! -f "src-tauri/target/release/quiverdesktop" ]; then | |
| echo "❌ Binary not found after build" | |
| exit 1 | |
| fi | |
| echo "✅ Tauri binary built successfully" | |
| ls -la src-tauri/target/release/ | |
| test-coverage-rust: | |
| name: Test Coverage - Rust | |
| runs-on: ubuntu-latest | |
| needs: [build-frontend, build-tauri] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev \ | |
| build-essential \ | |
| curl \ | |
| wget \ | |
| file \ | |
| libssl-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev | |
| - name: Set up Rust | |
| uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| with: | |
| toolchain: ${{ env.RUST_VERSION }} | |
| - name: Install cargo-tarpaulin | |
| run: cargo install cargo-tarpaulin | |
| - name: Run tests with coverage | |
| run: | | |
| cd src-tauri | |
| cargo tarpaulin --out Xml --out Html --out Lcov --output-dir ../coverage --verbose | |
| - name: Check overall coverage | |
| run: | | |
| if [ ! -f "coverage/cobertura.xml" ]; then | |
| echo "⚠️ Coverage file not found, skipping coverage check" | |
| exit 0 | |
| fi | |
| OVERALL_COVERAGE=$(grep -oP 'line-rate="\K[0-9.]+' coverage/cobertura.xml | head -1) | |
| COVERAGE_PERCENT=$(echo "$OVERALL_COVERAGE * 100" | bc) | |
| echo "Overall coverage: ${COVERAGE_PERCENT}%" | |
| if [ $(echo "$OVERALL_COVERAGE < 0.80" | bc -l) -eq 1 ]; then | |
| echo "❌ Overall coverage ${COVERAGE_PERCENT}% is below required 80%" | |
| exit 1 | |
| fi | |
| echo "✅ Overall coverage ${COVERAGE_PERCENT}% meets requirement (≥80%)" | |
| - name: Upload coverage reports | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-reports | |
| path: | | |
| coverage/*.xml | |
| coverage/*.html | |
| coverage/*.lcov | |
| retention-days: 7 | |
| pr-validation-complete: | |
| name: PR Validation Complete | |
| runs-on: ubuntu-latest | |
| needs: [validate-branch, code-quality-frontend, code-quality-rust, build-frontend, build-tauri, test-coverage-rust] | |
| if: always() | |
| steps: | |
| - name: Check all jobs status | |
| run: | | |
| echo "Validation results:" | |
| echo "- Branch validation: ${{ needs.validate-branch.result }}" | |
| echo "- Frontend code quality: ${{ needs.code-quality-frontend.result }}" | |
| echo "- Rust code quality: ${{ needs.code-quality-rust.result }}" | |
| echo "- Frontend build: ${{ needs.build-frontend.result }}" | |
| echo "- Tauri build: ${{ needs.build-tauri.result }}" | |
| echo "- Rust test coverage: ${{ needs.test-coverage-rust.result }}" | |
| if [ "${{ needs.validate-branch.result }}" != "success" ] || \ | |
| [ "${{ needs.code-quality-frontend.result }}" != "success" ] || \ | |
| [ "${{ needs.code-quality-rust.result }}" != "success" ] || \ | |
| [ "${{ needs.build-frontend.result }}" != "success" ] || \ | |
| [ "${{ needs.build-tauri.result }}" != "success" ] || \ | |
| [ "${{ needs.test-coverage-rust.result }}" != "success" ]; then | |
| echo "❌ Some checks failed. Please review and fix the issues." | |
| exit 1 | |
| fi | |
| echo "✅ All PR validation checks passed successfully!" | |
| echo "" | |
| echo "📋 Summary:" | |
| echo "- ✅ Branch follows the defined branching model" | |
| echo "- ✅ Frontend code quality checks passed" | |
| echo "- ✅ Rust code quality checks passed" | |
| echo "- ✅ Frontend builds successfully" | |
| echo "- ✅ Tauri backend builds successfully" | |
| echo "- ✅ Rust test coverage ≥ 80%" | |
| echo "" | |
| echo "🎉 This PR is ready for review!" | |