workspace-tools 0.41.5 → 0.41.7

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.
Files changed (60) hide show
  1. package/lib/git/branchRefs.d.ts +36 -0
  2. package/lib/git/branchRefs.js +84 -0
  3. package/lib/git/branchRefs.js.map +1 -0
  4. package/lib/git/config.d.ts +16 -0
  5. package/lib/git/config.js +39 -4
  6. package/lib/git/config.js.map +1 -1
  7. package/lib/git/fetchRemote.d.ts +13 -0
  8. package/lib/git/fetchRemote.js +56 -0
  9. package/lib/git/fetchRemote.js.map +1 -0
  10. package/lib/git/getChanges.d.ts +54 -0
  11. package/lib/git/getChanges.js +138 -0
  12. package/lib/git/getChanges.js.map +1 -0
  13. package/lib/git/getCurrentHash.d.ts +8 -0
  14. package/lib/git/getCurrentHash.js +24 -0
  15. package/lib/git/getCurrentHash.js.map +1 -0
  16. package/lib/git/getDefaultRemote.d.ts +14 -3
  17. package/lib/git/getDefaultRemote.js +92 -53
  18. package/lib/git/getDefaultRemote.js.map +1 -1
  19. package/lib/git/getDefaultRemoteBranch.d.ts +29 -2
  20. package/lib/git/getDefaultRemoteBranch.js +61 -21
  21. package/lib/git/getDefaultRemoteBranch.js.map +1 -1
  22. package/lib/git/getFileAddedHash.d.ts +10 -0
  23. package/lib/git/getFileAddedHash.js +24 -0
  24. package/lib/git/getFileAddedHash.js.map +1 -0
  25. package/lib/git/getFileFromRef.d.ts +11 -0
  26. package/lib/git/getFileFromRef.js +22 -0
  27. package/lib/git/getFileFromRef.js.map +1 -0
  28. package/lib/git/getRecentCommitMessages.d.ts +10 -0
  29. package/lib/git/getRecentCommitMessages.js +27 -0
  30. package/lib/git/getRecentCommitMessages.js.map +1 -0
  31. package/lib/git/getRemotes.d.ts +14 -0
  32. package/lib/git/getRemotes.js +53 -0
  33. package/lib/git/getRemotes.js.map +1 -0
  34. package/lib/git/gitUtilities.d.ts +12 -212
  35. package/lib/git/gitUtilities.js +38 -448
  36. package/lib/git/gitUtilities.js.map +1 -1
  37. package/lib/git/index.d.ts +17 -5
  38. package/lib/git/index.js +123 -17
  39. package/lib/git/index.js.map +1 -1
  40. package/lib/git/init.d.ts +11 -0
  41. package/lib/git/init.js +48 -0
  42. package/lib/git/init.js.map +1 -0
  43. package/lib/git/listAllTrackedFiles.d.ts +12 -0
  44. package/lib/git/listAllTrackedFiles.js +25 -0
  45. package/lib/git/listAllTrackedFiles.js.map +1 -0
  46. package/lib/git/parseRemoteBranch.d.ts +26 -0
  47. package/lib/git/parseRemoteBranch.js +77 -0
  48. package/lib/git/parseRemoteBranch.js.map +1 -0
  49. package/lib/git/revertLocalChanges.d.ts +9 -0
  50. package/lib/git/revertLocalChanges.js +42 -0
  51. package/lib/git/revertLocalChanges.js.map +1 -0
  52. package/lib/git/stageAndCommit.d.ts +21 -0
  53. package/lib/git/stageAndCommit.js +69 -0
  54. package/lib/git/stageAndCommit.js.map +1 -0
  55. package/lib/git/types.d.ts +5 -2
  56. package/lib/git/types.js.map +1 -1
  57. package/lib/workspaces/getCatalogVersion.d.ts +8 -3
  58. package/lib/workspaces/getCatalogVersion.js +9 -3
  59. package/lib/workspaces/getCatalogVersion.js.map +1 -1
  60. package/package.json +1 -1
@@ -2,9 +2,21 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- Object.defineProperty(exports, "getDefaultRemote", {
6
- enumerable: true,
7
- get: function() {
5
+ 0 && (module.exports = {
6
+ _matchRepositoryUrlToRemote: null,
7
+ getDefaultRemote: null
8
+ });
9
+ function _export(target, all) {
10
+ for(var name in all)Object.defineProperty(target, name, {
11
+ enumerable: true,
12
+ get: Object.getOwnPropertyDescriptor(all, name).get
13
+ });
14
+ }
15
+ _export(exports, {
16
+ get _matchRepositoryUrlToRemote () {
17
+ return _matchRepositoryUrlToRemote;
18
+ },
19
+ get getDefaultRemote () {
8
20
  return getDefaultRemote;
9
21
  }
10
22
  });
@@ -12,7 +24,7 @@ const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
12
24
  const _path = /*#__PURE__*/ _interop_require_default(require("path"));
13
25
  const _paths = require("../paths.js");
14
26
  const _getRepositoryName = require("./getRepositoryName.js");
15
- const _git = require("./git.js");
27
+ const _getRemotes = require("./getRemotes.js");
16
28
  function _interop_require_default(obj) {
17
29
  return obj && obj.__esModule ? obj : {
18
30
  default: obj
@@ -30,63 +42,90 @@ function getDefaultRemote(cwdOrOptions) {
30
42
  }
31
43
  log(message);
32
44
  };
33
- const gitRoot = (0, _paths.findGitRoot)(cwd);
34
- let packageJson = {};
35
- const packageJsonPath = _path.default.join(gitRoot, "package.json");
36
- try {
37
- packageJson = JSON.parse(_fs.default.readFileSync(packageJsonPath, "utf8").trim());
38
- } catch {
39
- logOrThrow(`Could not read "${packageJsonPath}"`);
45
+ // Get remote names and URLs via `git config`.
46
+ // In strict mode, it will throw if cwd isn't in a git repo or no remotes are found.
47
+ const remotes = options.remotes || (0, _getRemotes.getRemotes)({
48
+ cwd,
49
+ throwOnError: strict
50
+ });
51
+ if (!Object.keys(remotes).length) {
52
+ // For non-strict, verify cwd is actually in a git repo (throws if not)
53
+ !strict && (0, _paths.findGitRoot)(cwd);
54
+ // It's a git repo with no remotes configured. This should probably always be an error (since
55
+ // subsequent operations which require a remote likely won't work), but to match old behavior,
56
+ // still default to "origin" unless `strict` is true.
57
+ logOrThrow(`No remotes defined in git repo at ${cwd}`);
58
+ log(`Assuming default remote "origin"`);
59
+ return "origin";
40
60
  }
41
- const { repository } = packageJson;
42
- const repositoryUrl = typeof repository === "string" ? repository : repository && repository.url || "";
61
+ // Try to find the repository URL:
62
+ // Try package.json from `cwd` first, since cwd is often the project root in actual usage,
63
+ // and the repository URL should be the same throughout the repo.
64
+ const cwdPackageJsonPath = _path.default.join(cwd, "package.json");
65
+ const hasCwdPackageJson = _fs.default.existsSync(cwdPackageJsonPath);
66
+ let repositoryUrl;
67
+ if (hasCwdPackageJson) {
68
+ // Only try to read this if it exists (will fall back to git root later)
69
+ repositoryUrl = getRepositoryUrlFromPackageJson(cwdPackageJsonPath, logOrThrow);
70
+ }
71
+ let rootPackageJsonPath;
43
72
  if (!repositoryUrl) {
44
- // This is always logged because it's strongly recommended to fix
45
- console.log(`Valid "repository" key not found in "${packageJsonPath}". Consider adding this info for more accurate git remote detection.`);
73
+ // If cwd doesn't have package.json or it doesn't specify a repository, try the git root
74
+ const gitRoot = (0, _paths.findGitRoot)(cwd);
75
+ rootPackageJsonPath = _path.default.join(gitRoot, "package.json");
76
+ if (!hasCwdPackageJson && !_fs.default.existsSync(rootPackageJsonPath)) {
77
+ // no package.json found
78
+ const paths = cwd === gitRoot ? `${cwd}` : `${cwd} or git root ${gitRoot}`;
79
+ logOrThrow(`Could not find package.json under ${paths}`);
80
+ } else if (gitRoot !== cwd) {
81
+ repositoryUrl = getRepositoryUrlFromPackageJson(rootPackageJsonPath, logOrThrow);
82
+ }
46
83
  }
47
- /** Repository full name (owner and repo name) specified in package.json */ const repositoryName = (0, _getRepositoryName.getRepositoryName)(repositoryUrl);
48
- const remotesResult = (0, _git.git)([
49
- "remote",
50
- "-v"
51
- ], {
52
- cwd
53
- });
54
- if (!remotesResult.success) {
55
- logOrThrow(`Could not determine available git remotes under "${cwd}"`);
84
+ if (!repositoryUrl) {
85
+ // This is always logged because it's strongly recommended to fix.
86
+ // Recommend putting it in package.json at cwd if it exists.
87
+ // (if there is no {cwd}/package.json, rootPackageJsonPath is always defined)
88
+ const jsonPath = hasCwdPackageJson ? cwdPackageJsonPath : rootPackageJsonPath;
89
+ console.log(`Valid "repository" key not found in package.json at ${jsonPath}. ` + `Consider adding this info for more accurate git remote detection.`);
90
+ }
91
+ // If a repository URL is found, try to match it with a remote
92
+ const remoteName = repositoryUrl && _matchRepositoryUrlToRemote(repositoryUrl, remotes, logOrThrow);
93
+ if (remoteName) {
94
+ return remoteName;
56
95
  }
57
- /** Mapping from remote URL to full name (owner and repo name) */ const remotes = {};
58
- remotesResult.stdout.split("\n").forEach((line)=>{
59
- const [remoteName, remoteUrl] = line.split(/\s+/);
96
+ // Default to upstream or origin if available, or the first remote otherwise
97
+ const fallback = [
98
+ "upstream",
99
+ "origin"
100
+ ].find((name)=>!!remotes[name]) || Object.keys(remotes)[0];
101
+ log(`Default to remote "${fallback}"`);
102
+ return fallback;
103
+ }
104
+ function _matchRepositoryUrlToRemote(/** repository.url from package.json */ repositoryUrl, /** Mapping from remote name to remote URL */ remotes, logOrThrow = ()=>{}) {
105
+ // Repository full name (owner and repo name) specified in package.json
106
+ const repositoryName = (0, _getRepositoryName.getRepositoryName)(repositoryUrl);
107
+ for (const [remoteName, remoteUrl] of Object.entries(remotes)){
108
+ // There are many possible remote URL formats, so normalize before comparison
60
109
  const remoteRepoName = (0, _getRepositoryName.getRepositoryName)(remoteUrl);
61
- if (remoteRepoName) {
62
- remotes[remoteRepoName] = remoteName;
110
+ if (remoteRepoName === repositoryName) {
111
+ return remoteName;
63
112
  }
64
- });
113
+ }
65
114
  if (repositoryName) {
66
- // If the repository name was found in package.json, check for a matching remote
67
- if (remotes[repositoryName]) {
68
- return remotes[repositoryName];
69
- }
70
115
  // If `strict` is true, and repositoryName is found, there MUST be a matching remote
71
- logOrThrow(`Could not find remote pointing to repository "${repositoryName}".`);
116
+ logOrThrow(`Could not find remote pointing to repository "${repositoryName}"`);
72
117
  }
73
- // Default to upstream or origin if available, or the first remote otherwise
74
- const allRemoteNames = Object.values(remotes);
75
- const fallbacks = [
76
- "upstream",
77
- "origin",
78
- ...allRemoteNames
79
- ];
80
- for (const fallback of fallbacks){
81
- if (allRemoteNames.includes(fallback)) {
82
- log(`Default to remote "${fallback}"`);
83
- return fallback;
84
- }
118
+ }
119
+ /**
120
+ * Read and parse `packageJsonPath` and return the `repository` URL if found.
121
+ * Calls `logOrThrow` if it can't be read or parsed.
122
+ */ function getRepositoryUrlFromPackageJson(packageJsonPath, logOrThrow) {
123
+ try {
124
+ const packageJson = JSON.parse(_fs.default.readFileSync(packageJsonPath, "utf8"));
125
+ const { repository } = packageJson;
126
+ return typeof repository === "string" ? repository : repository?.url;
127
+ } catch {
128
+ logOrThrow(`Could not read ${packageJsonPath}`);
129
+ return undefined;
85
130
  }
86
- // If we get here, no git remotes were found. This should probably always be an error (since
87
- // subsequent operations which require a remote likely won't work), but to match old behavior,
88
- // still default to "origin" unless `strict` is true.
89
- logOrThrow(`Could not find any remotes in git repo at "${gitRoot}".`);
90
- log(`Assuming default remote "origin".`);
91
- return "origin";
92
131
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/git/getDefaultRemote.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { findGitRoot } from \"../paths.js\";\nimport { type PackageInfo } from \"../types/PackageInfo.js\";\nimport { getRepositoryName } from \"./getRepositoryName.js\";\nimport { git } from \"./git.js\";\n\nexport type GetDefaultRemoteOptions = {\n /** Get repository info relative to this directory. */\n cwd: string;\n /**\n * If true, throw an error if remote info can't be found, or if a `repository` is not specified\n * in package.json and no matching remote is found.\n */\n strict?: boolean;\n /** If true, log debug messages about how the remote was chosen */\n verbose?: boolean;\n};\n\n/**\n * Get the name of the default remote: the one matching the `repository` field in package.json.\n * Throws if `options.cwd` is not in a git repo or there's no package.json at the repo root.\n *\n * The order of preference for returned remotes is:\n * 1. If `repository` is defined in package.json, the remote with a matching URL (if `options.strict`\n * is true, throws an error if no matching remote exists)\n * 2. `upstream` if defined\n * 3. `origin` if defined\n * 4. The first defined remote\n * 5. If there are no defined remotes: throws an error if `options.strict` is true; otherwise returns `origin`\n *\n * @returns The name of the inferred default remote.\n */\nexport function getDefaultRemote(options: GetDefaultRemoteOptions): string;\n/** @deprecated Use the object param version */\nexport function getDefaultRemote(cwd: string): string;\nexport function getDefaultRemote(cwdOrOptions: string | GetDefaultRemoteOptions): string {\n const options = typeof cwdOrOptions === \"string\" ? { cwd: cwdOrOptions } : cwdOrOptions;\n const { cwd, strict, verbose } = options;\n\n const log = (message: string) => verbose && console.log(message);\n const logOrThrow = (message: string) => {\n if (strict) {\n throw new Error(message);\n }\n log(message);\n };\n\n const gitRoot = findGitRoot(cwd);\n\n let packageJson: Partial<PackageInfo> = {};\n const packageJsonPath = path.join(gitRoot, \"package.json\");\n try {\n packageJson = JSON.parse(fs.readFileSync(packageJsonPath, \"utf8\").trim());\n } catch {\n logOrThrow(`Could not read \"${packageJsonPath}\"`);\n }\n\n const { repository } = packageJson;\n const repositoryUrl = typeof repository === \"string\" ? repository : (repository && repository.url) || \"\";\n if (!repositoryUrl) {\n // This is always logged because it's strongly recommended to fix\n console.log(\n `Valid \"repository\" key not found in \"${packageJsonPath}\". Consider adding this info for more accurate git remote detection.`\n );\n }\n /** Repository full name (owner and repo name) specified in package.json */\n const repositoryName = getRepositoryName(repositoryUrl);\n\n const remotesResult = git([\"remote\", \"-v\"], { cwd });\n if (!remotesResult.success) {\n logOrThrow(`Could not determine available git remotes under \"${cwd}\"`);\n }\n\n /** Mapping from remote URL to full name (owner and repo name) */\n const remotes: { [remoteRepoUrl: string]: string } = {};\n remotesResult.stdout.split(\"\\n\").forEach((line) => {\n const [remoteName, remoteUrl] = line.split(/\\s+/);\n const remoteRepoName = getRepositoryName(remoteUrl);\n if (remoteRepoName) {\n remotes[remoteRepoName] = remoteName;\n }\n });\n\n if (repositoryName) {\n // If the repository name was found in package.json, check for a matching remote\n if (remotes[repositoryName]) {\n return remotes[repositoryName];\n }\n\n // If `strict` is true, and repositoryName is found, there MUST be a matching remote\n logOrThrow(`Could not find remote pointing to repository \"${repositoryName}\".`);\n }\n\n // Default to upstream or origin if available, or the first remote otherwise\n const allRemoteNames = Object.values(remotes);\n const fallbacks = [\"upstream\", \"origin\", ...allRemoteNames];\n for (const fallback of fallbacks) {\n if (allRemoteNames.includes(fallback)) {\n log(`Default to remote \"${fallback}\"`);\n return fallback;\n }\n }\n\n // If we get here, no git remotes were found. This should probably always be an error (since\n // subsequent operations which require a remote likely won't work), but to match old behavior,\n // still default to \"origin\" unless `strict` is true.\n logOrThrow(`Could not find any remotes in git repo at \"${gitRoot}\".`);\n log(`Assuming default remote \"origin\".`);\n return \"origin\";\n}\n"],"names":["getDefaultRemote","cwdOrOptions","options","cwd","strict","verbose","log","message","console","logOrThrow","Error","gitRoot","findGitRoot","packageJson","packageJsonPath","path","join","JSON","parse","fs","readFileSync","trim","repository","repositoryUrl","url","repositoryName","getRepositoryName","remotesResult","git","success","remotes","stdout","split","forEach","line","remoteName","remoteUrl","remoteRepoName","allRemoteNames","Object","values","fallbacks","fallback","includes"],"mappings":";;;;+BAoCgBA;;;eAAAA;;;2DApCD;6DACE;uBACW;mCAEM;qBACd;;;;;;AA+Bb,SAASA,iBAAiBC,YAA8C;IAC7E,MAAMC,UAAU,OAAOD,iBAAiB,WAAW;QAAEE,KAAKF;IAAa,IAAIA;IAC3E,MAAM,EAAEE,GAAG,EAAEC,MAAM,EAAEC,OAAO,EAAE,GAAGH;IAEjC,MAAMI,MAAM,CAACC,UAAoBF,WAAWG,QAAQF,GAAG,CAACC;IACxD,MAAME,aAAa,CAACF;QAClB,IAAIH,QAAQ;YACV,MAAM,IAAIM,MAAMH;QAClB;QACAD,IAAIC;IACN;IAEA,MAAMI,UAAUC,IAAAA,kBAAW,EAACT;IAE5B,IAAIU,cAAoC,CAAC;IACzC,MAAMC,kBAAkBC,aAAI,CAACC,IAAI,CAACL,SAAS;IAC3C,IAAI;QACFE,cAAcI,KAAKC,KAAK,CAACC,WAAE,CAACC,YAAY,CAACN,iBAAiB,QAAQO,IAAI;IACxE,EAAE,OAAM;QACNZ,WAAW,CAAC,gBAAgB,EAAEK,gBAAgB,CAAC,CAAC;IAClD;IAEA,MAAM,EAAEQ,UAAU,EAAE,GAAGT;IACvB,MAAMU,gBAAgB,OAAOD,eAAe,WAAWA,aAAa,AAACA,cAAcA,WAAWE,GAAG,IAAK;IACtG,IAAI,CAACD,eAAe;QAClB,iEAAiE;QACjEf,QAAQF,GAAG,CACT,CAAC,qCAAqC,EAAEQ,gBAAgB,oEAAoE,CAAC;IAEjI;IACA,yEAAyE,GACzE,MAAMW,iBAAiBC,IAAAA,oCAAiB,EAACH;IAEzC,MAAMI,gBAAgBC,IAAAA,QAAG,EAAC;QAAC;QAAU;KAAK,EAAE;QAAEzB;IAAI;IAClD,IAAI,CAACwB,cAAcE,OAAO,EAAE;QAC1BpB,WAAW,CAAC,iDAAiD,EAAEN,IAAI,CAAC,CAAC;IACvE;IAEA,+DAA+D,GAC/D,MAAM2B,UAA+C,CAAC;IACtDH,cAAcI,MAAM,CAACC,KAAK,CAAC,MAAMC,OAAO,CAAC,CAACC;QACxC,MAAM,CAACC,YAAYC,UAAU,GAAGF,KAAKF,KAAK,CAAC;QAC3C,MAAMK,iBAAiBX,IAAAA,oCAAiB,EAACU;QACzC,IAAIC,gBAAgB;YAClBP,OAAO,CAACO,eAAe,GAAGF;QAC5B;IACF;IAEA,IAAIV,gBAAgB;QAClB,gFAAgF;QAChF,IAAIK,OAAO,CAACL,eAAe,EAAE;YAC3B,OAAOK,OAAO,CAACL,eAAe;QAChC;QAEA,oFAAoF;QACpFhB,WAAW,CAAC,8CAA8C,EAAEgB,eAAe,EAAE,CAAC;IAChF;IAEA,4EAA4E;IAC5E,MAAMa,iBAAiBC,OAAOC,MAAM,CAACV;IACrC,MAAMW,YAAY;QAAC;QAAY;WAAaH;KAAe;IAC3D,KAAK,MAAMI,YAAYD,UAAW;QAChC,IAAIH,eAAeK,QAAQ,CAACD,WAAW;YACrCpC,IAAI,CAAC,mBAAmB,EAAEoC,SAAS,CAAC,CAAC;YACrC,OAAOA;QACT;IACF;IAEA,4FAA4F;IAC5F,8FAA8F;IAC9F,qDAAqD;IACrDjC,WAAW,CAAC,2CAA2C,EAAEE,QAAQ,EAAE,CAAC;IACpEL,IAAI,CAAC,iCAAiC,CAAC;IACvC,OAAO;AACT"}
1
+ {"version":3,"sources":["../../src/git/getDefaultRemote.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { findGitRoot } from \"../paths.js\";\nimport { type PackageInfo } from \"../types/PackageInfo.js\";\nimport { getRepositoryName } from \"./getRepositoryName.js\";\nimport { getRemotes } from \"./getRemotes.js\";\n\nexport type GetDefaultRemoteOptions = {\n /** Get repository info relative to this directory. */\n cwd: string;\n /**\n * If true, throw an error if remote info can't be found, if no `package.json` is found, or if\n * a `repository` is specified in package.json but no matching remote exists.\n */\n strict?: boolean;\n /** If true, log debug messages about how the remote was chosen */\n verbose?: boolean;\n /** Optional pre-fetched mapping from remote name to remote URL */\n remotes?: Record<string, string>;\n};\n\n/**\n * Get the name of the default remote: the one matching the `repository` field in package.json.\n * Throws if `options.cwd` is not in a git repo.\n *\n * It's recommended to set `strict: true` to also throw if no remotes are defined, no package.json\n * is found, or package.json has a `repository` field but no matching remote exists.\n *\n * The order of preference for returned remotes is:\n * 1. If `repository` is defined in package.json, the remote with a matching URL (if `options.strict`\n * is true, throws an error if no matching remote exists)\n * 2. `upstream` if defined\n * 3. `origin` if defined\n * 4. The first defined remote\n * 5. If there are no defined remotes: throws an error if `options.strict` is true; otherwise returns `origin`\n *\n * @returns The name of the inferred default remote.\n */\nexport function getDefaultRemote(options: GetDefaultRemoteOptions): string;\n/** @deprecated Use the object param version */\nexport function getDefaultRemote(cwd: string): string;\nexport function getDefaultRemote(cwdOrOptions: string | GetDefaultRemoteOptions): string {\n const options = typeof cwdOrOptions === \"string\" ? { cwd: cwdOrOptions } : cwdOrOptions;\n const { cwd, strict, verbose } = options;\n\n const log = (message: string) => verbose && console.log(message);\n const logOrThrow = (message: string) => {\n if (strict) {\n throw new Error(message);\n }\n log(message);\n };\n\n // Get remote names and URLs via `git config`.\n // In strict mode, it will throw if cwd isn't in a git repo or no remotes are found.\n const remotes = options.remotes || getRemotes({ cwd, throwOnError: strict });\n if (!Object.keys(remotes).length) {\n // For non-strict, verify cwd is actually in a git repo (throws if not)\n !strict && findGitRoot(cwd);\n\n // It's a git repo with no remotes configured. This should probably always be an error (since\n // subsequent operations which require a remote likely won't work), but to match old behavior,\n // still default to \"origin\" unless `strict` is true.\n logOrThrow(`No remotes defined in git repo at ${cwd}`);\n log(`Assuming default remote \"origin\"`);\n return \"origin\";\n }\n\n // Try to find the repository URL:\n // Try package.json from `cwd` first, since cwd is often the project root in actual usage,\n // and the repository URL should be the same throughout the repo.\n const cwdPackageJsonPath = path.join(cwd, \"package.json\");\n const hasCwdPackageJson = fs.existsSync(cwdPackageJsonPath);\n\n let repositoryUrl: string | undefined;\n if (hasCwdPackageJson) {\n // Only try to read this if it exists (will fall back to git root later)\n repositoryUrl = getRepositoryUrlFromPackageJson(cwdPackageJsonPath, logOrThrow);\n }\n\n let rootPackageJsonPath: string | undefined;\n if (!repositoryUrl) {\n // If cwd doesn't have package.json or it doesn't specify a repository, try the git root\n const gitRoot = findGitRoot(cwd);\n rootPackageJsonPath = path.join(gitRoot, \"package.json\");\n if (!hasCwdPackageJson && !fs.existsSync(rootPackageJsonPath)) {\n // no package.json found\n const paths = cwd === gitRoot ? `${cwd}` : `${cwd} or git root ${gitRoot}`;\n logOrThrow(`Could not find package.json under ${paths}`);\n } else if (gitRoot !== cwd) {\n repositoryUrl = getRepositoryUrlFromPackageJson(rootPackageJsonPath, logOrThrow);\n }\n }\n\n if (!repositoryUrl) {\n // This is always logged because it's strongly recommended to fix.\n // Recommend putting it in package.json at cwd if it exists.\n // (if there is no {cwd}/package.json, rootPackageJsonPath is always defined)\n const jsonPath = hasCwdPackageJson ? cwdPackageJsonPath : rootPackageJsonPath!;\n console.log(\n `Valid \"repository\" key not found in package.json at ${jsonPath}. ` +\n `Consider adding this info for more accurate git remote detection.`\n );\n }\n\n // If a repository URL is found, try to match it with a remote\n const remoteName = repositoryUrl && _matchRepositoryUrlToRemote(repositoryUrl, remotes, logOrThrow);\n if (remoteName) {\n return remoteName;\n }\n\n // Default to upstream or origin if available, or the first remote otherwise\n const fallback = [\"upstream\", \"origin\"].find((name) => !!remotes[name]) || Object.keys(remotes)[0];\n log(`Default to remote \"${fallback}\"`);\n return fallback;\n}\n\n/** Match repository URL from package.json to a git remote. Exported for testing. */\nexport function _matchRepositoryUrlToRemote(\n /** repository.url from package.json */\n repositoryUrl: string,\n /** Mapping from remote name to remote URL */\n remotes: Record<string, string>,\n logOrThrow: (message: string) => void = () => {}\n): string | undefined {\n // Repository full name (owner and repo name) specified in package.json\n const repositoryName = getRepositoryName(repositoryUrl);\n\n for (const [remoteName, remoteUrl] of Object.entries(remotes)) {\n // There are many possible remote URL formats, so normalize before comparison\n const remoteRepoName = getRepositoryName(remoteUrl);\n if (remoteRepoName === repositoryName) {\n return remoteName;\n }\n }\n\n if (repositoryName) {\n // If `strict` is true, and repositoryName is found, there MUST be a matching remote\n logOrThrow(`Could not find remote pointing to repository \"${repositoryName}\"`);\n }\n}\n\n/**\n * Read and parse `packageJsonPath` and return the `repository` URL if found.\n * Calls `logOrThrow` if it can't be read or parsed.\n */\nfunction getRepositoryUrlFromPackageJson(\n packageJsonPath: string,\n logOrThrow: (message: string) => void\n): string | undefined {\n try {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, \"utf8\")) as PackageInfo;\n const { repository } = packageJson;\n return typeof repository === \"string\" ? repository : repository?.url;\n } catch {\n logOrThrow(`Could not read ${packageJsonPath}`);\n return undefined;\n }\n}\n"],"names":["_matchRepositoryUrlToRemote","getDefaultRemote","cwdOrOptions","options","cwd","strict","verbose","log","message","console","logOrThrow","Error","remotes","getRemotes","throwOnError","Object","keys","length","findGitRoot","cwdPackageJsonPath","path","join","hasCwdPackageJson","fs","existsSync","repositoryUrl","getRepositoryUrlFromPackageJson","rootPackageJsonPath","gitRoot","paths","jsonPath","remoteName","fallback","find","name","repositoryName","getRepositoryName","remoteUrl","entries","remoteRepoName","packageJsonPath","packageJson","JSON","parse","readFileSync","repository","url","undefined"],"mappings":"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"}
@@ -1,12 +1,24 @@
1
1
  import { type GetDefaultRemoteOptions } from "./getDefaultRemote.js";
2
2
  export type GetDefaultRemoteBranchOptions = GetDefaultRemoteOptions & {
3
- /** Name of branch to use. If undefined, uses the default branch name (falling back to `master`). */
3
+ /**
4
+ * Name of branch to use, **without** a remote prefix. If you want to resolve a branch
5
+ * that may already include a remote prefix, use {@link resolveRemoteBranch}.
6
+ *
7
+ * If undefined, uses the default branch name (falling back to `master`).
8
+ */
4
9
  branch?: string;
5
10
  };
6
11
  /**
7
12
  * Gets a reference to `options.branch` or the default branch relative to the default remote.
8
13
  * (See {@link getDefaultRemote} for how the default remote is determined.)
9
- * Throws if `options.cwd` is not in a git repo or there's no package.json at the repo root.
14
+ * Throws if `options.cwd` is not in a git repo.
15
+ *
16
+ * If you want to resolve a branch that may already include a remote prefix, use
17
+ * {@link resolveRemoteBranch} instead.
18
+ *
19
+ * If `options.strict` is true, throws in the same cases as {@link getDefaultRemote}, {@link getRemotes},
20
+ * or if querying the default branch from the remote fails.
21
+ *
10
22
  * @returns A branch reference like `upstream/master` or `origin/master`.
11
23
  */
12
24
  export declare function getDefaultRemoteBranch(options: GetDefaultRemoteBranchOptions): string;
@@ -16,3 +28,18 @@ export declare function getDefaultRemoteBranch(options: GetDefaultRemoteBranchOp
16
28
  * @deprecated Use the object param version
17
29
  */
18
30
  export declare function getDefaultRemoteBranch(...args: string[]): string;
31
+ /**
32
+ * Resolve a user-provided branch (possibly with a remote) to a fully-qualified remote branch.
33
+ * First tries the less-expensive {@link parseRemoteBranchPlusRemotes} (compares with remote names
34
+ * read from `git config`) to see if there's an explicit remote in the branch name, then tries
35
+ * {@link getDefaultRemoteBranch}.
36
+ *
37
+ * If `options.strict` is true, throws in the same cases as {@link parseRemoteBranch},
38
+ * {@link getDefaultRemoteBranch}, {@link getDefaultRemote}, or {@link getRemotes}.
39
+ *
40
+ * @returns A fully-qualified target remote branch reference (e.g. `origin/main`)
41
+ */
42
+ export declare function resolveRemoteBranch(options: Omit<GetDefaultRemoteBranchOptions, "branch" | "remotes"> & {
43
+ /** Branch which might include a remote prefix */
44
+ branch: string | undefined;
45
+ }): string;
@@ -2,15 +2,28 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- Object.defineProperty(exports, "getDefaultRemoteBranch", {
6
- enumerable: true,
7
- get: function() {
5
+ 0 && (module.exports = {
6
+ getDefaultRemoteBranch: null,
7
+ resolveRemoteBranch: null
8
+ });
9
+ function _export(target, all) {
10
+ for(var name in all)Object.defineProperty(target, name, {
11
+ enumerable: true,
12
+ get: Object.getOwnPropertyDescriptor(all, name).get
13
+ });
14
+ }
15
+ _export(exports, {
16
+ get getDefaultRemoteBranch () {
8
17
  return getDefaultRemoteBranch;
18
+ },
19
+ get resolveRemoteBranch () {
20
+ return resolveRemoteBranch;
9
21
  }
10
22
  });
11
23
  const _getDefaultRemote = require("./getDefaultRemote.js");
12
24
  const _git = require("./git.js");
13
25
  const _gitUtilities = require("./gitUtilities.js");
26
+ const _parseRemoteBranch = require("./parseRemoteBranch.js");
14
27
  function getDefaultRemoteBranch(...args) {
15
28
  const [branchOrOptions, argsCwd] = args;
16
29
  const options = typeof branchOrOptions === "string" ? {
@@ -22,27 +35,54 @@ function getDefaultRemoteBranch(...args) {
22
35
  if (branch) {
23
36
  return `${defaultRemote}/${branch}`;
24
37
  }
25
- const showRemote = (0, _git.git)([
26
- "remote",
27
- "show",
28
- defaultRemote
29
- ], {
30
- cwd
31
- });
32
38
  let remoteDefaultBranch;
33
- if (showRemote.success) {
34
- /**
35
- * `showRemote.stdout` is something like this:
36
- *
37
- * * remote origin
38
- * Fetch URL: .../monorepo-upstream
39
- * Push URL: .../monorepo-upstream
40
- * HEAD branch: main
41
- */ remoteDefaultBranch = showRemote.stdout.split(/\n/).find((line)=>line.includes("HEAD branch"))?.replace(/^\s*HEAD branch:\s+/, "");
39
+ // Get the default branch name from the default remote.
40
+ // ls-remote is a plumbing command with stable, locale-independent output.
41
+ // Output format: "ref: refs/heads/main\tHEAD\n<hash>\tHEAD"
42
+ const lsRemoteCmd = [
43
+ "ls-remote",
44
+ "--symref",
45
+ defaultRemote,
46
+ "HEAD"
47
+ ];
48
+ const lsRemote = (0, _git.git)(lsRemoteCmd, {
49
+ cwd,
50
+ throwOnError: options.strict,
51
+ description: `Fetching default branch info from remote "${defaultRemote}"`
52
+ });
53
+ if (lsRemote.success) {
54
+ const refRegex = /^ref: refs\/heads\/(.*?)\t/;
55
+ const symRefLine = lsRemote.stdout.split("\n").find((line)=>refRegex.test(line));
56
+ remoteDefaultBranch = symRefLine && symRefLine.match(refRegex)?.[1];
57
+ if (!remoteDefaultBranch && options.strict) {
58
+ throw new Error(`Could not parse default branch from \`git ${lsRemoteCmd.join(" ")}\` output:\n${lsRemote.stdout}`);
59
+ }
42
60
  }
61
+ // If no default branch found from the remote, fall back to the local git config or "master"
62
+ // (this can't use throwOnError in case the key isn't set)
43
63
  remoteDefaultBranch || (remoteDefaultBranch = (0, _gitUtilities.getDefaultBranch)({
44
- cwd,
45
- throwOnError: options.strict
64
+ cwd
46
65
  }));
47
66
  return `${defaultRemote}/${remoteDefaultBranch}`;
48
67
  }
68
+ function resolveRemoteBranch(options) {
69
+ const { branch } = options;
70
+ let parsed;
71
+ if (branch) {
72
+ // A branch is provided, so see if it includes a remote name.
73
+ // The result is saved so the fetched list of remotes can be reused.
74
+ parsed = (0, _parseRemoteBranch.parseRemoteBranchPlusRemotes)({
75
+ ...options,
76
+ branch
77
+ });
78
+ if (parsed.remote) {
79
+ return `${parsed.remote}/${parsed.remoteBranch}`;
80
+ }
81
+ }
82
+ // No branch provided, or the provided branch didn't include a remote.
83
+ // Get the default remote and possibly default branch.
84
+ return getDefaultRemoteBranch({
85
+ ...options,
86
+ remotes: parsed?.remotes
87
+ });
88
+ }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/git/getDefaultRemoteBranch.ts"],"sourcesContent":["import { getDefaultRemote, type GetDefaultRemoteOptions } from \"./getDefaultRemote.js\";\nimport { git } from \"./git.js\";\nimport { getDefaultBranch } from \"./gitUtilities.js\";\n\nexport type GetDefaultRemoteBranchOptions = GetDefaultRemoteOptions & {\n /** Name of branch to use. If undefined, uses the default branch name (falling back to `master`). */\n branch?: string;\n};\n\n/**\n * Gets a reference to `options.branch` or the default branch relative to the default remote.\n * (See {@link getDefaultRemote} for how the default remote is determined.)\n * Throws if `options.cwd` is not in a git repo or there's no package.json at the repo root.\n * @returns A branch reference like `upstream/master` or `origin/master`.\n */\nexport function getDefaultRemoteBranch(options: GetDefaultRemoteBranchOptions): string;\n/**\n * First param: `branch`. Second param: `cwd`. See {@link GetDefaultRemoteBranchOptions} for more info.\n * (This had to be changed to `...args` to avoid a conflict with the object param version.)\n * @deprecated Use the object param version\n */\nexport function getDefaultRemoteBranch(...args: string[]): string;\nexport function getDefaultRemoteBranch(...args: (string | GetDefaultRemoteBranchOptions)[]): string {\n const [branchOrOptions, argsCwd] = args;\n const options =\n typeof branchOrOptions === \"string\"\n ? ({ branch: branchOrOptions, cwd: argsCwd } as GetDefaultRemoteBranchOptions)\n : branchOrOptions;\n const { cwd, branch } = options;\n\n const defaultRemote = getDefaultRemote(options);\n\n if (branch) {\n return `${defaultRemote}/${branch}`;\n }\n\n const showRemote = git([\"remote\", \"show\", defaultRemote], { cwd });\n let remoteDefaultBranch: string | undefined;\n\n if (showRemote.success) {\n /**\n * `showRemote.stdout` is something like this:\n *\n * * remote origin\n * Fetch URL: .../monorepo-upstream\n * Push URL: .../monorepo-upstream\n * HEAD branch: main\n */\n remoteDefaultBranch = showRemote.stdout\n .split(/\\n/)\n .find((line) => line.includes(\"HEAD branch\"))\n ?.replace(/^\\s*HEAD branch:\\s+/, \"\");\n }\n\n remoteDefaultBranch ||= getDefaultBranch({ cwd, throwOnError: options.strict });\n\n return `${defaultRemote}/${remoteDefaultBranch}`;\n}\n"],"names":["getDefaultRemoteBranch","args","branchOrOptions","argsCwd","options","branch","cwd","defaultRemote","getDefaultRemote","showRemote","git","remoteDefaultBranch","success","stdout","split","find","line","includes","replace","getDefaultBranch","throwOnError","strict"],"mappings":";;;;+BAsBgBA;;;eAAAA;;;kCAtB+C;qBAC3C;8BACa;AAoB1B,SAASA,uBAAuB,GAAGC,IAAgD;IACxF,MAAM,CAACC,iBAAiBC,QAAQ,GAAGF;IACnC,MAAMG,UACJ,OAAOF,oBAAoB,WACtB;QAAEG,QAAQH;QAAiBI,KAAKH;IAAQ,IACzCD;IACN,MAAM,EAAEI,GAAG,EAAED,MAAM,EAAE,GAAGD;IAExB,MAAMG,gBAAgBC,IAAAA,kCAAgB,EAACJ;IAEvC,IAAIC,QAAQ;QACV,OAAO,GAAGE,cAAc,CAAC,EAAEF,QAAQ;IACrC;IAEA,MAAMI,aAAaC,IAAAA,QAAG,EAAC;QAAC;QAAU;QAAQH;KAAc,EAAE;QAAED;IAAI;IAChE,IAAIK;IAEJ,IAAIF,WAAWG,OAAO,EAAE;QACtB;;;;;;;KAOC,GACDD,sBAAsBF,WAAWI,MAAM,CACpCC,KAAK,CAAC,MACNC,IAAI,CAAC,CAACC,OAASA,KAAKC,QAAQ,CAAC,iBAC5BC,QAAQ,uBAAuB;IACrC;IAEAP,wBAAAA,sBAAwBQ,IAAAA,8BAAgB,EAAC;QAAEb;QAAKc,cAAchB,QAAQiB,MAAM;IAAC;IAE7E,OAAO,GAAGd,cAAc,CAAC,EAAEI,qBAAqB;AAClD"}
1
+ {"version":3,"sources":["../../src/git/getDefaultRemoteBranch.ts"],"sourcesContent":["import { getDefaultRemote, type GetDefaultRemoteOptions } from \"./getDefaultRemote.js\";\n// eslint-disable-next-line @typescript-eslint/no-unused-vars -- referenced by docs\nimport type { getRemotes } from \"./getRemotes.js\";\nimport { git } from \"./git.js\";\nimport { getDefaultBranch } from \"./gitUtilities.js\";\nimport {\n parseRemoteBranchPlusRemotes,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n type parseRemoteBranch,\n} from \"./parseRemoteBranch.js\";\n\nexport type GetDefaultRemoteBranchOptions = GetDefaultRemoteOptions & {\n /**\n * Name of branch to use, **without** a remote prefix. If you want to resolve a branch\n * that may already include a remote prefix, use {@link resolveRemoteBranch}.\n *\n * If undefined, uses the default branch name (falling back to `master`).\n */\n branch?: string;\n};\n\n/**\n * Gets a reference to `options.branch` or the default branch relative to the default remote.\n * (See {@link getDefaultRemote} for how the default remote is determined.)\n * Throws if `options.cwd` is not in a git repo.\n *\n * If you want to resolve a branch that may already include a remote prefix, use\n * {@link resolveRemoteBranch} instead.\n *\n * If `options.strict` is true, throws in the same cases as {@link getDefaultRemote}, {@link getRemotes},\n * or if querying the default branch from the remote fails.\n *\n * @returns A branch reference like `upstream/master` or `origin/master`.\n */\nexport function getDefaultRemoteBranch(options: GetDefaultRemoteBranchOptions): string;\n/**\n * First param: `branch`. Second param: `cwd`. See {@link GetDefaultRemoteBranchOptions} for more info.\n * (This had to be changed to `...args` to avoid a conflict with the object param version.)\n * @deprecated Use the object param version\n */\nexport function getDefaultRemoteBranch(...args: string[]): string;\nexport function getDefaultRemoteBranch(...args: (string | GetDefaultRemoteBranchOptions)[]): string {\n const [branchOrOptions, argsCwd] = args;\n const options =\n typeof branchOrOptions === \"string\"\n ? ({ branch: branchOrOptions, cwd: argsCwd } as GetDefaultRemoteBranchOptions)\n : branchOrOptions;\n const { cwd, branch } = options;\n\n const defaultRemote = getDefaultRemote(options);\n\n if (branch) {\n return `${defaultRemote}/${branch}`;\n }\n\n let remoteDefaultBranch: string | undefined;\n\n // Get the default branch name from the default remote.\n // ls-remote is a plumbing command with stable, locale-independent output.\n // Output format: \"ref: refs/heads/main\\tHEAD\\n<hash>\\tHEAD\"\n const lsRemoteCmd = [\"ls-remote\", \"--symref\", defaultRemote, \"HEAD\"];\n const lsRemote = git(lsRemoteCmd, {\n cwd,\n throwOnError: options.strict,\n description: `Fetching default branch info from remote \"${defaultRemote}\"`,\n });\n if (lsRemote.success) {\n const refRegex = /^ref: refs\\/heads\\/(.*?)\\t/;\n const symRefLine = lsRemote.stdout.split(\"\\n\").find((line) => refRegex.test(line));\n remoteDefaultBranch = symRefLine && symRefLine.match(refRegex)?.[1];\n\n if (!remoteDefaultBranch && options.strict) {\n throw new Error(\n `Could not parse default branch from \\`git ${lsRemoteCmd.join(\" \")}\\` output:\\n${lsRemote.stdout}`\n );\n }\n }\n\n // If no default branch found from the remote, fall back to the local git config or \"master\"\n // (this can't use throwOnError in case the key isn't set)\n remoteDefaultBranch ||= getDefaultBranch({ cwd });\n\n return `${defaultRemote}/${remoteDefaultBranch}`;\n}\n\n/**\n * Resolve a user-provided branch (possibly with a remote) to a fully-qualified remote branch.\n * First tries the less-expensive {@link parseRemoteBranchPlusRemotes} (compares with remote names\n * read from `git config`) to see if there's an explicit remote in the branch name, then tries\n * {@link getDefaultRemoteBranch}.\n *\n * If `options.strict` is true, throws in the same cases as {@link parseRemoteBranch},\n * {@link getDefaultRemoteBranch}, {@link getDefaultRemote}, or {@link getRemotes}.\n *\n * @returns A fully-qualified target remote branch reference (e.g. `origin/main`)\n */\nexport function resolveRemoteBranch(\n options: Omit<GetDefaultRemoteBranchOptions, \"branch\" | \"remotes\"> & {\n /** Branch which might include a remote prefix */\n branch: string | undefined;\n }\n): string {\n const { branch } = options;\n\n let parsed: ReturnType<typeof parseRemoteBranchPlusRemotes> | undefined;\n if (branch) {\n // A branch is provided, so see if it includes a remote name.\n // The result is saved so the fetched list of remotes can be reused.\n parsed = parseRemoteBranchPlusRemotes({ ...options, branch });\n if (parsed.remote) {\n return `${parsed.remote}/${parsed.remoteBranch}`;\n }\n }\n\n // No branch provided, or the provided branch didn't include a remote.\n // Get the default remote and possibly default branch.\n return getDefaultRemoteBranch({ ...options, remotes: parsed?.remotes });\n}\n"],"names":["getDefaultRemoteBranch","resolveRemoteBranch","args","branchOrOptions","argsCwd","options","branch","cwd","defaultRemote","getDefaultRemote","remoteDefaultBranch","lsRemoteCmd","lsRemote","git","throwOnError","strict","description","success","refRegex","symRefLine","stdout","split","find","line","test","match","Error","join","getDefaultBranch","parsed","parseRemoteBranchPlusRemotes","remote","remoteBranch","remotes"],"mappings":";;;;;;;;;;;;;;;QAyCgBA;eAAAA;;QAuDAC;eAAAA;;;kCAhG+C;qBAG3C;8BACa;mCAK1B;AAgCA,SAASD,uBAAuB,GAAGE,IAAgD;IACxF,MAAM,CAACC,iBAAiBC,QAAQ,GAAGF;IACnC,MAAMG,UACJ,OAAOF,oBAAoB,WACtB;QAAEG,QAAQH;QAAiBI,KAAKH;IAAQ,IACzCD;IACN,MAAM,EAAEI,GAAG,EAAED,MAAM,EAAE,GAAGD;IAExB,MAAMG,gBAAgBC,IAAAA,kCAAgB,EAACJ;IAEvC,IAAIC,QAAQ;QACV,OAAO,GAAGE,cAAc,CAAC,EAAEF,QAAQ;IACrC;IAEA,IAAII;IAEJ,uDAAuD;IACvD,0EAA0E;IAC1E,4DAA4D;IAC5D,MAAMC,cAAc;QAAC;QAAa;QAAYH;QAAe;KAAO;IACpE,MAAMI,WAAWC,IAAAA,QAAG,EAACF,aAAa;QAChCJ;QACAO,cAAcT,QAAQU,MAAM;QAC5BC,aAAa,CAAC,0CAA0C,EAAER,cAAc,CAAC,CAAC;IAC5E;IACA,IAAII,SAASK,OAAO,EAAE;QACpB,MAAMC,WAAW;QACjB,MAAMC,aAAaP,SAASQ,MAAM,CAACC,KAAK,CAAC,MAAMC,IAAI,CAAC,CAACC,OAASL,SAASM,IAAI,CAACD;QAC5Eb,sBAAsBS,cAAcA,WAAWM,KAAK,CAACP,WAAW,CAAC,EAAE;QAEnE,IAAI,CAACR,uBAAuBL,QAAQU,MAAM,EAAE;YAC1C,MAAM,IAAIW,MACR,CAAC,0CAA0C,EAAEf,YAAYgB,IAAI,CAAC,KAAK,YAAY,EAAEf,SAASQ,MAAM,EAAE;QAEtG;IACF;IAEA,4FAA4F;IAC5F,0DAA0D;IAC1DV,wBAAAA,sBAAwBkB,IAAAA,8BAAgB,EAAC;QAAErB;IAAI;IAE/C,OAAO,GAAGC,cAAc,CAAC,EAAEE,qBAAqB;AAClD;AAaO,SAAST,oBACdI,OAGC;IAED,MAAM,EAAEC,MAAM,EAAE,GAAGD;IAEnB,IAAIwB;IACJ,IAAIvB,QAAQ;QACV,6DAA6D;QAC7D,oEAAoE;QACpEuB,SAASC,IAAAA,+CAA4B,EAAC;YAAE,GAAGzB,OAAO;YAAEC;QAAO;QAC3D,IAAIuB,OAAOE,MAAM,EAAE;YACjB,OAAO,GAAGF,OAAOE,MAAM,CAAC,CAAC,EAAEF,OAAOG,YAAY,EAAE;QAClD;IACF;IAEA,sEAAsE;IACtE,sDAAsD;IACtD,OAAOhC,uBAAuB;QAAE,GAAGK,OAAO;QAAE4B,SAASJ,QAAQI;IAAQ;AACvE"}
@@ -0,0 +1,10 @@
1
+ import type { GitCommonOptions } from "./types.js";
2
+ /**
3
+ * Get the commit hash in which the file was first added.
4
+ * @returns The commit hash if found, undefined otherwise
5
+ */
6
+ export declare function getFileAddedHash(options: {
7
+ filename: string;
8
+ } & GitCommonOptions): string | undefined;
9
+ /** @deprecated Use object params version */
10
+ export declare function getFileAddedHash(filename: string, cwd: string): string | undefined;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "getFileAddedHash", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return getFileAddedHash;
9
+ }
10
+ });
11
+ const _git = require("./git.js");
12
+ function getFileAddedHash(filenameOrOptions, cwd) {
13
+ const { filename, ...options } = typeof filenameOrOptions === "string" ? {
14
+ filename: filenameOrOptions,
15
+ cwd: cwd
16
+ } : filenameOrOptions;
17
+ const results = (0, _git.git)([
18
+ "rev-list",
19
+ "--max-count=1",
20
+ "HEAD",
21
+ filename
22
+ ], options);
23
+ return results.success ? results.stdout.trim() : undefined;
24
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/git/getFileAddedHash.ts"],"sourcesContent":["import { git } from \"./git.js\";\nimport type { GitCommonOptions } from \"./types.js\";\n\n/**\n * Get the commit hash in which the file was first added.\n * @returns The commit hash if found, undefined otherwise\n */\nexport function getFileAddedHash(options: { filename: string } & GitCommonOptions): string | undefined;\n/** @deprecated Use object params version */\nexport function getFileAddedHash(filename: string, cwd: string): string | undefined;\nexport function getFileAddedHash(\n filenameOrOptions: string | ({ filename: string } & GitCommonOptions),\n cwd?: string\n): string | undefined {\n const { filename, ...options } =\n typeof filenameOrOptions === \"string\" ? { filename: filenameOrOptions, cwd: cwd! } : filenameOrOptions;\n\n const results = git([\"rev-list\", \"--max-count=1\", \"HEAD\", filename], options);\n\n return results.success ? results.stdout.trim() : undefined;\n}\n"],"names":["getFileAddedHash","filenameOrOptions","cwd","filename","options","results","git","success","stdout","trim","undefined"],"mappings":";;;;+BAUgBA;;;eAAAA;;;qBAVI;AAUb,SAASA,iBACdC,iBAAqE,EACrEC,GAAY;IAEZ,MAAM,EAAEC,QAAQ,EAAE,GAAGC,SAAS,GAC5B,OAAOH,sBAAsB,WAAW;QAAEE,UAAUF;QAAmBC,KAAKA;IAAK,IAAID;IAEvF,MAAMI,UAAUC,IAAAA,QAAG,EAAC;QAAC;QAAY;QAAiB;QAAQH;KAAS,EAAEC;IAErE,OAAOC,QAAQE,OAAO,GAAGF,QAAQG,MAAM,CAACC,IAAI,KAAKC;AACnD"}
@@ -0,0 +1,11 @@
1
+ import type { GitCommonOptions } from "./types.js";
2
+ /**
3
+ * Get the content of a file at a specific git ref (commit, branch, tag, etc).
4
+ * Returns undefined if the file doesn't exist at that ref or the command fails.
5
+ */
6
+ export declare function getFileFromRef(params: {
7
+ /** cwd-relative path to the file with *forward* slashes */
8
+ filePath: string;
9
+ /** git ref (branch, tag, commit SHA, etc) to get the file content from */
10
+ ref: string;
11
+ } & GitCommonOptions): string | undefined;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "getFileFromRef", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return getFileFromRef;
9
+ }
10
+ });
11
+ const _git = require("./git.js");
12
+ function getFileFromRef(params) {
13
+ const { filePath, ref, ...options } = params;
14
+ const result = (0, _git.git)([
15
+ "show",
16
+ `${ref}:${filePath}`
17
+ ], {
18
+ description: `Getting file ${filePath} at ref ${ref}`,
19
+ ...options
20
+ });
21
+ return result.success ? result.stdout : undefined;
22
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/git/getFileFromRef.ts"],"sourcesContent":["import { git } from \"./git.js\";\nimport type { GitCommonOptions } from \"./types.js\";\n\n/**\n * Get the content of a file at a specific git ref (commit, branch, tag, etc).\n * Returns undefined if the file doesn't exist at that ref or the command fails.\n */\nexport function getFileFromRef(\n params: {\n /** cwd-relative path to the file with *forward* slashes */\n filePath: string;\n /** git ref (branch, tag, commit SHA, etc) to get the file content from */\n ref: string;\n } & GitCommonOptions\n): string | undefined {\n const { filePath, ref, ...options } = params;\n const result = git([\"show\", `${ref}:${filePath}`], {\n description: `Getting file ${filePath} at ref ${ref}`,\n ...options,\n });\n return result.success ? result.stdout : undefined;\n}\n"],"names":["getFileFromRef","params","filePath","ref","options","result","git","description","success","stdout","undefined"],"mappings":";;;;+BAOgBA;;;eAAAA;;;qBAPI;AAOb,SAASA,eACdC,MAKoB;IAEpB,MAAM,EAAEC,QAAQ,EAAEC,GAAG,EAAE,GAAGC,SAAS,GAAGH;IACtC,MAAMI,SAASC,IAAAA,QAAG,EAAC;QAAC;QAAQ,GAAGH,IAAI,CAAC,EAAED,UAAU;KAAC,EAAE;QACjDK,aAAa,CAAC,aAAa,EAAEL,SAAS,QAAQ,EAAEC,KAAK;QACrD,GAAGC,OAAO;IACZ;IACA,OAAOC,OAAOG,OAAO,GAAGH,OAAOI,MAAM,GAAGC;AAC1C"}
@@ -0,0 +1,10 @@
1
+ import type { GitBranchOptions } from "./types.js";
2
+ /**
3
+ * Gets recent commit messages between the specified parent branch and HEAD.
4
+ * By default, returns an empty array if the operation fails.
5
+ *
6
+ * @returns An array of commit message strings
7
+ */
8
+ export declare function getRecentCommitMessages(options: GitBranchOptions): string[];
9
+ /** @deprecated Use object params version */
10
+ export declare function getRecentCommitMessages(branch: string, cwd: string): string[];
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "getRecentCommitMessages", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return getRecentCommitMessages;
9
+ }
10
+ });
11
+ const _git = require("./git.js");
12
+ function getRecentCommitMessages(branchOrOptions, cwd) {
13
+ const { branch, ...options } = typeof branchOrOptions === "string" ? {
14
+ branch: branchOrOptions,
15
+ cwd: cwd
16
+ } : branchOrOptions;
17
+ const results = (0, _git.git)([
18
+ "log",
19
+ "--decorate",
20
+ "--pretty=format:%s",
21
+ `${branch}..HEAD`
22
+ ], {
23
+ description: `Getting recent commit messages for branch "${branch}"`,
24
+ ...options
25
+ });
26
+ return (0, _git.processGitOutput)(results);
27
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/git/getRecentCommitMessages.ts"],"sourcesContent":["import { git, processGitOutput } from \"./git.js\";\nimport type { GitBranchOptions } from \"./types.js\";\n\n/**\n * Gets recent commit messages between the specified parent branch and HEAD.\n * By default, returns an empty array if the operation fails.\n *\n * @returns An array of commit message strings\n */\nexport function getRecentCommitMessages(options: GitBranchOptions): string[];\n/** @deprecated Use object params version */\nexport function getRecentCommitMessages(branch: string, cwd: string): string[];\nexport function getRecentCommitMessages(branchOrOptions: string | GitBranchOptions, cwd?: string): string[] {\n const { branch, ...options } =\n typeof branchOrOptions === \"string\" ? { branch: branchOrOptions, cwd: cwd! } : branchOrOptions;\n\n const results = git([\"log\", \"--decorate\", \"--pretty=format:%s\", `${branch}..HEAD`], {\n description: `Getting recent commit messages for branch \"${branch}\"`,\n ...options,\n });\n return processGitOutput(results);\n}\n"],"names":["getRecentCommitMessages","branchOrOptions","cwd","branch","options","results","git","description","processGitOutput"],"mappings":";;;;+BAYgBA;;;eAAAA;;;qBAZsB;AAY/B,SAASA,wBAAwBC,eAA0C,EAAEC,GAAY;IAC9F,MAAM,EAAEC,MAAM,EAAE,GAAGC,SAAS,GAC1B,OAAOH,oBAAoB,WAAW;QAAEE,QAAQF;QAAiBC,KAAKA;IAAK,IAAID;IAEjF,MAAMI,UAAUC,IAAAA,QAAG,EAAC;QAAC;QAAO;QAAc;QAAsB,GAAGH,OAAO,MAAM,CAAC;KAAC,EAAE;QAClFI,aAAa,CAAC,2CAA2C,EAAEJ,OAAO,CAAC,CAAC;QACpE,GAAGC,OAAO;IACZ;IACA,OAAOI,IAAAA,qBAAgB,EAACH;AAC1B"}
@@ -0,0 +1,14 @@
1
+ import type { GitCommonOptions } from "./types.js";
2
+ /**
3
+ * Get a mapping from remote names to fetch URLs.
4
+ *
5
+ * Note this returns the URLs directly from `git config --local --get-regexp 'remote\..*\.url'`,
6
+ * which doesn't respect any `url.<base>.insteadOf` remappings (such as for ssh). This should be
7
+ * fine for current usage: `parseRemoteBranch` only needs the names, and `getDefaultRemote`
8
+ * compares parsed URLs from `package.json` `repository` and should be flexible about formats.
9
+ *
10
+ * If `options.throwOnError` is true, throws if no remotes are found or `cwd` isn't in a git repo.
11
+ *
12
+ * @returns An object mapping remote names to URLs.
13
+ */
14
+ export declare function getRemotes(options: GitCommonOptions): Record<string, string>;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "getRemotes", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return getRemotes;
9
+ }
10
+ });
11
+ const _git = require("./git.js");
12
+ function getRemotes(options) {
13
+ let remotesResult;
14
+ try {
15
+ // Get remote names and URLs, similar to `git remote -v` but without localization concerns.
16
+ // --local ensures it errors if cwd is not in a git repo.
17
+ remotesResult = (0, _git.git)([
18
+ "config",
19
+ "--local",
20
+ "--get-regexp",
21
+ "remote\\..*\\.url"
22
+ ], {
23
+ ...options,
24
+ description: "Getting git remotes"
25
+ });
26
+ } catch (e) {
27
+ if (e instanceof _git.GitError) {
28
+ if (e.gitOutput?.status === 1) {
29
+ // Per git config docs, 1 means the key wasn't found, so fail with a clearer message
30
+ // (this case will only be hit with throwOnError: true)
31
+ throw new _git.GitError(`No remotes defined in git repo at ${options.cwd}`, undefined, e.gitOutput);
32
+ }
33
+ if (e.gitOutput?.status === 128) {
34
+ // 128 most commonly means not a git repository
35
+ throw new _git.GitError(`${options.cwd} is not in a git repository`, undefined, e.gitOutput);
36
+ }
37
+ }
38
+ throw e;
39
+ }
40
+ if (!remotesResult.success) {
41
+ // throwOnError was false/unset but no remotes were found
42
+ return {};
43
+ }
44
+ const remotes = {};
45
+ const remoteLines = remotesResult.stdout.trim().split("\n");
46
+ for (const line of remoteLines){
47
+ const remoteMatch = line.match(/^remote\.(.+?)\.url\s+(.*)$/);
48
+ if (!remoteMatch) continue;
49
+ const [, remoteName, remoteUrl] = remoteMatch;
50
+ remotes[remoteName] = remoteUrl;
51
+ }
52
+ return remotes;
53
+ }