docs: sync documentation with v1.1.0 protocol and CLI changes
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
# Development
|
||||
|
||||
This guide covers the day-to-day workflow for working on **goget** — building,
|
||||
testing, releasing, and contributing.
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Go 1.26+**
|
||||
- **Platform:** Linux (amd64, arm64, riscv64, loong64) or
|
||||
FreeBSD (amd64, arm64, riscv64)
|
||||
- **`just`** — task runner (`brew install just` / `apt install just` /
|
||||
`pacman -S just`)
|
||||
- **`groff`** *(optional)* — for `just man` manpage validation
|
||||
|
||||
All Go source files carry the build constraint `//go:build linux || freebsd`.
|
||||
goget does not build or run on macOS or Windows.
|
||||
|
||||
## First-time Setup
|
||||
|
||||
```bash
|
||||
git clone https://codeberg.org/petrbalvin/goget.git
|
||||
cd goget
|
||||
just install # go mod download
|
||||
just test # verify everything works on your machine
|
||||
just build # produce bin/goget
|
||||
```
|
||||
|
||||
A successful `just build` produces a static `bin/goget` binary with no
|
||||
runtime dependencies beyond the Go standard library and `golang.org/x/`
|
||||
packages.
|
||||
|
||||
## Task Reference
|
||||
|
||||
Every task is defined in [`justfile`](../justfile) and is the canonical
|
||||
way to interact with the project.
|
||||
|
||||
| Task | What it does |
|
||||
|------|--------------|
|
||||
| `just` | List all recipes (default) |
|
||||
| `just install` | `go mod download` |
|
||||
| `just run` | `go run ./cmd/goget` (development loop) |
|
||||
| `just build` | `gofmt -l` check + `go vet ./...` + build `bin/goget` |
|
||||
| `just test` | `go test -race -count=1 ./...` |
|
||||
| `just uninstall` | Remove `bin/` and `coverage.out` |
|
||||
| `just man` | Validate `man/goget.1` with `groff` (skips if absent) |
|
||||
| `just install-man` | Install manpage to `~/.local/share/man/man1/` (gzipped, XDG) |
|
||||
| `just uninstall-man` | Remove installed manpage |
|
||||
|
||||
`just build` is **strict**: it runs `gofmt -l` (any output is a failure)
|
||||
plus `go vet ./...`. Both must report zero warnings before the binary
|
||||
compiles. This is exactly what CI checks; running it locally first
|
||||
saves a round-trip.
|
||||
|
||||
## Development Loop
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Edit[Edit source in cmd/, internal/, pkg/]
|
||||
Test[just test]
|
||||
Vet[just build runs gofmt + vet + build]
|
||||
Man[just man - groff validation]
|
||||
Commit[Conventional Commits message]
|
||||
Push[Push to development branch]
|
||||
CI[Forgejo CI: test.yml]
|
||||
|
||||
Edit --> Test
|
||||
Test -->|fail| Edit
|
||||
Test --> Vet
|
||||
Vet -->|fail| Edit
|
||||
Vet --> Man
|
||||
Man -->|fail| Edit
|
||||
Man --> Commit
|
||||
Commit --> Push
|
||||
Push --> CI
|
||||
CI -->|fail| Edit
|
||||
CI -->|pass| Merge[Merge / open PR]
|
||||
```
|
||||
|
||||
Typical iteration:
|
||||
|
||||
```bash
|
||||
# Make a focused change.
|
||||
$EDITOR cmd/goget/flags.go
|
||||
|
||||
# Quick check that compile + format + vet pass.
|
||||
just build
|
||||
|
||||
# Run the relevant tests with the race detector.
|
||||
just test
|
||||
|
||||
# Validate any manpage edits.
|
||||
just man
|
||||
```
|
||||
|
||||
## Building from Source
|
||||
|
||||
`just build` does three things in order:
|
||||
|
||||
1. Copies `man/goget.1` into `cmd/goget/man-page-data/` — the manpage is
|
||||
embedded into the binary via `//go:embed`, and `//go:embed` can only
|
||||
reference files within the embedding package's directory.
|
||||
2. Runs `gofmt -l` over `cmd/`, `internal/`, and `pkg/`. Any output is a
|
||||
formatting violation that breaks the build.
|
||||
3. Runs `go vet ./...` — must report zero warnings.
|
||||
4. Compiles `bin/goget` with `-ldflags "-s -w"` (strips DWARF).
|
||||
|
||||
The resulting binary is fully static. `ldd bin/goget` should report
|
||||
`not a dynamic executable` on Linux.
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
just test # full suite, race detector, count=1
|
||||
go test ./internal/protocol/gemini/... # focused
|
||||
go test -run TestFoo ./internal/core/ # one test
|
||||
```
|
||||
|
||||
Conventions:
|
||||
|
||||
- Tests live next to the code as `*_test.go`.
|
||||
- Use table-driven tests for parsers, validators, and protocol handlers.
|
||||
- Cover both happy path and error path.
|
||||
- Test names follow `TestFunctionName_Scenario`.
|
||||
- Fuzz tests use `testing.F` and live next to the code they exercise.
|
||||
|
||||
The race detector is **always** on in CI. New code that introduces a
|
||||
data race must be fixed, not silenced.
|
||||
|
||||
## Manpage Authoring
|
||||
|
||||
The single source of truth is `man/goget.1` (troff). Editing this file is
|
||||
what most users eventually read via `man goget` and what
|
||||
`--generate-man-page` prints.
|
||||
|
||||
Workflow:
|
||||
|
||||
```bash
|
||||
$EDITOR man/goget.1
|
||||
just man # validates the troff
|
||||
just build # copies the file into cmd/goget/man-page-data/
|
||||
just test # cmd/goget/man_page_test.go asserts every CLI flag
|
||||
# is documented and the embedded source still parses
|
||||
```
|
||||
|
||||
`cmd/goget/man_page_test.go` enforces documentation coverage — adding a
|
||||
new flag to `defineFlags` without documenting it in `man/goget.1` breaks
|
||||
the build.
|
||||
|
||||
## Logging
|
||||
|
||||
The project uses `internal/log` for structured output. Prefer `log.Infof`,
|
||||
`log.Errorf`, etc. over ad-hoc `fmt.Fprintf(os.Stderr, ...)` or
|
||||
`cli.Print*`. The backlog tracks a migration of the remaining ~140 legacy
|
||||
callsites to `internal/log`.
|
||||
|
||||
## Branching & Releases
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Feature[Feature branches]
|
||||
Development[development]
|
||||
Main[main]
|
||||
Tag[vX.Y.Z tag]
|
||||
Release[Forgejo release]
|
||||
|
||||
Feature --> Development
|
||||
Development --> Main
|
||||
Main --> Tag
|
||||
Tag --> Release
|
||||
```
|
||||
|
||||
- **`development`** — the only branch that receives day-to-day work.
|
||||
All pull requests target `development`.
|
||||
- **`main`** — only changes when `development` is merged for a release.
|
||||
Never commit directly to `main`.
|
||||
- **Tags** — `vX.Y.Z` tags trigger the release workflow.
|
||||
|
||||
### Cutting a Release
|
||||
|
||||
1. Bump `Version` in [`internal/core/version.go`](../internal/core/version.go).
|
||||
2. Move the top `## [development]` section in
|
||||
[`CHANGELOG.md`](../CHANGELOG.md) to `## [X.Y.Z] — YYYY-MM-DD`,
|
||||
inserting a fresh empty `## [development]` section above it.
|
||||
3. Ensure CI is green on `development`.
|
||||
4. Merge `development` → `main`.
|
||||
5. Tag and push:
|
||||
```bash
|
||||
git tag -a vX.Y.Z -m "goget vX.Y.Z"
|
||||
git push origin main
|
||||
git push origin vX.Y.Z
|
||||
```
|
||||
6. The release workflow builds binaries for all seven platform targets,
|
||||
extracts the matching `CHANGELOG.md` section, and publishes the
|
||||
release on Codeberg.
|
||||
|
||||
## CI
|
||||
|
||||
Two Forgejo Actions workflows live under
|
||||
[`.forgejo/workflows/`](../.forgejo/workflows):
|
||||
|
||||
### `test.yml`
|
||||
|
||||
Triggered on every push to `development` and on every pull request
|
||||
targeting `development`.
|
||||
|
||||
| Job | What it does |
|
||||
|-----|--------------|
|
||||
| `vet` | `gofmt -l` check + `go vet ./...` (no output = pass) |
|
||||
| `test` | `go test -race -count=1 ./...` + coverage gate |
|
||||
|
||||
Run the same locally before opening a PR:
|
||||
|
||||
```bash
|
||||
go vet ./...
|
||||
just test
|
||||
```
|
||||
|
||||
### `release.yml`
|
||||
|
||||
Triggered by pushing a `v*` tag. Verifies that the tag matches
|
||||
`internal/core.Version`, runs the quality gate, builds static binaries
|
||||
for all seven targets, and publishes the release.
|
||||
|
||||
Requires a `FORGEJO_TOKEN` secret with release-creation permissions on
|
||||
the runner.
|
||||
|
||||
## Code Style
|
||||
|
||||
- Follow [Effective Go](https://go.dev/doc/effective_go).
|
||||
- Keep lines under 100 characters.
|
||||
- `camelCase` for locals, `PascalCase` for exported symbols.
|
||||
- Prefix every file with a one-line comment describing its purpose.
|
||||
- Use `//go:build linux || freebsd` on every source file.
|
||||
- Use long CLI flags only (`--header`, not `-H`).
|
||||
- Stick to the Go standard library and `golang.org/x/`. External
|
||||
dependencies require an explicit justification.
|
||||
- Error messages: English, lowercase, no trailing period, always with
|
||||
context (e.g. `open config: permission denied`).
|
||||
- Run `gofmt` before committing.
|
||||
|
||||
## Reporting Bugs
|
||||
|
||||
Open an issue at
|
||||
<https://codeberg.org/petrbalvin/goget/issues> with:
|
||||
|
||||
- `goget --version` output.
|
||||
- Operating system and architecture.
|
||||
- The full command used and its output.
|
||||
- Expected vs actual behaviour.
|
||||
|
||||
For **security issues**, email
|
||||
[opensource@petrbalvin.org](mailto:opensource@petrbalvin.org) instead of
|
||||
opening a public issue.
|
||||
Reference in New Issue
Block a user