Files
Content-Monorepo/.actions/publish/publish.rs
2026-04-12 19:54:53 -06:00

157 lines
5.9 KiB
Rust

use serde_json::Value;
use std::env;
use std::fs::{self, OpenOptions};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};
fn main() {
let diff_output = Command::new("git")
.args(["diff-tree", "--no-commit-id", "--name-only", "-r", "HEAD"])
.output()
.expect("failed to run git diff");
let diff_str = String::from_utf8_lossy(&diff_output.stdout);
let manifest_path_str = diff_str.lines().find(|l| l.ends_with("manifest.json"));
let manifest_path_str = match manifest_path_str {
Some(p) => p,
None => {
println!("no manifest.json found in recent commit. skipping.");
std::process::exit(0);
}
};
let manifest_path = Path::new(manifest_path_str);
let p_dir = manifest_path.parent().expect("Could not find parent dir");
let manifest_content = fs::read_to_string(manifest_path).expect("Failed to read manifest");
let manifest: Value = serde_json::from_str(&manifest_content).expect("Failed to parse manifest JSON");
let raw_name = manifest["name"].as_str().unwrap();
let p_name = raw_name.replace(" ", "-");
let p_ver = manifest["version"].as_str().unwrap();
let mc_ver = manifest["mc_version"].as_str().unwrap();
let p_type = manifest["type"].as_str().unwrap();
let mr_id = manifest["modrinth_id"].as_str().unwrap_or("");
let cf_id = manifest["curseforge_id"].as_str().unwrap_or("");
let filename_base = format!("{}-{}-fabric-{}", p_name, mc_ver, p_ver);
let changelog_file = p_dir.join("changelog.md");
let mut notes = if changelog_file.exists() {
fs::read_to_string(&changelog_file).unwrap()
} else {
format!("update for {}", raw_name)
};
let prev_bump = Command::new("git")
.args(["log", "-n", "2", "--format=%H", "--", manifest_path_str])
.output()
.expect("Failed to get git log for manifest");
let prev_hashes = String::from_utf8_lossy(&prev_bump.stdout);
let prev_hash = prev_hashes.lines().nth(1).unwrap_or("HEAD~1");
let logs = Command::new("git")
.args(["log", &format!("{}..HEAD", prev_hash), "--format=%h %s - %an", "--", p_dir.to_str().unwrap()])
.output()
.expect("Failed to get commit logs");
let commit_lines: Vec<&str> = std::str::from_utf8(&logs.stdout)
.unwrap()
.lines()
.filter(|l| l.contains(": "))
.collect();
if !commit_lines.is_empty() {
if !notes.contains("# :purple_circle: Meta-changes") {
notes.push_str("\n\n# :purple_circle: Meta-changes\n");
}
notes.push_str("\n### Automated Commit Log\n");
for line in commit_lines {
notes.push_str(&format!("{}\n", line));
}
}
let workspace = env::var("GITHUB_WORKSPACE").unwrap_or_else(|_| ".".to_string());
let artifacts_dir = Path::new(&workspace).join(p_dir).join("artifacts");
if artifacts_dir.exists() {
fs::remove_dir_all(&artifacts_dir).unwrap();
}
fs::create_dir_all(&artifacts_dir).unwrap();
println!("::group::Building Artifacts");
if p_type == "modpack" {
for platform in &["mr", "cf"] {
let target_folder = format!("{}-{}", mc_ver, platform);
let target_path = p_dir.join(&target_folder);
if target_path.exists() {
// Refresh packwiz
run_cmd("packwiz", &["refresh"], &target_path);
let (export_cmd, ext) = if *platform == "mr" { ("modrinth", "mrpack") } else { ("curseforge", "zip") };
let out_file = artifacts_dir.join(format!("{}-{}.{}", filename_base, platform, ext));
// Export packwiz
run_cmd("packwiz", &[export_cmd, "export", "--output", out_file.to_str().unwrap()], &target_path);
} else {
println!("Skipping {}: folder {} not found", platform, target_path.display());
}
}
} else if p_type == "resourcepack" || p_type == "datapack" {
let out_file = artifacts_dir.join(format!("{}-{}.zip", manifest["id"].as_str().unwrap(), p_ver));
let content_dir = p_dir.join("content");
if content_dir.exists() {
run_cmd("zip", &["-r", out_file.to_str().unwrap(), "."], &content_dir);
} else {
println!("Error: content directory not found at {}", content_dir.display());
}
}
println!("::endgroup::");
if let Ok(out_path) = env::var("GITHUB_OUTPUT") {
let mut out_file = OpenOptions::new()
.append(true)
.create(true)
.open(out_path)
.expect("Could not open GITHUB_OUTPUT");
writeln!(out_file, "mr_id={}", mr_id).unwrap();
writeln!(out_file, "cf_id={}", cf_id).unwrap();
writeln!(out_file, "name={} {}", raw_name, p_ver).unwrap();
writeln!(out_file, "ver={}", p_ver).unwrap();
writeln!(out_file, "mc={}", mc_ver).unwrap();
writeln!(out_file, "type={}", p_type).unwrap();
writeln!(out_file, "path={}", p_dir.to_str().unwrap()).unwrap();
let delimiter = "EOF_NOTES_DELIMITER";
writeln!(out_file, "notes<<{}\n{}\n{}", delimiter, notes.trim(), delimiter).unwrap();
}
}
fn run_cmd(cmd: &str, args: &[&str], dir: &PathBuf) {
let status = Command::new(cmd)
.args(args)
.current_dir(dir)
.status();
match status {
Ok(s) if s.success() => (),
Ok(s) => {
eprintln!("Command '{} {:?}' failed with exit code: {}", cmd, args, s);
std::process::exit(1);
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
eprintln!("CRITICAL: Binary '{}' not found in PATH.", cmd);
eprintln!("Ensure it is installed and added to GITHUB_PATH.");
std::process::exit(1);
}
Err(e) => {
eprintln!("Failed to execute '{}': {}", cmd, e);
std::process::exit(1);
}
}
}