use regex::Regex;
use semver::Version;
use crate::{
forge::request::{FileChange, FileUpdateType},
packages::manifests::ManifestFile,
result::Result,
updater::{manager::UpdaterPackage, traits::PackageUpdater},
};
#[derive(Default)]
pub struct GenericUpdater {}
impl GenericUpdater {
pub fn update_manifest(
manifest: &ManifestFile,
next_version: &Version,
version_regex: &Regex,
) -> Option<FileChange> {
if !version_regex.is_match(&manifest.content) {
return None;
}
let content = version_regex
.replace_all(&manifest.content, |caps: ®ex::Captures| {
let full_match = &caps[0];
let version_match = &caps["version"];
full_match.replacen(version_match, &next_version.to_string(), 1)
})
.to_string();
if content != manifest.content {
return Some(FileChange {
path: manifest.path.to_string_lossy().to_string(),
content,
update_type: FileUpdateType::Replace,
});
}
None
}
}
impl PackageUpdater for GenericUpdater {
fn update(
&self,
_package: &UpdaterPackage,
_workspace_packages: &[UpdaterPackage],
) -> Result<Option<Vec<FileChange>>> {
Ok(None)
}
}
#[cfg(test)]
mod tests {
use semver::Version;
use std::{path::Path, rc::Rc};
use crate::{
config::{package::GENERIC_VERSION_REGEX, release_type::ReleaseType},
forge::request::Tag,
updater::dispatch::Updater,
};
use super::*;
fn create_manifest(content: &str) -> ManifestFile {
ManifestFile {
path: Path::new("test.txt").to_path_buf(),
basename: "test.txt".to_string(),
content: content.to_string(),
}
}
#[test]
fn update_manifest_updates_version_with_double_quotes() {
let manifest = create_manifest(r#"version = "1.0.0""#);
let next_version = Version::parse("2.0.0").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
let change = result.unwrap();
assert_eq!(change.content, r#"version = "2.0.0""#);
assert_eq!(change.path, "test.txt");
}
#[test]
fn update_manifest_updates_version_with_single_quotes() {
let manifest = create_manifest("version = '1.0.0'");
let next_version = Version::parse("2.0.0").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
assert!(result.unwrap().content.contains("'2.0.0'"));
}
#[test]
fn update_manifest_updates_version_with_colon() {
let manifest = create_manifest(r#""version": "1.0.0""#);
let next_version = Version::parse("2.0.0").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
assert_eq!(result.unwrap().content, r#""version": "2.0.0""#);
}
#[test]
fn update_manifest_preserves_whitespace() {
let manifest = create_manifest("version = \"1.0.0\"");
let next_version = Version::parse("2.0.0").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
assert_eq!(result.unwrap().content, "version = \"2.0.0\"");
}
#[test]
fn update_manifest_updates_version_with_prerelease() {
let manifest = create_manifest(r#"version = "1.0.0-alpha.1""#);
let next_version = Version::parse("2.0.0-beta.2").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
assert!(result.unwrap().content.contains("2.0.0-beta.2"));
}
#[test]
fn update_manifest_handles_multiline_content() {
let manifest = create_manifest(
"name = \"my-package\"\nversion = \"1.0.0\"\nauthor = \"Test\"",
);
let next_version = Version::parse("2.0.0").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
let content = result.unwrap().content;
assert!(content.contains("version = \"2.0.0\""));
assert!(content.contains("name = \"my-package\""));
assert!(content.contains("author = \"Test\""));
}
#[test]
fn update_manifest_returns_none_when_no_version_pattern() {
let manifest = create_manifest("name = \"my-package\"");
let next_version = Version::parse("2.0.0").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
assert!(result.is_none());
}
#[test]
fn update_manifest_returns_none_when_version_unchanged() {
let manifest = create_manifest(r#"version = "2.0.0""#);
let next_version = Version::parse("2.0.0").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
assert!(result.is_none());
}
#[test]
fn update_manifest_is_case_insensitive() {
let manifest = create_manifest(r#"VERSION = "1.0.0""#);
let next_version = Version::parse("2.0.0").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
assert!(result.unwrap().content.contains("2.0.0"));
}
#[test]
fn update_manifest_updates_yaml_format() {
let manifest = create_manifest(
"metadata:\n version: \"1.0.0\"\n description: \"My app\"",
);
let next_version = Version::parse("2.5.3").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
let content = result.unwrap().content;
assert!(content.contains("version: \"2.5.3\""));
assert!(content.contains("metadata:"));
assert!(content.contains("description: \"My app\""));
}
#[test]
fn update_manifest_updates_go_version_file() {
let manifest = create_manifest(
"package main\n\nconst Version = \"1.0.0\"\nconst AppName = \"myapp\"",
);
let next_version = Version::parse("3.2.1").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
);
let content = result.unwrap().content;
assert!(content.contains("const Version = \"3.2.1\""));
assert!(content.contains("package main"));
assert!(content.contains("const AppName = \"myapp\""));
}
#[test]
fn package_updater_update_returns_none() {
let updater = GenericUpdater::default();
let package = UpdaterPackage {
package_name: "test".to_string(),
manifest_files: vec![],
next_version: Tag {
sha: "abc".to_string(),
name: "v1.0.0".to_string(),
semver: Version::parse("1.0.0").unwrap(),
timestamp: None,
},
updater: Rc::new(Updater::new(ReleaseType::Generic)),
};
let result = updater.update(&package, &[]).unwrap();
assert!(result.is_none());
}
#[test]
fn update_manifest_handles_multi_digit_versions() {
let manifest = create_manifest(r#"version = "10.200.3""#);
let next_version = Version::parse("11.0.0").unwrap();
let result = GenericUpdater::update_manifest(
&manifest,
&next_version,
&GENERIC_VERSION_REGEX,
)
.unwrap();
assert_eq!(result.content, r#"version = "11.0.0""#);
}
}