This commit is contained in:
Jonas Rutishauser 2025-01-02 18:34:12 +01:00 committed by GitHub
commit fe6b90c108
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 193 additions and 13 deletions

View file

@ -3173,7 +3173,6 @@ Managers which do not support replacement:
- `gomod`
- `gradle`
- `homebrew`
- `maven`
- `regex`
- `sbt`

View file

@ -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);
});
});

View file

@ -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.groupName) {
@ -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.slice(elementStart).indexOf('>') + elementStart + 1;
const end = content.slice(start).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;
}