gitCommitInfoPlugin.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. "use strict";
  2. var __create = Object.create;
  3. var __defProp = Object.defineProperty;
  4. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  5. var __getOwnPropNames = Object.getOwnPropertyNames;
  6. var __getProtoOf = Object.getPrototypeOf;
  7. var __hasOwnProp = Object.prototype.hasOwnProperty;
  8. var __export = (target, all) => {
  9. for (var name in all)
  10. __defProp(target, name, { get: all[name], enumerable: true });
  11. };
  12. var __copyProps = (to, from, except, desc) => {
  13. if (from && typeof from === "object" || typeof from === "function") {
  14. for (let key of __getOwnPropNames(from))
  15. if (!__hasOwnProp.call(to, key) && key !== except)
  16. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  17. }
  18. return to;
  19. };
  20. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  21. // If the importer is in node compatibility mode or this is not an ESM
  22. // file that has been converted to a CommonJS file using a Babel-
  23. // compatible transform (i.e. "__esModule" has not been set), then set
  24. // "default" to the CommonJS "module.exports" for node compatibility.
  25. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  26. mod
  27. ));
  28. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  29. var gitCommitInfoPlugin_exports = {};
  30. __export(gitCommitInfoPlugin_exports, {
  31. addGitCommitInfoPlugin: () => addGitCommitInfoPlugin
  32. });
  33. module.exports = __toCommonJS(gitCommitInfoPlugin_exports);
  34. var fs = __toESM(require("fs"));
  35. var import_utils = require("playwright-core/lib/utils");
  36. const GIT_OPERATIONS_TIMEOUT_MS = 3e3;
  37. const addGitCommitInfoPlugin = (fullConfig) => {
  38. fullConfig.plugins.push({ factory: gitCommitInfoPlugin.bind(null, fullConfig) });
  39. };
  40. function print(s, ...args) {
  41. console.log("GitCommitInfo: " + s, ...args);
  42. }
  43. function debug(s, ...args) {
  44. if (!process.env.DEBUG_GIT_COMMIT_INFO)
  45. return;
  46. print(s, ...args);
  47. }
  48. const gitCommitInfoPlugin = (fullConfig) => {
  49. return {
  50. name: "playwright:git-commit-info",
  51. setup: async (config, configDir) => {
  52. const metadata = config.metadata;
  53. const ci = await ciInfo();
  54. if (!metadata.ci && ci) {
  55. debug("ci info", ci);
  56. metadata.ci = ci;
  57. }
  58. if (fullConfig.captureGitInfo?.commit || fullConfig.captureGitInfo?.commit === void 0 && ci) {
  59. const git = await gitCommitInfo(configDir).catch((e) => print("failed to get git commit info", e));
  60. if (git) {
  61. debug("commit info", git);
  62. metadata.gitCommit = git;
  63. }
  64. }
  65. if (fullConfig.captureGitInfo?.diff || fullConfig.captureGitInfo?.diff === void 0 && ci) {
  66. const diffResult = await gitDiff(configDir, ci).catch((e) => print("failed to get git diff", e));
  67. if (diffResult) {
  68. debug(`diff length ${diffResult.length}`);
  69. metadata.gitDiff = diffResult;
  70. }
  71. }
  72. }
  73. };
  74. };
  75. async function ciInfo() {
  76. if (process.env.GITHUB_ACTIONS) {
  77. let pr;
  78. try {
  79. const json = JSON.parse(await fs.promises.readFile(process.env.GITHUB_EVENT_PATH, "utf8"));
  80. pr = { title: json.pull_request.title, number: json.pull_request.number, baseHash: json.pull_request.base.sha };
  81. } catch {
  82. }
  83. return {
  84. commitHref: `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/commit/${process.env.GITHUB_SHA}`,
  85. commitHash: process.env.GITHUB_SHA,
  86. prHref: pr ? `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/pull/${pr.number}` : void 0,
  87. prTitle: pr?.title,
  88. prBaseHash: pr?.baseHash,
  89. buildHref: `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`
  90. };
  91. }
  92. if (process.env.GITLAB_CI) {
  93. return {
  94. commitHref: `${process.env.CI_PROJECT_URL}/-/commit/${process.env.CI_COMMIT_SHA}`,
  95. commitHash: process.env.CI_COMMIT_SHA,
  96. buildHref: process.env.CI_JOB_URL,
  97. branch: process.env.CI_COMMIT_REF_NAME
  98. };
  99. }
  100. if (process.env.JENKINS_URL && process.env.BUILD_URL) {
  101. return {
  102. commitHref: process.env.BUILD_URL,
  103. commitHash: process.env.GIT_COMMIT,
  104. branch: process.env.GIT_BRANCH
  105. };
  106. }
  107. }
  108. async function gitCommitInfo(gitDir) {
  109. const separator = `---786eec917292---`;
  110. const tokens = [
  111. "%H",
  112. // commit hash
  113. "%h",
  114. // abbreviated commit hash
  115. "%s",
  116. // subject
  117. "%B",
  118. // raw body (unwrapped subject and body)
  119. "%an",
  120. // author name
  121. "%ae",
  122. // author email
  123. "%at",
  124. // author date, UNIX timestamp
  125. "%cn",
  126. // committer name
  127. "%ce",
  128. // committer email
  129. "%ct",
  130. // committer date, UNIX timestamp
  131. ""
  132. // branch
  133. ];
  134. const output = await runGit(`git log -1 --pretty=format:"${tokens.join(separator)}" && git rev-parse --abbrev-ref HEAD`, gitDir);
  135. if (!output)
  136. return void 0;
  137. const [hash, shortHash, subject, body, authorName, authorEmail, authorTime, committerName, committerEmail, committerTime, branch] = output.split(separator);
  138. return {
  139. shortHash,
  140. hash,
  141. subject,
  142. body,
  143. author: {
  144. name: authorName,
  145. email: authorEmail,
  146. time: +authorTime * 1e3
  147. },
  148. committer: {
  149. name: committerName,
  150. email: committerEmail,
  151. time: +committerTime * 1e3
  152. },
  153. branch: branch.trim()
  154. };
  155. }
  156. async function gitDiff(gitDir, ci) {
  157. const diffLimit = 1e5;
  158. if (ci?.prBaseHash) {
  159. await runGit(`git fetch origin ${ci.prBaseHash} --depth=1 --no-auto-maintenance --no-auto-gc --no-tags --no-recurse-submodules`, gitDir);
  160. const diff2 = await runGit(`git diff ${ci.prBaseHash} HEAD`, gitDir);
  161. if (diff2)
  162. return diff2.substring(0, diffLimit);
  163. }
  164. if (ci)
  165. return;
  166. const uncommitted = await runGit("git diff", gitDir);
  167. if (uncommitted === void 0) {
  168. return;
  169. }
  170. if (uncommitted)
  171. return uncommitted.substring(0, diffLimit);
  172. const diff = await runGit("git diff HEAD~1", gitDir);
  173. return diff?.substring(0, diffLimit);
  174. }
  175. async function runGit(command, cwd) {
  176. debug(`running "${command}"`);
  177. const start = (0, import_utils.monotonicTime)();
  178. const result = await (0, import_utils.spawnAsync)(
  179. command,
  180. [],
  181. { stdio: "pipe", cwd, timeout: GIT_OPERATIONS_TIMEOUT_MS, shell: true }
  182. );
  183. if ((0, import_utils.monotonicTime)() - start > GIT_OPERATIONS_TIMEOUT_MS) {
  184. print(`timeout of ${GIT_OPERATIONS_TIMEOUT_MS}ms exceeded while running "${command}"`);
  185. return;
  186. }
  187. if (result.code)
  188. debug(`failure, code=${result.code}
  189. ${result.stderr}`);
  190. else
  191. debug(`success`);
  192. return result.code ? void 0 : result.stdout.trim();
  193. }
  194. // Annotate the CommonJS export names for ESM import in node:
  195. 0 && (module.exports = {
  196. addGitCommitInfoPlugin
  197. });