diff --git a/.autocrate.yaml b/.autocrate.yaml new file mode 100644 index 0000000..eb8ea98 --- /dev/null +++ b/.autocrate.yaml @@ -0,0 +1,25 @@ +changelog: + enable: true + git-log: true + +uses: + cargo: + publish: true + # tokens are loaded from ~/.cargo/config.toml + registries: + - crates.io + - example.com + +api: + github: + type: github + endpoint: https://github.com + auth: + user: myUserName + pass: token_superimportantsecret + myserv: + type: gitea + endpoint: https://git.example.com + auth: + user: myUserName + pass: importantsecrettoken diff --git a/Cargo.toml b/Cargo.toml index 2c8be54..c281b4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,12 +20,15 @@ keywords = [ [dependencies] +anyhow = "1.0.79" clap = { version = "4.4.18", features = ["derive"] } clap-num = "1.1.1" clap-verbosity-flag = "2.1.2" +git2 = "0.18.1" libpt = { version = "0.3.11", features = ["log"] } serde = { version = "1.0.195", features = ["derive"] } serde_yaml = "0.9.30" +thiserror = "1.0.56" [[bin]] name = "autocrate" diff --git a/README.md b/README.md index adfd774..5ea9159 100644 --- a/README.md +++ b/README.md @@ -85,21 +85,30 @@ repository. It should contain the following parameters (replace the placeholders An example `.autocrate.yaml` could look like this: ```yaml changelog: -- enable: true -- git-log: true + enable: true + git-log: true uses: -- cargo: - - publish = true + cargo: + publish: true # tokens are loaded from ~/.cargo/config.toml - - registries: + registries: - crates.io - example.com api: github: - user: myUserName - pass: token_superimportantsecret + type: github + endpoint: https://github.com + auth: + user: myUserName + pass: token_superimportantsecret + myserv: + type: gitea + endpoint: https://git.example.com + auth: + user: myUserName + pass: importantsecrettoken ``` ## Using Autocrate diff --git a/src/config/cli.rs b/src/config/cli.rs new file mode 100644 index 0000000..0a72775 --- /dev/null +++ b/src/config/cli.rs @@ -0,0 +1,65 @@ +use serde; +use serde_yaml; + +use std::path::PathBuf; + +use libpt::log::{Level, Logger}; + +use clap::Parser; +use clap_verbosity_flag::{InfoLevel, Verbosity}; + +/// short about section displayed in help +const ABOUT_ROOT: &'static str = r##" +Release Manager for Your Projects on Gitea, GitHub, and GitLab. +"##; +/// longer about section displayed in help, is combined with [the short help](ABOUT_ROOT) +static LONG_ABOUT_ROOT: &'static str = r##""##; + +#[derive(Debug, Clone, Parser)] +#[command( + author, + version, + about = ABOUT_ROOT, + long_about = format!("{}{}", ABOUT_ROOT ,LONG_ABOUT_ROOT), + help_template = +r#"{about-section} +{usage-heading} {usage} +{all-args}{tab} + +autocrate: {version} +Author: {author-with-newline} +"# + )] +pub struct Cli { + // clap_verbosity_flag seems to make this a global option implicitly + /// set a verbosity, multiple allowed (f.e. -vvv) + #[command(flatten)] + pub(crate) verbose: Verbosity, + + /// show additional logging meta data + #[arg(long)] + pub(crate) meta: bool, +} + +impl Cli { + pub fn cli_parse() -> Self { + let cli = Self::parse(); + let ll: Level = match cli.verbose.log_level().unwrap().as_str() { + "TRACE" => Level::TRACE, + "DEBUG" => Level::DEBUG, + "INFO" => Level::INFO, + "WARN" => Level::WARN, + "ERROR" => Level::ERROR, + _ => { + unreachable!(); + } + }; + if cli.meta { + Logger::init(None, Some(ll), true).expect("could not initialize Logger"); + } else { + // less verbose version + Logger::init_mini(Some(ll)).expect("could not initialize Logger"); + } + return cli; + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..3ae3922 --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,86 @@ +use std::{ + fmt::{write, Debug}, fs::File, path::PathBuf +}; + +use anyhow::{anyhow, Result}; +use git2; +use libpt::log::error; +use serde::Deserialize; + +use self::cli::Cli; + +pub mod cli; + +#[derive(Debug, Clone, Deserialize)] +pub struct Changelog { + enabled: bool, + git_log: bool, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Uses { + cargo: Option, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Cargo { + publish: bool, + registries: Vec, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Api { + api_type: ApiType, + publish: bool, + registries: Vec, +} + +#[derive(Debug, Clone, Deserialize)] +pub enum ApiType { + Gitea, + Gitlab, + Github, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct YamlConfig { + pub changelog: Changelog, + pub uses: Uses, + pub apis: Vec, +} + +pub struct Config { + pub yaml: YamlConfig, + pub repo: git2::Repository, + pub path: PathBuf, +} + +impl Debug for Config { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + format!( + "Config {{yaml: {:?}, repo_path: {:?}}}", + self.yaml, self.path + ) + ) + } +} + +impl Config { + pub fn load(cli: Cli) -> Result { + let repo = match git2::Repository::open_from_env() { + Ok(repo) => repo, + Err(err) => { + let msg = format!("could not find a git repository: {err:?}"); + error!("{}", msg); + return Err(anyhow!(msg)); + } + }; + let mut path = repo.path().to_path_buf(); + path.pop(); // we want the real root, not the `.git` dir + + todo!() + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ef68c36 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod config; diff --git a/src/main.rs b/src/main.rs index e7a11a9..7e2beb5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,12 @@ -fn main() { - println!("Hello, world!"); +use anyhow::Result; + +mod config; +use config::{cli::Cli, Config}; + +fn main() -> Result<()> { + let cli = Cli::cli_parse(); + let config = Config::load(cli.clone())?; + + dbg!(config); + todo!() }