11#!/usr/bin/env node
22import { spawnSync } from 'node:child_process' ;
3+ import { readFileSync } from 'node:fs' ;
34import { dirname , resolve } from 'node:path' ;
45import { fileURLToPath } from 'node:url' ;
56
@@ -77,8 +78,12 @@ function parseBaseArg(argv) {
7778}
7879
7980function resolveBaseRef ( preferredRef ) {
81+ const headCommit = resolveGitCommit ( 'HEAD' ) ;
8082 if ( hasGitRef ( preferredRef ) ) {
81- return preferredRef ;
83+ const preferredCommit = resolveGitCommit ( preferredRef ) ;
84+ if ( ! headCommit || preferredCommit !== headCommit ) {
85+ return preferredRef ;
86+ }
8287 }
8388
8489 const refs = [ ] ;
@@ -96,9 +101,22 @@ function resolveBaseRef(preferredRef) {
96101
97102 for ( const ref of refs ) {
98103 if ( hasGitRef ( ref ) ) {
99- return ref ;
104+ const candidateCommit = resolveGitCommit ( ref ) ;
105+ if ( ! headCommit || candidateCommit !== headCommit ) {
106+ return ref ;
107+ }
108+ }
109+ }
110+
111+ for ( const ref of getPreviousCommitCandidates ( ) ) {
112+ if ( hasGitRef ( ref ) ) {
113+ const candidateCommit = resolveGitCommit ( ref ) ;
114+ if ( ! headCommit || candidateCommit !== headCommit ) {
115+ return ref ;
116+ }
100117 }
101118 }
119+
102120 return null ;
103121}
104122
@@ -117,6 +135,28 @@ function hasGitRef(ref) {
117135 return result . status === 0 ;
118136}
119137
138+ function resolveGitCommit ( ref ) {
139+ if ( ! ref ) {
140+ return null ;
141+ }
142+
143+ const result = spawnSync (
144+ 'git' ,
145+ [ 'rev-parse' , '--verify' , '--quiet' , `${ ref } ^{commit}` ] ,
146+ {
147+ cwd : ROOT ,
148+ stdio : 'pipe' ,
149+ encoding : 'utf-8' ,
150+ } ,
151+ ) ;
152+
153+ if ( result . status !== 0 ) {
154+ return null ;
155+ }
156+
157+ return result . stdout . trim ( ) || null ;
158+ }
159+
120160function getChangedFiles ( baseRef , headRef ) {
121161 const result = spawnSync ( 'git' , [ 'diff' , '--name-only' , baseRef , headRef ] , {
122162 cwd : ROOT ,
@@ -187,11 +227,37 @@ function isGlobalPackageTestImpactPath(changedFilePath) {
187227 changedFilePath === 'pnpm-workspace.yaml' ||
188228 changedFilePath === 'turbo.json' ||
189229 changedFilePath === 'tsconfig.base.json' ||
230+ changedFilePath . startsWith ( 'scripts/' ) ||
231+ changedFilePath . startsWith ( 'tools/scripts/' ) ||
190232 / ^ j e s t \. (?: p r e s e t | c o n f i g ) \. [ c m ] ? [ j t ] s $ / . test ( changedFilePath ) ||
191233 / ^ b a b e l \. c o n f i g \. (?: j s o n | [ c m ] ? [ j t ] s ) $ / . test ( changedFilePath )
192234 ) ;
193235}
194236
237+ function getPreviousCommitCandidates ( ) {
238+ const refs = new Set ( ) ;
239+
240+ if ( process . env . GITHUB_EVENT_BEFORE ) {
241+ refs . add ( process . env . GITHUB_EVENT_BEFORE ) ;
242+ }
243+
244+ const eventPath = process . env . GITHUB_EVENT_PATH ;
245+ if ( eventPath ) {
246+ try {
247+ const payload = JSON . parse ( readFileSync ( eventPath , 'utf-8' ) ) ;
248+ if ( typeof payload ?. before === 'string' && payload . before ) {
249+ refs . add ( payload . before ) ;
250+ }
251+ } catch {
252+ // Ignore invalid GitHub event payloads.
253+ }
254+ }
255+
256+ refs . add ( 'HEAD~1' ) ;
257+
258+ return Array . from ( refs ) ;
259+ }
260+
195261function getWorkspacePackages ( ) {
196262 const result = spawnSync (
197263 'pnpm' ,
0 commit comments