mirror of
https://codeberg.org/Cyborus/forgejo-cli.git
synced 2024-11-10 12:09:33 +01:00
Merge pull request 'improve organization' (#2) from organize into main
Reviewed-on: https://codeberg.org/Cyborus/forgejo-cli/pulls/2
This commit is contained in:
commit
1a7f0de260
3 changed files with 167 additions and 145 deletions
59
src/auth.rs
Normal file
59
src/auth.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use clap::Subcommand;
|
||||||
|
|
||||||
|
#[derive(Subcommand, Clone, Debug)]
|
||||||
|
pub enum AuthCommand {
|
||||||
|
Login,
|
||||||
|
Logout {
|
||||||
|
host: String,
|
||||||
|
},
|
||||||
|
AddKey {
|
||||||
|
/// The domain name of the forgejo instance.
|
||||||
|
host: String,
|
||||||
|
/// The user that the key is associated with
|
||||||
|
user: String,
|
||||||
|
/// The key to add. If not present, the key will be read in from stdin.
|
||||||
|
key: Option<String>,
|
||||||
|
},
|
||||||
|
List,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthCommand {
|
||||||
|
pub async fn run(self, keys: &mut crate::KeyInfo) -> eyre::Result<()> {
|
||||||
|
match self {
|
||||||
|
AuthCommand::Login => {
|
||||||
|
todo!();
|
||||||
|
// let user = readline("username: ").await?;
|
||||||
|
// let pass = readline("password: ").await?;
|
||||||
|
}
|
||||||
|
AuthCommand::Logout { host } => {
|
||||||
|
let info_opt = keys.hosts.remove(&host);
|
||||||
|
if let Some(info) = info_opt {
|
||||||
|
eprintln!("signed out of {}@{}", &info.username(), host);
|
||||||
|
} else {
|
||||||
|
eprintln!("already not signed in to {host}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AuthCommand::AddKey { host, user, key } => {
|
||||||
|
let key = match key {
|
||||||
|
Some(key) => key,
|
||||||
|
None => crate::readline("new key: ").await?,
|
||||||
|
};
|
||||||
|
if keys.hosts.get(&user).is_none() {
|
||||||
|
keys.hosts.insert(host, crate::keys::LoginInfo::new(user, key));
|
||||||
|
} else {
|
||||||
|
println!("key for {} already exists", host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AuthCommand::List => {
|
||||||
|
if keys.hosts.is_empty() {
|
||||||
|
println!("No logins.");
|
||||||
|
}
|
||||||
|
for (host_url, login_info) in &keys.hosts {
|
||||||
|
println!("{}@{}", login_info.username(), host_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
152
src/main.rs
152
src/main.rs
|
@ -9,6 +9,9 @@ use url::Url;
|
||||||
mod keys;
|
mod keys;
|
||||||
use keys::*;
|
use keys::*;
|
||||||
|
|
||||||
|
mod repo;
|
||||||
|
mod auth;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct App {
|
pub struct App {
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
|
@ -18,53 +21,13 @@ pub struct App {
|
||||||
#[derive(Subcommand, Clone, Debug)]
|
#[derive(Subcommand, Clone, Debug)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
Repo(RepoCommand),
|
Repo(repo::RepoCommand),
|
||||||
User {
|
User {
|
||||||
#[clap(long, short)]
|
#[clap(long, short)]
|
||||||
host: Option<String>,
|
host: Option<String>,
|
||||||
},
|
},
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
Auth(AuthCommand),
|
Auth(auth::AuthCommand),
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subcommand, Clone, Debug)]
|
|
||||||
pub enum RepoCommand {
|
|
||||||
Create {
|
|
||||||
host: String,
|
|
||||||
repo: String,
|
|
||||||
|
|
||||||
// flags
|
|
||||||
#[clap(long, short)]
|
|
||||||
description: Option<String>,
|
|
||||||
#[clap(long, short)]
|
|
||||||
private: bool,
|
|
||||||
/// Sets the new repo to be the `origin` remote of the current local repo.
|
|
||||||
#[clap(long, short)]
|
|
||||||
set_upstream: Option<String>,
|
|
||||||
/// Pushes the current branch to the default branch on the new repo.
|
|
||||||
/// Implies `--set-upstream=origin` (setting upstream manual overrides this)
|
|
||||||
#[clap(long, short)]
|
|
||||||
push: bool,
|
|
||||||
},
|
|
||||||
Info,
|
|
||||||
Browse,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subcommand, Clone, Debug)]
|
|
||||||
pub enum AuthCommand {
|
|
||||||
Login,
|
|
||||||
Logout {
|
|
||||||
host: String,
|
|
||||||
},
|
|
||||||
AddKey {
|
|
||||||
/// The domain name of the forgejo instance.
|
|
||||||
host: String,
|
|
||||||
/// The user that the key is associated with
|
|
||||||
user: String,
|
|
||||||
/// The key to add. If not present, the key will be read in from stdin.
|
|
||||||
key: Option<String>,
|
|
||||||
},
|
|
||||||
List,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
@ -73,75 +36,7 @@ async fn main() -> eyre::Result<()> {
|
||||||
let mut keys = KeyInfo::load().await?;
|
let mut keys = KeyInfo::load().await?;
|
||||||
|
|
||||||
match args.command {
|
match args.command {
|
||||||
Command::Repo(repo_subcommand) => match repo_subcommand {
|
Command::Repo(repo_subcommand) => repo_subcommand.run(&keys).await?,
|
||||||
RepoCommand::Create {
|
|
||||||
host,
|
|
||||||
repo,
|
|
||||||
|
|
||||||
description,
|
|
||||||
private,
|
|
||||||
set_upstream,
|
|
||||||
push,
|
|
||||||
} => {
|
|
||||||
let host = Url::parse(&host)?;
|
|
||||||
let login = keys.get_login(&host)?;
|
|
||||||
let api = login.api_for(&host)?;
|
|
||||||
let repo_spec = CreateRepoOption {
|
|
||||||
auto_init: false,
|
|
||||||
default_branch: "main".into(),
|
|
||||||
description,
|
|
||||||
gitignores: String::new(),
|
|
||||||
issue_labels: String::new(),
|
|
||||||
license: String::new(),
|
|
||||||
name: repo.clone(),
|
|
||||||
private,
|
|
||||||
readme: String::new(),
|
|
||||||
template: false,
|
|
||||||
trust_model: forgejo_api::TrustModel::Default,
|
|
||||||
};
|
|
||||||
let new_repo = api.create_repo(repo_spec).await?;
|
|
||||||
eprintln!(
|
|
||||||
"created new repo at {}",
|
|
||||||
host.join(&format!("{}/{}", login.username(), repo))?
|
|
||||||
);
|
|
||||||
|
|
||||||
let upstream = set_upstream.as_deref().unwrap_or("origin");
|
|
||||||
|
|
||||||
let repo = git2::Repository::open(".")?;
|
|
||||||
let mut remote = if set_upstream.is_some() || push {
|
|
||||||
repo.remote(upstream, new_repo.clone_url.as_str())?
|
|
||||||
} else {
|
|
||||||
repo.find_remote(upstream)?
|
|
||||||
};
|
|
||||||
|
|
||||||
if push {
|
|
||||||
remote.push::<&str>(&[], None)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RepoCommand::Info => {
|
|
||||||
let (host, repo) = keys.get_current()?;
|
|
||||||
let api = host.api()?;
|
|
||||||
let repo = api.get_repo(repo.owner(), repo.name()).await?;
|
|
||||||
match repo {
|
|
||||||
Some(repo) => {
|
|
||||||
dbg!(repo);
|
|
||||||
}
|
|
||||||
None => eprintln!("repo not found"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RepoCommand::Browse => {
|
|
||||||
let (host, repo) = keys.get_current()?;
|
|
||||||
let mut url = host.url().clone();
|
|
||||||
let new_path = format!(
|
|
||||||
"{}/{}/{}",
|
|
||||||
url.path().strip_suffix("/").unwrap_or(url.path()),
|
|
||||||
repo.owner(),
|
|
||||||
repo.name(),
|
|
||||||
);
|
|
||||||
url.set_path(&new_path);
|
|
||||||
open::that(url.as_str())?;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Command::User { host } => {
|
Command::User { host } => {
|
||||||
let host = host.map(|host| Url::parse(&host)).transpose()?;
|
let host = host.map(|host| Url::parse(&host)).transpose()?;
|
||||||
let (url, name) = match host {
|
let (url, name) = match host {
|
||||||
|
@ -153,40 +48,7 @@ async fn main() -> eyre::Result<()> {
|
||||||
};
|
};
|
||||||
eprintln!("currently signed in to {name}@{url}");
|
eprintln!("currently signed in to {name}@{url}");
|
||||||
}
|
}
|
||||||
Command::Auth(auth_subcommand) => match auth_subcommand {
|
Command::Auth(auth_subcommand) => auth_subcommand.run(&mut keys).await?,
|
||||||
AuthCommand::Login => {
|
|
||||||
todo!();
|
|
||||||
// let user = readline("username: ").await?;
|
|
||||||
// let pass = readline("password: ").await?;
|
|
||||||
}
|
|
||||||
AuthCommand::Logout { host } => {
|
|
||||||
let info_opt = keys.hosts.remove(&host);
|
|
||||||
if let Some(info) = info_opt {
|
|
||||||
eprintln!("signed out of {}@{}", &info.username(), host);
|
|
||||||
} else {
|
|
||||||
eprintln!("already not signed in to {host}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AuthCommand::AddKey { host, user, key } => {
|
|
||||||
let key = match key {
|
|
||||||
Some(key) => key,
|
|
||||||
None => readline("new key: ").await?,
|
|
||||||
};
|
|
||||||
if keys.hosts.get(&user).is_none() {
|
|
||||||
keys.hosts.insert(host, LoginInfo::new(user, key));
|
|
||||||
} else {
|
|
||||||
println!("key for {} already exists", host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AuthCommand::List => {
|
|
||||||
if keys.hosts.is_empty() {
|
|
||||||
println!("No logins.");
|
|
||||||
}
|
|
||||||
for (host_url, login_info) in &keys.hosts {
|
|
||||||
println!("{}@{}", login_info.username(), host_url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keys.save().await?;
|
keys.save().await?;
|
||||||
|
|
101
src/repo.rs
Normal file
101
src/repo.rs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
use clap::Subcommand;
|
||||||
|
use url::Url;
|
||||||
|
use forgejo_api::CreateRepoOption;
|
||||||
|
|
||||||
|
#[derive(Subcommand, Clone, Debug)]
|
||||||
|
pub enum RepoCommand {
|
||||||
|
Create {
|
||||||
|
host: String,
|
||||||
|
repo: String,
|
||||||
|
|
||||||
|
// flags
|
||||||
|
#[clap(long, short)]
|
||||||
|
description: Option<String>,
|
||||||
|
#[clap(long, short)]
|
||||||
|
private: bool,
|
||||||
|
/// Sets the new repo to be the `origin` remote of the current local repo.
|
||||||
|
#[clap(long, short)]
|
||||||
|
set_upstream: Option<String>,
|
||||||
|
/// Pushes the current branch to the default branch on the new repo.
|
||||||
|
/// Implies `--set-upstream=origin` (setting upstream manual overrides this)
|
||||||
|
#[clap(long, short)]
|
||||||
|
push: bool,
|
||||||
|
},
|
||||||
|
Info,
|
||||||
|
Browse,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RepoCommand {
|
||||||
|
pub async fn run(self, keys: &crate::KeyInfo) -> eyre::Result<()> {
|
||||||
|
match self {
|
||||||
|
RepoCommand::Create {
|
||||||
|
host,
|
||||||
|
repo,
|
||||||
|
|
||||||
|
description,
|
||||||
|
private,
|
||||||
|
set_upstream,
|
||||||
|
push,
|
||||||
|
} => {
|
||||||
|
let host = Url::parse(&host)?;
|
||||||
|
let login = keys.get_login(&host)?;
|
||||||
|
let api = login.api_for(&host)?;
|
||||||
|
let repo_spec = CreateRepoOption {
|
||||||
|
auto_init: false,
|
||||||
|
default_branch: "main".into(),
|
||||||
|
description,
|
||||||
|
gitignores: String::new(),
|
||||||
|
issue_labels: String::new(),
|
||||||
|
license: String::new(),
|
||||||
|
name: repo.clone(),
|
||||||
|
private,
|
||||||
|
readme: String::new(),
|
||||||
|
template: false,
|
||||||
|
trust_model: forgejo_api::TrustModel::Default,
|
||||||
|
};
|
||||||
|
let new_repo = api.create_repo(repo_spec).await?;
|
||||||
|
eprintln!(
|
||||||
|
"created new repo at {}",
|
||||||
|
host.join(&format!("{}/{}", login.username(), repo))?
|
||||||
|
);
|
||||||
|
|
||||||
|
let upstream = set_upstream.as_deref().unwrap_or("origin");
|
||||||
|
|
||||||
|
let repo = git2::Repository::open(".")?;
|
||||||
|
let mut remote = if set_upstream.is_some() || push {
|
||||||
|
repo.remote(upstream, new_repo.clone_url.as_str())?
|
||||||
|
} else {
|
||||||
|
repo.find_remote(upstream)?
|
||||||
|
};
|
||||||
|
|
||||||
|
if push {
|
||||||
|
remote.push::<&str>(&[], None)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RepoCommand::Info => {
|
||||||
|
let (host, repo) = keys.get_current()?;
|
||||||
|
let api = host.api()?;
|
||||||
|
let repo = api.get_repo(repo.owner(), repo.name()).await?;
|
||||||
|
match repo {
|
||||||
|
Some(repo) => {
|
||||||
|
dbg!(repo);
|
||||||
|
}
|
||||||
|
None => eprintln!("repo not found"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RepoCommand::Browse => {
|
||||||
|
let (host, repo) = keys.get_current()?;
|
||||||
|
let mut url = host.url().clone();
|
||||||
|
let new_path = format!(
|
||||||
|
"{}/{}/{}",
|
||||||
|
url.path().strip_suffix("/").unwrap_or(url.path()),
|
||||||
|
repo.owner(),
|
||||||
|
repo.name(),
|
||||||
|
);
|
||||||
|
url.set_path(&new_path);
|
||||||
|
open::that(url.as_str())?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue