diff --git a/hive-forge/src/client.rs b/hive-forge/src/client.rs index 2bc0093a..ace4a3b3 100644 --- a/hive-forge/src/client.rs +++ b/hive-forge/src/client.rs @@ -206,29 +206,6 @@ impl Client { decode_json(resp, &format!("PUT {url}")) } - /// PUT a JSON body to `/` for an endpoint that returns - /// `204 No Content` (empty body), so there is nothing to decode. - /// Used by `repo-add-collaborator` (Forgejo's add-collaborator PUT - /// answers 204 on success). - /// - /// # Errors - /// - /// Returns an error if the request fails to send (transport/network - /// error) or the server responds with a non-2xx status (the response - /// body is included in the error). - pub fn put_no_content(&self, path: &str, body: &B) -> Result<()> { - let url = format!("{}{}", self.api(), path); - let resp = self - .http - .put(&url) - .header(CONTENT_TYPE, "application/json") - .json(body) - .send() - .context("PUT")?; - check_status(resp, &format!("PUT {url}"))?; - Ok(()) - } - /// DELETE `/`. Optional JSON body for endpoints that /// need it (Forgejo's subscription unwatch uses bodyless DELETE). pub fn delete(&self, path: &str, body: Option<&Value>) -> Result<()> { diff --git a/hive-forge/src/main.rs b/hive-forge/src/main.rs index 7b63d70c..4f99bfb1 100644 --- a/hive-forge/src/main.rs +++ b/hive-forge/src/main.rs @@ -80,13 +80,6 @@ enum Verb { /// Clone a forge repo (default `-r`/`HIVE_FORGE_REPO`) with /// credentials auto-injected. Pairs with `pr-create --agit`. Clone(verbs::clone::Args), - /// Create a forge repo under the current user (or `--org`). Prints - /// the repo URL. The instance disables push-to-create, so this is - /// the supported path to a new repo. Pairs with `repo-add-collaborator`. - RepoCreate(verbs::repo_create::Args), - /// Add a collaborator to the active repo (`-r`/`HIVE_FORGE_REPO`) - /// with a permission level. Companion to `repo-create`. - RepoAddCollaborator(verbs::repo_add_collaborator::Args), /// Triage lint queries (unassigned / no-reviewer / stale-branches / assignments). Lint(verbs::lint::Args), /// List issues / PRs with filters (`--kind`, `--state`, `--assignee`, @@ -137,8 +130,6 @@ fn main() -> Result<()> { Verb::Labels(a) => verbs::labels::run(&client, a), Verb::PrStatus(a) => verbs::pr_status::run(&client, a), Verb::Clone(a) => verbs::clone::run(&client, a), - Verb::RepoCreate(a) => verbs::repo_create::run(&client, a), - Verb::RepoAddCollaborator(a) => verbs::repo_add_collaborator::run(&client, a), Verb::Lint(a) => verbs::lint::run(&client, a), Verb::List(a) => verbs::list::run(&client, a), Verb::Milestone(a) => verbs::milestone::run(&client, a), diff --git a/hive-forge/src/verbs/mod.rs b/hive-forge/src/verbs/mod.rs index 578e1610..ad0d8fbd 100644 --- a/hive-forge/src/verbs/mod.rs +++ b/hive-forge/src/verbs/mod.rs @@ -25,8 +25,6 @@ pub mod pr; pub mod pr_create; pub mod pr_reviews; pub mod pr_status; -pub mod repo_add_collaborator; -pub mod repo_create; pub mod subscription; pub mod timeline; pub mod tree_sha; diff --git a/hive-forge/src/verbs/repo_add_collaborator.rs b/hive-forge/src/verbs/repo_add_collaborator.rs deleted file mode 100644 index 7fa24068..00000000 --- a/hive-forge/src/verbs/repo_add_collaborator.rs +++ /dev/null @@ -1,63 +0,0 @@ -//! `repo-add-collaborator [--permission read|write|admin] [-r ]` -//! — add `` as a collaborator on the active repo (from `-r` / -//! `HIVE_FORGE_REPO`). Prints a one-line confirmation. -//! -//! Wraps `PUT /api/v1/repos/{owner}/{repo}/collaborators/{collaborator}`. -//! A fresh agent-namespace repo (see `repo-create`) usually needs peers -//! added before they can collaborate; this is the companion verb. - -use anyhow::Result; -use clap::Args as ClapArgs; -use clap::ValueEnum; -use serde_json::json; - -use crate::client::Client; - -/// Collaborator permission level accepted by Forgejo. -#[derive(Clone, Copy, ValueEnum)] -pub enum Permission { - /// Pull (read-only) access. - Read, - /// Push (read/write) access. - Write, - /// Full administrative access to the repo. - Admin, -} - -impl Permission { - /// The wire string Forgejo's API expects. - fn as_api(self) -> &'static str { - match self { - Permission::Read => "read", - Permission::Write => "write", - Permission::Admin => "admin", - } - } -} - -#[derive(ClapArgs)] -pub struct Args { - /// Collaborator's forge login to add. - user: String, - /// Permission level to grant (default: write — a freshly added - /// collaborator usually needs to push). - #[arg(long, value_enum, default_value_t = Permission::Write)] - permission: Permission, -} - -/// # Errors -/// -/// Propagates any transport error from the Forgejo REST call (network -/// unreachable, 4xx/5xx response such as an unknown user or insufficient -/// permission on the repo, token missing/invalid) and any I/O error from -/// writing the confirmation to stdout. -pub fn run(client: &Client, args: Args) -> Result<()> { - let repo = client.repo(); - let perm = args.permission.as_api(); - client.put_no_content( - &format!("/repos/{repo}/collaborators/{}", args.user), - &json!({ "permission": perm }), - )?; - println!("added {} to {repo} ({perm})", args.user); - Ok(()) -} diff --git a/hive-forge/src/verbs/repo_create.rs b/hive-forge/src/verbs/repo_create.rs deleted file mode 100644 index edaef007..00000000 --- a/hive-forge/src/verbs/repo_create.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! `repo-create [--description ] [--private] [--default-branch ] -//! [--org ] [--auto-init]` — create a forge repository under the current -//! user (or under `--org`). Prints the new repo's web URL (or the full repo -//! object under `--json`). -//! -//! Wraps `POST /api/v1/user/repos` (or `/orgs/{org}/repos`) so agents don't -//! reach for raw API calls when the operator greenlights a new repo — the -//! instance has push-to-create disabled, so `git push` to a non-existent -//! repo 403s. Pairs with `clone` (then push your content) and -//! `repo-add-collaborator` (add peers to a fresh agent-namespace repo). - -use anyhow::Result; -use clap::Args as ClapArgs; -use serde_json::{Value, json}; - -use crate::client::Client; -use crate::verbs::print_json; - -#[derive(ClapArgs)] -pub struct Args { - /// Repository name (required). Created under the authenticated user - /// unless `--org` is given. - name: String, - /// Repository description. - #[arg(long)] - description: Option, - /// Create the repo as private (default: public). - #[arg(long)] - private: bool, - /// Default branch name (e.g. `main`). Forgejo applies it to the - /// initial commit, so it only takes effect alongside `--auto-init`. - #[arg(long = "default-branch")] - default_branch: Option, - /// Create under this organisation (`POST /orgs//repos`) instead - /// of the authenticated user's namespace. - #[arg(long)] - org: Option, - /// Seed an initial commit (README) so the repo is non-empty and can - /// be cloned immediately. Omit to create a bare repo you push into. - #[arg(long = "auto-init")] - auto_init: bool, -} - -/// # Errors -/// -/// Propagates any transport error from the Forgejo REST call (network -/// unreachable, 4xx/5xx response such as a name clash or insufficient -/// permission on the target namespace, token missing/invalid) and any -/// I/O error from writing the result to stdout. -pub fn run(client: &Client, args: Args) -> Result<()> { - let mut payload = json!({ - "name": args.name, - "private": args.private, - "auto_init": args.auto_init, - }); - if let Some(d) = args.description { - payload["description"] = json!(d); - } - if let Some(b) = args.default_branch { - payload["default_branch"] = json!(b); - } - - let path = match args.org.as_deref() { - Some(org) => format!("/orgs/{org}/repos"), - None => "/user/repos".to_owned(), - }; - let resp = client.post_json(&path, &payload)?; - - if client.json_mode() { - return print_json(&resp); - } - // Default human path: print the web URL, like issue-create / pr-create. - if let Some(url) = resp.get("html_url").and_then(Value::as_str) { - println!("{url}"); - } - Ok(()) -}