feat(packages): add fj packages command group (FJ-41) #51

Merged
nrupard merged 2 commits from feat/packages-command-FJ-41 into main 2026-06-08 20:08:59 +02:00
Member

Summary

Adds a fj packages command group for the Forgejo Packages registry, closing the verify-after-publish gap: after publishing to a Forgejo registry there was no terminal path to confirm the artifact landed (an auth-gated registry 401s an anonymous GET, leaving only the web UI), even though fj already holds the credentials.

Subcommands

  • packages list --owner <o> [--type <t>] - list an owner's packages.
  • packages versions <name> --owner <o> [--type <t>] - list one package's versions.
  • packages view <name> --owner <o> [--type <t>] [--version <v>] - with --version, show that single version plus its files and sha256 checksums; without it, list the package's versions.
  • packages delete <name> --owner <o> --type <t> --version <v> - delete a version behind a y/N confirmation (skipped under --json, matching repo delete).

Owner comes from --owner, else is inferred from --repo / the current git remote. --host and --format json / --json are honored like the other command groups; auth uses the existing keys.json credentials.

Design notes

  • Domain logic lives in a new fj_core::packages module (thin wrappers returning forgejo-api structs) so the planned MCP server can reuse it; rendering, the clap tree, and localization stay in the binary. The MCP-reuse contract grep (clap|crossterm|fluent in fj-core/fj-client) stays clean.
  • --type is validated up front against the ListPackagesQueryType enum via the serde rename the API already declares, so accepted spellings never drift from the wire format; an unknown type errors with the full accepted list.
  • versions narrows server-side with the name as a query, then keeps only exact name matches so a substring q hit on another package cannot leak in (the API has no exact-name version endpoint).
  • en-US and de-DE messages added.

Testing

cargo fmt --check, cargo clippy --all-targets -- -D warnings, and the full cargo test suite pass in the rust-builder-glibc image. Smoke-tested live against dev.a8n.run: list, versions, view (single-version with files, and no-version listing), --json for all, the --type filter, the unknown-type error, and the --version-without---type guard all behave. The destructive delete path mirrors the proven repo delete confirmation flow.

Closes FJ-41.

## Summary Adds a `fj packages` command group for the Forgejo Packages registry, closing the verify-after-publish gap: after publishing to a Forgejo registry there was no terminal path to confirm the artifact landed (an auth-gated registry 401s an anonymous GET, leaving only the web UI), even though `fj` already holds the credentials. ## Subcommands - `packages list --owner <o> [--type <t>]` - list an owner's packages. - `packages versions <name> --owner <o> [--type <t>]` - list one package's versions. - `packages view <name> --owner <o> [--type <t>] [--version <v>]` - with `--version`, show that single version plus its files and sha256 checksums; without it, list the package's versions. - `packages delete <name> --owner <o> --type <t> --version <v>` - delete a version behind a y/N confirmation (skipped under `--json`, matching `repo delete`). Owner comes from `--owner`, else is inferred from `--repo` / the current git remote. `--host` and `--format json` / `--json` are honored like the other command groups; auth uses the existing `keys.json` credentials. ## Design notes - Domain logic lives in a new `fj_core::packages` module (thin wrappers returning `forgejo-api` structs) so the planned MCP server can reuse it; rendering, the clap tree, and localization stay in the binary. The MCP-reuse contract grep (`clap|crossterm|fluent` in `fj-core`/`fj-client`) stays clean. - `--type` is validated up front against the `ListPackagesQueryType` enum via the serde rename the API already declares, so accepted spellings never drift from the wire format; an unknown type errors with the full accepted list. - `versions` narrows server-side with the name as a query, then keeps only exact name matches so a substring `q` hit on another package cannot leak in (the API has no exact-name version endpoint). - en-US and de-DE messages added. ## Testing `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, and the full `cargo test` suite pass in the rust-builder-glibc image. Smoke-tested live against `dev.a8n.run`: `list`, `versions`, `view` (single-version with files, and no-version listing), `--json` for all, the `--type` filter, the unknown-type error, and the `--version`-without-`--type` guard all behave. The destructive `delete` path mirrors the proven `repo delete` confirmation flow. Closes FJ-41.
feat(packages): add fj packages command group
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 37s
4d745fbfcd
Adds a `fj packages` command group that lists and reads the Forgejo Packages registry, backed by the `forgejo-api` package endpoints. This closes the verify-after-publish gap: after publishing to a Forgejo registry there was no terminal path to confirm the artifact landed (an auth-gated registry returns 401 to an anonymous GET, leaving only the web UI), even though `fj` already holds the credentials.

Subcommands: `list --owner <o> [--type <t>]` lists an owner's packages; `versions <name> --owner <o> [--type <t>]` lists one package's versions; `view <name> --owner <o> [--type <t>] [--version <v>]` shows metadata (with `--version` it shows that single version plus its files and checksums; without it, it lists versions); `delete <name> --owner <o> --type <t> --version <v>` deletes a version behind a y/N confirmation (skipped under `--json`, matching `repo delete`). Owner comes from `--owner`, else is inferred from `--repo` / the current git remote; `--host` and `--format json` / `--json` are honored like the other groups.

The domain logic lives in a new `fj_core::packages` module (thin wrappers returning `forgejo-api` structs) so a future MCP server can reuse it; rendering, the clap tree, and localization stay in the binary. `--type` is validated up front against the API enum via its own serde rename, so accepted spellings never drift from the wire format. `versions` filters list results to exact name matches so a substring query hit on another package cannot leak in. en-US and de-DE messages added.

#FJ-41

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(packages): emit RFC 3339 UTC timestamps and localize view date
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 37s
Create release / Create release from merged PR (pull_request) Has been skipped
5eaed6ac9b
The package JSON renderer formatted `created_at` with `OffsetDateTime::to_string()`, producing `2026-06-08 12:14:39.0 +02:00:00` (space-separated, not UTC-normalized) instead of the RFC 3339 the rest of the CLI's stable JSON emits (`release.rs`, `org.rs`, `issues.rs` all use `t.to_offset(UtcOffset::UTC).format(&Rfc3339)`). A consumer parsing the documented machine-readable timestamp as RFC 3339 would fail on packages output only. Add a `rfc3339_utc` helper matching that convention, make `package_to_json` fallible like `release_to_json`, and thread the `?` through the three callers.

The text `view` likewise printed the raw timestamp; switch it to the localized `DATETIME(...)` formatting `release view` uses, via `AsFluent::ftl`, so the en-US and de-DE `msg-packages-view-created` messages render a proper date (`Created June 8, 2026`).

#FJ-41

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nrupard deleted branch feat/packages-command-FJ-41 2026-06-08 20:08:59 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
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
pandoras-box/forgejo-cli!51
No description provided.