1
1
import type { GitHubApp } from './GitHubApp'
2
2
import type { RequestContext } from './RequestContext'
3
3
import { resolveGitHubUsernameFromId } from './resolveGitHubUsernameFromId'
4
- import { resolveOctokit , ContentsgartenOctokit } from './resolveOctokit'
4
+ import { ContentsgartenOctokit , resolveOctokit } from './resolveOctokit'
5
5
6
6
export interface ContentsgartenStorage {
7
7
getFile ( ctx : RequestContext , path : string ) : Promise < GetFileResult | undefined >
@@ -10,8 +10,13 @@ export interface ContentsgartenStorage {
10
10
path : string ,
11
11
options : PutFileOptions ,
12
12
) : Promise < PutFileResult >
13
+ listContributors (
14
+ ctx : RequestContext ,
15
+ path : string ,
16
+ ) : Promise < ListContributorsResult >
13
17
listFiles ( ctx : RequestContext ) : Promise < string [ ] >
14
18
}
19
+
15
20
export interface GetFileResult {
16
21
content : Buffer
17
22
lastModified ?: string
@@ -32,6 +37,16 @@ export interface PutFileResult {
32
37
lastModifiedBy : string [ ]
33
38
}
34
39
40
+ export interface ListContributorsResult {
41
+ contributors : Contributor [ ]
42
+ }
43
+
44
+ export interface Contributor {
45
+ login : string
46
+ avatarUrl : string
47
+ contributions : number
48
+ }
49
+
35
50
export class GitHubStorage implements ContentsgartenStorage {
36
51
owner : string
37
52
repo : string
@@ -128,6 +143,63 @@ export class GitHubStorage implements ContentsgartenStorage {
128
143
. filter ( ( item ) => item . type === 'blob' )
129
144
. map ( ( item ) => item . path ! )
130
145
}
146
+
147
+ async listContributors (
148
+ ctx : RequestContext ,
149
+ path : string ,
150
+ ) : Promise < ListContributorsResult > {
151
+ const octokit = await resolveOctokit ( ctx , this . config . app , this . config . repo )
152
+ const { owner, repo } = this
153
+ const { data } = await octokit . request ( 'POST /graphql' , {
154
+ query : `query($path: String!) {
155
+ repository(owner: "${ owner } ", name: "${ repo } ") {
156
+ object(expression: "${ this . config . branch } ") {
157
+ ... on Commit {
158
+ history(first: 100, path: $path) {
159
+ nodes {
160
+ oid
161
+ committedDate
162
+ authors(first: 2) {
163
+ nodes {
164
+ user {
165
+ avatarUrl(size: 64)
166
+ login
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }` ,
176
+ variables : {
177
+ path,
178
+ } ,
179
+ } )
180
+ const commits = data . data . repository . object . history . nodes
181
+ const profileMap = new Map < string , Contributor > ( )
182
+ for ( const commit of commits ) {
183
+ for ( const { user } of commit . authors . nodes ) {
184
+ if ( user . login . endsWith ( '[bot]' ) ) continue
185
+ const profile = profileMap . get ( user . login )
186
+ if ( profile ) {
187
+ profile . contributions ++
188
+ } else {
189
+ profileMap . set ( user . login , {
190
+ login : user . login ,
191
+ avatarUrl : user . avatarUrl ,
192
+ contributions : 1 ,
193
+ } )
194
+ }
195
+ }
196
+ }
197
+ return {
198
+ contributors : Array . from ( profileMap . values ( ) ) . sort (
199
+ ( a , b ) => b . contributions - a . contributions ,
200
+ ) ,
201
+ }
202
+ }
131
203
}
132
204
133
205
export interface GitHubStorageConfig {
0 commit comments