Skip to content

Commit

Permalink
feat(manager/maven): Add replacement support (#32635)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasrutishauser authored Jan 30, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 917ac1d commit 89b12fa
Showing 3 changed files with 193 additions and 13 deletions.
1 change: 0 additions & 1 deletion docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
@@ -3173,7 +3173,6 @@ Managers which do not support replacement:
- `gomod`
- `gradle`
- `homebrew`
- `maven`
- `regex`
- `sbt`

132 changes: 128 additions & 4 deletions lib/modules/manager/maven/update.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// TODO #22198
import { codeBlock } from 'common-tags';
import { XmlDocument } from 'xmldoc';
import { Fixtures } from '../../../../test/fixtures';
import { bumpPackageVersion, updateDependency } from './update';
@@ -10,12 +11,135 @@ const prereleaseContent = Fixtures.get(`prerelease.pom.xml`);

describe('modules/manager/maven/update', () => {
describe('updateDependency', () => {
it('should return null for replacement', () => {
it('should update version', () => {
const res = updateDependency({
fileContent: '',
upgrade: { updateType: 'replacement' },
fileContent: simpleContent,
upgrade: {
updateType: 'patch',
depName: 'org.example:foo',
currentValue: '0.0.1',
fileReplacePosition: 905,
newValue: '0.0.2',
},
});
expect(res).toBeNull();

const project = new XmlDocument(res!);
expect(
project.valueWithPath(
'dependencyManagement.dependencies.dependency.version',
),
).toBe('0.0.2');
});

it('should do simple replacement', () => {
const res = updateDependency({
fileContent: simpleContent,
upgrade: {
updateType: 'replacement',
depName: 'org.example:foo',
currentValue: '0.0.1',
fileReplacePosition: 905,
newName: 'org.example.new:foo',
newValue: '0.0.1',
},
});

const project = new XmlDocument(res!);
expect(
project.valueWithPath(
'dependencyManagement.dependencies.dependency.groupId',
),
).toBe('org.example.new');
});

it('should do full replacement', () => {
const res = updateDependency({
fileContent: simpleContent,
upgrade: {
updateType: 'replacement',
depName: 'org.example:foo',
currentValue: '0.0.1',
fileReplacePosition: 905,
newName: 'org.example.new:bar',
newValue: '0.0.2',
},
});

const project = new XmlDocument(res!);
expect(
project.valueWithPath(
'dependencyManagement.dependencies.dependency.groupId',
),
).toBe('org.example.new');
expect(
project.valueWithPath(
'dependencyManagement.dependencies.dependency.artifactId',
),
).toBe('bar');
expect(
project.valueWithPath(
'dependencyManagement.dependencies.dependency.version',
),
).toBe('0.0.2');
});

it('should do replacement if version is first', () => {
const res = updateDependency({
fileContent: codeBlock`
<project xmlns="http://maven.apache.org/POM/4.0.0">
<dependencyManagement>
<dependencies>
<dependency>
<version>0.0.1</version>
<artifactId>foo</artifactId>
<groupId>org.example</groupId>
</dependency>
</dependencies>
</dependencyManagement>
</project>
`,
upgrade: {
updateType: 'replacement',
depName: 'org.example:foo',
currentValue: '0.0.1',
fileReplacePosition: 132,
newName: 'org.example.new:bar',
newValue: '0.0.1',
},
});

const project = new XmlDocument(res!);
expect(
project.valueWithPath(
'dependencyManagement.dependencies.dependency.groupId',
),
).toBe('org.example.new');
expect(
project.valueWithPath(
'dependencyManagement.dependencies.dependency.artifactId',
),
).toBe('bar');
expect(
project.valueWithPath(
'dependencyManagement.dependencies.dependency.version',
),
).toBe('0.0.1');
});

it('should ignore replacement if name does not match', () => {
const res = updateDependency({
fileContent: simpleContent,
upgrade: {
updateType: 'replacement',
depName: 'org.example.old:bar',
currentValue: '0.0.1',
fileReplacePosition: 905,
newName: 'org.example:foo',
newValue: '0.0.1',
},
});

expect(res).toBe(simpleContent);
});
});

73 changes: 65 additions & 8 deletions lib/modules/manager/maven/update.ts
Original file line number Diff line number Diff line change
@@ -15,14 +15,54 @@ export function updateAtPosition(
upgrade: Upgrade,
endingAnchor: string,
): string | null {
const { depName, currentValue, newValue, fileReplacePosition } = upgrade;
const leftPart = fileContent.slice(0, fileReplacePosition);
const { depName, newName, currentValue, newValue, fileReplacePosition } =
upgrade;
let leftPart = fileContent.slice(0, fileReplacePosition);
const rightPart = fileContent.slice(fileReplacePosition);
const versionClosePosition = rightPart.indexOf(endingAnchor);
const restPart = rightPart.slice(versionClosePosition);
let restPart = rightPart.slice(versionClosePosition);
const versionPart = rightPart.slice(0, versionClosePosition);
const version = versionPart.trim();
if (version === newValue) {
if (newName) {
const blockStart = Math.max(
leftPart.lastIndexOf('<parent'),
leftPart.lastIndexOf('<dependency'),
leftPart.lastIndexOf('<plugin'),
leftPart.lastIndexOf('<extension'),
);
let leftBlock = leftPart.slice(blockStart);
const blockEnd = Math.min(
restPart.indexOf('</parent'),
restPart.indexOf('</dependency'),
restPart.indexOf('</plugin'),
restPart.indexOf('</extension'),
);
let rightBlock = restPart.slice(0, blockEnd);
const [groupId, artifactId] = depName!.split(':', 2);
const [newGroupId, newArtifactId] = newName.split(':', 2);
if (leftBlock.indexOf('<groupId') > 0) {
leftBlock = updateValue(leftBlock, 'groupId', groupId, newGroupId);
} else {
rightBlock = updateValue(rightBlock, 'groupId', groupId, newGroupId);
}
if (leftBlock.indexOf('<artifactId') > 0) {
leftBlock = updateValue(
leftBlock,
'artifactId',
artifactId,
newArtifactId,
);
} else {
rightBlock = updateValue(
rightBlock,
'artifactId',
artifactId,
newArtifactId,
);
}
leftPart = leftPart.slice(0, blockStart) + leftBlock;
restPart = rightBlock + restPart.slice(blockEnd);
} else if (version === newValue) {
return fileContent;
}
if (version === currentValue || upgrade.sharedVariableName) {
@@ -38,10 +78,6 @@ export function updateDependency({
fileContent,
upgrade,
}: UpdateDependencyConfig): string | null {
if (upgrade.updateType === 'replacement') {
logger.warn('maven manager does not support replacement updates yet');
return null;
}
const offset = fileContent.indexOf('<');
const spaces = fileContent.slice(0, offset);
const restContent = fileContent.slice(offset);
@@ -141,3 +177,24 @@ function isSnapshot(
const lastPart = prerelease?.at(-1);
return is.string(lastPart) && lastPart.endsWith('SNAPSHOT');
}

function updateValue(
content: string,
nodeName: string,
oldValue: string,
newValue: string,
): string {
const elementStart = content.indexOf('<' + nodeName);
const start = content.indexOf('>', elementStart) + 1;
const end = content.indexOf('</' + nodeName, start);
const elementContent = content.slice(start, end);
if (elementContent.trim() === oldValue) {
return (
content.slice(0, start) +
elementContent.replace(oldValue, newValue) +
content.slice(end)
);
}
logger.debug({ content, nodeName, oldValue, newValue }, 'Unknown value');
return content;
}

0 comments on commit 89b12fa

Please sign in to comment.