manager: The big refactoring
Clean up the logic in main to make it more readable. Factor out common functionality into the respective modules.
This commit is contained in:
		
							parent
							
								
									bc54cd91fd
								
							
						
					
					
						commit
						785ff37107
					
				
					 5 changed files with 171 additions and 140 deletions
				
			
		| 
						 | 
				
			
			@ -10,11 +10,12 @@ pub struct BotCommentInfo {
 | 
			
		|||
pub async fn make_bot_comment(
 | 
			
		||||
    ctx: &crate::Context,
 | 
			
		||||
    issue_number: u64,
 | 
			
		||||
) -> anyhow::Result<CommentId> {
 | 
			
		||||
) -> anyhow::Result<BotCommentInfo> {
 | 
			
		||||
    let initial_message =
 | 
			
		||||
        "_Please be patient, this issue is currently being integrated into the techtree..._";
 | 
			
		||||
 | 
			
		||||
    let res = ctx.forgejo
 | 
			
		||||
    let res = ctx
 | 
			
		||||
        .forgejo
 | 
			
		||||
        .issue_create_comment(
 | 
			
		||||
            &ctx.owner,
 | 
			
		||||
            &ctx.repo,
 | 
			
		||||
| 
						 | 
				
			
			@ -26,14 +27,18 @@ pub async fn make_bot_comment(
 | 
			
		|||
        )
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
    Ok(res.id.unwrap())
 | 
			
		||||
    Ok(BotCommentInfo {
 | 
			
		||||
        id: res.id.unwrap(),
 | 
			
		||||
        body: initial_message.to_owned(),
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn find_bot_comment(
 | 
			
		||||
    ctx: &crate::Context,
 | 
			
		||||
    issue_number: u64,
 | 
			
		||||
) -> anyhow::Result<Option<BotCommentInfo>> {
 | 
			
		||||
    let mut comments = ctx.forgejo
 | 
			
		||||
    let mut comments = ctx
 | 
			
		||||
        .forgejo
 | 
			
		||||
        .issue_get_comments(
 | 
			
		||||
            &ctx.owner,
 | 
			
		||||
            &ctx.repo,
 | 
			
		||||
| 
						 | 
				
			
			@ -58,6 +63,27 @@ pub async fn find_bot_comment(
 | 
			
		|||
    }))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Find existing bot comment or create a new one.
 | 
			
		||||
///
 | 
			
		||||
/// Returns a tuple of the comment information and a boolean indicating whether the comment was
 | 
			
		||||
/// newly created.
 | 
			
		||||
pub async fn find_or_make_bot_comment(
 | 
			
		||||
    ctx: &crate::Context,
 | 
			
		||||
    issue_number: u64,
 | 
			
		||||
) -> anyhow::Result<(BotCommentInfo, bool)> {
 | 
			
		||||
    if let Some(comment) = find_bot_comment(ctx, issue_number)
 | 
			
		||||
        .await
 | 
			
		||||
        .context("Failed to search for bot comment in issue")?
 | 
			
		||||
    {
 | 
			
		||||
        Ok((comment, false))
 | 
			
		||||
    } else {
 | 
			
		||||
        make_bot_comment(ctx, issue_number)
 | 
			
		||||
            .await
 | 
			
		||||
            .context("Failed to make new bot comment in issue")
 | 
			
		||||
            .map(|c| (c, true))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn update_bot_comment(
 | 
			
		||||
    ctx: &crate::Context,
 | 
			
		||||
    id: CommentId,
 | 
			
		||||
| 
						 | 
				
			
			@ -79,11 +105,32 @@ pub async fn update_bot_comment(
 | 
			
		|||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn remove_stale_label(
 | 
			
		||||
pub async fn update_bot_comment_from_subtree(
 | 
			
		||||
    ctx: &crate::Context,
 | 
			
		||||
    issue_number: u64,
 | 
			
		||||
    id: CommentId,
 | 
			
		||||
    subtree: &crate::tree::Subtree<'_>,
 | 
			
		||||
    hash: &str,
 | 
			
		||||
) -> anyhow::Result<()> {
 | 
			
		||||
    let labels = ctx.forgejo
 | 
			
		||||
    let mermaid = subtree.to_mermaid(&ctx.repo_url.to_string());
 | 
			
		||||
 | 
			
		||||
    let full_text = format!(
 | 
			
		||||
        r##"## Partial Techtree
 | 
			
		||||
```mermaid
 | 
			
		||||
{mermaid}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<small>Digest: {hash}; Last Updated: {timestamp}</small>"##,
 | 
			
		||||
        timestamp = ctx.timestamp,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    update_bot_comment(&ctx, id, full_text).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn remove_stale_label(ctx: &crate::Context, issue_number: u64) -> anyhow::Result<()> {
 | 
			
		||||
    let labels = ctx
 | 
			
		||||
        .forgejo
 | 
			
		||||
        .issue_get_labels(&ctx.owner, &ctx.repo, issue_number)
 | 
			
		||||
        .await
 | 
			
		||||
        .context("Failed fetching issue labels")?;
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +144,8 @@ 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 = ctx.forgejo
 | 
			
		||||
        let res = ctx
 | 
			
		||||
            .forgejo
 | 
			
		||||
            .issue_remove_label(
 | 
			
		||||
                &ctx.owner,
 | 
			
		||||
                &ctx.repo,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,64 +72,43 @@ async fn run() -> anyhow::Result<()> {
 | 
			
		|||
        timestamp,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let new_comment_id = if meta.action == event_meta::IssueAction::Opened {
 | 
			
		||||
        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(&ctx, 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
 | 
			
		||||
                    }
 | 
			
		||||
    if meta.action == event_meta::IssueAction::Opened {
 | 
			
		||||
        log::debug!("Running for a newly opened issue.  Taking care of the comment first...");
 | 
			
		||||
        match issue::find_or_make_bot_comment(&ctx, meta.issue.number).await {
 | 
			
		||||
            Ok((_comment, is_new)) => {
 | 
			
		||||
                if is_new {
 | 
			
		||||
                    log::info!(
 | 
			
		||||
                        "Waiting for a minute, as the issue is brand new.  We will likely catch some more updates this way!"
 | 
			
		||||
                    );
 | 
			
		||||
                    tokio::time::sleep(std::time::Duration::from_secs(60)).await;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        log::info!(
 | 
			
		||||
            "Waiting for a minute, as the issue is brand new.  We will likely catch some more updates this way!"
 | 
			
		||||
        );
 | 
			
		||||
        tokio::time::sleep(std::time::Duration::from_secs(60)).await;
 | 
			
		||||
 | 
			
		||||
        id
 | 
			
		||||
    } else {
 | 
			
		||||
        None
 | 
			
		||||
    };
 | 
			
		||||
            Err(err) => {
 | 
			
		||||
                log::warn!(
 | 
			
		||||
                    "Error while commenting on new issue #{}, continuing anyway... Error: {err:?}",
 | 
			
		||||
                    meta.issue.number
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    log::info!("Collecting tree from issue metadata...");
 | 
			
		||||
    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(&ctx, &tree)
 | 
			
		||||
    let rendered_tree = render::render(&ctx, &tree)
 | 
			
		||||
        .await
 | 
			
		||||
        .context("Failed to render and publish the techtree to git")?;
 | 
			
		||||
        .context("Failed to render the techtree")?;
 | 
			
		||||
    render::publish(&ctx, &rendered_tree)
 | 
			
		||||
        .await
 | 
			
		||||
        .context("Failed to publish rendered tree to git")?;
 | 
			
		||||
 | 
			
		||||
    // Wiki is disabled because the tree is too big for mermaid to handle
 | 
			
		||||
    if false {
 | 
			
		||||
        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:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
{mermaid}
 | 
			
		||||
```
 | 
			
		||||
"##
 | 
			
		||||
        );
 | 
			
		||||
        log::info!("Updating the wiki overview...");
 | 
			
		||||
        wiki::update_wiki_overview(&ctx, wiki_text)
 | 
			
		||||
        wiki::update_wiki_from_tree(&ctx, &tree)
 | 
			
		||||
            .await
 | 
			
		||||
            .context("Failed to update the techtree wiki page")?;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -138,52 +117,23 @@ async fn run() -> anyhow::Result<()> {
 | 
			
		|||
        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(&ctx, issue)
 | 
			
		||||
        let (bot_comment, _is_new) = issue::find_or_make_bot_comment(&ctx, issue)
 | 
			
		||||
            .await
 | 
			
		||||
            .with_context(|| format!("Failed to find or make bot comment in issue #{issue}"))?;
 | 
			
		||||
 | 
			
		||||
        if bot_comment.body.contains(&hash) {
 | 
			
		||||
            log::info!("Issue #{issue} is up-to-date, not editing comment.");
 | 
			
		||||
            issue::remove_stale_label(&ctx, issue)
 | 
			
		||||
                .await
 | 
			
		||||
                .with_context(|| format!("Failed searching for bot comment for issue #{issue}"))?;
 | 
			
		||||
                .with_context(|| format!("Failed to remove `Stale` label from 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(&ctx, issue)
 | 
			
		||||
                        .await
 | 
			
		||||
                        .with_context(|| {
 | 
			
		||||
                            format!("Failed to remove `Stale` label from issue #{issue}")
 | 
			
		||||
                        })?;
 | 
			
		||||
 | 
			
		||||
                    continue 'issues;
 | 
			
		||||
                }
 | 
			
		||||
                bot_comment.id
 | 
			
		||||
            } else {
 | 
			
		||||
                log::warn!("Missing bot comment in issue #{issue}");
 | 
			
		||||
 | 
			
		||||
                issue::make_bot_comment(&ctx, issue)
 | 
			
		||||
                    .await
 | 
			
		||||
                    .with_context(|| {
 | 
			
		||||
                        format!("Failed to create a retrospective bot comment on issue #{issue}")
 | 
			
		||||
                    })?
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let mermaid = subtree.to_mermaid(&ctx.repo_url.to_string());
 | 
			
		||||
 | 
			
		||||
        let full_text = format!(
 | 
			
		||||
            r##"## Partial Techtree
 | 
			
		||||
```mermaid
 | 
			
		||||
{mermaid}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<small>Digest: {hash}; Last Updated: {timestamp}</small>"##,
 | 
			
		||||
            timestamp = ctx.timestamp,
 | 
			
		||||
        );
 | 
			
		||||
            continue 'issues;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        log::info!("Updating bot comment in issue #{issue} ...");
 | 
			
		||||
        issue::update_bot_comment(&ctx, comment_id, full_text)
 | 
			
		||||
        issue::update_bot_comment_from_subtree(&ctx, bot_comment.id, &subtree, &hash)
 | 
			
		||||
            .await
 | 
			
		||||
            .with_context(|| format!("Failed to update the bot comment in issue #{issue}"))?;
 | 
			
		||||
            .with_context(|| format!("Failed to update bot comment in issue #{issue}"))?;
 | 
			
		||||
 | 
			
		||||
        issue::remove_stale_label(&ctx, issue)
 | 
			
		||||
            .await
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,45 +15,27 @@ impl SuccessExt for Command {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn render_and_publish(
 | 
			
		||||
    ctx: &crate::Context,
 | 
			
		||||
    tree: &crate::tree::Tree,
 | 
			
		||||
) -> anyhow::Result<()> {
 | 
			
		||||
    let render_repo = std::path::PathBuf::from("render-git");
 | 
			
		||||
pub struct RenderedTree {
 | 
			
		||||
    repo_dir: std::path::PathBuf,
 | 
			
		||||
    dot_file: std::path::PathBuf,
 | 
			
		||||
    svg_file: std::path::PathBuf,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    if render_repo.is_dir() {
 | 
			
		||||
        log::info!("Found old {render_repo:?} repository, removing...");
 | 
			
		||||
        std::fs::remove_dir_all(&render_repo)
 | 
			
		||||
            .context("Failed to remove stale render repository")?;
 | 
			
		||||
pub async fn render(
 | 
			
		||||
    _ctx: &crate::Context,
 | 
			
		||||
    tree: &crate::tree::Tree,
 | 
			
		||||
) -> anyhow::Result<RenderedTree> {
 | 
			
		||||
    let repo_dir = std::path::PathBuf::from("render-git");
 | 
			
		||||
 | 
			
		||||
    if repo_dir.is_dir() {
 | 
			
		||||
        log::info!("Found old {repo_dir:?} repository, removing...");
 | 
			
		||||
        std::fs::remove_dir_all(&repo_dir).context("Failed to remove stale render repository")?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::fs::create_dir(&render_repo).context("Failed creating directory for rendered graph")?;
 | 
			
		||||
    std::fs::create_dir(&repo_dir).context("Failed creating directory for rendered graph")?;
 | 
			
		||||
 | 
			
		||||
    Command::new("git")
 | 
			
		||||
        .arg("-C")
 | 
			
		||||
        .arg(&render_repo)
 | 
			
		||||
        .arg("init")
 | 
			
		||||
        .arg("--initial-branch=render")
 | 
			
		||||
        .arg("--quiet")
 | 
			
		||||
        .success()
 | 
			
		||||
        .context("Failed to initialize render repository")?;
 | 
			
		||||
 | 
			
		||||
    Command::new("git")
 | 
			
		||||
        .arg("-C")
 | 
			
		||||
        .arg(&render_repo)
 | 
			
		||||
        .args(["config", "user.email", "git@fa-fo.de"])
 | 
			
		||||
        .success()
 | 
			
		||||
        .context("Failed to configure identity for render repo")?;
 | 
			
		||||
 | 
			
		||||
    Command::new("git")
 | 
			
		||||
        .arg("-C")
 | 
			
		||||
        .arg(&render_repo)
 | 
			
		||||
        .args(["config", "user.name", "Forgejo Actions"])
 | 
			
		||||
        .success()
 | 
			
		||||
        .context("Failed to configure identity for render repo")?;
 | 
			
		||||
 | 
			
		||||
    let dot_file = render_repo.join("techtree.dot");
 | 
			
		||||
    let svg_file = render_repo.join("techtree.svg");
 | 
			
		||||
    let dot_file = repo_dir.join("techtree.dot");
 | 
			
		||||
    let svg_file = repo_dir.join("techtree.svg");
 | 
			
		||||
 | 
			
		||||
    let dot_source = tree.to_dot();
 | 
			
		||||
    std::fs::write(&dot_file, dot_source.as_bytes())
 | 
			
		||||
| 
						 | 
				
			
			@ -67,18 +49,49 @@ pub async fn render_and_publish(
 | 
			
		|||
        .success()
 | 
			
		||||
        .context("Failed to generate svg graph from dot source")?;
 | 
			
		||||
 | 
			
		||||
    Ok(RenderedTree {
 | 
			
		||||
        repo_dir,
 | 
			
		||||
        dot_file,
 | 
			
		||||
        svg_file,
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn publish(ctx: &crate::Context, rendered: &RenderedTree) -> anyhow::Result<()> {
 | 
			
		||||
    Command::new("git")
 | 
			
		||||
        .arg("-C")
 | 
			
		||||
        .arg(&render_repo)
 | 
			
		||||
        .arg(&rendered.repo_dir)
 | 
			
		||||
        .arg("init")
 | 
			
		||||
        .arg("--initial-branch=render")
 | 
			
		||||
        .arg("--quiet")
 | 
			
		||||
        .success()
 | 
			
		||||
        .context("Failed to initialize render repository")?;
 | 
			
		||||
 | 
			
		||||
    Command::new("git")
 | 
			
		||||
        .arg("-C")
 | 
			
		||||
        .arg(&rendered.repo_dir)
 | 
			
		||||
        .args(["config", "user.email", "git@fa-fo.de"])
 | 
			
		||||
        .success()
 | 
			
		||||
        .context("Failed to configure identity for render repo")?;
 | 
			
		||||
 | 
			
		||||
    Command::new("git")
 | 
			
		||||
        .arg("-C")
 | 
			
		||||
        .arg(&rendered.repo_dir)
 | 
			
		||||
        .args(["config", "user.name", "Forgejo Actions"])
 | 
			
		||||
        .success()
 | 
			
		||||
        .context("Failed to configure identity for render repo")?;
 | 
			
		||||
 | 
			
		||||
    Command::new("git")
 | 
			
		||||
        .arg("-C")
 | 
			
		||||
        .arg(&rendered.repo_dir)
 | 
			
		||||
        .arg("add")
 | 
			
		||||
        .arg(dot_file.file_name().unwrap())
 | 
			
		||||
        .arg(svg_file.file_name().unwrap())
 | 
			
		||||
        .arg(rendered.dot_file.strip_prefix(&rendered.repo_dir).unwrap())
 | 
			
		||||
        .arg(rendered.svg_file.strip_prefix(&rendered.repo_dir).unwrap())
 | 
			
		||||
        .success()
 | 
			
		||||
        .context("Failed to add generated graph files to git index")?;
 | 
			
		||||
 | 
			
		||||
    Command::new("git")
 | 
			
		||||
        .arg("-C")
 | 
			
		||||
        .arg(&render_repo)
 | 
			
		||||
        .arg(&rendered.repo_dir)
 | 
			
		||||
        .arg("commit")
 | 
			
		||||
        .args(["-m", &format!("Updated techtree at {}", ctx.timestamp)])
 | 
			
		||||
        .success()
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +99,7 @@ pub async fn render_and_publish(
 | 
			
		|||
 | 
			
		||||
    Command::new("git")
 | 
			
		||||
        .arg("-C")
 | 
			
		||||
        .arg(&render_repo)
 | 
			
		||||
        .arg(&rendered.repo_dir)
 | 
			
		||||
        .arg("push")
 | 
			
		||||
        .arg("--force")
 | 
			
		||||
        .arg("--quiet")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -166,11 +166,14 @@ impl Tree {
 | 
			
		|||
            &|_g, (_, element)| element.to_dot_node_attributes(None),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        format!(r#"digraph {{
 | 
			
		||||
        format!(
 | 
			
		||||
            r#"digraph {{
 | 
			
		||||
    ranksep=1.2
 | 
			
		||||
{:?}
 | 
			
		||||
}}
 | 
			
		||||
"#, dot)
 | 
			
		||||
"#,
 | 
			
		||||
            dot
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn to_mermaid(&self, repo_url: &str) -> String {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,29 @@
 | 
			
		|||
use anyhow::Context as _;
 | 
			
		||||
use base64::prelude::*;
 | 
			
		||||
 | 
			
		||||
pub async fn update_wiki_overview(
 | 
			
		||||
pub async fn update_wiki_from_tree(
 | 
			
		||||
    ctx: &crate::Context,
 | 
			
		||||
    new_body: String,
 | 
			
		||||
    tree: &crate::tree::Tree,
 | 
			
		||||
) -> anyhow::Result<()> {
 | 
			
		||||
    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:
 | 
			
		||||
 | 
			
		||||
```mermaid
 | 
			
		||||
{mermaid}
 | 
			
		||||
```
 | 
			
		||||
"##
 | 
			
		||||
    );
 | 
			
		||||
    update_wiki_overview(&ctx, wiki_text)
 | 
			
		||||
        .await
 | 
			
		||||
        .context("Failed to update the techtree wiki page")?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn update_wiki_overview(ctx: &crate::Context, new_body: String) -> anyhow::Result<()> {
 | 
			
		||||
    // TODO: Figure out why we get a 404 when the edit was successfull...
 | 
			
		||||
    let _ = ctx.forgejo
 | 
			
		||||
    let _ = ctx
 | 
			
		||||
        .forgejo
 | 
			
		||||
        .repo_edit_wiki_page(
 | 
			
		||||
            &ctx.owner,
 | 
			
		||||
            &ctx.repo,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue