5.0 KiB
REPORT — mopac-gitea-go (mgit): Gitea Go client + CLI delivered
Task: TASK-20260829-1600 — Gitea Go client (Redmine #508) Delivered: 2026-08-29 16:00 turn Repo: https://git.knownelement.com/ukrrs/mopac-gitea-go (created via the Gitea API with the tea token; public, AGPLv3) Clone: ~/projects/meta/MOPAC/gitea-go (origin main, 9 commits, pushed) Status: v0 complete, green, pushed. Ready for harness PR-flow cutover.
No Redmine writes in this turn (PMO owns the ticket, per directive).
What landed
Stdlib-only Go module git.knownelement.com/ukrrs/mopac-gitea-go:
library package gitea (Client + sentinel errors — importable by the
harness for the turn PR flow, no shell parsing), CLI mgit
(internal/cli + cmd/mgit), stateful fake Gitea
(internal/fakegitea), 0600-disciplined config loader
(internal/config). ALL dev work ran inside the digest-pinned
golang:1.26-bookworm builder via ./dev.sh/Makefile (host never
runs a toolchain). TDD red/green at every layer; atomic conventional
commits pushed to origin main.
| Commit | Content |
|---|---|
1e47f5b |
Seed: AGPLv3 LICENSE (first commit) |
eb49c62 |
Dev harness (digest-pinned Docker builder) |
43bc581 |
Config: GITEA_* env + 0600 env-file loading |
7c11987 |
gitea client core, fake server, repo endpoints |
c251cd6 |
Branch list + commit-status endpoints |
5b35e8c |
Pull-request create/list/get/merge endpoints |
9b08589 |
mgit CLI (flags accepted after positionals) |
5feac3c |
End-to-end smoke vs containerized fake |
55dbc9a |
README to docs standard |
Command surface
| Command | Effect | Key flags |
|---|---|---|
mgit repo create -n NAME |
create repo (own account or org) | --owner ORG, --desc, --private, --auto-init, --default-branch |
mgit repo list |
list repos | --owner OWNER |
mgit repo show OWNER/REPO |
one repo | |
mgit branch list OWNER/REPO |
branches + tip shas | |
mgit status create OWNER/REPO REF |
report commit status | --state success|pending|error|failure, --context, --description, --target-url |
mgit status list OWNER/REPO REF |
combined + latest per check | |
mgit pr create OWNER/REPO |
open PR (head may be owner:branch) |
--title, --body FILE|-, --base, --head |
mgit pr list OWNER/REPO |
list PRs | --state open|closed|all |
mgit pr show OWNER/REPO NUMBER |
one PR with body | |
mgit pr merge OWNER/REPO NUMBER |
merge open PR | --do merge|rebase|rebase-merge|squash|fast-forward |
Auth is token-scoped via env GITEA_URL/GITEA_KEY (or a 0600
--config env file; MGIT_CONFIG/~/.config/mgit/env also honored).
-o json on every command. Exit codes 0/1/2; API errors are one
parseable stderr line (mgit: gitea: not found: http 404). Flags parse
before OR after positionals.
Test results
- Unit suite: 71 passing tests (39 functions + 32 table-driven subtests), 0 failures/skips, across three packages (library round-trips against the fake, error mapping 401/403/404/409/422/5xx -> sentinels with "http NNN", unreachable, malformed, redaction, config 0600 discipline, CLI surface incl. usage tables and stdin body).
- The fake Gitea implements real semantics the tests pin: latest-status-per-context folding, worst-of combined status, short-sha (>= 7 char) resolution, merge-style validation, 409 on duplicate open PRs and re-merges, branch-advance on merge.
- Token redaction: the fake DELIBERATELY echoes the presented token in
every error body; library test + CLI test + the smoke redaction pass
prove the token appears nowhere else (it lives only in the
Authorization: tokenheader).
Smoke (end-to-end, ./dev.sh smoke)
Builds mgit + fakegitea in the digest-pinned builder, boots the fake in
a container on 127.0.0.1:8602, drives the real binary from the host
through a 0600 env file: repo create (private, auto-init) -> list ->
list -o json (parsed) -> show; branch list; status pending -> success
flip -> combined "success (1 checks)"; PR create (body from file) ->
list -> show -> merge squash -> closed list still shows it, open list
empty; failure paths: missing repo (exit 2, one-line http 404
stderr), wrong token (http 401, no token material), loose env file
(exit 1, "insecure mode"); final redaction scan over every captured
out/err. Result: smoke: OK. Only the exact container ID the script
spawns is ever removed.
Notes for the harness
- PR flow for turns =
branch list->status createon head sha ->pr create->pr merge, one static binary, JSON everywhere. - One bootstrapping fix during the turn: the smoke fake initially used
per-boot
go run(cold compile inside the container raced the readiness window); it now buildsbin/fakegiteaalongside the CLI in the same builder step and boots the compiled binary. - A stale
go run ./smoke/fakeserverdebug container (harness repo's, not this repo's) was removed by exact ID match during cleanup; no broad process or container operations were used at any point.