use indexmap::IndexMap;
use itertools::Itertools;
use knope_config::Package;
use serde::{Deserialize, Serialize};
use toml::Spanned;
use crate::workflow::Workflow;
#[derive(Debug, Deserialize)]
pub(crate) struct ConfigLoader {
#[serde(flatten)]
pub(crate) shared: knope_config::Config,
pub(crate) package: Option<Spanned<Package>>,
pub(crate) packages: Option<IndexMap<String, Spanned<Package>>>,
pub(crate) workflows: Option<Spanned<Vec<Spanned<Workflow>>>>,
pub(crate) jira: Option<Spanned<Jira>>,
pub(crate) github: Option<Spanned<GitHub>>,
pub(crate) gitea: Option<Spanned<Gitea>>,
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod test_package_configs {
use pretty_assertions::assert_eq;
use super::ConfigLoader;
const REQUIRED_CONFIG_STUFF: &str = "\n[[workflows]]\nname = \"default\"\n[[workflows.steps]]\ntype = \"Command\"\ncommand = \"echo this is nothing, really\"";
#[test]
fn single_package() {
let toml_str = format!("[package]{REQUIRED_CONFIG_STUFF}");
let config: ConfigLoader = toml::from_str(&toml_str).unwrap();
assert!(config.package.is_some());
assert!(config.packages.is_none());
}
#[test]
fn multi_package() {
let toml_str = format!("[packages.something]\n[packages.blah]{REQUIRED_CONFIG_STUFF}");
let config: ConfigLoader = toml::from_str(&toml_str).unwrap();
assert!(config.package.is_none());
let packages = config.packages.unwrap();
assert_eq!(packages.len(), 2);
assert!(packages.contains_key("something"));
assert!(packages.contains_key("blah"));
}
#[test]
fn single_package_with_help() {
let toml_str =
format!("[package]{REQUIRED_CONFIG_STUFF}\nhelp_text = \"This is a help text\"");
let config: ConfigLoader = toml::from_str(&toml_str).unwrap();
assert!(config.package.is_some());
assert!(config.packages.is_none());
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub(crate) struct Jira {
pub(crate) url: String,
pub(crate) project: String,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub(crate) struct GitHub {
pub(crate) owner: String,
pub(crate) repo: String,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(test, derive(PartialEq, Eq))]
pub(crate) struct Gitea {
pub(crate) owner: String,
pub(crate) repo: String,
pub(crate) host: String,
}
impl Gitea {
pub(crate) const KNOWN_PUBLIC_GITEA_HOSTS: &'static [&'static str] = &["codeberg.org"];
fn get_base_url(&self) -> String {
format!("{host}/api/v1", host = self.host)
}
pub(crate) fn get_pulls_url(&self) -> String {
format!(
"{base_url}/repos/{owner}/{repo}/pulls",
base_url = self.get_base_url(),
owner = self.owner,
repo = self.repo
)
}
pub(crate) fn get_pull_url(&self, pr_number: u32) -> String {
format!("{pulls_url}/{pr_number}", pulls_url = self.get_pulls_url())
}
pub(crate) fn get_releases_url(&self) -> String {
format!(
"{base_url}/repos/{owner}/{repo}/releases",
base_url = self.get_base_url(),
owner = self.owner,
repo = self.repo
)
}
pub(crate) fn get_issues_url(&self) -> String {
format!(
"{base_url}/repos/{owner}/{repo}/issues",
base_url = self.get_base_url(),
owner = self.owner,
repo = self.repo
)
}
pub(crate) fn try_from_remote(remote: &str) -> Option<Self> {
let (scheme, path) = remote.split_once(':')?;
if scheme.contains("git@") {
let (owner, repo) = path.strip_prefix('/').unwrap_or(path).split_once('/')?;
Some(Self {
owner: owner.to_string(),
repo: repo.strip_suffix(".git").unwrap_or(repo).to_string(),
host: format!("https://{host}", host = scheme.strip_prefix("git@")?),
})
} else {
let [host, owner, repo]: [&str; 3] = path
.strip_prefix("//")?
.splitn(3, '/')
.collect_vec()
.try_into()
.ok()?;
Some(Self {
host: format!("https://{host}"),
owner: owner.to_string(),
repo: repo.strip_suffix(".git").unwrap_or(repo).to_string(),
})
}
}
}
#[cfg(test)]
mod test_gitea_try_from_remote {
use super::Gitea;
#[test]
fn https_remote() {
let config = Gitea::try_from_remote("https://codeberg.org/knope-dev/knope.git");
assert_eq!(
Some(Gitea {
owner: "knope-dev".to_string(),
repo: "knope".to_string(),
host: "https://codeberg.org".to_string()
}),
config
);
}
#[test]
fn https_remote_without_git_suffix() {
let config = Gitea::try_from_remote("https://codeberg.org/knope-dev/knope");
assert_eq!(
Some(Gitea {
owner: "knope-dev".to_string(),
repo: "knope".to_string(),
host: "https://codeberg.org".to_string()
}),
config
);
}
#[test]
fn ssh_remote() {
let config = Gitea::try_from_remote("git@codeberg.org:/knope-dev/knope.git");
assert_eq!(
Some(Gitea {
owner: "knope-dev".to_string(),
repo: "knope".to_string(),
host: "https://codeberg.org".to_string()
}),
config
);
}
#[test]
fn ssh_remote_without_git_suffix() {
let config = Gitea::try_from_remote("git@codeberg.org:/knope-dev/knope");
assert_eq!(
Some(Gitea {
owner: "knope-dev".to_string(),
repo: "knope".to_string(),
host: "https://codeberg.org".to_string()
}),
config
);
}
}