use std::{fs::create_dir_all, path::PathBuf};
use miette::Diagnostic;
use crate::{integrations::http::ClientCreationError, prompt, prompt::get_input};
pub(crate) fn get_or_prompt_for_email() -> Result<String, Error> {
load_value_or_prompt("email", "Input your email address")
}
pub(crate) fn get_or_prompt_for_jira_token() -> Result<String, Error> {
load_value_or_prompt(
"jira_token",
"No Jira token found, generate one from https://id.atlassian.com/manage-profile/security/api-tokens and input here",
)
}
pub(crate) fn get_github_token() -> Result<Option<String>, Error> {
std::env::var("GITHUB_TOKEN")
.map(Some)
.or_else(|_| load_value("github_token"))
}
pub(crate) fn get_or_prompt_for_github_token() -> Result<String, Error> {
std::env::var("GITHUB_TOKEN").or_else(|_| {
load_value_or_prompt(
"github_token",
"No GitHub token found, generate one from https://github.com/settings/tokens with `repo` permissions and input here",
)
})
}
pub(crate) fn get_or_prompt_for_gitea_token(host: &str) -> Result<String, Error> {
std::env::var("GITEA_TOKEN").or_else(|_| {
let prompt = format!(
"\
No Gitea token found, generate one from {host}/user/settings/applications with\n\
`repository` permissions set to `Read and Write`\
and `issue` permissions set to `Read` and input here\
"
);
load_value_or_prompt("gitea_token", &prompt)
})
}
pub(crate) fn load_value(key: &str) -> Result<Option<String>, Error> {
let config_dir = config_dir()?;
let config_path = config_dir.join(key);
if !config_path.exists() {
return Ok(None);
}
std::fs::read_to_string(&config_path)
.or(Err(Error::CouldNotOpenConfigPath))
.map(Some)
}
pub(crate) fn load_value_or_prompt(key: &str, prompt: &str) -> Result<String, Error> {
if let Some(value) = load_value(key)? {
Ok(value)
} else {
let contents = get_input(prompt)?;
let config_dir = config_dir()?;
create_dir_all(&config_dir)
.map_err(|err| Error::CouldNotCreateDirectory(config_dir.clone(), err))?;
let config_path = config_dir.join(key);
std::fs::write(config_path, &contents).map_err(Error::CouldNotWriteConfig)?;
Ok(contents)
}
}
fn config_dir() -> Result<PathBuf, Error> {
Ok(dirs::config_dir()
.ok_or(Error::CouldNotOpenConfigPath)?
.join("knope"))
}
#[derive(Debug, Diagnostic, thiserror::Error)]
pub(crate) enum Error {
#[error("Could not open configuration path")]
#[diagnostic(
code(app_config::could_not_open_config_path),
help(
"Knope attempts to store config in a local config directory, this error may be a \
permissions issue or may mean you're using an obscure operating system"
)
)]
CouldNotOpenConfigPath,
#[error("Could not write config: {0}")]
#[diagnostic(
code(app_config::could_not_write_config),
help(
"Knope attempts to store config in a local config directory, this error may be a \
permissions issue or may mean you're using an obscure operating system"
)
)]
CouldNotWriteConfig(std::io::Error),
#[error("Could not create directory {0}: {1}")]
#[diagnostic(
code(app_config::could_not_create_directory),
help("Failed to create the configuration directory, this is likely a permissions error.")
)]
CouldNotCreateDirectory(PathBuf, std::io::Error),
#[error(transparent)]
#[diagnostic(transparent)]
Prompt(#[from] prompt::Error),
#[error(transparent)]
#[diagnostic(transparent)]
ClientCreation(#[from] ClientCreationError),
}