workspace-tools 0.18.4 → 0.19.2

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.
@@ -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.d.ts CHANGED
@@ -1,8 +1,11 @@
1
+ /// <reference types="node" />
2
+ import { SpawnSyncOptions } from "child_process";
1
3
  declare type ProcessOutput = {
2
4
  stderr: string;
3
5
  stdout: string;
4
6
  success: boolean;
5
7
  };
8
+ /** Observes the git operations called from `git()` or `gitFailFast()` */
6
9
  declare type GitObserver = (args: string[], output: ProcessOutput) => void;
7
10
  /**
8
11
  * Adds an observer for the git operations, e.g. for testing
@@ -10,19 +13,13 @@ declare type GitObserver = (args: string[], output: ProcessOutput) => void;
10
13
  */
11
14
  export declare function addGitObserver(observer: GitObserver): void;
12
15
  /**
13
- * Runs git command - use this for read only commands
16
+ * Runs git command - use this for read-only commands
14
17
  */
15
- export declare function git(args: string[], options?: {
16
- cwd: string;
17
- maxBuffer?: number;
18
- }): ProcessOutput;
18
+ export declare function git(args: string[], options?: SpawnSyncOptions): ProcessOutput;
19
19
  /**
20
- * Runs git command - use this for commands that makes changes to the file system
20
+ * Runs git command - use this for commands that make changes to the filesystem
21
21
  */
22
- export declare function gitFailFast(args: string[], options?: {
23
- cwd: string;
24
- maxBuffer?: number;
25
- }): void;
22
+ export declare function gitFailFast(args: string[], options?: SpawnSyncOptions): void;
26
23
  export declare function getUntrackedChanges(cwd: string): string[];
27
24
  export declare function fetchRemote(remote: string, cwd: string): void;
28
25
  export declare function fetchRemoteBranch(remote: string, remoteBranch: string, cwd: string): void;
package/lib/git.js CHANGED
@@ -16,11 +16,11 @@ function gitError(message, e) {
16
16
  return new Error(message);
17
17
  }
18
18
  /**
19
- * A maxBuffer override globally for all git operations
20
- * Bumps up the default to 500MB as opposed to the 1MB
21
- * Override this value with "GIT_MAX_BUFFER" environment variable
19
+ * A global maxBuffer override for all git operations.
20
+ * Bumps up the default to 500MB instead of 1MB.
21
+ * Override this value with the `GIT_MAX_BUFFER` environment variable.
22
22
  */
23
- const MaxBufferOption = process.env.GIT_MAX_BUFFER ? parseInt(process.env.GIT_MAX_BUFFER) : 500 * 1024 * 1024;
23
+ const defaultMaxBuffer = process.env.GIT_MAX_BUFFER ? parseInt(process.env.GIT_MAX_BUFFER) : 500 * 1024 * 1024;
24
24
  const observers = [];
25
25
  let observing;
26
26
  /**
@@ -32,25 +32,15 @@ function addGitObserver(observer) {
32
32
  }
33
33
  exports.addGitObserver = addGitObserver;
34
34
  /**
35
- * Runs git command - use this for read only commands
35
+ * Runs git command - use this for read-only commands
36
36
  */
37
37
  function git(args, options) {
38
- const results = (0, child_process_1.spawnSync)("git", args, Object.assign({ maxBuffer: MaxBufferOption }, options));
39
- let output;
40
- if (results.status === 0) {
41
- output = {
42
- stderr: results.stderr.toString().trimRight(),
43
- stdout: results.stdout.toString().trimRight(),
44
- success: true,
45
- };
46
- }
47
- else {
48
- output = {
49
- stderr: results.stderr.toString().trimRight(),
50
- stdout: results.stdout.toString().trimRight(),
51
- success: false,
52
- };
53
- }
38
+ const results = (0, child_process_1.spawnSync)("git", args, Object.assign({ maxBuffer: defaultMaxBuffer }, options));
39
+ const output = {
40
+ stderr: results.stderr.toString().trimRight(),
41
+ stdout: results.stdout.toString().trimRight(),
42
+ success: results.status === 0
43
+ };
54
44
  // notify observers, flipping the observing bit to prevent infinite loops
55
45
  if (!observing) {
56
46
  observing = true;
@@ -63,7 +53,7 @@ function git(args, options) {
63
53
  }
64
54
  exports.git = git;
65
55
  /**
66
- * Runs git command - use this for commands that makes changes to the file system
56
+ * Runs git command - use this for commands that make changes to the filesystem
67
57
  */
68
58
  function gitFailFast(args, options) {
69
59
  const gitResult = git(args, options);
@@ -85,7 +75,7 @@ function getUntrackedChanges(cwd) {
85
75
  if (changes.length == 0) {
86
76
  return [];
87
77
  }
88
- const lines = changes.split(/\0/).filter((line) => line) || [];
78
+ const lines = changes.split(/[\r\n]+/).filter((line) => line) || [];
89
79
  const untracked = [];
90
80
  for (let i = 0; i < lines.length; i++) {
91
81
  const line = lines[i];
@@ -145,17 +135,12 @@ exports.getChanges = getChanges;
145
135
  * @param cwd
146
136
  */
147
137
  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
- }
138
+ return getChangesBetweenRefs(branch, "", [], "", cwd);
154
139
  }
155
140
  exports.getBranchChanges = getBranchChanges;
156
141
  function getChangesBetweenRefs(fromRef, toRef, options, pattern, cwd) {
157
142
  try {
158
- return processGitOutput(git(["--no-pager", "diff", "--relative", "--name-only", ...options, `${fromRef}...${toRef}`, "--", pattern], {
143
+ return processGitOutput(git(["--no-pager", "diff", "--name-only", "--relative", ...options, `${fromRef}...${toRef}`, ...(pattern ? ["--", pattern] : [])], {
159
144
  cwd,
160
145
  }));
161
146
  }
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.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,6 +10,8 @@
10
10
  "types": "lib/index.d.ts",
11
11
  "scripts": {
12
12
  "build": "tsc",
13
+ "build:docs": "typedoc src/index.ts",
14
+ "release:docs": "typedoc src/index.ts && gh-pages -d docs",
13
15
  "change": "beachball change",
14
16
  "checkchange": "beachball check",
15
17
  "release": "beachball publish -y",
@@ -23,7 +25,8 @@
23
25
  "globby": "^11.0.0",
24
26
  "jju": "^1.4.0",
25
27
  "multimatch": "^4.0.0",
26
- "read-yaml-file": "^2.0.0"
28
+ "read-yaml-file": "^2.0.0",
29
+ "typedoc": "^0.22.15"
27
30
  },
28
31
  "devDependencies": {
29
32
  "@types/git-url-parse": "^9.0.0",
@@ -38,6 +41,7 @@
38
41
  "jest": "^25.0.0",
39
42
  "tmp": "^0.2.1",
40
43
  "ts-jest": "^25.5.1",
41
- "typescript": "^4.5.4"
44
+ "typescript": "^4.5.4",
45
+ "gh-pages": "^3.2.3"
42
46
  }
43
47
  }