Add support for sonatype nexus (#1017)

Close #783
This commit is contained in:
James Z.M. Gao
2017-09-28 08:48:51 +08:00
committed by Paul Melnikow
parent 6287c65104
commit e2ee910383
4 changed files with 181 additions and 0 deletions

4
.gitignore vendored
View File

@@ -16,6 +16,10 @@ Desktop.ini
._*
Thumbs.db
# eclipse
.project
.settings
# Files that might appear on external disks
.Spotlight-V100
.Trashes

View File

@@ -4626,6 +4626,103 @@ cache(function(data, match, sendBadge, request) {
});
}));
function isNexusSnapshotVersion(version) {
var pattern = /(\d+\.)*\d\-SNAPSHOT/;
if (version) {
return version.match(pattern);
} else {
return false;
}
}
// standalone sonatype nexus installation
// API pattern:
// /nexus/(r|s|<repo-name>)/(http|https)/<nexus.host>[:port][/<entry-path>]/<group>/<artifact>[:k1=v1[:k2=v2[...]]].<format>
// 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.
camp.route(/^\/nexus\/(r|s|[^\/]+)\/(https?)\/((?:[^\/]+)(?:\/[^\/]+)?)\/([^\/]+)\/([^\/:]+)(:.+)?\.(svg|png|gif|jpg|json)$/,
cache(function(data, match, sendBadge, request) {
var repo = match[1]; // r | s | repo-name
var scheme = match[2]; // http | https
var host = match[3]; // eg, `nexus.example.com`
var groupId = encodeURIComponent(match[4]); // eg, `com.google.inject`
var artifactId = encodeURIComponent(match[5]); // eg, `guice`
var queryOpt = (match[6] || '').replace(/:/g, '&'); // eg, `&p=pom&c=doc`
var format = match[7];
var badgeData = getBadgeData('nexus', data);
var apiUrl = scheme + '://' + host
+ ((repo == 'r' || repo == 's')
? ('/service/local/lucene/search?g=' + groupId + '&a=' + artifactId + queryOpt)
: ('/service/local/artifact/maven/resolve?r=' + repo + '&g=' + groupId + '&a=' + artifactId + '&v=LATEST' + queryOpt));
request(apiUrl, { headers: { 'Accept': 'application/json' } }, function(err, res, buffer) {
if (err != null) {
badgeData.text[1] = 'inaccessible';
sendBadge(format, badgeData);
return;
} else if (res && (res.statusCode === 404)) {
badgeData.text[1] = 'no-artifact';
sendBadge(format, badgeData);
return;
}
try {
var parsed = JSON.parse(buffer);
var version = '0';
switch (repo) {
case 'r':
if (parsed.data.length === 0) {
badgeData.text[1] = 'no-artifact';
sendBadge(format, badgeData);
return;
}
version = parsed.data[0].latestRelease;
break;
case 's':
if (parsed.data.length === 0) {
badgeData.text[1] = 'no-artifact';
sendBadge(format, badgeData);
return;
}
// 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
parsed.data.every(function(artifact) {
if (isNexusSnapshotVersion(artifact.latestSnapshot)) {
version = artifact.latestSnapshot;
return;
}
if (isNexusSnapshotVersion(artifact.version)) {
version = artifact.version;
return;
}
return true;
});
break;
default:
version = parsed.data.baseVersion || parsed.data.version;
break;
}
if (version === '0' || /SNAPSHOT/.test(version)) {
badgeData.colorscheme = 'orange';
if (version !== '0') {
badgeData.text[1] = version;
} else {
badgeData.text[1] = 'undefined';
}
} else {
badgeData.colorscheme = 'blue';
badgeData.text[1] = version;
}
sendBadge(format, badgeData);
} catch(e) {
badgeData.text[1] = 'invalid';
sendBadge(format, badgeData);
}
});
}));
// Bower version integration.
camp.route(/^\/bower\/v\/(.*)\.(svg|png|gif|jpg|json)$/,
cache((data, match, sendBadge, request) => {

72
service-tests/nexus.js Normal file
View File

@@ -0,0 +1,72 @@
'use strict';
const Joi = require('joi');
const ServiceTester = require('./runner/service-tester');
const t = new ServiceTester({ id: 'nexus', title: 'Nexus' });
module.exports = t;
t.create('search release version')
.get('/r/https/repository.jboss.org/nexus/jboss/jboss-client.json')
.expectJSONTypes(Joi.object().keys({
name: Joi.equal('nexus'),
value: Joi.string().regex(/^4(\.\d+)+$/)
}));
t.create('search release version of an inexistent artifact')
.get('/r/https/repository.jboss.org/nexus/jboss/inexistent-artifact-id.json')
.expectJSON({ name: 'nexus', value: 'no-artifact' });
t.create('search snapshot version')
.get('/s/https/repository.jboss.org/nexus/com.progress.fuse/fusehq.json')
.expectJSONTypes(Joi.object().keys({
name: Joi.equal('nexus'),
value: Joi.string().regex(/-SNAPSHOT$/)
}));
t.create('search snapshot version not in latestSnapshot')
.get('/s/https/repository.jboss.org/nexus/com.progress.fuse/fusehq.json')
.intercept(nock => nock('https://repository.jboss.org')
.get('/nexus/service/local/lucene/search')
.query({g: 'com.progress.fuse', a: 'fusehq'})
.reply(200, '{ "data": [ { "version": "7.0.1-SNAPSHOT" } ] }'))
.expectJSON({ name: 'nexus', value: '7.0.1-SNAPSHOT' });
t.create('search snapshot version of a release artifact')
.get('/s/https/repository.jboss.org/nexus/jboss/jboss-client.json')
.expectJSON({ name: 'nexus', value: 'undefined' });
t.create('search snapshot version of an inexistent artifact')
.get('/s/https/repository.jboss.org/nexus/jboss/inexistent-artifact-id.json')
.expectJSON({ name: 'nexus', value: 'no-artifact' });
t.create('resolve version')
.get('/developer/https/repository.jboss.org/nexus/ai.h2o/h2o-automl.json')
.expectJSONTypes(Joi.object().keys({
name: Joi.equal('nexus'),
value: Joi.string().regex(/^3(\.\d+)+$/)
}));
t.create('resolve version with query')
.get('/fs-public-snapshots/https/repository.jboss.org/nexus/com.progress.fuse/fusehq:c=agent-apple-osx:p=tar.gz.json')
.expectJSONTypes(Joi.object().keys({
name: Joi.equal('nexus'),
value: Joi.string().regex(/^7(\.\d+)+-SNAPSHOT$/)
}));
t.create('resolve version of an inexistent artifact')
.get('/developer/https/repository.jboss.org/nexus/jboss/inexistent-artifact-id.json')
.expectJSON({ name: 'nexus', value: 'no-artifact' });
t.create('connection error')
.get('/r/https/repository.jboss.org/nexus/jboss/jboss-client.json')
.networkOff()
.expectJSON({ name: 'nexus', value: 'inaccessible' });
t.create('json parsing error')
.get('/r/https/repository.jboss.org/nexus/jboss/jboss-client.json')
.intercept(nock => nock('https://repository.jboss.org')
.get('/nexus/service/local/lucene/search')
.query({g: 'jboss', a: 'jboss-client'})
.reply(200, "this should be a valid json"))
.expectJSON({ name: 'nexus', value: 'invalid' });

View File

@@ -598,6 +598,14 @@ Pixel-perfect &nbsp; Retina-ready &nbsp; Fast &nbsp; Consistent &nbsp; Hackable
<td><img src='/maven-central/v/org.apache.maven/apache-maven/2.svg' alt=''/></td>
<td><code>https://img.shields.io/maven-central/v/org.apache.maven/apache-maven/2.svg</code></td>
</tr>
<tr><th> Sonatype Nexus (Releases): </th>
<td><img src='/nexus/r/https/oss.sonatype.org/com.google.guava/guava.svg' alt=''/></td>
<td><code>https://img.shields.io/nexus/r/https/oss.sonatype.org/com.google.guava/guava.svg</code></td>
</tr>
<tr><th> Sonatype Nexus (Snapshots): </th>
<td><img src='/nexus/s/https/oss.sonatype.org/com.google.guava/guava.svg' alt=''/></td>
<td><code>https://img.shields.io/nexus/s/https/oss.sonatype.org/com.google.guava/guava.svg</code></td>
</tr>
<tr><th> WordPress plugin: </th>
<td><img src='/wordpress/plugin/v/akismet.svg' alt=''/></td>
<td><code>https://img.shields.io/wordpress/plugin/v/akismet.svg</code></td>