From dcc329e764503e6b76415892a52ebd06f35a5dcd Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar Date: Wed, 18 Feb 2026 09:00:11 +0100 Subject: [PATCH] ci: add Gitea Actions pipeline and Dockerfile Three-stage CI pipeline with fmt, clippy and audit as parallel quality gates, tests gated on quality, and Docker build+push to registry.meghsakha.com on main and release/* branches. Co-Authored-By: Claude Opus 4.6 --- .gitea/workflows/ci.yml | 114 ++++++++++++++++++++++++++++++++++++++++ Dockerfile | 61 +++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 .gitea/workflows/ci.yml create mode 100644 Dockerfile diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..3b37db3 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,114 @@ +name: CI + +on: + push: + branches: + - "**" + pull_request: + branches: + - main + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: "-D warnings" + +# Cancel in-progress runs for the same branch/PR +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # --------------------------------------------------------------------------- + # Stage 1: Code quality checks (run in parallel) + # --------------------------------------------------------------------------- + fmt: + name: Format + runs-on: docker + container: + image: rust:1.89-bookworm + steps: + - uses: actions/checkout@v4 + - run: rustup component add rustfmt + - run: cargo fmt --check + + clippy: + name: Clippy + runs-on: docker + container: + image: rust:1.89-bookworm + steps: + - uses: actions/checkout@v4 + - run: rustup component add clippy + # Lint both feature sets independently + - name: Clippy (server) + run: cargo clippy --features server --no-default-features -- -D warnings + - name: Clippy (web) + run: cargo clippy --features web --no-default-features -- -D warnings + + audit: + name: Security Audit + runs-on: docker + container: + image: rust:1.89-bookworm + steps: + - uses: actions/checkout@v4 + - run: cargo install cargo-audit + - run: cargo audit + + # --------------------------------------------------------------------------- + # Stage 2: Tests (only after all quality checks pass) + # --------------------------------------------------------------------------- + test: + name: Tests + runs-on: docker + needs: [fmt, clippy, audit] + container: + image: rust:1.89-bookworm + steps: + - uses: actions/checkout@v4 + - name: Run tests (server) + run: cargo test --features server --no-default-features + - name: Run tests (web) + run: cargo test --features web --no-default-features + + # --------------------------------------------------------------------------- + # Stage 3: Build Docker image and push to registry + # Only on main and release/* branches + # --------------------------------------------------------------------------- + build-and-push: + name: Build & Push Image + runs-on: docker + needs: [test] + if: >- + github.event_name == 'push' && + (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) + steps: + - uses: actions/checkout@v4 + + - name: Determine image tag + id: tag + run: | + BRANCH="${GITHUB_REF#refs/heads/}" + # Replace / with - for valid Docker tags (e.g. release/1.0 -> release-1.0) + BRANCH_SAFE=$(echo "$BRANCH" | tr '/' '-') + SHA=$(echo "$GITHUB_SHA" | head -c 8) + echo "tag=${BRANCH_SAFE}-${SHA}" >> "$GITHUB_OUTPUT" + + - name: Log in to container registry + run: >- + echo "${{ secrets.REGISTRY_PASSWORD }}" + | docker login https://registry.meghsakha.com + -u "${{ secrets.REGISTRY_USERNAME }}" + --password-stdin + + - name: Build Docker image + run: >- + docker build + -t registry.meghsakha.com/certifai/dashboard:${{ steps.tag.outputs.tag }} + -t registry.meghsakha.com/certifai/dashboard:latest + . + + - name: Push Docker image + run: | + docker push registry.meghsakha.com/certifai/dashboard:${{ steps.tag.outputs.tag }} + docker push registry.meghsakha.com/certifai/dashboard:latest diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4880070 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,61 @@ +# Stage 1: Generate dependency recipe for caching +FROM rust:1.89-bookworm AS chef +RUN cargo install cargo-chef +WORKDIR /app + +FROM chef AS planner +COPY . . +RUN cargo chef prepare --recipe-path recipe.json + +# Stage 2: Build dependencies + application +FROM chef AS builder + +# Install system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + pkg-config libssl-dev curl unzip \ + && rm -rf /var/lib/apt/lists/* + +# Install bun (for Tailwind CSS build step) +RUN curl -fsSL https://bun.sh/install | bash +ENV PATH="/root/.bun/bin:$PATH" + +# Install dx CLI via cargo-binstall +RUN curl -L --proto '=https' --tlsv1.2 -sSf \ + https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh \ + | bash +RUN cargo binstall dioxus-cli@0.7.3 --root /.cargo -y --force +ENV PATH="/.cargo/bin:$PATH" + +# Cook dependencies from recipe (cached layer) +COPY --from=planner /app/recipe.json recipe.json +RUN cargo chef cook --release --recipe-path recipe.json + +# Copy source and build +COPY . . + +# Ensure styles directory exists for build.rs tailwind step +RUN mkdir -p styles && touch styles/input.css + +# Bundle the fullstack application +RUN dx bundle --platform fullstack + +# Stage 3: Minimal runtime image +FROM debian:bookworm-slim AS runtime + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates libssl3 \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd --create-home --shell /bin/bash app +USER app +WORKDIR /home/app + +# Copy the bundled output from builder +COPY --from=builder --chown=app:app /app/target/dx/dashboard/release/web/ ./ + +EXPOSE 8000 + +ENV IP=0.0.0.0 +ENV PORT=8000 + +ENTRYPOINT ["./server"]