Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ env_logger = "0.10"
chrono = "0.4"
colored = "2.0"
dialoguer = "0.11"
serde_yaml = "0.9.34"

[dev-dependencies]
tempfile = "3.8"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ For more detailed development instructions, see [DEVELOPMENT.md](docs/DEVELOPMEN
- Runs go mod tidy to update dependencies
- **Ruby**: Updates versions in gemspec and version.rb files
- Runs bundle install to update dependencies
- **Helm charts**: Updates version in the Chart.yaml file

## Acknowledgements

Expand Down
80 changes: 80 additions & 0 deletions src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,88 @@ pub fn detect_project(dir: &str) -> Result<Box<dyn Project>> {
return Ok(Box::new(RubyProject::new(gemfile_path)));
}

let chart_path = dir_path.join("Chart.yaml");
if chart_path.exists() {
debug!("Detected Helm chart project (Chart.yaml)");
return Ok(Box::new(HelmChartProject::new(chart_path)));
}

Err(anyhow!("No supported project files found in {}", dir))
}
// Helm chart project (Chart.yaml)
pub struct HelmChartProject {
path: PathBuf,
}

impl HelmChartProject {
pub fn new(path: PathBuf) -> Self {
Self { path }
}

fn update_version_internal(&self, version: &Version, dry_run: bool) -> Result<String> {
// Read the original content
let content = fs::read_to_string(&self.path).context("Failed to read Chart.yaml")?;

let old_version = self.get_version()?;

// Using regex for targeted replacement that preserves all formatting
let re = regex::Regex::new(r#"(?m)^(version:\s)([^\s]+)(.*)$"#).unwrap();
let new_content = re.replace(&content, |caps: &regex::Captures| {
format!("{}{}{}", &caps[1], version, &caps[3])
});

let diff = format!(
"{} Chart.yaml:\n version: {} → {}",
if dry_run { "Would update" } else { "Updated" },
old_version,
version
);

if !dry_run {
fs::write(&self.path, new_content.as_bytes())
.context("Failed to write updated Chart.yaml")?;
}

Ok(diff)
}
}

impl Project for HelmChartProject {
fn get_version(&self) -> Result<Version> {
let content = fs::read_to_string(&self.path).context("Failed to read Chart.yaml")?;

let yaml: serde_yaml::Value =
serde_yaml::from_str(&content).context("Failed to parse Chart.yaml")?;

let version_str = yaml["version"]
.as_str()
.ok_or_else(|| anyhow!("No version field found in Chart.yaml"))?;

Version::parse(version_str).context("Failed to parse version from Chart.yaml")
}

fn update_version(&self, version: &Version) -> Result<()> {
self.update_version_internal(version, false)?;
Ok(())
}

fn dry_run_update(&self, version: &Version) -> Result<String> {
self.update_version_internal(version, true)
}

fn get_file_path(&self) -> &Path {
&self.path
}

fn get_files_to_commit(&self) -> Vec<PathBuf> {
vec![self.path.clone()]
}

fn get_package_manager_update_command(&self) -> Option<String> {
// Helm doesn't have a package manager update command
None
}
}

// Node.js project (package.json)
pub struct NodeProject {
Expand Down
36 changes: 36 additions & 0 deletions tests/test_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,42 @@ fn test_node_project_detection() -> Result<()> {
Ok(())
}

#[test]
fn test_chart_project_detection() -> Result<()> {
let temp_dir = tempdir()?;
let package_json_path = temp_dir.path().join("Chart.yaml");

// Create a minimal package.json
fs::write(
&package_json_path,
r#"
apiVersion: v2
name: Helm Chart
description: A Helm chart for Kubernetes
type: application
version: 1.2.3
appVersion: "Release-1.0.0"
"#,
)?;

// Detect project type
let project = detect_project(temp_dir.path().to_str().unwrap())?;

// Verify detected version
let version = project.get_version()?;
assert_eq!(version, Version::new(1, 2, 3));

// Test update
let new_version = Version::new(2, 0, 0);
project.update_version(&new_version)?;

// Verify updated version
let updated_content = fs::read_to_string(&package_json_path)?;
assert!(updated_content.contains(r#"version: 2.0.0"#));

Ok(())
}

#[test]
fn test_python_project_detection() -> Result<()> {
let temp_dir = tempdir()?;
Expand Down