233 lines
7.7 KiB
Rust
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(())
|
|
}
|