nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1// @ts-check
2const { promisify } = require('node:util')
3const execFile = promisify(require('node:child_process').execFile)
4
5/**
6 * @param {{
7 * args: string[]
8 * core: import('@actions/core'),
9 * quiet?: boolean,
10 * repoPath?: string,
11 * }} RunGitProps
12 */
13async function runGit({ args, repoPath, core, quiet }) {
14 if (repoPath) {
15 args = ['-C', repoPath, ...args]
16 }
17
18 if (!quiet) {
19 core.info(`About to run \`git ${args.map((s) => `'${s}'`).join(' ')}\``)
20 }
21
22 return await execFile('git', args)
23}
24
25/**
26 * Gets the SHA, subject and changed files for each commit in the given PR.
27 *
28 * Don't use GitHub API at all: the "list commits on PR" endpoint has a limit
29 * of 250 commits and doesn't return the changed files.
30 *
31 * @param {{
32 * core: import('@actions/core'),
33 * pr: Awaited<ReturnType<InstanceType<import('@actions/github/lib/utils').GitHub>["rest"]["pulls"]["get"]>>["data"]
34 * repoPath?: string,
35 * }} GetCommitMessagesForPRProps
36 *
37 * @returns {Promise<{
38 * subject: string,
39 * sha: string,
40 * changedPaths: string[],
41 * changedPathSegments: Set<string>,
42 * }[]>}
43 */
44async function getCommitDetailsForPR({ core, pr, repoPath }) {
45 await runGit({
46 args: ['fetch', `--depth=1`, 'origin', pr.base.sha],
47 repoPath,
48 core,
49 })
50 await runGit({
51 args: ['fetch', `--depth=${pr.commits + 1}`, 'origin', pr.head.sha],
52 repoPath,
53 core,
54 })
55
56 const shas = (
57 await runGit({
58 args: [
59 'rev-list',
60 `--max-count=${pr.commits}`,
61 `${pr.base.sha}..${pr.head.sha}`,
62 ],
63 repoPath,
64 core,
65 })
66 ).stdout
67 .split('\n')
68 .map((s) => s.trim())
69 .filter(Boolean)
70
71 return Promise.all(
72 shas.map(async (sha) => {
73 // Subject first, then a blank line, then filenames.
74 const result = (
75 await runGit({
76 args: ['log', '--format=%s', '--name-only', '-1', sha],
77 repoPath,
78 core,
79 quiet: true,
80 })
81 ).stdout.split('\n')
82
83 const subject = result[0]
84
85 const changedPaths = result.slice(2, -1)
86
87 const changedPathSegments = new Set(
88 changedPaths.flatMap((path) => path.split('/')),
89 )
90
91 return {
92 sha,
93 subject,
94 changedPaths,
95 changedPathSegments,
96 }
97 }),
98 )
99}
100
101module.exports = { getCommitDetailsForPR }