Skip to content

Commit b057cbd

Browse files
wenytang-msCopilot
andcommitted
fix: use maven-metadata.xml to look up the latest test framework version
The previous implementation queried search.maven.org's Solr endpoint and returned the `latestVersion` field. That index has been frozen since around May 2025 (a side effect of the Sonatype migration to central.sonatype.com), so the endpoint now serves stale data. For example, the latest version it reports for `junit-platform-console-standalone` is `1.13.0-M3` (a JUnit 5 milestone), while the actual current stable on Maven Central is `6.1.0`. As a result, `Enable Java Tests` ends up downloading either that milestone or, after falling back, the hard-coded `1.9.3`. Switch the lookup to the artifact's own `maven-metadata.xml` on repo1.maven.org, which is the authoritative metadata maintained alongside the artifact: * Prefer the `<release>` tag (Maven's pointer to the latest non-snapshot version). * Fall back to scanning `<version>` entries from newest to oldest for the first stable build. * Pre-release qualifiers (`-M*`, `-RC*`, `-beta`, `-SNAPSHOT`, etc.) are rejected via `isStableVersion`. Also bump the JUnit Jupiter `defaultVersion` from `1.9.3` to `6.1.0` so the offline fallback matches a currently published stable. Related to #1866 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 46c7835 commit b057cbd

1 file changed

Lines changed: 33 additions & 11 deletions

File tree

src/commands/testDependenciesCommands.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ function getJarIds(testKind: TestKind): IArtifactMetadata[] {
138138
return [{
139139
groupId: 'org.junit.platform',
140140
artifactId: 'junit-platform-console-standalone',
141-
defaultVersion: '1.9.3',
141+
defaultVersion: '6.1.0',
142142
}];
143143
case TestKind.JUnit:
144144
return [{
@@ -172,20 +172,43 @@ function getJarIds(testKind: TestKind): IArtifactMetadata[] {
172172

173173
async function getLatestVersion(groupId: string, artifactId: string): Promise<string | undefined> {
174174
try {
175-
const response: any = await getHttpsAsJSON(getQueryLink(groupId, artifactId));
175+
const xml: string = await getHttpsAsText(getMetadataLink(groupId, artifactId));
176176

177-
if (!response.response?.docs?.[0]?.latestVersion) {
178-
sendError(new Error('Invalid format for the latest version response'));
179-
return undefined;
177+
// Prefer the <release> tag (Maven's authoritative pointer to the latest non-snapshot version).
178+
const releaseMatch: RegExpMatchArray | null = xml.match(/<release>([^<]+)<\/release>/);
179+
if (releaseMatch && isStableVersion(releaseMatch[1])) {
180+
return releaseMatch[1];
180181
}
181-
return response.response.docs[0].latestVersion;
182+
183+
// Fallback: scan <version> entries (chronologically ordered) for the newest stable version,
184+
// in case <release> is missing or points to a milestone / RC.
185+
const versionRegex: RegExp = /<version>([^<]+)<\/version>/g;
186+
const versions: string[] = [];
187+
let match: RegExpExecArray | null;
188+
while ((match = versionRegex.exec(xml)) !== null) {
189+
versions.push(match[1]);
190+
}
191+
for (let i: number = versions.length - 1; i >= 0; i--) {
192+
if (isStableVersion(versions[i])) {
193+
return versions[i];
194+
}
195+
}
196+
197+
sendError(new Error(`No stable version found in maven-metadata.xml for ${groupId}:${artifactId}`));
182198
} catch (e) {
183199
sendError(new Error(`Failed to fetch the latest version for ${groupId}:${artifactId}`));
184200
}
185201

186202
return undefined;
187203
}
188204

205+
function isStableVersion(version: string): boolean {
206+
// A stable Maven version is composed solely of dot-separated numeric segments
207+
// (e.g. 6.1.0, 4.13.2). Anything with a qualifier such as -M3, -RC1, -beta-1
208+
// or -SNAPSHOT is treated as a pre-release.
209+
return /^\d+(\.\d+)*$/.test(version);
210+
}
211+
189212
async function downloadJar(
190213
libFolder: string,
191214
groupId: string,
@@ -274,9 +297,9 @@ async function updateProjectSettings(projectUri: Uri, libFolder: string): Promis
274297
window.showInformationMessage(`Test libraries have been downloaded into '${relativePath}/'.`);
275298
}
276299

277-
async function getHttpsAsJSON(link: string): Promise<any> {
300+
async function getHttpsAsText(link: string): Promise<string> {
278301
// eslint-disable-next-line @typescript-eslint/typedef
279-
const response: string = await new Promise<string>((resolve, reject) => {
302+
return new Promise<string>((resolve, reject) => {
280303
let result: string = '';
281304
https.get(link, {
282305
headers: {
@@ -295,7 +318,6 @@ async function getHttpsAsJSON(link: string): Promise<any> {
295318
res.on('error', reject);
296319
});
297320
});
298-
return JSON.parse(response);
299321
}
300322

301323
async function getTotalBytes(url: string): Promise<number> {
@@ -315,8 +337,8 @@ async function getTotalBytes(url: string): Promise<number> {
315337
});
316338
}
317339

318-
function getQueryLink(groupId: string, artifactId: string): string {
319-
return `https://search.maven.org/solrsearch/select?q=id:%22${groupId}:${artifactId}%22&rows=1&wt=json`;
340+
function getMetadataLink(groupId: string, artifactId: string): string {
341+
return `https://repo1.maven.org/maven2/${groupId.split('.').join('/')}/${artifactId}/maven-metadata.xml`;
320342
}
321343

322344
function getDownloadLink(groupId: string, artifactId: string, version: string): string {

0 commit comments

Comments
 (0)