diff --git a/.gitignore b/.gitignore index 694e047e..fa6f8ca3 100644 --- a/.gitignore +++ b/.gitignore @@ -129,7 +129,3 @@ $RECYCLE.BIN/ package-lock.json yarn.lock - -# Registry tests -test/helpers/registry/couch -test/helpers/registry/data diff --git a/.travis.yml b/.travis.yml index 8dcc787d..e08cb38b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,13 @@ language: node_js services: - - couchdb - docker notifications: email: false node_js: + - 9 - 8 +os: + - linux # 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) diff --git a/package.json b/package.json index ab00d634..169e278f 100644 --- a/package.json +++ b/package.json @@ -46,11 +46,12 @@ "eslint-plugin-prettier": "^2.3.0", "file-url": "^2.0.2", "fs-extra": "^4.0.2", + "got": "^8.0.0", "js-yaml": "^3.10.0", "mockserver-client": "^2.0.0", "nock": "^9.0.2", - "npm-registry-couchapp": "^2.6.12", "nyc": "^11.2.1", + "p-retry": "^1.0.0", "prettier": "~1.8.0", "proxyquire": "^1.8.0", "sinon": "^4.0.0", diff --git a/test/helpers/mockserver.js b/test/helpers/mockserver.js index 97075b84..fbae5a58 100644 --- a/test/helpers/mockserver.js +++ b/test/helpers/mockserver.js @@ -1,5 +1,7 @@ import Docker from 'dockerode'; import getStream from 'get-stream'; +import got from 'got'; +import pRetry from 'p-retry'; import {mockServerClient} from 'mockserver-client'; const MOCK_SERVER_PORT = 1080; @@ -7,6 +9,14 @@ const MOCK_SERVER_HOST = 'localhost'; const docker = new Docker(); 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. * @@ -19,7 +29,14 @@ async function start() { Image: 'jamesdbloom/mockserver', 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`); + } } /** diff --git a/test/helpers/npm-registry.js b/test/helpers/npm-registry.js new file mode 100644 index 00000000..0646fdb6 --- /dev/null +++ b/test/helpers/npm-registry.js @@ -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}; diff --git a/test/helpers/registry/index.js b/test/helpers/registry/index.js deleted file mode 100644 index 9c90e0b8..00000000 --- a/test/helpers/registry/index.js +++ /dev/null @@ -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}; diff --git a/test/helpers/registry/local.ini b/test/helpers/registry/local.ini deleted file mode 100644 index 8bacecb2..00000000 --- a/test/helpers/registry/local.ini +++ /dev/null @@ -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 diff --git a/test/helpers/registry/start.sh b/test/helpers/registry/start.sh deleted file mode 100755 index 15161916..00000000 --- a/test/helpers/registry/start.sh +++ /dev/null @@ -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 diff --git a/test/helpers/registry/stop.sh b/test/helpers/registry/stop.sh deleted file mode 100755 index 28a9157f..00000000 --- a/test/helpers/registry/stop.sh +++ /dev/null @@ -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 diff --git a/test/integration.test.js b/test/integration.test.js index 954bc700..8e1c5370 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -3,15 +3,15 @@ import {writeJson, readJson} from 'fs-extra'; import {stub} from 'sinon'; import execa from 'execa'; import {gitRepo, gitCommits, gitHead, gitTagVersion, gitPackRefs, gitAmmendCommit} from './helpers/git-utils'; -import registry from './helpers/registry'; import mockServer from './helpers/mockserver'; +import npmRegistry from './helpers/npm-registry'; import semanticRelease from '..'; /* eslint camelcase: ["error", {properties: "never"}] */ // Environment variables used with cli const env = { - npm_config_registry: registry.uri, + npm_config_registry: npmRegistry.url, GH_TOKEN: 'github_token', GITHUB_URL: mockServer.url, NPM_EMAIL: 'integration@test.com', @@ -23,10 +23,10 @@ const pluginError = require.resolve('./fixtures/plugin-error'); const pluginInheritedError = require.resolve('./fixtures/plugin-error-inherited'); test.before(async () => { + // Start the local NPM registry + await npmRegistry.start(); // Start Mock Server await mockServer.start(); - // Start the local NPM registry - await registry.start(); }); test.beforeEach(t => { @@ -54,9 +54,10 @@ test.afterEach.always(t => { }); test.after.always(async () => { - await mockServer.stop(); // 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 => { @@ -71,7 +72,7 @@ test.serial('Release patch, minor and major versions', async t => { version: '0.0.0-dev', repository: {url: `git+https://github.com/${owner}/${packageName}`}, release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']}, - publishConfig: {registry: registry.uri}, + publishConfig: {registry: npmRegistry.url}, }); // Create a npm-shrinkwrap.json file 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', repository: {url: `git@github.com:${owner}/${packageName}.git`}, release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']}, - publishConfig: {registry: registry.uri}, + publishConfig: {registry: npmRegistry.url}, }); /* Initial release */ @@ -399,7 +400,7 @@ test.serial('Create a tag as a recovery solution for "ENOTINHISTORY" error', asy version: '0.0.0-dev', repository: {url: `git+https://github.com/${owner}/${packageName}`}, release: {verifyConditions: ['@semantic-release/github', '@semantic-release/npm']}, - publishConfig: {registry: registry.uri}, + publishConfig: {registry: npmRegistry.url}, }); /* Initial release */ @@ -528,7 +529,7 @@ test.serial('Dry-run', async t => { name: packageName, version: '0.0.0-dev', repository: {url: `git+https://github.com/${owner}/${packageName}`}, - publishConfig: {registry: registry.uri}, + publishConfig: {registry: npmRegistry.url}, }); /* Initial release */ @@ -557,7 +558,7 @@ test.serial('Pass options via CLI arguments', async t => { name: packageName, version: '0.0.0-dev', repository: {url: `git+https://github.com/${owner}/${packageName}`}, - publishConfig: {registry: registry.uri}, + publishConfig: {registry: npmRegistry.url}, }); /* Initial release */ @@ -597,7 +598,7 @@ test.serial('Run via JS API', async t => { name: packageName, version: '0.0.0-dev', repository: {url: `git+https://github.com/${owner}/${packageName}`}, - publishConfig: {registry: registry.uri}, + publishConfig: {registry: npmRegistry.url}, }); /* Initial release */