Skip to content

Initial Scaffolding

Initial Scaffolding #3

Workflow file for this run

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!"