pass enum
cargo devel CI / cargo CI (push) Successful in 4m4s Details

This commit is contained in:
Christoph J. Scherr 2024-02-24 13:24:14 +01:00
parent f12f5763d1
commit bd04eea9cc
Signed by: PlexSheep
GPG Key ID: 7CDD0B14851A08EF
11 changed files with 111 additions and 39 deletions

View File

@ -16,11 +16,13 @@ api:
type: github type: github
endpoint: https://github.com endpoint: https://github.com
auth: auth:
user: myUserName user: PlexSheep
pass: token_superimportantsecret pass:
myserv: env: TOKEN_GH
type: gitea cscherr:
type: forgejo
endpoint: https://git.cscherr.de endpoint: https://git.cscherr.de
auth: auth:
user: myUserName user: PlexSheep
pass: importantsecrettoken pass:
env: TOKEN_CSCHERR

View File

@ -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 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): repository. It should contain the following parameters (replace the placeholders):
| Parent | Key | Value | Explanation | | Parent | Key | Value | Explanation |
|-----------------|--------------|----------------------------------------------------------------------------------|------------------------------------------------------------------------------| |----------------------|--------------|----------------------------------------------------------------------------------|------------------------------------------------------------------------------|
| (root) | `changelog` | list of keys with this as parent (`git-log` etc) | information on how a changelog is generated | | (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` | `enable` | `true`/`false` | If false, no changelog will be generated |
| `changelog` | `git-log` | `true`/`false` | should a changelog be generated with `git log`? | | `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 | | (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 | | `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` | `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`. | | `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 | | (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` | `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` | `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` | 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` | `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 | | `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: An example `.autocrate.yaml` could look like this:
@ -102,13 +105,15 @@ api:
endpoint: https://github.com endpoint: https://github.com
auth: auth:
user: PlexSheep user: PlexSheep
pass: token_superimportantsecret pass:
text: token_superimportantsecret
cscherr: cscherr:
type: gitea type: gitea
endpoint: https://git.cscherr.de endpoint: https://git.cscherr.de
auth: auth:
user: PlexSheep user: PlexSheep
pass: Bearer importantsecrettoken pass:
file: secrettoken.txt
``` ```
After Autocrate has been bootstrapped, you it will be released and published After Autocrate has been bootstrapped, you it will be released and published

View File

@ -38,6 +38,7 @@ pub struct Cli {
#[derive(Debug, Clone, Subcommand)] #[derive(Debug, Clone, Subcommand)]
pub enum Commands { pub enum Commands {
Changelog {}, Changelog {},
/// Create a new release on the server
Release { Release {
// FIXME: allow taking a message like this: // FIXME: allow taking a message like this:
// `autocrate changelog -m arg1 arg2 arg3` // `autocrate changelog -m arg1 arg2 arg3`
@ -55,15 +56,26 @@ pub enum Commands {
// //
// TODO: // TODO:
// integrate a CHANGELOG.md file // integrate a CHANGELOG.md file
//
/// Message body of the release
#[arg(short, long)] #[arg(short, long)]
message: Option<Vec<String>>, message: Option<Vec<String>>,
/// generate and add a changelog
changelog: bool,
/// publish after releasing
publish: bool,
}, },
/// Publish to a package registry
Publish { Publish {
// see Commands::Release { message } // see Commands::Release { message }
#[arg(short, long)] #[arg(short, long)]
message: Option<Vec<String>>, message: Option<Vec<String>>,
}, },
///
Version {}, Version {},
Init {},
} }
impl Display for Commands { impl Display for Commands {
@ -76,6 +88,7 @@ impl Display for Commands {
Self::Release { .. } => "Release", Self::Release { .. } => "Release",
Self::Publish { .. } => "Publish", Self::Publish { .. } => "Publish",
Self::Version { .. } => "Version", Self::Version { .. } => "Version",
Self::Init { .. } => "Init",
} }
) )
} }

View File

@ -9,8 +9,8 @@ use crate::error::*;
pub mod cli; pub mod cli;
pub mod packages; pub mod packages;
use packages::*;
use cli::Cli; use cli::Cli;
use packages::*;
pub trait YamlConfigSection: Debug + Clone + for<'a> Deserialize<'a> { pub trait YamlConfigSection: Debug + Clone + for<'a> Deserialize<'a> {
fn check(&self) -> Result<()>; 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<String> {
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)] #[derive(Debug, Clone, Deserialize)]
pub struct ApiAuth { pub struct ApiAuth {
pub user: String, pub user: String,
pub pass: Option<String>, pub pass: Pass,
pub pass_file: Option<PathBuf>,
} }
impl YamlConfigSection for ApiAuth { impl YamlConfigSection for ApiAuth {
fn check(&self) -> Result<()> { fn check(&self) -> Result<()> {
if self.pass.is_some() && self.pass_file.is_some() { self.pass.check()?;
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());
}
}
Ok(()) Ok(())
} }
} }

View File

@ -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 anyhow;
use thiserror::Error; use thiserror::Error;
@ -45,4 +45,8 @@ pub enum ConfigError {
YamlApiAuthBothPass(ApiAuth), YamlApiAuthBothPass(ApiAuth),
#[error("password provided as file, but does not exist: {0}")] #[error("password provided as file, but does not exist: {0}")]
PassFileDoesNotExist(PathBuf), 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),
} }

View File

@ -32,6 +32,10 @@ async fn main() -> Result<()> {
// TODO: version select automated // TODO: version select automated
todo!() todo!()
} }
Commands::Init { .. } => {
// TODO: create a basic autocrate yaml
todo!()
}
}; };
Ok(()) Ok(())
} }

View File

@ -1,6 +1,6 @@
use crate::{config::Config, error::*, serverapi::ApiCollection}; 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: git tag
// TODO: push to each server // TODO: push to each server

View File

@ -15,9 +15,13 @@ impl ServerApi for Forgejo {
async fn push_release(&mut self) -> Result<()> { async fn push_release(&mut self) -> Result<()> {
todo!() todo!()
} }
async fn push_release_artifact(&mut self) -> Result<()> {
todo!()
}
async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> { async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> {
todo!() todo!()
} }
} }
impl Forgejo { impl Forgejo {

View File

@ -15,6 +15,9 @@ impl ServerApi for Gitea {
async fn push_release(&mut self) -> Result<()> { async fn push_release(&mut self) -> Result<()> {
todo!() todo!()
} }
async fn push_release_artifact(&mut self) -> Result<()> {
todo!()
}
async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> { async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> {
todo!() todo!()
} }

View File

@ -15,6 +15,9 @@ impl ServerApi for Github {
async fn push_release(&mut self) -> Result<()> { async fn push_release(&mut self) -> Result<()> {
todo!() todo!()
} }
async fn push_release_artifact(&mut self) -> Result<()> {
todo!()
}
async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> { async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> {
todo!() todo!()
} }

View File

@ -15,6 +15,9 @@ impl ServerApi for Gitlab {
async fn push_release(&mut self) -> Result<()> { async fn push_release(&mut self) -> Result<()> {
todo!() todo!()
} }
async fn push_release_artifact(&mut self) -> Result<()> {
todo!()
}
async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> { async fn push_pkg(&mut self, pkg_type: PackageType) -> Result<()> {
todo!() todo!()
} }