Skip to content

Commit c2f9369

Browse files
committed
feat(tooling): Add npm publish for components
1 parent 8a615ed commit c2f9369

File tree

10 files changed

+221
-71
lines changed

10 files changed

+221
-71
lines changed

Jenkinsfile

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,15 @@ ansiColor('xterm') {
9090
'''
9191
}
9292

93-
stage('Test') {
93+
stage('Unit Tests') {
94+
sh '''#!/bin/bash -ex
95+
source ~/.nvm/nvm.sh
96+
nvm use v7
97+
npm run jest
98+
'''
99+
}
100+
101+
stage('Journey Tests') {
94102
withCredentials([
95103
string(credentialsId: 'ddfd04fb-e00a-4df0-9250-9a7cb37bce0e', variable: 'CISCOSPARK_CLIENT_SECRET'),
96104
usernamePassword(credentialsId: 'SAUCE_LABS_VALIDATED_MERGE_CREDENTIALS', passwordVariable: 'SAUCE_ACCESS_KEY', usernameVariable: 'SAUCE_USERNAME'),
@@ -120,12 +128,13 @@ ansiColor('xterm') {
120128
packageJsonVersion = readFile '.version'
121129
}
122130

123-
stage('Build'){
131+
stage('Build for CDN'){
124132
withCredentials([usernamePassword(credentialsId: 'MESSAGE_DEMO_CLIENT', passwordVariable: 'MESSAGE_DEMO_CLIENT_SECRET', usernameVariable: 'MESSAGE_DEMO_CLIENT_ID')]) {
125133
sh '''#!/bin/bash -ex
126134
source ~/.nvm/nvm.sh
127135
nvm use v7
128136
version=`cat .version`
137+
NODE_ENV=production
129138
BUILD_PUBLIC_PATH="https://code.s4d.io/widget-message-meet/archives/${version}/demo/" npm run build:package widget-message-meet-demo
130139
BUILD_PUBLIC_PATH="https://code.s4d.io/widget-message-meet/archives/${version}/" npm run build:package widget-message-meet
131140
BUILD_PUBLIC_PATH="https://code.s4d.io/widget-space/archives/${version}/" npm run build:package widget-space
@@ -173,6 +182,28 @@ ansiColor('xterm') {
173182
warn('failed to publish to CDN')
174183
}
175184
}
185+
186+
stage('Publish to NPM') {
187+
try {
188+
image.inside(DOCKER_RUN_OPTS) {
189+
sh 'echo \'//registry.npmjs.org/:_authToken=${NPM_TOKEN}\' > $HOME/.npmrc'
190+
echo ''
191+
echo 'Reminder: E403 errors below are normal. They occur for any package that has no updates to publish'
192+
echo ''
193+
sh '''#!/bin/bash -ex
194+
source ~/.nvm/nvm.sh
195+
nvm use v7
196+
npm run publish:components
197+
'''
198+
echo ''
199+
echo 'Reminder: E403 errors above are normal. They occur for any package that has no updates to publish'
200+
echo ''
201+
}
202+
}
203+
catch (error) {
204+
warn("failed to publish to npm ${error.toString()}")
205+
}
206+
}
176207
}
177208
cleanup()
178209
}

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
"version": "0.1.137",
44
"description": "The Cisco Spark for React library allows developers to easily incorporate Spark functionality into an application.",
55
"scripts": {
6-
"build": "cross-env NODE_ENV=${NODE_ENV:-production} ./scripts/build/index.js",
6+
"build": "./scripts/build/index.js",
77
"build:all": "npm run build all",
88
"build:package": "npm run build dist",
9+
"build:components": "npm run build components",
910
"build:packagejson": "npm run build package.json",
1011
"build:widgets": "npm run build widgets",
1112
"clean": "npm run clean:snapshots && npm run clean:dist && npm run clean:transpile",
@@ -27,7 +28,9 @@
2728
"serve": "npm run start",
2829
"stylelint": "stylelint \"packages/node_modules/**/*.css\"",
2930
"start": "cross-env NODE_ENV=${NODE_ENV:-development} ./scripts/start/index.js",
30-
"start:package": "npm run start package"
31+
"start:package": "npm run start package",
32+
"publish": "cross-env-shell NODE_ENV='' ./scripts/publish/index.js",
33+
"publish:components": "npm run build:components && npm run build:packagejson && npm run publish components"
3134
},
3235
"repository": {
3336
"type": "git",

scripts/build/commands/components.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env babel-node
2+
const path = require(`path`);
3+
const {
4+
transpile
5+
} = require(`../../utils/build`);
6+
const {getAllPackagePaths} = require(`../../utils/package`);
7+
8+
9+
module.exports = {
10+
command: `components`,
11+
desc: `Build all component and module packages`,
12+
builder: {},
13+
handler: () =>
14+
getAllPackagePaths().map((pkg) => {
15+
try {
16+
const pkgJson = require(path.resolve(pkg, `package.json`));
17+
const pkgName = pkgJson.name.split(`/`).pop();
18+
const isWidget = pkgName.startsWith(`widget-`);
19+
if (!isWidget && !pkgJson.private) {
20+
return transpile(pkgName, pkg);
21+
}
22+
}
23+
catch (err) {
24+
throw err;
25+
}
26+
return false;
27+
})
28+
};
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
/* eslint-disable no-sync */
2-
const {updatePackageJson} = require(`../../utils/deps`);
2+
const {updateAllPackageJson, updatePackageJson} = require(`../../utils/deps`);
3+
const {getPackage} = require(`../../utils/package`);
34

45
module.exports = {
5-
command: `package.json`,
6+
command: `package.json [packageName]`,
67
desc: `Update all package.json`,
78
builder: {},
8-
handler: () => updatePackageJson()
9+
handler: ({packageName}) => {
10+
if (packageName) {
11+
return updatePackageJson(getPackage(packageName));
12+
}
13+
return updateAllPackageJson();
14+
}
915
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env babel-node
2+
const path = require(`path`);
3+
const {npmPublishPackage} = require(`../../utils/publish`);
4+
const {getAllPackagePaths} = require(`../../utils/package`);
5+
6+
7+
module.exports = {
8+
command: `components`,
9+
desc: `Publish all component and module packages`,
10+
builder: {},
11+
handler: () =>
12+
getAllPackagePaths().map((pkg) => {
13+
try {
14+
const pkgJson = require(path.resolve(pkg, `package.json`));
15+
const pkgName = pkgJson.name.split(`/`).pop();
16+
const isWidget = pkgName.startsWith(`widget-`);
17+
if (!isWidget && !pkgJson.private) {
18+
return npmPublishPackage(pkgName);
19+
}
20+
}
21+
catch (err) {
22+
// Ignore errors
23+
}
24+
return false;
25+
})
26+
};

scripts/publish/commands/package.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const {npmPublishPackage, npmPublishAll} = require(`../../utils/publish`);
2+
3+
module.exports = {
4+
command: `package <packageName>`,
5+
desc: `Publish a package to NPM`,
6+
builder: {},
7+
handler: ({packageName}) => {
8+
if (packageName) {
9+
switch (packageName.toLowerCase()) {
10+
case `all`:
11+
return npmPublishAll();
12+
default:
13+
return npmPublishPackage(packageName);
14+
}
15+
}
16+
return false;
17+
}
18+
};

scripts/publish/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env babel-node
2+
/**
3+
* Publish a Package
4+
*/
5+
6+
require(`yargs`) // eslint-disable-line no-unused-expressions
7+
.usage(`Usage: $0 <target> [args]`)
8+
.commandDir(`commands`)
9+
.demandCommand(1, `Please let us know what package you'd like to publish.`)
10+
.help()
11+
.argv;
12+

scripts/utils/deps.js

Lines changed: 75 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,85 +6,98 @@ const builtinModules = require(`builtin-modules`);
66
const {uniq} = require(`lodash`);
77
const {getAllPackages, getAllPackagePaths} = require(`./package`);
88

9+
const flatten = (arr) => arr.reduce(
10+
(acc, val) => acc.concat(
11+
Array.isArray(val) ? flatten(val) : val
12+
),
13+
[]
14+
);
15+
16+
917
/**
1018
* Updates all package.json files with depedencies
1119
* @returns {undefined}
1220
*/
13-
function updatePackageJson() {
14-
const topPkgJson = JSON.parse(readFileSync(`./package.json`, `utf8`));
21+
function updateAllPackageJson() {
1522
const packages = getAllPackages();
1623
const pkgPaths = getAllPackagePaths();
24+
const topPkgJson = JSON.parse(readFileSync(`./package.json`, `utf8`));
1725
console.log(packages);
18-
const flatten = (arr) => arr.reduce(
19-
(acc, val) => acc.concat(
20-
Array.isArray(val) ? flatten(val) : val
21-
),
22-
[]
23-
);
2426

25-
pkgPaths.forEach((pkgPath) => {
26-
const pkgJsonPath = path.join(pkgPath, `package.json`);
27-
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, `utf8`));
27+
pkgPaths.forEach((pkgPath) => updatePackageJson(pkgPath, packages, topPkgJson));
28+
}
29+
30+
function updatePackageJson(pkgPath, packages, topPkgJson) {
31+
if (!packages) {
32+
packages = getAllPackages();
33+
}
34+
if (!topPkgJson) {
35+
topPkgJson = JSON.parse(readFileSync(`./package.json`, `utf8`));
36+
}
2837

29-
// for the dependencies, find all require() calls
30-
const srcFiles = glob.sync(path.join(pkgPath, `src/**/*.js`), {
31-
ignore: [
32-
`**/*.test.js`,
33-
`**/__mocks__/*.js`,
34-
`**/__fixtures__/*.js`,
35-
`**/react-test-utils/**/*.js`
36-
]
37-
});
38+
const pkgJsonPath = path.join(pkgPath, `package.json`);
39+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, `utf8`));
3840

39-
const uniqDeps = uniq(
40-
flatten(
41-
srcFiles.map(
42-
(srcFile) => {
43-
const code = readFileSync(srcFile, `utf8`);
44-
try {
45-
return detective(code);
46-
}
47-
catch (e) {
48-
return [];
49-
}
41+
// for the dependencies, find all require() calls
42+
const srcFiles = glob.sync(path.join(pkgPath, `src/**/*.js`), {
43+
ignore: [
44+
`**/*.test.js`,
45+
`**/__mocks__/*.js`,
46+
`**/__fixtures__/*.js`,
47+
`**/react-test-utils/**/*.js`
48+
]
49+
});
50+
51+
const uniqDeps = uniq(
52+
flatten(
53+
srcFiles.map(
54+
(srcFile) => {
55+
const code = readFileSync(srcFile, `utf8`);
56+
try {
57+
return detective(code);
58+
}
59+
catch (e) {
60+
return [];
5061
}
51-
)
62+
}
5263
)
5364
)
54-
.filter((dep) =>
55-
// built in modules
56-
builtinModules.indexOf(dep) === -1
57-
// react-intl locale imports
58-
&& !dep.includes(`react-intl/locale-data`)
59-
// local references
60-
&& dep[0] !== `.`
61-
)
62-
.sort();
63-
const deps = pkgJson.dependencies = {};
64-
uniqDeps.forEach((dep) => {
65-
const depArray = dep.split(`/`);
66-
let cleanDep = depArray[0];
67-
if (depArray[0].startsWith(`@`)) {
68-
cleanDep = depArray.slice(0, 2).join(`/`);
69-
}
70-
if (topPkgJson.dependencies[cleanDep]) {
71-
deps[cleanDep] = topPkgJson.dependencies[cleanDep];
72-
}
73-
else if (packages.indexOf(cleanDep) !== -1) { // eslint-disable-line no-negated-condition
74-
deps[cleanDep] = topPkgJson.version;
75-
}
76-
else {
77-
throw new Error(`Unknown dependency ${cleanDep}`);
78-
}
79-
});
65+
)
66+
.filter((dep) =>
67+
// built in modules
68+
builtinModules.indexOf(dep) === -1
69+
// react-intl locale imports
70+
&& !dep.includes(`react-intl/locale-data`)
71+
// local references
72+
&& dep[0] !== `.`
73+
)
74+
.sort();
75+
const deps = pkgJson.dependencies = {};
76+
uniqDeps.forEach((dep) => {
77+
const depArray = dep.split(`/`);
78+
let cleanDep = depArray[0];
79+
if (depArray[0].startsWith(`@`)) {
80+
cleanDep = depArray.slice(0, 2).join(`/`);
81+
}
82+
if (topPkgJson.dependencies[cleanDep]) {
83+
deps[cleanDep] = topPkgJson.dependencies[cleanDep];
84+
}
85+
else if (packages.indexOf(cleanDep) !== -1) { // eslint-disable-line no-negated-condition
86+
deps[cleanDep] = topPkgJson.version;
87+
}
88+
else {
89+
throw new Error(`Unknown dependency ${cleanDep}`);
90+
}
91+
});
8092

81-
pkgJson[`module`] = `./es/index.js`;
93+
pkgJson[`version`] = topPkgJson.version;
8294

83-
const jsonString = `${JSON.stringify(pkgJson, null, ` `)}\n`;
84-
writeFileSync(pkgJsonPath, jsonString, `utf8`);
85-
});
95+
const jsonString = `${JSON.stringify(pkgJson, null, ` `)}\n`;
96+
writeFileSync(pkgJsonPath, jsonString, `utf8`);
8697
}
8798

99+
88100
module.exports = {
101+
updateAllPackageJson,
89102
updatePackageJson
90103
};

scripts/utils/package.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,11 @@ function getPackage(pkg, packagesDir = `packages/node_modules/@ciscospark`) {
6969
return false;
7070
}
7171

72-
function getAllPackages() {
73-
const pkgPaths = getAllPackagePaths();
72+
function getAllPackages(omitPrivate) {
73+
let pkgPaths = getAllPackagePaths();
74+
if (omitPrivate) {
75+
pkgPaths = pkgPaths.filter((pkgPath) => !require(path.resolve(pkgPath, `package.json`)).private);
76+
}
7477
return pkgPaths.map((pkgPath) => require(path.resolve(pkgPath, `package.json`)).name);
7578
}
7679

scripts/utils/publish.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const path = require(`path`);
2+
const {runInPackage} = require(`./package`);
3+
4+
export function npmPublishPackage(pkgName) {
5+
return runInPackage({
6+
constructCommand: (targetPath) => `cd ${path.resolve(targetPath)} && npm publish --access public`,
7+
commandName: `Publish Package to NPM`,
8+
pkgName
9+
});
10+
}

0 commit comments

Comments
 (0)