diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 6e4065777..3461943ea 100644 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -4,4 +4,4 @@ set -euo pipefail repo_root="$(git rev-parse --show-toplevel)" -"$repo_root/scripts/pre-commit.sh" \ No newline at end of file +"$repo_root/contrib/dev-tools/git/hooks/pre-commit.sh" \ No newline at end of file diff --git a/.github/agents/committer.agent.md b/.github/agents/committer.agent.md index 016ee2c0f..a8ef84b04 100644 --- a/.github/agents/committer.agent.md +++ b/.github/agents/committer.agent.md @@ -17,7 +17,7 @@ Treat every commit request as a review-and-verify workflow, not as a blind reque - Follow `AGENTS.md` for repository-wide behaviour and `.github/skills/dev/git-workflow/commit-changes/SKILL.md` for commit-specific reference details. -- The pre-commit validation command is `./scripts/pre-commit.sh`. +- The pre-commit validation command is `./contrib/dev-tools/git/hooks/pre-commit.sh`. - Create GPG-signed Conventional Commits (`git commit -S`). ## Required Workflow @@ -25,7 +25,7 @@ Treat every commit request as a review-and-verify workflow, not as a blind reque 1. Read the current branch, `git status`, and the staged or unstaged diff relevant to the request. 2. Summarize the intended commit scope before taking action. 3. Ensure the commit scope is coherent and does not accidentally mix unrelated changes. -4. Run `./scripts/pre-commit.sh` when feasible and fix issues that are directly related to the +4. Run `./contrib/dev-tools/git/hooks/pre-commit.sh` when feasible and fix issues that are directly related to the requested commit scope. 5. Propose a precise Conventional Commit message. 6. Create the commit with `git commit -S` only after the scope is clear and blockers are resolved. diff --git a/.github/agents/implementer.agent.md b/.github/agents/implementer.agent.md index a083a507c..a34033693 100644 --- a/.github/agents/implementer.agent.md +++ b/.github/agents/implementer.agent.md @@ -27,7 +27,7 @@ Reference: [Beck Design Rules](https://martinfowler.com/bliki/BeckDesignRules.ht ## Repository Rules - Follow `AGENTS.md` for repository-wide conventions. -- The pre-commit validation command is `./scripts/pre-commit.sh`. +- The pre-commit validation command is `./contrib/dev-tools/git/hooks/pre-commit.sh`. - Relevant skills to load when needed: - `.github/skills/dev/testing/write-unit-test/SKILL.md` — test naming and Arrange/Act/Assert pattern. - `.github/skills/dev/rust-code-quality/handle-errors-in-code/SKILL.md` — error handling. @@ -82,5 +82,5 @@ description of what was implemented. Do not commit directly — always delegate - Do not implement more than was asked — scope creep is a defect. - Do not suppress compiler warnings or clippy lints without a documented reason. - Do not add dependencies without running `cargo machete` afterward. -- Do not commit code that fails `./scripts/pre-commit.sh`. +- Do not commit code that fails `./contrib/dev-tools/git/hooks/pre-commit.sh`. - Do not skip the audit step, even for small changes. diff --git a/.github/skills/dev/git-workflow/commit-changes/SKILL.md b/.github/skills/dev/git-workflow/commit-changes/SKILL.md index 415ee2895..5d3995d54 100644 --- a/.github/skills/dev/git-workflow/commit-changes/SKILL.md +++ b/.github/skills/dev/git-workflow/commit-changes/SKILL.md @@ -14,13 +14,13 @@ This skill guides you through the complete commit process for the Torrust Tracke ```bash # One-time setup: install the pre-commit Git hook -./scripts/install-git-hooks.sh +./contrib/dev-tools/git/install-git-hooks.sh # Stage changes git add # Commit with conventional format and GPG signature (MANDATORY) -# The pre-commit hook runs ./scripts/pre-commit.sh automatically +# The pre-commit hook runs ./contrib/dev-tools/git/hooks/pre-commit.sh automatically git commit -S -m "[()]: " ``` @@ -66,11 +66,11 @@ git commit -S -m "your commit message" ### Git Hook -The repository ships a `pre-commit` Git hook that runs `./scripts/pre-commit.sh` +The repository ships a `pre-commit` Git hook that runs `./contrib/dev-tools/git/hooks/pre-commit.sh` automatically on every `git commit`. Install it once after cloning: ```bash -./scripts/install-git-hooks.sh +./contrib/dev-tools/git/install-git-hooks.sh ``` Once installed, the hook fires on every commit and you do not need to run the script manually. @@ -84,7 +84,7 @@ If the hook is not installed, run the script explicitly before committing. > command timeout of **at least 5 minutes** before invoking this script. ```bash -./scripts/pre-commit.sh +./contrib/dev-tools/git/hooks/pre-commit.sh ``` The script runs: diff --git a/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md b/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md index b0eb24e4d..371c27dfc 100644 --- a/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md +++ b/.github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md @@ -10,11 +10,11 @@ metadata: ## Git Hook (Recommended Setup) -The repository ships a `pre-commit` Git hook that runs `./scripts/pre-commit.sh` +The repository ships a `pre-commit` Git hook that runs `./contrib/dev-tools/git/hooks/pre-commit.sh` automatically on every `git commit`. Install it once after cloning: ```bash -./scripts/install-git-hooks.sh +./contrib/dev-tools/git/install-git-hooks.sh ``` After installation the hook fires automatically; you do not need to invoke the script @@ -23,14 +23,14 @@ manually before each commit. ## Automated Checks > **⏱️ Expected runtime: ~3 minutes** on a modern developer machine. AI agents must set a -> command timeout of **at least 5 minutes** before invoking `./scripts/pre-commit.sh`. Agents +> command timeout of **at least 5 minutes** before invoking `./contrib/dev-tools/git/hooks/pre-commit.sh`. Agents > with a default per-command timeout below 5 minutes will likely time out and report a false > failure. Run the pre-commit script. **It must exit with code `0` before every commit.** ```bash -./scripts/pre-commit.sh +./contrib/dev-tools/git/hooks/pre-commit.sh ``` The script runs these steps in order: diff --git a/.github/skills/dev/maintenance/setup-dev-environment/SKILL.md b/.github/skills/dev/maintenance/setup-dev-environment/SKILL.md index 1228611b5..dae36c068 100644 --- a/.github/skills/dev/maintenance/setup-dev-environment/SKILL.md +++ b/.github/skills/dev/maintenance/setup-dev-environment/SKILL.md @@ -72,10 +72,10 @@ cargo install cargo-machete # Unused dependency checker Install the project pre-commit hook (one-time, re-run after hook changes): ```bash -./scripts/install-git-hooks.sh +./contrib/dev-tools/git/install-git-hooks.sh ``` -The hook runs `./scripts/pre-commit.sh` automatically on every `git commit`. +The hook runs `./contrib/dev-tools/git/hooks/pre-commit.sh` automatically on every `git commit`. ## Step 8: Smoke Test diff --git a/.github/skills/dev/maintenance/update-dependencies/SKILL.md b/.github/skills/dev/maintenance/update-dependencies/SKILL.md index c0aa1c867..121c99fbb 100644 --- a/.github/skills/dev/maintenance/update-dependencies/SKILL.md +++ b/.github/skills/dev/maintenance/update-dependencies/SKILL.md @@ -37,7 +37,7 @@ cargo update 2>&1 | tee /tmp/cargo-update.txt # If Cargo.lock has no changes, nothing to do — stop here. # Verify -./scripts/pre-commit.sh +./contrib/dev-tools/git/hooks/pre-commit.sh # Commit and push git add Cargo.lock @@ -92,7 +92,7 @@ cargo update --precise {old-version} {crate-name} ```bash cargo machete -./scripts/pre-commit.sh +./contrib/dev-tools/git/hooks/pre-commit.sh ``` Fix any failures before proceeding. diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 2017038b9..4b9e90407 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -7,13 +7,13 @@ on: push: paths: - .github/workflows/copilot-setup-steps.yml - - scripts/install-git-hooks.sh - - scripts/pre-commit.sh + - contrib/dev-tools/git/install-git-hooks.sh + - contrib/dev-tools/git/hooks/pre-commit.sh pull_request: paths: - .github/workflows/copilot-setup-steps.yml - - scripts/install-git-hooks.sh - - scripts/pre-commit.sh + - contrib/dev-tools/git/install-git-hooks.sh + - contrib/dev-tools/git/hooks/pre-commit.sh jobs: # The job MUST be called `copilot-setup-steps` or it will not be picked up @@ -47,7 +47,7 @@ jobs: run: cargo install cargo-machete - name: Install Git pre-commit hooks - run: ./scripts/install-git-hooks.sh + run: ./contrib/dev-tools/git/install-git-hooks.sh - name: Smoke-check — run all linters run: linter all diff --git a/AGENTS.md b/AGENTS.md index 801bf8eef..4bcbe8459 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,7 +38,7 @@ native IPv4/IPv6 support, private/whitelisted mode, and a management REST API. - `packages/` — Cargo workspace packages (all domain logic lives here; see package catalog below) - `console/` — Console tools (e.g., `tracker-client`) - `contrib/` — Community-contributed utilities (`bencode`) and developer tooling -- `contrib/dev-tools/` — Developer tools: git hooks (`pre-commit.sh`, `pre-push.sh`), +- `contrib/dev-tools/` — Developer tools: git hooks (`pre-commit.sh`, `pre-push.sh`, `install-git-hooks.sh`), container scripts, and init scripts - `tests/` — Integration tests (`integration.rs`, `servers/`) - `docs/` — Project documentation, ADRs, issue specs, and benchmarking guides @@ -127,7 +127,7 @@ All packages live under `packages/`. The workspace version is `3.0.0-develop`. ```sh rustup show # Check active toolchain rustup update # Update toolchain -rustup toolchain install nightly # Optional: only needed for manual cargo +nightly doc; the repo hook runs ./scripts/pre-commit.sh +rustup toolchain install nightly # Optional: needed for manual cargo +nightly commands and the repo pre-push checks (fmt/check/doc) ``` ### Build diff --git a/contrib/dev-tools/git/hooks/pre-commit.sh b/contrib/dev-tools/git/hooks/pre-commit.sh index c1b183fde..b26bcdb1c 100755 --- a/contrib/dev-tools/git/hooks/pre-commit.sh +++ b/contrib/dev-tools/git/hooks/pre-commit.sh @@ -1,10 +1,83 @@ -#!/bin/bash - -cargo +nightly fmt --check && - cargo +nightly check --tests --benches --examples --workspace --all-targets --all-features && - cargo +nightly doc --no-deps --bins --examples --workspace --all-features && - cargo +nightly machete && - cargo +stable build && - CARGO_INCREMENTAL=0 cargo +stable clippy --no-deps --tests --benches --examples --workspace --all-targets --all-features -- -D clippy::correctness -D clippy::suspicious -D clippy::complexity -D clippy::perf -D clippy::style -D clippy::pedantic && - cargo +stable test --doc --workspace && - cargo +stable test --tests --benches --examples --workspace --all-targets --all-features +#!/usr/bin/env bash +# Pre-commit verification script +# Run all mandatory checks before committing changes. +# +# Usage: +# ./contrib/dev-tools/git/hooks/pre-commit.sh +# +# Expected runtime: ~3 minutes on a modern developer machine. +# AI agents: set a per-command timeout of at least 5 minutes before invoking this script. +# +# All steps must pass (exit 0) before committing. + +set -euo pipefail + +# ============================================================================ +# STEPS +# ============================================================================ +# Each step: "description|success_message|command" + +declare -a STEPS=( + "Checking for unused dependencies (cargo machete)|No unused dependencies found|cargo machete" + "Running all linters|All linters passed|linter all" + "Running documentation tests|Documentation tests passed|cargo test --doc --workspace" + "Running all tests|All tests passed|cargo test --tests --benches --examples --workspace --all-targets --all-features" +) + +# ============================================================================ +# HELPER FUNCTIONS +# ============================================================================ + +format_time() { + local total_seconds=$1 + local minutes=$((total_seconds / 60)) + local seconds=$((total_seconds % 60)) + if [ "$minutes" -gt 0 ]; then + echo "${minutes}m ${seconds}s" + else + echo "${seconds}s" + fi +} + +run_step() { + local step_number=$1 + local total_steps=$2 + local description=$3 + local success_message=$4 + local command=$5 + + echo "[Step ${step_number}/${total_steps}] ${description}..." + + local step_start=$SECONDS + local -a cmd_array + read -ra cmd_array <<< "${command}" + "${cmd_array[@]}" + local step_elapsed=$((SECONDS - step_start)) + + echo "PASSED: ${success_message} ($(format_time "${step_elapsed}"))" + echo +} + +trap 'echo ""; echo "=========================================="; echo "FAILED: Pre-commit checks failed!"; echo "Fix the errors above before committing."; echo "=========================================="; exit 1' ERR + +# ============================================================================ +# MAIN +# ============================================================================ + +TOTAL_START=$SECONDS +TOTAL_STEPS=${#STEPS[@]} + +echo "Running pre-commit checks..." +echo + +for i in "${!STEPS[@]}"; do + IFS='|' read -r description success_message command <<< "${STEPS[$i]}" + run_step $((i + 1)) "${TOTAL_STEPS}" "${description}" "${success_message}" "${command}" +done + +TOTAL_ELAPSED=$((SECONDS - TOTAL_START)) +echo "==========================================" +echo "SUCCESS: All pre-commit checks passed! ($(format_time "${TOTAL_ELAPSED}"))" +echo "==========================================" +echo +echo "You can now safely stage and commit your changes." diff --git a/contrib/dev-tools/git/hooks/pre-push.sh b/contrib/dev-tools/git/hooks/pre-push.sh index 593068cee..f03c6d5cd 100755 --- a/contrib/dev-tools/git/hooks/pre-push.sh +++ b/contrib/dev-tools/git/hooks/pre-push.sh @@ -1,11 +1,88 @@ -#!/bin/bash - -cargo +nightly fmt --check && - cargo +nightly check --tests --benches --examples --workspace --all-targets --all-features && - cargo +nightly doc --no-deps --bins --examples --workspace --all-features && - cargo +nightly machete && - cargo +stable build && - CARGO_INCREMENTAL=0 cargo +stable clippy --no-deps --tests --benches --examples --workspace --all-targets --all-features -- -D clippy::correctness -D clippy::suspicious -D clippy::complexity -D clippy::perf -D clippy::style -D clippy::pedantic && - cargo +stable test --doc --workspace && - cargo +stable test --tests --benches --examples --workspace --all-targets --all-features && - cargo +stable run --bin e2e_tests_runner -- --config-toml-path "./share/default/config/tracker.e2e.container.sqlite3.toml" +#!/usr/bin/env bash +# Pre-push verification script +# Run comprehensive checks before pushing changes, including nightly toolchain +# validation and end-to-end tests. +# +# Usage: +# ./contrib/dev-tools/git/hooks/pre-push.sh +# +# Expected runtime: ~15 minutes on a modern developer machine. +# AI agents: set a per-command timeout of at least 30 minutes before invoking this script. +# +# All steps must pass (exit 0) before pushing. + +set -euo pipefail + +# ============================================================================ +# STEPS +# ============================================================================ +# Each step: "description|success_message|command" + +declare -a STEPS=( + "Checking for unused dependencies (cargo machete)|No unused dependencies found|cargo +stable machete" + "Running all linters|All linters passed|linter all" + "Checking format with nightly toolchain|Nightly format check passed|cargo +nightly fmt --check" + "Checking workspace with nightly toolchain|Nightly check passed|cargo +nightly check --tests --benches --examples --workspace --all-targets --all-features" + "Building documentation with nightly toolchain|Nightly documentation built|cargo +nightly doc --no-deps --bins --examples --workspace --all-features" + "Running documentation tests|Documentation tests passed|cargo +stable test --doc --workspace" + "Running all tests|All tests passed|cargo +stable test --tests --benches --examples --workspace --all-targets --all-features" + "Running E2E tests|E2E tests passed|cargo +stable run --bin e2e_tests_runner -- --config-toml-path ./share/default/config/tracker.e2e.container.sqlite3.toml" +) + +# ============================================================================ +# HELPER FUNCTIONS +# ============================================================================ + +format_time() { + local total_seconds=$1 + local minutes=$((total_seconds / 60)) + local seconds=$((total_seconds % 60)) + if [ "$minutes" -gt 0 ]; then + echo "${minutes}m ${seconds}s" + else + echo "${seconds}s" + fi +} + +run_step() { + local step_number=$1 + local total_steps=$2 + local description=$3 + local success_message=$4 + local command=$5 + + echo "[Step ${step_number}/${total_steps}] ${description}..." + + local step_start=$SECONDS + local -a cmd_array + read -ra cmd_array <<< "${command}" + "${cmd_array[@]}" + local step_elapsed=$((SECONDS - step_start)) + + echo "PASSED: ${success_message} ($(format_time "${step_elapsed}"))" + echo +} + +trap 'echo ""; echo "=========================================="; echo "FAILED: Pre-push checks failed!"; echo "Fix the errors above before pushing."; echo "=========================================="; exit 1' ERR + +# ============================================================================ +# MAIN +# ============================================================================ + +TOTAL_START=$SECONDS +TOTAL_STEPS=${#STEPS[@]} + +echo "Running pre-push checks..." +echo + +for i in "${!STEPS[@]}"; do + IFS='|' read -r description success_message command <<< "${STEPS[$i]}" + run_step $((i + 1)) "${TOTAL_STEPS}" "${description}" "${success_message}" "${command}" +done + +TOTAL_ELAPSED=$((SECONDS - TOTAL_START)) +echo "==========================================" +echo "SUCCESS: All pre-push checks passed! ($(format_time "${TOTAL_ELAPSED}"))" +echo "==========================================" +echo +echo "You can now safely push your changes." diff --git a/scripts/install-git-hooks.sh b/contrib/dev-tools/git/install-git-hooks.sh similarity index 94% rename from scripts/install-git-hooks.sh rename to contrib/dev-tools/git/install-git-hooks.sh index 478377791..16de7fe5a 100755 --- a/scripts/install-git-hooks.sh +++ b/contrib/dev-tools/git/install-git-hooks.sh @@ -2,7 +2,7 @@ # Install project Git hooks from .githooks/ into .git/hooks/. # # Usage: -# ./scripts/install-git-hooks.sh +# ./contrib/dev-tools/git/install-git-hooks.sh # # Run once after cloning the repository. Re-run to update hooks after # they change. diff --git a/docs/issues/1697-ai-agent-configuration.md b/docs/issues/1697-ai-agent-configuration.md index 925f04ea5..3d38eb003 100644 --- a/docs/issues/1697-ai-agent-configuration.md +++ b/docs/issues/1697-ai-agent-configuration.md @@ -197,7 +197,7 @@ tasks can be delegated to focused agents with the right prompt context. **Candidate initial agents**: - `committer` ✅ — commit specialist: reads branch/diff, runs pre-commit checks - (`./scripts/pre-commit.sh`), proposes a GPG-signed Conventional Commit message, and creates + (`./contrib/dev-tools/git/hooks/pre-commit.sh`), proposes a GPG-signed Conventional Commit message, and creates the commit only after scope and checks are clear. Reference: [`torrust-tracker-demo/.github/agents/commiter.agent.md`](https://raw.githubusercontent.com/torrust/torrust-tracker-demo/refs/heads/main/.github/agents/commiter.agent.md) - `implementer` ✅ — software implementer that applies Test-Driven Development and seeks the @@ -277,7 +277,7 @@ Minimum steps to include: - [x] Install `cargo-machete` — `cargo install cargo-machete`; ensures Copilot can run unused dependency checks (`cargo machete`) as required by the essential rules - [x] Smoke-check: run `linter all` to confirm the environment is healthy before Copilot begins -- [x] Install Git pre-commit hooks — `./scripts/install-git-hooks.sh` +- [x] Install Git pre-commit hooks — `./contrib/dev-tools/git/install-git-hooks.sh` Commit message: `ci(copilot): add copilot-setup-steps workflow` diff --git a/scripts/pre-commit.sh b/scripts/pre-commit.sh deleted file mode 100755 index c360ad6b6..000000000 --- a/scripts/pre-commit.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash -# Pre-commit verification script -# Run all mandatory checks before committing changes. -# -# Usage: -# ./scripts/pre-commit.sh -# -# Expected runtime: ~3 minutes on a modern developer machine. -# AI agents: set a per-command timeout of at least 5 minutes before invoking this script. -# -# All steps must pass (exit 0) before committing. - -set -euo pipefail - -# ============================================================================ -# STEPS -# ============================================================================ -# Each step: "description|success_message|command" - -declare -a STEPS=( - "Checking for unused dependencies (cargo machete)|No unused dependencies found|cargo machete" - "Running all linters|All linters passed|linter all" - "Running documentation tests|Documentation tests passed|cargo test --doc --workspace" - "Running all tests|All tests passed|cargo test --tests --benches --examples --workspace --all-targets --all-features" -) - -# ============================================================================ -# HELPER FUNCTIONS -# ============================================================================ - -format_time() { - local total_seconds=$1 - local minutes=$((total_seconds / 60)) - local seconds=$((total_seconds % 60)) - if [ "$minutes" -gt 0 ]; then - echo "${minutes}m ${seconds}s" - else - echo "${seconds}s" - fi -} - -run_step() { - local step_number=$1 - local total_steps=$2 - local description=$3 - local success_message=$4 - local command=$5 - - echo "[Step ${step_number}/${total_steps}] ${description}..." - - local step_start=$SECONDS - local -a cmd_array - read -ra cmd_array <<< "${command}" - "${cmd_array[@]}" - local step_elapsed=$((SECONDS - step_start)) - - echo "PASSED: ${success_message} ($(format_time "${step_elapsed}"))" - echo -} - -trap 'echo ""; echo "=========================================="; echo "FAILED: Pre-commit checks failed!"; echo "Fix the errors above before committing."; echo "=========================================="; exit 1' ERR - -# ============================================================================ -# MAIN -# ============================================================================ - -TOTAL_START=$SECONDS -TOTAL_STEPS=${#STEPS[@]} - -echo "Running pre-commit checks..." -echo - -for i in "${!STEPS[@]}"; do - IFS='|' read -r description success_message command <<< "${STEPS[$i]}" - run_step $((i + 1)) "${TOTAL_STEPS}" "${description}" "${success_message}" "${command}" -done - -TOTAL_ELAPSED=$((SECONDS - TOTAL_START)) -echo "==========================================" -echo "SUCCESS: All pre-commit checks passed! ($(format_time "${TOTAL_ELAPSED}"))" -echo "==========================================" -echo -echo "You can now safely stage and commit your changes."