gitea-release/src/main.rs

233 lines
7.7 KiB
Rust

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<String>,
}
// 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<Client> {
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<gitea::Release> = 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<gitea::Release> = 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<Row> = 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(())
}