stalecontext/forgejo-cli-plus
2
4
Fork
You've already forked forgejo-cli-plus
1

Upstream sync 2026年07月02日 #52

Merged
stalecontext merged 64 commits from upstream-sync/2026-07-02 into main 2026年07月02日 21:52:34 +02:00

Summary

Cherry-pick upstream forgejo-cli changes since upstream-reviewed/2026-03-31, bump forgejo-api 0.9.0 → 0.11.0, and expose the new Actions API surface.

Cherry-picked (17 commits)

repo edit & units -- new repo management subcommands:

repo migrate -- migrate directly into an org:

Issue/PR fixes:

OAuth/keys:

ssh/git:

Deps/chores:

Adapted (ported manually, upstream diffs entangled with l10n or our divergences)

Skipped (~235 commits)

  • The entire fluent/l10n localization framework (forgejo-contrib/forgejo-cli#279) and all locale/Weblate commits -- fork policy
  • 1c1228e auth_server unreachable fix, 799f35f pr review panic fix -- both fix regressions introduced by l10n commits we don't carry
  • Lock file maintenance, upstream Woodpecker CI, release/publish infra, version bumps, README badge docs, issue templates

Fork additions

  • New: fj actions run list|view|jobs|logs|cancel|delete, fj actions artifact list|download|delete, fj actions tasks --status, fj pr search --base/--head (new forgejo-api 0.10/0.11 endpoints, Forgejo v15/v16)
  • main runs the runtime on a 16 MiB thread: forgejo-api 0.11's larger structs overflow the 1 MiB Windows main-thread stack in debug builds
  • Dropped unused git2/uuid build-dependencies (was compiling a second vendored libgit2)
  • Corrected the codefloe.com OAuth client id to upstream's canonical value
  • --repo/-r on the new repo edit/units and pr review subcommands, mutation confirmations, verbose logging
  • Test suite grew ~40 tests (assign/unassign regression, archived warnings, readme casings, pr reviews, pr status skipped, actions surface, ssh config aliases, legacy keys.json compat)

Live-testing fixes (found against codeberg.org and a v15 sandbox)

  • Vendored forgejo-api with a pre-v16 compatibility patch (vendor/forgejo-api via [patch.crates-io]): stock 0.11.0 requires key presence for many Option response fields, and Forgejo v15 omits several (Organization.created -- also inside Team objects embedded in PR responses -- and PublicKey.updated_at). On codeberg.org this broke pr view/pr search --base on any PR with a team review request, plus org view and user key list. The patch adds serde(default) to 183 presence-required Option fields; see vendor/forgejo-api/PATCHES.md. All four failures verified fixed against codeberg.org (15.0.0) and a 15.0.3 instance.
  • repo units <unit> with no flags now reports status instead of sending a no-op PATCH and claiming "Updated".
  • ssh config HostName IP literals no longer rewrite the API host: Host git.example.com + HostName <ip> redirects the ssh transport, but the domain is still the forge identity; the rewrite made fj derive https://<ip> as the API base and miss the saved login.

All 25 test binaries pass (~320 tests). Live-tested read-only against codeberg.org/forgejo/forgejo (search, pagination, reviews, releases, activity) and mutating against a private v15 sandbox (issue lifecycle, milestones, repo create/edit/units/delete with dry-run, archived warnings, full PR create/status/checkout/squash-merge flow, scp-style remotes).

## Summary Cherry-pick upstream [forgejo-cli](https://codeberg.org/forgejo-contrib/forgejo-cli) changes since `upstream-reviewed/2026-03-31`, bump forgejo-api 0.9.0 → 0.11.0, and expose the new Actions API surface. ### Cherry-picked (17 commits) **repo edit & units** -- new repo management subcommands: - `41a9922` feat: repo edit command (forgejo-contrib/forgejo-cli#349) - `90449f4` feat: repo units command (forgejo-contrib/forgejo-cli#349) **repo migrate** -- migrate directly into an org: - `b075f78` feat: allow setting owner for migrated repo (forgejo-contrib/forgejo-cli#416) - `92c163a` docs: add oneline helptext to 'repo migrate' command (forgejo-contrib/forgejo-cli#443) **Issue/PR fixes**: - `c35fc0f` fix: don't include pull requests in `issue list` (forgejo-contrib/forgejo-cli#393) - `9d630f3` feat(pr-reviews): Add command to view pull request reviews (forgejo-contrib/forgejo-cli#429) - `6eec300` feat: support all casings of README (forgejo-contrib/forgejo-cli#415) -- supersedes our b44d9ae - `d195b9e` feat: add warning about `git push --force` on agit prs (forgejo-contrib/forgejo-cli#420) **OAuth/keys**: - `1514dc7` fix(oauth): detach opened browser (forgejo-contrib/forgejo-cli#407) - `e0e1d04` fix(oauth): save new token immediately after refreshing (forgejo-contrib/forgejo-cli#417) - `1d455ac` refactor: move `keys.save()` out of `main` (forgejo-contrib/forgejo-cli#417) - `117c4a7` `b5da7f6` `bf10bd5` `a3ce4dc` `72cb79e` restrict keys.json/tempfile permissions to 0600 on Unix (forgejo-contrib/forgejo-cli#449) - `b122607` feat(login): v16.next.forgejo.org (forgejo-contrib/forgejo-cli#496) - `4a5e2f2` chore(login): remove id for v7.next.forgejo.org (forgejo-contrib/forgejo-cli#497) - `a5831f5` **feat!: remove username from keys** (forgejo-contrib/forgejo-cli#504) -- BREAKING: `auth add-key` loses its `<user>` positional; old keys.json files still load, new ones won't load in ≤v1.1.0. Warrants a major version bump. **ssh/git**: - `0796529` fix: Use get_ssh_config() to access ssh config (forgejo-contrib/forgejo-cli#462) - `279af48` fix(checkout): don't include port in refspec (forgejo-contrib/forgejo-cli#510) - `955e6db` feat: make `--host` flag global (forgejo-contrib/forgejo-cli#514) **Deps/chores**: - `f474338` chore: add query parameter to `list_action_tasks` (forgejo-contrib/forgejo-cli#422) - `772c567` Update Rust crate comrak to 0.52.0 (forgejo-contrib/forgejo-cli#396) - `d53ac46` Update Rust crate git2 to 0.21.0 (forgejo-contrib/forgejo-cli#467) - `ff9e70c` chore: update `auth-git2` to 0.6.0 (forgejo-contrib/forgejo-cli#467) - `8493d43` chore(dep): enable `https` and `ssh` features on git2 (forgejo-contrib/forgejo-cli#490) - `36a30e0` fix: typos (forgejo-contrib/forgejo-cli#430) - `e3ad8f2` fix typo (forgejo-contrib/forgejo-cli#469) - `90a5a0d` Fix project licenses (forgejo-contrib/forgejo-cli#507) - `cb46e0f` build: use `trixie` tag for debian image (forgejo-contrib/forgejo-cli#425) ### Adapted (ported manually, upstream diffs entangled with l10n or our divergences) - `1244fcc`+`15e9fb2` forgejo-api 0.11.0 bump (forgejo-contrib/forgejo-cli#519, forgejo-contrib/forgejo-cli#422) -- single-step 0.9→0.11; fixes `pr status` against modern servers (relative `target_url`); pre-v16 server compatibility restored via the vendored patch below - `f8dbe99` support `skipped` commit status (forgejo-contrib/forgejo-cli#519) - `e040613` show warning on archived repos (forgejo-contrib/forgejo-cli#419) -- gated off `--json` so agent output stays clean and costs no extra API call - `ba50965`+`8b82c17` issue/pr assign & unassign (forgejo-contrib/forgejo-cli#414) -- reimplemented over our `edit_assignees`; upstream's `unassign` has an inverted `retain` that deletes every other assignee (still live at upstream HEAD; regression-tested here) - `1df2ad5` resolve ssh host via ssh config (forgejo-contrib/forgejo-cli#462) -- with the scp-style `git@host:path` fallback upstream's version regressed, and HostName resolution gated to ssh-scheme URLs - `c4defdb` break up auth_server return type (forgejo-contrib/forgejo-cli#484) - `447091d`+`d5ab501` activity repo_name dedup (forgejo-contrib/forgejo-cli#437) -- kept our dual-format content parser (JSON + legacy pipe) - `92d90ab` replace crossterm with terminal_size (forgejo-contrib/forgejo-cli#526) - `a0aa39f` optimize cargo release profile (forgejo-contrib/forgejo-cli#520) - `298a3ee` clippy fixes, applicable half (forgejo-contrib/forgejo-cli#531) - `b7192ce` org name message pluralization (fluent-only upstream; plain string here) - `e10940c` rand 0.10.1 security floor (forgejo-contrib/forgejo-cli#409) - `4eee04c` serde-saphyr 0.0.28 (consolidates six Renovate bumps; 0.0.x are mutually incompatible so Cargo.toml had to move) ### Skipped (~235 commits) - The entire fluent/l10n localization framework (forgejo-contrib/forgejo-cli#279) and all locale/Weblate commits -- fork policy - `1c1228e` auth_server unreachable fix, `799f35f` pr review panic fix -- both fix regressions introduced by l10n commits we don't carry - Lock file maintenance, upstream Woodpecker CI, release/publish infra, version bumps, README badge docs, issue templates ### Fork additions - New: `fj actions run list|view|jobs|logs|cancel|delete`, `fj actions artifact list|download|delete`, `fj actions tasks --status`, `fj pr search --base/--head` (new forgejo-api 0.10/0.11 endpoints, Forgejo v15/v16) - `main` runs the runtime on a 16 MiB thread: forgejo-api 0.11's larger structs overflow the 1 MiB Windows main-thread stack in debug builds - Dropped unused git2/uuid build-dependencies (was compiling a second vendored libgit2) - Corrected the codefloe.com OAuth client id to upstream's canonical value - `--repo`/`-r` on the new repo edit/units and pr review subcommands, mutation confirmations, verbose logging - Test suite grew ~40 tests (assign/unassign regression, archived warnings, readme casings, pr reviews, pr status skipped, actions surface, ssh config aliases, legacy keys.json compat) ### Live-testing fixes (found against codeberg.org and a v15 sandbox) - **Vendored forgejo-api with a pre-v16 compatibility patch** (`vendor/forgejo-api` via `[patch.crates-io]`): stock 0.11.0 requires key presence for many `Option` response fields, and Forgejo v15 omits several (`Organization.created` -- also inside `Team` objects embedded in PR responses -- and `PublicKey.updated_at`). On codeberg.org this broke `pr view`/`pr search --base` on any PR with a team review request, plus `org view` and `user key list`. The patch adds `serde(default)` to 183 presence-required `Option` fields; see `vendor/forgejo-api/PATCHES.md`. All four failures verified fixed against codeberg.org (15.0.0) and a 15.0.3 instance. - **`repo units <unit>` with no flags now reports status** instead of sending a no-op PATCH and claiming "Updated". - **ssh config `HostName` IP literals no longer rewrite the API host**: `Host git.example.com` + `HostName <ip>` redirects the ssh transport, but the domain is still the forge identity; the rewrite made fj derive `https://<ip>` as the API base and miss the saved login. All 25 test binaries pass (~320 tests). Live-tested read-only against codeberg.org/forgejo/forgejo (search, pagination, reviews, releases, activity) and mutating against a private v15 sandbox (issue lifecycle, milestones, repo create/edit/units/delete with dry-run, archived warnings, full PR create/status/checkout/squash-merge flow, scp-style remotes).
Follow-up to the cherry-picked upstream repo edit (41a9922) and repo units (90449f4) commands: add confirmation output via crate::output::success and verbose_log per fork mutation conventions, switch the repo arg to the --repo/-r flag matching the Labels subcommand, add wiremock coverage asserting the PATCH body, and accept the help_repo snapshot.
Covers the cherry-picked upstream migrate-owner feature (b075f78): the wiremock test asserts repo_owner/repo_name are split from the OWNER/NAME positional and sent in the POST body. Snapshot picks up the new migrate oneline helptext (92c163a).
It wasn't setting the `type` parameter in the API
request, so it was incorrectly listing both issue
and PRs.
Regression coverage for the cherry-picked upstream fix (c35fc0f): the wiremock matcher asserts the type=issues query param is sent so pull requests are excluded server-side.
Now that it's called right after refreshing, the only other place that
modifies the keys file is `auth` commands. Now `keys.save()` is only
called when it needs to be, instead of writing the file on every run.
Manual port of upstream c4defdb (not cherry-pickable, upstream version is entangled with the fluent l10n framework we don't adopt): introduces the AuthResponse struct and AuthServerReceiver alias, dropping the clippy type_complexity allowance. Also rewords the keys-file-not-found message since load no longer implies an immediate save after 1d455ac.
The cherry-picked upstream handlers passed &keys, but the fork's run() already holds a reference. Silences clippy needless_borrow.
Guards the new LoginInfo::refresh path from e0e1d04: only OAuth logins with an expired token should refresh; application tokens must pass through untouched.
Manual port of upstream e040613 (not cherry-pickable: the fork's view functions are wrapped in print_or_json closures). Deviates from upstream deliberately: the extra repo_get is gated on json_mode so --json output stays clean and agents don't pay for an API call they can't see, and the PR side resolves the base repo via repo_name_from_pr. Wiremock tests cover the warning in all three views plus expect(0) guards proving --json makes no repo fetch.
Follow-up to the cherry-picked pr reviews command (9d630f3): the Review variant gains the fork's --repo/-r flag matching the other pr subcommands, and wiremock tests cover default stale filtering, --all, the stale-only hint, the empty case, and --comments rendering including the file:position header that upstream's l10n port later broke (799f35f, not applicable to our plain-string version).
The cherry-picked upstream README casing rewrite (6eec300, supersedes fork commit b44d9ae) resolves the readme via the contents-list endpoint instead of probing fixed filenames, so the wiremock flow changed. Adds coverage for nonstandard casing (ReadMe.MD) and the no-readme failure path.
Port of upstream ba50965 and 8b82c17 (upstream PR #414), reimplemented as thin wrappers over the fork's existing edit_assignees instead of importing upstream's 240-line helpers, which duplicate that logic and carry an inverted retain predicate in unassign that wipes every assignee except the ones being removed (still unfixed at upstream HEAD). Assignee matching is now case-insensitive with the correct polarity, extracted into a pure apply_assignee_changes function with unit tests, plus wiremock regression coverage proving unassign preserves other assignees.
Applies the applicable half of upstream 298a3ee (the yaml.rs needless into_iter; the auth.rs hunk targets username-printing code the fork still has) plus a needless borrow introduced by the cherry-picked README rewrite.
Manual port of upstream 1df2ad5 (upstream PR #462). Deviates deliberately in two ways: the scp-style rewrite still runs when Url::parse fails outright, because WHATWG parsing rejects git@host:path remotes and upstream's version regresses them (verified against url 2.5.8, still broken at upstream HEAD); and HostName resolution is gated to ssh-scheme URLs so ssh config can never rewrite https remotes. Logic lives in ssh_url_parse_with(s, config) so unit tests stay hermetic instead of reading the developer's real ~/.ssh/config.
The `:` character in the URL that marks the port is
disallowed in git refspecs, so trying to checkout
a PR on a non-default port would fail.
Every subcommand's help now lists -H/--host after the cherry-picked 955e6db; the top-level help is unchanged since it already showed the flag.
Covers upstream 15e9fb2 and 1244fcc in one step (the intermediate 0.10.0 state has no value; the Renovate commits don't apply to our inline-table Cargo.toml). Code changes required by the bump: the skipped commit-status state gains a match arm in pr status (adapted from upstream f8dbe99, whose own diff is l10n-entangled), and the cherry-picked list_action_tasks query param (f474338) now compiles. 0.11 also fixes pr status against modern instances: CommitStatus.target_url is now String, so the relative URLs Forgejo returns no longer fail deserialization.
forgejo-api 0.11 made Organization.created and PublicKey.updated_at presence-required, so the org and ssh-key wiremock fixtures gain those keys; note this also means fj org/user key commands now require Forgejo v16+ servers. The larger 0.11 structs pushed debug-build futures past the 1 MiB Windows main-thread stack, so main now runs the runtime on a 16 MiB thread.
The e3ad8f2 cherry-pick landed with unresolved markers in migrate_repo; keep the corrected doesn't spelling with the fork's output::success call instead of upstream's ftl_println.
Port of upstream b7192ce, which fixed this string in the fluent files we don't carry; the same singular wording predates l10n and lives in src/org.rs here.
Port of upstream 447091d plus d5ab501's repo_name helper. The fork keeps its own issue_name content parsing (754892a), which handles both the JSON-array and legacy pipe formats where upstream's issue_content is JSON-only; both helpers are hoisted to module scope and unit-tested.
Fork equivalent of upstream e10940c (a lockfile-only Renovate commit that can't cherry-pick onto our divergent lock): the lock was still pinned to the vulnerable rand 0.10.0, and the Cargo.toml floor now encodes the fixed version.
The d53ac46/ff9e70c cherry-picks covered upstream's call sites; this migrates the fork's own: the eyre::Context import the wrap_err conversions need, and the origin-fallback remote scan (24e9236) where StringArray::iter now yields Results. Lock picks up auth-git2 0.6.0 and libgit2-sys 1.9.4.
As pointed out in #474, the license files did not contain the copyright
information required. I now filled in the current year and the
forgejo-cli developers as the copyright holders.
Port of upstream 92d90ab; crossterm was only used to read the terminal width and drops about a hundred transitive lock entries. Covers the fork-only call site in output.rs terminal_width that upstream doesn't have.
Ports upstream a0aa39f (lto plus single codegen unit for release builds) and consolidates the six serde-saphyr Renovate bumps in the range (d3e489f through 4eee04c): 0.0.x releases are mutually incompatible so the lock could never move past the pinned 0.0.22 without this Cargo.toml edit. Upstream needed no source changes across 0.0.22 to 0.0.28 and the issue-template tests stay green.
The fork picked up the id from upstream b572e85, but upstream superseded it in 07c17a8; matches upstream HEAD.
Lock maintenance equivalent to the Renovate lockfile commits skipped per sync policy; picks up the remaining compatible transitive bumps.
build.rs only forwards the TARGET env var; the git2 and uuid build-dependencies were never used, and the git2 one forced a second vendored libgit2 compile for the host on every clean build.
BTreeSet::insert returns true when the value was newly inserted, so the variable meant the opposite of its name; behavior unchanged.
The --repo inconsistency and upstream-pointing metadata notes were stale; replaced with the new load-bearing constraints from this sync: the Forgejo v16+ requirement from forgejo-api 0.11, the big-stack async_main workaround, and the per-mutation keys.save contract from 1d455ac.
Exposes the Forgejo Actions surface added in forgejo-api 0.10/0.11 (Forgejo v15/v16): run list/view/jobs/logs/cancel/delete with --ref/--workflow-id/--status filters, artifact list/download/delete with numeric-id-then-name resolution, and a repeatable --status filter on tasks. run delete and artifact delete follow the destructive-command template with --force/--dry-run and dry_run.rs cases; 13 new wiremock tests cover the endpoints and query params.
Uses forgejo-api 0.11's RepoListPullRequestsQuery.base/.head for server-side branch filtering. When either flag is given the command switches to the pulls endpoint (the issues endpoint the default path uses has no branch filters); labels and milestones are resolved name-to-ID for that path, and --assignee errors clearly there since the pulls endpoint has no assignee param. Note the --json shape on the filtered path is PullRequest objects rather than Issue objects.
Silences clippy for_kv_map left by the username-removal port; the map values are no longer read.
Fixes the confirmed findings from the branch review:
The archived-repo warning lookups in issue/pr view are now best-effort: a failed repo_get (scoped token, transient 5xx) skips the decorative warning instead of aborting a view that already fetched its payload.
label_names_to_ids errors on unresolved names instead of silently dropping them; on the pr search --base/--head path a typo'd --labels previously disabled the filter entirely (empty ID lists are omitted from the query), listing every PR instead of none. The strict behavior also fixes silent no-ops in issue/pr create label metadata.
pr review list now honors global --json (serializing the visible reviews, with comments when -c is set), treats a missing review id as an error instead of silently truncating the remaining reviews, drops REQUEST_REVIEW entries up front so request-only PRs print 'No reviews.' rather than a stale/dismissed hint that -a cannot satisfy.
artifact name resolution prefers the newest match and says so when several runs uploaded the same artifact name, instead of acting on whichever the server lists first. The repo units wiki help no longer promises a disable path that doesn't exist (forgejo-api#143).
Stock forgejo-api 0.11.0 makes many Option response fields presence-required (rfc3339::option and custom URL deserializers error on absent keys). Forgejo v15 omits several of them: Organization.created (also inside Team objects embedded in PR responses via requested_reviewers_teams), and PublicKey.updated_at. On codeberg.org (v15) this broke pr view / pr search --base on any PR with a team review request, plus org view and user key list.
Vendor the crate with serde(default) added to all 183 presence-required Option fields and apply it via [patch.crates-io]. Verified live against codeberg.org 15.0.0 and git.cathedral.gg 15.0.3: all four failing commands now succeed. See vendor/forgejo-api/PATCHES.md for details and removal criteria.
fj repo units <unit> with no options sent a no-op PATCH and printed 'Updated ... unit', found while live-testing against the sandbox. Compare the built EditRepoOption against NOOP_EDIT_REPO_OPTION and report the unit's current enabled state (JSON-aware via print_or_json) instead of editing. Regression test asserts GET is used and no PATCH is sent.
keep remote host when ssh config HostName is an IP literal
Some checks failed
Test / test (pull_request) Failing after 5m38s
a6eae5799b
An ssh config like 'Host git.example.com / HostName 178.156.199.96' redirects the ssh transport to an IP (common with Cloudron-style gateways), but the domain in the remote is still the forge's identity. Unconditionally rewriting the URL host made fj derive https://<ip> as the API base, which misses the saved login and fails TLS/vhost routing. Found live-testing an scp-style remote against git.cathedral.gg. Skip the rewrite when the resolved HostName parses as an IP address; alias-to-domain mappings still resolve as before.
Sign in to join this conversation.
No reviewers
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
stalecontext/forgejo-cli-plus!52
Reference in a new issue
stalecontext/forgejo-cli-plus
No description provided.
Delete branch "upstream-sync/2026-07-02"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?