pi-gogs-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/package.json +31 -0
- package/skills/gogs-cli/SKILL.md +128 -0
- package/skills/gogs-cli/references/gogs-api.md +98 -0
- package/skills/gogs-cli/scripts/gogs-cli +12 -0
- package/skills/gogs-cli/scripts/gogs_cli.py +1074 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 summerway
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# pi-gogs-cli
|
|
2
|
+
|
|
3
|
+
A [pi coding agent](https://github.com/earendil-works/pi-coding-agent) skill that ships **gogs-cli** — a GitHub-CLI-style (`gh`) command line for self-hosted [Gogs](https://gogs.io) instances. Usable by any agent (pi, Codex, Claude Code, ...) or by a human, on desktop, headless boxes, containers, and CI. Python 3 stdlib only — zero dependencies.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Gogs has a usable API for repos/issues/labels but **no pull-request API at all** (`/pulls` 404s), and its issues list excludes PRs. Existing CLIs either ignore PRs or drive a real browser. gogs-cli gives an agent full repo/issue/PR capability with one stateless tool:
|
|
8
|
+
|
|
9
|
+
- **repo / issue / label** — plain Gogs API (`gh`-style verbs, `issue develop` branches off an issue gh-style)
|
|
10
|
+
- **pr list/create/merge/close/reopen** — headless **webform engine**: session login + CSRF form POSTs against the Gogs Web UI itself, no browser, no OS dependency
|
|
11
|
+
- every webform write is **verified through the API** before success is reported — a submitted form alone is never reported as success
|
|
12
|
+
- `--json` on every command; structured `reason` warnings (exit 2) for `pr merge` no-ops (already merged / empty diff / conflict)
|
|
13
|
+
|
|
14
|
+
## Install (pi)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pi install npm:pi-gogs-cli
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The skill's `scripts/gogs-cli` lands under `~/.pi/agent/npm/pi-gogs-cli/...`; symlink it onto PATH:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
ln -sf ~/.pi/agent/npm/pi-gogs-cli/skills/gogs-cli/scripts/gogs-cli ~/.local/bin/gogs-cli
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Any other agent or a human can use the same checkout directly.
|
|
27
|
+
|
|
28
|
+
## Configuration
|
|
29
|
+
|
|
30
|
+
All config is loaded from disk, never printed.
|
|
31
|
+
|
|
32
|
+
| File | Keys |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `~/.config/gogs-cli/config` | `GOGS_TOKEN` (required for API ops), `GOGS_USERNAME` / `GOGS_PASSWORD` (webform PR ops) |
|
|
35
|
+
| `~/.codex/local/gogs-workflow/.env` | legacy location, still honored |
|
|
36
|
+
| `<repo-root>/.gogs.local.env` | `GOGS_BASE_URL`, `GOGS_WEB_BASE_URL`, `GOGS_USERNAME`, `GOGS_PASSWORD` |
|
|
37
|
+
|
|
38
|
+
Repo-level wins. Create a token in Gogs under `user/settings/applications`.
|
|
39
|
+
|
|
40
|
+
**Base resolution:** `GOGS_BASE_URL` is probed live; then each address in `GOGS_FALLBACK_URLS` (space/comma-separated) in order — first responder wins, cached per process:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
GOGS_FALLBACK_URLS="http://192.168.1.10:10015 https://gogs.example.com"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Same invocation on-LAN and off-LAN, no config change. No built-in default; unconfigured runs exit with setup instructions.
|
|
47
|
+
|
|
48
|
+
Default `OWNER/REPO` derives from `git remote get-url origin`.
|
|
49
|
+
|
|
50
|
+
## Command surface
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
gogs-cli repo view|list
|
|
54
|
+
gogs-cli issue list|view|create|edit|close|reopen|comment|develop
|
|
55
|
+
gogs-cli label list
|
|
56
|
+
gogs-cli pr list|view|create|merge|close|reopen
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Full reference lives in the skill itself (`skills/gogs-cli/SKILL.md`) and is what agents see; the authoritative endpoint map is `skills/gogs-cli/references/gogs-api.md`.
|
|
60
|
+
|
|
61
|
+
## Merge styles
|
|
62
|
+
|
|
63
|
+
If the instance offers only one merge style (many Gogs setups expose `create_merge_commit` only), `--squash`/`--rebase` fall back to the offered style with a note. `--delete-branch` is accepted for `gh` compatibility but prints a reminder (manual delete).
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
[MIT](LICENSE)
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-gogs-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "pi coding agent skill: gh-style CLI for self-hosted Gogs — repos, issues, labels over the Gogs API; pull requests via headless Web-UI form POSTs (Gogs has no PR API). Python 3 stdlib only, cross-platform",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pi-package",
|
|
7
|
+
"pi",
|
|
8
|
+
"pi-coding-agent",
|
|
9
|
+
"pi-skill",
|
|
10
|
+
"gogs",
|
|
11
|
+
"cli",
|
|
12
|
+
"git",
|
|
13
|
+
"self-hosted"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/summerway/pi-gogs-cli.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/summerway/pi-gogs-cli/issues"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"skills",
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE"
|
|
27
|
+
],
|
|
28
|
+
"pi": {
|
|
29
|
+
"skills": ["./skills"]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gogs-cli
|
|
3
|
+
description: Reusable, agent-agnostic Gogs CLI mirroring the GitHub CLI (`gh`) command surface. Repos, issues (list/view/create/edit/close/reopen/comment, plus gh-style `issue develop` to branch from an issue), and labels (read-only) over the Gogs API; pull requests (Gogs exposes no PR API) via headless Web-UI form POSTs — list/create/merge/close/reopen, no browser needed. Every webform write is verified through the API before success is reported. Base URL comes from config with optional GOGS_FALLBACK_URLS probing, so the same invocation works from several networks. Use for anything read/write against a Gogs instance. Cross-platform (macOS/Linux/containers), Python 3 stdlib, stateless; no workflow mapping.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# gogs-cli
|
|
7
|
+
|
|
8
|
+
A single command line tool for Gogs capability, usable by any agent (Codex,
|
|
9
|
+
Claude Code, pi, ...) or by a human, on desktop or headless/container hosts.
|
|
10
|
+
Mirrors the GitHub CLI (`gh`) command surface.
|
|
11
|
+
|
|
12
|
+
- **Interface contract:** `references/gogs-api.md` is the authoritative endpoint
|
|
13
|
+
map, sourced from `https://gogs.io/api-reference/introduction`. It is the sole
|
|
14
|
+
reference for the command set; update it when the API or the instance changes.
|
|
15
|
+
- **Encapsulation:** callers see only clean `gh`-style verbs. Whether an
|
|
16
|
+
operation is served by the Gogs API or by Web-UI form POSTs is hidden.
|
|
17
|
+
- **Stateless:** no workflow mapping, no local database, no `LI/LPR` ids.
|
|
18
|
+
|
|
19
|
+
## Setup
|
|
20
|
+
|
|
21
|
+
`gogs-cli` is on PATH (e.g. `~/.local/bin/gogs-cli`, a symlink to this skill's
|
|
22
|
+
`scripts/gogs-cli`). Python 3 stdlib only — no dependencies.
|
|
23
|
+
|
|
24
|
+
Config (loaded from disk, never printed):
|
|
25
|
+
- `~/.config/gogs-cli/config` → `GOGS_TOKEN` (required for API ops).
|
|
26
|
+
`~/.codex/local/gogs-workflow/.env` is honored as a legacy location.
|
|
27
|
+
- `<repo-root>/.gogs.local.env` → `GOGS_BASE_URL`, `GOGS_WEB_BASE_URL`,
|
|
28
|
+
`GOGS_USERNAME`, `GOGS_PASSWORD` (web creds used only for webform PR ops).
|
|
29
|
+
- Either file may hold any of these keys; repo-level wins. On headless/container
|
|
30
|
+
hosts put everything in the global file, with `GOGS_BASE_URL` pointing at the
|
|
31
|
+
internal address (e.g. `http://gogs:3000` over a shared Docker network).
|
|
32
|
+
|
|
33
|
+
Default `OWNER/REPO` is derived from `git remote get-url origin`; pass an explicit
|
|
34
|
+
`OWNER/REPO` positional to override.
|
|
35
|
+
|
|
36
|
+
**Base resolution.** The Gogs web/API base is resolved at first use and cached
|
|
37
|
+
for the process: the configured `GOGS_BASE_URL`/`GOGS_WEB_BASE_URL` is tried
|
|
38
|
+
first, then each address in `GOGS_FALLBACK_URLS` (space- or comma-separated) in
|
|
39
|
+
order — the first that responds is used. Set e.g.
|
|
40
|
+
`GOGS_FALLBACK_URLS="http://192.168.1.10:10015 https://gogs.example.com"` so the
|
|
41
|
+
same invocation works on-LAN (fast, direct) and off-LAN (public host) with no
|
|
42
|
+
config change. There is no built-in default; with nothing configured the CLI
|
|
43
|
+
exits with setup instructions.
|
|
44
|
+
|
|
45
|
+
## Commands
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
# repo — API, read-only
|
|
49
|
+
gogs-cli repo view [OWNER/REPO] [--json]
|
|
50
|
+
gogs-cli repo list [--user USER] [--limit N] [--json]
|
|
51
|
+
|
|
52
|
+
# issue — API
|
|
53
|
+
gogs-cli issue list [OWNER/REPO] [--state open|closed|all] [--label NAME...] [--assignee USER] [--limit N] [--json]
|
|
54
|
+
gogs-cli issue view [OWNER/REPO] NUMBER [--json]
|
|
55
|
+
gogs-cli issue create --title T [--body B | -F FILE] [--assignee USER] [--label NAME...] [--milestone N] [OWNER/REPO] [--json]
|
|
56
|
+
gogs-cli issue edit [OWNER/REPO] NUMBER [--title T] [--body B | -F FILE] [--state open|closed] [--json]
|
|
57
|
+
gogs-cli issue close [OWNER/REPO] NUMBER [--json]
|
|
58
|
+
gogs-cli issue reopen [OWNER/REPO] NUMBER [--json]
|
|
59
|
+
gogs-cli issue comment [OWNER/REPO] NUMBER [--body B | -F FILE] [--json]
|
|
60
|
+
gogs-cli issue develop [OWNER/REPO] NUMBER [--base B] [--name NAME] [--json] # local branch off --base, named from the issue (gh-style)
|
|
61
|
+
|
|
62
|
+
# label — API
|
|
63
|
+
gogs-cli label list [OWNER/REPO] [--json]
|
|
64
|
+
|
|
65
|
+
# pr — view via API; list/create/merge/close/reopen via Web UI (no PR API)
|
|
66
|
+
gogs-cli pr list [OWNER/REPO] [--state open|closed|all] [--limit N] [--json] # Web UI scrape
|
|
67
|
+
gogs-cli pr view [OWNER/REPO] NUMBER [--json] # API
|
|
68
|
+
gogs-cli pr create [--base B] [--head H] --title T [--body B | -F FILE] [OWNER/REPO] [--json] # --base default develop, --head default current branch
|
|
69
|
+
gogs-cli pr merge [OWNER/REPO] NUMBER [--merge|--squash|--rebase] [--delete-branch] [--json]
|
|
70
|
+
gogs-cli pr close [OWNER/REPO] NUMBER [--json]
|
|
71
|
+
gogs-cli pr reopen [OWNER/REPO] NUMBER [--json]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`--json` switches any command to machine-readable JSON output (the raw API
|
|
75
|
+
object) so other tools/agents can compose. `--label NAME` is resolved to label
|
|
76
|
+
IDs via the labels API (Gogs accepts IDs only) — unknown name → error.
|
|
77
|
+
|
|
78
|
+
Exit codes: 0 success · 1 failure · 2 soft warning — `pr merge` that cannot
|
|
79
|
+
proceed (empty diff, conflict, already merged) exits 2 with a structured
|
|
80
|
+
`reason` instead of failing hard (details below). `--delete-branch` is
|
|
81
|
+
accepted for `gh` compatibility but **not automated**: it prints a reminder;
|
|
82
|
+
delete the branch manually.
|
|
83
|
+
|
|
84
|
+
## How PR ops work (no PR API exists)
|
|
85
|
+
|
|
86
|
+
Gogs exposes **no** pull-request API (`/pulls` returns 404), and the issues list
|
|
87
|
+
**excludes** PRs. So PR operations submit the Gogs Web UI's own forms directly —
|
|
88
|
+
**webform**: Python-stdlib session login + CSRF form POSTs, no browser and no OS
|
|
89
|
+
dependency, identical behavior on macOS, Linux, and containers:
|
|
90
|
+
|
|
91
|
+
- `pr list` scrapes `/pulls?type=all&state=…` (paginated)
|
|
92
|
+
- `pr create` POSTs the compare-page form (`title`/`content`); the redirect
|
|
93
|
+
target carries the new PR number
|
|
94
|
+
- `pr merge` POSTs the `/pulls/N/merge` form (`merge_style`)
|
|
95
|
+
- `pr close/reopen` POST the comment form's hidden `status` field
|
|
96
|
+
(`close`/`reopen`)
|
|
97
|
+
- Web login uses `GOGS_USERNAME`/`GOGS_PASSWORD` from the env files
|
|
98
|
+
|
|
99
|
+
For every write, `gogs-cli` **verifies the real remote state through the issues
|
|
100
|
+
API** (e.g. `pull_request.merged === true`, or issue `state`) before reporting
|
|
101
|
+
success — a submitted form alone is never reported as success.
|
|
102
|
+
|
|
103
|
+
`pr merge` that **cannot proceed** (empty-diff / nothing-to-merge, conflict, or
|
|
104
|
+
already-merged) is reported as a **non-zero warning (exit 2)**, not a hard
|
|
105
|
+
failure: Gogs renders no merge form in these cases, so `gogs-cli` reads the
|
|
106
|
+
page banner plus the issues-API `merged` flag and emits a structured `reason`
|
|
107
|
+
(`empty_diff` · `conflict` · `already_merged` · `not_mergeable`) with Gogs's raw
|
|
108
|
+
banner text — in both human and `--json` output. Genuine failures (auth error,
|
|
109
|
+
submitted-but-not-merged, or `#N` is not a PR) still exit 1.
|
|
110
|
+
|
|
111
|
+
If this Gogs offers only one merge style (e.g. `create_merge_commit` only),
|
|
112
|
+
`--squash`/`--rebase` fall back to the offered style with a stderr note.
|
|
113
|
+
|
|
114
|
+
Limitations: the `/pulls` closed tab groups merged PRs as "closed" — use
|
|
115
|
+
`pr view N` for the precise merged state; `--base/--head` are not supported by
|
|
116
|
+
`pr list`.
|
|
117
|
+
|
|
118
|
+
## Token safety
|
|
119
|
+
|
|
120
|
+
If `GOGS_TOKEN` is missing, `gogs-cli` stops and prints setup instructions — it
|
|
121
|
+
never guesses or retries. Tokens and `.gogs.local.env` contents are never
|
|
122
|
+
printed. Do not commit credentials or workflow mapping files.
|
|
123
|
+
|
|
124
|
+
## Importing as a module
|
|
125
|
+
|
|
126
|
+
`gogs_cli.py` is importable. Functions like `resolve_target`, `api`, `api_root`,
|
|
127
|
+
`create`/`view` helpers, and the `webform_*` PR functions can be
|
|
128
|
+
reused directly to avoid duplicating the API client.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Gogs API Reference (authoritative for `gogs-cli`)
|
|
2
|
+
|
|
3
|
+
Source of truth for the `gogs-cli` command surface. Captured from the official
|
|
4
|
+
Gogs API docs (`https://gogs.io/api-reference/introduction`, full index
|
|
5
|
+
`https://gogs.io/llms.txt`) and verified against the local instance
|
|
6
|
+
`http://192.168.100.3:10015` (HTTP status in parentheses, probed 2026-08-01).
|
|
7
|
+
|
|
8
|
+
Any future change to `gogs-cli` commands MUST be justified against this map.
|
|
9
|
+
The official API docs at `https://gogs.io/api-reference/introduction` are the
|
|
10
|
+
sole interface reference; update this file when the API or the instance changes.
|
|
11
|
+
|
|
12
|
+
## Conventions
|
|
13
|
+
|
|
14
|
+
- Base path: `/api/v1`.
|
|
15
|
+
- Auth: `Authorization: token <TOKEN>` (the token is read from
|
|
16
|
+
`~/.codex/local/gogs-workflow/.env` as `GOGS_TOKEN`; never printed).
|
|
17
|
+
- `:owner/:repo` resolves from the `origin` git remote unless overridden.
|
|
18
|
+
- List endpoints paginate with `?page=N` (~10/page). Gogs ignores `limit`; the
|
|
19
|
+
`type=` param (a Gitea feature) is also ignored. `state=all` is **not** honored
|
|
20
|
+
— pass a concrete `state=open`/`closed` and combine them for "all".
|
|
21
|
+
|
|
22
|
+
## Repository (API — read only is wrapped)
|
|
23
|
+
|
|
24
|
+
| Method | Path | Status | `gogs-cli` |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| GET | `/repos/:owner/:repo` | 200 | `repo view` |
|
|
27
|
+
| GET | `/user/repos` | 200 | `repo list` (authenticated user) |
|
|
28
|
+
| GET | `/users/:username/repos` | 200 | `repo list --user <name>` |
|
|
29
|
+
| GET | `/repos/:owner/:repo/branches` | 200 | _(not wrapped; use `git`)_ |
|
|
30
|
+
|
|
31
|
+
`repo create/delete/fork/collaborators` are management endpoints — intentionally
|
|
32
|
+
**not** wrapped.
|
|
33
|
+
|
|
34
|
+
## Issues (API)
|
|
35
|
+
|
|
36
|
+
| Method | Path | Status | `gogs-cli` |
|
|
37
|
+
|---|---|---|---|
|
|
38
|
+
| GET | `/repos/:owner/:repo/issues` | 200 | `issue list` (supports `state`, `labels`, `assignee`) |
|
|
39
|
+
| GET | `/repos/:owner/:repo/issues/:number` | 200 | `issue view` |
|
|
40
|
+
| POST | `/repos/:owner/:repo/issues` | 201 | `issue create` (body: `title`, `body`, `assignee`, `milestone`, `labels` IDs) |
|
|
41
|
+
| PATCH | `/repos/:owner/:repo/issues/:number` | 200 | `issue edit` / `issue close` / `issue reopen` (body: `state`) |
|
|
42
|
+
| GET | `/repos/:owner/:repo/issues/:number/comments` | 200 | _(shown by `issue view`)_ |
|
|
43
|
+
| POST | `/repos/:owner/:repo/issues/:number/comments` | 201 | `issue comment` |
|
|
44
|
+
|
|
45
|
+
Notes:
|
|
46
|
+
- `labels` on create/edit takes label **IDs**, not names. `gogs-cli --label NAME`
|
|
47
|
+
resolves names → IDs via `GET /repos/:owner/:repo/labels` (gh-compatible UX).
|
|
48
|
+
- Closing = `PATCH /issues/:number {"state": "closed"}`; reopen = `{"state": "open"}`.
|
|
49
|
+
|
|
50
|
+
## Labels (API)
|
|
51
|
+
|
|
52
|
+
| Method | Path | Status | `gogs-cli` |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| GET | `/repos/:owner/:repo/labels` | 200 | `label list` |
|
|
55
|
+
|
|
56
|
+
Only `label list` is wrapped (to support `--label` name resolution). Label
|
|
57
|
+
create/edit/delete are management ops — not wrapped.
|
|
58
|
+
|
|
59
|
+
## Pull Requests (NO API — ego black box)
|
|
60
|
+
|
|
61
|
+
| Path | Status | Conclusion |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `GET /repos/:owner/:repo/pulls` | **404** | No PR list endpoint |
|
|
64
|
+
| `GET /repos/:owner/:repo/pulls/:number` | **404** | No PR get endpoint |
|
|
65
|
+
| `POST /repos/:owner/:repo/pulls` | **absent** | No PR create endpoint |
|
|
66
|
+
| merge/close/reopen | **absent** | No PR mutation endpoints |
|
|
67
|
+
|
|
68
|
+
Gogs registers **no PR API routes**, and the issues list **excludes** PRs
|
|
69
|
+
entirely (a PR is only observable via `GET /issues/:number`, which then carries a
|
|
70
|
+
`pull_request` key). Therefore in `gogs-cli`:
|
|
71
|
+
|
|
72
|
+
- **`pr view N`** — served by the **issues endpoint**: `GET /issues/N`, asserting
|
|
73
|
+
`pull_request` is present. Authoritative (includes `merged`, `base`, `head`).
|
|
74
|
+
- **`pr list`** — **no API exists**; the issues list returns zero PRs. Served by
|
|
75
|
+
**ego-browser scraping the Web UI**: `/pulls?type=all&state=<open|closed>
|
|
76
|
+
&labels=0&milestone=0&assignee=0`. The ego profile auto-logs in via
|
|
77
|
+
`GOGS_USERNAME`/`GOGS_PASSWORD` when it hits `/user/login`. Limitation: the
|
|
78
|
+
closed tab groups merged PRs as "closed"; use `pr view N` for the precise
|
|
79
|
+
merged state. `--base/--head` are not filterable here.
|
|
80
|
+
- **PR write** (`pr create`, `pr merge`, `pr close`, `pr reopen`) is performed by
|
|
81
|
+
**ego-browser on the Gogs Web UI as a black box** (`/compare/...`, `/pulls/:n`,
|
|
82
|
+
`/pulls/:n/merge`). After the browser action, `gogs-cli` **verifies the real
|
|
83
|
+
state via the issues API** (e.g. `pull_request.merged === true`, or issue
|
|
84
|
+
`state`) before reporting success — never trusts a click alone.
|
|
85
|
+
- **`pr merge` nothing-to-merge detection**: when Gogs renders no merge button
|
|
86
|
+
(empty-diff / nothing-to-merge, conflict, or already-merged), `gogs-cli` reads
|
|
87
|
+
the page banner + the issues-API `merged` flag and returns a **non-zero warning
|
|
88
|
+
(exit 2)** carrying `reason` (`empty_diff` · `conflict` · `already_merged` ·
|
|
89
|
+
`not_mergeable`) and the raw banner text — distinct from a hard failure (exit 1).
|
|
90
|
+
|
|
91
|
+
## Token setup
|
|
92
|
+
|
|
93
|
+
When `GOGS_TOKEN` is missing, `gogs-cli` stops and instructs:
|
|
94
|
+
|
|
95
|
+
1. Log in to the Gogs Web UI.
|
|
96
|
+
2. Open `<base>/user/settings/applications`.
|
|
97
|
+
3. Generate a token (e.g. named `gogs-cli`).
|
|
98
|
+
4. Save to `~/.codex/local/gogs-workflow/.env` as `GOGS_TOKEN=<token>` (chmod 600).
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Console entry for gogs-cli. Resolves the symlink to the real script dir so
|
|
3
|
+
the `gogs_cli` module can be imported, then delegates to gogs_cli.main()."""
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
|
8
|
+
|
|
9
|
+
import gogs_cli # noqa: E402
|
|
10
|
+
|
|
11
|
+
if __name__ == "__main__":
|
|
12
|
+
gogs_cli.main()
|