ci: Run npm registry in Docker
This commit is contained in:
parent
0c67ba517f
commit
40c58c9b42
4
.gitignore
vendored
4
.gitignore
vendored
@ -129,7 +129,3 @@ $RECYCLE.BIN/
|
|||||||
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
|
||||||
# Registry tests
|
|
||||||
test/helpers/registry/couch
|
|
||||||
test/helpers/registry/data
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
services:
|
services:
|
||||||
- couchdb
|
|
||||||
- docker
|
- docker
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
node_js:
|
node_js:
|
||||||
|
- 9
|
||||||
- 8
|
- 8
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
|
||||||
# Trigger a push build on caribou and greenkeeper branches + PRs build on every branches
|
# Trigger a push build on caribou and greenkeeper branches + PRs build on every branches
|
||||||
# Avoid double build on PRs (See https://github.com/travis-ci/travis-ci/issues/1147)
|
# Avoid double build on PRs (See https://github.com/travis-ci/travis-ci/issues/1147)
|
||||||
|
@ -46,11 +46,12 @@
|
|||||||
"eslint-plugin-prettier": "^2.3.0",
|
"eslint-plugin-prettier": "^2.3.0",
|
||||||
"file-url": "^2.0.2",
|
"file-url": "^2.0.2",
|
||||||
"fs-extra": "^4.0.2",
|
"fs-extra": "^4.0.2",
|
||||||
|
"got": "^8.0.0",
|
||||||
"js-yaml": "^3.10.0",
|
"js-yaml": "^3.10.0",
|
||||||
"mockserver-client": "^2.0.0",
|
"mockserver-client": "^2.0.0",
|
||||||
"nock": "^9.0.2",
|
"nock": "^9.0.2",
|
||||||
"npm-registry-couchapp": "^2.6.12",
|
|
||||||
"nyc": "^11.2.1",
|
"nyc": "^11.2.1",
|
||||||
|
"p-retry": "^1.0.0",
|
||||||
"prettier": "~1.8.0",
|
"prettier": "~1.8.0",
|
||||||
"proxyquire": "^1.8.0",
|
"proxyquire": "^1.8.0",
|
||||||
"sinon": "^4.0.0",
|
"sinon": "^4.0.0",
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import Docker from 'dockerode';
|
import Docker from 'dockerode';
|
||||||
import getStream from 'get-stream';
|
import getStream from 'get-stream';
|
||||||
|
import got from 'got';
|
||||||
|
import pRetry from 'p-retry';
|
||||||
import {mockServerClient} from 'mockserver-client';
|
import {mockServerClient} from 'mockserver-client';
|
||||||
|
|
||||||
const MOCK_SERVER_PORT = 1080;
|
const MOCK_SERVER_PORT = 1080;
|
||||||
@ -7,6 +9,14 @@ const MOCK_SERVER_HOST = 'localhost';
|
|||||||
const docker = new Docker();
|
const docker = new Docker();
|
||||||
let container;
|
let container;
|
||||||
|
|
||||||
|
async function checkStatus() {
|
||||||
|
const response = await got.put(`http://${MOCK_SERVER_HOST}:${MOCK_SERVER_PORT}/status`, {cache: false});
|
||||||
|
if (response.status === 200) {
|
||||||
|
// If the registry returns a 200 status, it's ready. Abort the retry.
|
||||||
|
throw new pRetry.AbortError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download the `mockserver` Docker image, create a new container and start it.
|
* Download the `mockserver` Docker image, create a new container and start it.
|
||||||
*
|
*
|
||||||
@ -19,7 +29,14 @@ async function start() {
|
|||||||
Image: 'jamesdbloom/mockserver',
|
Image: 'jamesdbloom/mockserver',
|
||||||
PortBindings: {[`${MOCK_SERVER_PORT}/tcp`]: [{HostPort: `${MOCK_SERVER_PORT}`}]},
|
PortBindings: {[`${MOCK_SERVER_PORT}/tcp`]: [{HostPort: `${MOCK_SERVER_PORT}`}]},
|
||||||
});
|
});
|
||||||
return container.start();
|
await container.start();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Wait for the mock server to be ready
|
||||||
|
await pRetry(checkStatus, {retries: 5, minTimeout: 1000, factor: 2});
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`Couldn't start mock-server after 30s`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
69
test/helpers/npm-registry.js
Normal file
69
test/helpers/npm-registry.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import Docker from 'dockerode';
|
||||||
|
import getStream from 'get-stream';
|
||||||
|
import got from 'got';
|
||||||
|
import pRetry from 'p-retry';
|
||||||
|
|
||||||
|
const SERVER_PORT = 15986;
|
||||||
|
const COUCHDB_PORT = 5984;
|
||||||
|
const SERVER_HOST = 'localhost';
|
||||||
|
const NPM_USERNAME = 'integration';
|
||||||
|
const NPM_PASSWORD = 'suchsecure';
|
||||||
|
const NPM_EMAIL = 'integration@test.com';
|
||||||
|
const docker = new Docker();
|
||||||
|
let container;
|
||||||
|
|
||||||
|
async function checkStatus() {
|
||||||
|
const response = await got(`http://${SERVER_HOST}:${SERVER_PORT}/registry/_design/app`, {cache: false});
|
||||||
|
if (response.status === 200) {
|
||||||
|
// If the registry returns a 200 status, it's ready. Abort the retry.
|
||||||
|
throw new pRetry.AbortError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function start() {
|
||||||
|
await getStream(await docker.pull('npmjs/npm-docker-couchdb:1.6.1'));
|
||||||
|
|
||||||
|
container = await docker.createContainer({
|
||||||
|
Image: 'npmjs/npm-docker-couchdb:1.6.1',
|
||||||
|
PortBindings: {[`${COUCHDB_PORT}/tcp`]: [{HostPort: `${SERVER_PORT}`}]},
|
||||||
|
});
|
||||||
|
|
||||||
|
await container.start();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Wait for the registry to be ready
|
||||||
|
await pRetry(checkStatus, {retries: 5, minTimeout: 1000, factor: 2});
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`Couldn't start npm-docker-couchdb after 30s`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create user
|
||||||
|
await got(`http://${SERVER_HOST}:${SERVER_PORT}/_users/org.couchdb.user:${NPM_USERNAME}`, {
|
||||||
|
json: true,
|
||||||
|
auth: 'admin:admin',
|
||||||
|
method: 'PUT',
|
||||||
|
body: {
|
||||||
|
_id: `org.couchdb.user:${NPM_USERNAME}`,
|
||||||
|
name: NPM_USERNAME,
|
||||||
|
roles: [],
|
||||||
|
type: 'user',
|
||||||
|
password: NPM_PASSWORD,
|
||||||
|
email: NPM_EMAIL,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `http://${SERVER_HOST}:${SERVER_PORT}/registry/_design/app/_rewrite/`;
|
||||||
|
|
||||||
|
const authEnv = {
|
||||||
|
npm_config_registry: url, // eslint-disable-line camelcase
|
||||||
|
NPM_USERNAME,
|
||||||
|
NPM_PASSWORD,
|
||||||
|
NPM_EMAIL,
|
||||||
|
};
|
||||||
|
|
||||||
|
async function stop() {
|
||||||
|
return container.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {start, stop, authEnv, url};
|
@ -1,14 +0,0 @@
|
|||||||
import execa from 'execa';
|
|
||||||
|
|
||||||
const opts = {cwd: __dirname};
|
|
||||||
const uri = 'http://localhost:' + (process.env.TRAVIS === 'true' ? 5984 : 15986) + '/registry/_design/app/_rewrite/';
|
|
||||||
|
|
||||||
function start() {
|
|
||||||
return execa('./start.sh', opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
function stop() {
|
|
||||||
return execa('./stop.sh', opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {start, stop, uri};
|
|
@ -1,20 +0,0 @@
|
|||||||
[couchdb]
|
|
||||||
database_dir = data
|
|
||||||
view_index_dir = data
|
|
||||||
delayed_commits = false
|
|
||||||
uuid = bf4ecd84a7c89d60b5b2540fdf8c322c
|
|
||||||
|
|
||||||
[couch_httpd_auth]
|
|
||||||
public_fields = appdotnet, avatar, avatarMedium, avatarLarge, date, email, fields, freenode, fullname, github, homepage, name, roles, twitter, type, _id, _rev
|
|
||||||
users_db_public = true
|
|
||||||
|
|
||||||
[httpd]
|
|
||||||
port = 15986
|
|
||||||
bind_address = 127.0.0.1
|
|
||||||
secure_rewrites = false
|
|
||||||
|
|
||||||
[log]
|
|
||||||
file = couch/couch.log
|
|
||||||
|
|
||||||
[admins]
|
|
||||||
admin = -pbkdf2-89582b49cd2e8443e29a841f5a76d367956a8e58,1afa2f1531a17ac97f2ac9e334293753,10
|
|
@ -1,41 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# exit if an error occurs
|
|
||||||
set -e
|
|
||||||
|
|
||||||
cd $(dirname $0)
|
|
||||||
|
|
||||||
mkdir -p couch
|
|
||||||
|
|
||||||
if [[ $TRAVIS = true ]]
|
|
||||||
then
|
|
||||||
COUCH=http://admin:password@127.0.0.1:5984
|
|
||||||
|
|
||||||
curl -X PUT http://127.0.0.1:5984/_config/admins/admin -d '"password"'
|
|
||||||
|
|
||||||
curl -X PUT $COUCH/_config/couchdb/delayed_commits -d '"false"'
|
|
||||||
curl -X PUT $COUCH/_config/couch_httpd_auth/users_db_public -d '"true"'
|
|
||||||
curl -X PUT $COUCH/_config/couch_httpd_auth/public_fields -d '"appdotnet, avatar, avatarMedium, avatarLarge, date, email, fields, freenode, fullname, github, homepage, name, roles, twitter, type, _id, _rev"'
|
|
||||||
curl -X PUT $COUCH/_config/httpd/secure_rewrites -d '"false"'
|
|
||||||
|
|
||||||
else
|
|
||||||
COUCH=http://admin:password@127.0.0.1:15986
|
|
||||||
couchdb -b -a local.ini -p couch/pid -o couch/stdout.log -e couch/stderr.log
|
|
||||||
# wait for couch to start
|
|
||||||
sleep 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# create "registry" database
|
|
||||||
curl -X PUT $COUCH/registry
|
|
||||||
|
|
||||||
# create sample npm user
|
|
||||||
curl -X PUT $COUCH/_users/org.couchdb.user:integration -H Content-Type:application/json --data-binary '{"_id": "org.couchdb.user:integration", "name": "integration", "roles": [], "type": "user", "password": "suchsecure", "email": "integration@test.com"}'
|
|
||||||
|
|
||||||
# npm-registry-couchpp needs this variable set to run
|
|
||||||
export DEPLOY_VERSION=nope
|
|
||||||
|
|
||||||
# setup npm-registry-couchapp
|
|
||||||
npm explore npm-registry-couchapp -- npm start --npm-registry-couchapp:couch=$COUCH/registry
|
|
||||||
npm explore npm-registry-couchapp -- npm run load --npm-registry-couchapp:couch=$COUCH/registry
|
|
||||||
export NO_PROMPT=yes
|
|
||||||
npm explore npm-registry-couchapp -- npm run copy --npm-registry-couchapp:couch=$COUCH/registry
|
|
@ -1,13 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# close couchdb background process
|
|
||||||
couchdb -d
|
|
||||||
|
|
||||||
# delete data and logs
|
|
||||||
cd $(dirname $0)
|
|
||||||
|
|
||||||
cat couch/{couch,stdout,stderr}.log
|
|
||||||
|
|
||||||
cat couch/pid | xargs kill
|
|
||||||
rm -rf couch
|
|
||||||
rm -rf data
|
|
@ -3,15 +3,15 @@ import {writeJson, readJson} from 'fs-extra';
|
|||||||
import {stub} from 'sinon';
|
import {stub} from 'sinon';
|
||||||
import execa from 'execa';
|
import execa from 'execa';
|
||||||
import {gitRepo, gitCommits, gitHead, gitTagVersion, gitPackRefs, gitAmmendCommit} from './helpers/git-utils';
|
import {gitRepo, gitCommits, gitHead, gitTagVersion, gitPackRefs, gitAmmendCommit} from './helpers/git-utils';
|
||||||
import registry from './helpers/registry';
|
|
||||||
import mockServer from './helpers/mockserver';
|
import mockServer from './helpers/mockserver';
|
||||||
|
import npmRegistry from './helpers/npm-registry';
|
||||||
import semanticRelease from '..';
|
import semanticRelease from '..';
|
||||||
|
|
||||||
/* eslint camelcase: ["error", {properties: "never"}] */
|
/* eslint camelcase: ["error", {properties: "never"}] */
|
||||||
|
|
||||||
// Environment variables used with cli
|
// Environment variables used with cli
|
||||||
const env = {
|
const env = {
|
||||||
npm_config_registry: registry.uri,
|
npm_config_registry: npmRegistry.url,
|
||||||
GH_TOKEN: 'github_token',
|
GH_TOKEN: 'github_token',
|
||||||
GITHUB_URL: mockServer.url,
|
GITHUB_URL: mockServer.url,
|
||||||
NPM_EMAIL: 'integration@test.com',
|
NPM_EMAIL: 'integration@test.com',
|
||||||
@ -23,10 +23,10 @@ const pluginError = require.resolve('./fixtures/plugin-error');
|
|||||||
const pluginInheritedError = require.resolve('./fixtures/plugin-error-inherited');
|
const pluginInheritedError = require.resolve('./fixtures/plugin-error-inherited');
|
||||||
|
|
||||||
test.before(async () => {
|
test.before(async () => {
|
||||||
|
// Start the local NPM registry
|
||||||
|
await npmRegistry.start();
|
||||||
// Start Mock Server
|
// Start Mock Server
|
||||||
await mockServer.start();
|
await mockServer.start();
|
||||||
// Start the local NPM registry
|
|
||||||
await registry.start();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.beforeEach(t => {
|
test.beforeEach(t => {
|
||||||
@ -54,9 +54,10 @@ test.afterEach.always(t => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.after.always(async () => {
|
test.after.always(async () => {
|
||||||
await mockServer.stop();
|
|
||||||
// Stop the local NPM registry
|
// Stop the local NPM registry
|
||||||
await registry.stop();
|
await npmRegistry.stop();
|
||||||
|
// Stop Mock Server
|
||||||
|
await mockServer.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.serial('Release patch, minor and major versions', async t => {
|
test.serial('Release patch, minor and major versions', async t => {
|
||||||
@ -71,7 +72,7 @@ test.serial('Release patch, minor and major versions', async t => {
|
|||||||
version: '0.0.0-dev',
|
version: '0.0.0-dev',
|
||||||
repository: {url: `git+https://github.com/${owner}/${packageName}`},
|
repository: {url: `git+https://github.com/${owner}/${packageName}`},
|
||||||
release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']},
|
release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']},
|
||||||
publishConfig: {registry: registry.uri},
|
publishConfig: {registry: npmRegistry.url},
|
||||||
});
|
});
|
||||||
// Create a npm-shrinkwrap.json file
|
// Create a npm-shrinkwrap.json file
|
||||||
await execa('npm', ['shrinkwrap'], {env});
|
await execa('npm', ['shrinkwrap'], {env});
|
||||||
@ -284,7 +285,7 @@ test.serial('Release versions from a packed git repository, using tags to determ
|
|||||||
version: '0.0.0-dev',
|
version: '0.0.0-dev',
|
||||||
repository: {url: `git@github.com:${owner}/${packageName}.git`},
|
repository: {url: `git@github.com:${owner}/${packageName}.git`},
|
||||||
release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']},
|
release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']},
|
||||||
publishConfig: {registry: registry.uri},
|
publishConfig: {registry: npmRegistry.url},
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Initial release */
|
/* Initial release */
|
||||||
@ -399,7 +400,7 @@ test.serial('Create a tag as a recovery solution for "ENOTINHISTORY" error', asy
|
|||||||
version: '0.0.0-dev',
|
version: '0.0.0-dev',
|
||||||
repository: {url: `git+https://github.com/${owner}/${packageName}`},
|
repository: {url: `git+https://github.com/${owner}/${packageName}`},
|
||||||
release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']},
|
release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']},
|
||||||
publishConfig: {registry: registry.uri},
|
publishConfig: {registry: npmRegistry.url},
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Initial release */
|
/* Initial release */
|
||||||
@ -528,7 +529,7 @@ test.serial('Dry-run', async t => {
|
|||||||
name: packageName,
|
name: packageName,
|
||||||
version: '0.0.0-dev',
|
version: '0.0.0-dev',
|
||||||
repository: {url: `git+https://github.com/${owner}/${packageName}`},
|
repository: {url: `git+https://github.com/${owner}/${packageName}`},
|
||||||
publishConfig: {registry: registry.uri},
|
publishConfig: {registry: npmRegistry.url},
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Initial release */
|
/* Initial release */
|
||||||
@ -557,7 +558,7 @@ test.serial('Pass options via CLI arguments', async t => {
|
|||||||
name: packageName,
|
name: packageName,
|
||||||
version: '0.0.0-dev',
|
version: '0.0.0-dev',
|
||||||
repository: {url: `git+https://github.com/${owner}/${packageName}`},
|
repository: {url: `git+https://github.com/${owner}/${packageName}`},
|
||||||
publishConfig: {registry: registry.uri},
|
publishConfig: {registry: npmRegistry.url},
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Initial release */
|
/* Initial release */
|
||||||
@ -597,7 +598,7 @@ test.serial('Run via JS API', async t => {
|
|||||||
name: packageName,
|
name: packageName,
|
||||||
version: '0.0.0-dev',
|
version: '0.0.0-dev',
|
||||||
repository: {url: `git+https://github.com/${owner}/${packageName}`},
|
repository: {url: `git+https://github.com/${owner}/${packageName}`},
|
||||||
publishConfig: {registry: registry.uri},
|
publishConfig: {registry: npmRegistry.url},
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Initial release */
|
/* Initial release */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user