package maven import ( "fmt" "os" "regexp" "strings" ) var parentBlockRe = regexp.MustCompile(`(?s).*?`) var versionTagRe = regexp.MustCompile(`([^<]+)`) // ReadVersion returns the project version from a pom.xml file. // It ignores the block version and dependency versions. func ReadVersion(pomPath string) (string, error) { data, err := os.ReadFile(pomPath) if err != nil { return "", fmt.Errorf("read %s: %w", pomPath, err) } // Strip before searching so we don't pick up the parent version. stripped := parentBlockRe.ReplaceAllString(string(data), "") m := versionTagRe.FindStringSubmatch(stripped) if m == nil { return "", fmt.Errorf("no element found in %s", pomPath) } return strings.TrimSpace(m[1]), nil } // WriteVersion replaces the project version in a pom.xml file in-place. // oldVersion must match what ReadVersion returned. The version is never touched. func WriteVersion(pomPath, oldVersion, newVersion string) error { data, err := os.ReadFile(pomPath) if err != nil { return fmt.Errorf("read %s: %w", pomPath, err) } updated := replaceProjectVersion(string(data), oldVersion, newVersion) if updated == string(data) { return fmt.Errorf("version %q not found in %s", oldVersion, pomPath) } return os.WriteFile(pomPath, []byte(updated), 0644) } // replaceProjectVersion replaces the first oldVersion that is not // inside a block. This preserves the parent version and dependency versions. func replaceProjectVersion(content, oldVersion, newVersion string) string { target := "" + oldVersion + "" replacement := "" + newVersion + "" // If there is a block, start searching after it. if idx := strings.Index(content, ""); idx >= 0 { after := content[idx:] if pos := strings.Index(after, target); pos >= 0 { abs := idx + pos return content[:abs] + replacement + content[abs+len(target):] } return content } return strings.Replace(content, target, replacement, 1) }