manager: Factor out a common context object
Clean up the global data a bit by bundling it in a context object.
This commit is contained in:
parent
eebbd9c453
commit
bc54cd91fd
|
@ -1,14 +1,12 @@
|
|||
use anyhow::Context as _;
|
||||
|
||||
/// Read all issues to generate the full techtree
|
||||
pub async fn collect_tree(
|
||||
forgejo: &forgejo_api::Forgejo,
|
||||
meta: &crate::event_meta::IssueEventMeta,
|
||||
) -> anyhow::Result<crate::tree::Tree> {
|
||||
let issues = forgejo
|
||||
pub async fn collect_tree(ctx: &crate::Context) -> anyhow::Result<crate::tree::Tree> {
|
||||
let issues = ctx
|
||||
.forgejo
|
||||
.issue_list_issues(
|
||||
&meta.issue.repository.owner,
|
||||
&meta.issue.repository.name,
|
||||
&ctx.owner,
|
||||
&ctx.repo,
|
||||
forgejo_api::structs::IssueListIssuesQuery {
|
||||
// We also want the closed issues
|
||||
state: Some(forgejo_api::structs::IssueListIssuesQueryState::All),
|
||||
|
@ -43,10 +41,12 @@ pub async fn collect_tree(
|
|||
}
|
||||
|
||||
for issue in issue_numbers.into_iter() {
|
||||
let dependencies = forgejo
|
||||
let dependencies = ctx
|
||||
.forgejo
|
||||
.issue_list_issue_dependencies(
|
||||
&meta.issue.repository.owner,
|
||||
&meta.issue.repository.name,
|
||||
&ctx.owner,
|
||||
&ctx.repo,
|
||||
// Why the hell is the issue number a string here?
|
||||
&issue.to_string(),
|
||||
forgejo_api::structs::IssueListIssueDependenciesQuery {
|
||||
limit: Some(10000),
|
||||
|
@ -54,12 +54,7 @@ pub async fn collect_tree(
|
|||
},
|
||||
)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to fetch issue dependencies for #{}",
|
||||
meta.issue.number
|
||||
)
|
||||
})?;
|
||||
.with_context(|| format!("Failed to fetch issue dependencies for #{issue}",))?;
|
||||
|
||||
for dep in dependencies {
|
||||
let dep_number = dep.number.context("Missing issue number in dependency")?;
|
||||
|
|
|
@ -8,17 +8,16 @@ pub struct BotCommentInfo {
|
|||
}
|
||||
|
||||
pub async fn make_bot_comment(
|
||||
forgejo: &forgejo_api::Forgejo,
|
||||
meta: &crate::event_meta::IssueEventMeta,
|
||||
ctx: &crate::Context,
|
||||
issue_number: u64,
|
||||
) -> anyhow::Result<CommentId> {
|
||||
let initial_message =
|
||||
"_Please be patient, this issue is currently being integrated into the techtree..._";
|
||||
|
||||
let res = forgejo
|
||||
let res = ctx.forgejo
|
||||
.issue_create_comment(
|
||||
&meta.issue.repository.owner,
|
||||
&meta.issue.repository.name,
|
||||
&ctx.owner,
|
||||
&ctx.repo,
|
||||
issue_number,
|
||||
forgejo_api::structs::CreateIssueCommentOption {
|
||||
body: initial_message.to_owned(),
|
||||
|
@ -31,14 +30,13 @@ pub async fn make_bot_comment(
|
|||
}
|
||||
|
||||
pub async fn find_bot_comment(
|
||||
forgejo: &forgejo_api::Forgejo,
|
||||
meta: &crate::event_meta::RepoMeta,
|
||||
ctx: &crate::Context,
|
||||
issue_number: u64,
|
||||
) -> anyhow::Result<Option<BotCommentInfo>> {
|
||||
let mut comments = forgejo
|
||||
let mut comments = ctx.forgejo
|
||||
.issue_get_comments(
|
||||
&meta.owner,
|
||||
&meta.name,
|
||||
&ctx.owner,
|
||||
&ctx.repo,
|
||||
issue_number,
|
||||
forgejo_api::structs::IssueGetCommentsQuery {
|
||||
..Default::default()
|
||||
|
@ -61,15 +59,14 @@ pub async fn find_bot_comment(
|
|||
}
|
||||
|
||||
pub async fn update_bot_comment(
|
||||
forgejo: &forgejo_api::Forgejo,
|
||||
meta: &crate::event_meta::RepoMeta,
|
||||
ctx: &crate::Context,
|
||||
id: CommentId,
|
||||
new_body: String,
|
||||
) -> anyhow::Result<()> {
|
||||
forgejo
|
||||
ctx.forgejo
|
||||
.issue_edit_comment(
|
||||
&meta.owner,
|
||||
&meta.name,
|
||||
&ctx.owner,
|
||||
&ctx.repo,
|
||||
id,
|
||||
forgejo_api::structs::EditIssueCommentOption {
|
||||
body: new_body,
|
||||
|
@ -83,12 +80,11 @@ pub async fn update_bot_comment(
|
|||
}
|
||||
|
||||
pub async fn remove_stale_label(
|
||||
forgejo: &forgejo_api::Forgejo,
|
||||
meta: &crate::event_meta::RepoMeta,
|
||||
ctx: &crate::Context,
|
||||
issue_number: u64,
|
||||
) -> anyhow::Result<()> {
|
||||
let labels = forgejo
|
||||
.issue_get_labels(&meta.owner, &meta.name, issue_number)
|
||||
let labels = ctx.forgejo
|
||||
.issue_get_labels(&ctx.owner, &ctx.repo, issue_number)
|
||||
.await
|
||||
.context("Failed fetching issue labels")?;
|
||||
|
||||
|
@ -101,10 +97,10 @@ pub async fn remove_stale_label(
|
|||
if let Some(stale_label_id) = stale_label_id {
|
||||
log::info!("Removing `Stale` label from issue #{issue_number}...");
|
||||
|
||||
let res = forgejo
|
||||
let res = ctx.forgejo
|
||||
.issue_remove_label(
|
||||
&meta.owner,
|
||||
&meta.name,
|
||||
&ctx.owner,
|
||||
&ctx.repo,
|
||||
issue_number,
|
||||
stale_label_id,
|
||||
forgejo_api::structs::DeleteLabelsOption {
|
||||
|
|
|
@ -10,6 +10,21 @@ mod render;
|
|||
mod tree;
|
||||
mod wiki;
|
||||
|
||||
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,
|
||||
/// Human readable timestamp of this manager run
|
||||
pub timestamp: String,
|
||||
}
|
||||
|
||||
async fn run() -> anyhow::Result<()> {
|
||||
let meta = if std::env::var("TECHTREE_FAKE").ok().is_some() {
|
||||
log::warn!("Fake tree!");
|
||||
|
@ -48,21 +63,29 @@ async fn run() -> anyhow::Result<()> {
|
|||
|
||||
let forgejo = Forgejo::new(auth, server_url).context("Could not create API access object")?;
|
||||
|
||||
let ctx = Context {
|
||||
forgejo,
|
||||
owner: meta.issue.repository.owner.clone(),
|
||||
repo: meta.issue.repository.name.clone(),
|
||||
repo_url,
|
||||
repo_auth_url,
|
||||
timestamp,
|
||||
};
|
||||
|
||||
let new_comment_id = if meta.action == event_meta::IssueAction::Opened {
|
||||
let bot_comment =
|
||||
issue::find_bot_comment(&forgejo, &meta.issue.repository, meta.issue.number)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed searching for bot comment for issue #{}",
|
||||
meta.issue.number
|
||||
)
|
||||
})?;
|
||||
let bot_comment = issue::find_bot_comment(&ctx, meta.issue.number)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed searching for bot comment for issue #{}",
|
||||
meta.issue.number
|
||||
)
|
||||
})?;
|
||||
|
||||
let id = match bot_comment {
|
||||
Some(comment) => Some(comment.id),
|
||||
None => {
|
||||
let res = issue::make_bot_comment(&forgejo, &meta, meta.issue.number).await;
|
||||
let res = issue::make_bot_comment(&ctx, meta.issue.number).await;
|
||||
match res {
|
||||
Ok(id) => Some(id),
|
||||
Err(e) => {
|
||||
|
@ -86,17 +109,17 @@ async fn run() -> anyhow::Result<()> {
|
|||
None
|
||||
};
|
||||
|
||||
let tree = collect::collect_tree(&forgejo, &meta)
|
||||
let tree = collect::collect_tree(&ctx)
|
||||
.await
|
||||
.context("Failed to collect the techtree from issue metadata")?;
|
||||
|
||||
log::info!("Rendering and publishing techtree to git repository...");
|
||||
render::render_and_publish(&tree, ×tamp, &repo_auth_url)
|
||||
render::render_and_publish(&ctx, &tree)
|
||||
.await
|
||||
.context("Failed to render and publish the techtree to git")?;
|
||||
|
||||
if false {
|
||||
let mermaid = tree.to_mermaid(&repo_url.to_string());
|
||||
let mermaid = tree.to_mermaid(&ctx.repo_url.to_string());
|
||||
let wiki_text = format!(
|
||||
r##"This page is automatically updated to show the latest and greatest FAFO techtree:
|
||||
|
||||
|
@ -106,14 +129,9 @@ async fn run() -> anyhow::Result<()> {
|
|||
"##
|
||||
);
|
||||
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")?;
|
||||
wiki::update_wiki_overview(&ctx, wiki_text)
|
||||
.await
|
||||
.context("Failed to update the techtree wiki page")?;
|
||||
}
|
||||
|
||||
'issues: for issue in tree.iter_issues() {
|
||||
|
@ -123,14 +141,14 @@ async fn run() -> anyhow::Result<()> {
|
|||
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)
|
||||
let bot_comment = issue::find_bot_comment(&ctx, 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.");
|
||||
issue::remove_stale_label(&forgejo, &meta.issue.repository, issue)
|
||||
issue::remove_stale_label(&ctx, issue)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!("Failed to remove `Stale` label from issue #{issue}")
|
||||
|
@ -142,7 +160,7 @@ async fn run() -> anyhow::Result<()> {
|
|||
} else {
|
||||
log::warn!("Missing bot comment in issue #{issue}");
|
||||
|
||||
issue::make_bot_comment(&forgejo, &meta, issue)
|
||||
issue::make_bot_comment(&ctx, issue)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!("Failed to create a retrospective bot comment on issue #{issue}")
|
||||
|
@ -150,7 +168,7 @@ async fn run() -> anyhow::Result<()> {
|
|||
}
|
||||
};
|
||||
|
||||
let mermaid = subtree.to_mermaid(&repo_url.to_string());
|
||||
let mermaid = subtree.to_mermaid(&ctx.repo_url.to_string());
|
||||
|
||||
let full_text = format!(
|
||||
r##"## Partial Techtree
|
||||
|
@ -158,15 +176,16 @@ async fn run() -> anyhow::Result<()> {
|
|||
{mermaid}
|
||||
```
|
||||
|
||||
<small>Digest: {hash}; Last Updated: {timestamp}</small>"##
|
||||
<small>Digest: {hash}; Last Updated: {timestamp}</small>"##,
|
||||
timestamp = ctx.timestamp,
|
||||
);
|
||||
|
||||
log::info!("Updating bot comment in issue #{issue} ...");
|
||||
issue::update_bot_comment(&forgejo, &meta.issue.repository, comment_id, full_text)
|
||||
issue::update_bot_comment(&ctx, comment_id, full_text)
|
||||
.await
|
||||
.with_context(|| format!("Failed to update the bot comment in issue #{issue}"))?;
|
||||
|
||||
issue::remove_stale_label(&forgejo, &meta.issue.repository, issue)
|
||||
issue::remove_stale_label(&ctx, issue)
|
||||
.await
|
||||
.with_context(|| format!("Failed to remove `Stale` label from issue #{issue}"))?;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,8 @@ impl SuccessExt for Command {
|
|||
}
|
||||
|
||||
pub async fn render_and_publish(
|
||||
ctx: &crate::Context,
|
||||
tree: &crate::tree::Tree,
|
||||
timestamp: &str,
|
||||
repo_auth_url: &url::Url,
|
||||
) -> anyhow::Result<()> {
|
||||
let render_repo = std::path::PathBuf::from("render-git");
|
||||
|
||||
|
@ -81,7 +80,7 @@ pub async fn render_and_publish(
|
|||
.arg("-C")
|
||||
.arg(&render_repo)
|
||||
.arg("commit")
|
||||
.args(["-m", &format!("Updated techtree at {timestamp}")])
|
||||
.args(["-m", &format!("Updated techtree at {}", ctx.timestamp)])
|
||||
.success()
|
||||
.context("Failed to add generated graph files to git index")?;
|
||||
|
||||
|
@ -91,7 +90,7 @@ pub async fn render_and_publish(
|
|||
.arg("push")
|
||||
.arg("--force")
|
||||
.arg("--quiet")
|
||||
.arg(repo_auth_url.to_string())
|
||||
.arg(ctx.repo_auth_url.to_string())
|
||||
.arg("HEAD:refs/heads/render")
|
||||
.status()
|
||||
.context("Failed to push rendered graph to forgejo repository")?;
|
||||
|
|
|
@ -2,20 +2,18 @@ use anyhow::Context as _;
|
|||
use base64::prelude::*;
|
||||
|
||||
pub async fn update_wiki_overview(
|
||||
forgejo: &forgejo_api::Forgejo,
|
||||
meta: &crate::event_meta::RepoMeta,
|
||||
timestamp: String,
|
||||
ctx: &crate::Context,
|
||||
new_body: String,
|
||||
) -> anyhow::Result<()> {
|
||||
// TODO: Figure out why we get a 404 when the edit was successfull...
|
||||
let _ = forgejo
|
||||
let _ = ctx.forgejo
|
||||
.repo_edit_wiki_page(
|
||||
&meta.owner,
|
||||
&meta.name,
|
||||
&ctx.owner,
|
||||
&ctx.repo,
|
||||
"Home",
|
||||
forgejo_api::structs::CreateWikiPageOptions {
|
||||
content_base64: Some(BASE64_STANDARD.encode(new_body.as_bytes())),
|
||||
message: Some(format!("Updated to latest model at {timestamp}")),
|
||||
message: Some(format!("Updated to latest model at {}", ctx.timestamp)),
|
||||
title: Some("Home".to_owned()),
|
||||
},
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue