From 79dc1f0a7a0aa52510a20774d9c859c723af68e0 Mon Sep 17 00:00:00 2001 From: dimitar Date: Sun, 2 Aug 2026 09:32:23 +0200 Subject: [PATCH] docs: comprehensive build & run guide (buildAndRun.md) --- buildAndRun.md | 473 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 473 insertions(+) create mode 100644 buildAndRun.md diff --git a/buildAndRun.md b/buildAndRun.md new file mode 100644 index 0000000..83c9fad --- /dev/null +++ b/buildAndRun.md @@ -0,0 +1,473 @@ +# gitflow — Build & Run Guide + +## Prerequisites + +| Requirement | Minimum | Check with | +|---|---|---| +| Go toolchain | 1.24 | `go version` | +| Git | any recent | `git --version` | +| `make` (optional) | — | `make --version` | +| `golangci-lint` (optional) | any recent | `golangci-lint --version` | + +Linux, macOS, and Windows (WSL / MSYS2) are supported. The binary compiles +for all three platforms (ARM64 on macOS verified). + +## Quick start + +```bash +# Clone +git clone https://gitea.oblak.solutions/dimitar/gitFlow.git +cd gitFlow + +# Build (either method) +make build # produces ./gitflow +# or +go build -o gitflow ./cmd/gitflow + +# Run +./gitflow version # → "gitflow dev" +./gitflow scan # scans $PWD, asks for directory if stdin is a tty +./gitflow scan -d ~/projects +``` + +## Make targets + +```makefile +make build # compile the binary, injects VERSION via ldflags +make test # run the full test suite (go test ./...) +make fmt # format all Go sources (gofmt) +make vet # run go vet over all packages +make lint # run golangci-lint (needs it on PATH) +make install # install into $GOPATH/bin (or $GOBIN) +make clean # remove the binary and coverage output +``` + +**Stamped version** (optional): + +```bash +VERSION=v2.0.1 make build +./gitflow version # → "gitflow v2.0.1" +``` + +## Commands + +| Command | Purpose | +|---|---| +| `scan` | One-shot scan of repos under `--dir`, render and exit | +| `watch` | Rescan every `--interval`, detect changes, notify, fire webhooks | +| `tui` | Interactive terminal UI (bubbletea) with navigation, detail pane, AI panel | +| `config` | Print the resolved configuration (flags + env + file merged) | +| `completion` | Emit shell completions for bash, zsh, fish, or PowerShell | +| `version` | Print version and exit | + +Every command accepts the same flag set. Use `gitflow --help` for +the full list. + +### `scan` — single pass + +```bash +gitflow scan # prompt for dir, table output +gitflow scan -d ~/projects # explicit dir +gitflow scan -d ~/projects -f json # JSON to stdout, no human-facing sections +gitflow scan -d ~ --exclude node_modules --exclude vendor +gitflow scan -d ~/projects --max-depth 2 --workers 16 +``` + +### `watch` — periodic scan + +```bash +gitflow watch -d ~/projects -i 30s # scan every 30 seconds +gitflow watch -d ~/projects -i 5m --notify # also fire desktop notifications +gitflow watch -d ~/projects -i 1m --theme=light --color=always +``` + +Webhooks fire automatically when a `webhooks:` section exists in your +config file (no flag needed — they are config-only, like custom rules). + +### `tui` — interactive terminal UI + +```bash +gitflow tui -d ~/projects # one-shot scan, browse with j/k +gitflow tui -d ~/projects -i 30s # periodic scan, countdown in bar +gitflow tui -d ~/projects --ai --ai-provider ollama +``` + +**TUI keybindings:** + +``` +↑/↓ or j/k navigate repository list +g / Home jump to top +G / End jump to bottom +Enter / Space toggle detail pane for selected repo +r trigger immediate rescan +a toggle AI suggestion panel (requires --ai) +? toggle help overlay +q / Ctrl-C quit +``` + +### `config` — show effective configuration + +```bash +gitflow config # defaults +gitflow config -d /tmp -f compact # with flag overrides +GITFLOW_DIR=/tmp gitflow config # with env overrides +``` + +### `completion` — shell integration + +```bash +# bash +eval "$(gitflow completion bash)" + +# zsh +gitflow completion zsh > ~/.zsh/completion/_gitflow + +# fish +gitflow completion fish > ~/.config/fish/completions/gitflow.fish + +# powershell +gitflow completion powershell > gitflow.ps1 +``` + +## Configuration + +Settings resolve with this precedence (highest first): + +1. **CLI flags** — `--dir`, `--format`, etc. +2. **Environment variables** — `GITFLOW_` prefix, dots replaced by + underscores: `GITFLOW_DIR`, `GITFLOW_FORMAT`, `GITFLOW_AI_PROVIDER`, … +3. **Config file** — `~/.gitflow.yaml` (or `./.gitflow.yaml`); override + the path with `GITFLOW_CONFIG=/some/path.yaml` +4. **Built-in defaults** — `.` directory, `table` format, `auto` color, + `dark` theme, 8 workers, AI disabled, etc. + +### Complete config file reference + +```yaml +# ~/.gitflow.yaml +dir: ~/projects +interval: 5m +format: table # table | json | compact +color: auto # auto | always | never +theme: dark # dark | light +notify: true # desktop notifications (linux notify-send, macOS osascript) +max_depth: 3 # 0 = unlimited +workers: 8 +exclude: # glob patterns matched against base name and full path + - node_modules + - vendor + - ".cache" + +# AI agent (requires --ai flag or enabled: true) +ai: + enabled: false + provider: openai # openai | ollama | anthropic + model: gpt-4o # empty → provider default (ollama: llama3.2, anthropic: claude-3-5-haiku-latest) + api_key_env: OPENAI_API_KEY + base_url: "" # override provider endpoint; empty → vendor default + execute: false # run confirmed AI commands (experimental, allowlist-guarded) + +# Custom threshold rules +rules: + - name: stale-branch + field: behind # ahead | behind | stash | changes + op: ">=" # == | != | < | <= | > | >= + value: 10 + label: stale + - name: dirty-workspace + field: changes + op: ">=" + value: 1 + label: dirty + +# Webhooks (config-file-only, no CLI flags) +webhooks: + - name: team-slack + type: slack # slack | discord | generic + url: https://hooks.slack.com/services/T00/B00/TOKEN + on_change_only: true # skip when nothing changed + min_priority: 0 # 0 = fire on any change + rate_limit: 5m # minimum interval between fires + timeout: 10s # HTTP timeout per attempt + retry: + max_attempts: 3 # max 5 + backoff: 2s # exponential backoff start + + - name: ops-discord + type: discord + url: https://discord.com/api/webhooks/... + send_all: false # when true, include every repo, not just changed + + - name: internal-dashboard + type: generic + url: https://dashboard.internal/api/gitflow + headers: + Authorization: Bearer ${DASHBOARD_TOKEN} + X-Source: gitflow +``` + +### Environment variable mapping + +| Config key | Env var | +|---|---| +| `dir` | `GITFLOW_DIR` | +| `interval` | `GITFLOW_INTERVAL` | +| `format` | `GITFLOW_FORMAT` | +| `color` | `GITFLOW_COLOR` | +| `theme` | `GITFLOW_THEME` | +| `notify` | `GITFLOW_NOTIFY` | +| `max_depth` | `GITFLOW_MAX_DEPTH` | +| `workers` | `GITFLOW_WORKERS` | +| `exclude` | `GITFLOW_EXCLUDE` (comma-separated) | +| `ai.enabled` | `GITFLOW_AI_ENABLED` | +| `ai.provider` | `GITFLOW_AI_PROVIDER` | +| `ai.model` | `GITFLOW_AI_MODEL` | +| `ai.api_key_env` | `GITFLOW_AI_API_KEY_ENV` | +| `ai.base_url` | `GITFLOW_AI_BASE_URL` | +| `ai.execute` | `GITFLOW_AI_EXECUTE` | + +## Output formats + +### Table (default) + +``` +REPOSITORY BRANCH STATUS AHEAD/BEHIND CHANGES STASH +~/projects/api main clean - - - +~/projects/web feat/x modified 3/0 2M 1U - +~/projects/lib main behind 0/5 - 2 + +5 repos | 2 clean | 3 need attention | 0 errors +``` + +Colorised per status class (`--color=auto` respected, `NO_COLOR` honoured). +Path prefix `$HOME` collapsed to `~`. + +### JSON + +```json +{ + "scanned_at": "2026-08-02T10:00:00+02:00", + "parent_dir": "/home/user/projects", + "repos": [ + { + "path": "/home/user/projects/api", + "name": "api", + "branch": "main", + "status": "clean" + } + ], + "summary": { + "total": 5, + "clean": 2, + "attention": 3, + "errored": 0, + "staged": 0, + "modified": 2, + "untracked": 1 + } +} +``` + +Status fields marshal as string labels (`"clean"`, `"modified"`, …) and +unmarshal back from both strings and integers. + +### Compact + +``` +✓ ~/projects/api (main) +✗ ~/projects/web (feat/x) +3/-0 2 change(s) +↓ ~/projects/lib (main) +0/-5 +``` + +Status symbols: `✓ ✗ ↑ ↓ ⇄ ◉ ▢ !`. + +## AI agent + +Enable with `--ai` (or `ai.enabled: true` in config): + +```bash +# OpenAI (requires OPENAI_API_KEY exported or ai.api_key_env set) +gitflow scan -d ~/projects --ai + +# Local Ollama +gitflow scan -d ~/projects --ai --ai-provider ollama --ai-model llama3.2 + +# Anthropic +gitflow scan -d ~/projects --ai --ai-provider anthropic --ai-model claude-3-5-haiku-latest +``` + +Suggestions render below the scan table, colour-coded by priority: + +``` +AI SUGGESTIONS +REPOSITORY ACTION PRIORITY MESSAGE COMMAND +~/projects/web commit high commit the new file git add -A && git commit -m wip +~/projects/lib pull medium pull 5 commits from origin git pull +``` + +In JSON mode AI is skipped (machine-readable streams stay clean). In watch +mode AI is queried only on the first frame and when something changed. + +### `--ai-execute` (experimental) + +Runs suggested commands after **explicit per-command y/N confirmation**, +only for actions on an allowlist (`commit`, `push`, `pull`, `stash`, +`checkout`). LLM output can never run arbitrary shell commands. + +## Webhooks + +Webhooks fire in watch mode when `webhooks:` is present in the config file. +They run in a background goroutine and never block the scan interval. + +Each webhook has independent rate limiting and retry with exponential +backoff. Transient errors (5xx, timeouts) are retried; 4xx client errors +fail immediately. + +**Slack Block Kit payload:** +- Header: "gitflow: scan results" +- Section: summary line with repo counts +- Divider + changed-repo list (when changes exist) +- Context footer: timestamp + "gitflow" + +**Discord embed payload:** +- Sidebar colour: green (all clean), yellow (attention), red (errors) +- Title: "gitflow scan" +- Markdown body with summary + changed repos +- Footer and timestamp + +**Generic payload:** +- Raw JSON POST of the `webhook.Payload` struct (`timestamp`, `parent_dir`, + `summary`, `changed`, `all`) to any URL with custom headers. + +## Test suite + +```bash +make test # all packages, no race detection +go test -race ./... # with data-race detector (13 packages) +go test -count=1 -race ./internal/ai ./internal/webhook # specific packages +``` + +Coverage (latest run): + +| Package | Coverage | +|---|---| +| `internal/ai` | 84.9% | +| `internal/app` | 76.9% | +| `internal/config` | 90.9% | +| `internal/git` | 79.6% | +| `internal/httpclient` | 89.1% | +| `internal/presenter` | 86.6% | +| `internal/rules` | 83.3% | +| `internal/scanner` | 88.2% | +| `internal/scheduler` | 88.9% | +| `internal/webhook` | 91.7% | +| `internal/tui` | 89.4% | +| `pkg/status` | 91.1% | + +## Project layout + +``` +gitflow/ +├── cmd/gitflow/ CLI commands (cobra) +│ ├── main.go entry point +│ ├── root.go root command + version + completion +│ ├── scan.go gitflow scan +│ ├── watch.go gitflow watch +│ ├── tui.go gitflow tui +│ └── prompt.go TTY helpers (dir prompt, y/N confirmation) +├── internal/ +│ ├── ai/ AI providers (OpenAI, Ollama, Anthropic) + prompt +│ ├── app/ orchestration: discovery → scan → result +│ ├── config/ flags, env, config-file resolution (viper) +│ ├── git/ porcelain v2 git wrapper (executor pattern) +│ ├── httpclient/ shared JSON HTTP client (timeout, bounded reads) +│ ├── notify/ desktop notifications (notify-send / osascript) +│ ├── presenter/ table / json / compact output + colors + themes +│ ├── rules/ user-defined threshold rules +│ ├── scanner/ repository discovery + concurrent status scanning +│ ├── scheduler/ interval loop with graceful shutdown +│ ├── tui/ interactive terminal UI (bubbletea + lipgloss) +│ ├── version/ ldflags-injectable version +│ └── webhook/ Slack, Discord, Generic webhook senders + dispatcher +├── pkg/status/ shared domain model (RepoInfo, RepoStatus, ScanResult) +├── go.mod / go.sum +├── Makefile +├── .golangci.yml +├── .github/workflows/ci.yml +├── readme.md user-facing README +├── implementation.md original development plan + progress +├── tui.md TUI & webhooks plan + milestone status +└── buildAndRun.md this file +``` + +## CI + +GitHub Actions workflow (`.github/workflows/ci.yml`): + +``` +jobs: + test (matrix: go 1.24, 1.26) + - go build ./... + - go vet ./... + - go test -race ./... + lint + - golangci-lint +``` + +No remote pushes were made during development — branches were committed +and merged locally with `--no-ff`. + +## Troubleshooting + +**"not a git repository" when scanning a directory that IS a repo** + +The repo's `.git` directory may be missing or the path might be a bare +`.git` file pointing at a non-existent gitdir. Check `git status` manually +in that directory. + +**"no repositories found"** + +The directory contains no `.git` entries. If you expected repos deeper in +the tree, make sure `--max-depth` isn't set too low and no `--exclude` +pattern shadows the subtree. + +**"ai: OPENAI_API_KEY is not set"** + +Export the key (or the env var name in `ai.api_key_env`) before running: + +```bash +export OPENAI_API_KEY=sk-... +gitflow scan --ai +``` + +**TUI doesn't launch / exits immediately** + +The TUI requires a terminal that supports the alternate screen buffer. If +you are piping or redirecting output, use `scan` or `watch` instead. + +**Webhook not firing** + +1. Check `gitflow config` shows the `webhooks:` section. +2. Webhooks only fire in `watch` mode, not in `scan`. +3. If `on_change_only: true`, the webhook skips when nothing changed + between frames. +4. If `rate_limit` is set, the webhook won't fire until the cooldown + elapses. + +**Shell completion "command not found" after eval** + +Make sure `gitflow` is on your PATH (`go install` into `$GOBIN`): + +```bash +go install ./cmd/gitflow +# Or +sudo cp gitflow /usr/local/bin/ +``` + +## Cross-compilation + +```bash +GOOS=linux GOARCH=amd64 go build -o gitflow-linux ./cmd/gitflow +GOOS=darwin GOARCH=arm64 go build -o gitflow-darwin ./cmd/gitflow +GOOS=windows GOARCH=amd64 go build -o gitflow.exe ./cmd/gitflow +```