Skip to content

Commit

Permalink
JSUI-3159 Run CI/CD on jenkins and deploy beta tags to npm (#1665)
Browse files Browse the repository at this point in the history
  • Loading branch information
samisayegh authored Jan 7, 2021
1 parent 60f24e6 commit 2fb82d8
Show file tree
Hide file tree
Showing 14 changed files with 365 additions and 202 deletions.
81 changes: 81 additions & 0 deletions .deployment.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"product": "coveo-search-ui",
"team_name": "searchui",
"general": {
"aws_regions": {
"sequential": [
"us-east-1"
]
},
"environments_order": {
"sequential": [
"dev",
"qa",
"prd"
]
},
"team_jenkins": "searchuibuilds",
"start_environment_automatically": false,
"notifications": {
"slack_channels": [
"#searchuibuilds"
]
}
},
"phases": {
"s3": {
"bucket": "coveo-nprod-binaries",
"directory": "proda/StaticCDN/searchui/v$[MAJOR_MINOR_VERSION]",
"parameters": {
"acl": "public-read"
},
"dev": {
"disabled": true
},
"qa": {
"disabled": true
},
"source": "bin"
}
},
"certifiers": {
"dev": [
{
"system_certifier": "snyk"
},
{
"system_certifier": "veracode"
}
],
"prd": [
{
"job_name": "search_ui/job/update_npm_latest_tag",
"tag_suffix": "npm_latest_tag_updated",
"extra_parameters": {
"LATEST_NPM_VERSION": "$[LATEST_NPM_VERSION]"
}
}
]
},
"snyk": {
"org": "coveo-jsui",
"no_container_images": true,
"configurations": [
{
"directory": ".",
"project_name": "search-ui"
}
]
},
"veracode": {
"sandbox_name": "JS UI",
"scan_include_patterns": "*"
},
"observatory": {
"no_endpoint": true
},
"package_rollout": {
"only_consider_changesets_after": "16247824e24b"
},
"deployment_config_version": 1
}
71 changes: 71 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
node('linux && docker') {
checkout scm
def tag = env.TAG_NAME

withEnv([
'npm_config_cache=npm-cache'
]){
withDockerContainer(image: 'nikolaik/python-nodejs:python3.8-nodejs10', args: '-u=root') {
stage('Install') {
sh 'yarn install'
}

stage('Build') {
sh '. ./read.version.sh'
sh 'echo $PACKAGE_JSON_VERSION'
sh 'yarn run injectTag'
sh 'yarn run build'

if (tag) {
sh 'yarn run minimize'
}
}

stage('Install Chrome') {
sh "wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -"
sh "echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list"
sh "apt-get update"
sh "apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 libxtst6 --no-install-recommends"
sh "google-chrome --version"
}

stage('Test') {
sh 'yarn run unitTests'

if (tag) {
sh 'yarn run accessibilityTests'
}

sh 'set +e'
// sh 'yarn run uploadCoverage'
sh 'set -e'
sh 'yarn run validateTypeDefinitions'
}

stage('Docs') {
// sh 'if [[ "x$GIT_TAG_NAME" != "x" && $IS_PULL_REQUEST_PUSH_BUILD = false ]]; then bash ./deploy.doc.sh ; fi'
sh 'yarn run docsitemap'
sh 'yarn run zipForGitReleases'
}

if (!tag) {
return
}

stage('Deploy') {
withCredentials([
string(credentialsId: 'NPM_TOKEN', variable: 'NPM_TOKEN')
]) {
sh 'node ./build/npm.deploy.js'
}

sh 'rm -rf veracode && mkdir veracode'
sh 'mkdir veracode/search-ui'
sh 'cp -R src package.json yarn.lock veracode/search-ui'

sh 'node ./build/deployment-pipeline.deploy.js || true'
}
}

}
}
47 changes: 47 additions & 0 deletions build/deployment-pipeline.deploy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
const compareVersions = require('compare-versions');
const { getMajorMinorVersion, getVersion } = require('./tag.utilities');
const { getLatestVersionOnNpm } = require('./npm.utilities');

async function installDeploymentPipeLineCli() {
const command = 'pip install deployment_package==7.* --index-url https://pypi.dev.cloud.coveo.com/simple';
console.log('installing deployment pipeline cli');
await exec(command);
}

async function createAndDeployPackage() {
const paramString = await getResolvedParamString();
const command = `deployment-package package create ${paramString} --for-spinnaker --with-deploy`;

console.log('creating and deploying package');
await exec(command);
}

async function getResolvedParamString() {
const npmVersion = await getLatestNpmVersion();
const params = [`MAJOR_MINOR_VERSION=${getMajorMinorVersion()}`, `LATEST_NPM_VERSION=${npmVersion}`];
return ['', ...params].join(' --resolve ').trim();
}

async function getLatestNpmVersion() {
const currentVersion = getVersion();
const latestVersion = await getLatestVersionOnNpm();
const isCurrentVersionNewerThanLatest = compareVersions(currentVersion, latestVersion) === 1;

return isCurrentVersionNewerThanLatest ? currentVersion : latestVersion;
}

async function main() {
try {
await installDeploymentPipeLineCli();
await createAndDeployPackage();
console.log('Successfully uploaded package to deployment pipeline');
process.exit(0);
} catch (e) {
console.log('Failed to upload package to deployment pipeline', e);
process.exit(1);
}
}

main();
37 changes: 37 additions & 0 deletions build/npm.deploy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict';
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
const fs = require('fs');
const os = require('os');
const { isTagged } = require('./tag.utilities');

async function deployTaggedVersion() {
const suffix = 'beta';
console.log(`Doing a NPM deployment of a ${suffix} version`);
await publishToNpm(['--tag', suffix], `Deploy ${suffix} is done`);
}

async function publishToNpm(publishArgs = [], successMessage) {
const args = ['publish', ...publishArgs].join(' ');
await exec(`npm ${args}`);
console.log(successMessage);
}

function setNpmrcFile() {
const fileName = `${os.homedir()}/.npmrc`;
const npmrcString = `//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}`;

console.log('setting npmrc file');
return new Promise((resolve, reject) => fs.writeFile(fileName, npmrcString, err => (err ? reject(err) : resolve())));
}

async function main() {
if (!isTagged()) {
return console.log('Skipping NPM deployment because this is not a tagged commit');
}

await setNpmrcFile();
await deployTaggedVersion();
}

main();
18 changes: 18 additions & 0 deletions build/npm.utilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);

async function getLatestVersionOnNpm() {
const tags = await getTags();
const latestTag = tags.find(tag => tag.indexOf('latest') !== -1);
return latestTag.split(':')[1].trim();
}

async function getTags() {
const command = 'npm dist-tags ls coveo-search-ui';
const { stdout } = await exec(command);
return stdout.split('\n');
}

module.exports = {
getLatestVersionOnNpm
};
79 changes: 79 additions & 0 deletions build/tag.utilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const tag = process.env.TAG_NAME || '';

function isTagged() {
return tag && tag !== '';
}

function isOfficialTag() {
const officialForm = `^${semanticVersionForm()}$`;
const officialRegex = new RegExp(officialForm);

return officialRegex.test(tag);
}

function isBetaTag() {
const betaForm = `^${semanticVersionForm()}-beta$`;
const betaRegex = new RegExp(betaForm);

return betaRegex.test(tag);
}

function semanticVersionForm() {
const number = '[0-9]+';
const dot = '[.]';
return `${number}${dot}${number}${dot}${number}`;
}

function majorMinorForm() {
const number = '[0-9]+';
const dot = '[.]';
return `${number}${dot}${number}`;
}

function smallLetters() {
return '[a-z]+';
}

function tagHasAlphabeticSuffix() {
const suffixForm = `^${semanticVersionForm()}-${smallLetters()}$`;
const suffixRegex = new RegExp(suffixForm);

return suffixRegex.test(tag);
}

function getAlphabeticSuffix() {
if (!tagHasAlphabeticSuffix()) {
return '';
}

const suffixRegex = new RegExp(`${smallLetters()}$`);
return suffixRegex.exec(tag)[0];
}

function getVersion() {
return require('../package.json').version;
}

function getMajorMinorVersion() {
const version = getVersion();
const form = `^${majorMinorForm()}`;
const majorMinorRegex = new RegExp(form);

return majorMinorRegex.exec(version)[0];
}

function getHerokuVersion() {
const version = getVersion();
return version ? version.replace(/\./g, '-') : 'unknown-version';
}

module.exports = {
isTagged,
isOfficialTag,
isBetaTag,
tagHasAlphabeticSuffix,
getAlphabeticSuffix,
getVersion,
getHerokuVersion,
getMajorMinorVersion
};
29 changes: 0 additions & 29 deletions deploy.beta.js

This file was deleted.

6 changes: 3 additions & 3 deletions gulpTasks/injectTag.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ const replace = require('gulp-replace');
const colors = require('colors');

function injectTag() {
if (process.env.TRAVIS_TAG) {
console.log(`Injecting ${process.env.TRAVIS_TAG} in Coveo.version ...`.black.bgGreen);
if (process.env.TAG_NAME) {
console.log(`Injecting ${process.env.TAG_NAME} in Coveo.version ...`.black.bgGreen);
return gulp
.src('./src/misc/Version.ts')
.pipe(replace(/0\.0\.0\.0/g, process.env.TRAVIS_TAG))
.pipe(replace(/0\.0\.0\.0/g, process.env.TAG_NAME))
.pipe(gulp.dest('./src/misc/'));
}

Expand Down
2 changes: 1 addition & 1 deletion gulpTasks/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function configureTestServer(configPath, cb) {

const coverage = gulp.series(remapCoverage, convertCoverageToLcovFormat);

const uploadCoverage = gulp.series(coverage, shell.task(['cat bin/coverage/lcov.info | npx coveralls']));
const uploadCoverage = gulp.series(coverage, shell.task([`cat bin/coverage/lcov.info | npx coveralls`]));

function remapCoverage() {
return gulp
Expand Down
Loading

0 comments on commit 2fb82d8

Please sign in to comment.