feat(hive-forge): add repo-create + repo-add-collaborator verbs
This commit is contained in:
parent
41c4682f7a
commit
3790faf318
5 changed files with 168 additions and 0 deletions
77
hive-forge/src/verbs/repo_create.rs
Normal file
77
hive-forge/src/verbs/repo_create.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//! `repo-create <name> [--description <d>] [--private] [--default-branch <b>]
|
||||
//! [--org <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<String>,
|
||||
/// 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<String>,
|
||||
/// Create under this organisation (`POST /orgs/<org>/repos`) instead
|
||||
/// of the authenticated user's namespace.
|
||||
#[arg(long)]
|
||||
org: Option<String>,
|
||||
/// 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(())
|
||||
}
|
||||
Loading…
Reference in a new issue