diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 0045c38..b7aa096 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -11,6 +11,7 @@ import type { HealthCheckWithResult, CreateHealthCheckRequest, UpdateHealthCheckRequest, + HealthCheckListResponse, } from '../types' const BASE_URL = '/api/v1' @@ -273,7 +274,7 @@ export const settingsApi = { export const healthChecksApi = { list: (hostId: string) => - apiClient.get(`/hosts/${hostId}/health-checks`), + apiClient.get(`/hosts/${hostId}/health-checks`), get: (hostId: string, checkId: string) => apiClient.get(`/hosts/${hostId}/health-checks/${checkId}`), diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index f6eba75..6d62327 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -299,6 +299,11 @@ export interface HealthCheckWithResult extends HealthCheck { last_result?: HealthCheckResult } +export interface HealthCheckListResponse { + checks: HealthCheckWithResult[] + total: number +} + export interface CreateHealthCheckRequest { name: string check_type: HealthCheckType diff --git a/scripts/git-hooks/install.sh b/scripts/git-hooks/install.sh new file mode 100755 index 0000000..0b519dd --- /dev/null +++ b/scripts/git-hooks/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# ============================================================================= +# Linux Patch Manager — Git Hooks Installer +# ============================================================================= +# Installs pre-commit and pre-push hooks into .git/hooks/ +# Run from repo root: ./scripts/git-hooks/install.sh +# ============================================================================= + +set -euo pipefail + +REPO_ROOT="$(git rev-parse --show-toplevel)" +HOOKS_DIR="${REPO_ROOT}/.git/hooks" +SOURCE_DIR="${REPO_ROOT}/scripts/git-hooks" + +echo "Installing git hooks from ${SOURCE_DIR} ..." + +for hook in pre-commit pre-push; do + if [[ -f "${SOURCE_DIR}/${hook}" ]]; then + cp "${SOURCE_DIR}/${hook}" "${HOOKS_DIR}/${hook}" + chmod +x "${HOOKS_DIR}/${hook}" + echo " ✓ Installed ${hook}" + else + echo " ⚠ Skipped ${hook} (not found)" + fi +done + +echo "Done. Hooks will run automatically on commit and push." diff --git a/scripts/git-hooks/pre-commit b/scripts/git-hooks/pre-commit new file mode 100755 index 0000000..b1c92d6 --- /dev/null +++ b/scripts/git-hooks/pre-commit @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# ============================================================================= +# Linux Patch Manager — Pre-Commit Hook +# ============================================================================= +# Auto-formats Rust code and runs frontend type check before each commit. +# Prevents CI format-check failures by ensuring code is always formatted. +# Install: ./scripts/git-hooks/install.sh +# ============================================================================= + +set -euo pipefail + +REPO_ROOT="$(git rev-parse --show-toplevel)" + +# ── Rust auto-format ────────────────────────────────────────────────────────── +if [[ -f "${REPO_ROOT}/Cargo.toml" ]]; then + echo "[pre-commit] Running cargo fmt --all ..." + cargo fmt --all --manifest-path "${REPO_ROOT}/Cargo.toml" 2>/dev/null + + # Re-stage any files that cargo fmt reformatted (including previously unstaged) + STAGED_RS=$(git diff --name-only --diff-filter=ACM -- '*.rs') + if [[ -n "${STAGED_RS}" ]]; then + git add ${STAGED_RS} + fi +fi + +# ── Frontend type check ───────────────────────────────────────────────────── +if [[ -f "${REPO_ROOT}/frontend/package.json" ]]; then + echo "[pre-commit] Running TypeScript type check ..." + cd "${REPO_ROOT}/frontend" + npx tsc --noEmit 2>/dev/null +fi + +echo "[pre-commit] All checks passed ✓" diff --git a/scripts/git-hooks/pre-push b/scripts/git-hooks/pre-push new file mode 100755 index 0000000..3b06173 --- /dev/null +++ b/scripts/git-hooks/pre-push @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# ============================================================================= +# Linux Patch Manager — Pre-Push Hook +# ============================================================================= +# Safety net: verifies cargo fmt and frontend build pass before pushing. +# Install: ./scripts/git-hooks/install.sh +# ============================================================================= + +set -euo pipefail + +REPO_ROOT="$(git rev-parse --show-toplevel)" +FAILED=0 + +# ── Rust format check ──────────────────────────────────────────────────────── +if [[ -f "${REPO_ROOT}/Cargo.toml" ]]; then + echo "[pre-push] Checking Rust formatting ..." + if ! cargo fmt --all --manifest-path "${REPO_ROOT}/Cargo.toml" --check 2>/dev/null; then + echo "[pre-push] ❌ Rust formatting check FAILED. Run: cargo fmt --all" + FAILED=1 + fi +fi + +# ── Frontend type check ───────────────────────────────────────────────────── +if [[ -f "${REPO_ROOT}/frontend/package.json" ]]; then + echo "[pre-push] Checking TypeScript types ..." + if ! (cd "${REPO_ROOT}/frontend" && npx tsc --noEmit 2>/dev/null); then + echo "[pre-push] ❌ TypeScript type check FAILED." + FAILED=1 + fi +fi + +if [[ ${FAILED} -ne 0 ]]; then + echo "[pre-push] Push rejected — fix errors above before pushing." + exit 1 +fi + +echo "[pre-push] All checks passed ✓" diff --git a/tasks/lessons.md b/tasks/lessons.md index b938462..12714e7 100644 --- a/tasks/lessons.md +++ b/tasks/lessons.md @@ -65,3 +65,18 @@ The Docker container intercepted some jobs and ran them in its Alpine environmen **Fix:** Stopped Docker container runner. Switched to runs-on: ubuntu-latest with docker://ubuntu:24.04 containers. **Lesson:** Check for multiple runners with same name. Stop after 2 attempts and diagnose root cause. + +## 2026-05-05: Always Use Git → Gitea → Runner CI/CD Pipeline for Deployment +**Pattern:** When deploying code changes to any environment, always commit and push to Gitea and let the CI/CD pipeline handle building and deployment. +**Why:** Manually copying built files (scp, etc.) bypasses quality gates (format, clippy, test, lint) and is not reproducible. The CI pipeline ensures every change passes all checks before reaching any environment. +**Action:** Never manually copy files to servers. Always: commit → push to Gitea → let CI/CD run → deploy through proper pipeline. + +## 2026-05-05: Verify API Response Structure Matches Frontend Expectations +**Pattern:** When frontend data doesn't appear, check the API response structure before assuming the UI code is wrong. +**Why:** Health checks list was always empty because backend returns `{ checks: [...], total: N }` but frontend used `Array.isArray(res.data) ? res.data : []` which returned `[]` for an object. Maintenance windows worked because they correctly used `res.data?.windows ?? []`. +**Action:** When adding new API endpoints, verify the response wrapper structure matches what the frontend expects. Check existing working patterns (like maintenance windows) for the correct data extraction approach. + +## 2026-05-05: Run cargo fmt Before Pushing to Avoid CI Failures +**Pattern:** Always run `cargo fmt --all` locally before pushing Rust code changes. +**Why:** The CI pipeline has a Rust Format Check gate that will fail if code isn't formatted. This wastes CI runner time and delays deployment. +**Action:** Run `cargo fmt --all` as part of local pre-push checklist, alongside `npm run build` for frontend changes.