workspace-tools 0.23.1 → 0.24.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.
@@ -0,0 +1,286 @@
1
+ "use strict";
2
+ //
3
+ // Assorted other git utilities
4
+ // (could be split into separate files later if desired)
5
+ //
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.listAllTrackedFiles = exports.getDefaultBranch = exports.parseRemoteBranch = exports.getRemoteBranch = exports.getParentBranch = exports.revertLocalChanges = exports.stageAndCommit = exports.commit = exports.stage = exports.init = exports.getFileAddedHash = exports.getCurrentHash = exports.getShortBranchName = exports.getFullBranchRef = exports.getBranchName = exports.getUserEmail = exports.getRecentCommitMessages = exports.getStagedChanges = exports.getChangesBetweenRefs = exports.getBranchChanges = exports.getChanges = exports.getUnstagedChanges = exports.fetchRemoteBranch = exports.fetchRemote = exports.getUntrackedChanges = void 0;
8
+ const git_1 = require("./git");
9
+ function getUntrackedChanges(cwd) {
10
+ try {
11
+ const results = (0, git_1.git)(["status", "--short"], { cwd });
12
+ if (!results.success || !results.stdout) {
13
+ return [];
14
+ }
15
+ const lines = results.stdout.split(/[\r\n]+/).filter((line) => line);
16
+ const untracked = [];
17
+ for (let i = 0; i < lines.length; i++) {
18
+ const line = lines[i];
19
+ if (line[0] === " " || line[0] === "?") {
20
+ untracked.push(line.substring(3));
21
+ }
22
+ else if (line[0] === "R") {
23
+ i++;
24
+ }
25
+ }
26
+ return untracked;
27
+ }
28
+ catch (e) {
29
+ throw new git_1.GitError(`Cannot gather information about untracked changes`, e);
30
+ }
31
+ }
32
+ exports.getUntrackedChanges = getUntrackedChanges;
33
+ function fetchRemote(remote, cwd) {
34
+ const results = (0, git_1.git)(["fetch", "--", remote], { cwd });
35
+ if (!results.success) {
36
+ throw new git_1.GitError(`Cannot fetch remote "${remote}"`);
37
+ }
38
+ }
39
+ exports.fetchRemote = fetchRemote;
40
+ function fetchRemoteBranch(remote, remoteBranch, cwd) {
41
+ const results = (0, git_1.git)(["fetch", "--", remote, remoteBranch], { cwd });
42
+ if (!results.success) {
43
+ throw new git_1.GitError(`Cannot fetch branch "${remoteBranch}" from remote "${remote}"`);
44
+ }
45
+ }
46
+ exports.fetchRemoteBranch = fetchRemoteBranch;
47
+ /**
48
+ * Gets all the changes that have not been staged yet
49
+ * @param cwd
50
+ */
51
+ function getUnstagedChanges(cwd) {
52
+ try {
53
+ return processGitOutput((0, git_1.git)(["--no-pager", "diff", "--name-only", "--relative"], { cwd }));
54
+ }
55
+ catch (e) {
56
+ throw new git_1.GitError(`Cannot gather information about unstaged changes`, e);
57
+ }
58
+ }
59
+ exports.getUnstagedChanges = getUnstagedChanges;
60
+ function getChanges(branch, cwd) {
61
+ try {
62
+ return processGitOutput((0, git_1.git)(["--no-pager", "diff", "--relative", "--name-only", branch + "..."], { cwd }));
63
+ }
64
+ catch (e) {
65
+ throw new git_1.GitError(`Cannot gather information about changes`, e);
66
+ }
67
+ }
68
+ exports.getChanges = getChanges;
69
+ /**
70
+ * Gets all the changes between the branch and the merge-base
71
+ */
72
+ function getBranchChanges(branch, cwd) {
73
+ return getChangesBetweenRefs(branch, "", [], "", cwd);
74
+ }
75
+ exports.getBranchChanges = getBranchChanges;
76
+ function getChangesBetweenRefs(fromRef, toRef, options, pattern, cwd) {
77
+ try {
78
+ return processGitOutput((0, git_1.git)([
79
+ "--no-pager",
80
+ "diff",
81
+ "--name-only",
82
+ "--relative",
83
+ ...options,
84
+ `${fromRef}...${toRef}`,
85
+ ...(pattern ? ["--", pattern] : []),
86
+ ], { cwd }));
87
+ }
88
+ catch (e) {
89
+ throw new git_1.GitError(`Cannot gather information about change between refs changes (${fromRef} to ${toRef})`, e);
90
+ }
91
+ }
92
+ exports.getChangesBetweenRefs = getChangesBetweenRefs;
93
+ function getStagedChanges(cwd) {
94
+ try {
95
+ return processGitOutput((0, git_1.git)(["--no-pager", "diff", "--relative", "--staged", "--name-only"], { cwd }));
96
+ }
97
+ catch (e) {
98
+ throw new git_1.GitError(`Cannot gather information about staged changes`, e);
99
+ }
100
+ }
101
+ exports.getStagedChanges = getStagedChanges;
102
+ function getRecentCommitMessages(branch, cwd) {
103
+ try {
104
+ const results = (0, git_1.git)(["log", "--decorate", "--pretty=format:%s", `${branch}..HEAD`], { cwd });
105
+ if (!results.success) {
106
+ return [];
107
+ }
108
+ return results.stdout.split(/\n/).map((line) => line.trim());
109
+ }
110
+ catch (e) {
111
+ throw new git_1.GitError(`Cannot gather information about recent commits`, e);
112
+ }
113
+ }
114
+ exports.getRecentCommitMessages = getRecentCommitMessages;
115
+ function getUserEmail(cwd) {
116
+ try {
117
+ const results = (0, git_1.git)(["config", "user.email"], { cwd });
118
+ return results.success ? results.stdout : null;
119
+ }
120
+ catch (e) {
121
+ throw new git_1.GitError(`Cannot gather information about user.email`, e);
122
+ }
123
+ }
124
+ exports.getUserEmail = getUserEmail;
125
+ function getBranchName(cwd) {
126
+ try {
127
+ const results = (0, git_1.git)(["rev-parse", "--abbrev-ref", "HEAD"], { cwd });
128
+ return results.success ? results.stdout : null;
129
+ }
130
+ catch (e) {
131
+ throw new git_1.GitError(`Cannot get branch name`, e);
132
+ }
133
+ }
134
+ exports.getBranchName = getBranchName;
135
+ function getFullBranchRef(branch, cwd) {
136
+ const showRefResults = (0, git_1.git)(["show-ref", "--heads", branch], { cwd });
137
+ return showRefResults.success ? showRefResults.stdout.split(" ")[1] : null;
138
+ }
139
+ exports.getFullBranchRef = getFullBranchRef;
140
+ function getShortBranchName(fullBranchRef, cwd) {
141
+ const showRefResults = (0, git_1.git)(["name-rev", "--name-only", fullBranchRef], {
142
+ cwd,
143
+ });
144
+ return showRefResults.success ? showRefResults.stdout : null;
145
+ }
146
+ exports.getShortBranchName = getShortBranchName;
147
+ function getCurrentHash(cwd) {
148
+ try {
149
+ const results = (0, git_1.git)(["rev-parse", "HEAD"], { cwd });
150
+ return results.success ? results.stdout : null;
151
+ }
152
+ catch (e) {
153
+ throw new git_1.GitError(`Cannot get current git hash`, e);
154
+ }
155
+ }
156
+ exports.getCurrentHash = getCurrentHash;
157
+ /**
158
+ * Get the commit hash in which the file was first added.
159
+ */
160
+ function getFileAddedHash(filename, cwd) {
161
+ const results = (0, git_1.git)(["rev-list", "HEAD", filename], { cwd });
162
+ if (results.success) {
163
+ return results.stdout.trim().split("\n").slice(-1)[0];
164
+ }
165
+ return undefined;
166
+ }
167
+ exports.getFileAddedHash = getFileAddedHash;
168
+ function init(cwd, email, username) {
169
+ (0, git_1.git)(["init"], { cwd });
170
+ const configLines = (0, git_1.git)(["config", "--list"], { cwd }).stdout.split("\n");
171
+ if (!configLines.find((line) => line.includes("user.name"))) {
172
+ if (!username) {
173
+ throw new git_1.GitError("must include a username when initializing git repo");
174
+ }
175
+ (0, git_1.git)(["config", "user.name", username], { cwd });
176
+ }
177
+ if (!configLines.find((line) => line.includes("user.email"))) {
178
+ if (!email) {
179
+ throw new Error("must include a email when initializing git repo");
180
+ }
181
+ (0, git_1.git)(["config", "user.email", email], { cwd });
182
+ }
183
+ }
184
+ exports.init = init;
185
+ function stage(patterns, cwd) {
186
+ try {
187
+ patterns.forEach((pattern) => {
188
+ (0, git_1.git)(["add", pattern], { cwd });
189
+ });
190
+ }
191
+ catch (e) {
192
+ throw new git_1.GitError(`Cannot stage changes`, e);
193
+ }
194
+ }
195
+ exports.stage = stage;
196
+ function commit(message, cwd, options = []) {
197
+ try {
198
+ const commitResults = (0, git_1.git)(["commit", "-m", message, ...options], { cwd });
199
+ if (!commitResults.success) {
200
+ throw new Error(`Cannot commit changes: ${commitResults.stdout} ${commitResults.stderr}`);
201
+ }
202
+ }
203
+ catch (e) {
204
+ throw new git_1.GitError(`Cannot commit changes`, e);
205
+ }
206
+ }
207
+ exports.commit = commit;
208
+ function stageAndCommit(patterns, message, cwd, commitOptions = []) {
209
+ stage(patterns, cwd);
210
+ commit(message, cwd, commitOptions);
211
+ }
212
+ exports.stageAndCommit = stageAndCommit;
213
+ function revertLocalChanges(cwd) {
214
+ const stash = `workspace-tools_${new Date().getTime()}`;
215
+ (0, git_1.git)(["stash", "push", "-u", "-m", stash], { cwd });
216
+ const results = (0, git_1.git)(["stash", "list"]);
217
+ if (results.success) {
218
+ const lines = results.stdout.split(/\n/);
219
+ const foundLine = lines.find((line) => line.includes(stash));
220
+ if (foundLine) {
221
+ const matched = foundLine.match(/^[^:]+/);
222
+ if (matched) {
223
+ (0, git_1.git)(["stash", "drop", matched[0]]);
224
+ return true;
225
+ }
226
+ }
227
+ }
228
+ return false;
229
+ }
230
+ exports.revertLocalChanges = revertLocalChanges;
231
+ function getParentBranch(cwd) {
232
+ const branchName = getBranchName(cwd);
233
+ if (!branchName || branchName === "HEAD") {
234
+ return null;
235
+ }
236
+ const showBranchResult = (0, git_1.git)(["show-branch", "-a"], { cwd });
237
+ if (showBranchResult.success) {
238
+ const showBranchLines = showBranchResult.stdout.split(/\n/);
239
+ const parentLine = showBranchLines.find((line) => line.includes("*") && !line.includes(branchName) && !line.includes("publish_"));
240
+ const matched = parentLine === null || parentLine === void 0 ? void 0 : parentLine.match(/\[(.*)\]/);
241
+ return matched ? matched[1] : null;
242
+ }
243
+ return null;
244
+ }
245
+ exports.getParentBranch = getParentBranch;
246
+ function getRemoteBranch(branch, cwd) {
247
+ const results = (0, git_1.git)(["rev-parse", "--abbrev-ref", "--symbolic-full-name", `${branch}@\{u\}`], { cwd });
248
+ if (results.success) {
249
+ return results.stdout.trim();
250
+ }
251
+ return null;
252
+ }
253
+ exports.getRemoteBranch = getRemoteBranch;
254
+ function parseRemoteBranch(branch) {
255
+ const firstSlashPos = branch.indexOf("/", 0);
256
+ const remote = branch.substring(0, firstSlashPos);
257
+ const remoteBranch = branch.substring(firstSlashPos + 1);
258
+ return {
259
+ remote,
260
+ remoteBranch,
261
+ };
262
+ }
263
+ exports.parseRemoteBranch = parseRemoteBranch;
264
+ /**
265
+ * Gets the default branch based on `git config init.defaultBranch`, falling back to `master`.
266
+ */
267
+ function getDefaultBranch(cwd) {
268
+ const result = (0, git_1.git)(["config", "init.defaultBranch"], { cwd });
269
+ // Default to the legacy 'master' for backwards compat and old git clients
270
+ return result.success ? result.stdout.trim() : "master";
271
+ }
272
+ exports.getDefaultBranch = getDefaultBranch;
273
+ function listAllTrackedFiles(patterns, cwd) {
274
+ const results = (0, git_1.git)(["ls-files", ...patterns], { cwd });
275
+ return results.success ? results.stdout.split(/\n/) : [];
276
+ }
277
+ exports.listAllTrackedFiles = listAllTrackedFiles;
278
+ function processGitOutput(output) {
279
+ if (!output.success) {
280
+ return [];
281
+ }
282
+ return output.stdout
283
+ .split(/\n/)
284
+ .map((line) => line.trim())
285
+ .filter((line) => !!line && !line.includes("node_modules"));
286
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./git";
2
+ export * from "./getDefaultRemote";
3
+ export * from "./getDefaultRemoteBranch";
4
+ export * from "./gitUtilities";
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __exportStar(require("./git"), exports);
14
+ __exportStar(require("./getDefaultRemote"), exports);
15
+ __exportStar(require("./getDefaultRemoteBranch"), exports);
16
+ __exportStar(require("./gitUtilities"), exports);
17
+ // getRepositoryName is not currently exported; could be changed if it would be useful externally
@@ -1,3 +1,8 @@
1
1
  export * from "./createPackageGraph";
2
- import { createDependencyMap } from "./createDependencyMap";
3
- export { createDependencyMap as getDependentMap };
2
+ import { PackageInfos } from "../types/PackageInfo";
3
+ /**
4
+ * @deprecated - use createDependencyMap() instead
5
+ *
6
+ * Gets a map that has the package name as key, and its dependencies as values
7
+ */
8
+ export declare function getDependentMap(packages: PackageInfos): Map<string, Set<string>>;
@@ -13,4 +13,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.getDependentMap = void 0;
14
14
  __exportStar(require("./createPackageGraph"), exports);
15
15
  const createDependencyMap_1 = require("./createDependencyMap");
16
- Object.defineProperty(exports, "getDependentMap", { enumerable: true, get: function () { return createDependencyMap_1.createDependencyMap; } });
16
+ /**
17
+ * @deprecated - use createDependencyMap() instead
18
+ *
19
+ * Gets a map that has the package name as key, and its dependencies as values
20
+ */
21
+ function getDependentMap(packages) {
22
+ return (0, createDependencyMap_1.createDependencyMap)(packages).dependencies;
23
+ }
24
+ exports.getDependentMap = getDependentMap;
@@ -1,7 +1,13 @@
1
+ import { PackageInfo } from "../types/PackageInfo";
1
2
  /**
2
3
  * Create a temp directory containing the given fixture name in a git repo.
3
4
  * Be sure to call `cleanupFixtures()` after all tests to clean up temp directories.
4
5
  */
5
- export declare function setupFixture(fixtureName: string): string;
6
+ export declare function setupFixture(fixtureName?: string): string;
7
+ /**
8
+ * `tmp` is not always reliable about cleanup even with appropriate options, so it's recommended to
9
+ * call this function in `afterAll`.
10
+ */
6
11
  export declare function cleanupFixtures(): void;
7
- export declare function setupLocalRemote(cwd: string, remoteName: string, fixtureName: string): void;
12
+ export declare function setupPackageJson(cwd: string, packageJson?: Partial<PackageInfo>): void;
13
+ export declare function setupLocalRemote(cwd: string, remoteName: string, fixtureName?: string): void;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.setupLocalRemote = exports.cleanupFixtures = exports.setupFixture = void 0;
6
+ exports.setupLocalRemote = exports.setupPackageJson = exports.cleanupFixtures = exports.setupFixture = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const find_up_1 = __importDefault(require("find-up"));
9
9
  const fs_extra_1 = __importDefault(require("fs-extra"));
@@ -13,6 +13,7 @@ const git_1 = require("../git");
13
13
  // So we attempt to use its built-in cleanup mechanisms, but tests should ideally do their own cleanup too.
14
14
  tmp_1.default.setGracefulCleanup();
15
15
  let fixturesRoot;
16
+ // Temp directories are created under tempRoot.name with incrementing numeric sub-directories
16
17
  let tempRoot;
17
18
  let tempNumber = 0;
18
19
  /**
@@ -20,20 +21,23 @@ let tempNumber = 0;
20
21
  * Be sure to call `cleanupFixtures()` after all tests to clean up temp directories.
21
22
  */
22
23
  function setupFixture(fixtureName) {
23
- if (!fixturesRoot) {
24
- fixturesRoot = find_up_1.default.sync("__fixtures__", { cwd: __dirname, type: "directory" });
25
- }
26
- const fixturePath = path_1.default.join(fixturesRoot, fixtureName);
27
- if (!fs_extra_1.default.existsSync(fixturePath)) {
28
- throw new Error(`Couldn't find fixture "${fixtureName}" under "${fixturesRoot}"`);
24
+ let fixturePath;
25
+ if (fixtureName) {
26
+ if (!fixturesRoot) {
27
+ fixturesRoot = find_up_1.default.sync("__fixtures__", { cwd: __dirname, type: "directory" });
28
+ }
29
+ fixturePath = path_1.default.join(fixturesRoot, fixtureName);
30
+ if (!fs_extra_1.default.existsSync(fixturePath)) {
31
+ throw new Error(`Couldn't find fixture "${fixtureName}" under "${fixturesRoot}"`);
32
+ }
29
33
  }
30
34
  if (!tempRoot) {
31
35
  // Create a shared root temp directory for fixture files
32
36
  tempRoot = tmp_1.default.dirSync({ unsafeCleanup: true }); // clean up even if files are left
33
37
  }
34
- const cwd = path_1.default.join(tempRoot.name, String(tempNumber++), fixtureName);
38
+ // Make the directory and git init
39
+ const cwd = path_1.default.join(tempRoot.name, String(tempNumber++), fixtureName || "");
35
40
  fs_extra_1.default.mkdirpSync(cwd);
36
- fs_extra_1.default.copySync(fixturePath, cwd);
37
41
  (0, git_1.init)(cwd, "test@test.email", "test user");
38
42
  // Ensure GPG signing doesn't interfere with tests
39
43
  (0, git_1.gitFailFast)(["config", "commit.gpgsign", "false"], { cwd });
@@ -43,10 +47,18 @@ function setupFixture(fixtureName) {
43
47
  // a 'fixed' value for our tests, regardless of user configuration
44
48
  (0, git_1.gitFailFast)(["symbolic-ref", "HEAD", "refs/heads/main"], { cwd });
45
49
  (0, git_1.gitFailFast)(["config", "init.defaultBranch", "main"], { cwd });
46
- (0, git_1.stageAndCommit)(["."], "test", cwd);
50
+ // Copy and commit the fixture if requested
51
+ if (fixturePath) {
52
+ fs_extra_1.default.copySync(fixturePath, cwd);
53
+ (0, git_1.stageAndCommit)(["."], "test", cwd);
54
+ }
47
55
  return cwd;
48
56
  }
49
57
  exports.setupFixture = setupFixture;
58
+ /**
59
+ * `tmp` is not always reliable about cleanup even with appropriate options, so it's recommended to
60
+ * call this function in `afterAll`.
61
+ */
50
62
  function cleanupFixtures() {
51
63
  if (tempRoot) {
52
64
  tempRoot.removeCallback();
@@ -54,16 +66,21 @@ function cleanupFixtures() {
54
66
  }
55
67
  }
56
68
  exports.cleanupFixtures = cleanupFixtures;
69
+ function setupPackageJson(cwd, packageJson = {}) {
70
+ const pkgJsonPath = path_1.default.join(cwd, "package.json");
71
+ let oldPackageJson;
72
+ if (fs_extra_1.default.existsSync(pkgJsonPath)) {
73
+ oldPackageJson = JSON.parse(fs_extra_1.default.readFileSync(pkgJsonPath, "utf-8"));
74
+ }
75
+ fs_extra_1.default.writeFileSync(pkgJsonPath, JSON.stringify(Object.assign(Object.assign({}, oldPackageJson), packageJson), null, 2));
76
+ }
77
+ exports.setupPackageJson = setupPackageJson;
57
78
  function setupLocalRemote(cwd, remoteName, fixtureName) {
58
79
  // Create a seperate repo and configure it as a remote
59
80
  const remoteCwd = setupFixture(fixtureName);
60
81
  const remoteUrl = remoteCwd.replace(/\\/g, "/");
61
82
  (0, git_1.gitFailFast)(["remote", "add", remoteName, remoteUrl], { cwd });
62
83
  // Configure url in package.json
63
- const pkgJsonPath = path_1.default.join(cwd, "package.json");
64
- const pkgJson = JSON.parse(fs_extra_1.default.readFileSync(pkgJsonPath, "utf-8"));
65
- fs_extra_1.default.writeFileSync(pkgJsonPath, JSON.stringify(Object.assign(Object.assign({}, pkgJson), { repository: {
66
- url: remoteUrl,
67
- } }), null, 2));
84
+ setupPackageJson(cwd, { repository: { url: remoteUrl, type: "git" } });
68
85
  }
69
86
  exports.setupLocalRemote = setupLocalRemote;
@@ -14,11 +14,14 @@ export interface PackageInfo {
14
14
  private?: boolean;
15
15
  group?: string;
16
16
  scripts?: {
17
- [dep: string]: string;
17
+ [scriptName: string]: string;
18
18
  };
19
- [key: string]: string | boolean | string[] | {
20
- [dep: string]: string;
21
- } | undefined;
19
+ repository?: string | {
20
+ type: string;
21
+ url: string;
22
+ directory?: string;
23
+ };
24
+ [key: string]: any;
22
25
  }
23
26
  export interface PackageInfos {
24
27
  [pkgName: string]: PackageInfo;
@@ -50,7 +50,7 @@ exports.getChangedPackagesBetweenRefs = getChangedPackagesBetweenRefs;
50
50
  * @returns string[] of package names that have changed
51
51
  */
52
52
  function getChangedPackages(cwd, target, ignoreGlobs = []) {
53
- const targetBranch = target || (0, git_1.getDefaultRemoteBranch)(undefined, cwd);
53
+ const targetBranch = target || (0, git_1.getDefaultRemoteBranch)({ cwd });
54
54
  let changes = [
55
55
  ...new Set([
56
56
  ...((0, git_1.getUntrackedChanges)(cwd) || []),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workspace-tools",
3
- "version": "0.23.1",
3
+ "version": "0.24.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",