Skip to content

Commit 81b4f98

Browse files
TimothyJonesclaude
andauthored
fix(maven): Preserve XML attributes when updating pom.xml files (#279)
* fix: preserve XML attributes when updating Maven pom.xml files The XMLParser and XMLBuilder from fast-xml-parser were instantiated without attribute-related options, causing all XML attributes to be silently stripped during version bumping. This corrupted pom.xml files that contained elements with attributes (e.g., plugin configurations). Configure the parser with ignoreAttributes: false, parseTagValue: false, and parseAttributeValue: false, and the builder with matching options to preserve attributes, prevent boolean shorthand, and handle self-closing tags correctly. Fixes #268 https://claude.ai/code/session_01MnZuTu64zEfCCP1edZDdo8 * refactor: inline XML options and add explanatory comments https://claude.ai/code/session_01MnZuTu64zEfCCP1edZDdo8 * refactor: remove unrelated suppressEmptyNode option https://claude.ai/code/session_01MnZuTu64zEfCCP1edZDdo8 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 29264ae commit 81b4f98

File tree

4 files changed

+104
-2
lines changed

4 files changed

+104
-2
lines changed

lib/updaters/types/maven.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ const CRLF = '\r\n';
55
const LF = '\n';
66

77
function pomDocument(contents) {
8-
const parser = new XMLParser();
8+
const parser = new XMLParser({
9+
// Preserve attributes on XML elements (fast-xml-parser strips them by default)
10+
ignoreAttributes: false,
11+
// Don't coerce element text to numbers/booleans (e.g. keep version "1.0" as a string)
12+
parseTagValue: false,
13+
// Don't coerce attribute values to numbers/booleans (e.g. keep port="8080" as a string)
14+
parseAttributeValue: false,
15+
});
916
return parser.parse(contents);
1017
}
1118

@@ -32,7 +39,13 @@ module.exports.writeVersion = function (contents, version) {
3239

3340
document.project.version = version;
3441

35-
const builder = new XMLBuilder({ format: true });
42+
const builder = new XMLBuilder({
43+
// Preserve attributes on XML elements (fast-xml-parser strips them by default)
44+
ignoreAttributes: false,
45+
// Write fork="true" instead of shorthand fork (which is invalid in XML)
46+
suppressBooleanAttributes: false,
47+
format: true,
48+
});
3649
const xml = builder.build(document);
3750

3851
if (newline === CRLF) {

test/core.spec.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,40 @@ describe('cli', function () {
14091409
expect(calledWithContentStr).toEqual(expected);
14101410
});
14111411

1412+
it('bumps version in Maven `pom.xml` file preserving XML attributes', async function () {
1413+
const expected = fs.readFileSync(
1414+
'./test/mocks/pom-6.4.0-attrs-lf.xml',
1415+
'utf-8',
1416+
);
1417+
const filename = 'pom.xml';
1418+
mock({
1419+
bump: 'minor',
1420+
realTestFiles: [
1421+
{
1422+
filename,
1423+
path: './test/mocks/pom-6.3.1-attrs-lf.xml',
1424+
},
1425+
],
1426+
});
1427+
await exec({
1428+
packageFiles: [{ filename, type: 'maven' }],
1429+
bumpFiles: [{ filename, type: 'maven' }],
1430+
});
1431+
1432+
// filePath is the first arg passed to writeFileSync
1433+
const packageJsonWriteFileSynchCall = findWriteFileCallForPath({
1434+
writeFileSyncSpy,
1435+
filename,
1436+
});
1437+
1438+
if (!packageJsonWriteFileSynchCall) {
1439+
throw new Error(`writeFileSynch not invoked with path ${filename}`);
1440+
}
1441+
1442+
const calledWithContentStr = packageJsonWriteFileSynchCall[1];
1443+
expect(calledWithContentStr).toEqual(expected);
1444+
});
1445+
14121446
it('bumps version in Gradle `build.gradle.kts` file', async function () {
14131447
const expected = fs.readFileSync(
14141448
'./test/mocks/build-6.4.0.gradle.kts',

test/mocks/pom-6.3.1-attrs-lf.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
<groupId>com.mycompany.app</groupId>
4+
<artifactId>my-module</artifactId>
5+
<version>6.3.1</version>
6+
<build>
7+
<plugins>
8+
<plugin>
9+
<groupId>org.apache.maven.plugins</groupId>
10+
<artifactId>maven-antrun-plugin</artifactId>
11+
<executions>
12+
<execution>
13+
<id>ktlint</id>
14+
<configuration>
15+
<target name="ktlint">
16+
<java taskname="ktlint" dir="${project.basedir}" fork="true" failonerror="true" classname="com.pinterest.ktlint.Main">
17+
<classpath refid="maven.plugin.classpath"/>
18+
<arg value="src/**/*.kt"/>
19+
</java>
20+
</target>
21+
</configuration>
22+
</execution>
23+
</executions>
24+
</plugin>
25+
</plugins>
26+
</build>
27+
</project>

test/mocks/pom-6.4.0-attrs-lf.xml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
<groupId>com.mycompany.app</groupId>
4+
<artifactId>my-module</artifactId>
5+
<version>6.4.0</version>
6+
<build>
7+
<plugins>
8+
<plugin>
9+
<groupId>org.apache.maven.plugins</groupId>
10+
<artifactId>maven-antrun-plugin</artifactId>
11+
<executions>
12+
<execution>
13+
<id>ktlint</id>
14+
<configuration>
15+
<target name="ktlint">
16+
<java taskname="ktlint" dir="${project.basedir}" fork="true" failonerror="true" classname="com.pinterest.ktlint.Main">
17+
<classpath refid="maven.plugin.classpath"></classpath>
18+
<arg value="src/**/*.kt"></arg>
19+
</java>
20+
</target>
21+
</configuration>
22+
</execution>
23+
</executions>
24+
</plugin>
25+
</plugins>
26+
</build>
27+
</project>
28+

0 commit comments

Comments
 (0)