use std::fs;
use std::path::{Path, PathBuf};
use flate2::read::GzDecoder;
use gitversion_rs::{buildagent, config, git, version};
fn extract_fixtures() -> PathBuf {
let archive = Path::new(env!("CARGO_MANIFEST_DIR")).join("testdata/fixtures.tar.gz");
assert!(
archive.exists(),
"fixture 압축이 없습니다: {}",
archive.display()
);
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos())
.unwrap_or(0);
let dest = std::env::temp_dir().join(format!("gitversion-ba-{}-{}", std::process::id(), nanos));
fs::create_dir_all(&dest).unwrap();
let file = fs::File::open(&archive).unwrap();
tar::Archive::new(GzDecoder::new(file))
.unpack(&dest)
.unwrap();
dest
}
fn keep(line: &str) -> bool {
!line.is_empty() && !line.to_uppercase().contains("UNCOMMITTEDCHANGES")
}
#[test]
fn build_agents_match_real_gitversion() {
let root = extract_fixtures();
let agents = [
"TeamCity",
"AzurePipelines",
"ContinuaCi",
"MyGet",
"Drone",
"BitBucketPipelines",
"Jenkins",
"CodeBuild",
"BuildKite",
"SpaceAutomation",
"EnvRun",
"TravisCi",
"GitLabCi",
"GitHubActions",
];
let mut failures = Vec::new();
let mut checked = 0;
for scenario in ["buildagent_repo", "buildagent_no_ubn"] {
let repo_dir = root.join(scenario);
if !repo_dir.join("expected.json").exists() {
failures.push(format!("{scenario} 시나리오가 없습니다"));
continue;
}
let repo = git::GitRepo::discover(&repo_dir).unwrap();
let workdir = repo
.workdir()
.map(|p| p.to_path_buf())
.unwrap_or_else(|| repo_dir.clone());
let configuration = config::loader::load(None, &workdir, Some(&workdir)).unwrap();
let update_build_number = configuration.update_build_number.unwrap_or(true);
let vars = version::calculation::calculate(&repo, &configuration, None).unwrap();
for agent_name in agents {
let golden_path = repo_dir.join(format!("agent_{agent_name}.txt"));
let Ok(golden) = fs::read_to_string(&golden_path) else {
failures.push(format!(
"[{scenario}/{agent_name}] golden 파일 없음: {}",
golden_path.display()
));
continue;
};
let agent = buildagent::by_name(agent_name).expect("알 수 없는 에이전트");
if agent_name == "GitHubActions" {
let tmp = std::env::temp_dir().join(format!("gh_env_{}", std::process::id()));
unsafe { std::env::set_var("GITHUB_ENV", &tmp) };
}
let golden_lines: Vec<&str> = golden.lines().filter(|l| keep(l)).collect();
let mine: Vec<String> = agent
.write_integration(&vars, update_build_number)
.into_iter()
.filter(|l| keep(l))
.collect();
if mine.len() != golden_lines.len() {
failures.push(format!(
"[{scenario}/{agent_name}] 라인 수 불일치: real={} mine={}",
golden_lines.len(),
mine.len()
));
continue;
}
for (i, (g, m)) in golden_lines.iter().zip(mine.iter()).enumerate() {
if g != m {
failures.push(format!(
"[{scenario}/{agent_name}] line {i}: real={g:?} mine={m:?}"
));
}
}
checked += 1;
}
}
let _ = fs::remove_dir_all(&root);
assert!(
failures.is_empty(),
"{}개 에이전트 검증 중 불일치:\n{}",
checked,
failures.join("\n")
);
println!("{checked}개 빌드에이전트 출력이 실제 GitVersion 과 일치");
}