Use url pattern for [nexus] + minor cleanup (#3326)
* Use url `pattern` for [nexus] * chore: minor nexus example tweaks * chore: fix prettier issue * refactor(Nexus): minor refactor to fix tests and examples * chore: increase timeout on nexus service tests * chore: prettified for prettier * tests(Nexus): increase timeout for recurringly slow test * chore: update nexus schema with docs
This commit is contained in:
committed by
Caleb Cartwright
parent
049057c230
commit
a291ba73a3
@@ -16,7 +16,12 @@ const searchApiSchema = Joi.object({
|
||||
Joi.object({
|
||||
latestRelease: optionalDottedVersionNClausesWithOptionalSuffix,
|
||||
latestSnapshot: optionalDottedVersionNClausesWithOptionalSuffix,
|
||||
version: optionalDottedVersionNClausesWithOptionalSuffix,
|
||||
// `version` will almost always follow the same pattern as optionalDottedVersionNClausesWithOptionalSuffix.
|
||||
// However, there are a couple exceptions where `version` may be a simple string (like `android-SNAPSHOT`)
|
||||
// This schema is relaxed accordingly since for snapshot/release badges the schema has to validate
|
||||
// the entire history of each published version for the artifact.
|
||||
// Example artifact that includes such a historical version: https://oss.sonatype.org/service/local/lucene/search?g=com.google.guava&a=guava
|
||||
version: Joi.string(),
|
||||
})
|
||||
)
|
||||
.required(),
|
||||
@@ -46,24 +51,23 @@ module.exports = class Nexus extends BaseJsonService {
|
||||
base: 'nexus',
|
||||
// API pattern:
|
||||
// /nexus/(r|s|<repo-name>)/(http|https)/<nexus.host>[:port][/<entry-path>]/<group>/<artifact>[:k1=v1[:k2=v2[...]]]
|
||||
format:
|
||||
'(r|s|[^/]+)/(https?)/((?:[^/]+)(?:/[^/]+)?)/([^/]+)/([^/:]+)(:.+)?',
|
||||
capture: ['repo', 'scheme', 'host', 'groupId', 'artifactId', 'queryOpt'],
|
||||
pattern:
|
||||
':repo(r|s|[^/]+)/:scheme(http|https)/:hostAndPath+/:groupId/:artifactId([^/:]+):queryOpt(:.+)?',
|
||||
}
|
||||
}
|
||||
|
||||
static get defaultBadgeData() {
|
||||
return { color: 'blue', label: 'nexus' }
|
||||
return { label: 'nexus' }
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Sonatype Nexus (Releases)',
|
||||
pattern: 'r/:scheme/:host/:groupId/:artifactId',
|
||||
pattern: 'r/:scheme(http|https)/:hostAndPath/:groupId/:artifactId',
|
||||
namedParams: {
|
||||
scheme: 'https',
|
||||
host: 'oss.sonatype.org',
|
||||
hostAndPath: 'oss.sonatype.org',
|
||||
groupId: 'com.google.guava',
|
||||
artifactId: 'guava',
|
||||
},
|
||||
@@ -73,10 +77,10 @@ module.exports = class Nexus extends BaseJsonService {
|
||||
},
|
||||
{
|
||||
title: 'Sonatype Nexus (Snapshots)',
|
||||
pattern: 's/:scheme/:host/:groupId/:artifactId',
|
||||
pattern: 's/:scheme(http|https)/:hostAndPath/:groupId/:artifactId',
|
||||
namedParams: {
|
||||
scheme: 'https',
|
||||
host: 'oss.sonatype.org',
|
||||
hostAndPath: 'oss.sonatype.org',
|
||||
groupId: 'com.google.guava',
|
||||
artifactId: 'guava',
|
||||
},
|
||||
@@ -86,11 +90,11 @@ module.exports = class Nexus extends BaseJsonService {
|
||||
},
|
||||
{
|
||||
title: 'Sonatype Nexus (Repository)',
|
||||
pattern: ':repo/:scheme/:host/:groupId/:artifactId',
|
||||
pattern: ':repo/:scheme(http|https)/:hostAndPath/:groupId/:artifactId',
|
||||
namedParams: {
|
||||
repo: 'developer',
|
||||
scheme: 'https',
|
||||
host: 'repository.jboss.org/nexus',
|
||||
hostAndPath: 'repository.jboss.org/nexus',
|
||||
groupId: 'ai.h2o',
|
||||
artifactId: 'h2o-automl',
|
||||
},
|
||||
@@ -100,11 +104,12 @@ module.exports = class Nexus extends BaseJsonService {
|
||||
},
|
||||
{
|
||||
title: 'Sonatype Nexus (Query Options)',
|
||||
pattern: ':repo/:scheme/:host/:groupId/:artifactId/:queryOpt',
|
||||
pattern:
|
||||
':repo/:scheme(http|https)/:hostAndPath/:groupId/:artifactId/:queryOpt',
|
||||
namedParams: {
|
||||
repo: 'fs-public-snapshots',
|
||||
scheme: 'https',
|
||||
host: 'repository.jboss.org/nexus',
|
||||
hostAndPath: 'repository.jboss.org/nexus',
|
||||
groupId: 'com.progress.fuse',
|
||||
artifactId: 'fusehq',
|
||||
queryOpt: ':c=agent-apple-osx:p=tar.gz',
|
||||
@@ -114,10 +119,10 @@ module.exports = class Nexus extends BaseJsonService {
|
||||
}),
|
||||
documentation: `
|
||||
<p>
|
||||
Note that you can use query options with any Nexus badge type (Releases, Snapshots, or Repository)
|
||||
Note that you can use query options with any Nexus badge type (Releases, Snapshots, or Repository).
|
||||
</p>
|
||||
<p>
|
||||
Query options should be provided as key=value pairs separated by a semicolon
|
||||
Query options should be provided as key=value pairs separated by a colon.
|
||||
</p>
|
||||
`,
|
||||
},
|
||||
@@ -125,8 +130,15 @@ module.exports = class Nexus extends BaseJsonService {
|
||||
}
|
||||
|
||||
transform({ repo, json }) {
|
||||
if (json.data.length === 0) {
|
||||
throw new NotFound({ prettyMessage: 'artifact or version not found' })
|
||||
}
|
||||
if (repo === 'r') {
|
||||
return { version: json.data[0].latestRelease }
|
||||
const version = json.data[0].latestRelease
|
||||
if (!version) {
|
||||
throw new InvalidResponse({ prettyMessage: 'invalid artifact version' })
|
||||
}
|
||||
return { version }
|
||||
} else if (repo === 's') {
|
||||
// only want to match 1.2.3-SNAPSHOT style versions, which may not always be in
|
||||
// 'latestSnapshot' so check 'version' as well before continuing to next entry
|
||||
@@ -140,32 +152,31 @@ module.exports = class Nexus extends BaseJsonService {
|
||||
}
|
||||
throw new InvalidResponse({ prettyMessage: 'no snapshot versions found' })
|
||||
} else {
|
||||
return { version: json.data.baseVersion || json.data.version }
|
||||
const version = json.data.baseVersion || json.data.version
|
||||
if (!version) {
|
||||
throw new InvalidResponse({ prettyMessage: 'invalid artifact version' })
|
||||
}
|
||||
return { version }
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ repo, scheme, host, groupId, artifactId, queryOpt }) {
|
||||
async handle({ repo, scheme, hostAndPath, groupId, artifactId, queryOpt }) {
|
||||
const { json } = await this.fetch({
|
||||
repo,
|
||||
scheme,
|
||||
host,
|
||||
hostAndPath,
|
||||
groupId,
|
||||
artifactId,
|
||||
queryOpt,
|
||||
})
|
||||
if (json.data.length === 0) {
|
||||
throw new NotFound({ prettyMessage: 'artifact or version not found' })
|
||||
}
|
||||
|
||||
const { version } = this.transform({ repo, json })
|
||||
if (!version) {
|
||||
throw new InvalidResponse({ prettyMessage: 'invalid artifact version' })
|
||||
}
|
||||
return this.constructor.render({ version })
|
||||
}
|
||||
|
||||
addQueryParamsToQueryString({ qs, queryOpt }) {
|
||||
// Users specify query options with 'key=value' pairs, using a
|
||||
// semicolon delimiter between pairs ([:k1=v1[:k2=v2[...]]]).
|
||||
// colon delimiter between pairs ([:k1=v1[:k2=v2[...]]]).
|
||||
// queryOpt will be a string containing those key/value pairs,
|
||||
// For example: :c=agent-apple-osx:p=tar.gz
|
||||
const keyValuePairs = queryOpt.split(':')
|
||||
@@ -177,13 +188,13 @@ module.exports = class Nexus extends BaseJsonService {
|
||||
})
|
||||
}
|
||||
|
||||
async fetch({ repo, scheme, host, groupId, artifactId, queryOpt }) {
|
||||
async fetch({ repo, scheme, hostAndPath, groupId, artifactId, queryOpt }) {
|
||||
const qs = {
|
||||
g: groupId,
|
||||
a: artifactId,
|
||||
}
|
||||
let schema
|
||||
let url = `${scheme}://${host}/`
|
||||
let url = `${scheme}://${hostAndPath}/`
|
||||
// API pattern:
|
||||
// for /nexus/[rs]/... pattern, use the search api of the nexus server, and
|
||||
// for /nexus/<repo-name>/... pattern, use the resolve api of the nexus server.
|
||||
|
||||
71
services/nexus/nexus.spec.js
Normal file
71
services/nexus/nexus.spec.js
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict'
|
||||
|
||||
const { expect } = require('chai')
|
||||
const { InvalidResponse, NotFound } = require('..')
|
||||
const Nexus = require('./nexus.service')
|
||||
|
||||
describe('Nexus', function() {
|
||||
context('transform()', function() {
|
||||
it('throws NotFound error when no versions exist', function() {
|
||||
try {
|
||||
Nexus.prototype.transform({ json: { data: [] } })
|
||||
expect.fail('Expected to throw')
|
||||
} catch (e) {
|
||||
expect(e).to.be.an.instanceof(NotFound)
|
||||
expect(e.prettyMessage).to.equal('artifact or version not found')
|
||||
}
|
||||
})
|
||||
|
||||
it('throws InvalidResponse error when no there is no latestRelease version', function() {
|
||||
try {
|
||||
Nexus.prototype.transform({ repo: 'r', json: { data: [{}] } })
|
||||
expect.fail('Expected to throw')
|
||||
} catch (e) {
|
||||
expect(e).to.be.an.instanceof(InvalidResponse)
|
||||
expect(e.prettyMessage).to.equal('invalid artifact version')
|
||||
}
|
||||
})
|
||||
|
||||
it('returns latestSnapshot value', function() {
|
||||
const latestSnapshot = '7.0.1-SNAPSHOT'
|
||||
const { version } = Nexus.prototype.transform({
|
||||
repo: 's',
|
||||
json: {
|
||||
data: [{ latestSnapshot }, { version: '1.2.3' }],
|
||||
},
|
||||
})
|
||||
expect(version).to.equal(latestSnapshot)
|
||||
})
|
||||
|
||||
it('returns version value when it is a snapshot', function() {
|
||||
const latestSnapshot = '1.2.7-SNAPSHOT'
|
||||
const { version } = Nexus.prototype.transform({
|
||||
repo: 's',
|
||||
json: {
|
||||
data: [{ latestSnapshot: '1.2.3' }, { version: latestSnapshot }],
|
||||
},
|
||||
})
|
||||
expect(version).to.equal(latestSnapshot)
|
||||
})
|
||||
|
||||
it('throws InvalidResponse error when no snapshot versions exist', function() {
|
||||
try {
|
||||
Nexus.prototype.transform({ repo: 's', json: { data: [{}] } })
|
||||
expect.fail('Expected to throw')
|
||||
} catch (e) {
|
||||
expect(e).to.be.an.instanceof(InvalidResponse)
|
||||
expect(e.prettyMessage).to.equal('no snapshot versions found')
|
||||
}
|
||||
})
|
||||
|
||||
it('throws InvalidResponse error when repository has no version data', function() {
|
||||
try {
|
||||
Nexus.prototype.transform({ repo: 'developer', json: { data: {} } })
|
||||
expect.fail('Expected to throw')
|
||||
} catch (e) {
|
||||
expect(e).to.be.an.instanceof(InvalidResponse)
|
||||
expect(e.prettyMessage).to.equal('invalid artifact version')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -18,32 +18,36 @@ function mockNexusCreds() {
|
||||
}
|
||||
|
||||
t.create('live: search release version valid artifact')
|
||||
.get('/r/https/repository.jboss.org/nexus/jboss/jboss-client.json')
|
||||
.timeout(15000)
|
||||
.get('/r/https/oss.sonatype.org/com.google.guava/guava.json')
|
||||
.expectBadge({
|
||||
label: 'nexus',
|
||||
message: isVersion,
|
||||
})
|
||||
|
||||
t.create('live: search release version of an inexistent artifact')
|
||||
.get('/r/https/repository.jboss.org/nexus/jboss/inexistent-artifact-id.json')
|
||||
t.create('live: search release version of an nonexistent artifact')
|
||||
.timeout(10000)
|
||||
.get(
|
||||
'/r/https/oss.sonatype.org/com.google.guava/nonexistent-artifact-id.json'
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'nexus',
|
||||
message: 'artifact or version not found',
|
||||
})
|
||||
|
||||
t.create('live: search snapshot version valid snapshot artifact')
|
||||
.get('/s/https/repository.jboss.org/nexus/com.progress.fuse/fusehq.json')
|
||||
.timeout(10000)
|
||||
.get('/s/https/oss.sonatype.org/com.google.guava/guava.json')
|
||||
.expectBadge({
|
||||
label: 'nexus',
|
||||
message: isVersion,
|
||||
})
|
||||
|
||||
t.create('live: search snapshot version of a release artifact')
|
||||
.get('/s/https/repository.jboss.org/nexus/jboss/jboss-client.json')
|
||||
.expectBadge({ label: 'nexus', message: 'no snapshot versions found' })
|
||||
|
||||
t.create('live: search snapshot version of an inexistent artifact')
|
||||
.get('/s/https/repository.jboss.org/nexus/jboss/inexistent-artifact-id.json')
|
||||
t.create('live: search snapshot version of an nonexistent artifact')
|
||||
.timeout(10000)
|
||||
.get(
|
||||
'/s/https/oss.sonatype.org/com.google.guava/nonexistent-artifact-id.json'
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'nexus',
|
||||
message: 'artifact or version not found',
|
||||
@@ -66,9 +70,9 @@ t.create('live: repository version with query')
|
||||
message: isVersion,
|
||||
})
|
||||
|
||||
t.create('live: repository version of an inexistent artifact')
|
||||
t.create('live: repository version of an nonexistent artifact')
|
||||
.get(
|
||||
'/developer/https/repository.jboss.org/nexus/jboss/inexistent-artifact-id.json'
|
||||
'/developer/https/repository.jboss.org/nexus/jboss/nonexistent-artifact-id.json'
|
||||
)
|
||||
.expectBadge({
|
||||
label: 'nexus',
|
||||
|
||||
Reference in New Issue
Block a user