1- import { hasProperty } from '@metamask/utils' ;
21import { exec as execCallback } from 'child_process' ;
32import fs from 'fs' ;
43import path from 'path' ;
54import { promisify } from 'util' ;
65
76const exec = promisify ( execCallback ) ;
87
8+ // The CIRCLE_PR_NUMBER variable is only available on forked Pull Requests
9+ const PR_NUMBER =
10+ process . env . CIRCLE_PR_NUMBER ||
11+ process . env . CIRCLE_PULL_REQUEST ?. split ( '/' ) . pop ( ) ;
12+
913const MAIN_BRANCH = 'develop' ;
14+ const SOURCE_BRANCH = `refs/pull/${ PR_NUMBER } /head` ;
15+
16+ const CHANGED_FILES_DIR = 'changed-files' ;
17+
18+ type PRInfo = {
19+ base : {
20+ ref : string ;
21+ } ;
22+ body : string ;
23+ } ;
1024
1125/**
12- * Get the target branch for the given pull request.
26+ * Get JSON info about the given pull request
1327 *
14- * @returns The name of the branch targeted by the PR.
28+ * @returns JSON info from GitHub
1529 */
16- async function getBaseRef ( ) : Promise < string | null > {
17- if ( ! process . env . CIRCLE_PULL_REQUEST ) {
30+ async function getPrInfo ( ) : Promise < PRInfo | null > {
31+ if ( ! PR_NUMBER ) {
1832 return null ;
1933 }
2034
21- // We're referencing the CIRCLE_PULL_REQUEST environment variable within the script rather than
22- // passing it in because this makes it easier to use Bash parameter expansion to extract the
23- // PR number from the URL.
24- const result = await exec ( `gh pr view --json baseRefName "\${CIRCLE_PULL_REQUEST##*/}" --jq '.baseRefName'` ) ;
25- const baseRef = result . stdout . trim ( ) ;
26- return baseRef ;
35+ return await (
36+ await fetch (
37+ `https://api.github.com/repos/${ process . env . CIRCLE_PROJECT_USERNAME } /${ process . env . CIRCLE_PROJECT_REPONAME } /pulls/${ PR_NUMBER } ` ,
38+ )
39+ ) . json ( ) ;
2740}
2841
2942/**
@@ -34,8 +47,10 @@ async function getBaseRef(): Promise<string | null> {
3447 */
3548async function fetchWithDepth ( depth : number ) : Promise < boolean > {
3649 try {
37- await exec ( `git fetch --depth ${ depth } origin develop` ) ;
38- await exec ( `git fetch --depth ${ depth } origin ${ process . env . CIRCLE_BRANCH } ` ) ;
50+ await exec ( `git fetch --depth ${ depth } origin "${ MAIN_BRANCH } "` ) ;
51+ await exec (
52+ `git fetch --depth ${ depth } origin "${ SOURCE_BRANCH } :${ SOURCE_BRANCH } "` ,
53+ ) ;
3954 return true ;
4055 } catch ( error : unknown ) {
4156 console . error ( `Failed to fetch with depth ${ depth } :` , error ) ;
@@ -59,18 +74,16 @@ async function fetchUntilMergeBaseFound() {
5974 await exec ( `git merge-base origin/HEAD HEAD` ) ;
6075 return ;
6176 } catch ( error : unknown ) {
62- if (
63- error instanceof Error &&
64- hasProperty ( error , 'code' ) &&
65- error . code === 1
66- ) {
67- console . error ( `Error 'no merge base' encountered with depth ${ depth } . Incrementing depth...` ) ;
77+ if ( error instanceof Error && 'code' in error ) {
78+ console . error (
79+ `Error 'no merge base' encountered with depth ${ depth } . Incrementing depth...` ,
80+ ) ;
6881 } else {
6982 throw error ;
7083 }
7184 }
7285 }
73- await exec ( `git fetch --unshallow origin develop ` ) ;
86+ await exec ( `git fetch --unshallow origin " ${ MAIN_BRANCH } " ` ) ;
7487}
7588
7689/**
@@ -82,55 +95,69 @@ async function fetchUntilMergeBaseFound() {
8295 */
8396async function gitDiff ( ) : Promise < string > {
8497 await fetchUntilMergeBaseFound ( ) ;
85- const { stdout : diffResult } = await exec ( `git diff --name-only origin/HEAD...${ process . env . CIRCLE_BRANCH } ` ) ;
98+ const { stdout : diffResult } = await exec (
99+ `git diff --name-only "origin/HEAD...${ SOURCE_BRANCH } "` ,
100+ ) ;
86101 if ( ! diffResult ) {
87- throw new Error ( 'Unable to get diff after full checkout.' ) ;
102+ throw new Error ( 'Unable to get diff after full checkout.' ) ;
88103 }
89104 return diffResult ;
90105}
91106
107+ function writePrBodyToFile ( prBody : string ) {
108+ const prBodyPath = path . resolve ( CHANGED_FILES_DIR , 'pr-body.txt' ) ;
109+ fs . writeFileSync ( prBodyPath , prBody . trim ( ) ) ;
110+ console . log ( `PR body saved to ${ prBodyPath } ` ) ;
111+ }
112+
92113/**
93- * Stores the output of git diff to a file.
114+ * Main run function, stores the output of git diff and the body of the matching PR to a file.
94115 *
95- * @returns Returns a promise that resolves when the git diff output is successfully stored.
116+ * @returns Returns a promise that resolves when the git diff output and PR body is successfully stored.
96117 */
97- async function storeGitDiffOutput ( ) {
118+ async function storeGitDiffOutputAndPrBody ( ) {
98119 try {
99120 // Create the directory
100121 // This is done first because our CirleCI config requires that this directory is present,
101122 // even if we want to skip this step.
102- const outputDir = 'changed-files' ;
103- fs . mkdirSync ( outputDir , { recursive : true } ) ;
123+ fs . mkdirSync ( CHANGED_FILES_DIR , { recursive : true } ) ;
104124
105- console . log ( `Determining whether this run is for a PR targetting ${ MAIN_BRANCH } ` )
106- if ( ! process . env . CIRCLE_PULL_REQUEST ) {
107- console . log ( "Not a PR, skipping git diff" ) ;
125+ console . log (
126+ `Determining whether this run is for a PR targeting ${ MAIN_BRANCH } ` ,
127+ ) ;
128+ if ( ! PR_NUMBER ) {
129+ console . log ( 'Not a PR, skipping git diff' ) ;
108130 return ;
109131 }
110132
111- const baseRef = await getBaseRef ( ) ;
112- if ( baseRef === null ) {
113- console . log ( "Not a PR, skipping git diff" ) ;
133+ const prInfo = await getPrInfo ( ) ;
134+
135+ const baseRef = prInfo ?. base . ref ;
136+ if ( ! baseRef ) {
137+ console . log ( 'Not a PR, skipping git diff' ) ;
114138 return ;
115139 } else if ( baseRef !== MAIN_BRANCH ) {
116140 console . log ( `This is for a PR targeting '${ baseRef } ', skipping git diff` ) ;
141+ writePrBodyToFile ( prInfo . body ) ;
117142 return ;
118143 }
119144
120- console . log ( " Attempting to get git diff..." ) ;
145+ console . log ( ' Attempting to get git diff...' ) ;
121146 const diffOutput = await gitDiff ( ) ;
122147 console . log ( diffOutput ) ;
123148
124149 // Store the output of git diff
125- const outputPath = path . resolve ( outputDir , 'changed-files.txt' ) ;
150+ const outputPath = path . resolve ( CHANGED_FILES_DIR , 'changed-files.txt' ) ;
126151 fs . writeFileSync ( outputPath , diffOutput . trim ( ) ) ;
127-
128152 console . log ( `Git diff results saved to ${ outputPath } ` ) ;
153+
154+ writePrBodyToFile ( prInfo . body ) ;
155+
129156 process . exit ( 0 ) ;
130157 } catch ( error : any ) {
131158 console . error ( 'An error occurred:' , error . message ) ;
132159 process . exit ( 1 ) ;
133160 }
134161}
135162
136- storeGitDiffOutput ( ) ;
163+ storeGitDiffOutputAndPrBody ( ) ;
0 commit comments