From bd04eea9ccfea18e4886b2f44ffdff0cb90773e0 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sat, 24 Feb 2024 13:24:14 +0100 Subject: [PATCH] pass enum --- .autocrate.yaml | 14 ++++++---- README.md | 39 ++++++++++++++------------ src/config/cli.rs | 13 +++++++++ src/config/mod.rs | 59 ++++++++++++++++++++++++++++++---------- src/error.rs | 6 +++- src/main.rs | 4 +++ src/release/mod.rs | 2 +- src/serverapi/forgejo.rs | 4 +++ src/serverapi/gitea.rs | 3 ++ src/serverapi/github.rs | 3 ++ src/serverapi/gitlab.rs | 3 ++ 11 files changed, 111 insertions(+), 39 deletions(-) diff --git a/.autocrate.yaml b/.autocrate.yaml index 9797223..52b1079 100644 --- a/.autocrate.yaml +++ b/.autocrate.yaml @@ -16,11 +16,13 @@ api: type: github endpoint: https://github.com auth: - user: myUserName - pass: token_superimportantsecret - myserv: - type: gitea + user: PlexSheep + pass: + env: TOKEN_GH + cscherr: + type: forgejo endpoint: https://git.cscherr.de auth: - user: myUserName - pass: importantsecrettoken + user: PlexSheep + pass: + env: TOKEN_CSCHERR diff --git a/README.md b/README.md index 86f688d..289cff0 100644 --- a/README.md +++ b/README.md @@ -65,21 +65,24 @@ locally, making it readily accessible through your command line interfaces. Create a YAML file named `.autocrate.yml` (or `.yaml`) in the root of your Git repository. It should contain the following parameters (replace the placeholders): -| Parent | Key | Value | Explanation | -|-----------------|--------------|----------------------------------------------------------------------------------|------------------------------------------------------------------------------| -| (root) | `changelog` | list of keys with this as parent (`git-log` etc) | information on how a changelog is generated | -| `changelog` | `enable` | `true`/`false` | If false, no changelog will be generated | -| `changelog` | `git-log` | `true`/`false` | should a changelog be generated with `git log`? | -| (root) | `uses` | list of keys with this as parent (`cargo` etc) | Marks features to be used by Autocrate | -| `uses` | `cargo` | list of keys with this as parent (`publish` etc) | tells us that your project uses cargo | -| `cargo` | `publish` | `true`/`false` | should we publish crates? | -| `cargo` | `registries` | registries see [this](https://doc.rust-lang.org/cargo/reference/registries.html) | A list of registries we should publish to. If empty defaults to `crates.io`. | -| (root) | `api` | list of names, which each have the same keys | defines the api we talk to | -| `api.NAME` | `type` | one of `gitea`,`github`,`gitlab` (currently only support for `gitea` | Let's us know which api type we are talking to | -| `api.NAME` | `endpoint` | Base URL of the target server | Let's us know which api type we are talking to | -| `api.NAME` | `auth` | list of keys with this as parent (`user` and `pass`) | We probably need authentication on the target server | -| `api.NAME.auth` | `user` | a string | Which user should we try to authenticate as | -| `api.NAME.auth` | `pass` | a string | A secret for authentication o the server, probably a token | +| Parent | Key | Value | Explanation | +|----------------------|--------------|----------------------------------------------------------------------------------|------------------------------------------------------------------------------| +| (root) | `changelog` | list of keys with this as parent (`git-log` etc) | information on how a changelog is generated | +| `changelog` | `enable` | `true`/`false` | If false, no changelog will be generated | +| `changelog` | `git-log` | `true`/`false` | should a changelog be generated with `git log`? | +| (root) | `uses` | list of keys with this as parent (`cargo` etc) | Marks features to be used by Autocrate | +| `uses` | `cargo` | list of keys with this as parent (`publish` etc) | tells us that your project uses cargo | +| `cargo` | `publish` | `true`/`false` | should we publish crates? | +| `cargo` | `registries` | registries see [this](https://doc.rust-lang.org/cargo/reference/registries.html) | A list of registries we should publish to. If empty defaults to `crates.io`. | +| (root) | `api` | list of names, which each have the same keys | defines the api we talk to | +| `api.NAME` | `type` | one of `gitea`,`github`,`gitlab` (currently only support for `gitea` | Let's us know which api type we are talking to | +| `api.NAME` | `endpoint` | Base URL of the target server | Let's us know which api type we are talking to | +| `api.NAME` | `auth` | list of keys with this as parent (`user` and `pass`) | We probably need authentication on the target server | +| `api.NAME.auth` | `user` | a string | Which user should we try to authenticate as | +| `api.NAME.auth` | `pass` | contains either of `text`, `env` or `file` | sets the secret for authentication with this server | +| `api.NAME.auth.pass` | `text` | a authentication pass as clear text | A secret for authentication of the server, probably a token | +| `api.NAME.auth.pass` | `env` | env var which contains the token | A secret for authentication of the server, probably a token | +| `api.NAME.auth.pass` | `file` | file var which contains the token | A secret for authentication of the server, probably a token | An example `.autocrate.yaml` could look like this: @@ -102,13 +105,15 @@ api: endpoint: https://github.com auth: user: PlexSheep - pass: token_superimportantsecret + pass: + text: token_superimportantsecret cscherr: type: gitea endpoint: https://git.cscherr.de auth: user: PlexSheep - pass: Bearer importantsecrettoken + pass: + file: secrettoken.txt ``` After Autocrate has been bootstrapped, you it will be released and published diff --git a/src/config/cli.rs b/src/config/cli.rs index 554b911..1f977a7 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -38,6 +38,7 @@ pub struct Cli { #[derive(Debug, Clone, Subcommand)] pub enum Commands { Changelog {}, + /// Create a new release on the server Release { // FIXME: allow taking a message like this: // `autocrate changelog -m arg1 arg2 arg3` @@ -55,15 +56,26 @@ pub enum Commands { // // TODO: // integrate a CHANGELOG.md file + // + /// Message body of the release #[arg(short, long)] message: Option>, + + /// generate and add a changelog + changelog: bool, + + /// publish after releasing + publish: bool, }, + /// Publish to a package registry Publish { // see Commands::Release { message } #[arg(short, long)] message: Option>, }, + /// Version {}, + Init {}, } impl Display for Commands { @@ -76,6 +88,7 @@ impl Display for Commands { Self::Release { .. } => "Release", Self::Publish { .. } => "Publish", Self::Version { .. } => "Version", + Self::Init { .. } => "Init", } ) } diff --git a/src/config/mod.rs b/src/config/mod.rs index 6f8bb45..0e5e7b9 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -9,8 +9,8 @@ use crate::error::*; pub mod cli; pub mod packages; -use packages::*; use cli::Cli; +use packages::*; pub trait YamlConfigSection: Debug + Clone + for<'a> Deserialize<'a> { fn check(&self) -> Result<()>; @@ -50,25 +50,56 @@ impl YamlConfigSection for Uses { } } +#[derive(Debug, Clone, Deserialize)] +pub enum Pass { + /// pass specified as plainext + Text(String), + /// pass to be loaded from an env var + Env(String), + /// pass to be loaded from a file + File(PathBuf), +} +impl Pass { + /// Get the pass, extracting from the underlying source + fn get_pass(&self) -> Result { + self.check()?; + Ok(match self { + Self::Text(pass) => pass.clone(), + Self::Env(key) => std::env::var(key).map_err(|err| ConfigError::from(err))?, + Self::File(file) => std::fs::read_to_string(file)?, + }) + } +} +impl YamlConfigSection for Pass { + fn check(&self) -> Result<()> { + match self { + Self::Text(_) => (), + Self::Env(envvar) => { + if !std::env::var(envvar) + .map_err(ConfigError::from)? + .is_empty() + { + } else { + return Err(ConfigError::EnvNotSet(envvar.clone()).into()); + } + } + Self::File(file) => { + if !file.exists() { + return Err(ConfigError::PassFileDoesNotExist(file.clone()).into()); + } + } + }; + Ok(()) + } +} #[derive(Debug, Clone, Deserialize)] pub struct ApiAuth { pub user: String, - pub pass: Option, - pub pass_file: Option, + pub pass: Pass, } impl YamlConfigSection for ApiAuth { fn check(&self) -> Result<()> { - if self.pass.is_some() && self.pass_file.is_some() { - let err = ConfigError::YamlApiAuthBothPass(self.clone()).into(); - error!("{err}"); - return Err(err); - } - if self.pass_file.is_some() { - let file = self.pass_file.clone().unwrap(); - if !file.exists() { - return Err(ConfigError::PassFileDoesNotExist(file).into()); - } - } + self.pass.check()?; Ok(()) } } diff --git a/src/error.rs b/src/error.rs index deb1e8a..e0d5b06 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -use std::{path::PathBuf, process::ExitStatus, string::FromUtf8Error}; +use std::{env::VarError, path::PathBuf, process::ExitStatus, string::FromUtf8Error}; use anyhow; use thiserror::Error; @@ -45,4 +45,8 @@ pub enum ConfigError { YamlApiAuthBothPass(ApiAuth), #[error("password provided as file, but does not exist: {0}")] PassFileDoesNotExist(PathBuf), + #[error("config requires environment variable {0}, but {0} is not set")] + EnvNotSet(String), + #[error("Bad value for environment variable: {0}")] + BadEnv(#[from] VarError), } diff --git a/src/main.rs b/src/main.rs index 98641ae..81770d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,10 @@ async fn main() -> Result<()> { // TODO: version select automated todo!() } + Commands::Init { .. } => { + // TODO: create a basic autocrate yaml + todo!() + } }; Ok(()) } diff --git a/src/release/mod.rs b/src/release/mod.rs index 4f51099..9c8eee9 100644 --- a/src/release/mod.rs +++ b/src/release/mod.rs @@ -1,6 +1,6 @@ use crate::{config::Config, error::*, serverapi::ApiCollection}; -pub async fn release(_cfg: &Config, _apis: &mut ApiCollection) -> Result<()> { +pub async fn release(cfg: &Config, apis: &mut ApiCollection) -> Result<()> { // TODO: git tag // TODO: push to each server diff --git a/src/serverapi/forgejo.rs b/src/serverapi/forgejo.rs index e854a04..011eeba 100644 --- a/src/serverapi/forgejo.rs +++ b/src/serverapi/forgejo.rs @@ -15,9 +15,13 @@ impl ServerApi for Forgejo { async fn push_release(&mut self) -> Result<()> { todo!() } + async fn push_release_artifact(&mut self) -> Result<()> { + todo!() + } async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> { todo!() } + } impl Forgejo { diff --git a/src/serverapi/gitea.rs b/src/serverapi/gitea.rs index 7c74584..425fd74 100644 --- a/src/serverapi/gitea.rs +++ b/src/serverapi/gitea.rs @@ -15,6 +15,9 @@ impl ServerApi for Gitea { async fn push_release(&mut self) -> Result<()> { todo!() } + async fn push_release_artifact(&mut self) -> Result<()> { + todo!() + } async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> { todo!() } diff --git a/src/serverapi/github.rs b/src/serverapi/github.rs index a7be38a..1456dff 100644 --- a/src/serverapi/github.rs +++ b/src/serverapi/github.rs @@ -15,6 +15,9 @@ impl ServerApi for Github { async fn push_release(&mut self) -> Result<()> { todo!() } + async fn push_release_artifact(&mut self) -> Result<()> { + todo!() + } async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> { todo!() } diff --git a/src/serverapi/gitlab.rs b/src/serverapi/gitlab.rs index 2d47f34..fc330bd 100644 --- a/src/serverapi/gitlab.rs +++ b/src/serverapi/gitlab.rs @@ -15,6 +15,9 @@ impl ServerApi for Gitlab { async fn push_release(&mut self) -> Result<()> { todo!() } + async fn push_release_artifact(&mut self) -> Result<()> { + todo!() + } async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> { todo!() }