From 765cade2bec7e01a2071a8973a067f0a702d404d Mon Sep 17 00:00:00 2001
From: Dmitry Ivakhnenko <jeetiss@yandex.ru>
Date: Wed, 27 Nov 2019 19:57:47 +0300
Subject: [PATCH] feat: add support for scoped packages (#451)

* add support for scoped and private packages

* simplify scoped package detection

* simplify custom publishComand condition

* ask question about access only for scoped packages

* use serialize-javascript instead of JSON.stringify
---
 packages/shipjs/package.json                  |  1 +
 packages/shipjs/src/flow/setup.js             |  4 +++
 .../shipjs/src/step/setup/addShipConfig.js    | 15 ++++++---
 .../shipjs/src/step/setup/askQuestions.js     | 31 +++++++++++++++++++
 yarn.lock                                     |  5 +++
 5 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/packages/shipjs/package.json b/packages/shipjs/package.json
index f7376102..4fe7f876 100644
--- a/packages/shipjs/package.json
+++ b/packages/shipjs/package.json
@@ -46,6 +46,7 @@
     "inquirer": "7.0.0",
     "mkdirp": "^0.5.1",
     "prettier": "^1.18.2",
+    "serialize-javascript": "^2.1.0",
     "shell-quote": "^1.7.2",
     "shipjs-lib": "0.10.0",
     "temp-write": "4.0.0"
diff --git a/packages/shipjs/src/flow/setup.js b/packages/shipjs/src/flow/setup.js
index 297c3e09..26c2e3a8 100644
--- a/packages/shipjs/src/flow/setup.js
+++ b/packages/shipjs/src/flow/setup.js
@@ -22,11 +22,15 @@ async function setup({ help = false, dir = '.' }) {
     mainVersionFile,
     packagesToBump,
     packagesToPublish,
+    isScoped,
+    isPublic,
   } = await askQuestions({ dir });
   const outputs = [
     addDevDependencies({ dependencies: ['shipjs'], dir }),
     addScriptsToPackageJson({ dir }),
     await addShipConfig({
+      isScoped,
+      isPublic,
       baseBranch,
       releaseBranch,
       useMonorepo,
diff --git a/packages/shipjs/src/step/setup/addShipConfig.js b/packages/shipjs/src/step/setup/addShipConfig.js
index 4c995ac7..fc2a6ce8 100644
--- a/packages/shipjs/src/step/setup/addShipConfig.js
+++ b/packages/shipjs/src/step/setup/addShipConfig.js
@@ -1,11 +1,14 @@
-import runStep from '../runStep';
 import fs from 'fs';
 import path from 'path';
+import serialize from 'serialize-javascript';
+import runStep from '../runStep';
 import { runPrettier } from '../../helper';
 import { info } from '../../color';
 import { print } from '../../util';
 
 export default async ({
+  isScoped,
+  isPublic,
   baseBranch,
   releaseBranch,
   useMonorepo,
@@ -17,6 +20,10 @@ export default async ({
   await runStep({ title: 'Creating ship.config.js' }, async () => {
     const filePath = path.resolve(dir, 'ship.config.js');
     const json = {
+      publishCommand:
+        isScoped && isPublic
+          ? ({ defaultCommand }) => `${defaultCommand} --access public`
+          : undefined,
       mergeStrategy:
         baseBranch === releaseBranch
           ? {
@@ -35,10 +42,8 @@ export default async ({
           }
         : undefined,
     };
-    fs.writeFileSync(
-      filePath,
-      `module.exports = ${JSON.stringify(json, null, 2)};`
-    );
+
+    fs.writeFileSync(filePath, `module.exports = ${serialize(json)};`);
     await runPrettier({ filePath, dir });
 
     return () => {
diff --git a/packages/shipjs/src/step/setup/askQuestions.js b/packages/shipjs/src/step/setup/askQuestions.js
index f1f2f013..e941962a 100644
--- a/packages/shipjs/src/step/setup/askQuestions.js
+++ b/packages/shipjs/src/step/setup/askQuestions.js
@@ -27,6 +27,8 @@ export default async ({ dir }) =>
       packagesToPublish,
     } = await askMonorepo(dir);
 
+    const { isScoped, isPublic } = await askPackageAccess(dir);
+
     return {
       baseBranch,
       releaseBranch,
@@ -37,6 +39,8 @@ export default async ({ dir }) =>
       mainVersionFile,
       packagesToBump,
       packagesToPublish,
+      isScoped,
+      isPublic,
     };
   });
 
@@ -195,6 +199,25 @@ async function askMonorepo(dir) {
   return { useMonorepo, mainVersionFile, packagesToBump, packagesToPublish };
 }
 
+async function askPackageAccess(dir) {
+  const isScoped = isScopedPackage(getJson(dir, 'package.json').name);
+
+  if (!isScoped) {
+    return { isScoped };
+  }
+
+  const { isPublic } = await inquirer.prompt([
+    {
+      type: 'confirm',
+      name: 'isPublic',
+      message: 'Publish public package?',
+      default: true,
+    },
+  ]);
+
+  return { isScoped, isPublic };
+}
+
 function detectMonorepo(dir) {
   if (fs.existsSync(path.resolve(dir, 'lerna.json'))) {
     return true;
@@ -258,3 +281,11 @@ function stringArrayValidator(answer) {
     return errorMessage;
   }
 }
+
+function isScopedPackage(name) {
+  try {
+    return name[0] === '@' && name.indexOf('/') !== -1;
+  } catch (err) {
+    return false;
+  }
+}
diff --git a/yarn.lock b/yarn.lock
index e88f13f3..b56acd54 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7470,6 +7470,11 @@ sentence-case@^2.1.0:
     no-case "^2.2.0"
     upper-case-first "^1.1.2"
 
+serialize-javascript@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.0.tgz#9310276819efd0eb128258bb341957f6eb2fc570"
+  integrity sha512-a/mxFfU00QT88umAJQsNWOnUKckhNCqOl028N48e7wFmo2/EHpTo9Wso+iJJCMrQnmFvcjto5RJdAHEvVhcyUQ==
+
 set-blocking@^2.0.0, set-blocking@~2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"