claude-git-hooks 2.17.1 → 2.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ Todos los cambios notables en este proyecto se documentarán en este archivo.
5
5
  El formato está basado en [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.17.2] - 2026-03-02
9
+
10
+ ### 🐛 Fixed
11
+ - Improved pom.xml version detection to correctly distinguish project version from dependency/property versions (#76)
12
+ - Fixed false version mismatch errors for Maven submodules with inherited parent versions
13
+
14
+
8
15
  ## [2.17.1] - 2026-03-02
9
16
 
10
17
  ### 🐛 Fixed
@@ -21,6 +21,64 @@ import logger from './logger.js';
21
21
  */
22
22
  let cachedDiscoveryResult = null;
23
23
 
24
+ /**
25
+ * Extracts the project version from pom.xml content (not dependency/property versions)
26
+ * Why: Maven POMs require context-aware parsing to distinguish the project's own
27
+ * <version> tag from dependency versions, property references (${...}), or
28
+ * inherited versions inside <parent> blocks.
29
+ *
30
+ * Taxative rule: In a Maven POM, the project coordinates (<groupId>, <artifactId>,
31
+ * <version>, <packaging>) are direct children of <project> and must appear BEFORE
32
+ * any section-level element. After </parent>, the project's own <version> (if explicit)
33
+ * will be in this "header" region before any section element.
34
+ *
35
+ * @param {string} content - pom.xml file content
36
+ * @returns {{ version: string|null, inherited: boolean }}
37
+ * - version: The effective project version (explicit or from parent)
38
+ * - inherited: true if version comes from <parent> block (no explicit project <version>)
39
+ */
40
+ function extractPomProjectVersion(content) {
41
+ const hasParent = /<parent>[\s\S]*?<\/parent>/.test(content);
42
+
43
+ if (hasParent) {
44
+ // Section-level elements that mark the end of the project coordinates region.
45
+ // Any <version> tag inside these sections belongs to dependencies, plugins, etc.
46
+ const sectionTags = [
47
+ 'properties', 'dependencies', 'dependencyManagement',
48
+ 'build', 'profiles', 'modules', 'reporting',
49
+ 'distributionManagement', 'repositories', 'pluginRepositories',
50
+ '\\/project'
51
+ ].join('|');
52
+
53
+ // Extract the "header" region: between </parent> and the first section element
54
+ const headerRegex = new RegExp(
55
+ `<\\/parent>([\\s\\S]*?)(?=<(?:${sectionTags})\\b)`
56
+ );
57
+ const headerMatch = content.match(headerRegex);
58
+
59
+ if (headerMatch) {
60
+ const versionMatch = headerMatch[1].match(/<version>([^<]+)<\/version>/);
61
+ if (versionMatch) {
62
+ return { version: versionMatch[1].trim(), inherited: false };
63
+ }
64
+ }
65
+
66
+ // No explicit project <version> found — fall back to <parent><version>
67
+ const parentVersionRegex = /<parent>[\s\S]*?<version>([^<]+)<\/version>[\s\S]*?<\/parent>/;
68
+ const parentMatch = content.match(parentVersionRegex);
69
+ if (parentMatch) {
70
+ return { version: parentMatch[1].trim(), inherited: true };
71
+ }
72
+
73
+ return { version: null, inherited: false };
74
+ }
75
+
76
+ // No parent block — first <version> after <project> is the project version
77
+ const projectVersionRegex = /<project[^>]*>[\s\S]*?<version>([^<]+)<\/version>/;
78
+ const match = content.match(projectVersionRegex);
79
+ return { version: match ? match[1].trim() : null, inherited: false };
80
+ }
81
+
24
82
  /**
25
83
  * Registry of supported version file types
26
84
  * Why: Extensible system for multi-language version management
@@ -61,17 +119,8 @@ const VERSION_FILE_TYPES = {
61
119
  readVersion: (filePath) => {
62
120
  try {
63
121
  const content = fs.readFileSync(filePath, 'utf8');
64
- const hasParent = /<parent>[\s\S]*?<\/parent>/.test(content);
65
-
66
- if (hasParent) {
67
- const afterParentRegex = /<\/parent>[\s\S]*?<version>([^<]+)<\/version>/;
68
- const match = content.match(afterParentRegex);
69
- return match ? match[1].trim() : null;
70
- } else {
71
- const projectVersionRegex = /<project[^>]*>[\s\S]*?<version>([^<]+)<\/version>/;
72
- const match = content.match(projectVersionRegex);
73
- return match ? match[1].trim() : null;
74
- }
122
+ const { version } = extractPomProjectVersion(content);
123
+ return version;
75
124
  } catch (error) {
76
125
  logger.debug('version-manager - VERSION_FILE_TYPES', 'Failed to read pom.xml', {
77
126
  filePath,
@@ -82,15 +131,22 @@ const VERSION_FILE_TYPES = {
82
131
  },
83
132
  writeVersion: (filePath, newVersion) => {
84
133
  const content = fs.readFileSync(filePath, 'utf8');
85
- const hasParent = /<parent>[\s\S]*?<\/parent>/.test(content);
134
+ const { inherited } = extractPomProjectVersion(content);
86
135
 
87
136
  let newContent;
88
- if (hasParent) {
89
- const afterParentRegex = /(<\/parent>[\s\S]*?<version>)[^<]+(<\/version>)/;
90
- newContent = content.replace(afterParentRegex, `$1${newVersion}$2`);
137
+ if (inherited) {
138
+ // Version is inherited from parent — update <parent><version> tag
139
+ const parentRegex = /(<parent>[\s\S]*?<version>)[^<]+(<\/version>[\s\S]*?<\/parent>)/;
140
+ newContent = content.replace(parentRegex, `$1${newVersion}$2`);
91
141
  } else {
92
- const projectVersionRegex = /(<project[^>]*>[\s\S]*?<version>)[^<]+(<\/version>)/;
93
- newContent = content.replace(projectVersionRegex, `$1${newVersion}$2`);
142
+ const hasParent = /<parent>[\s\S]*?<\/parent>/.test(content);
143
+ if (hasParent) {
144
+ const afterParentRegex = /(<\/parent>[\s\S]*?<version>)[^<]+(<\/version>)/;
145
+ newContent = content.replace(afterParentRegex, `$1${newVersion}$2`);
146
+ } else {
147
+ const projectVersionRegex = /(<project[^>]*>[\s\S]*?<version>)[^<]+(<\/version>)/;
148
+ newContent = content.replace(projectVersionRegex, `$1${newVersion}$2`);
149
+ }
94
150
  }
95
151
 
96
152
  if (content === newContent) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-git-hooks",
3
- "version": "2.17.1",
3
+ "version": "2.17.2",
4
4
  "description": "Git hooks with Claude CLI for code analysis and automatic commit messages",
5
5
  "type": "module",
6
6
  "bin": {