Repository: Yoctol/bottender
Pull request #31 (2017-11-21 09:11:34)

Allow cli to skip config validate


Patch:
diff --git a/examples/with-botanalytics/README.md b/examples/with-botanalytics/README.md
new file mode 100644
index 00000000..b11913cf
--- /dev/null
+++ b/examples/with-botanalytics/README.md
@@ -0,0 +1,37 @@
+# With botanalytics
+
+## Install and Run
+
+Download this example or clone [Bottender](https://github.com/Yoctol/bottender).
+
+```
+curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/with-botanalytics
+cd with-botanalytics
+npm install
+npm run dev
+```
+
+## Idea of this example
+
+This example shows how to combine your bot with **bot analytics tool**. In this
+case, we take [botanalytics](https://botanalytics.co/) as an example.
+
+The following code is the main part of this example which demonstrates the way
+to connect your bot with [botanalytics](https://botanalytics.co/). Furthermore,
+it will be better to check [with-express example](../with-express) first.
+
+```js
+const server = createServer(bot, {
+  verifyToken: '__FILL_YOUR_VERIFY_TOKEN_HERE__',
+  webhookMiddleware: botanalyticsMiddleware(bot, {
+    apiToken: '__FILL_YOUR_BOTANALYTICS_TOKEN_HERE__',
+  }),
+});
+```
+
+## Related examples
+
+* [with-chatbase](../with-chatbase)
+* [with-botimize](../with-botimize)
+* [with-express](../with-express)
+* [messenger-hello-world](../messenger-hello-world)
diff --git a/examples/with-botanalytics/botanalyticsMiddleware.js b/examples/with-botanalytics/botanalyticsMiddleware.js
new file mode 100644
index 00000000..621c2713
--- /dev/null
+++ b/examples/with-botanalytics/botanalyticsMiddleware.js
@@ -0,0 +1,26 @@
+const _botanalytics = require('botanalytics');
+
+module.exports = function botanalyticsMiddleware(bot, { apiToken }) {
+  const botanalytics = _botanalytics.FacebookMessenger(apiToken);
+
+  const { client } = bot.connector;
+  const accessToken = client._accessToken;
+  const axios = client.axios;
+
+  // Add a response interceptor
+  axios.interceptors.response.use(response => {
+    const { config } = response;
+    if (/graph\.facebook\.com.*\/me\/messages/.test(config.url)) {
+      const { recipient: { id }, message: { text } } = JSON.parse(config.data);
+
+      botanalytics.logOutgoingMessage({ text }, id, accessToken);
+    }
+    return response;
+  });
+
+  return (req, res, next) => {
+    botanalytics.logIncomingMessage(req.body);
+
+    next();
+  };
+};
diff --git a/examples/with-botanalytics/index.js b/examples/with-botanalytics/index.js
new file mode 100644
index 00000000..7ce0c519
--- /dev/null
+++ b/examples/with-botanalytics/index.js
@@ -0,0 +1,24 @@
+const { MessengerBot } = require('bottender');
+const { createServer } = require('bottender/express');
+
+const botanalyticsMiddleware = require('./botanalyticsMiddleware');
+
+const bot = new MessengerBot({
+  accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  appSecret: '__FILL_YOUR_SECRET_HERE__',
+});
+
+bot.onEvent(async context => {
+  await context.sendText('Hello World');
+});
+
+const server = createServer(bot, {
+  verifyToken: '__FILL_YOUR_VERIFY_TOKEN_HERE__',
+  webhookMiddleware: botanalyticsMiddleware(bot, {
+    apiToken: '__FILL_YOUR_BOTANALYTICS_TOKEN_HERE__',
+  }),
+});
+
+server.listen(5000, () => {
+  console.log('server is running on 5000 port...');
+});
diff --git a/examples/with-botanalytics/package.json b/examples/with-botanalytics/package.json
new file mode 100644
index 00000000..8c986509
--- /dev/null
+++ b/examples/with-botanalytics/package.json
@@ -0,0 +1,13 @@
+{
+  "dependencies": {
+    "botanalytics": "^2.0.2",
+    "bottender": "latest"
+  },
+  "devDependencies": {
+    "nodemon": "^1.11.0"
+  },
+  "scripts": {
+    "dev": "nodemon index.js",
+    "start": "node index.js"
+  }
+}
diff --git a/examples/with-botimize/README.md b/examples/with-botimize/README.md
index b3231148..99faca41 100644
--- a/examples/with-botimize/README.md
+++ b/examples/with-botimize/README.md
@@ -33,5 +33,6 @@ const server = createServer(bot, {
 ## Related examples
 
 * [with-chatbase](../with-chatbase)
+* [with-botanalytics](../with-botanalytics)
 * [with-express](../with-express)
 * [messenger-hello-world](../messenger-hello-world)
diff --git a/examples/with-chatbase/README.md b/examples/with-chatbase/README.md
index 829c6b93..a1b42d44 100644
--- a/examples/with-chatbase/README.md
+++ b/examples/with-chatbase/README.md
@@ -34,5 +34,6 @@ const server = createServer(bot, {
 ## Related examples
 
 * [with-botimize](../with-botimize)
+* [with-botanalytics](../with-botanalytics)
 * [with-express](../with-express)
 * [messenger-hello-world](../messenger-hello-world)
diff --git a/src/cli/providers/sh/help.js b/src/cli/providers/sh/help.js
index 43c2926f..86f5e3ed 100644
--- a/src/cli/providers/sh/help.js
+++ b/src/cli/providers/sh/help.js
@@ -16,6 +16,10 @@ const help = () => {
         init                    Init a bot skeleton
         help                    Show this help
 
+    ${chalk.dim('Configs:')}
+
+        --skip-validate         Skip the config validation
+
     ${chalk.dim('Examples:')}
 
     ${chalk.dim('-')} Init a bot
@@ -30,6 +34,10 @@ const help = () => {
     ${chalk.dim('-')} Manage the Messenger command
 
       ${chalk.cyan('$ bottender messenger webhook set')}
+
+    ${chalk.dim('-')} Skip config validation
+
+      ${chalk.cyan('$ bottender messenger profile set --skip-validate')}
   `);
 };
 
diff --git a/src/cli/shared/getConfig.js b/src/cli/shared/getConfig.js
index d4b70f8a..5f9f1e1c 100644
--- a/src/cli/shared/getConfig.js
+++ b/src/cli/shared/getConfig.js
@@ -4,17 +4,21 @@ import invariant from 'invariant';
 import get from 'lodash/get';
 import importFresh from 'import-fresh';
 import Joi from 'joi';
+import minimist from 'minimist';
 
 import schema from './schema';
 
 const getConfig = (configPath, platform) => {
+  const argv = minimist(process.argv);
   const config = importFresh(path.resolve(configPath));
-  const validateResult = Joi.validate(config, schema, { allowUnknown: true });
-  invariant(
-    !validateResult.error,
-    validateResult.error &&
-      `The config format is not valid. ${validateResult.error.message}`
-  );
+  if (!argv['skip-validate']) {
+    const validateResult = Joi.validate(config, schema, { allowUnknown: true });
+    invariant(
+      !validateResult.error,
+      validateResult.error &&
+        `The config format is not valid. ${validateResult.error.message}`
+    );
+  }
   const result = get(config, platform, undefined);
   invariant(
     result,


Test patch:
diff --git a/src/cli/shared/__tests__/getConfig.spec.js b/src/cli/shared/__tests__/getConfig.spec.js
index 84371095..b44b9f5a 100644
--- a/src/cli/shared/__tests__/getConfig.spec.js
+++ b/src/cli/shared/__tests__/getConfig.spec.js
@@ -57,8 +57,11 @@ const setup = () => {
 
 let getConfig;
 let importFresh;
+let Joi;
+
 beforeEach(() => {
   importFresh = require('import-fresh'); // eslint-disable-line global-require
+  Joi = require('joi'); // eslint-disable-line global-require
   getConfig = require('../getConfig'); // eslint-disable-line global-require
 });
 
@@ -111,3 +114,43 @@ it('read the config file with platform key', () => {
     },
   });
 });
+
+describe('Joi validate', () => {
+  it('should validate as default', () => {
+    const { MOCK_FILE_WITH_PLATFORM } = setup();
+    importFresh.mockReturnValue(MOCK_FILE_WITH_PLATFORM);
+    const configPath = 'bottender.config.js';
+    const platform = 'messenger';
+
+    const spy = jest.spyOn(Joi, 'validate');
+    getConfig(configPath, platform);
+
+    expect(spy).toBeCalled();
+
+    spy.mockReset();
+    spy.mockRestore();
+  });
+
+  it('should pass validate when with `--skip-validate`', () => {
+    const { MOCK_FILE_WITH_PLATFORM } = setup();
+    importFresh.mockReturnValue(MOCK_FILE_WITH_PLATFORM);
+    process.argv = [
+      'node',
+      'cli/index.js',
+      'messenger',
+      'profile',
+      'set',
+      '--skip-validate',
+    ];
+    const configPath = 'bottender.config.js';
+    const platform = 'messenger';
+
+    const spy = jest.spyOn(Joi, 'validate');
+    getConfig(configPath, platform);
+
+    expect(spy).not.toBeCalled();
+
+    spy.mockReset();
+    spy.mockRestore();
+  });
+});