002 — tp issue list: open issues on the release remote's Forgejo (#22)

Status: shipped (v0.2.0)

Why

Story 001 is the whole tp issue command. Its hard part is not any one subcommand but the plumbing under all of them: finding the forge, owner, repo and token from the release remote, and talking to the Forgejo issues API. Listing open issues is the smallest read that exercises all of it, and it is useful on its own — "what's open here?" is the first question before picking the next story. Shipping it first proves the plumbing before the write subcommands build on it, and keeps 001 to one release.

What changes

  • New command tp issue list: open issues of the current repo, one line each, #N title, ascending by number. No issues prints nothing and exits 0.
  • The forge, owner, repo and token come from the release remote exactly as tp release finds them: release_remote (default origin), its forge/token_env overrides in task-plus.yml, tokens fetched through the configured secrets provider. No new configuration.
  • Forgejo/Gitea API only: GET /api/v1/repos/{owner}/{repo}/issues?state=open&type=issues, following pages until one comes back short.
  • internal/forge gains the issue list call; internal/cli gains the issue dispatch with list as its only subcommand. Docs page docs/issue.md; README command table row.

Acceptance

Forge resolution, given release_remote names remote R:

R's URL forge: override Outcome
https://host/owner/repo.git none, detected forgejo API at https://host/api/v1/repos/owner/repo
git@host:owner/repo.git none, detected forgejo same
ssh://git@host/owner/repo.git none, detected forgejo same
alias:owner/repo.git (ssh alias, no dots) none error: "cannot derive forge host from ssh alias; use the canonical name in the remote"
any github error: "tp issue: issues live on the Forgejo origin, not GitHub"
any none error: no forge
not recognisable as a forge host none error: "set forge: forgejo on the remote in task-plus.yml"
any gitlab error: only Forgejo/Gitea issues are supported
ssh://git@host:2222/owner/repo.git forgejo API at https://host/... (the ssh port is dropped)

Token, for a resolved Forgejo host:

token_env set variable present in env secrets provider Outcome
yes yes any used
yes no bitwarden, unlocked fetched, used
yes no bitwarden, no session error naming tp unlock
yes no none error naming the variable
no — — request sent unauthenticated

Listing, with a resolved forge:

API response Prints Exit
open issues on one page #N title per issue, ascending 0
more open issues than one page every issue across all pages 0
a pull request among the results excluded (type=issues) 0
no open issues nothing 0
404 (missing repo, or private without a token) error with status and the API's message 1
other non-2xx error with status and the API's message 1
401 whose message echoes the token the token replaced by <redacted> 1

Out of scope

  • closed/all states, show, create, edit, comment, close, reopen, and -json — the rest of story 001.
  • Labels, milestones, assignees, and filtering.
  • Issues across several repos.

Decisions

None: the forge resolution is tp release's, reused. Two gaps were filled while building: a remote on a host tp cannot recognise (git.bytestone.uk has no "forgejo" in its name) needs forge: forgejo, as it does for tp release; and Forgejo's 401 message quotes the rejected token, so API errors redact it.

Done when

  • tests express the three acceptance tables and pass (forge resolution and token chain as unit tests; listing against an httptest server)
  • spec updated (docs/issue.md, README command table)
  • ADR written if a fork was resolved
  • roadmap ticked and stamped; changelog entry
  • issue closed with a link to the release