workspace-tools 0.18.4 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.json CHANGED
@@ -2,7 +2,22 @@
2
2
  "name": "workspace-tools",
3
3
  "entries": [
4
4
  {
5
- "date": "Wed, 20 Apr 2022 16:48:59 GMT",
5
+ "date": "Thu, 05 May 2022 19:40:19 GMT",
6
+ "tag": "workspace-tools_v0.19.0",
7
+ "version": "0.19.0",
8
+ "comments": {
9
+ "minor": [
10
+ {
11
+ "author": "kchau@microsoft.com",
12
+ "package": "workspace-tools",
13
+ "comment": "adds a new API to allow retrieving a list of packages affected by files and also by git ref range",
14
+ "commit": "8d3b9dd8a8e1831b56a5f1606491be403debcbed"
15
+ }
16
+ ]
17
+ }
18
+ },
19
+ {
20
+ "date": "Wed, 20 Apr 2022 16:49:02 GMT",
6
21
  "tag": "workspace-tools_v0.18.4",
7
22
  "version": "0.18.4",
8
23
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,12 +1,20 @@
1
1
  # Change Log - workspace-tools
2
2
 
3
- This log was last generated on Wed, 20 Apr 2022 16:48:59 GMT and should not be manually modified.
3
+ This log was last generated on Thu, 05 May 2022 19:40:19 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 0.19.0
8
+
9
+ Thu, 05 May 2022 19:40:19 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - adds a new API to allow retrieving a list of packages affected by files and also by git ref range (kchau@microsoft.com)
14
+
7
15
  ## 0.18.4
8
16
 
9
- Wed, 20 Apr 2022 16:48:59 GMT
17
+ Wed, 20 Apr 2022 16:49:02 GMT
10
18
 
11
19
  ### Patches
12
20
 
@@ -122,4 +122,21 @@ describe("getChangedPackages()", () => {
122
122
  // assert
123
123
  expect(changedPkgs).toEqual([]);
124
124
  });
125
+ it("can detect changed packages between two refs", () => {
126
+ // arrange
127
+ const root = (0, setupFixture_1.setupFixture)("monorepo");
128
+ const newFile = path_1.default.join(root, "packages/package-a/footest.txt");
129
+ fs_1.default.writeFileSync(newFile, "hello foo test");
130
+ (0, git_1.git)(["add", newFile], { cwd: root });
131
+ (0, git_1.stageAndCommit)(["packages/package-a/footest.txt"], "test commit in a", root);
132
+ const newFile2 = path_1.default.join(root, "packages/package-b/footest2.txt");
133
+ fs_1.default.writeFileSync(newFile2, "hello foo test");
134
+ (0, git_1.git)(["add", newFile2], { cwd: root });
135
+ (0, git_1.stageAndCommit)(["packages/package-b/footest2.txt"], "test commit in b", root);
136
+ // act
137
+ const changedPkgs = (0, getChangedPackages_1.getChangedPackagesBetweenRefs)(root, "HEAD^1", "HEAD");
138
+ // assert
139
+ expect(changedPkgs).toContain("package-b");
140
+ expect(changedPkgs).not.toContain("package-a");
141
+ });
125
142
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const setupFixture_1 = require("../helpers/setupFixture");
9
+ const getPackagesByFiles_1 = require("../workspaces/getPackagesByFiles");
10
+ describe("getPackagesByFiles()", () => {
11
+ afterAll(() => {
12
+ (0, setupFixture_1.cleanupFixtures)();
13
+ });
14
+ it("can find all packages that contain the files in a monorepo", () => {
15
+ // arrange
16
+ const root = (0, setupFixture_1.setupFixture)("monorepo");
17
+ const newFile = path_1.default.join(root, "packages/package-a/footest.txt");
18
+ fs_1.default.writeFileSync(newFile, "hello foo test");
19
+ // act
20
+ const packages = (0, getPackagesByFiles_1.getPackagesByFiles)(root, ["packages/package-a/footest.txt"]);
21
+ // assert
22
+ expect(packages).toContain("package-a");
23
+ expect(packages).not.toContain("package-b");
24
+ });
25
+ it("can find can ignore changes in a glob pattern", () => {
26
+ // arrange
27
+ const root = (0, setupFixture_1.setupFixture)("monorepo");
28
+ const newFileA = path_1.default.join(root, "packages/package-a/footest.txt");
29
+ fs_1.default.writeFileSync(newFileA, "hello foo test");
30
+ const newFileB = path_1.default.join(root, "packages/package-b/footest.txt");
31
+ fs_1.default.writeFileSync(newFileB, "hello foo test");
32
+ // act
33
+ const packages = (0, getPackagesByFiles_1.getPackagesByFiles)(root, ["packages/package-a/footest.txt", "packages/package-b/footest.txt"], ["packages/package-b/**"]);
34
+ // assert
35
+ expect(packages).toContain("package-a");
36
+ expect(packages).not.toContain("package-b");
37
+ });
38
+ it("can find can handle empty files", () => {
39
+ // arrange
40
+ const root = (0, setupFixture_1.setupFixture)("monorepo");
41
+ // act
42
+ const packages = (0, getPackagesByFiles_1.getPackagesByFiles)(root, []);
43
+ // assert
44
+ expect(packages.length).toBe(0);
45
+ });
46
+ it("can find can handle unrelated files", () => {
47
+ // arrange
48
+ const root = (0, setupFixture_1.setupFixture)("monorepo");
49
+ // act
50
+ const packages = (0, getPackagesByFiles_1.getPackagesByFiles)(root, ["package.json"]);
51
+ // assert
52
+ expect(packages.length).toBe(0);
53
+ });
54
+ });
package/lib/git.js CHANGED
@@ -145,17 +145,12 @@ exports.getChanges = getChanges;
145
145
  * @param cwd
146
146
  */
147
147
  function getBranchChanges(branch, cwd) {
148
- try {
149
- return processGitOutput(git(["--no-pager", "diff", "--name-only", "--relative", branch + "..."], { cwd }));
150
- }
151
- catch (e) {
152
- throw gitError(`Cannot gather information about branch changes`, e);
153
- }
148
+ return getChangesBetweenRefs(branch, "", [], "", cwd);
154
149
  }
155
150
  exports.getBranchChanges = getBranchChanges;
156
151
  function getChangesBetweenRefs(fromRef, toRef, options, pattern, cwd) {
157
152
  try {
158
- return processGitOutput(git(["--no-pager", "diff", "--relative", "--name-only", ...options, `${fromRef}...${toRef}`, "--", pattern], {
153
+ return processGitOutput(git(["--no-pager", "diff", "--name-only", "--relative", ...options, `${fromRef}...${toRef}`, ...(pattern ? ["--", pattern] : [])], {
159
154
  cwd,
160
155
  }));
161
156
  }
package/lib/index.d.ts CHANGED
@@ -14,5 +14,6 @@ export * from "./workspaces/implementations/pnpm";
14
14
  export * from "./workspaces/implementations/rush";
15
15
  export * from "./workspaces/implementations/yarn";
16
16
  export * from "./workspaces/getChangedPackages";
17
+ export * from "./workspaces/getPackagesByFiles";
17
18
  export * from "./workspaces/listOfWorkspacePackageNames";
18
19
  export * from "./workspaces/workspaces";
package/lib/index.js CHANGED
@@ -26,5 +26,6 @@ __exportStar(require("./workspaces/implementations/pnpm"), exports);
26
26
  __exportStar(require("./workspaces/implementations/rush"), exports);
27
27
  __exportStar(require("./workspaces/implementations/yarn"), exports);
28
28
  __exportStar(require("./workspaces/getChangedPackages"), exports);
29
+ __exportStar(require("./workspaces/getPackagesByFiles"), exports);
29
30
  __exportStar(require("./workspaces/listOfWorkspacePackageNames"), exports);
30
31
  __exportStar(require("./workspaces/workspaces"), exports);
@@ -1,3 +1,21 @@
1
+ /**
2
+ * Finds all packages that had been changed between two refs in the repo under cwd
3
+ *
4
+ * executes a "git diff $fromRef...$toRef" to get changes given a merge-base
5
+ *
6
+ * further explanation with the three dots:
7
+ *
8
+ * > git diff [--options] <commit>...<commit> [--] [<path>...]
9
+ * >
10
+ * > This form is to view the changes on the branch containing and up to
11
+ * > the second <commit>, starting at a common ancestor of both
12
+ * > <commit>. "git diff A...B" is equivalent to "git diff
13
+ * > $(git-merge-base A B) B". You can omit any one of <commit>, which
14
+ * > has the same effect as using HEAD instead.
15
+ *
16
+ * @returns string[] of package names that have changed
17
+ */
18
+ export declare function getChangedPackagesBetweenRefs(cwd: string, fromRef: string, toRef?: string, ignoreGlobs?: string[]): string[];
1
19
  /**
2
20
  * Finds all packages that had been changed in the repo under cwd
3
21
  *
@@ -1,13 +1,37 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getChangedPackages = void 0;
3
+ exports.getChangedPackages = exports.getChangedPackagesBetweenRefs = void 0;
7
4
  const git_1 = require("../git");
8
- const getWorkspaces_1 = require("./getWorkspaces");
9
- const multimatch_1 = __importDefault(require("multimatch"));
10
- const path_1 = __importDefault(require("path"));
5
+ const getPackagesByFiles_1 = require("./getPackagesByFiles");
6
+ /**
7
+ * Finds all packages that had been changed between two refs in the repo under cwd
8
+ *
9
+ * executes a "git diff $fromRef...$toRef" to get changes given a merge-base
10
+ *
11
+ * further explanation with the three dots:
12
+ *
13
+ * > git diff [--options] <commit>...<commit> [--] [<path>...]
14
+ * >
15
+ * > This form is to view the changes on the branch containing and up to
16
+ * > the second <commit>, starting at a common ancestor of both
17
+ * > <commit>. "git diff A...B" is equivalent to "git diff
18
+ * > $(git-merge-base A B) B". You can omit any one of <commit>, which
19
+ * > has the same effect as using HEAD instead.
20
+ *
21
+ * @returns string[] of package names that have changed
22
+ */
23
+ function getChangedPackagesBetweenRefs(cwd, fromRef, toRef = "", ignoreGlobs = []) {
24
+ let changes = [
25
+ ...new Set([
26
+ ...((0, git_1.getUntrackedChanges)(cwd) || []),
27
+ ...((0, git_1.getUnstagedChanges)(cwd) || []),
28
+ ...((0, git_1.getChangesBetweenRefs)(fromRef, toRef, [], "", cwd) || []),
29
+ ...((0, git_1.getStagedChanges)(cwd) || []),
30
+ ]),
31
+ ];
32
+ return (0, getPackagesByFiles_1.getPackagesByFiles)(cwd, changes, ignoreGlobs, true);
33
+ }
34
+ exports.getChangedPackagesBetweenRefs = getChangedPackagesBetweenRefs;
11
35
  /**
12
36
  * Finds all packages that had been changed in the repo under cwd
13
37
  *
@@ -26,32 +50,15 @@ const path_1 = __importDefault(require("path"));
26
50
  * @returns string[] of package names that have changed
27
51
  */
28
52
  function getChangedPackages(cwd, target, ignoreGlobs = []) {
29
- const workspaceInfo = (0, getWorkspaces_1.getWorkspaces)(cwd);
30
- target = target || (0, git_1.getDefaultRemoteBranch)(undefined, cwd);
53
+ const targetBranch = target || (0, git_1.getDefaultRemoteBranch)(undefined, cwd);
31
54
  let changes = [
32
55
  ...new Set([
33
56
  ...((0, git_1.getUntrackedChanges)(cwd) || []),
34
57
  ...((0, git_1.getUnstagedChanges)(cwd) || []),
35
- ...((0, git_1.getBranchChanges)(target, cwd) || []),
58
+ ...((0, git_1.getBranchChanges)(targetBranch, cwd) || []),
36
59
  ...((0, git_1.getStagedChanges)(cwd) || []),
37
60
  ]),
38
61
  ];
39
- const ignoreSet = new Set((0, multimatch_1.default)(changes, ignoreGlobs));
40
- changes = changes.filter((change) => !ignoreSet.has(change));
41
- const changeSet = new Set();
42
- for (const change of changes) {
43
- const candidates = workspaceInfo.filter((pkgPath) => change.indexOf(path_1.default.relative(cwd, pkgPath.path).replace(/\\/g, "/")) ===
44
- 0);
45
- if (candidates && candidates.length > 0) {
46
- const found = candidates.reduce((found, item) => {
47
- return found.path.length > item.path.length ? found : item;
48
- }, candidates[0]);
49
- changeSet.add(found.name);
50
- }
51
- else {
52
- return workspaceInfo.map((pkg) => pkg.name);
53
- }
54
- }
55
- return [...changeSet];
62
+ return (0, getPackagesByFiles_1.getPackagesByFiles)(cwd, changes, ignoreGlobs, true);
56
63
  }
57
64
  exports.getChangedPackages = getChangedPackages;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Given a list of files, finds all packages names that contain those files
3
+ *
4
+ * @param workspaceRoot - The root of the workspace
5
+ * @param files - files to search for
6
+ * @param ignoreGlobs - glob patterns to ignore
7
+ * @param returnAllPackagesOnNoMatch - if true, will return all packages if no matches are found
8
+ * @returns package names that have changed
9
+ */
10
+ export declare function getPackagesByFiles(workspaceRoot: string, files: string[], ignoreGlobs?: string[], returnAllPackagesOnNoMatch?: boolean): string[];
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getPackagesByFiles = void 0;
7
+ const multimatch_1 = __importDefault(require("multimatch"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const getWorkspaces_1 = require("./getWorkspaces");
10
+ /**
11
+ * Given a list of files, finds all packages names that contain those files
12
+ *
13
+ * @param workspaceRoot - The root of the workspace
14
+ * @param files - files to search for
15
+ * @param ignoreGlobs - glob patterns to ignore
16
+ * @param returnAllPackagesOnNoMatch - if true, will return all packages if no matches are found
17
+ * @returns package names that have changed
18
+ */
19
+ function getPackagesByFiles(workspaceRoot, files, ignoreGlobs = [], returnAllPackagesOnNoMatch = false) {
20
+ const workspaceInfo = (0, getWorkspaces_1.getWorkspaces)(workspaceRoot);
21
+ const ignoreSet = new Set((0, multimatch_1.default)(files, ignoreGlobs));
22
+ files = files.filter((change) => !ignoreSet.has(change));
23
+ const packages = new Set();
24
+ for (const file of files) {
25
+ const candidates = workspaceInfo.filter((pkgPath) => file.indexOf(path_1.default.relative(workspaceRoot, pkgPath.path).replace(/\\/g, "/")) === 0);
26
+ if (candidates && candidates.length > 0) {
27
+ const found = candidates.reduce((found, item) => {
28
+ return found.path.length > item.path.length ? found : item;
29
+ }, candidates[0]);
30
+ packages.add(found.name);
31
+ }
32
+ else if (returnAllPackagesOnNoMatch) {
33
+ return workspaceInfo.map((pkg) => pkg.name);
34
+ }
35
+ }
36
+ return [...packages];
37
+ }
38
+ exports.getPackagesByFiles = getPackagesByFiles;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workspace-tools",
3
- "version": "0.18.4",
3
+ "version": "0.19.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",