//! The tag publish step must not recreate the git tag and must not send //! replace. BlueGit has no attach-to-existing-tag route; the script refuses //! the create-release call instead of issuing it. use std::fs; use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; use std::process::Command; fn repo_root() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) } fn path_prefix_env(prefix: &std::path::Path) -> std::ffi::OsString { let mut path = std::ffi::OsString::from(prefix); path.push(":"); path.push(std::env::var_os("PATH").unwrap_or_default()); path } fn install_curl_trap(dir: &std::path::Path) -> PathBuf { let curl = dir.join("curl"); fs::write( &curl, "#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"${CURL_TRAP_LOG:?}\"\nexit 0\n", ) .unwrap(); let mut permissions = fs::metadata(&curl).unwrap().permissions(); permissions.set_mode(0o755); fs::set_permissions(&curl, permissions).unwrap(); curl } fn executable_lines(script: &str) -> String { script .lines() .map(str::trim) .filter(|line| !line.is_empty() && !line.starts_with('#')) .collect::>() .join("\n") } #[test] fn tag_publish_does_not_call_create_release_or_send_replace() { let dir = std::env::temp_dir().join(format!("paperdoll-release-trap-{}", std::process::id())); let _ = fs::remove_dir_all(&dir); fs::create_dir_all(&dir).unwrap(); let log = dir.join("curl.log"); install_curl_trap(&dir); let output = Command::new("bash") .arg(repo_root().join("scripts/ci/release.sh")) .env("PATH", path_prefix_env(&dir)) .env("CURL_TRAP_LOG", &log) .env("CI_API_URL", "https://git.example.invalid/api/v1") .env("CI_JOB_TOKEN", "bgj_test_token_not_secret") .env("CI_COMMIT_SHA", "0123456789abcdef0123456789abcdef01234567") .env("CI_PROJECT_PATH", "golden-age/paperdoll-renderer") .env("CI_COMMIT_TAG", "v0.1.0") .env_remove("PACKAGE_VERSION") .output() .unwrap(); let stderr = String::from_utf8_lossy(&output.stderr); let stdout = String::from_utf8_lossy(&output.stdout); assert_eq!( output.status.code(), Some(3), "stdout:\n{stdout}\nstderr:\n{stderr}" ); assert!( stderr.contains("release-blocked: no-attach-endpoint"), "{stderr}" ); assert!( !log.exists(), "curl was invoked:\n{}", fs::read_to_string(&log).unwrap_or_default() ); let script = fs::read_to_string(repo_root().join("scripts/ci/release.sh")).unwrap(); let executable = executable_lines(&script); assert!( !executable.contains("curl"), "executable release script must not call curl:\n{executable}" ); assert!( !executable.contains("replace"), "executable release script must not send replace:\n{executable}" ); let _ = fs::remove_dir_all(&dir); } #[test] fn tag_publish_still_rejects_a_non_semver_tag_before_the_api_block() { let dir = std::env::temp_dir().join(format!("paperdoll-release-trap-bad-{}", std::process::id())); let _ = fs::remove_dir_all(&dir); fs::create_dir_all(&dir).unwrap(); let log = dir.join("curl.log"); install_curl_trap(&dir); let output = Command::new("bash") .arg(repo_root().join("scripts/ci/release.sh")) .env("PATH", path_prefix_env(&dir)) .env("CURL_TRAP_LOG", &log) .env("CI_API_URL", "https://git.example.invalid/api/v1") .env("CI_JOB_TOKEN", "bgj_test_token_not_secret") .env("CI_COMMIT_SHA", "0123456789abcdef0123456789abcdef01234567") .env("CI_PROJECT_PATH", "golden-age/paperdoll-renderer") .env("CI_COMMIT_TAG", "not-a-version") .env_remove("PACKAGE_VERSION") .output() .unwrap(); assert_ne!(output.status.code(), Some(0)); assert_ne!(output.status.code(), Some(3)); let stderr = String::from_utf8_lossy(&output.stderr); assert!(stderr.contains("package version must be X.Y.Z"), "{stderr}"); assert!(!log.exists(), "curl was invoked for an invalid tag"); let _ = fs::remove_dir_all(&dir); }