Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03f8bc8a6a | ||
|
|
311599e8f2 | ||
|
|
ef9935e3d0 | ||
|
|
c64136d094 |
10 changed files with 53 additions and 99 deletions
|
|
@ -36,24 +36,17 @@ use clap::{Parser, Subcommand};
|
||||||
disable_help_subcommand = true
|
disable_help_subcommand = true
|
||||||
)]
|
)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
/// Repo override (default from `HIVE_FORGE_REPO`).
|
/// Repo to act on, as `owner/name` (default: `HIVE_FORGE_REPO`).
|
||||||
/// Applies to any verb; replaces the per-verb `[repo]` trailing
|
/// Works with any verb.
|
||||||
/// positional the bash helper used.
|
|
||||||
#[arg(short = 'r', long, global = true)]
|
#[arg(short = 'r', long, global = true)]
|
||||||
repo: Option<String>,
|
repo: Option<String>,
|
||||||
/// Target an external forge account provisioned via the dashboard's
|
/// Act as a dashboard-provisioned external forge account (by its
|
||||||
/// FORGES tab, by label, instead of the internal forge. Reads
|
/// FORGES-tab label) instead of the internal forge. Independent of
|
||||||
/// `${HYPERHIVE_STATE_DIR}/forge-<label>-token` for the token and
|
/// `-r/--repo`.
|
||||||
/// `forge-<label>.json` for the base URL (the same two files the
|
|
||||||
/// dashboard writes) instead of `HIVE_FORGE_URL`/`forge-token`.
|
|
||||||
/// Orthogonal to `-r/--repo`, which still just picks which repo on
|
|
||||||
/// whichever forge is selected.
|
|
||||||
#[arg(short = 'f', long, global = true)]
|
#[arg(short = 'f', long, global = true)]
|
||||||
forge: Option<String>,
|
forge: Option<String>,
|
||||||
/// Emit JSON output instead of the verb's default human-readable
|
/// Emit JSON instead of the default human-readable output (for verbs
|
||||||
/// shape, for verbs that support both. Verbs whose
|
/// that support both).
|
||||||
/// only output is already JSON (`issue`, `pr`, etc.) ignore this
|
|
||||||
/// flag — they always print JSON regardless.
|
|
||||||
#[arg(long, global = true)]
|
#[arg(long, global = true)]
|
||||||
json: bool,
|
json: bool,
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
|
|
@ -80,8 +73,6 @@ enum Verb {
|
||||||
/// PR-scoped commands: `pr <show|status|create|merge|reviews|assign-reviewer|commits|diff|view|comment|comments|close|reopen|labels|assign-committer|timeline> …`.
|
/// PR-scoped commands: `pr <show|status|create|merge|reviews|assign-reviewer|commits|diff|view|comment|comments|close|reopen|labels|assign-committer|timeline> …`.
|
||||||
Pr(verbs::pr_cmd::Args),
|
Pr(verbs::pr_cmd::Args),
|
||||||
/// List a PR's commits as JSON (sha, message, author date, author).
|
/// List a PR's commits as JSON (sha, message, author date, author).
|
||||||
/// Survives rebase-rewritten shas — message + author date let a
|
|
||||||
/// caller match the rows against linear `main` history.
|
|
||||||
#[command(hide = true)]
|
#[command(hide = true)]
|
||||||
PrCommits(verbs::pr_commits::Args),
|
PrCommits(verbs::pr_commits::Args),
|
||||||
/// Create a pull request. Prints the PR URL on success.
|
/// Create a pull request. Prints the PR URL on success.
|
||||||
|
|
@ -115,21 +106,15 @@ enum Verb {
|
||||||
/// credentials auto-injected. Pairs with `pr-create --agit`.
|
/// credentials auto-injected. Pairs with `pr-create --agit`.
|
||||||
Clone(verbs::clone::Args),
|
Clone(verbs::clone::Args),
|
||||||
/// Create a forge repo under the current user (or `--org`). Prints
|
/// Create a forge repo under the current user (or `--org`). Prints
|
||||||
/// the repo URL. The instance disables push-to-create, so this is
|
/// the repo URL.
|
||||||
/// the supported path to a new repo. Pairs with `repo-add-collaborator`.
|
|
||||||
RepoCreate(verbs::repo_create::Args),
|
RepoCreate(verbs::repo_create::Args),
|
||||||
/// Add a collaborator to the active repo (`-r`/`HIVE_FORGE_REPO`)
|
/// Add a collaborator to the active repo (`-r`/`HIVE_FORGE_REPO`)
|
||||||
/// with a permission level. Companion to `repo-create`.
|
/// with a permission level. Companion to `repo-create`.
|
||||||
RepoAddCollaborator(verbs::repo_add_collaborator::Args),
|
RepoAddCollaborator(verbs::repo_add_collaborator::Args),
|
||||||
/// List the active repo's full label set (project-wide), optionally
|
/// List every label defined on the repo (name + description),
|
||||||
/// filtered by a name substring. Unlike `labels <number>` (which lists
|
/// optionally filtered by a name substring.
|
||||||
/// an issue/PR's labels), this shows every label defined on the repo —
|
|
||||||
/// the valid names + descriptions for triage / labelling. `--json`
|
|
||||||
/// emits the full label objects (id, name, color, description).
|
|
||||||
RepoLabels(verbs::repo_labels::Args),
|
RepoLabels(verbs::repo_labels::Args),
|
||||||
/// Search for repositories on the forge instance by keyword, topic, or
|
/// Search the forge for repositories by keyword, topic, or description.
|
||||||
/// description. Not repo-scoped — queries the instance-wide explore
|
|
||||||
/// endpoint. `--json` emits the full repository objects.
|
|
||||||
RepoSearch(verbs::repo_search::Args),
|
RepoSearch(verbs::repo_search::Args),
|
||||||
/// Triage lint queries (unassigned / no-reviewer / stale-branches / assignments).
|
/// Triage lint queries (unassigned / no-reviewer / stale-branches / assignments).
|
||||||
Lint(verbs::lint::Args),
|
Lint(verbs::lint::Args),
|
||||||
|
|
@ -178,18 +163,13 @@ enum Verb {
|
||||||
/// prints the path (pass `-o -` to stream raw bytes to stdout).
|
/// prints the path (pass `-o -` to stream raw bytes to stdout).
|
||||||
AttachmentGet(verbs::attachment_get::Args),
|
AttachmentGet(verbs::attachment_get::Args),
|
||||||
/// Download a CI Actions artifact from a run (`<name> --run <n>`).
|
/// Download a CI Actions artifact from a run (`<name> --run <n>`).
|
||||||
/// Forgejo serves artifacts only via the web route, not REST; the
|
/// Saves a zip, or pass `-o -` to stream to stdout.
|
||||||
/// caller supplies the run number + artifact name. Saves a zip
|
|
||||||
/// (or `-o -` to stream).
|
|
||||||
ArtifactGet(verbs::artifact_get::Args),
|
ArtifactGet(verbs::artifact_get::Args),
|
||||||
/// Print a CI Actions run's job step logs (`--run <n> [--job i]
|
/// Print a CI Actions run's job step logs
|
||||||
/// [--step i]`). Uses Forgejo's web run-view streamer (no REST
|
/// (`--run <n> [--job i] [--step i]`).
|
||||||
/// endpoint exists); reliable for live + recently-finished runs.
|
|
||||||
CiLog(verbs::ci_log::Args),
|
CiLog(verbs::ci_log::Args),
|
||||||
/// Re-run CI without an empty commit: dispatches a fresh run via the
|
/// Re-run CI without an empty commit. Pass one of `--pr <n>`,
|
||||||
/// workflow-dispatch API. Pass one of `--pr <n>` (the PR head branch),
|
/// `--run <n>`, or `--branch <name>`; `--workflow` defaults to `ci.yml`.
|
||||||
/// `--run <n>` (branch + workflow resolved from that run), or
|
|
||||||
/// `--branch <name>`; `--workflow <file>` defaults to `ci.yml`.
|
|
||||||
CiRerun(verbs::ci_rerun::Args),
|
CiRerun(verbs::ci_rerun::Args),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,20 +30,17 @@ use crate::client::Client;
|
||||||
|
|
||||||
#[derive(ClapArgs)]
|
#[derive(ClapArgs)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Workflow run number — the `runs/<n>` in the run-page URL, which
|
/// Workflow run number — the `runs/<n>` in the run-page URL (shown
|
||||||
/// `pr-status` surfaces as a CI context's `target_url`.
|
/// by `pr-status`).
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
run: u64,
|
run: u64,
|
||||||
/// Job index within the run (0-based; default 0 — the first job).
|
/// Job index within the run (0-based, default 0).
|
||||||
#[arg(long, default_value_t = 0)]
|
#[arg(long, default_value_t = 0)]
|
||||||
job: u64,
|
job: u64,
|
||||||
/// Print only this step's log (0-based). Omit to print every step.
|
/// Print only this step's log (0-based). Omit to print every step.
|
||||||
/// Honored on the live-streamer path only; the durable persisted-log
|
|
||||||
/// fallback serves a flat whole-job log and ignores `--step`.
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
step: Option<usize>,
|
step: Option<usize>,
|
||||||
/// Run attempt number for the durable persisted-log download (re-runs
|
/// Run attempt number (re-runs increment it; default 1).
|
||||||
/// increment it; default 1 covers the common single-attempt case).
|
|
||||||
#[arg(long, default_value_t = 1)]
|
#[arg(long, default_value_t = 1)]
|
||||||
attempt: u64,
|
attempt: u64,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,23 +35,21 @@ use crate::client::{Client, index};
|
||||||
|
|
||||||
#[derive(ClapArgs)]
|
#[derive(ClapArgs)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Re-run CI for this PR: resolves the PR's head branch and dispatches
|
/// Re-run CI for this PR (its head branch). Mutually exclusive with
|
||||||
/// `--workflow` on it. Mutually exclusive with `--run` / `--branch`.
|
/// `--run` / `--branch`.
|
||||||
#[arg(long, conflicts_with_all = ["run", "branch"])]
|
#[arg(long, conflicts_with_all = ["run", "branch"])]
|
||||||
pr: Option<u64>,
|
pr: Option<u64>,
|
||||||
/// Dispatch a fresh run of the workflow that produced this run, on the
|
/// Re-run the same workflow on the same branch this run used. The run
|
||||||
/// same branch the run used. The run number is the `runs/<n>` in the
|
/// number is the `runs/<n>` in the run-page URL. Mutually exclusive
|
||||||
/// run-page URL — what `pr-status` surfaces as a CI context's
|
/// with `--pr` / `--branch`.
|
||||||
/// `target_url`. Mutually exclusive with `--pr` / `--branch`.
|
|
||||||
#[arg(long, conflicts_with_all = ["pr", "branch"])]
|
#[arg(long, conflicts_with_all = ["pr", "branch"])]
|
||||||
run: Option<u64>,
|
run: Option<u64>,
|
||||||
/// Dispatch `--workflow` on this branch directly. Mutually exclusive
|
/// Re-run `--workflow` on this branch. Mutually exclusive with
|
||||||
/// with `--pr` / `--run`.
|
/// `--pr` / `--run`.
|
||||||
#[arg(long, conflicts_with_all = ["pr", "run"])]
|
#[arg(long, conflicts_with_all = ["pr", "run"])]
|
||||||
branch: Option<String>,
|
branch: Option<String>,
|
||||||
/// Workflow file to dispatch for `--pr` / `--branch` (the file name under
|
/// Workflow file to run (default `ci.yml`). Ignored for `--run`,
|
||||||
/// `.forgejo/workflows/`). Ignored for `--run`, which resolves the
|
/// which uses the run's own workflow.
|
||||||
/// workflow from the run itself (falling back to this value).
|
|
||||||
#[arg(long, default_value = "ci.yml")]
|
#[arg(long, default_value = "ci.yml")]
|
||||||
workflow: String,
|
workflow: String,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,15 +44,12 @@ const PAGE_SIZE: usize = 50;
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Issue or PR number.
|
/// Issue or PR number.
|
||||||
pub(crate) number: u64,
|
pub(crate) number: u64,
|
||||||
/// Page size for the head-of-thread shape (Forgejo caps at 50).
|
/// Number of comments from the start of the thread (max 50).
|
||||||
/// Mutually exclusive with `--tail`.
|
/// Mutually exclusive with `--tail`.
|
||||||
#[arg(long, default_value_t = 50, conflicts_with = "tail")]
|
#[arg(long, default_value_t = 50, conflicts_with = "tail")]
|
||||||
limit: u64,
|
limit: u64,
|
||||||
/// Return the last `N` comments in chronological order. Reads
|
/// Return the last `N` comments (chronological). Mutually exclusive
|
||||||
/// the issue's `comments` count first, then fetches only the
|
/// with `--limit`.
|
||||||
/// `ceil(N/50) + 1` pages that contain the tail — work is
|
|
||||||
/// bounded by N, not by thread length. Mutually exclusive with
|
|
||||||
/// `--limit`.
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
tail: Option<usize>,
|
tail: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,9 @@ use crate::client::{Client, index};
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// PR number.
|
/// PR number.
|
||||||
number: u64,
|
number: u64,
|
||||||
/// Print the unfiltered diff including autogenerated-file
|
/// Print the unfiltered diff. By default, autogenerated-file hunks
|
||||||
/// hunks (`flake.lock`, `Cargo.lock`, etc.). Default is to
|
/// (`flake.lock`, `Cargo.lock`, …) are collapsed to a placeholder so
|
||||||
/// collapse those hunks to a placeholder so the human-authored
|
/// human-authored changes stay readable.
|
||||||
/// changes aren't drowned in lock churn.
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
full: bool,
|
full: bool,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,10 +109,8 @@ struct NoReviewerArgs {
|
||||||
/// Filter by PR state.
|
/// Filter by PR state.
|
||||||
#[arg(long, value_enum, default_value_t = State::Open)]
|
#[arg(long, value_enum, default_value_t = State::Open)]
|
||||||
state: State,
|
state: State,
|
||||||
/// Reviewer login to look for (matches `@<reviewer>` in PR body or
|
/// Reviewer login to look for (matches `@<reviewer>` in the PR body
|
||||||
/// any comment). Required — defaulting to a specific name would
|
/// or any comment).
|
||||||
/// bake one deployment's reviewer convention into the binary
|
|
||||||
/// (flagged in review).
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
reviewer: String,
|
reviewer: String,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,12 +89,8 @@ pub struct Args {
|
||||||
/// ~50, applies). Must be >= 1.
|
/// ~50, applies). Must be >= 1.
|
||||||
#[arg(long, default_value_t = 30, value_parser = clap::value_parser!(u64).range(1..))]
|
#[arg(long, default_value_t = 30, value_parser = clap::value_parser!(u64).range(1..))]
|
||||||
limit: u64,
|
limit: u64,
|
||||||
/// Page number to fetch (1-based; default 1). Combine with `--limit`
|
/// Page number to fetch (1-based, default 1). Combine with `--limit`
|
||||||
/// to walk a large result set incrementally — fetch page 1, process,
|
/// to page through large result sets incrementally.
|
||||||
/// fetch page 2, … until a short/empty page. This keeps each call
|
|
||||||
/// token-bounded (one page at a time) instead of pulling a whole
|
|
||||||
/// repo's population into a single response. Must be >= 1 (the forge
|
|
||||||
/// pages are 1-based; page 0 is rejected).
|
|
||||||
#[arg(long, default_value_t = 1, value_parser = clap::value_parser!(u64).range(1..))]
|
#[arg(long, default_value_t = 1, value_parser = clap::value_parser!(u64).range(1..))]
|
||||||
page: u64,
|
page: u64,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,29 +48,22 @@ pub struct Args {
|
||||||
/// Read body from a file. `-` means stdin.
|
/// Read body from a file. `-` means stdin.
|
||||||
#[arg(long = "body-file")]
|
#[arg(long = "body-file")]
|
||||||
body_file: Option<String>,
|
body_file: Option<String>,
|
||||||
/// Open as draft. Ignored in `--agit` mode (the `AGit` push has no
|
/// Open as draft. Ignored in `--agit` mode.
|
||||||
/// draft push-option).
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
draft: bool,
|
draft: bool,
|
||||||
/// Push the local `--head` branch to `--remote` before creating
|
/// Push the local `--head` branch to `--remote` before creating the PR.
|
||||||
/// the PR. Suppresses forgejo's "Create / Visit a pull request"
|
|
||||||
/// hint block (we print the URL ourselves).
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
push: bool,
|
push: bool,
|
||||||
/// Remote name to push to. Defaults to the hyperhive convention
|
/// Remote to push to (default: `forge`, or `origin` in `--agit` mode).
|
||||||
/// `forge` for the normal flow, and `origin` in `--agit` mode (the
|
|
||||||
/// remote a `hive-forge clone` sets up).
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
remote: Option<String>,
|
remote: Option<String>,
|
||||||
/// Open the PR via Forgejo's `AGit` flow: push the current `HEAD`
|
/// Open the PR via Forgejo's `AGit` flow instead of pushing a branch —
|
||||||
/// to `refs/for/<base>/<topic>` instead of calling the REST API.
|
/// works for read-only collaborators. Run from inside a cloned repo.
|
||||||
/// Works for read-only collaborators (no branch-push needed). Run
|
|
||||||
/// from inside a cloned repo.
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
agit: bool,
|
agit: bool,
|
||||||
/// `AGit` topic — groups repeated pushes into ONE PR (re-running
|
/// `AGit` topic — groups repeated pushes into one PR (re-run with the
|
||||||
/// with the same topic updates it). Defaults to the current branch
|
/// same topic to update it). Defaults to the branch name. Only
|
||||||
/// name, or `contribution`. Only meaningful with `--agit`.
|
/// meaningful with `--agit`.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
topic: Option<String>,
|
topic: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ use crate::client::{Client, index, split_repo};
|
||||||
/// per-commit history, so a squash option isn't exposed).
|
/// per-commit history, so a squash option isn't exposed).
|
||||||
#[derive(Clone, Copy, ValueEnum)]
|
#[derive(Clone, Copy, ValueEnum)]
|
||||||
pub enum Method {
|
pub enum Method {
|
||||||
/// Create a merge commit (Forgejo `Do: merge`).
|
/// Create a merge commit.
|
||||||
Merge,
|
Merge,
|
||||||
/// Rebase the head branch onto the base then fast-forward (Forgejo `Do: rebase`).
|
/// Rebase the head branch onto the base, then fast-forward.
|
||||||
Rebase,
|
Rebase,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,13 +56,11 @@ pub struct Args {
|
||||||
/// Merge strategy (default: a merge commit). Squash is not offered.
|
/// Merge strategy (default: a merge commit). Squash is not offered.
|
||||||
#[arg(long, value_enum, default_value = "merge")]
|
#[arg(long, value_enum, default_value = "merge")]
|
||||||
method: Method,
|
method: Method,
|
||||||
/// Keep the head branch after merging. By default the head branch is
|
/// Keep the head branch after merging (deleted by default).
|
||||||
/// deleted once the merge succeeds.
|
|
||||||
#[arg(long = "keep-branch")]
|
#[arg(long = "keep-branch")]
|
||||||
keep_branch: bool,
|
keep_branch: bool,
|
||||||
/// Merge even if the PR is not mergeable, CI is not green, or a review
|
/// Merge even if the PR is not mergeable, CI is not green, or a review
|
||||||
/// requests changes. Also sets Forgejo's `force_merge` so the server does
|
/// requests changes.
|
||||||
/// not refuse on its own status checks.
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
force: bool,
|
force: bool,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,10 @@ pub struct Args {
|
||||||
/// Create the repo as private (default: public).
|
/// Create the repo as private (default: public).
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
private: bool,
|
private: bool,
|
||||||
/// Default branch name (e.g. `main`). Forgejo applies it to the
|
/// Default branch name (e.g. `main`). Only takes effect with `--auto-init`.
|
||||||
/// initial commit, so it only takes effect alongside `--auto-init`.
|
|
||||||
#[arg(long = "default-branch")]
|
#[arg(long = "default-branch")]
|
||||||
default_branch: Option<String>,
|
default_branch: Option<String>,
|
||||||
/// Create under this organisation (`POST /orgs/<org>/repos`) instead
|
/// Create under this organisation instead of your own namespace.
|
||||||
/// of the authenticated user's namespace.
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
org: Option<String>,
|
org: Option<String>,
|
||||||
/// Seed an initial commit (README) so the repo is non-empty and can
|
/// Seed an initial commit (README) so the repo is non-empty and can
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue