diff --git a/lib/modules/manager/maven/__fixtures__/minimum_snapshot.pom.xml b/lib/modules/manager/maven/__fixtures__/minimum_snapshot.pom.xml
new file mode 100644
index 00000000000000..37ffe02f8e3523
--- /dev/null
+++ b/lib/modules/manager/maven/__fixtures__/minimum_snapshot.pom.xml
@@ -0,0 +1,6 @@
+
+ 4.0.0
+ com.mycompany.app
+ my-app
+ 0.0.1-SNAPSHOT
+
diff --git a/lib/modules/manager/maven/extract.spec.ts b/lib/modules/manager/maven/extract.spec.ts
index 4c8fc2ab43077e..3ff8e84aaec9d0 100644
--- a/lib/modules/manager/maven/extract.spec.ts
+++ b/lib/modules/manager/maven/extract.spec.ts
@@ -243,6 +243,20 @@ describe('modules/manager/maven/extract', () => {
packageFileVersion: '1',
});
});
+
+ it('tries minimum snapshot manifests', () => {
+ const res = extractPackage(
+ Fixtures.get(`minimum_snapshot.pom.xml`),
+ 'some-file',
+ );
+ expect(res).toEqual({
+ datasource: 'maven',
+ deps: [],
+ mavenProps: {},
+ packageFile: 'some-file',
+ packageFileVersion: '0.0.1-SNAPSHOT',
+ });
+ });
});
describe('resolveParents', () => {
diff --git a/lib/modules/manager/maven/update.spec.ts b/lib/modules/manager/maven/update.spec.ts
index 5c8c6ab52b360d..a6f9a5717a361e 100644
--- a/lib/modules/manager/maven/update.spec.ts
+++ b/lib/modules/manager/maven/update.spec.ts
@@ -5,6 +5,7 @@ import { bumpPackageVersion, updateDependency } from './update';
const simpleContent = Fixtures.get(`simple.pom.xml`);
const minimumContent = Fixtures.get(`minimum.pom.xml`);
+const minimumSnapshotContent = Fixtures.get(`minimum_snapshot.pom.xml`);
const prereleaseContent = Fixtures.get(`prerelease.pom.xml`);
describe('modules/manager/maven/update', () => {
@@ -30,6 +31,53 @@ describe('modules/manager/maven/update', () => {
expect(project.valueWithPath('version')).toBe('0.0.2');
});
+ it('bumps pom.xml version keeping SNAPSHOT', () => {
+ const { bumpedContent } = bumpPackageVersion(
+ minimumSnapshotContent,
+ '0.0.1-SNAPSHOT',
+ 'patch',
+ );
+
+ const project = new XmlDocument(bumpedContent!);
+ expect(project.valueWithPath('version')).toBe('0.0.2-SNAPSHOT');
+ });
+
+ it('bumps pom.xml minor version keeping SNAPSHOT', () => {
+ const { bumpedContent } = bumpPackageVersion(
+ minimumSnapshotContent,
+ '0.0.1-SNAPSHOT',
+ 'minor',
+ );
+
+ const project = new XmlDocument(bumpedContent!);
+ expect(project.valueWithPath('version')).toBe('0.1.0-SNAPSHOT');
+ });
+
+ it('bumps pom.xml major version keeping SNAPSHOT', () => {
+ const { bumpedContent } = bumpPackageVersion(
+ minimumSnapshotContent,
+ '0.0.1-SNAPSHOT',
+ 'major',
+ );
+
+ const project = new XmlDocument(bumpedContent!);
+ expect(project.valueWithPath('version')).toBe('1.0.0-SNAPSHOT');
+ });
+
+ it('bumps pom.xml version keeping qualifier with -SNAPSHOT', () => {
+ const { bumpedContent } = bumpPackageVersion(
+ minimumSnapshotContent.replace(
+ '0.0.1-SNAPSHOT',
+ '0.0.1-qualified-SNAPSHOT',
+ ),
+ '0.0.1-qualified-SNAPSHOT',
+ 'patch',
+ );
+
+ const project = new XmlDocument(bumpedContent!);
+ expect(project.valueWithPath('version')).toBe('0.0.2-qualified-SNAPSHOT');
+ });
+
it('does not bump version twice', () => {
const { bumpedContent } = bumpPackageVersion(
simpleContent,
@@ -71,6 +119,17 @@ describe('modules/manager/maven/update', () => {
expect(bumpedContent).toEqual(simpleContent);
});
+ it('bumps pom.xml version to SNAPSHOT with prerelease', () => {
+ const { bumpedContent } = bumpPackageVersion(
+ simpleContent,
+ '0.0.1',
+ 'prerelease',
+ );
+
+ const project = new XmlDocument(bumpedContent!);
+ expect(project.valueWithPath('version')).toBe('0.0.2-SNAPSHOT');
+ });
+
it('bumps pom.xml version with prerelease semver level', () => {
const { bumpedContent } = bumpPackageVersion(
prereleaseContent,
diff --git a/lib/modules/manager/maven/update.ts b/lib/modules/manager/maven/update.ts
index 055d033cccb9ac..1d89f30f5c3ed7 100644
--- a/lib/modules/manager/maven/update.ts
+++ b/lib/modules/manager/maven/update.ts
@@ -1,3 +1,4 @@
+import is from '@sindresorhus/is';
import semver, { ReleaseType } from 'semver';
import { XmlDocument } from 'xmldoc';
import { logger } from '../../../logger';
@@ -78,7 +79,31 @@ export function bumpPackageVersion(
const startTagPosition = versionNode.startTagPosition;
const versionPosition = content.indexOf(versionNode.val, startTagPosition);
- const newPomVersion = semver.inc(currentValue, bumpVersion);
+ let newPomVersion: string | null = null;
+ const currentPrereleaseValue = semver.prerelease(currentValue);
+ if (isSnapshot(currentPrereleaseValue)) {
+ // It is already a SNAPSHOT version.
+ // Therefore the same qualifier (prerelease) will be used as before.
+ let releaseType = bumpVersion;
+ if (!bumpVersion.startsWith('pre')) {
+ releaseType = `pre${bumpVersion}` as ReleaseType;
+ }
+ newPomVersion = semver.inc(
+ currentValue,
+ releaseType,
+ currentPrereleaseValue!.join('.'),
+ false,
+ );
+ } else if (currentPrereleaseValue) {
+ // Some qualifier which is not a SNAPSHOT is present.
+ // The expected behaviour in this case is unclear and the standard increase will be used.
+ newPomVersion = semver.inc(currentValue, bumpVersion);
+ } else {
+ // A release version without any qualifier is present.
+ // Therefore the SNAPSHOT qualifier will be added if a prerelease is requested.
+ // This will do a normal increment, ignoring SNAPSHOT, if a non-prerelease bumpVersion is configured
+ newPomVersion = semver.inc(currentValue, bumpVersion, 'SNAPSHOT', false);
+ }
if (!newPomVersion) {
throw new Error('semver inc failed');
}
@@ -108,3 +133,10 @@ export function bumpPackageVersion(
}
return { bumpedContent };
}
+
+function isSnapshot(
+ prerelease: ReadonlyArray | null,
+): boolean {
+ const lastPart = prerelease?.at(-1);
+ return is.string(lastPart) && lastPart.endsWith('SNAPSHOT');
+}