diff --git a/techtree-manager/.gitignore b/techtree-manager/.gitignore index b83d222..00df608 100644 --- a/techtree-manager/.gitignore +++ b/techtree-manager/.gitignore @@ -1 +1,2 @@ /target/ +/render-git/ diff --git a/techtree-manager/src/main.rs b/techtree-manager/src/main.rs index 6dfe71f..cef79ca 100644 --- a/techtree-manager/src/main.rs +++ b/techtree-manager/src/main.rs @@ -4,6 +4,7 @@ use forgejo_api::Forgejo; mod collect; mod event_meta; mod issue; +mod render; mod tree; mod wiki; @@ -21,7 +22,7 @@ async fn run() -> anyhow::Result<()> { meta.issue.number ); - let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"); + let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); log::info!("Timestamp of this run is {timestamp}"); let token = @@ -33,6 +34,10 @@ async fn run() -> anyhow::Result<()> { ) .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 { @@ -56,6 +61,11 @@ async fn run() -> anyhow::Result<()> { .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) + .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: diff --git a/techtree-manager/src/render.rs b/techtree-manager/src/render.rs new file mode 100644 index 0000000..9373d2d --- /dev/null +++ b/techtree-manager/src/render.rs @@ -0,0 +1,69 @@ +use std::process::Command; + +use anyhow::Context as _; + +pub async fn render_and_publish( + tree: &crate::tree::Tree, + timestamp: &str, + repo_auth_url: &url::Url, +) -> anyhow::Result<()> { + let render_repo = std::path::PathBuf::from("render-git"); + + 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")?; + } + + std::fs::create_dir(&render_repo).context("Failed creating directory for rendered graph")?; + + Command::new("git") + .arg("-C") + .arg(&render_repo) + .arg("init") + .status() + .context("Failed to initialize render repository")?; + + let dot_file = render_repo.join("techtree.dot"); + let svg_file = render_repo.join("techtree.svg"); + + let dot_source = tree.to_dot(); + std::fs::write(&dot_file, dot_source.as_bytes()) + .context("Failed to write `dot` source file")?; + + Command::new("dot") + .args(["-T", "svg"]) + .arg("-o") + .arg(&svg_file) + .arg(&dot_file) + .status() + .context("Failed to generate svg graph from dot source")?; + + Command::new("git") + .arg("-C") + .arg(&render_repo) + .arg("add") + .arg(dot_file.file_name().unwrap()) + .arg(svg_file.file_name().unwrap()) + .status() + .context("Failed to add generated graph files to git index")?; + + Command::new("git") + .arg("-C") + .arg(&render_repo) + .arg("commit") + .args(["-m", &format!("Updated techtree at {timestamp}")]) + .status() + .context("Failed to add generated graph files to git index")?; + + Command::new("git") + .arg("-C") + .arg(&render_repo) + .arg("push") + .arg("--force") + .arg(repo_auth_url.to_string()) + .arg("HEAD:refs/heads/render") + .status() + .context("Failed to push rendered graph to forgejo repository")?; + + Ok(()) +}