pmo: FINAL — self-hosted teardown; loop sole worker; 0900-ready
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# 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: token` header).
|
||||
|
||||
## 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 create` on 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 builds `bin/fakegitea` alongside the CLI in
|
||||
the same builder step and boots the compiled binary.
|
||||
- A stale `go run ./smoke/fakeserver` debug 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.
|
||||
Reference in New Issue
Block a user