Repository: atlassian/changesets (ts)

Issue:
When setting `access` - respect package-specific config
I don't explicitly know this doesn't work, but we should validate it's fine, or 'fix' it.

## Problem

Currently `access` is set on all publishes, meaning a repo probably can't have both `public` and `restricted` packages (needs actual verification that this will go wrong as well, but I think it should)

## Proposed Solution

The publish command should check if `publishConfig.access` is set in each workspace's `package.json` and then respect the package config over the changeset config.

Pull request:
Respect per-package package.json publishConfig.access
fixes #193
closes #203 
is combination of #203 and https://github.com/Andarist/changesets/commit/82c83baf019720cb3289cf460df05a4b6e150056

Patch:
diff --git a/.changeset/proud-rings-appear.md b/.changeset/proud-rings-appear.md
new file mode 100644
index 0000000..e4b86a2
--- /dev/null
+++ b/.changeset/proud-rings-appear.md
@@ -0,0 +1,17 @@
+---
+"@changesets/apply-release-plan": patch
+"@changesets/cli": patch
+"@changesets/config": patch
+"get-workspaces": patch
+"@changesets/types": patch
+---
+
+Correctly handle the 'access' flag for packages
+
+Previously, we had access as "public" or "private", access "private" isn't valid. This was a confusing because there are three states for publishing a package:
+
+- `private: true` - the package will not be published to npm (worked)
+- `access: public` - the package will be publicly published to npm (even if it uses a scope) (worked)
+- `access: restricted` - the package will be published to npm, but only visible/accessible by those who are part of the scope. This technically worked, but we were passing the wrong bit of information in.
+
+Now, we pass the correct access options `public` or `restricted`.
diff --git a/.changeset/slow-queens-remember.md b/.changeset/slow-queens-remember.md
new file mode 100644
index 0000000..ce0d8c4
--- /dev/null
+++ b/.changeset/slow-queens-remember.md
@@ -0,0 +1,9 @@
+---
+"@changesets/cli": minor
+---
+
+Respect `publishConfig.access` in workspace package.jsons
+
+Previously, every package in your repository had one 'public' or 'restricted' setting.
+
+Now, if a workspace has `publishConfig.access` in its package.json, we will prioritize it over the global changesets config.
diff --git a/packages/cli/src/commands/publish/publishPackages.ts b/packages/cli/src/commands/publish/publishPackages.ts
index 9a5f74b..44a7306 100644
--- a/packages/cli/src/commands/publish/publishPackages.ts
+++ b/packages/cli/src/commands/publish/publishPackages.ts
@@ -1,5 +1,6 @@
 import semver from "semver";
 import chalk from "chalk";
+import { AccessType } from "@changesets/types";
 import getWorkspaces from "../../utils/getWorkspaces";
 import { Workspace } from "get-workspaces";
 import * as npmUtils from "./npm-utils";
@@ -12,7 +13,7 @@ export default async function publishPackages({
   otp
 }: {
   cwd: string;
-  access: "public" | "private";
+  access: AccessType;
   otp?: string;
 }) {
   const packages = await getWorkspaces({ cwd });
@@ -46,10 +47,11 @@ export default async function publishPackages({
 
 async function publishAPackage(
   pkg: Workspace,
-  access: "public" | "private",
+  access: AccessType,
   twoFactorState: TwoFactorState
 ) {
-  const { name, version } = pkg.config;
+  const { name, version, publishConfig } = pkg.config;
+  const localAccess = publishConfig && publishConfig.access;
   info(
     `Publishing ${chalk.cyan(`"${name}"`)} at ${chalk.green(`"${version}"`)}`
   );
@@ -60,7 +62,7 @@ async function publishAPackage(
     name,
     {
       cwd: publishDir,
-      access
+      access: localAccess || access
     },
     twoFactorState
   );
diff --git a/packages/cli/src/types.ts b/packages/cli/src/types.ts
index f67b714..6e28c95 100644
--- a/packages/cli/src/types.ts
+++ b/packages/cli/src/types.ts
@@ -1,7 +1,9 @@
+import { AccessType } from "@changesets/types";
+
 export type CliOptions = {
   commit?: boolean;
   changelog?: string;
-  access?: "public" | "private";
+  access?: AccessType;
   sinceMaster?: boolean;
   verbose?: boolean;
   output?: string;
diff --git a/packages/config/package.json b/packages/config/package.json
index ec32ac7..6a7b265 100644
--- a/packages/config/package.json
+++ b/packages/config/package.json
@@ -12,6 +12,7 @@
   ],
   "dependencies": {
     "@changesets/errors": "^0.1.0",
+    "@changesets/logger": "^0.0.0",
     "@changesets/types": "^0.3.0",
     "fs-extra": "^7.0.1"
   },
diff --git a/packages/config/schema.json b/packages/config/schema.json
index 85db5bf..2b569fa 100644
--- a/packages/config/schema.json
+++ b/packages/config/schema.json
@@ -44,10 +44,10 @@
       "default": false
     },
     "access": {
-      "enum": ["private", "public"],
+      "enum": ["restricted", "public"],
       "type": "string",
-      "description": "Determines whether changesets should publish packages to the registry publicly or privately",
-      "default": "private"
+      "description": "Determines whether changesets should publish packages to the registry publicly or to a restricted scope",
+      "default": "restricted"
     }
   }
 }
diff --git a/packages/config/src/index.ts b/packages/config/src/index.ts
index a419f4c..d4e4a83 100644
--- a/packages/config/src/index.ts
+++ b/packages/config/src/index.ts
@@ -1,6 +1,7 @@
 import * as fs from "fs-extra";
 import path from "path";
 import { ValidationError } from "@changesets/errors";
+import { warn } from "@changesets/logger";
 import { Config, WrittenConfig, Workspace } from "@changesets/types";
 import packageJson from "../package.json";
 
@@ -11,7 +12,7 @@ export let defaultWrittenConfig = {
   changelog: "@changesets/cli/changelog",
   commit: false,
   linked: [] as ReadonlyArray<ReadonlyArray<string>>,
-  access: "private"
+  access: "restricted"
 } as const;
 
 function getNormalisedChangelogOption(
@@ -55,17 +56,24 @@ export let parse = (
     );
   }
 
+  let normalizedAccess: WrittenConfig["access"] = json.access;
+  if ((json.access as string) === "private") {
+    normalizedAccess = "restricted";
+    warn(
+      'The `access` option is set as "private", but this is actually not a valid value - the correct form is "restricted".'
+    );
+  }
   if (
-    json.access !== undefined &&
-    json.access !== "private" &&
-    json.access !== "public"
+    normalizedAccess !== undefined &&
+    normalizedAccess !== "restricted" &&
+    normalizedAccess !== "public"
   ) {
     messages.push(
       `The \`access\` option is set as ${JSON.stringify(
-        json.access,
+        normalizedAccess,
         null,
         2
-      )} when the only valid values are undefined, "public" or "private"`
+      )} when the only valid values are undefined, "public" or "restricted"`
     );
   }
 
@@ -136,7 +144,9 @@ export let parse = (
         : json.changelog
     ),
     access:
-      json.access === undefined ? defaultWrittenConfig.access : json.access,
+      normalizedAccess === undefined
+        ? defaultWrittenConfig.access
+        : normalizedAccess,
     commit:
       json.commit === undefined ? defaultWrittenConfig.commit : json.commit,
     linked:
diff --git a/packages/get-workspaces/package.json b/packages/get-workspaces/package.json
index f36b65b..d8a41ff 100644
--- a/packages/get-workspaces/package.json
+++ b/packages/get-workspaces/package.json
@@ -7,6 +7,7 @@
   "license": "MIT",
   "repository": "https://github.com/changesets/changesets/tree/master/packages/get-workspaces",
   "dependencies": {
+    "@changesets/types": "^0.3.0",
     "fs-extra": "^7.0.1",
     "globby": "^9.2.0"
   },
diff --git a/packages/get-workspaces/src/index.ts b/packages/get-workspaces/src/index.ts
index c8c1385..6f12d8f 100644
--- a/packages/get-workspaces/src/index.ts
+++ b/packages/get-workspaces/src/index.ts
@@ -5,22 +5,13 @@
 import fs from "fs-extra";
 import path from "path";
 import globby from "globby";
+import { PackageJSON } from "@changesets/types";
 
 type Options = {
   cwd?: string;
   tools?: Array<"yarn" | "bolt" | "root">;
 };
 
-export type PackageJSON = {
-  name: string;
-  version: string;
-  dependencies?: { [key: string]: string };
-  peerDependencies?: { [key: string]: string };
-  devDependencies?: { [key: string]: string };
-  optionalDependencies?: { [key: string]: string };
-  private?: boolean;
-};
-
 export type Workspace = { config: PackageJSON; name: string; dir: string };
 
 export default async function getWorkspaces(
diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts
index baeac70..704cf65 100644
--- a/packages/types/src/index.ts
+++ b/packages/types/src/index.ts
@@ -11,6 +11,8 @@ export type VersionType = "major" | "minor" | "patch";
 
 export type DependencyType = typeof DEPENDENCY_TYPES[number];
 
+export type AccessType = "public" | "restricted";
+
 export type Release = { name: string; type: VersionType };
 
 // This is a release that has been modified to include all relevant information
@@ -41,6 +43,10 @@ export type PackageJSON = {
   peerDependencies?: { [key: string]: string };
   devDependencies?: { [key: string]: string };
   optionalDependencies?: { [key: string]: string };
+  private?: boolean;
+  publishConfig?: {
+    access?: AccessType;
+  };
 };
 
 export type Linked = ReadonlyArray<ReadonlyArray<string>>;
@@ -49,14 +55,14 @@ export type Config = {
   changelog: false | readonly [string, any];
   commit: boolean;
   linked: Linked;
-  access: "public" | "private";
+  access: AccessType;
 };
 
 export type WrittenConfig = {
   changelog?: false | readonly [string, any] | string;
   commit?: boolean;
   linked?: Linked;
-  access?: "public" | "private";
+  access?: AccessType;
 };
 
 export type Workspace = { config: PackageJSON; name: string; dir: string };


Test patch:
diff --git a/packages/apply-release-plan/src/index.test.ts b/packages/apply-release-plan/src/index.test.ts
index 62289ab..e4cdc02 100644
--- a/packages/apply-release-plan/src/index.test.ts
+++ b/packages/apply-release-plan/src/index.test.ts
@@ -40,7 +40,7 @@ class FakeReleasePlan {
       changelog: false,
       commit: false,
       linked: [],
-      access: "private"
+      access: "restricted"
     };
 
     this.changesets = [this.baseChangeset, ...changesets];
@@ -66,7 +66,7 @@ async function testSetup(
       changelog: false,
       commit: false,
       linked: [],
-      access: "private"
+      access: "restricted"
     };
 
   let tempDir = await copyFixtureIntoTempDir(__dirname, fixtureName);
@@ -251,7 +251,7 @@ describe("apply release plan", () => {
         - pkg-b@2.0.0`);
 
       expect(readmeB.trim()).toEqual(outdent`# pkg-b
-      
+
       ## 2.0.0`);
     });
   });
diff --git a/packages/config/src/index.test.ts b/packages/config/src/index.test.ts
index 7758d24..99740de 100644
--- a/packages/config/src/index.test.ts
+++ b/packages/config/src/index.test.ts
@@ -1,6 +1,9 @@
 import fixturez from "fixturez";
 import { read, parse } from "./";
 import jestInCase from "jest-in-case";
+import * as logger from "@changesets/logger";
+
+jest.mock("@changesets/logger");
 
 let f = fixturez(__dirname);
 
@@ -11,7 +14,7 @@ test("read reads the config", async () => {
     linked: [],
     changelog: false,
     commit: true,
-    access: "private"
+    access: "restricted"
   });
 });
 
@@ -19,7 +22,7 @@ let defaults = {
   linked: [],
   changelog: ["@changesets/cli/changelog", null],
   commit: false,
-  access: "private"
+  access: "restricted"
 } as const;
 
 let correctCases = {
@@ -74,11 +77,11 @@ let correctCases = {
   },
   "access private": {
     input: {
-      access: "private"
+      access: "restricted"
     },
     output: {
       ...defaults,
-      access: "private"
+      access: "restricted"
     }
   },
   "access public": {
@@ -153,7 +156,7 @@ The \`changelog\` option is set as [
       unsafeParse({ access: "something" });
     }).toThrowErrorMatchingInlineSnapshot(`
 "Some errors occurred when validating the changesets config:
-The \`access\` option is set as \\"something\\" when the only valid values are undefined, \\"public\\" or \\"private\\""
+The \`access\` option is set as \\"something\\" when the only valid values are undefined, \\"public\\" or \\"restricted\\""
 `);
   });
   test("commit non-boolean", () => {
@@ -212,4 +215,16 @@ The package \\"pkg-a\\" is specified in the \`linked\` option but it is not foun
 The package \\"pkg-a\\" is in multiple sets of linked packages. Packages can only be in a single set of linked packages."
 `);
   });
+  test("access private warns and sets to restricted", () => {
+    let config = unsafeParse({ access: "private" }, []);
+    expect(config).toEqual({
+      linked: [],
+      changelog: ["@changesets/cli/changelog", null],
+      commit: false,
+      access: "restricted"
+    });
+    expect(logger.warn).toBeCalledWith(
+      'The `access` option is set as "private", but this is actually not a valid value - the correct form is "restricted".'
+    );
+  });
 });