diff --git a/.config.bk/cargo.toml b/.config/cargo.toml similarity index 100% rename from .config.bk/cargo.toml rename to .config/cargo.toml diff --git a/Cargo.lock b/Cargo.lock index 40c82bc..85bb670 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -344,6 +344,7 @@ dependencies = [ "chrono", "clap", "conventional_commit_parser", + "cuddle-please-frontend", "dotenv", "git-cliff-core", "lazy_static", @@ -361,6 +362,23 @@ dependencies = [ "url", ] +[[package]] +name = "cuddle-please-frontend" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "dotenv", + "pretty_assertions", + "serde", + "serde_yaml", + "tempdir", + "tracing", + "tracing-subscriber", + "tracing-test", +] + [[package]] name = "deunicode" version = "0.4.3" diff --git a/Cargo.toml b/Cargo.toml index f2ca9ce..b0915df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,10 @@ [workspace] -members = ["crates/cuddle-please"] +members = ["crates/cuddle-please", "crates/cuddle-please-frontend"] resolver = "2" [workspace.dependencies] cuddle-please = { path = "crates/cuddle-please" } +cuddle-please-frontend = { path = "crates/cuddle-please-frontend" } anyhow = { version = "1.0.71" } tracing = { version = "0.1", features = ["log"] } diff --git a/README.md b/README.md index cd8eaaf..9027885 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ See docs for more information about installation and some such ### 0.1 Milestone - [x] Hide unneccessary commands -- [ ] Redo configuration frontend +- [x] Redo configuration frontend - [ ] Refactor command.rs into smaller bits so that bits are easier to test - [ ] Add reporter for PR and Repositories - [ ] Setup temporary git name and email to use for git committing diff --git a/crates/cuddle-please-frontend/Cargo.toml b/crates/cuddle-please-frontend/Cargo.toml new file mode 100644 index 0000000..cb05727 --- /dev/null +++ b/crates/cuddle-please-frontend/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "cuddle-please-frontend" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +clap.workspace = true +dotenv.workspace = true +serde_yaml.workspace = true +serde.workspace = true +chrono.workspace = true +tempdir.workspace = true + +[dev-dependencies] +tracing-test = { workspace = true, features = ["no-env-filter"] } +pretty_assertions.workspace = true diff --git a/crates/cuddle-please-frontend/src/gatheres/cli.rs b/crates/cuddle-please-frontend/src/gatheres/cli.rs new file mode 100644 index 0000000..54dec55 --- /dev/null +++ b/crates/cuddle-please-frontend/src/gatheres/cli.rs @@ -0,0 +1,71 @@ +use std::path::PathBuf; + +use clap::Args; + +use crate::stage0_config::{ + PleaseConfigBuilder, PleaseProjectConfigBuilder, PleaseSettingsConfigBuilder, +}; + +#[derive(Args, Debug, Clone)] +pub struct ConfigArgs { + /// Which repository to publish against. If not supplied remote url will be inferred from environment or fail if not present. + #[arg( + env = "CUDDLE_PLEASE_API_URL", + long, + global = true, + help_heading = "Config" + )] + pub api_url: Option, + + /// repo is the name of repository you want to release for + #[arg( + env = "CUDDLE_PLEASE_REPO", + long, + global = true, + help_heading = "Config" + )] + pub repo: Option, + + /// owner is the name of user from which the repository belongs / + #[arg( + env = "CUDDLE_PLEASE_OWNER", + long, + global = true, + help_heading = "Config" + )] + pub owner: Option, + + /// which source directory to use, if not set `std::env::current_dir` is used instead. + #[arg( + env = "CUDDLE_PLEASE_SOURCE", + long, + global = true, + help_heading = "Config" + )] + pub source: Option, + + /// which branch is being run from + #[arg( + env = "CUDDLE_PLEASE_BRANCH", + long, + global = true, + help_heading = "Config" + )] + pub branch: Option, +} + +impl From for PleaseConfigBuilder { + fn from(value: ConfigArgs) -> Self { + Self { + project: Some(PleaseProjectConfigBuilder { + owner: value.owner, + repository: value.repo, + source: value.source, + branch: value.branch, + }), + settings: Some(PleaseSettingsConfigBuilder { + api_url: value.api_url, + }), + } + } +} diff --git a/crates/cuddle-please-frontend/src/gatheres/config_file.rs b/crates/cuddle-please-frontend/src/gatheres/config_file.rs new file mode 100644 index 0000000..8cae974 --- /dev/null +++ b/crates/cuddle-please-frontend/src/gatheres/config_file.rs @@ -0,0 +1,80 @@ +use std::path::{Path, PathBuf}; + +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +use crate::stage0_config::PleaseConfigBuilder; + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct CuddleEmbeddedPleaseConfig { + please: PleaseConfigBuilder, +} + +impl From for PleaseConfigBuilder { + fn from(value: CuddleEmbeddedPleaseConfig) -> Self { + value.please + } +} +#[derive(Debug, Clone, Serialize, Deserialize)] +struct CuddlePleaseConfig { + #[serde(flatten)] + please: PleaseConfigBuilder, +} +impl From for PleaseConfigBuilder { + fn from(value: CuddlePleaseConfig) -> Self { + value.please + } +} + +const CUDDLE_FILE_NAME: &str = "cuddle"; +const CUDDLE_CONFIG_FILE_NAME: &str = "cuddle.please"; +const YAML_EXTENSION: &str = "yaml"; + +pub fn get_config_from_config_file(current_dir: &Path) -> PleaseConfigBuilder { + let current_cuddle_path = current_dir + .clone() + .join(format!("{CUDDLE_FILE_NAME}.{YAML_EXTENSION}")); + let current_cuddle_config_path = current_dir + .clone() + .join(format!("{CUDDLE_CONFIG_FILE_NAME}.{YAML_EXTENSION}")); + let mut please_config = PleaseConfigBuilder::default(); + + if let Some(config) = get_config_from_file::(current_cuddle_path) { + please_config = please_config.merge(&config).clone(); + } + + if let Some(config) = get_config_from_file::(current_cuddle_config_path) { + please_config = please_config.merge(&config).clone(); + } + + please_config +} + +pub fn get_config_from_file(current_cuddle_path: PathBuf) -> Option +where + T: DeserializeOwned, + T: Into, +{ + match std::fs::File::open(¤t_cuddle_path) { + Ok(file) => match serde_yaml::from_reader::<_, T>(file) { + Ok(config) => { + return Some(config.into()); + } + Err(e) => { + tracing::debug!( + "{} doesn't contain a valid please config: {}", + ¤t_cuddle_path.display(), + e + ); + } + }, + Err(e) => { + tracing::debug!( + "did not find or was not allowed to read {}, error: {}", + ¤t_cuddle_path.display(), + e, + ); + } + } + + None +} diff --git a/crates/cuddle-please-frontend/src/gatheres/execution_env.rs b/crates/cuddle-please-frontend/src/gatheres/execution_env.rs new file mode 100644 index 0000000..bb97a9e --- /dev/null +++ b/crates/cuddle-please-frontend/src/gatheres/execution_env.rs @@ -0,0 +1,53 @@ +use std::{collections::HashMap, path::PathBuf}; + +use crate::stage0_config::{PleaseConfigBuilder, PleaseProjectConfigBuilder}; + +pub fn get_from_environment(vars: std::env::Vars) -> PleaseConfigBuilder { + let vars: HashMap = vars.collect(); + + let env = detect_environment(&vars); + + match env { + ExecutionEnvironment::Local => PleaseConfigBuilder { + project: Some(PleaseProjectConfigBuilder { + source: Some(PathBuf::from(".")), + ..Default::default() + }), + settings: None, + }, + ExecutionEnvironment::Drone => PleaseConfigBuilder { + project: Some(PleaseProjectConfigBuilder { + owner: Some( + vars.get("DRONE_REPO_OWNER") + .expect("DRONE_REPO_OWNER to be present") + .clone(), + ), + repository: Some( + vars.get("DRONE_REPO_NAME") + .expect("DRONE_REPO_NAME to be present") + .clone(), + ), + source: Some(PathBuf::from(".")), + branch: Some( + vars.get("DRONE_REPO_BRANCH") + .expect("DRONE_REPO_BRANCH to be present") + .clone(), + ), + }), + settings: None, + }, + } +} + +pub fn detect_environment(vars: &HashMap) -> ExecutionEnvironment { + if let Some(_) = vars.get("DRONE".into()) { + return ExecutionEnvironment::Drone; + } + + ExecutionEnvironment::Local +} + +pub enum ExecutionEnvironment { + Local, + Drone, +} diff --git a/crates/cuddle-please-frontend/src/gatheres/mod.rs b/crates/cuddle-please-frontend/src/gatheres/mod.rs new file mode 100644 index 0000000..0ec8679 --- /dev/null +++ b/crates/cuddle-please-frontend/src/gatheres/mod.rs @@ -0,0 +1,9 @@ +mod cli; +mod config_file; +mod execution_env; +mod stdin; + +pub use cli::ConfigArgs; +pub(crate) use config_file::get_config_from_config_file; +pub(crate) use execution_env::get_from_environment; +pub(crate) use stdin::get_config_from_stdin; diff --git a/crates/cuddle-please-frontend/src/gatheres/stdin.rs b/crates/cuddle-please-frontend/src/gatheres/stdin.rs new file mode 100644 index 0000000..f718330 --- /dev/null +++ b/crates/cuddle-please-frontend/src/gatheres/stdin.rs @@ -0,0 +1,19 @@ +use serde::Deserialize; + +use crate::stage0_config::PleaseConfigBuilder; + +pub fn get_config_from_stdin<'d, T>(stdin: &'d str) -> PleaseConfigBuilder +where + T: Deserialize<'d>, + T: Into, +{ + match serde_yaml::from_str::<'d, T>(stdin) { + Ok(config) => { + return config.into(); + } + Err(e) => { + tracing::debug!("stdin doesn't contain a valid please config: {}", e); + } + } + PleaseConfigBuilder::default() +} diff --git a/crates/cuddle-please-frontend/src/lib.rs b/crates/cuddle-please-frontend/src/lib.rs new file mode 100644 index 0000000..011efa4 --- /dev/null +++ b/crates/cuddle-please-frontend/src/lib.rs @@ -0,0 +1,95 @@ +use std::path::{Path, PathBuf}; + +pub mod gatheres; +mod stage0_config; + +pub use gatheres::ConfigArgs; + +#[derive(Debug, Clone)] +pub struct PleaseProjectConfig { + pub owner: String, + pub repository: String, + pub source: PathBuf, + pub branch: String, +} + +#[derive(Debug, Clone)] +pub struct PleaseSettingsConfig { + pub api_url: String, +} + +#[derive(Debug, Clone)] +pub struct PleaseConfig { + pub project: PleaseProjectConfig, + pub settings: PleaseSettingsConfig, +} + +impl PleaseConfig { + pub fn get_owner<'a>(&'a self) -> &'a str { + &self.project.owner + } + pub fn get_repository<'a>(&'a self) -> &'a str { + &self.project.repository + } + pub fn get_source<'a>(&'a self) -> &'a PathBuf { + &self.project.source + } + pub fn get_branch<'a>(&'a self) -> &'a str { + &self.project.branch + } + pub fn get_api_url<'a>(&'a self) -> &'a str { + &self.settings.api_url + } +} + +#[derive(Clone, Debug, Default)] +pub struct PleaseConfigBuilder { + stdin: Option, + execution_env: Option, + cli: Option, + config: Option, +} + +impl PleaseConfigBuilder { + pub fn new() -> Self { + Self { + ..Default::default() + } + } + + pub fn with_stdin(&mut self, stdin: String) -> &mut Self { + self.stdin = Some(gatheres::get_config_from_stdin::< + stage0_config::PleaseConfigBuilder, + >(stdin.as_str())); + self + } + + pub fn with_config_file(&mut self, current_dir: &Path) -> &mut Self { + self.config = Some(gatheres::get_config_from_config_file(current_dir)); + + self + } + + pub fn with_execution_env(&mut self, env_bag: std::env::Vars) -> &mut Self { + self.execution_env = Some(gatheres::get_from_environment(env_bag)); + self + } + + pub fn with_cli(&mut self, cli: gatheres::ConfigArgs) -> &mut Self { + self.cli = Some(cli.into()); + self + } + + pub fn build(&mut self) -> anyhow::Result { + let gathered = vec![&self.execution_env, &self.config, &self.stdin, &self.cli]; + + let final_config = gathered + .into_iter() + .flatten() + .fold(stage0_config::PleaseConfigBuilder::default(), |mut a, x| { + a.merge(x).clone() + }); + + Ok(final_config.try_into()?) + } +} diff --git a/crates/cuddle-please-frontend/src/stage0_config.rs b/crates/cuddle-please-frontend/src/stage0_config.rs new file mode 100644 index 0000000..9108101 --- /dev/null +++ b/crates/cuddle-please-frontend/src/stage0_config.rs @@ -0,0 +1,111 @@ +use std::{default, path::PathBuf}; + +use serde::{Deserialize, Serialize}; + +use crate::{PleaseConfig, PleaseProjectConfig, PleaseSettingsConfig}; + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PleaseProjectConfigBuilder { + pub owner: Option, + pub repository: Option, + pub source: Option, + pub branch: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PleaseSettingsConfigBuilder { + pub api_url: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PleaseConfigBuilder { + pub project: Option, + pub settings: Option, +} + +impl PleaseConfigBuilder { + pub fn merge(&mut self, config: &PleaseConfigBuilder) -> &Self { + let config = config.clone(); + let mut fproject = match self.project.clone() { + None => PleaseProjectConfigBuilder::default(), + Some(project) => project, + }; + let mut fsettings = match self.settings.clone() { + None => PleaseSettingsConfigBuilder::default(), + Some(settings) => settings, + }; + + if let Some(mut project) = config.project { + if let Some(owner) = project.owner { + fproject.owner = Some(owner); + } + if let Some(repository) = project.repository { + fproject.repository = Some(repository); + } + if let Some(source) = project.source { + fproject.source = Some(source); + } + if let Some(branch) = project.branch { + fproject.branch = Some(branch); + } + self.project = Some(fproject); + } + + if let Some(mut settings) = config.settings { + if let Some(api_url) = settings.api_url { + fsettings.api_url = Some(api_url); + } + + self.settings = Some(fsettings); + } + + self + } +} + +impl TryFrom for PleaseConfig { + type Error = anyhow::Error; + + fn try_from(value: PleaseConfigBuilder) -> Result { + Ok(Self { + project: value + .project + .ok_or(value_is_missing("project"))? + .try_into()?, + settings: value + .settings + .ok_or(value_is_missing("settings"))? + .try_into()?, + }) + } +} + +impl TryFrom for PleaseProjectConfig { + type Error = anyhow::Error; + + fn try_from(value: PleaseProjectConfigBuilder) -> Result { + Ok(Self { + owner: value.owner.ok_or(value_is_missing("owner"))?, + repository: value.repository.ok_or(value_is_missing("repository"))?, + source: value.source.ok_or(value_is_missing("source"))?, + branch: value.branch.ok_or(value_is_missing("branch"))?, + }) + } +} + +impl TryFrom for PleaseSettingsConfig { + type Error = anyhow::Error; + + fn try_from(value: PleaseSettingsConfigBuilder) -> Result { + Ok(Self { + api_url: value.api_url.ok_or(value_is_missing("api_url"))?, + }) + } +} + +fn value_is_missing(message: &str) -> anyhow::Error { + anyhow::anyhow!( + "{} is required, pass via. cli, env or config file, see --help", + message.to_string() + ) +} diff --git a/crates/cuddle-please/Cargo.toml b/crates/cuddle-please/Cargo.toml index c863442..c013a6a 100644 --- a/crates/cuddle-please/Cargo.toml +++ b/crates/cuddle-please/Cargo.toml @@ -4,6 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] +cuddle-please-frontend.workspace = true + anyhow.workspace = true tracing.workspace = true tracing-subscriber.workspace = true diff --git a/crates/cuddle-please/src/command.rs b/crates/cuddle-please/src/command.rs index 46adcdd..5584577 100644 --- a/crates/cuddle-please/src/command.rs +++ b/crates/cuddle-please/src/command.rs @@ -8,11 +8,10 @@ use std::{ use ::semver::Version; use anyhow::Context; use clap::{Args, Parser, Subcommand}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use cuddle_please_frontend::{gatheres::ConfigArgs, PleaseConfig, PleaseConfigBuilder}; use crate::{ cliff::{self, changelog_parser}, - environment::get_from_environment, git_client::VcsClient, gitea_client::GiteaClient, ui::{ConsoleUi, DynUi}, @@ -27,6 +26,9 @@ pub struct Command { #[command(flatten)] global: GlobalArgs, + #[command(flatten)] + config: ConfigArgs, + #[command(subcommand)] commands: Option, @@ -49,32 +51,13 @@ struct GlobalArgs { )] token: Option, - /// Which repository to publish against. If not supplied remote url will be inferred from environment or fail if not present. - #[arg(long, global = true, help_heading = "Global")] - api_url: Option, - - /// repo is the name of repository you want to release for - #[arg(long, global = true, help_heading = "Global")] - repo: Option, - - /// owner is the name of user from which the repository belongs / - #[arg(long, global = true, help_heading = "Global")] - owner: Option, - - /// which source directory to use, if not set `std::env::current_dir` is used instead. - #[arg(long, global = true, help_heading = "Global")] - source: Option, - - /// which branch is being run from - #[arg(long, global = true, help_heading = "Global")] - branch: Option, - /// whether to run in dry run mode (i.e. no pushes or releases) #[arg(long, global = true, help_heading = "Global")] dry_run: bool, /// Inject configuration from stdin #[arg( + env = "CUDDLE_PLEASE_CONFIG_STDIN", long, global = true, help_heading = "Global", @@ -138,31 +121,23 @@ impl Command { s } - fn get_config( - &self, - current_dir: &Path, - stdin: Option, - ) -> anyhow::Result { - let mut config = get_config(current_dir, stdin)?; - - self.get_from_environment(&mut config)?; - - Ok(config) - } - pub fn execute(self, current_dir: Option<&Path>) -> anyhow::Result<()> { - // 1. Parse the current directory - let current_dir = get_current_path(current_dir, self.global.source.clone())?; - let stdin = if self.global.config_stdin { + // 0. Get config + let mut builder = &mut PleaseConfigBuilder::new(); + + if self.global.config_stdin { if let Some(stdin_fn) = self.stdin.clone() { let output = (stdin_fn.lock().unwrap().deref())(); - Some(output.unwrap()) - } else { - None + builder = builder.with_stdin(output?); } - } else { - None - }; + } + // 1. Parse the current directory + let current_dir = get_current_path(current_dir, self.config.source.clone())?; + let config = builder + .with_config_file(¤t_dir) + .with_execution_env(std::env::vars()) + .with_cli(self.config.clone()) + .build()?; match &self.commands { Some(Commands::Release {}) => { @@ -170,30 +145,24 @@ impl Command { // 2. Parse the cuddle.please.yaml let cuddle.please.yaml take precedence // 2a. if not existing use default. // 2b. if not in a git repo abort. (unless --no-vcs is turned added) - let _config = self.get_config(¤t_dir, stdin)?; - - let owner = self.global.owner.as_ref().expect("owner to be set"); - let repo = self.global.repo.as_ref().expect("repo to be set"); - let branch = self.global.branch.as_ref().expect("branch to be set"); - - let git_client = self.get_git(¤t_dir)?; + let git_client = self.get_git(config.get_source())?; // 3. Create gitea client and do a health check let gitea_client = self.get_gitea_client(); gitea_client - .connect(owner, repo) + .connect(config.get_owner(), config.get_repository()) .context("failed to connect to gitea repository")?; // 4. Fetch git tags for the current repository - let tags = gitea_client.get_tags(owner, repo)?; + let tags = gitea_client.get_tags(config.get_owner(), config.get_repository())?; let significant_tag = get_most_significant_version(tags.iter().collect()); // 5. Fetch git commits since last git tag let commits = gitea_client.get_commits_since( - owner, - repo, + config.get_owner(), + config.get_repository(), significant_tag.map(|st| st.commit.sha.clone()), - branch, + config.get_branch(), )?; // 7. Create a versioning client @@ -219,12 +188,7 @@ impl Command { let builder = cliff::ChangeLogBuilder::new(&commit_strs, next_version.to_string()).build(); - let changelog_placement = self - .global - .source - .as_ref() - .map(|s| s.join("CHANGELOG.md")) - .unwrap_or(PathBuf::from("CHANGELOG.md")); + let changelog_placement = config.get_source().join("CHANGELOG.md"); let changelog = match std::fs::read_to_string(&changelog_placement).ok() { Some(existing_changelog) => builder.prepend(existing_changelog)?, @@ -239,8 +203,8 @@ impl Command { if first_commit.contains("chore(release): ") { if !self.global.dry_run { gitea_client.create_release( - owner, - repo, + config.get_owner(), + config.get_repository(), next_version.to_string(), changelog_last_changes.unwrap(), !next_version.pre.is_empty(), @@ -261,12 +225,14 @@ impl Command { git_client.commit_and_push(next_version.to_string(), self.global.dry_run)?; - let _pr_number = match gitea_client.get_pull_request(owner, repo)? { + let _pr_number = match gitea_client + .get_pull_request(config.get_owner(), config.get_repository())? + { Some(existing_pr) => { if !self.global.dry_run { gitea_client.update_pull_request( - owner, - repo, + config.get_owner(), + config.get_repository(), next_version.to_string(), changelog_last_changes.unwrap(), existing_pr, @@ -279,11 +245,11 @@ impl Command { None => { if !self.global.dry_run { gitea_client.create_pull_request( - owner, - repo, + config.get_owner(), + config.get_repository(), next_version.to_string(), changelog, - self.global.branch.clone().unwrap(), + config.get_branch(), )? } else { tracing::debug!("creating pull request (dry_run)"); @@ -296,13 +262,12 @@ impl Command { Some(Commands::Config { command }) => match command { ConfigCommand::List { .. } => { tracing::debug!("running command: config list"); - let _config = self.get_config(current_dir.as_path(), stdin)?; self.ui.write_str_ln("cuddle-config"); } }, Some(Commands::Gitea { command }) => { - let git_url = url::Url::parse(&self.global.api_url.unwrap())?; + let git_url = url::Url::parse(config.get_api_url())?; let mut url = String::new(); url.push_str(git_url.scheme()); @@ -315,13 +280,13 @@ impl Command { let client = GiteaClient::new(url, self.global.token); match command { GiteaCommand::Connect {} => { - client.connect(self.global.owner.unwrap(), self.global.repo.unwrap())?; + client.connect(config.get_owner(), config.get_repository())?; self.ui.write_str_ln("connected succesfully go gitea"); } GiteaCommand::Tags { command } => match command { Some(GiteaTagsCommand::MostSignificant {}) => { - let tags = client - .get_tags(self.global.owner.unwrap(), self.global.repo.unwrap())?; + let tags = + client.get_tags(config.get_owner(), config.get_repository())?; match get_most_significant_version(tags.iter().collect()) { Some(tag) => { @@ -336,8 +301,8 @@ impl Command { } } None => { - let tags = client - .get_tags(self.global.owner.unwrap(), self.global.repo.unwrap())?; + let tags = + client.get_tags(config.get_owner(), config.get_repository())?; self.ui.write_str_ln("got tags from gitea"); for tag in tags { self.ui.write_str_ln(&format!("- {}", tag.name)) @@ -346,8 +311,8 @@ impl Command { }, GiteaCommand::SinceCommit { sha, branch } => { let commits = client.get_commits_since( - self.global.owner.unwrap(), - self.global.repo.unwrap(), + config.get_owner(), + config.get_repository(), Some(sha), branch, )?; @@ -357,10 +322,8 @@ impl Command { } } GiteaCommand::CheckPr {} => { - let pr = client.get_pull_request( - self.global.owner.unwrap(), - self.global.repo.unwrap(), - )?; + let pr = + client.get_pull_request(config.get_owner(), config.get_repository())?; match pr { Some(index) => { @@ -398,16 +361,9 @@ impl Command { VcsClient::new_git(current_dir) } - fn get_from_environment(&self, config: &mut PleaseConfig) -> anyhow::Result<()> { - let input_config = get_from_environment(); - config.merge_mut(input_config); - - Ok(()) - } - fn get_gitea_client(&self) -> GiteaClient { GiteaClient::new( - self.global.api_url.clone().expect("api_url to be set"), + self.config.api_url.clone().expect("api_url to be set"), self.global.token.clone(), ) } @@ -469,7 +425,8 @@ fn get_current_path( .or_else(|| optional_current_dir.map(|p| p.to_path_buf())) // fall back on current env from environment .filter(|v| v.to_string_lossy() != "") // make sure we don't get empty values //.and_then(|p| p.canonicalize().ok()) // Make sure we get the absolute path - .context("could not find current dir, pass --source as a replacement")?; + //.context("could not find current dir, pass --source as a replacement")?; + .unwrap_or(PathBuf::from(".")); if !path.exists() { anyhow::bail!("path doesn't exist {}", path.display()); @@ -477,131 +434,3 @@ fn get_current_path( Ok(path) } - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PleaseProjectConfig { - pub owner: Option, - pub repository: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PleaseSettingsConfig { - pub api_url: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct PleaseConfig { - pub project: Option, - pub settings: Option, -} - -impl PleaseConfig { - fn merge(self, _config: PleaseConfig) -> Self { - self - } - - fn merge_mut(&mut self, _config: PleaseConfig) -> &mut Self { - self - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct CuddleEmbeddedPleaseConfig { - please: PleaseConfig, -} - -impl From for PleaseConfig { - fn from(value: CuddleEmbeddedPleaseConfig) -> Self { - value.please - } -} -#[derive(Debug, Clone, Serialize, Deserialize)] -struct CuddlePleaseConfig { - #[serde(flatten)] - please: PleaseConfig, -} -impl From for PleaseConfig { - fn from(value: CuddlePleaseConfig) -> Self { - value.please - } -} - -const CUDDLE_FILE_NAME: &str = "cuddle"; -const CUDDLE_CONFIG_FILE_NAME: &str = "cuddle.please"; -const YAML_EXTENSION: &str = "yaml"; - -fn get_config(current_dir: &Path, stdin: Option) -> anyhow::Result { - let current_cuddle_path = current_dir - .clone() - .join(format!("{CUDDLE_FILE_NAME}.{YAML_EXTENSION}")); - let current_cuddle_config_path = current_dir - .clone() - .join(format!("{CUDDLE_CONFIG_FILE_NAME}.{YAML_EXTENSION}")); - let mut please_config = PleaseConfig::default(); - - if let Some(config) = get_config_from_file::(current_cuddle_path) { - please_config = please_config.merge(config); - } - - if let Some(config) = get_config_from_file::(current_cuddle_config_path) { - please_config = please_config.merge(config); - } - - if let Some(input_config) = get_config_from_stdin::(stdin.as_ref()) { - please_config = please_config.merge(input_config); - } - - Ok(please_config) -} - -fn get_config_from_file(current_cuddle_path: PathBuf) -> Option -where - T: DeserializeOwned, - T: Into, -{ - match std::fs::File::open(¤t_cuddle_path) { - Ok(file) => match serde_yaml::from_reader::<_, T>(file) { - Ok(config) => { - return Some(config.into()); - } - Err(e) => { - tracing::debug!( - "{} doesn't contain a valid please config: {}", - ¤t_cuddle_path.display(), - e - ); - } - }, - Err(e) => { - tracing::debug!( - "did not find or was not allowed to read {}, error: {}", - ¤t_cuddle_path.display(), - e, - ); - } - } - - None -} - -fn get_config_from_stdin<'d, T>(stdin: Option<&'d String>) -> Option -where - T: Deserialize<'d>, - T: Into, -{ - match stdin { - Some(content) => match serde_yaml::from_str::<'d, T>(content) { - Ok(config) => { - return Some(config.into()); - } - Err(e) => { - tracing::debug!("stdin doesn't contain a valid please config: {}", e); - } - }, - None => { - tracing::trace!("Stdin was not set continueing",); - } - } - - None -} diff --git a/crates/cuddle-please/src/environment/drone.rs b/crates/cuddle-please/src/environment/drone.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/cuddle-please/src/environment/drone.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/cuddle-please/src/environment/mod.rs b/crates/cuddle-please/src/environment/mod.rs deleted file mode 100644 index d1ecc22..0000000 --- a/crates/cuddle-please/src/environment/mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::command::{PleaseConfig, PleaseProjectConfig}; - -pub mod drone; - -pub fn get_from_environment() -> PleaseConfig { - let env = detect_environment(); - - match env { - ExecutionEnvironment::Local => PleaseConfig { - project: None, - settings: None, - }, - ExecutionEnvironment::Drone => PleaseConfig { - project: Some(PleaseProjectConfig { - owner: Some( - std::env::var("DRONE_REPO_OWNER").expect("DRONE_REPO_OWNER to be present"), - ), - repository: Some( - std::env::var("DRONE_REPO_NAME").expect("DRONE_REPO_NAME to be present"), - ), - }), - settings: None, - }, - } -} - -pub fn detect_environment() -> ExecutionEnvironment { - if std::env::var("DRONE").is_ok() { - return ExecutionEnvironment::Drone; - } - - ExecutionEnvironment::Local -} - -pub enum ExecutionEnvironment { - Local, - Drone, -} diff --git a/crates/cuddle-please/src/lib.rs b/crates/cuddle-please/src/lib.rs index 0ada347..0d35dfa 100644 --- a/crates/cuddle-please/src/lib.rs +++ b/crates/cuddle-please/src/lib.rs @@ -1,6 +1,5 @@ pub mod cliff; pub mod command; -pub mod environment; pub mod git_client; pub mod gitea_client; pub mod ui; diff --git a/crates/cuddle-please/src/main.rs b/crates/cuddle-please/src/main.rs index d4fe149..5f20b40 100644 --- a/crates/cuddle-please/src/main.rs +++ b/crates/cuddle-please/src/main.rs @@ -1,6 +1,5 @@ pub mod cliff; pub mod command; -pub mod environment; pub mod git_client; pub mod gitea_client; pub mod ui; diff --git a/crates/cuddle-please/testdata/cuddle-embed/cuddle.please.yaml b/crates/cuddle-please/testdata/cuddle-embed/cuddle.please.yaml new file mode 100644 index 0000000..e6b1e7d --- /dev/null +++ b/crates/cuddle-please/testdata/cuddle-embed/cuddle.please.yaml @@ -0,0 +1,6 @@ +project: + owner: kjuulh + repository: cuddle-please + branch: main +settings: + api_url: https://some-example.gitea-instance \ No newline at end of file diff --git a/crates/cuddle-please/testdata/cuddle-embed/cuddle.yaml b/crates/cuddle-please/testdata/cuddle-embed/cuddle.yaml index e69de29..a441458 100644 --- a/crates/cuddle-please/testdata/cuddle-embed/cuddle.yaml +++ b/crates/cuddle-please/testdata/cuddle-embed/cuddle.yaml @@ -0,0 +1,7 @@ +please: + project: + owner: kjuulh + repository: cuddle-please + branch: main + settings: + api_url: https://some-example.gitea-instance \ No newline at end of file diff --git a/crates/cuddle-please/testdata/cuddle-please/cuddle.please.yaml b/crates/cuddle-please/testdata/cuddle-please/cuddle.please.yaml index e69de29..e6b1e7d 100644 --- a/crates/cuddle-please/testdata/cuddle-please/cuddle.please.yaml +++ b/crates/cuddle-please/testdata/cuddle-please/cuddle.please.yaml @@ -0,0 +1,6 @@ +project: + owner: kjuulh + repository: cuddle-please + branch: main +settings: + api_url: https://some-example.gitea-instance \ No newline at end of file diff --git a/crates/cuddle-please/tests/config.rs b/crates/cuddle-please/tests/config.rs index d2fc792..6057eb1 100644 --- a/crates/cuddle-please/tests/config.rs +++ b/crates/cuddle-please/tests/config.rs @@ -45,15 +45,19 @@ fn test_config_from_source_dir() { fn test_config_from_stdin() { let mut args = get_base_args(); let ui = &BufferUi::default(); - let current_dir = get_test_data_path("cuddle-embed"); - args.push("--source"); - args.push(current_dir.to_str().unwrap()); - args.push("--config-stdin"); + let config = r#" +project: + owner: kjuulh + repository: cuddle-please + branch: main +settings: + api_url: https://some-example.gitea-instance +"#; - Command::new_from_args_with_stdin(Some(ui), args, || Ok("please".into())) + args.push("--config-stdin"); + Command::new_from_args_with_stdin(Some(ui), args, || Ok(config.into())) .execute(None) .unwrap(); - assert_output(ui, "cuddle-config\n", ""); }