use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct PoiTrackerConfig {
#[serde(default)]
pub bugzilla: BugzillaConfig,
#[serde(default, rename = "dist-git")]
pub dist_git: DistGitConfig,
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct DistGitConfig {
#[serde(default)]
pub api_token: String,
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct BugzillaConfig {
#[serde(default)]
pub api_key: String,
#[serde(default)]
pub email: String,
#[serde(default)]
pub url: String,
}
impl BugzillaConfig {
pub const DEFAULT_URL: &'static str = "https://bugzilla.redhat.com";
}
pub fn resolve_api_key(cli_key: Option<&str>) -> Result<String, String> {
if let Some(key) = cli_key
&& !key.is_empty()
{
return Ok(key.to_string());
}
if let Ok(key) = std::env::var("BUGZILLA_API_KEY")
&& !key.is_empty()
{
return Ok(key);
}
if let Ok(config) =
sandogasa_config::ConfigFile::for_tool("poi-tracker").load::<PoiTrackerConfig>()
&& !config.bugzilla.api_key.is_empty()
{
return Ok(config.bugzilla.api_key);
}
Err("Bugzilla API key not found.\n\
Set it up with: poi-tracker config\n\
Or pass --api-key or set BUGZILLA_API_KEY."
.to_string())
}
pub fn resolve_distgit_token(cli_token: Option<&str>) -> Result<String, String> {
if let Some(token) = cli_token
&& !token.is_empty()
{
return Ok(token.to_string());
}
if let Ok(token) = std::env::var("PAGURE_API_TOKEN")
&& !token.is_empty()
{
return Ok(token);
}
if let Ok(config) =
sandogasa_config::ConfigFile::for_tool("poi-tracker").load::<PoiTrackerConfig>()
&& !config.dist_git.api_token.is_empty()
{
return Ok(config.dist_git.api_token);
}
Err("dist-git API token not found.\n\
Generate one at https://src.fedoraproject.org/settings/token/new\n\
with the \"Modify an existing project\" ACL, then set it up\n\
with: poi-tracker config\n\
Or pass --api-token or set PAGURE_API_TOKEN."
.to_string())
}
pub fn resolve_url() -> String {
sandogasa_config::ConfigFile::for_tool("poi-tracker")
.load::<PoiTrackerConfig>()
.ok()
.filter(|c| !c.bugzilla.url.is_empty())
.map(|c| c.bugzilla.url)
.unwrap_or_else(|| BugzillaConfig::DEFAULT_URL.to_string())
}
pub fn resolve_email() -> Option<String> {
sandogasa_config::ConfigFile::for_tool("poi-tracker")
.load::<PoiTrackerConfig>()
.ok()
.map(|c| c.bugzilla.email)
.filter(|e| !e.is_empty())
}
pub async fn cmd_config(args: &sandogasa_cli::ConfigArgs) -> Result<(), String> {
use sandogasa_config::{Setting, ask};
let cf = sandogasa_config::ConfigFile::for_tool("poi-tracker");
let mut config: PoiTrackerConfig = cf.load_user().unwrap_or_default();
println!("poi-tracker configuration\n");
println!("Config file: {}\n", cf.path().display());
if config.bugzilla.url.is_empty() {
config.bugzilla.url = BugzillaConfig::DEFAULT_URL.to_string();
}
println!("Bugzilla URL: {}", config.bugzilla.url);
config.bugzilla.api_key = ask(
&Setting::new("Bugzilla", "API key").sensitive().hint(
"\nGenerate an API key at:\n \
https://bugzilla.redhat.com/userprefs.cgi?tab=apikey\n",
),
&config.bugzilla.api_key,
args.all,
)
.map_err(|e| format!("failed to read API key: {e}"))?;
config.bugzilla.email = ask(
&Setting::new("Bugzilla", "email (optional, for --claim)")
.optional()
.validated(&sandogasa_config::validate_email),
&config.bugzilla.email,
args.all,
)
.map_err(|e| format!("failed to read e-mail: {e}"))?;
config.dist_git.api_token = ask(
&Setting::new("dist-git", "API token (optional, empty to skip)")
.sensitive()
.optional()
.hint(
"\nOptional: a dist-git API token lets `adopt` take orphaned\n\
packages. Generate one at\n \
https://src.fedoraproject.org/settings/token/new\n\
with the \"Modify an existing project\" ACL.",
),
&config.dist_git.api_token,
args.all,
)
.map_err(|e| format!("failed to read token: {e}"))?;
let url = config.bugzilla.url.clone();
config.bugzilla.api_key = sandogasa_cli::credential::validated_key(
"Bugzilla",
"API key",
config.bugzilla.api_key.clone(),
move |key| {
let url = url.clone();
Box::pin(async move {
use sandogasa_cli::credential::KeyVerdict;
let bz = match sandogasa_bugzilla::BzClient::new(&url).with_api_key(key) {
Ok(bz) => bz,
Err(e) => return KeyVerdict::Unknown(format!("could not check: {e}")),
};
match bz.check_api_key().await {
Ok(sandogasa_bugzilla::KeyCheck::Accepted) => {
KeyVerdict::Accepted("accepted.".to_string())
}
Ok(sandogasa_bugzilla::KeyCheck::Refused(why)) => {
KeyVerdict::Refused(format!("refused: {why}"))
}
Ok(sandogasa_bugzilla::KeyCheck::Unclear(why)) => {
KeyVerdict::Unknown(format!("could not tell: {why}"))
}
Ok(_) => KeyVerdict::Unknown("could not tell.".to_string()),
Err(e) => KeyVerdict::Unknown(format!("could not check: {e}")),
}
})
},
)
.await
.key;
cf.save(&config)
.map_err(|e| format!("failed to save config: {e}"))?;
println!("\nConfig saved to {}", cf.path().display());
Ok(())
}