docs(readme): document mgit to the docs standard
This commit is contained in:
@@ -0,0 +1,143 @@
|
|||||||
|
# mopac-gitea-go
|
||||||
|
|
||||||
|
A 100% Go client library and CLI (`mgit`) for the Gitea API (v1).
|
||||||
|
Replaces shell/tea glue for every forge operation the MOPAC verticals
|
||||||
|
need: one static binary, zero third-party modules (stdlib only),
|
||||||
|
machine-parseable JSON output, and a token that never appears in flags,
|
||||||
|
logs, or error strings. Built for the harness PR flow: branch list ->
|
||||||
|
commit status -> PR create/list/merge.
|
||||||
|
|
||||||
|
Status: 2026-08-29 — v0 complete and green: repo create/list/show,
|
||||||
|
branch list, commit statuses (report + combined), pull requests
|
||||||
|
(create/list/show/merge, all five merge styles), token-scoped auth via
|
||||||
|
`GITEA_URL`/`GITEA_KEY`, 0600 env-file config, `-o json` on every
|
||||||
|
command, exit codes 0/1/2 with one-line API-error stderr. Built and
|
||||||
|
tested entirely against a fake Gitea (unit suite + end-to-end smoke);
|
||||||
|
the live forge (git.knownelement.com) attaches with zero code change
|
||||||
|
via `GITEA_URL`/`GITEA_KEY`.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph host[Host]
|
||||||
|
M[mgit CLI\nbin/mgit] --config 0600 env --> M
|
||||||
|
S[smoke/smoke.sh]
|
||||||
|
end
|
||||||
|
subgraph docker[Digest-pinned Docker builder — ALL dev]
|
||||||
|
B[go build / vet / test]
|
||||||
|
F[smoke/fakegitea\nstateful in-memory Gitea]
|
||||||
|
end
|
||||||
|
subgraph wire[Library: package gitea]
|
||||||
|
C[Client\nAuthorization: token header only]
|
||||||
|
end
|
||||||
|
M --> C
|
||||||
|
C --> F
|
||||||
|
C -.-> R[(real Gitea\ngit.knownelement.com)]
|
||||||
|
S --> B
|
||||||
|
S --> F
|
||||||
|
```
|
||||||
|
|
||||||
|
All compilation, vetting, and testing runs inside the digest-pinned
|
||||||
|
`golang:1.26-bookworm` builder (`./dev.sh`); the host never runs a Go
|
||||||
|
toolchain. Tests and smoke talk only to the in-process/containerized
|
||||||
|
fake; the real forge is never contacted by the test suite.
|
||||||
|
|
||||||
|
## Quickstart (verified against the fake)
|
||||||
|
|
||||||
|
This is the exact flow the smoke run (`./dev.sh smoke`) executes:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./dev.sh check # build + vet + test inside the Docker builder
|
||||||
|
./dev.sh smoke # boots fake Gitea on 127.0.0.1:8602, drives bin/mgit
|
||||||
|
|
||||||
|
# against a real forge instead:
|
||||||
|
export GITEA_URL=https://git.knownelement.com
|
||||||
|
export GITEA_KEY=<api token> # or: --config ~/.config/mgit/env (0600)
|
||||||
|
|
||||||
|
mgit repo create -n vertical-x --owner ukrrs --desc "one vertical" --private --auto-init
|
||||||
|
mgit repo list # your repos
|
||||||
|
mgit repo list --owner ukrrs # an org's / user's repos
|
||||||
|
mgit repo show ukrrs/Mopac-gitea-go
|
||||||
|
mgit branch list ukrrs/MOPAC
|
||||||
|
mgit status create ukrrs/MOPAC feat/quota --state success \
|
||||||
|
--context ci/lint --description "lint clean" --target-url https://ci.example/run/1
|
||||||
|
mgit status list ukrrs/MOPAC feat/quota # combined + per-check
|
||||||
|
mgit pr create ukrrs/MOPAC --title "Quota accounting" --body - \
|
||||||
|
--base main --head feat/quota <<'EOF'
|
||||||
|
## Scope
|
||||||
|
- usage accounting per acting identity
|
||||||
|
EOF
|
||||||
|
mgit pr list ukrrs/MOPAC # open by default
|
||||||
|
mgit pr list ukrrs/MOPAC --state all
|
||||||
|
mgit pr show ukrrs/MOPAC 1
|
||||||
|
mgit pr merge ukrrs/MOPAC 1 --do squash
|
||||||
|
```
|
||||||
|
|
||||||
|
Add `-o json` to any command for machine output. REF arguments accept
|
||||||
|
anything the server resolves (full or short sha, branch, tag); PR head
|
||||||
|
may be `branch` or `owner:branch` (fork syntax).
|
||||||
|
|
||||||
|
## Command reference
|
||||||
|
|
||||||
|
| Command | Effect | Key flags |
|
||||||
|
|---|---|---|
|
||||||
|
| `repo create -n NAME` | create repo (under your account, or an org) | `--owner ORG`, `--desc`, `--private`, `--auto-init`, `--default-branch` |
|
||||||
|
| `repo list` | list repos | `--owner OWNER` (default: yours) |
|
||||||
|
| `repo show OWNER/REPO` | one repo | |
|
||||||
|
| `branch list OWNER/REPO` | branches with tip shas | |
|
||||||
|
| `status create OWNER/REPO REF` | report a commit status | `--state success\|pending\|error\|failure`, `--context`, `--description`, `--target-url` |
|
||||||
|
| `status list OWNER/REPO REF` | combined status + latest per check | |
|
||||||
|
| `pr create OWNER/REPO` | open a PR | `--title`, `--body FILE\|-`, `--base`, `--head` |
|
||||||
|
| `pr list OWNER/REPO` | list PRs (open by default) | `--state open\|closed\|all` |
|
||||||
|
| `pr show OWNER/REPO NUMBER` | one PR with body | |
|
||||||
|
| `pr merge OWNER/REPO NUMBER` | merge an open PR | `--do merge\|rebase\|rebase-merge\|squash\|fast-forward` |
|
||||||
|
| `help` | usage | |
|
||||||
|
|
||||||
|
Flags may appear before or after positionals (`mgit pr merge
|
||||||
|
ukrrs/MOPAC 1 --do squash` parses).
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
| Source | Keys | Discipline |
|
||||||
|
|---|---|---|
|
||||||
|
| env vars | `GITEA_URL`, `GITEA_KEY` | wins over the file |
|
||||||
|
| `--config PATH` (or `MGIT_CONFIG`, or `~/.config/mgit/env`) | same keys | must be 0600 or stricter; refused before any read |
|
||||||
|
|
||||||
|
The token travels ONLY in the `Authorization: token` header. Response
|
||||||
|
bodies are never surfaced in error strings — the fake Gitea deliberately
|
||||||
|
echoes the presented token back in every error body, and the suite plus
|
||||||
|
the smoke redaction pass prove it appears nowhere else.
|
||||||
|
|
||||||
|
## Library
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "git.knownelement.com/ukrrs/mopac-gitea-go/gitea"
|
||||||
|
|
||||||
|
c := gitea.New(gitea.Config{BaseURL: url, Token: key})
|
||||||
|
prs, err := c.ListPullRequests(ctx, "ukrrs", "MOPAC", gitea.PRStateOpen)
|
||||||
|
err := c.MergePullRequest(ctx, "ukrrs", "MOPAC", prs[0].Number, gitea.MergeParams{Do: gitea.MergeSquash})
|
||||||
|
```
|
||||||
|
|
||||||
|
Sentinel errors (`ErrAuth`, `ErrNotFound`, `ErrValidation`, `ErrServer`,
|
||||||
|
`ErrUnreachable`, `ErrMalformedResponse`) wrap-check with `errors.Is`;
|
||||||
|
every API failure carries an `http NNN` code in its one-line message.
|
||||||
|
This is the surface the harness turns use for their PR flow — no
|
||||||
|
copy-paste, no shell parsing.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./dev.sh build|vet|test|check|smoke|shell # everything runs in the digest-pinned builder
|
||||||
|
```
|
||||||
|
|
||||||
|
The fake Gitea (`internal/fakegitea`) implements exactly the endpoints
|
||||||
|
the client uses, records every request for round-trip assertions,
|
||||||
|
honors `FailSpec` for pinned error responses, and maintains real
|
||||||
|
semantics: latest-status-per-context folding, worst-of combined status,
|
||||||
|
short-sha resolution, merge-style validation, 409 on duplicate open PRs
|
||||||
|
and re-merges.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
AGPLv3 (see LICENSE).
|
||||||
Reference in New Issue
Block a user