Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/agents/committer.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ 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 `./contrib/dev-tools/git/hooks/pre-commit.sh`.
- For AI execution, prefer `./contrib/dev-tools/git/hooks/pre-commit.sh --format=json` first,
and retry with `./contrib/dev-tools/git/hooks/pre-commit.sh --format=text --verbosity=verbose`
when deeper diagnostics are needed.
- Create GPG-signed Conventional Commits (`git commit -S`).

## Required Workflow
Expand All @@ -34,7 +37,8 @@ Treat every commit request as a review-and-verify workflow, not as a blind reque
5. Check for obvious repository-policy violations in the diff (for example missing required spec
progress updates, missing documented rationale where required, or similar policy blockers).
If found, stop and return to the Implementer/Reviewer before committing.
6. Run `./contrib/dev-tools/git/hooks/pre-commit.sh` when feasible. If it fails:
6. Run `./contrib/dev-tools/git/hooks/pre-commit.sh` when feasible. For AI execution, use
`--format=json` first and retry with `--format=text --verbosity=verbose` if needed. If it fails:
- **You may fix**: formatting, linting, spell-check, import organization, and similar
metadata-only issues that are direct artifacts of the commit scope.
- **You must not fix**: build failures, test failures, logic errors, or runtime issues.
Expand Down
3 changes: 3 additions & 0 deletions .github/agents/implementer.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ Reference: [Beck Design Rules](https://martinfowler.com/bliki/BeckDesignRules.ht

- Follow `AGENTS.md` for repository-wide conventions.
- The pre-commit validation command is `./contrib/dev-tools/git/hooks/pre-commit.sh`.
- For AI execution, prefer `./contrib/dev-tools/git/hooks/pre-commit.sh --format=json` first,
and retry with `./contrib/dev-tools/git/hooks/pre-commit.sh --format=text --verbosity=verbose`
when deeper diagnostics are needed.
- Relevant skills to load when needed:
- `.github/skills/dev/maintenance/add-rust-dependency/SKILL.md` — adding new Rust dependencies safely.
- `.github/skills/dev/testing/write-unit-test/SKILL.md` — test naming and Arrange/Act/Assert pattern.
Expand Down
17 changes: 14 additions & 3 deletions .github/skills/dev/git-workflow/commit-changes/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ Once installed, the hook fires on every commit and you do not need to run the sc
If the hook is not installed, run the script explicitly before committing.
**It must exit with code `0`.**

> **⏱️ Expected runtime: ~3 minutes** on a modern developer machine. AI agents must set a
> command timeout of **at least 5 minutes** before invoking this script.
> **⏱️ Expected runtime: ~1 minute** on a modern developer machine with warm caches.
> AI agents should set a command timeout of **at least 3 minutes** before invoking this script.

```bash
./contrib/dev-tools/git/hooks/pre-commit.sh
Expand All @@ -92,7 +92,18 @@ The script runs:
1. `cargo machete` — unused dependency check
2. `linter all` — all linters (markdown, YAML, TOML, clippy, rustfmt, shellcheck, cspell)
3. `cargo test --doc --workspace` — documentation tests
4. `cargo test --tests --benches --examples --workspace --all-targets --all-features` — all tests

For AI execution, prefer structured output first:

```bash
./contrib/dev-tools/git/hooks/pre-commit.sh --format=json
```

If it fails and deeper diagnostics are needed, retry with:

```bash
./contrib/dev-tools/git/hooks/pre-commit.sh --format=text --verbosity=verbose
```

### Manual Checks (Cannot Be Automated)

Expand Down
74 changes: 66 additions & 8 deletions .github/skills/dev/git-workflow/run-pre-commit-checks/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ 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 `./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.
> **⏱️ Expected runtime: ~1 minute** on a modern developer machine with warm caches.
> AI agents should set a command timeout of **at least 3 minutes** before invoking
> `./contrib/dev-tools/git/hooks/pre-commit.sh`.

Run the pre-commit script. **It must exit with code `0` before every commit.**

Expand All @@ -35,10 +34,60 @@ Run the pre-commit script. **It must exit with code `0` before every commit.**

The script runs these steps in order:

1. `cargo machete` — unused dependency check
2. `linter all` — all linters (markdown, YAML, TOML, clippy, rustfmt, shellcheck, cspell)
3. `cargo test --doc --workspace` — documentation tests
4. `cargo test --tests --benches --examples --workspace --all-targets --all-features` — all tests
1. `cargo machete` - unused dependency check
2. `linter all` - all linters (markdown, YAML, TOML, clippy, rustfmt, shellcheck, cspell)
3. `cargo test --doc --workspace` - documentation tests

## Output Modes

The pre-commit script supports concise human output, verbose human output, and JSON output for
automation.

```bash
# Default: text + concise
./contrib/dev-tools/git/hooks/pre-commit.sh

# Explicit text + concise
./contrib/dev-tools/git/hooks/pre-commit.sh --format=text --verbosity=concise

# Text + verbose streaming command output
./contrib/dev-tools/git/hooks/pre-commit.sh --format=text --verbosity=verbose

# Compatibility alias
./contrib/dev-tools/git/hooks/pre-commit.sh --format=text --verbose

# Structured output (single JSON document to stdout)
./contrib/dev-tools/git/hooks/pre-commit.sh --format=json
```

Flag behavior:

- `--format=<text|json>` defaults to `text`
- `--verbosity=<concise|verbose>` defaults to `concise`
- `--verbose` is an alias for `--verbosity=verbose`
- Duplicate `--format`/`--verbosity` flags: last value wins
- Invalid values or unknown flags exit with code `2` and print usage guidance to stderr
- In `--format=json`, structured output remains JSON regardless of verbosity value
- Per-step logs are written to `PRE_COMMIT_LOG_DIR` (default: `/tmp`)

For restricted agent environments that cannot write outside the workspace, run with:

```bash
PRE_COMMIT_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh
```

The `.tmp/` directory is git-ignored.
Because `.tmp/` is workspace-local, clean stale `pre-commit-*.log` files periodically.

## Check Tier Ownership

Check ownership is intentionally split by gate:

- Pre-commit: fast local gate (`cargo machete`, `linter all`, `cargo test --doc --workspace`)
- Pre-push: comprehensive developer gate (nightly format/check/doc + stable tests + E2E)
- CI: merge authority with full validation and E2E matrix jobs

E2E is intentionally excluded from pre-commit and remains a pre-push/CI responsibility.

> **MySQL tests**: MySQL-specific tests require a running instance and a feature flag:
>
Expand All @@ -63,6 +112,15 @@ Verify these by hand before committing:
cargo +nightly doc --no-deps --bins --examples --workspace --all-features
```

## Troubleshooting Output Modes

- Concise mode shows high-signal per-step summaries only. On failure, it prints the log path and
a short failure tail.
- Verbose mode streams full command output to the terminal. Use this for deep local debugging.
- JSON mode emits one structured document to stdout; diagnostics and usage errors go to stderr.
- If concise output is too short for debugging, re-run the same command with
`--format=text --verbosity=verbose`.

## Debugging Individual Linters

Run individual linters to isolate a failure:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,13 @@ After editing `Cargo.toml`/`Cargo.lock`:
```bash
cargo update -p <crate-name>
cargo machete
./contrib/dev-tools/git/hooks/pre-commit.sh
./contrib/dev-tools/git/hooks/pre-commit.sh --format=json
```

If the run fails and more diagnostics are needed, retry with:

```bash
./contrib/dev-tools/git/hooks/pre-commit.sh --format=text --verbosity=verbose
```

If checks fail, resolve issues or revert the dependency addition.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ Install the project pre-commit hook (one-time, re-run after hook changes):
```

The hook runs `./contrib/dev-tools/git/hooks/pre-commit.sh` automatically on every `git commit`.
If an AI agent runs the command manually, prefer:

```bash
./contrib/dev-tools/git/hooks/pre-commit.sh --format=json
```

Retry with `--format=text --verbosity=verbose` only when deeper diagnostics are needed.

## Step 8: Smoke Test

Expand Down
10 changes: 8 additions & 2 deletions .github/skills/dev/maintenance/update-dependencies/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ cargo update 2>&1 | tee /tmp/cargo-update.txt
# If Cargo.lock has no changes, nothing to do — stop here.

# Verify
./contrib/dev-tools/git/hooks/pre-commit.sh
./contrib/dev-tools/git/hooks/pre-commit.sh --format=json

# Commit and push
git add Cargo.lock
Expand Down Expand Up @@ -95,7 +95,13 @@ cargo update --precise {old-version} {crate-name}

```bash
cargo machete
./contrib/dev-tools/git/hooks/pre-commit.sh
./contrib/dev-tools/git/hooks/pre-commit.sh --format=json
```

If the run fails and deeper diagnostics are needed, retry with:

```bash
./contrib/dev-tools/git/hooks/pre-commit.sh --format=text --verbosity=verbose
```

Fix any failures before proceeding.
Expand Down
20 changes: 20 additions & 0 deletions .github/skills/dev/pr-reviews/fetch-review-threads/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ description: Fetch unresolved GitHub pull request review thread IDs for the torr
metadata:
author: torrust
version: "1.0"
semantic-links:
related-artifacts:
- .github/skills/dev/pr-reviews/fetch-review-threads/scripts/get-pr-review-threads.sh
- .github/skills/dev/pr-reviews/fetch-review-threads/scripts/list-unresolved-threads.sh
---

# Fetching PR Review Threads
Expand Down Expand Up @@ -48,6 +52,22 @@ Only unresolved threads should be considered for follow-up work.

Use GitHub CLI if you need to retrieve threads directly from the terminal.

## Available Scripts

- `scripts/get-pr-review-threads.sh` - Fetches review threads into a JSON file.
- `scripts/list-unresolved-threads.sh` - Emits unresolved threads as JSON lines.

Recommended usage:

```bash
bash scripts/get-pr-review-threads.sh \
--pr-number 1707 \
--output-file /tmp/pr_threads_1707.json

bash scripts/list-unresolved-threads.sh \
--threads-file /tmp/pr_threads_1707.json
```

```bash
gh api graphql \
-F owner=torrust \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/env bash

set -euo pipefail

usage() {
cat <<'EOF'
Usage: get-pr-review-threads.sh --pr-number <number> [--output-file <path>] [--owner <owner>] [--repo <repo>]

Fetch pull-request review threads and write full JSON response to an output file.

Options:
--pr-number <number> Pull request number (required)
--output-file <path> Output JSON file (default: /tmp/pr_threads_<PR_NUMBER>.json)
--owner <owner> Repository owner (default: torrust)
--repo <repo> Repository name (default: torrust-tracker)
-h, --help Show this help

Output:
- Writes GraphQL response JSON to --output-file
- Writes a small summary JSON object to stdout
- Writes diagnostics to stderr
EOF
}

OWNER="torrust"
REPO="torrust-tracker"
PR_NUMBER=""
OUTPUT_FILE=""

while [[ $# -gt 0 ]]; do
case "$1" in
--pr-number)
PR_NUMBER=${2:-}
shift 2
;;
--output-file)
OUTPUT_FILE=${2:-}
shift 2
;;
--owner)
OWNER=${2:-}
shift 2
;;
--repo)
REPO=${2:-}
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Error: unknown argument '$1'." >&2
usage >&2
exit 2
;;
esac
done

if [[ -z "${PR_NUMBER}" ]]; then
echo "Error: --pr-number is required." >&2
usage >&2
exit 2
fi

if [[ -z "${OUTPUT_FILE}" ]]; then
OUTPUT_FILE="/tmp/pr_threads_${PR_NUMBER}.json"
fi

echo "Fetching review threads for ${OWNER}/${REPO} PR #${PR_NUMBER}..." >&2
# shellcheck disable=SC2016
gh api graphql \
-F owner="${OWNER}" \
-F repo="${REPO}" \
-F pullNumber="${PR_NUMBER}" \
-f query='query($owner: String!, $repo: String!, $pullNumber: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pullNumber) {
reviewThreads(first: 100) {
nodes {
id
isResolved
isOutdated
path
isCollapsed
comments(first: 20) {
nodes {
url
body
createdAt
author {
login
}
}
}
}
}
}
}
}' > "${OUTPUT_FILE}"

printf '{"status":"ok","pr_number":%s,"output_file":"%s"}\n' "${PR_NUMBER}" "${OUTPUT_FILE}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash

set -euo pipefail

usage() {
cat <<'EOF'
Usage: list-unresolved-threads.sh --threads-file <path>

List unresolved review threads as JSON lines.

Options:
--threads-file <path> Path to review threads JSON file (required)
-h, --help Show this help
EOF
}

THREADS_FILE=""

while [[ $# -gt 0 ]]; do
case "$1" in
--threads-file)
THREADS_FILE=${2:-}
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Error: unknown argument '$1'." >&2
usage >&2
exit 2
;;
esac
done

if [[ -z "${THREADS_FILE}" ]]; then
echo "Error: --threads-file is required." >&2
usage >&2
exit 2
fi

jq -c '.data.repository.pullRequest.reviewThreads.nodes[]
| select(.isResolved == false)
| {
id,
isOutdated,
path,
url: (.comments.nodes[0].url // null)
}' "${THREADS_FILE}"
Loading
Loading