diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml deleted file mode 100644 index 993f2a6..0000000 --- a/.gitea/workflows/build.yml +++ /dev/null @@ -1,153 +0,0 @@ -name: Build .deb Package - -on: - push: - tags: ["v*"] - -env: - CARGO_TERM_COLOR: always - -jobs: - build-and-package: - runs-on: linux - steps: - - name: Install system dependencies - run: | - sudo apt-get update -qq - sudo apt-get install -y --no-install-recommends \ - curl pkg-config libssl-dev ca-certificates \ - git nodejs npm dpkg-dev python3 - - - name: Checkout repository - run: | - # Use Gitea API archive download with token auth - # GITHUB_TOKEN may not be injected in linux:host mode; fall back to GITEA_TOKEN - TOKEN="${GITHUB_TOKEN:-$GITEA_TOKEN}" - curl -sf -H "Authorization: token ${TOKEN}" \ - "http://192.168.2.189:3000/api/v1/repos/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" \ - -o repo.tar.gz - tar xzf repo.tar.gz --strip-components=1 - rm repo.tar.gz - - - name: Ensure Rust toolchain - run: | - . "$HOME/.cargo/env" 2>/dev/null || true - if ! command -v cargo &>/dev/null; then - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - . "$HOME/.cargo/env" - fi - echo "Rust: $(cargo --version)" - - - name: Build Rust backend (release) - run: | - . "$HOME/.cargo/env" 2>/dev/null || true - cargo build --release 2>&1 - - - name: Run Rust tests - run: | - . "$HOME/.cargo/env" 2>/dev/null || true - cargo test --release 2>&1 || true - - - name: Strip binaries - run: | - strip target/release/pm-web - strip target/release/pm-worker - - - name: Install frontend dependencies - working-directory: frontend - run: npm ci - - - name: Build frontend - working-directory: frontend - run: npm run build - - - name: Determine version - id: version - run: | - if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then - VERSION="${GITHUB_REF#refs/tags/v}" - else - VERSION="1.0.0-dev.$(date +%Y%m%d%H%M)" - fi - echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "Building version: ${VERSION}" - - - name: Assemble .deb package - run: | - VERSION="${{ steps.version.outputs.version }}" - BUILD_DIR="package-build" - - mkdir -p "${BUILD_DIR}/DEBIAN" - mkdir -p "${BUILD_DIR}/usr/local/bin" - mkdir -p "${BUILD_DIR}/usr/share/patch-manager/frontend" - mkdir -p "${BUILD_DIR}/usr/share/patch-manager/migrations" - mkdir -p "${BUILD_DIR}/lib/systemd/system" - - # Binaries - cp target/release/pm-web "${BUILD_DIR}/usr/local/bin/pm-web" - cp target/release/pm-worker "${BUILD_DIR}/usr/local/bin/pm-worker" - cp scripts/backup.sh "${BUILD_DIR}/usr/local/bin/backup.sh" - chmod 755 "${BUILD_DIR}/usr/local/bin/pm-web" - chmod 755 "${BUILD_DIR}/usr/local/bin/pm-worker" - chmod 700 "${BUILD_DIR}/usr/local/bin/backup.sh" - - # Frontend - cp -r frontend/dist/* "${BUILD_DIR}/usr/share/patch-manager/frontend/" - - # Config + migrations - cp config/config.example.toml "${BUILD_DIR}/usr/share/patch-manager/config.example.toml" - cp migrations/*.sql "${BUILD_DIR}/usr/share/patch-manager/migrations/" - - # Systemd units - cp systemd/patch-manager-web.service "${BUILD_DIR}/lib/systemd/system/" - cp systemd/patch-manager-worker.service "${BUILD_DIR}/lib/systemd/system/" - cp systemd/patch-manager.target "${BUILD_DIR}/lib/systemd/system/" - - # DEBIAN control scripts - cp debian/postinst "${BUILD_DIR}/DEBIAN/postinst" - cp debian/prerm "${BUILD_DIR}/DEBIAN/prerm" - cp debian/postrm "${BUILD_DIR}/DEBIAN/postrm" - chmod 755 "${BUILD_DIR}/DEBIAN/postinst" "${BUILD_DIR}/DEBIAN/prerm" "${BUILD_DIR}/DEBIAN/postrm" - - # Generate control file - INSTALLED_SIZE=$(du -sk "${BUILD_DIR}" | cut -f1) - cat > "${BUILD_DIR}/DEBIAN/control" < - Installed-Size: ${INSTALLED_SIZE} - Depends: postgresql-16, libssl3, libc6 (>= 2.39) - Recommends: postgresql-client-16 - Suggests: gpg - Section: admin - Priority: optional - Description: Enterprise Linux Patch Management System - Linux Patch Manager is a secure, web-based management interface for - controlling patching and updates on Linux servers and workstations. - CTRL - - # Build .deb - DEB_NAME="linux-patch-manager_${VERSION}-1_amd64.deb" - dpkg-deb --build "${BUILD_DIR}" "${DEB_NAME}" - echo "Built: ${DEB_NAME}" - du -h "${DEB_NAME}" - - - name: Verify package - run: | - DEB_NAME=$(ls linux-patch-manager_*.deb) - echo "=== Package Info ===" - dpkg-deb --info "${DEB_NAME}" - echo "=== Package Size ===" - du -h "${DEB_NAME}" - - - name: Create Gitea Release (tags only) - if: startsWith(github.ref, 'refs/tags/v') - run: | - DEB_NAME=$(ls linux-patch-manager_*.deb) - VERSION="${{ steps.version.outputs.version }}" - export GITEA_TOKEN="${GITHUB_TOKEN:-$GITEA_TOKEN}" - python3 scripts/create-release.py \ - --tag "${GITHUB_REF_NAME:-v${VERSION}}" \ - --deb "${DEB_NAME}" \ - --version "${VERSION}" diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index a92a9ec..063b3eb 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,8 +1,9 @@ -name: CI Quality Gates +name: CI Pipeline on: push: branches: [master] + tags: ["v*"] pull_request: branches: [master] @@ -11,6 +12,8 @@ env: RUST_BACKTRACE: 1 jobs: + # ─── Quality Gates (run on every push/PR/tag) ─── + rust-format: name: Rust Format Check runs-on: linux @@ -39,7 +42,6 @@ jobs: run: | . "$HOME/.cargo/env" cargo fmt --check --all 2>&1 - echo "All Rust code is properly formatted" clippy: name: Clippy Lints @@ -83,7 +85,6 @@ jobs: -A clippy::cast-possible-wrap \ -A clippy::missing-errors-doc \ -A clippy::missing-panics-doc 2>&1 - echo "No Clippy warnings" rust-test: name: Rust Unit Tests @@ -116,7 +117,6 @@ jobs: run: | . "$HOME/.cargo/env" cargo test --workspace --all-features 2>&1 - echo "All Rust tests passed" security-audit: name: Security Audit @@ -148,7 +148,6 @@ jobs: run: | . "$HOME/.cargo/env" cargo audit 2>&1 - echo "No known security vulnerabilities" frontend-lint: name: Frontend Lint & Type Check @@ -169,12 +168,155 @@ jobs: - name: Run ESLint working-directory: frontend - run: | - npx eslint src/ --ext .ts,.tsx --max-warnings 0 2>&1 - echo "No ESLint errors" + run: npx eslint src/ --ext .ts,.tsx --max-warnings 0 2>&1 - name: TypeScript type check working-directory: frontend + run: npx tsc --noEmit 2>&1 + + # ─── Build & Release (only on tag pushes, gated by quality checks) ─── + + build-and-release: + name: Build .deb & Release + runs-on: linux + needs: [rust-format, clippy, rust-test, security-audit, frontend-lint] + if: startsWith(github.ref, 'refs/tags/v') + steps: + - name: Install system dependencies run: | - npx tsc --noEmit 2>&1 - echo "TypeScript types are valid" + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends \ + curl pkg-config libssl-dev ca-certificates \ + git nodejs npm dpkg-dev python3 + + - name: Checkout repository + run: | + TOKEN="${GITHUB_TOKEN:-$GITEA_TOKEN}" + curl -sf -H "Authorization: token ${TOKEN}" \ + "http://192.168.2.189:3000/api/v1/repos/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" \ + -o repo.tar.gz + tar xzf repo.tar.gz --strip-components=1 + rm repo.tar.gz + + - name: Ensure Rust toolchain + run: | + . "$HOME/.cargo/env" 2>/dev/null || true + if ! command -v cargo &>/dev/null; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + . "$HOME/.cargo/env" + fi + echo "Rust: $(cargo --version)" + + - name: Build Rust backend (release) + run: | + . "$HOME/.cargo/env" 2>/dev/null || true + cargo build --release 2>&1 + + - name: Run Rust tests + run: | + . "$HOME/.cargo/env" 2>/dev/null || true + cargo test --release 2>&1 || true + + - name: Strip binaries + run: | + strip target/release/pm-web + strip target/release/pm-worker + + - name: Install frontend dependencies + working-directory: frontend + run: npm ci + + - name: Build frontend + working-directory: frontend + run: npm run build + + - name: Determine version + id: version + run: | + if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then + VERSION="${GITHUB_REF#refs/tags/v}" + else + VERSION="1.0.0-dev.$(date +%Y%m%d%H%M)" + fi + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "Building version: ${VERSION}" + + - name: Assemble .deb package + run: | + VERSION="${{ steps.version.outputs.version }}" + BUILD_DIR="package-build" + + mkdir -p "${BUILD_DIR}/DEBIAN" + mkdir -p "${BUILD_DIR}/usr/local/bin" + mkdir -p "${BUILD_DIR}/usr/share/patch-manager/frontend" + mkdir -p "${BUILD_DIR}/usr/share/patch-manager/migrations" + mkdir -p "${BUILD_DIR}/lib/systemd/system" + + # Binaries + cp target/release/pm-web "${BUILD_DIR}/usr/local/bin/pm-web" + cp target/release/pm-worker "${BUILD_DIR}/usr/local/bin/pm-worker" + cp scripts/backup.sh "${BUILD_DIR}/usr/local/bin/backup.sh" + chmod 755 "${BUILD_DIR}/usr/local/bin/pm-web" + chmod 755 "${BUILD_DIR}/usr/local/bin/pm-worker" + chmod 700 "${BUILD_DIR}/usr/local/bin/backup.sh" + + # Frontend + cp -r frontend/dist/* "${BUILD_DIR}/usr/share/patch-manager/frontend/" + + # Config + migrations + cp config/config.example.toml "${BUILD_DIR}/usr/share/patch-manager/config.example.toml" + cp migrations/*.sql "${BUILD_DIR}/usr/share/patch-manager/migrations/" + + # Systemd units + cp systemd/patch-manager-web.service "${BUILD_DIR}/lib/systemd/system/" + cp systemd/patch-manager-worker.service "${BUILD_DIR}/lib/systemd/system/" + cp systemd/patch-manager.target "${BUILD_DIR}/lib/systemd/system/" + + # DEBIAN control scripts + cp debian/postinst "${BUILD_DIR}/DEBIAN/postinst" + cp debian/prerm "${BUILD_DIR}/DEBIAN/prerm" + cp debian/postrm "${BUILD_DIR}/DEBIAN/postrm" + chmod 755 "${BUILD_DIR}/DEBIAN/postinst" "${BUILD_DIR}/DEBIAN/prerm" "${BUILD_DIR}/DEBIAN/postrm" + + # Generate control file + INSTALLED_SIZE=$(du -sk "${BUILD_DIR}" | cut -f1) + cat > "${BUILD_DIR}/DEBIAN/control" < + Installed-Size: ${INSTALLED_SIZE} + Depends: postgresql-16, libssl3, libc6 (>= 2.39) + Recommends: postgresql-client-16 + Suggests: gpg + Section: admin + Priority: optional + Description: Enterprise Linux Patch Management System + Linux Patch Manager is a secure, web-based management interface for + controlling patching and updates on Linux servers and workstations. + CTRL + + # Build .deb + DEB_NAME="linux-patch-manager_${VERSION}-1_amd64.deb" + dpkg-deb --build "${BUILD_DIR}" "${DEB_NAME}" + echo "Built: ${DEB_NAME}" + du -h "${DEB_NAME}" + + - name: Verify package + run: | + DEB_NAME=$(ls linux-patch-manager_*.deb) + echo "=== Package Info ===" + dpkg-deb --info "${DEB_NAME}" + echo "=== Package Size ===" + du -h "${DEB_NAME}" + + - name: Create Gitea Release + if: startsWith(github.ref, 'refs/tags/v') + run: | + DEB_NAME=$(ls linux-patch-manager_*.deb) + VERSION="${{ steps.version.outputs.version }}" + export GITEA_TOKEN="${GITHUB_TOKEN:-$GITEA_TOKEN}" + python3 scripts/create-release.py \ + --tag "${GITHUB_REF_NAME:-v${VERSION}}" \ + --deb "${DEB_NAME}" \ + --version "${VERSION}"