techtree/techtree-manager/src/main.rs

141 lines
4.4 KiB
Rust

use anyhow::Context as _;
use forgejo_api::Forgejo;
mod collect;
mod event_meta;
mod issue;
mod render;
mod tree;
mod wiki;
async fn run() -> anyhow::Result<()> {
let meta = if std::env::var("TECHTREE_FAKE").ok().is_some() {
log::warn!("Fake tree!");
event_meta::fake()
} else {
event_meta::get_issue_event_meta_from_env().context("Failed reading issue event data")?
};
log::info!(
"Running due to event \"{:?}\" on issue #{} ...",
meta.action,
meta.issue.number
);
let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
log::info!("Timestamp of this run is {timestamp}");
let token =
std::env::var("GITHUB_TOKEN").context("Failed accessing GITHUB_TOKEN auth token")?;
let auth = forgejo_api::Auth::Token(&token);
let server_url = url::Url::parse(
&std::env::var("GITHUB_SERVER_URL")
.context("Failed reading GITHUB_SERVER_URL server url")?,
)
.context("Failed parsing GITHUB_SERVER_URL as a url")?;
let mut repo_auth_url = server_url.join(&format!("{}/{}", meta.issue.repository.owner, meta.issue.repository.name)).unwrap();
repo_auth_url.set_username("forgejo-actions").unwrap();
repo_auth_url.set_password(Some(&token)).unwrap();
let forgejo = Forgejo::new(auth, server_url).context("Could not create API access object")?;
let new_comment_id = if meta.action == event_meta::IssueAction::Opened {
let res = issue::make_bot_comment(&forgejo, &meta, meta.issue.number).await;
match res {
Ok(id) => Some(id),
Err(e) => {
log::warn!(
"Error while creating the informational comment on issue #{}:\n{e:?}",
meta.issue.number
);
None
}
}
} else {
None
};
let tree = collect::collect_tree(&forgejo, &meta)
.await
.context("Failed to collect the techtree from issue metadata")?;
log::info!("Rendering and publishing techtree to git repository...");
render::render_and_publish(&tree, &timestamp, &repo_auth_url)
.await
.context("Failed to render and publish the techtree to git")?;
let mermaid = tree.to_mermaid();
let wiki_text = format!(
r##"This page is automatically updated to show the latest and greatest FAFO techtree:
```mermaid
{mermaid}
```
"##
);
log::info!("Updating the wiki overview...");
wiki::update_wiki_overview(
&forgejo,
&meta.issue.repository,
timestamp.to_string(),
wiki_text,
)
.await
.context("Failed to update the techtree wiki page")?;
'issues: for issue in tree.iter_issues() {
let subtree = tree.subtree_for_issue(issue).unwrap();
let hash = subtree.stable_hash();
let comment_id = if new_comment_id.is_some() && issue == meta.issue.number {
new_comment_id.unwrap()
} else {
let bot_comment = issue::find_bot_comment(&forgejo, &meta.issue.repository, issue)
.await
.with_context(|| format!("Failed searching for bot comment for issue #{issue}"))?;
if let Some(bot_comment) = bot_comment {
if bot_comment.body.contains(&hash) {
log::info!("Issue #{issue} is up-to-date, not editing comment.");
continue 'issues;
}
bot_comment.id
} else {
log::warn!("Missing bot comment in issue #{issue}");
issue::make_bot_comment(&forgejo, &meta, issue)
.await
.with_context(|| {
format!("Failed to create a retrospective bot comment on issue #{issue}")
})?
}
};
let mermaid = subtree.to_mermaid();
let full_text = format!(
r##"## Partial Techtree
```mermaid
{mermaid}
```
<small>Digest: {hash}; Last Updated: {timestamp}</small>"##
);
log::info!("Updating bot comment in issue #{issue} ...");
issue::update_bot_comment(&forgejo, &meta.issue.repository, comment_id, full_text)
.await
.with_context(|| format!("Failed to update the bot comment in issue #{issue}"))?;
}
Ok(())
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
run().await
}