From 6985e2ce7c9f55f7a5143383675b5fbe614fa17c Mon Sep 17 00:00:00 2001 From: Felipe Vargas Date: Thu, 13 Jul 2017 19:22:42 -0700 Subject: [PATCH 1/7] Fix issue when extending webpack config --- app/react/src/server/config.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/react/src/server/config.js b/app/react/src/server/config.js index 36e2d30ec259..21d476051f4a 100644 --- a/app/react/src/server/config.js +++ b/app/react/src/server/config.js @@ -73,7 +73,10 @@ export default function(configType, baseConfig, configDir) { ...config.module, // We need to use our and custom rules. ...customConfig.module, - rules: [...config.module.rules, ...(customConfig.module.rules || [])], + rules: [ + ...config.module.rules, + ...((customConfig.module && customConfig.module.rules) || []), + ], }, resolve: { ...config.resolve, From 299a53ac7267a647e6383cd725749f81775b4ab7 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Sun, 16 Jul 2017 13:37:30 +0200 Subject: [PATCH 2/7] SWITCH to circleci over travisCI && CHANGE lerna bootstrap procedure: - Use yarn for installation - Hoist all dependencies to root - Hoist known packages to root - Test storyshots in cra-kitchen-sink --- .circleci/config.yml | 178 +++++ .travis.yml | 33 - addons/actions/package.json | 2 +- addons/comments/package.json | 2 +- addons/events/package.json | 10 +- addons/info/package.json | 2 +- addons/knobs/package.json | 2 +- addons/storyshots/package.json | 2 +- addons/storyshots/src/index.js | 38 +- app/react-native/package.json | 14 +- app/react/package.json | 4 +- .../cra-kitchen-sink/.storybook/config.js | 4 +- examples/cra-kitchen-sink/package.json | 2 +- .../src/__snapshots__/storyshots.test.js.snap | 613 ++++++++++++++++++ .../cra-kitchen-sink/src/storyshots.test.js | 45 +- examples/test-cra/package.json | 1 - .../src/__snapshots__/storyshots.test.js.snap | 124 ---- examples/test-cra/src/storyshots.test.js | 17 - lerna.json | 2 +- lib/addons/src/index.js | 2 +- lib/cli/package.json | 2 +- lib/ui/package.json | 6 +- package.json | 28 +- scripts/hoist-internals.js | 74 +++ 24 files changed, 949 insertions(+), 258 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 .travis.yml create mode 100644 examples/cra-kitchen-sink/src/__snapshots__/storyshots.test.js.snap delete mode 100644 examples/test-cra/src/__snapshots__/storyshots.test.js.snap delete mode 100644 examples/test-cra/src/storyshots.test.js create mode 100644 scripts/hoist-internals.js diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000000..25c4fdfe2bbe --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,178 @@ +defaults: &defaults + working_directory: /tmp/storybook + docker: + - image: node:8 + +version: 2 +dependencies: + pre: + - npm install -g npm +jobs: + validate: + <<: *defaults + steps: + - run: + name: "Checking Versions" + command: | + node --version + npm --version + yarn --version + build: + <<: *defaults + steps: + - checkout + - restore_cache: + keys: + - root-dependencies-{{ checksum "package.json" }} + - root-dependencies- + - run: + name: "Install root dependencies" + command: | + yarn install + - save_cache: + key: root-dependencies-{{ checksum "package.json" }} + paths: + - node_modules + - restore_cache: + keys: + - package-dependencies-{{ checksum "package.json" }} + - package-dependencies- + - run: + name: "Bootstrapping" + command: | + npm run bootstrap + - save_cache: + key: package-dependencies-{{ checksum "package.json" }} + paths: + - app/**/node_modules + - docs/**/node_modules + - examples/**/node_modules + - lib/**/node_modules + example-kitchen-sink: + <<: *defaults + steps: + - run: + name: "Running kitchen-sink" + command: | + echo "TODO" + example-test-cra: + <<: *defaults + steps: + - checkout + - restore_cache: + keys: + - root-dependencies-{{ checksum "package.json" }} + - root-dependencies- + - run: + name: "Install root dependencies" + command: | + yarn install + - run: + name: "Bootstrapping" + command: | + npm run bootstrap + npm run bootstrap:test-cra + - run: + name: "Running test-cra" + command: | + echo "TODO" + example-react-native: + <<: *defaults + steps: + - checkout + - restore_cache: + keys: + - root-dependencies-{{ checksum "package.json" }} + - root-dependencies- + - run: + name: "Install root dependencies" + command: | + yarn install + - run: + name: "Bootstrapping packages" + command: | + npm run bootstrap + npm run bootstrap:react-native-vanilla + - run: + name: "Running react-native" + command: | + echo "TODO" + + docs: + <<: *defaults + steps: + - checkout + - restore_cache: + keys: + - root-dependencies-{{ checksum "package.json" }} + - root-dependencies- + - run: + name: "Install root dependencies" + command: | + yarn install + - run: + name: "Bootstrapping" + command: | + npm run bootstrap:docs + - run: + name: "Running docs" + command: | + npm run docs:build + lint: + <<: *defaults + steps: + - checkout + - restore_cache: + keys: + - root-dependencies-{{ checksum "package.json" }} + - root-dependencies- + - run: + name: "Install root dependencies" + command: | + yarn install + - run: + name: "Linting" + command: | + npm run lint + unit-test: + <<: *defaults + steps: + - checkout + - restore_cache: + keys: + - root-dependencies-{{ checksum "package.json" }} + - root-dependencies- + - run: + name: "Install root dependencies" + command: | + yarn install + - run: + name: "Bootstrapping" + command: | + npm run bootstrap:docs + npm run bootstrap:test-cra + npm run bootstrap:react-native-vanilla + npm run bootstrap + - run: + name: "Unit testing" + command: | + npm run test -- --coverage + npm run coverage + +workflows: + version: 2 + build_accept_deploy: + jobs: + - validate + - build + - example-kitchen-sink + - example-test-cra + - example-react-native + - docs + - lint + - unit-test + - deploy: + requires: + - lint + - unit-test + - docs diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b7eada8bd776..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,33 +0,0 @@ -language: node_js -cache: - directories: - - node_modules - - ".cache" -notifications: - email: false -node_js: -- node -before_install: "./scripts/travis/before_install.sh" -after_success: "./scripts/travis/after_success.sh" -script: -- npm run bootstrap -- npm run bootstrap:test-cra -- npm run bootstrap:react-native-vanilla -- npm run bootstrap:docs -- npm run lint -- npm run test -- --coverage -- npm run coverage -- ([ -z "$DANGER_GITHUB_API_TOKEN" ] && echo "DANGER_GITHUB_API_TOKEN not set") || npm run danger -git: - depth: 1 -env: - global: - - CXX=g++-4.8 - - secure: cAde4wBX75KtTWcyOOLAG3Z9ODdqvmbkL7+8fVNj/+QkZZWE8pFa3deaTIHF9NyVO2h6/jutSkzmsz/nOyBYVPHhGsxBTmsyXoko48Wg+iNm7epoH5uts/kmAPiwpzaWGXwuiAvsOGZjYYFzM335jyaOAcZW3f0C5gIJ5XCCdWBQRaFFLq+ZLKsLSME6xTfV2OMVH24hxXvbF9wvO0aj6p/GaT0cS8Rpg4sQ9eeih2IM/uLiqWzp9UUM2m8SUiFfveqYJFkBtzqAus9pbwsoQjnAT5e3CKJUpPiruCAe5FOt57Hl+mH1N1xqP1ei8j2ZNF+E6zuDdAcMpArTIMM69L+D7wzJYDoF2PuF+jeet7ytAFxSgnZHSTsBJn5cZMPh2tuX7aWwgrpMknVe3bdoINwkyVCaIW+Ur6vc37l/Kuw25eiMBtRDyMhUf4V3FAFi3PV1XKn+34cR4kvpOHt6vk8v5CobBHfQdwU+6FMZMo3GFIkDBcLydLn3WLQ3jKa4OcLqWws6o85k+bHZkLhlADjbiX/PzG23D+sT7Inzj//Tef93SIL02yN+ooZdIUtDus3+qZzhcSrDeSb2octjLXRzPiGn5cFNI86HVcu7qF0+4zCPconhM4+mfAh5S19fmnRdTQctQQxbsObuT9jcMvgJdhIX89aA7Ry3pAx2b6Q= - - secure: 1iZAjDqikmJaXvql/bpNZay9u5yyQCwNyz3OmcvhJDds6lIKUUU24S3srsYatmE2lkpUuRertieGtzMPkhNx/rFRePD7SZAnSMADyA+lxW9SWu8LHEBcjgsDY89iJH6+4BiYIrldP0vjORYJDwtiEKB3bSJX88zkLpTVTS/L5EHS9kQ/xtQsvoNB69C1ExCt7EVgSL9cDVccFvrU1FhC8w4eH5j3fNikQduaPhF+iqoTo8GW/m22/95Xhmngcu7n6Fm8G/YA2xmkvdCBLL7rLSwccwG9j9MRei704NrBOux7xN/2euVg5jYbFCaDQNjuu4UrvVB2YFxqvpsjYByktfqNMTheqcGdVuh3Jd7cMGmkMSBhUgmUW5KPH4v73mLUlHroywQUU3iiMiCvVMmTd5Xy0o0X0ks5mvXAXWHTmnQkvPyy/V6cwcUfgJC5k3M/V1hDCRMeMVPZsmh73lZffwpAkfx3xJsNf46f7h9aN9Q++danf9JryoS9YsdRBtjfJTtNaO2uH+iUMNSNzAbJmgxtsi3NuX+G+2N02mtaUCzN/SOmKKoZsuPfKVcpHgVa41mgio6QJs7wy9/VWYYASNZddj2HnvLGLBLnJpv+uKKpdSB0Xe6k8dOl1MbaWJT4Xy0/NUD3gawLCvhfN9qL0+QnlJAXCbOoms6EoAyc6fY= -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 diff --git a/addons/actions/package.json b/addons/actions/package.json index 7974b938f0aa..c2ced9a9c39f 100644 --- a/addons/actions/package.json +++ b/addons/actions/package.json @@ -24,7 +24,7 @@ "@storybook/addons": "^3.1.6", "deep-equal": "^1.0.1", "json-stringify-safe": "^5.0.1", - "prop-types": "^15.5.8", + "prop-types": "^15.5.10", "react-inspector": "^2.1.1", "uuid": "^3.1.0" }, diff --git a/addons/comments/package.json b/addons/comments/package.json index 8fddb0ef3e5b..ddec6cf0f719 100644 --- a/addons/comments/package.json +++ b/addons/comments/package.json @@ -31,7 +31,7 @@ "insert-css": "^1.0.0", "marked": "^0.3.6", "moment": "^2.18.1", - "prop-types": "^15.5.8", + "prop-types": "^15.5.10", "react-render-html": "^0.1.6", "react-textarea-autosize": "^4.3.0" }, diff --git a/addons/events/package.json b/addons/events/package.json index 56c7094ae6b9..ee61486ea8e0 100644 --- a/addons/events/package.json +++ b/addons/events/package.json @@ -21,15 +21,15 @@ }, "dependencies": { "@storybook/addons": "^3.1.6", - "babel-runtime": "^6.5.0", + "babel-runtime": "^6.23.0", "format-json": "^1.0.3", "prop-types": "^15.5.10", - "react-textarea-autosize": "^4.0.5", - "uuid": "^3.0.1" + "react-textarea-autosize": "^4.3.0", + "uuid": "^3.1.0" }, "devDependencies": { - "react": "^15.3.2", - "react-dom": "^15.3.2" + "react": "^15.5.4", + "react-dom": "^15.5.4" }, "peerDependencies": { "react": "*" diff --git a/addons/info/package.json b/addons/info/package.json index 24e7353c263c..6b4fe5949491 100644 --- a/addons/info/package.json +++ b/addons/info/package.json @@ -18,7 +18,7 @@ "babel-runtime": "^6.23.0", "global": "^4.3.2", "marksy": "^2.0.0", - "prop-types": "^15.5.8", + "prop-types": "^15.5.10", "react-addons-create-fragment": "^15.5.3" }, "devDependencies": { diff --git a/addons/knobs/package.json b/addons/knobs/package.json index 34a08897c517..e48699273ae4 100644 --- a/addons/knobs/package.json +++ b/addons/knobs/package.json @@ -23,7 +23,7 @@ "insert-css": "^1.0.0", "lodash.debounce": "^4.0.8", "moment": "^2.18.1", - "prop-types": "^15.5.8", + "prop-types": "^15.5.10", "react-color": "^2.11.4", "react-datetime": "^2.8.10", "react-textarea-autosize": "^4.3.0" diff --git a/addons/storyshots/package.json b/addons/storyshots/package.json index d9847fca28ab..81e32b9068f4 100644 --- a/addons/storyshots/package.json +++ b/addons/storyshots/package.json @@ -16,7 +16,7 @@ "dependencies": { "babel-runtime": "^6.23.0", "global": "^4.3.2", - "prop-types": "^15.5.8", + "prop-types": "^15.5.10", "read-pkg-up": "^2.0.0" }, "devDependencies": { diff --git a/addons/storyshots/src/index.js b/addons/storyshots/src/index.js index 6bd2614cb899..42b9f4e10e97 100644 --- a/addons/storyshots/src/index.js +++ b/addons/storyshots/src/index.js @@ -3,18 +3,16 @@ import global, { describe, it } from 'global'; import readPkgUp from 'read-pkg-up'; import addons from '@storybook/addons'; -import runWithRequireContext from './require_context'; import createChannel from './storybook-channel-mock'; import { snapshot } from './test-bodies'; export { snapshotWithOptions, snapshot, shallowSnapshot, renderOnly } from './test-bodies'; -let storybook; +let getStorybook; +let configOutput; let configPath; global.STORYBOOK_REACT_CLASSES = global.STORYBOOK_REACT_CLASSES || {}; -const babel = require('babel-core'); - const pkg = readPkgUp.sync().pkg; const hasDependency = name => @@ -29,36 +27,40 @@ export default function testStorySnapshots(options = {}) { options.framework === 'react-native' || hasDependency('@storybook/react-native'); if (isStorybook) { - storybook = require.requireActual('@storybook/react'); + getStorybook = require.requireActual('@storybook/react').getStorybook; // eslint-disable-next-line - const loadBabelConfig = require('@storybook/react/dist/server/babel_config') - .default; + // const loadBabelConfig = require('@storybook/react/dist/server/babel_config').default; const configDirPath = path.resolve(options.configPath || '.storybook'); configPath = path.join(configDirPath, 'config.js'); - const babelConfig = loadBabelConfig(configDirPath); - const content = babel.transformFileSync(configPath, babelConfig).code; - const contextOpts = { - filename: configPath, - dirname: configDirPath, - }; + // const babelConfig = loadBabelConfig(configDirPath); + // const content = babel.transformFileSync(configPath, babelConfig).code; + // const contextOpts = { + // filename: configPath, + // dirname: configDirPath, + // }; - runWithRequireContext(content, contextOpts); + // runWithRequireContext(content, contextOpts); + configOutput = require.requireActual(configPath); } else if (isRNStorybook) { - storybook = require.requireActual('@storybook/react-native'); + getStorybook = require.requireActual('@storybook/react-native').getStorybook; configPath = path.resolve(options.configPath || 'storybook'); - require.requireActual(configPath); + configOutput = require.requireActual(configPath); } else { throw new Error('storyshots is intended only to be used with storybook'); } if (typeof describe !== 'function') { - throw new Error('testStorySnapshots is intended only to be used inside jest'); + throw new Error('storyshots is intended only to be used inside jest'); + } + + if (typeof configOutput.default === 'function') { + getStorybook = configOutput.default; } // NOTE: keep `suit` typo for backwards compatibility const suite = options.suite || options.suit || 'Storyshots'; - const stories = storybook.getStorybook(); + const stories = getStorybook(); // Added not to break existing storyshots configs (can be removed in a future major release) // eslint-disable-next-line diff --git a/app/react-native/package.json b/app/react-native/package.json index b585c1a6365b..a86c576b5874 100644 --- a/app/react-native/package.json +++ b/app/react-native/package.json @@ -29,7 +29,7 @@ "@storybook/addons": "^3.1.6", "@storybook/channel-websocket": "^3.1.6", "@storybook/ui": "^3.1.9", - "autoprefixer": "^7.0.1", + "autoprefixer": "^7.1.1", "babel-core": "^6.24.1", "babel-loader": "^7.0.0", "babel-plugin-syntax-async-functions": "^6.13.0", @@ -47,22 +47,22 @@ "babel-runtime": "^6.23.0", "case-sensitive-paths-webpack-plugin": "^2.0.0", "commander": "^2.9.0", - "css-loader": "^0.28.0", + "css-loader": "^0.28.1", "events": "^1.1.1", - "express": "^4.15.2", + "express": "^4.15.3", "file-loader": "^0.11.1", "find-cache-dir": "^1.0.0", "global": "^4.3.2", "json-loader": "^0.5.4", "json5": "^0.5.1", - "postcss-loader": "^2.0.3", + "postcss-loader": "^2.0.5", "shelljs": "^0.7.7", "style-loader": "^0.17.0", "url-loader": "^0.5.8", "util-deprecate": "^1.0.2", - "uuid": "^3.0.1", - "webpack": "^2.4.1", - "webpack-dev-middleware": "^1.10.1", + "uuid": "^3.1.0", + "webpack": "^2.5.1 || ^3.0.0", + "webpack-dev-middleware": "^1.10.2", "webpack-hot-middleware": "^2.18.0", "ws": "^3.0.0" }, diff --git a/app/react/package.json b/app/react/package.json index 3bc5ea8fd681..9dcd1b83838e 100644 --- a/app/react/package.json +++ b/app/react/package.json @@ -39,7 +39,7 @@ "babel-preset-stage-0": "^6.24.1", "babel-runtime": "^6.23.0", "case-sensitive-paths-webpack-plugin": "^2.0.0", - "chalk": "^1.1.3", + "chalk": "^2.0.1", "commander": "^2.9.0", "common-tags": "^1.4.0", "configstore": "^3.1.0", @@ -67,7 +67,7 @@ "style-loader": "^0.17.0", "url-loader": "^0.5.8", "util-deprecate": "^1.0.2", - "uuid": "^3.0.1", + "uuid": "^3.1.0", "webpack": "^2.5.1 || ^3.0.0", "webpack-dev-middleware": "^1.10.2", "webpack-hot-middleware": "^2.18.0" diff --git a/examples/cra-kitchen-sink/.storybook/config.js b/examples/cra-kitchen-sink/.storybook/config.js index 7e57d3f7fef0..63f258fcbe98 100644 --- a/examples/cra-kitchen-sink/.storybook/config.js +++ b/examples/cra-kitchen-sink/.storybook/config.js @@ -1,4 +1,4 @@ -import { configure, setAddon } from '@storybook/react'; +import { configure, setAddon, getStorybook } from '@storybook/react'; import { setOptions } from '@storybook/addon-options'; import infoAddon from '@storybook/addon-info'; @@ -20,3 +20,5 @@ function loadStories() { } configure(loadStories, module); + +export { getStorybook as default }; diff --git a/examples/cra-kitchen-sink/package.json b/examples/cra-kitchen-sink/package.json index 12e29d108e2f..813526b757cf 100644 --- a/examples/cra-kitchen-sink/package.json +++ b/examples/cra-kitchen-sink/package.json @@ -16,7 +16,7 @@ "prop-types": "^15.5.10", "react": "^15.5.4", "react-dom": "^15.5.4", - "uuid": "^3.0.1" + "uuid": "^3.1.0" }, "devDependencies": { "@storybook/addon-actions": "^3.0.0", diff --git a/examples/cra-kitchen-sink/src/__snapshots__/storyshots.test.js.snap b/examples/cra-kitchen-sink/src/__snapshots__/storyshots.test.js.snap new file mode 100644 index 000000000000..b80b1bbad5d9 --- /dev/null +++ b/examples/cra-kitchen-sink/src/__snapshots__/storyshots.test.js.snap @@ -0,0 +1,613 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Storyshots App full app 1`] = ` +
+
+ logo +

+ Welcome to React +

+
+

+ To get started, edit + + src/App.js + + and save to reload. +

+
+`; + +exports[`Storyshots Button with knobs 1`] = ` +
+

+ My name is Storyteller, I'm 70 years old, and my favorite fruit is apple. +

+

+ My birthday is: + 2017-1-20 +

+

+ My wallet contains: $ + 12.50 +

+

+ In my backpack, I have: +

+
    +
  • + Laptop +
  • +
  • + Book +
  • +
  • + Whiskey +
  • +
+

+ Nice to meet you! +

+
+`; + +exports[`Storyshots Button with notes 1`] = ` + +`; + +exports[`Storyshots Button with some emoji 1`] = ` + +`; + +exports[`Storyshots Button with some info 1`] = ` +
+
+ +
+ + Show Info + +
+ + × + +
+
+
+

+ Button +

+

+ with some info +

+
+
+

+ Use the + + info addon + + with its painful API. +

+
+
+

+ Story Source +

+
+            
+
+ + < + Button + + + + > + +
+
+ + click the "?" in top right for info + +
+
+ + </ + Button + > + +
+
+
+
+
+

+ Prop Types +

+
+

+ " + Button + " Component +

+ + + + + + + + + + + + + + + + + + + + + + + + +
+ property + + propType + + required + + default + + description +
+ children + + node + + yes + + - + +
+ onClick + + func + + no + + - + +
+
+
+
+
+
+
+`; + +exports[`Storyshots Button with text 1`] = ` + +`; + +exports[`Storyshots Centered Button with text 1`] = ` +
+
+ +
+
+`; + +exports[`Storyshots Welcome to Storybook 1`] = ` +
+

+ Welcome to storybook +

+

+ This is a UI component dev environment for your app. +

+

+ We've added some basic stories inside the + + + src/stories + + + directory. +
+ A story is a single state of one or more UI components. You can have as many stories as you want. +
+ (Basically a story is like a visual test case.) +

+

+ See these sample + + + stories + + + for a component called + + + Button + + . +

+

+ Just like that, you can add your own components as stories. +
+ You can also edit those components and see changes right away. +
+ (Try editing the + + Button + + stories located at + + src/stories/index.js + + .) +

+

+ Usually we create stories with smaller UI components in the app. +
+ Have a look at the + + + Writing Stories + + + section in our documentation. +

+

+ + NOTE: + +
+ Have a look at the + + + .storybook/webpack.config.js + + + to add webpack loaders and plugins you are using in this project. +

+
+`; + +exports[`Storyshots WithEvents Logger 1`] = ` +
+

+ Logger +

+
+
+`; diff --git a/examples/cra-kitchen-sink/src/storyshots.test.js b/examples/cra-kitchen-sink/src/storyshots.test.js index dd3bc52975ca..51cce11163f0 100644 --- a/examples/cra-kitchen-sink/src/storyshots.test.js +++ b/examples/cra-kitchen-sink/src/storyshots.test.js @@ -1,30 +1,17 @@ -describe('Storyshots', () => { - xit('should run snapshot tests, but we\'ve disabled this temporarily', () => {}); -}); +import initStoryshots, { snapshotWithOptions } from '@storybook/addon-storyshots'; +import path from 'path'; + +function createNodeMock(element) { + if (element.type === 'div') { + return { scrollWidth: 123 }; + } + return null; +} -// NOTE: this file should contain a snapshot test, but it is temporarily disabled. -// -// From @tmeasday: "Both Lerna/npm5 and Jest are incompatible, so we cannot run -// Jest tests right now, unless we go to great lengths (see `test-cra`'s build process)." -// -// A succinct repro here: https://github.com/tmeasday/preserve-symlinks-test -// -// Once this difference is resolved, we should uncomment the following code: -// -// import initStoryshots, { snapshotWithOptions } from '@storybook/addon-storyshots'; -// import path from 'path'; -// -// function createNodeMock(element) { -// if (element.type === 'div') { -// return { scrollWidth: 123 }; -// } -// return null; -// } -// -// initStoryshots({ -// framework: 'react', -// configPath: path.join(__dirname, '..', '.storybook'), -// test: snapshotWithOptions({ -// createNodeMock, -// }), -// }); +initStoryshots({ + framework: 'react', + configPath: path.join(__dirname, '..', '.storybook'), + test: snapshotWithOptions({ + createNodeMock, + }), +}); diff --git a/examples/test-cra/package.json b/examples/test-cra/package.json index 4f16d82bad88..b83ca58fd5cc 100644 --- a/examples/test-cra/package.json +++ b/examples/test-cra/package.json @@ -19,7 +19,6 @@ "devDependencies": { "@storybook/addon-actions": "file:../../packs/storybook-addon-actions.tgz", "@storybook/addon-links": "file:../../packs/storybook-addon-links.tgz", - "@storybook/addon-storyshots": "file:../../packs/storybook-addon-storyshots.tgz", "@storybook/addons": "file:../../packs/storybook-addons.tgz", "@storybook/channel-postmessage": "file:../../packs/storybook-channel-postmessage.tgz", "@storybook/channels": "file:../../packs/storybook-channels.tgz", diff --git a/examples/test-cra/src/__snapshots__/storyshots.test.js.snap b/examples/test-cra/src/__snapshots__/storyshots.test.js.snap deleted file mode 100644 index 142cc1e87e51..000000000000 --- a/examples/test-cra/src/__snapshots__/storyshots.test.js.snap +++ /dev/null @@ -1,124 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots Button with some emoji 1`] = ` - -`; - -exports[`Storyshots Button with text 1`] = ` - -`; - -exports[`Storyshots ComponentWithRef basic 1`] = `
`; - -exports[`Storyshots Welcome to Storybook 1`] = ` -
-

- Welcome to storybook -

-

- This is a UI component dev environment for your app. -

-

- We've added some basic stories inside the - - - src/stories - - - directory. -
- A story is a single state of one or more UI components. You can have as many stories as you want. -
- (Basically a story is like a visual test case.) -

-

- See these sample - - - stories - - - for a component called - - - Button - - . -

-

- Just like that, you can add your own components as stories. -
- You can also edit those components and see changes right away. -
- (Try editing the - - Button - - stories located at - - src/stories/index.js - - .) -

-

- Usually we create stories with smaller UI components in the app. -
- Have a look at the - - - Writing Stories - - - section in our documentation. -

-

- - NOTE: - -
- Have a look at the - - - .storybook/webpack.config.js - - - to add webpack loaders and plugins you are using in this project. -

-
-`; diff --git a/examples/test-cra/src/storyshots.test.js b/examples/test-cra/src/storyshots.test.js deleted file mode 100644 index 51cce11163f0..000000000000 --- a/examples/test-cra/src/storyshots.test.js +++ /dev/null @@ -1,17 +0,0 @@ -import initStoryshots, { snapshotWithOptions } from '@storybook/addon-storyshots'; -import path from 'path'; - -function createNodeMock(element) { - if (element.type === 'div') { - return { scrollWidth: 123 }; - } - return null; -} - -initStoryshots({ - framework: 'react', - configPath: path.join(__dirname, '..', '.storybook'), - test: snapshotWithOptions({ - createNodeMock, - }), -}); diff --git a/lerna.json b/lerna.json index 6f821b56958f..23e2f461f21d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "lerna": "2.0.0-rc.5", + "lerna": "2.0.0", "commands": { "bootstrap": { "ignore": [ diff --git a/lib/addons/src/index.js b/lib/addons/src/index.js index f1169d27cd92..0b2bbfeb83cc 100644 --- a/lib/addons/src/index.js +++ b/lib/addons/src/index.js @@ -2,7 +2,7 @@ export class AddonStore { constructor() { this.loaders = {}; this.panels = {}; - this.channel = null; + this.channel = { on() {}, emit() {} }; this.preview = null; this.database = null; } diff --git a/lib/cli/package.json b/lib/cli/package.json index 96be6b0d1a5a..91091fe92b07 100644 --- a/lib/cli/package.json +++ b/lib/cli/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@storybook/codemod": "^3.1.6", - "chalk": "^1.1.3", + "chalk": "^2.0.1", "child-process-promise": "^2.2.1", "commander": "^2.9.0", "cross-spawn": "^5.0.1", diff --git a/lib/ui/package.json b/lib/ui/package.json index d1592bea0fcc..931ca2109de2 100644 --- a/lib/ui/package.json +++ b/lib/ui/package.json @@ -26,11 +26,11 @@ "lodash.sortby": "^4.7.0", "mantra-core": "^1.7.0", "podda": "^1.2.2", - "prop-types": "^15.5.8", + "prop-types": "^15.5.10", "qs": "^6.4.0", - "react-inspector": "^2.0.0", + "react-inspector": "^2.1.1", "react-komposer": "^2.0.0", - "react-modal": "^1.7.6", + "react-modal": "^1.7.7", "react-split-pane": "^0.1.63", "redux": "^3.6.0" }, diff --git a/package.json b/package.json index b64637b4892f..e34e55bcfd05 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,16 @@ { "name": "storybook", + "version": "3.0.0", "repository": { "type": "git", "url": "https://github.com/storybooks/storybook.git" }, "scripts": { - "bootstrap": "lerna bootstrap", - "bootstrap:docs": "cd docs && npmc install", - "bootstrap:test-cra": "npm run build-packs && lerna exec --scope test-cra -- npmc install", - "bootstrap:react-native-vanilla": "lerna exec --scope react-native-vanilla -- npmc install", + "bootstrap": "lerna bootstrap --concurrency 1 --npm-client=\"yarn\" --hoist && node ./scripts/hoist-internals.js", + "bootstrap:docs": "cd docs && yarn install", + "bootstrap:react-native-vanilla": "lerna exec --scope react-native-vanilla -- yarn install", + "bootstrap:test-cra": "npm run build-packs && lerna exec --scope test-cra -- yarn install", + "build": "npm run bootstrap:docs && npm run docs:build", "build-packs": "lerna exec --scope '@storybook/*' --parallel -- ../../scripts/build-pack.sh ../../packs", "changelog": "pr-log --sloppy", "precommit": "lint-staged", @@ -25,15 +27,14 @@ "lint:js": "eslint . --cache --cache-location=.cache/eslint --ext .js,.jsx,.json", "lint:md": "remark .", "publish": "lerna publish", + "start": "serve ./docs/out --single", "test": "jest --projects ./ ./examples/react-native-vanilla" }, - "engines": { - "node": "node" - }, "devDependencies": { "babel-cli": "^6.24.1", "babel-core": "^6.24.1", "babel-eslint": "^7.2.3", + "babel-plugin-transform-md-import-to-string": "^1.0.6", "babel-plugin-transform-runtime": "^6.23.0", "babel-polyfill": "^6.23.0", "babel-preset-env": "^1.5.1", @@ -52,15 +53,16 @@ "eslint-plugin-jsx-a11y": "^5.0.3", "eslint-plugin-prettier": "^2.1.1", "eslint-plugin-react": "^7.0.1", + "fs-extra": "^4.0.0", "gh-pages": "^1.0.0", "github-release-from-changelog": "^1.2.1", + "glob": "^7.1.2", "husky": "^0.14.3", "jest": "^20.0.4", "jest-enzyme": "^3.2.0", "lerna": "2.0.0", "lint-staged": "^4.0.0", "nodemon": "^1.11.0", - "npmc": "^5.1.0-canary.2", "prettier": "^1.5.2", "react": "^15.5.4", "react-dom": "^15.5.4", @@ -71,7 +73,11 @@ "remark-lint-code-eslint": "^2.0.0", "remark-preset-lint-recommended": "^2.0.0", "remark-toc": "^4.0.0", - "shelljs": "^0.7.7" + "shelljs": "^0.7.7", + "symlink-dir": "^1.1.0" + }, + "engines": { + "node": "node" }, "collective": { "type": "opencollective", @@ -82,6 +88,10 @@ "npm run lint:js -- --fix", "git add" ], + "*.json": [ + "npm run lint:js -- --fix", + "git add" + ], "*.md": [ "npm run lint:md -- -o", "git add" diff --git a/scripts/hoist-internals.js b/scripts/hoist-internals.js new file mode 100644 index 000000000000..2b92685196ca --- /dev/null +++ b/scripts/hoist-internals.js @@ -0,0 +1,74 @@ +const path = require('path'); +const fs = require('fs-extra'); +const fse = require('fs-extra'); +const shell = require('shelljs'); +const chalk = require('chalk'); +const glob = require('glob'); +const symlink = require('symlink-dir'); + +const targetPath = path.join(__dirname, '..', 'node_modules', '@storybook'); + +const task = fse + .readJson(path.join(__dirname, '..', 'lerna.json')) + .then(json => { + const { packages, lerna } = json; + shell.echo(chalk.gray('\n=> Hoisting internal packages')); + shell.echo(chalk.gray(`\n=> lerna version: ${lerna}`)); + shell.echo(chalk.gray(`\n=> source paths: ${packages.join(', ')}`)); + shell.echo(chalk.gray(`\n=> target path: ${targetPath}`)); + return json; + }) + .then( + ({ packages }) => + new Promise((resolve, reject) => { + const pattern = `@(${packages.map(s => s.replace('/*', '')).join('|')})/*`; + const cwd = path.join(__dirname, '..'); + glob(pattern, { cwd }, (error, results) => (error ? reject(error) : resolve(results))); + }) + ) + .then(results => + Promise.all( + results + .map(sourcePath => path.resolve(fs.realpathSync(sourcePath))) + .map(i => console.log(i) || i) + .reduce((acc, item) => { + if (!acc.includes(item)) { + acc.push(item); + } + return acc; + }, []) + .map(sourcePath => + fse + .readJson(path.join(sourcePath, 'package.json')) + .then(json => json.name.replace('@storybook/', '')) + .then(packageName => { + const localTargetPath = path.join(targetPath, packageName); + return symlink(sourcePath, localTargetPath) + .catch(error => console.log('ERROR symlink', error)) + .then(() => sourcePath); + }) + ) + ) + ) + .then(locations => + Promise.all( + locations + .map(location => { + const removePath = path.join(location, 'node_modules', '@storybook'); + console.log(removePath); + return shell.rm('-rf', removePath); + }) + .map( + (item, index) => + item.code === 0 ? Promise.resolve(locations[index]) : Promise.reject(item) + ) + ) + ); + +task + .then(() => { + shell.echo(chalk.green('COMPLETE'), chalk.gray('=> Hoisting internal packages')); + }) + .catch(() => { + shell.echo(chalk.red('FAIL'), chalk.gray('=> Hoisting internal packages')); + }); From cad2b8d419e85cdb2d5975f9de21a1faf75c4d9c Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 19 Jul 2017 08:21:47 +0200 Subject: [PATCH 3/7] export getStorybook from config --- addons/storyshots/src/index.js | 4 ++-- examples/cra-kitchen-sink/.storybook/config.js | 2 +- examples/react-native-vanilla/storybook/storybook.js | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/addons/storyshots/src/index.js b/addons/storyshots/src/index.js index 42b9f4e10e97..ec944977e71f 100644 --- a/addons/storyshots/src/index.js +++ b/addons/storyshots/src/index.js @@ -54,8 +54,8 @@ export default function testStorySnapshots(options = {}) { throw new Error('storyshots is intended only to be used inside jest'); } - if (typeof configOutput.default === 'function') { - getStorybook = configOutput.default; + if (typeof configOutput.getStorybook === 'function') { + getStorybook = configOutput.getStorybook; } // NOTE: keep `suit` typo for backwards compatibility diff --git a/examples/cra-kitchen-sink/.storybook/config.js b/examples/cra-kitchen-sink/.storybook/config.js index 63f258fcbe98..0d39e829dc43 100644 --- a/examples/cra-kitchen-sink/.storybook/config.js +++ b/examples/cra-kitchen-sink/.storybook/config.js @@ -21,4 +21,4 @@ function loadStories() { configure(loadStories, module); -export { getStorybook as default }; +export { getStorybook }; diff --git a/examples/react-native-vanilla/storybook/storybook.js b/examples/react-native-vanilla/storybook/storybook.js index 9af39a2ee00c..95075cd63ed0 100644 --- a/examples/react-native-vanilla/storybook/storybook.js +++ b/examples/react-native-vanilla/storybook/storybook.js @@ -1,5 +1,5 @@ import { AppRegistry } from 'react-native'; -import { getStorybookUI, configure } from '@storybook/react-native'; +import { getStorybookUI, configure, getStorybook } from '@storybook/react-native'; import { setOptions } from '@storybook/addon-options'; // import stories @@ -19,4 +19,5 @@ setTimeout( ); AppRegistry.registerComponent('ReactNativeVanilla', () => StorybookUI); -export default StorybookUI; + +export { StorybookUI as default, getStorybook }; From 9faced558edbf57e5907102e0ccc0556eb4f3793 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 19 Jul 2017 09:33:10 +0200 Subject: [PATCH 4/7] CI run jest in series && add dummy deploy --- .circleci/config.yml | 13 ++++++++++--- examples/react-native-vanilla/package.json | 2 +- jest.config.js | 1 - 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 25c4fdfe2bbe..65d7fc239439 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -149,16 +149,22 @@ jobs: - run: name: "Bootstrapping" command: | + npm run bootstrap npm run bootstrap:docs npm run bootstrap:test-cra npm run bootstrap:react-native-vanilla - npm run bootstrap - run: name: "Unit testing" command: | - npm run test -- --coverage + npm run test -- --coverage -i npm run coverage - + deploy: + <<: *defaults + steps: + - run: + name: "Deploy" + command: | + echo "TODO" workflows: version: 2 build_accept_deploy: @@ -172,6 +178,7 @@ workflows: - lint - unit-test - deploy: + type: approval requires: - lint - unit-test diff --git a/examples/react-native-vanilla/package.json b/examples/react-native-vanilla/package.json index 643f02744594..1d151031509e 100644 --- a/examples/react-native-vanilla/package.json +++ b/examples/react-native-vanilla/package.json @@ -14,7 +14,7 @@ "devDependencies": { "babel-jest": "20.0.3", "babel-preset-react-native": "1.9.2", - "jest": "20.0.4", + "jest": "^20.0.4", "react-test-renderer": "16.0.0-alpha.6", "@storybook/addon-actions": "file:../../addons/actions", "@storybook/addon-links": "file:../../addons/links", diff --git a/jest.config.js b/jest.config.js index 2f36d438c986..b97bf6bd126c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -14,7 +14,6 @@ module.exports = { '/examples/test-cra', ], testPathIgnorePatterns: ['/node_modules/'], - projects: ['./', './examples/react-native-vanilla'], collectCoverage: false, collectCoverageFrom: [ 'app/**/*.{js,jsx}', From 9469f5da55dac14c4ab25c9c974d399a61102d95 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 19 Jul 2017 17:38:45 +0200 Subject: [PATCH 5/7] REVERT storyshots changes --- addons/storyshots/src/index.js | 38 +++++++++---------- .../cra-kitchen-sink/.storybook/config.js | 4 +- .../storybook/storybook.js | 4 +- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/addons/storyshots/src/index.js b/addons/storyshots/src/index.js index ec944977e71f..6bd2614cb899 100644 --- a/addons/storyshots/src/index.js +++ b/addons/storyshots/src/index.js @@ -3,16 +3,18 @@ import global, { describe, it } from 'global'; import readPkgUp from 'read-pkg-up'; import addons from '@storybook/addons'; +import runWithRequireContext from './require_context'; import createChannel from './storybook-channel-mock'; import { snapshot } from './test-bodies'; export { snapshotWithOptions, snapshot, shallowSnapshot, renderOnly } from './test-bodies'; -let getStorybook; -let configOutput; +let storybook; let configPath; global.STORYBOOK_REACT_CLASSES = global.STORYBOOK_REACT_CLASSES || {}; +const babel = require('babel-core'); + const pkg = readPkgUp.sync().pkg; const hasDependency = name => @@ -27,40 +29,36 @@ export default function testStorySnapshots(options = {}) { options.framework === 'react-native' || hasDependency('@storybook/react-native'); if (isStorybook) { - getStorybook = require.requireActual('@storybook/react').getStorybook; + storybook = require.requireActual('@storybook/react'); // eslint-disable-next-line - // const loadBabelConfig = require('@storybook/react/dist/server/babel_config').default; + const loadBabelConfig = require('@storybook/react/dist/server/babel_config') + .default; const configDirPath = path.resolve(options.configPath || '.storybook'); configPath = path.join(configDirPath, 'config.js'); - // const babelConfig = loadBabelConfig(configDirPath); - // const content = babel.transformFileSync(configPath, babelConfig).code; - // const contextOpts = { - // filename: configPath, - // dirname: configDirPath, - // }; + const babelConfig = loadBabelConfig(configDirPath); + const content = babel.transformFileSync(configPath, babelConfig).code; + const contextOpts = { + filename: configPath, + dirname: configDirPath, + }; - // runWithRequireContext(content, contextOpts); - configOutput = require.requireActual(configPath); + runWithRequireContext(content, contextOpts); } else if (isRNStorybook) { - getStorybook = require.requireActual('@storybook/react-native').getStorybook; + storybook = require.requireActual('@storybook/react-native'); configPath = path.resolve(options.configPath || 'storybook'); - configOutput = require.requireActual(configPath); + require.requireActual(configPath); } else { throw new Error('storyshots is intended only to be used with storybook'); } if (typeof describe !== 'function') { - throw new Error('storyshots is intended only to be used inside jest'); - } - - if (typeof configOutput.getStorybook === 'function') { - getStorybook = configOutput.getStorybook; + throw new Error('testStorySnapshots is intended only to be used inside jest'); } // NOTE: keep `suit` typo for backwards compatibility const suite = options.suite || options.suit || 'Storyshots'; - const stories = getStorybook(); + const stories = storybook.getStorybook(); // Added not to break existing storyshots configs (can be removed in a future major release) // eslint-disable-next-line diff --git a/examples/cra-kitchen-sink/.storybook/config.js b/examples/cra-kitchen-sink/.storybook/config.js index 0d39e829dc43..7e57d3f7fef0 100644 --- a/examples/cra-kitchen-sink/.storybook/config.js +++ b/examples/cra-kitchen-sink/.storybook/config.js @@ -1,4 +1,4 @@ -import { configure, setAddon, getStorybook } from '@storybook/react'; +import { configure, setAddon } from '@storybook/react'; import { setOptions } from '@storybook/addon-options'; import infoAddon from '@storybook/addon-info'; @@ -20,5 +20,3 @@ function loadStories() { } configure(loadStories, module); - -export { getStorybook }; diff --git a/examples/react-native-vanilla/storybook/storybook.js b/examples/react-native-vanilla/storybook/storybook.js index 95075cd63ed0..c6d187825e89 100644 --- a/examples/react-native-vanilla/storybook/storybook.js +++ b/examples/react-native-vanilla/storybook/storybook.js @@ -1,5 +1,5 @@ import { AppRegistry } from 'react-native'; -import { getStorybookUI, configure, getStorybook } from '@storybook/react-native'; +import { getStorybookUI, configure } from '@storybook/react-native'; import { setOptions } from '@storybook/addon-options'; // import stories @@ -20,4 +20,4 @@ setTimeout( AppRegistry.registerComponent('ReactNativeVanilla', () => StorybookUI); -export { StorybookUI as default, getStorybook }; +export { StorybookUI as default }; From f1ae38793976121eb2aceb2396904bc05ed8ebaa Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 19 Jul 2017 17:42:43 +0200 Subject: [PATCH 6/7] CLEANUP junk npm scripts --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index e34e55bcfd05..9be641170392 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "bootstrap:docs": "cd docs && yarn install", "bootstrap:react-native-vanilla": "lerna exec --scope react-native-vanilla -- yarn install", "bootstrap:test-cra": "npm run build-packs && lerna exec --scope test-cra -- yarn install", - "build": "npm run bootstrap:docs && npm run docs:build", "build-packs": "lerna exec --scope '@storybook/*' --parallel -- ../../scripts/build-pack.sh ../../packs", "changelog": "pr-log --sloppy", "precommit": "lint-staged", @@ -27,7 +26,6 @@ "lint:js": "eslint . --cache --cache-location=.cache/eslint --ext .js,.jsx,.json", "lint:md": "remark .", "publish": "lerna publish", - "start": "serve ./docs/out --single", "test": "jest --projects ./ ./examples/react-native-vanilla" }, "devDependencies": { From 3be8c8d5613fef2ce7347065f4e7d74ff12c7c15 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 19 Jul 2017 23:26:21 +0200 Subject: [PATCH 7/7] CLEANUP && improve hoist internals script --- examples/package.json | 15 --- .../scripts/automated-cra-getstorybook.js | 25 ----- package.json | 1 + scripts/hoist-internals.js | 104 ++++++++++++------ 4 files changed, 72 insertions(+), 73 deletions(-) delete mode 100644 examples/package.json delete mode 100755 examples/scripts/automated-cra-getstorybook.js diff --git a/examples/package.json b/examples/package.json deleted file mode 100644 index 53327ed10c59..000000000000 --- a/examples/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@storybook/examples", - "version": "1.0.0", - "description": "A set of examples of how to use storybook, also used for regression testing", - "main": "index.js", - "scripts": { - "test:automated-cra-getstorybook": "node scripts/automated-cra-getstorybook.js" - }, - "license": "ISC", - "dependencies": { - "child-process-promise": "^2.2.1", - "getstorybook": "^1.7.0", - "rimraf": "^2.6.1" - } -} diff --git a/examples/scripts/automated-cra-getstorybook.js b/examples/scripts/automated-cra-getstorybook.js deleted file mode 100755 index 5f850160239e..000000000000 --- a/examples/scripts/automated-cra-getstorybook.js +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env node - -/* eslint-disable */ -/* This is an automated install of create-react-app & getstorybook */ - -const { exec } = require('child-process-promise'); -const rimraf = require('rimraf'); - -const targetFolder = 'automated-cra-getstorybook'; - -const cleanDir = () => new Promise(resolve => rimraf(`./${targetFolder}`, resolve)); - -const craInstaller = () => exec('npm install create-react-app'); -const craBoot = () => exec(`create-react-app ${targetFolder}`); - -const storybookBoot = () => exec(`cd ${targetFolder} && getstorybook`); -const storybookBuild = () => exec(`cd ${targetFolder} && npm run build-storybook`); - -Promise.all([craInstaller(), cleanDir()]) - .then(craBoot) - .then(storybookBoot) - .then(storybookBuild) - .catch(error => { - console.log('rejected: ', error); - }); diff --git a/package.json b/package.json index 9be641170392..8d285c3d4180 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "lerna": "2.0.0", "lint-staged": "^4.0.0", "nodemon": "^1.11.0", + "npmlog": "^4.1.2", "prettier": "^1.5.2", "react": "^15.5.4", "react-dom": "^15.5.4", diff --git a/scripts/hoist-internals.js b/scripts/hoist-internals.js index 2b92685196ca..d178df18df9b 100644 --- a/scripts/hoist-internals.js +++ b/scripts/hoist-internals.js @@ -2,27 +2,46 @@ const path = require('path'); const fs = require('fs-extra'); const fse = require('fs-extra'); const shell = require('shelljs'); -const chalk = require('chalk'); const glob = require('glob'); const symlink = require('symlink-dir'); +const log = require('npmlog'); const targetPath = path.join(__dirname, '..', 'node_modules', '@storybook'); +const prefix = 'hoist-internals'; +const cwd = path.join(__dirname, '..'); -const task = fse - .readJson(path.join(__dirname, '..', 'lerna.json')) - .then(json => { - const { packages, lerna } = json; - shell.echo(chalk.gray('\n=> Hoisting internal packages')); - shell.echo(chalk.gray(`\n=> lerna version: ${lerna}`)); - shell.echo(chalk.gray(`\n=> source paths: ${packages.join(', ')}`)); - shell.echo(chalk.gray(`\n=> target path: ${targetPath}`)); - return json; - }) +log.heading = 'lerna+'; +log.addLevel('success', 3001, { fg: 'green', bold: true }); +log.info(prefix, 'Hoisting internal packages'); + +const getLernaPackages = () => + fse.readJson(path.join(__dirname, '..', 'lerna.json')).then(json => json.packages); +const passingLog = fn => i => { + fn(i); + return i; +}; +const getPackageNameOfFolder = sourcePath => + fse + .readJson(path.join(sourcePath, 'package.json')) + .then(json => json.name.replace('@storybook/', '')); + +const task = getLernaPackages() .then( - ({ packages }) => + passingLog(packages => { + log.verbose(prefix, 'working dir paths: %j', cwd); + log.verbose(prefix, 'source paths: %j', packages); + log.verbose(prefix, 'target paths: %j', targetPath); + }) + ) + .then(packages => `@(${packages.map(s => s.replace('/*', '')).join('|')})/*/`) + .then( + passingLog(pattern => { + log.silly(prefix, 'pattern to look for packages: %j', pattern); + }) + ) + .then( + pattern => new Promise((resolve, reject) => { - const pattern = `@(${packages.map(s => s.replace('/*', '')).join('|')})/*`; - const cwd = path.join(__dirname, '..'); glob(pattern, { cwd }, (error, results) => (error ? reject(error) : resolve(results))); }) ) @@ -30,34 +49,51 @@ const task = fse Promise.all( results .map(sourcePath => path.resolve(fs.realpathSync(sourcePath))) - .map(i => console.log(i) || i) .reduce((acc, item) => { if (!acc.includes(item)) { acc.push(item); } return acc; }, []) + .map( + passingLog(item => { + log.silly(prefix, 'found package path', item); + }) + ) .map(sourcePath => - fse - .readJson(path.join(sourcePath, 'package.json')) - .then(json => json.name.replace('@storybook/', '')) - .then(packageName => { - const localTargetPath = path.join(targetPath, packageName); - return symlink(sourcePath, localTargetPath) - .catch(error => console.log('ERROR symlink', error)) - .then(() => sourcePath); - }) + getPackageNameOfFolder(sourcePath) + .then( + passingLog(packageName => { + log.silly(prefix, 'found package name', packageName); + }) + ) + .then(packageName => path.join(targetPath, packageName)) + .then(localTargetPath => + symlink(sourcePath, localTargetPath) + .then( + passingLog(() => { + log.silly(prefix, 'symlinked ', [sourcePath, localTargetPath]); + }) + ) + .then(() => localTargetPath) + .catch(error => { + log.error(prefix, 'symlink', error); + throw new Error('failed symlink'); + }) + ) ) ) ) .then(locations => Promise.all( locations - .map(location => { - const removePath = path.join(location, 'node_modules', '@storybook'); - console.log(removePath); - return shell.rm('-rf', removePath); - }) + .map(location => path.join(location, 'node_modules', '@storybook')) + .map( + passingLog(removePath => { + log.verbose(prefix, 'removing ', removePath); + }) + ) + .map(removePath => shell.rm('-rf', removePath)) .map( (item, index) => item.code === 0 ? Promise.resolve(locations[index]) : Promise.reject(item) @@ -66,9 +102,11 @@ const task = fse ); task - .then(() => { - shell.echo(chalk.green('COMPLETE'), chalk.gray('=> Hoisting internal packages')); + .then(packages => { + log.info(prefix, packages.map(dir => dir.replace(cwd, '')).join(',\n')); + log.success(prefix, 'complete'); }) - .catch(() => { - shell.echo(chalk.red('FAIL'), chalk.gray('=> Hoisting internal packages')); + .catch(error => { + log.error(prefix, 'failed', error); + shell.exit(1); });