use anyhow::{anyhow, Result}; use reqwest::{header, Client}; use std::path::PathBuf; use structopt::StructOpt; mod gitea; #[derive(StructOpt, Debug)] struct Common { /// The gitea server to connect to #[structopt(short, long, env = "GITEA_SERVER")] server: String, /// The gitea token to authenticate with #[structopt(long, env = "GITEA_TOKEN")] token: String, /// The gitea user to authenticate as #[structopt(short, long, env = "GITEA_AUTH_USER")] auth_user: String, /// The owner of the gitea repo #[structopt(short, long, env = "GITEA_OWNER")] owner: String, /// The gitea repo to operate on #[structopt(short, long, env = "GITEA_REPO")] repo: String, /// The version tag to operate on #[structopt(short, long)] tag: Option, } // Name your user agent after your app? static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); fn client(c: &Common) -> Result { let mut headers = header::HeaderMap::new(); let auth = format!("token {}", &c.token); let auth = auth.as_str(); headers.insert(header::AUTHORIZATION, header::HeaderValue::from_str(auth)?); Ok(Client::builder() .user_agent(APP_USER_AGENT) .default_headers(headers) .build()?) } #[derive(StructOpt, Debug)] struct ReleaseMeta { /// Release name #[structopt(short, long, default_value = "")] name: String, /// Draft release #[structopt(long)] draft: bool, /// Pre-release (not suitable for production) #[structopt(short, long)] pre_release: bool, } #[derive(StructOpt, Debug)] #[structopt(about = "Gitea release assistant")] enum Cmd { /// Delete a given release from Gitea Delete { #[structopt(flatten)] common: Common, }, /// Downloads release artifacts Download { #[structopt(flatten)] common: Common, /// Folder to download release artifacts to #[structopt(short, long)] fname: PathBuf, }, /// Edits a release's description, name and other flags Edit { #[structopt(flatten)] common: Common, /// Release description #[structopt(short, long, default_value = "")] description: String, #[structopt(flatten)] release_meta: ReleaseMeta, }, /// Gets release info Info { #[structopt(flatten)] common: Common, #[structopt(long, short)] json: bool, }, /// Create a new tag and release on Gitea Release { #[structopt(flatten)] common: Common, /// Changelog file to read from to create the release description #[structopt(short, long, default_value = "./CHANGELOG.md")] changelog: PathBuf, #[structopt(flatten)] release_meta: ReleaseMeta, }, /// Uploads release artifacts to Gitea Upload { #[structopt(flatten)] common: Common, /// The name of the file #[structopt(short, long, default_value = "")] name: String, /// The description of the file #[structopt(short, long, default_value = "")] label: String, /// The location of the file on the disk #[structopt(short, long)] fname: PathBuf, /// Replace existing release artifacts? #[structopt(long)] replace: bool, }, } #[tokio::main] async fn main() -> Result<()> { let _ = kankyo::init(); let cmd = Cmd::from_args(); match cmd { Cmd::Delete { common } => { let cli = client(&common); } Cmd::Info { common, json } => { use cli_table::{Cell, Row, Table}; let cli = client(&common)?; let releases: Vec = cli .get( format!( "{}/api/v1/repos/{}/{}/releases", &common.server, &common.owner, &common.repo ) .as_str(), ) .send() .await? .json() .await?; match common.tag { Some(tag) => { let mut release: Option = None; for rls in releases { if tag == rls.tag_name { release = Some(rls); } } if release.is_none() { return Err(anyhow!("tag {} not found", tag)); } if json { println!("{}", serde_json::to_string_pretty(&release)?); } else { let rls = release.unwrap(); let table = Table::new( vec![ Row::new(vec![ Cell::new(&"id", Default::default()), Cell::new(&rls.id, Default::default()), ]), Row::new(vec![ Cell::new(&"author", Default::default()), Cell::new( &format!( "{} - {}", rls.author.full_name, rls.author.username ), Default::default(), ), ]), Row::new(vec![ Cell::new(&"tag", Default::default()), Cell::new(&rls.tag_name, Default::default()), ]), Row::new(vec![ Cell::new(&"created at", Default::default()), Cell::new(&rls.created_at, Default::default()), ]), Row::new(vec![ Cell::new(&"name", Default::default()), Cell::new(&rls.name, Default::default()), ]), Row::new(vec![ Cell::new(&"body", Default::default()), Cell::new(&rls.body, Default::default()), ]), ], Default::default(), )?; table.print_stdout()?; } } None => { if json { println!("{}", serde_json::to_string_pretty(&releases)?); } else { let mut rows: Vec = vec![Row::new(vec![ Cell::new(&"id", Default::default()), Cell::new(&"tag", Default::default()), Cell::new(&"created at", Default::default()), Cell::new(&"commit", Default::default()), Cell::new(&"author", Default::default()), Cell::new(&"name", Default::default()), ])]; for release in releases { rows.push(release.row()) } let table = Table::new(rows, Default::default())?; table.print_stdout()?; } } } } _ => { println!("{:?}", cmd); println!("not implemented yet") } } Ok(()) }