Skip to content

Commit d28456d

Browse files
committed
feat: add gradle plugin
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
1 parent 505c0dc commit d28456d

4 files changed

Lines changed: 37 additions & 5 deletions

File tree

services/apps/packages_worker/src/maven/__tests__/registry.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { describe, expect, it } from 'vitest'
22

33
import {
4+
GRADLE_PLUGIN_PORTAL_BASE_URL,
45
MAVEN_CENTRAL_BASE_URL,
56
resolveRegistryBaseUrl,
67
resolveRegistryPageUrl,
@@ -225,4 +226,14 @@ describe('resolveRegistryPageUrlFromBase', () => {
225226
resolveRegistryPageUrlFromBase('com.google.firebase', 'firebase-analytics', googleMavenUrl),
226227
).toBe('https://maven.google.com/web/index.html#com.google.firebase:firebase-analytics')
227228
})
229+
230+
it('returns Gradle Plugin Portal path when resolvedBaseUrl is Gradle Plugin Portal', () => {
231+
expect(
232+
resolveRegistryPageUrlFromBase(
233+
'io.github.trueangle',
234+
'gradle-plugin',
235+
GRADLE_PLUGIN_PORTAL_BASE_URL,
236+
),
237+
).toBe('https://plugins.gradle.org/m2/io/github/trueangle/gradle-plugin/')
238+
})
228239
})

services/apps/packages_worker/src/maven/metadata.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,12 @@ export async function resolveVersionsList(
111111
} catch (err) {
112112
if (axios.isAxiosError(err)) {
113113
const status = err.response?.status
114-
// 404 = standard not-found. 401 = JitPack's response for packages that
115-
// don't exist as public builds (JitPack uses 401 instead of 404 here).
116-
if (status === 404 || status === 401) return { kind: 'NOT_FOUND' }
114+
// 404 = standard not-found. 401 = JitPack-specific: returned for packages
115+
// that don't exist as public builds. Scoped to JitPack only — other
116+
// registries may return 401 for auth failures, which should not be
117+
// silently treated as a missing package.
118+
if (status === 404 || (status === 401 && url.includes('jitpack.io')))
119+
return { kind: 'NOT_FOUND' }
117120
// 429 = explicit rate limit, 403 = CDN throttle (Maven Central uses both)
118121
if ((status === 429 || status === 403) && attempt < MAX_RETRIES) {
119122
const delay = RETRY_BASE_MS * 2 ** attempt + Math.random() * 500

services/apps/packages_worker/src/maven/registry.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313

1414
export const MAVEN_CENTRAL_BASE_URL = 'https://repo1.maven.org/maven2'
15+
export const GRADLE_PLUGIN_PORTAL_BASE_URL = 'https://plugins.gradle.org/m2'
1516

1617
interface RegistryEntry {
1718
prefix: string
@@ -96,8 +97,8 @@ const ALTERNATIVE_REGISTRIES: RegistryEntry[] = [
9697
},
9798
{
9899
prefix: 'gradle.plugin',
99-
baseUrl: 'https://plugins.gradle.org/m2',
100-
pageUrl: (g, a) => `https://plugins.gradle.org/m2/${g.replace(/\./g, '/')}/${a}/`,
100+
baseUrl: GRADLE_PLUGIN_PORTAL_BASE_URL,
101+
pageUrl: (g, a) => `${GRADLE_PLUGIN_PORTAL_BASE_URL}/${g.replace(/\./g, '/')}/${a}/`,
101102
},
102103
// JitPack builds and serves artifacts directly from GitHub/GitLab/Bitbucket source repos.
103104
// The io.github.<username> and com.github.<username> groupId conventions are JitPack-specific
@@ -207,5 +208,8 @@ export function resolveRegistryPageUrlFromBase(
207208
if (isCentral) {
208209
return `https://central.sonatype.com/artifact/${groupId}/${artifactId}`
209210
}
211+
if (resolvedBaseUrl === GRADLE_PLUGIN_PORTAL_BASE_URL) {
212+
return `${GRADLE_PLUGIN_PORTAL_BASE_URL}/${groupId.replace(/\./g, '/')}/${artifactId}/`
213+
}
210214
return resolveRegistryPageUrl(groupId, artifactId)
211215
}

services/apps/packages_worker/src/maven/runMavenEnrichmentLoop.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { extractArtifact, getPomCacheStats, normalizeScmUrl } from './extract'
1919
import { isMavenFetchError, resolveVersionsList } from './metadata'
2020
import { isPrerelease, parseRepoUrl } from './normalize'
2121
import {
22+
GRADLE_PLUGIN_PORTAL_BASE_URL,
2223
MAVEN_CENTRAL_BASE_URL,
2324
isAlternativeRegistry,
2425
resolveRegistryBaseUrl,
@@ -141,6 +142,19 @@ async function processCriticalPackage(qx: QueryExecutor, pkg: PackageRow, forceF
141142
}
142143
}
143144

145+
// Third fallback: Gradle Plugin Portal. Plugins can be published under any groupId
146+
// (not just gradle.plugin.*), so this is worth trying for all NOT_FOUND packages.
147+
// Skip when GPP is already the primary registry (gradle.plugin.*) to avoid a
148+
// redundant second call to the same URL.
149+
if (isMavenFetchError(metadata) && metadata.kind === 'NOT_FOUND' && baseUrl !== GRADLE_PLUGIN_PORTAL_BASE_URL) {
150+
const gradlePortalMetadata = await resolveVersionsList(groupId, artifactId, GRADLE_PLUGIN_PORTAL_BASE_URL)
151+
if (!isMavenFetchError(gradlePortalMetadata)) {
152+
log.info({ groupId, artifactId }, 'Not found in primary/Central — resolved via Gradle Plugin Portal fallback')
153+
baseUrl = GRADLE_PLUGIN_PORTAL_BASE_URL
154+
metadata = gradlePortalMetadata
155+
}
156+
}
157+
144158
if (isMavenFetchError(metadata)) {
145159
if (metadata.kind === 'NOT_FOUND') {
146160
await upsertPackage(qx, {

0 commit comments

Comments
 (0)