use release_tool::command::SystemCommandRunner;
use release_tool::config::{Config, TargetConfig};
use release_tool::domain::{ArtifactIdentity, ReleaseCandidate, ReleaseIntent};
use release_tool::tag::CalendarTag;
use release_tool::target::{MavenReactorTarget, TargetAdapter};
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::sync::Arc;
#[test]
fn maven_target_derives_coordinates_from_the_reactor_and_prepares_exact_artifacts() {
let root = tempfile::tempdir().unwrap();
write_reactor(root.path());
let config = config();
let target_config = match &config.targets[0] {
value @ TargetConfig::MavenReactor { .. } => value,
_ => unreachable!(),
};
let adapter =
MavenReactorTarget::new(root.path(), target_config, Arc::new(SystemCommandRunner)).unwrap();
let release = ReleaseCandidate {
repository: "computed-parameter/example".to_owned(),
commit: "commit01".to_owned(),
tag: CalendarTag::parse("2026.08.23.1").unwrap(),
intent: ReleaseIntent::New,
tag_already_sealed: true,
};
let plan = adapter.resolve(&release).unwrap();
let identities = plan
.artifacts
.iter()
.map(|identity| match identity {
ArtifactIdentity::MavenPackage {
group_id,
artifact_id,
version,
extension,
} => format!("{group_id}:{artifact_id}:{version}:{extension}"),
_ => unreachable!(),
})
.collect::<Vec<_>>();
assert_eq!(
identities,
[
"com.example:example-sdk:2026.08.23.1:jar",
"com.example:example-sdk:2026.08.23.1:pom",
"com.example:example-model:2026.08.23.1:jar",
"com.example:example-model:2026.08.23.1:pom",
]
);
let manifest = adapter
.prepare(&plan, &Default::default(), &root.path().join("staging"))
.unwrap();
assert_eq!(manifest.artifacts.len(), 4);
assert!(
manifest
.artifacts
.iter()
.all(|artifact| artifact.path.is_file())
);
assert!(
manifest
.artifacts
.iter()
.all(|artifact| artifact.sha256.len() == 64)
);
assert_eq!(
fs::read_to_string(root.path().join("maven.log")).unwrap(),
"-f pom.xml -pl model -am -Drevision=2026.08.23.1 --batch-mode --no-transfer-progress verify\n"
);
}
#[test]
fn maven_target_fails_when_the_exact_artifact_inventory_is_not_supported() {
let root = tempfile::tempdir().unwrap();
write_reactor(root.path());
let model_pom = root.path().join("model/pom.xml");
let source = fs::read_to_string(&model_pom).unwrap().replace(
"<version>${revision}</version>\n <dependencies>",
"<version>${revision}</version>\n <packaging>war</packaging>\n <dependencies>",
);
fs::write(model_pom, source).unwrap();
let config = config();
let adapter = MavenReactorTarget::new(
root.path(),
&config.targets[0],
Arc::new(SystemCommandRunner),
)
.unwrap();
let release = ReleaseCandidate {
repository: "computed-parameter/example".to_owned(),
commit: "commit01".to_owned(),
tag: CalendarTag::parse("2026.08.23.1").unwrap(),
intent: ReleaseIntent::New,
tag_already_sealed: true,
};
let error = adapter.resolve(&release).unwrap_err();
assert!(error.to_string().contains("unsupported packaging `war`"));
}
fn config() -> Config {
Config::parse(
r#"required_version = "0.1.0"
[repository]
github = "computed-parameter/example"
branch = "main"
[publishers.packages]
kind = "github_maven"
settings = ".mvn/settings.xml"
server_id = "github"
[[targets]]
name = "maven"
kind = "maven_reactor"
publisher = "packages"
default = true
wrapper = "./mvnw"
pom = "pom.xml"
projects = ["model"]
also_make = true
remote_check = []
"#,
)
.unwrap()
}
fn write_reactor(root: &std::path::Path) {
fs::create_dir(root.join("sdk")).unwrap();
fs::create_dir(root.join("model")).unwrap();
fs::write(
root.join("pom.xml"),
r#"<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>${revision}</version>
<packaging>pom</packaging>
<modules><module>sdk</module><module>model</module></modules>
</project>
"#,
)
.unwrap();
fs::write(
root.join("sdk/pom.xml"),
r#"<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>example-sdk</artifactId>
<version>${revision}</version>
</project>
"#,
)
.unwrap();
fs::write(
root.join("model/pom.xml"),
r#"<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>example-model</artifactId>
<version>${revision}</version>
<dependencies><dependency>
<groupId>com.example</groupId>
<artifactId>example-sdk</artifactId>
<version>${revision}</version>
</dependency></dependencies>
</project>
"#,
)
.unwrap();
fs::create_dir(root.join(".mvn")).unwrap();
fs::write(root.join(".mvn/settings.xml"), "<settings/>\n").unwrap();
let wrapper = root.join("mvnw");
fs::write(
&wrapper,
r#"#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "$*" >> maven.log
version=""
for arg in "$@"; do
case "$arg" in -Drevision=*) version="${arg#-Drevision=}" ;; esac
done
for project in sdk model; do
artifact="example-$project"
mkdir -p "$project/target"
printf 'jar %s %s\n' "$artifact" "$version" > "$project/target/$artifact-$version.jar"
cp "$project/pom.xml" "$project/target/flattened-pom.xml"
done
"#,
)
.unwrap();
let mut permissions = fs::metadata(&wrapper).unwrap().permissions();
permissions.set_mode(0o755);
fs::set_permissions(wrapper, permissions).unwrap();
}