gitFlow/buildAndRun.md

474 lines
14 KiB
Markdown

# 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 <cmd> --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
```