130 lines
4 KiB
Rust
130 lines
4 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use anyhow::Context as _;
|
|
|
|
pub struct Context {
|
|
/// API Accessor object
|
|
pub forgejo: forgejo_api::Forgejo,
|
|
/// Repository Owner
|
|
pub owner: String,
|
|
/// Repository Name
|
|
pub repo: String,
|
|
/// URL of the repository page
|
|
pub repo_url: url::Url,
|
|
/// URL of the repository with authentication information attached
|
|
pub repo_auth_url: url::Url,
|
|
|
|
/// Timestamp "now" to be used in comparisons
|
|
pub timestamp: jiff::Zoned,
|
|
}
|
|
|
|
impl Context {
|
|
pub fn new_from_env_or_dev_fallback() -> anyhow::Result<Self> {
|
|
if std::env::var("CI").is_ok() {
|
|
Self::new_from_env()
|
|
} else {
|
|
log::info!("No CI=1 in environment, using development fallback environment.");
|
|
Self::new_from_dev_fallback()
|
|
}
|
|
}
|
|
|
|
pub fn new_from_env() -> anyhow::Result<Self> {
|
|
let token = get_env_value("GITHUB_TOKEN")?;
|
|
let server_url = get_env_value("GITHUB_SERVER_URL")?;
|
|
let repo_with_owner = get_env_value("GITHUB_REPOSITORY")?;
|
|
|
|
Self::new(&token, &server_url, &repo_with_owner)
|
|
}
|
|
|
|
pub fn new_from_dev_fallback() -> anyhow::Result<Self> {
|
|
let mut f = std::fs::File::open(&dev_environment_path()?)
|
|
.context("Failed to open dev environment config")?;
|
|
|
|
let config: DevEnvironment =
|
|
serde_json::de::from_reader(f).context("Failed to parse dev environment")?;
|
|
|
|
Self::new(
|
|
&config.dev_token,
|
|
&config.server_url,
|
|
&config.repo_with_owner,
|
|
)
|
|
}
|
|
|
|
fn new(token: &str, server_url: &str, repo_with_owner: &str) -> anyhow::Result<Self> {
|
|
let (owner, repo) = repo_with_owner.rsplit_once("/").with_context(|| {
|
|
format!("Could not split repo slug {repo_with_owner:?} into owner and repo")
|
|
})?;
|
|
|
|
let server_url = url::Url::parse(&server_url).context("Failed parsing server URL")?;
|
|
|
|
let repo_url = server_url
|
|
.join(&repo_with_owner)
|
|
.context("Failed to build server + repo URL")?;
|
|
let repo_auth_url = {
|
|
let mut repo_auth_url = repo_url.clone();
|
|
repo_auth_url.set_username("forgejo-actions").unwrap();
|
|
repo_auth_url.set_password(Some(token)).unwrap();
|
|
repo_auth_url
|
|
};
|
|
|
|
let forgejo = forgejo_api::Forgejo::new(forgejo_api::Auth::Token(token), server_url)
|
|
.context("Could not create Forgejo API access object")?;
|
|
|
|
let timestamp = jiff::Zoned::now();
|
|
|
|
Ok(Self {
|
|
forgejo,
|
|
owner: owner.to_owned(),
|
|
repo: repo.to_owned(),
|
|
repo_url,
|
|
repo_auth_url,
|
|
timestamp,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Debug for Context {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("Context")
|
|
.field("owner", &self.owner)
|
|
.field("repo", &self.repo)
|
|
.field("repo_url", &self.repo_url.to_string())
|
|
.field("repo_auth_url", &"<redacted>")
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
fn get_env_value(key: &str) -> anyhow::Result<String> {
|
|
std::env::var(key).with_context(|| format!("Missing ${key} environment variable"))
|
|
}
|
|
|
|
#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
struct DevEnvironment {
|
|
pub dev_token: String,
|
|
pub server_url: String,
|
|
pub repo_with_owner: String,
|
|
}
|
|
|
|
fn dev_environment_path() -> anyhow::Result<PathBuf> {
|
|
log::warn!("Not running in CI, using .dev-environment.json metadata instead.");
|
|
let p = PathBuf::from(".dev-environment.json");
|
|
if !p.exists() {
|
|
log::error!(
|
|
"{}",
|
|
r#"When not running in CI environment,
|
|
metadata has to be substituded using a `.dev-environment.json` file.
|
|
|
|
Example content:
|
|
|
|
{
|
|
"dev-token": "<your development access token>",
|
|
"server-url": "https://git.fa-fo.de",
|
|
"repo-with-owner": "rahix/TaskBot"
|
|
}
|
|
"#
|
|
);
|
|
anyhow::bail!("Missing development environment config.")
|
|
}
|
|
Ok(p)
|
|
}
|