diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..71666083 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[*.go] +indent_style = tab + +[Makefile] +indent_style = tab + +[{go.mod,go.sum}] +indent_style = tab + +[*.{md,markdown}] +trim_trailing_whitespace = false diff --git a/.githooks/commit-msg b/.githooks/commit-msg new file mode 100755 index 00000000..28cc78cb --- /dev/null +++ b/.githooks/commit-msg @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# commit-msg hook: enforce DCO sign-off and ≤72-char subject locally so we +# don't burn a CI cycle (or push, see the maintainer's mood drop) discovering +# either after the fact. Skips git-managed commit shapes (Merge, fixup!, +# squash!, amend!) where the rules don't apply or git rewrites the message. +# Bypass with `git commit --no-verify` if you must — CI still checks. +set -euo pipefail + +msg_file="$1" +[ -f "$msg_file" ] || exit 0 + +# First non-comment line is the subject (`git commit -v` prepends comments). +subject=$(grep -v '^#' "$msg_file" | head -n 1) + +case "$subject" in + Merge*|fixup!*|squash!*|amend!*) exit 0 ;; +esac + +# Subject length — see STYLE.md §"Commits". +subject_len=${#subject} +if [ "$subject_len" -gt 72 ]; then + echo "ERROR: commit subject is $subject_len chars (limit: 72)." >&2 + echo " Subject: $subject" >&2 + echo " Trim the subject; put detail in the body." >&2 + exit 1 +fi + +# DCO sign-off — mirrors the rules enforced by .github/scripts/dco-check.sh +# (the CI gate). Keep this check in sync if that script changes. +if ! grep -q '^Signed-off-by: ' "$msg_file"; then + echo "ERROR: missing Signed-off-by trailer." >&2 + echo " Use 'git commit -s' to add it, or amend with --signoff." >&2 + echo " See CONTRIBUTING.md §'Sign off your commits'." >&2 + exit 1 +fi + +exit 0 diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000..e28b0af6 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Pre-commit hook: run `make check` to keep the inner loop honest. +# Installed by `make hooks`, which sets core.hooksPath to .githooks. +# Bypass with `git commit --no-verify` if you must — CI will still catch you. +set -euo pipefail +exec make check diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 00000000..34b464fd --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# pre-push hook: run `make ci` so the moment of truth is `git push`, not the +# wait for GitHub Actions. Catches what `make check` (the pre-commit gate) +# deliberately skips: license-check, full build, govulncheck-adjacent checks. +# Bypass with `git push --no-verify` if you must — CI will still catch you. +set -euo pipefail +exec make ci diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..f75f2c8a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,58 @@ +--- +name: Bug report +about: Report something that isn't working +title: '' +labels: bug +--- + + + +## What happened + + + +## What you expected + + + +## Reproduction + + + +```yaml +# minimal config here +``` + +```sh +# commands here +``` + +## Environment + +- tracecore version (`tracecore --version`): +- OS / kernel: +- Go version (`go version`) — only if building from source: +- GPU / driver / NCCL versions — only if relevant to the bug: + +## Logs + + + +``` +logs here +``` + +## Additional context + + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..2c0b74cc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: Architectural proposal (RFC) + url: https://github.com/TraceCoreAI/tracecore/blob/main/docs/rfcs/0000-template.md + about: Architectural decisions go through the RFC process. Copy the template into docs/rfcs/ and open a PR — not an issue. + - name: Security vulnerability + url: https://github.com/TraceCoreAI/tracecore/security/advisories/new + about: Report vulnerabilities privately, never as public issues. See SECURITY.md. + - name: Question or discussion + url: https://github.com/TraceCoreAI/tracecore/discussions + about: For open-ended questions and design discussion. Bugs and feature requests belong in issues. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..149b9488 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,48 @@ +--- +name: Feature request +about: Suggest a new feature or enhancement +title: '' +labels: enhancement +--- + + + +## Problem + + + +## Proposal + + + +## Alternatives considered + + + +## Out of scope + + + +## Additional context + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index eaac3f29..242863a3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,9 @@ ## What this PR does @@ -9,9 +12,13 @@ before submitting. Keep PRs under 500 lines and focused on one concern. ## Linked issue(s) - + -Fixes # +_No linked issue._ ## Release notes @@ -28,7 +35,8 @@ Categories: FEATURE, ENHANCEMENT, BUGFIX, PERF, SECURITY, CHANGE ## Checklist - [ ] Tests added or updated -- [ ] `make ci` passes locally +- [ ] `make check` runs green continuously while editing; `make ci` passes before pushing - [ ] Commits are signed off (`git commit -s`) - [ ] If AI-assisted, commit message includes `Assisted-by:` trailer (see [`AGENTS.md`](../AGENTS.md)) - [ ] For new components, follows the layout required by [`STYLE.md`](../STYLE.md) +- [ ] PR title and Summary still reflect the current diff (re-check after pushing fixes) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9a1ed27f..7c1c1572 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ When you choose to file one: All developer tools (gofumpt, goimports, golangci-lint, govulncheck, addlicense) are pinned in `go.mod` under the `tool` directive and fetched automatically. There is no separate `install-tools` step. ```sh -go mod download # one-time after clone +scripts/setup-dev.sh # one-shot: go mod download + install all hooks make build # builds ./tracecore make test # unit tests with race detector make lint # runs golangci-lint @@ -31,7 +31,13 @@ make check # fast inner loop: fmt + tidy-check + lint + test make ci # what CI runs: license-check + vet + tidy-check + lint + test + build ``` -Use `make check` continuously while editing; use `make ci` once before pushing. +`scripts/setup-dev.sh` is idempotent — rerun it whenever. It installs three hooks (opt-in via `core.hooksPath = .githooks`) so problems surface before they hit CI: + +- **`pre-commit`** runs `make check` — fmt, tidy, lint, race-tested tests. +- **`commit-msg`** enforces the ≤72-char subject and DCO sign-off rules from STYLE.md §"Commits". +- **`pre-push`** runs `make ci` — the full gate CI runs, locally, before the network round-trip. + +Bypass any hook with `--no-verify` if you must (`git commit --no-verify`, `git push --no-verify`); CI still catches what you skip. ## Pull requests diff --git a/Makefile b/Makefile index 292016aa..85157115 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help build run test fmt fmt-fix vet lint lint-fix tidy tidy-check mod-verify license-check license-fix govulncheck dco-check ai-review clean check ci +.PHONY: help build run test fmt fmt-fix vet lint lint-fix tidy tidy-check mod-verify license-check license-fix govulncheck dco-check ai-review hooks clean check ci BIN := tracecore PKG := ./cmd/tracecore @@ -93,6 +93,14 @@ dco-check: ## Verify DCO sign-off on every commit since origin/main. ai-review: ## Run advisory Claude review on staged Go changes (never blocks). @scripts/ai-review.sh +hooks: ## Install repo-managed Git hooks (sets core.hooksPath to .githooks). + @git config core.hooksPath .githooks + @echo "Hooks installed under .githooks/ — all three now active:" + @echo " pre-commit -> make check (fmt, tidy-check, lint, test)" + @echo " commit-msg -> ≤72-char subject + DCO sign-off" + @echo " pre-push -> make ci (full gate)" + @echo "Bypass any one with --no-verify; CI still catches what you skip." + clean: ## Remove built binaries. rm -f $(BIN) go clean diff --git a/scripts/setup-dev.sh b/scripts/setup-dev.sh new file mode 100755 index 00000000..aa7d2b60 --- /dev/null +++ b/scripts/setup-dev.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# One-shot dev environment bootstrap. Run after cloning. Idempotent — +# rerunning is safe and only re-applies what changed. +set -euo pipefail + +cd "$(git rev-parse --show-toplevel)" + +if ! command -v go >/dev/null 2>&1; then + required=$(cat .go-version 2>/dev/null || echo "see .go-version") + echo "ERROR: Go is not installed or not on PATH." >&2 + echo " Required version: $required" >&2 + echo " Install from https://go.dev/dl/ or via your package manager." >&2 + exit 1 +fi + +echo "==> Downloading Go modules..." +go mod download + +echo "==> Installing Git hooks..." +make hooks + +cat <<'EOF' + +Setup complete. The hooks now run automatically: + pre-commit -> make check (fmt, tidy-check, lint, test) + commit-msg -> DCO sign-off + subject length + pre-push -> make ci (license, vet, lint, tidy, test, build) + +Manual commands you'll still want: + make check fast inner loop (~10s) + make ci full pre-push gate (~30s) + make help every target with one-line docs +EOF