@@ -100,6 +100,142 @@ export const GitHubUtils = {
100100 return null ;
101101 } ,
102102
103+ async fetchGitLogFromGitHub ( githubToken : string , owner : string , repo : string ) : Promise < string > {
104+ const octokit = this . createGitHubAPIClient ( githubToken ) ;
105+
106+ try {
107+ const repoInfo = await octokit . repos . get ( { owner, repo } ) ;
108+ const defaultBranch = repoInfo . data . default_branch ;
109+ const branches = await octokit . repos . listBranches ( { owner, repo } ) ;
110+
111+ let allCommits : any [ ] = [ ] ;
112+ const branchCommitMap = new Map < string , string [ ] > ( ) ;
113+
114+ for ( const branch of branches . data ) {
115+ try {
116+ let page = 1 ;
117+ let hasMoreCommits = true ;
118+ const branchCommits : string [ ] = [ ] ;
119+
120+ while ( hasMoreCommits && page <= 5 ) {
121+ const commits = await octokit . repos . listCommits ( {
122+ owner,
123+ repo,
124+ sha : branch . name ,
125+ per_page : 100 ,
126+ page
127+ } ) ;
128+
129+ allCommits . push ( ...commits . data . map ( commit => ( { ...commit , branchName : branch . name } ) ) ) ;
130+ branchCommits . push ( ...commits . data . map ( commit => commit . sha ) ) ;
131+ hasMoreCommits = commits . data . length === 100 ;
132+ page ++ ;
133+ }
134+
135+ branchCommitMap . set ( branch . name , branchCommits ) ;
136+ } catch ( error ) {
137+ console . debug ( `Failed to fetch commits for branch ${ branch . name } :` , error ) ;
138+ }
139+ }
140+
141+ const uniqueCommits = Array . from (
142+ new Map ( allCommits . map ( commit => [ commit . sha , commit ] ) ) . values ( )
143+ ) ;
144+
145+ uniqueCommits . sort ( ( a , b ) =>
146+ new Date ( a . commit . committer . date ) . getTime ( ) - new Date ( b . commit . committer . date ) . getTime ( )
147+ ) ;
148+
149+ const gitLogEntries = await Promise . all (
150+ uniqueCommits . slice ( 0 , 1000 ) . map ( async ( commit ) => {
151+ const hash = commit . sha ;
152+ const parents = commit . parents . map ( ( p : any ) => p . sha ) . join ( ' ' ) ;
153+
154+ const refs = [ ] ;
155+ for ( const [ branchName , commits ] of branchCommitMap . entries ( ) ) {
156+ if ( commits . includes ( hash ) ) {
157+ if ( branchName === defaultBranch ) {
158+ refs . push ( `origin/${ branchName } ` , branchName ) ;
159+ } else {
160+ refs . push ( `origin/${ branchName } ` ) ;
161+ }
162+ }
163+ }
164+
165+ if ( refs . length === 0 && commit . branchName ) {
166+ refs . push ( `origin/${ commit . branchName } ` ) ;
167+ }
168+
169+ const refString = refs . join ( ', ' ) ;
170+ const authorName = commit . commit . author ?. name || '' ;
171+ const authorEmail = commit . commit . author ?. email || '' ;
172+ const authorDate = commit . commit . author ?. date || '' ;
173+ const committerName = commit . commit . committer ?. name || '' ;
174+ const committerEmail = commit . commit . committer ?. email || '' ;
175+ const committerDate = commit . commit . committer ?. date || '' ;
176+ const message = commit . commit . message || '' ;
177+ const messageLines = message . split ( '\n' ) ;
178+ const subject = messageLines [ 0 ] || '' ;
179+ const body = messageLines . slice ( 1 ) . join ( '\n' ) . trim ( ) ;
180+
181+ let fileStats = '' ;
182+ try {
183+ const commitDetail = await octokit . repos . getCommit ( {
184+ owner,
185+ repo,
186+ ref : hash
187+ } ) ;
188+
189+ if ( commitDetail . data . files && commitDetail . data . files . length > 0 ) {
190+ fileStats = '\n' + commitDetail . data . files . map ( ( file : any ) => {
191+ const additions = file . additions || 0 ;
192+ const deletions = file . deletions || 0 ;
193+ const filename = file . filename || '' ;
194+ return `${ additions } \t${ deletions } \t${ filename } ` ;
195+ } ) . join ( '\n' ) ;
196+ }
197+ } catch ( error ) {
198+ console . debug ( `Failed to fetch file stats for commit ${ hash } ` ) ;
199+ }
200+
201+ const commitParts = [
202+ hash ,
203+ parents ,
204+ refString ,
205+ authorName ,
206+ authorEmail ,
207+ authorDate ,
208+ committerName ,
209+ committerEmail ,
210+ committerDate ,
211+ ` ${ subject } ` ,
212+ ] ;
213+
214+ if ( body ) {
215+ commitParts . push ( body ) ;
216+ }
217+
218+ return commitParts . join ( '\n' ) + fileStats ;
219+ } )
220+ ) ;
221+
222+ return '\n\n' + gitLogEntries . join ( '\n\n\n\n' ) ;
223+ } catch ( error : any ) {
224+ throw new Error ( `Failed to fetch commits from GitHub: ${ error . message } ` ) ;
225+ }
226+ } ,
227+
228+ async getDefaultBranch ( githubToken : string , owner : string , repo : string ) : Promise < string > {
229+ const octokit = this . createGitHubAPIClient ( githubToken ) ;
230+
231+ try {
232+ const repoInfo = await octokit . repos . get ( { owner, repo } ) ;
233+ return repoInfo . data . default_branch ;
234+ } catch ( error : any ) {
235+ throw new Error ( `Failed to get default branch: ${ error . message } ` ) ;
236+ }
237+ } ,
238+
103239 async safeApiCall < T > (
104240 apiCall : ( ) => Promise < T > ,
105241 errorMessage : string
@@ -143,3 +279,4 @@ export const CommonUtils = {
143279 return isNaN ( parsed ) ? 0 : parsed ;
144280 }
145281} ;
282+
0 commit comments