@@ -29,6 +29,27 @@ const hasUncommittedChanges = async (
2929 return ! ! status . stdout . trim ( ) ;
3030} ;
3131
32+ const getCommitMetadata = async (
33+ sshRun : ( cmd : string ) => Promise < { stdout : string } > ,
34+ skipCount = 0
35+ ) => {
36+ const skip = skipCount > 0 ? `--skip=${ skipCount } ` : '' ;
37+ const subject = ( await sshRun ( `git log -1 ${ skip } --format=%s` ) ) . stdout . trim ( ) ;
38+ const body = ( await sshRun ( `git log -1 ${ skip } --format=%b` ) ) . stdout . trim ( ) ;
39+ const authorDate = ( await sshRun ( `git log -1 ${ skip } --format=%aI` ) ) . stdout . trim ( ) ;
40+ const authorName = ( await sshRun ( `git log -1 ${ skip } --format=%an` ) ) . stdout . trim ( ) ;
41+ const timestamp =
42+ Number . parseInt ( ( await sshRun ( `git log -1 ${ skip } --format=%at` ) ) . stdout . trim ( ) ) * 1000 ;
43+
44+ return {
45+ subject,
46+ body,
47+ authorDate,
48+ authorName,
49+ timestamp,
50+ } ;
51+ } ;
52+
3253const updateCurrentCommit = async (
3354 sshRun : ( cmd : string ) => Promise < { stdout : string } > ,
3455 subject : string ,
@@ -132,33 +153,53 @@ export const squashUpdates = async (
132153 return ;
133154 }
134155
135- // Get current commit info
136- const lastCommitSubject = ( await sshRun ( 'git log -1 --format=%s' ) ) . stdout . trim ( ) ;
137- const lastCommitBody = ( await sshRun ( 'git log -1 --format=%b' ) ) . stdout . trim ( ) ;
156+ // Keep squashing while the previous commit is from an automated author
157+ let continueSquashing = true ;
158+ let loopCount = 0 ;
159+ const MAX_SQUASH_LOOPS = 50 ; // To prevent infinite loops
160+
161+ while ( continueSquashing && loopCount < MAX_SQUASH_LOOPS ) {
162+ loopCount ++ ;
163+ logger . info ( `Squash loop iteration ${ loopCount } ` ) ;
164+
165+ // Get current commit info (needs to be inside loop as HEAD changes after each squash)
166+ const lastCommit = await getCommitMetadata ( sshRun , 0 ) ;
167+
168+ // Get previous commit info
169+ const prevCommit = await getCommitMetadata ( sshRun , 1 ) ;
170+
171+ const isAutomatedAuthor = / d e p e n d a b o t | r e n o v a t e / i. test ( prevCommit . authorName ) ;
172+
173+ // If previous commit is not from automated author, stop squashing
174+ if ( ! isAutomatedAuthor ) {
175+ continueSquashing = false ;
176+ } else {
177+ // Previous commit is from automated author, squash them together
178+ logger . info ( `Squashing last 2 commits together (previous author: ${ prevCommit . authorName } )` ) ;
179+ await squashLastTwoCommits (
180+ sshRun ,
181+ lastCommit . subject ,
182+ lastCommit . body ,
183+ prevCommit . body ,
184+ prevCommit . authorDate
185+ ) ;
186+ }
187+ }
188+
189+ if ( loopCount >= MAX_SQUASH_LOOPS ) {
190+ logger . warn ( `Reached maximum squash loop limit of ${ MAX_SQUASH_LOOPS } ` ) ;
191+ }
138192
139- // Get previous commit info
140- const prevCommitSubject = ( await sshRun ( 'git log -1 --skip=1 --format=%s' ) ) . stdout . trim ( ) ;
141- const prevCommitBody = ( await sshRun ( 'git log -1 --skip=1 --format=%b' ) ) . stdout . trim ( ) ;
142- const prevCommitAuthorDate = ( await sshRun ( 'git log -1 --skip=1 --format=%aI' ) ) . stdout . trim ( ) ;
143- const prevCommitTimestamp =
144- Number . parseInt ( ( await sshRun ( 'git log -1 --skip=1 --format=%at' ) ) . stdout . trim ( ) ) * 1000 ;
193+ // Get current commit info after squashing
194+ const lastCommit = await getCommitMetadata ( sshRun , 0 ) ;
195+ const prevCommit = await getCommitMetadata ( sshRun , 1 ) ;
145196
146197 const DAYS_AGO = Date . now ( ) - SQUASH__DEPS_DAYS_AGO * 24 * 60 * 60 * 1000 ;
147198
148199 // If previous commit is old or doesn't start with "Update dependencies", just update current commit
149- if ( prevCommitTimestamp < DAYS_AGO || ! prevCommitSubject . includes ( SQUASH_UPDATE_MESSAGE ) ) {
200+ if ( prevCommit . timestamp < DAYS_AGO || ! prevCommit . subject . includes ( SQUASH_UPDATE_MESSAGE ) ) {
150201 logger . info ( 'Updating current commit message only (previous is old or not an update commit)' ) ;
151- await updateCurrentCommit ( sshRun , lastCommitSubject , lastCommitBody ) ;
152- } else {
153- // Previous commit already has "Update dependencies", squash them together
154- logger . info ( 'Squashing last 2 commits together' ) ;
155- await squashLastTwoCommits (
156- sshRun ,
157- lastCommitSubject ,
158- lastCommitBody ,
159- prevCommitBody ,
160- prevCommitAuthorDate
161- ) ;
202+ await updateCurrentCommit ( sshRun , lastCommit . subject , lastCommit . body ) ;
162203 }
163204
164205 // After squashing, check if we've exceeded the max number of update commits
0 commit comments