diff --git a/WebMoMMI/src/github/changelog.rs b/WebMoMMI/src/github/changelog.rs index abad611..adbc2f5 100755 --- a/WebMoMMI/src/github/changelog.rs +++ b/WebMoMMI/src/github/changelog.rs @@ -7,7 +7,7 @@ use serde::de::{Error, MapAccess, Visitor}; use serde::ser::SerializeMap; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; -use std::fs::{read_dir, File}; +use std::fs::{create_dir_all, read_dir, File, OpenOptions}; use std::io::Write; use std::path::Path; use std::process::Command; @@ -16,12 +16,57 @@ use std::sync::{Mutex, MutexGuard}; use std::thread; use std::time::{Duration, Instant}; +const LOG_DIR: &str = "logs"; +const LOG_FILE: &str = "logs/changelog.log"; + +fn get_timestamp() -> String { + Command::new("date") + .arg("+%Y-%m-%d %H:%M:%S") + .output() + .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string()) + .unwrap_or_else(|_| "???".to_string()) +} + +fn log_to_file(level: &str, message: &str) { + let timestamp = get_timestamp(); + let line = format!("{} [{}] {}\n", timestamp, level, message); + + match level { + "ERROR" | "WARNING" => eprint!("{}", line), + _ => print!("{}", line), + } + + let _ = create_dir_all(LOG_DIR); + if let Ok(mut file) = OpenOptions::new() + .create(true) + .append(true) + .open(LOG_FILE) + { + let _ = file.write_all(line.as_bytes()); + } +} + +fn log_info(message: &str) { + log_to_file("INFO", message); +} + +fn log_warning(message: &str) { + log_to_file("WARNING", message); +} + +fn log_error(message: &str) { + log_to_file("ERROR", message); +} + pub fn try_handle_changelog_pr(event: &PullRequestEvent, config: &Arc) { + log_info(&format!("Received PR event: action={:?}, merged={}, PR#{}", + event.action, event.pull_request.merged, event.number)); + if event.action != PullRequestAction::Closed || !event.pull_request.merged || !config.has_changelog_repo_path() { - // Not a merge + log_info("PR not a merge or no changelog repo configured, skipping"); return; } @@ -34,9 +79,12 @@ pub fn try_handle_changelog_pr(event: &PullRequestEvent, config: &Arc eprintln!("Error writing changelog temp file: {:?}", e), - _ => {} + Err(e) => log_error(&format!("Error writing changelog temp file: {:?}", e)), + _ => log_info(&format!("Wrote temp changelog for PR-{}", event.number)), }; process_changelogs(config); @@ -70,7 +118,7 @@ pub fn try_handle_changelog_push(event: &PushEvent, config: &Arc) { .iter() .flat_map(|c| c.added.iter().chain(c.modified.iter())) { - println!("{}", filename); + log_info(&format!("Push event file: {}", filename)); if IS_CHANGELOG_RE.is_match(filename) { process_changelogs(config); return; @@ -206,12 +254,14 @@ pub enum ChangelogEntryType { } pub fn process_changelogs(config: &Arc) { + log_info("process_changelogs called"); let mut lock = CHANGELOG_MANAGER.lock().unwrap(); let should_spawn_thread = lock.last_time.is_none(); lock.last_time = Some(Instant::now()); if should_spawn_thread { // Nobody currently processing. + log_info("Spawning new changelog thread"); lock.last_time = Some(Instant::now()); let config = config.clone(); thread::Builder::new() @@ -220,32 +270,40 @@ pub fn process_changelogs(config: &Arc) { handle_changelog_thread(config); }) .unwrap(); + } else { + log_info("Changelog thread already running, updated last_time"); } } fn handle_changelog_thread(config: Arc) { let delay = config.get_changelog_delay(); + log_info(&format!("Changelog thread started, delay={}s", delay)); loop { let time = { let lock = CHANGELOG_MANAGER.lock().unwrap(); let elapsed = lock.last_time.as_ref().unwrap().elapsed(); if elapsed.as_secs() > delay { + log_info("Delay elapsed, starting changelog processing"); return do_changelog(lock, config); } match Duration::from_secs(delay).checked_sub(elapsed) { Some(t) => t, - None => return do_changelog(lock, config), + None => { + log_info("Delay elapsed, starting changelog processing"); + return do_changelog(lock, config); + } } }; + log_info(&format!("Waiting {:?} before processing", time)); thread::sleep(time); } } // Pass the lock directly so we don't risk race conditions. fn do_changelog(mut lock: MutexGuard, config: Arc) { - println!("Running changelogs!"); + log_info("Running changelogs!"); // Get what we need and drop the lock. // so we don't hang everything for the time it takes for the git commands and stuff. lock.last_time = None; @@ -256,19 +314,39 @@ fn do_changelog(mut lock: MutexGuard, config: Arc .get_ssh_key() .map(|p| format!("ssh -i {}", p.to_string_lossy())); - // Git pull the repo. + let checkout_status = Command::new("git") + .arg("checkout") + .arg("Bleeding-Edge") + .current_dir(&path) + .status(); + + if let Ok(s) = checkout_status { + if !s.success() { + log_error(&format!("git checkout failed: {:?}", s)); + return; + } + } + + // Git pull the repo, resolve conflicts using remote version let mut command = Command::new("git"); command .arg("pull") - .arg("origin") .arg("--rebase") + .arg("origin") + .arg("Bleeding-Edge") + .arg("-X") + .arg("theirs") .current_dir(&path); if let Some(ref ssh_command) = ssh_config { command.env("GIT_SSH_COMMAND", &ssh_command); } let status = command.status().unwrap(); - assert!(status.success()); + if !status.success() { + log_error(&format!("Pull failed: {:?}", status)); + return; + } + log_info("git pull successful"); let mut changelog_dir_path = path.to_owned(); changelog_dir_path.push("html/changelogs"); @@ -286,16 +364,32 @@ fn do_changelog(mut lock: MutexGuard, config: Arc continue; } - println!("{}", file_name); + log_info(&format!("Processing changelog file: {}", file_name)); - let file = File::open(entry.path()).unwrap(); - let data: Changelog = serde_yaml::from_reader(&file).unwrap(); + let file = match File::open(entry.path()) { + Ok(f) => f, + Err(e) => { + log_error(&format!("Failed to open {}: {:?}", file_name, e)); + continue; + } + }; + let data: Changelog = match serde_yaml::from_reader(&file) { + Ok(d) => d, + Err(e) => { + log_error(&format!("Failed to parse {}: {:?}", file_name, e)); + continue; + } + }; if data.changes.len() == 0 { + log_warning(&format!("Changelog {} has no changes, skipping", file_name)); continue; } - commloop(addr, pass, "changelog", "", data).unwrap(); + match commloop(addr, pass, "changelog", "", &data) { + Ok(_) => log_info(&format!("Changelog for {} sent to commloop", file_name)), + Err(e) => log_error(&format!("Failed sending changelog for {}: {:?}", file_name, e)), + } } } @@ -305,63 +399,70 @@ fn do_changelog(mut lock: MutexGuard, config: Arc .arg("html/changelog.html") .arg("html/changelogs") .current_dir(&path) - .status() - .unwrap(); + .status(); - assert!(status.success()); + match status { + Ok(s) if s.success() => log_info("Changelog script successful"), + Ok(s) => log_error(&format!("Changelog script failed: {:?}", s)), + Err(e) => log_error(&format!("Changelog script failed badly: {:?}", e)), + } - Command::new("git") - .arg("update-index") - .arg("--refresh") - .current_dir(&path) - .status() - .unwrap(); - - // See if repo is dirty. - let status = Command::new("git") - .arg("diff-index") - .arg("--exit-code") - .arg("HEAD") - .current_dir(&path) - .status() - .unwrap(); - if status.code().unwrap_or(0) == 0 { - // No changes, nothing to commit. - return; - } + // Job below is handled by a github action now - let status = Command::new("git") - .arg("add") - .arg(".") - .arg("-A") - .current_dir(&path) - .status() - .unwrap(); - assert!(status.success()); + // Command::new("git") + // .arg("update-index") + // .arg("--refresh") + // .current_dir(&path) + // .status() + // .unwrap(); - let status = Command::new("git") - .arg("commit") - .arg("-m") - .arg("[ci skip] Automatic changelog update.") - .current_dir(&path) - .status() - .unwrap(); + // // See if repo is dirty. + // let status = Command::new("git") + // .arg("diff-index") + // .arg("--exit-code") + // .arg("HEAD") + // .current_dir(&path) + // .status() + // .unwrap(); - assert!(status.success()); + // if status.code().unwrap_or(0) == 0 { + // // No changes, nothing to commit. + // return; + // } - // Git push the repo. - let mut command = Command::new("git"); - command.arg("push").arg("origin").current_dir(&path); - if let Some(ref ssh_command) = ssh_config { - command.env("GIT_SSH_COMMAND", &ssh_command); - } - let status = command.status().unwrap(); + // let status = Command::new("git") + // .arg("add") + // .arg(".") + // .arg("-A") + // .current_dir(&path) + // .status() + // .unwrap(); - assert!(status.success()); + // assert!(status.success()); - println!("done"); + // let status = Command::new("git") + // .arg("commit") + // .arg("-m") + // .arg("[ci skip] Automatic changelog update.") + // .current_dir(&path) + // .status() + // .unwrap(); + + // assert!(status.success()); + + // Git push the repo. + //let mut command = Command::new("git"); + //command.arg("push").arg("origin").current_dir(&path); + //if let Some(ref ssh_command) = ssh_config { + // command.env("GIT_SSH_COMMAND", &ssh_command); + //} + //let status = command.status().unwrap(); +// + //assert!(status.success()); + + log_info("Changelog processing complete"); } #[cfg(test)] diff --git a/config/example/main.toml b/config/example/main.toml index ef27478..ea14d98 100755 --- a/config/example/main.toml +++ b/config/example/main.toml @@ -23,4 +23,7 @@ password = "secret" #COMMLOOP PASSWORD type="gamenudge" "server_status" = [[692441846739238952, 1160976587844501586]] #server id, channel id "ick" = [[692441846739238952, 1160976569435688970]] -"adminhelp" = [[692441846739238952, 1160976627078017175]] \ No newline at end of file +"adminhelp" = [[692441846739238952, 1160976627078017175]] + +[commloop.route.changelog] +"" = [[SERVER_ID, CHANGELOG_CHANNEL_ID]] #leading quotes are empty