Skip to content

Commit e9a6871

Browse files
committed
adds route: /v1/github/(orgs|users)/{login_name}/projects/{project_id_or_name}/repositories​/contributions (closes #58) [1.2.0]
1 parent a92d409 commit e9a6871

File tree

5 files changed

+167
-38
lines changed

5 files changed

+167
-38
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ bun run dev
1818

1919
Open <http://localhost:3000/> with your browser to see the result.
2020

21+
### GitHub GraphQL-Explorer
22+
23+
The [Github GraphQL-Explorer](https://docs.github.com/en/graphql/overview/explorer) can only be used on the GitHub docs domain, because everything else is not in GitHub's CORS policy (docs.github.com).
24+
25+
The window is quite small. I recommend using a [Stylus](https://chromewebstore.google.com/detail/stylus/clngdbkpkpeebahjckkjfobafhncgmne) user-css to make it larger. ([example](https://gist.github.com/jonasfroeller/c1714de2d7fb162fdef94e3f83df9d0e)).
26+
Use a [diacritics remover](https://pteo.paranoiaworks.mobi/diacriticsremover), if you copied the graphql from somewhere else, before pasting it.
27+
2128
### Testing
2229

2330
[![cov](https://propromo-software.github.io/propromo.rest/coverage.svg)](https://github.com/propromo-software/propromo.rest/actions)

src/v1/adapters/github/index.ts

+49-1
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,55 @@ const ACCOUNT_LEVEL_CHILDREN = (login_type: "organization" | "user") =>
10181018
tags: ["github"],
10191019
},
10201020
},
1021-
),
1021+
)
1022+
.get(
1023+
"/contributions",
1024+
async ({
1025+
fetchParams,
1026+
params: { login_name, project_id_or_name },
1027+
query,
1028+
set,
1029+
}) => {
1030+
const response =
1031+
await fetchGithubDataUsingGraphql<{
1032+
project: ProjectV2;
1033+
}>(
1034+
AccountScopeEntryRoot(
1035+
login_name,
1036+
getAllRepositoriesInProject(
1037+
project_id_or_name,
1038+
[
1039+
GITHUB_PROJECT_SCOPES.REPOSITORIES_LINKED,
1040+
],
1041+
[
1042+
{
1043+
scopeName: GITHUB_REPOSITORY_SCOPES.CONTRIBUTIONS,
1044+
pageSize: query.pageSize ?? 1,
1045+
continueAfter: query.continueAfter?.replaceAll("+", " "), // TODO: make this global (not sure, if only commits can have spaces in page hashes)
1046+
},
1047+
{
1048+
scopeName: GITHUB_REPOSITORY_SCOPES.COUNT,
1049+
pageSize: query.rootPageSize ?? 1,
1050+
continueAfter: query.rootContinueAfter,
1051+
},
1052+
] as PageSize<GITHUB_REPOSITORY_SCOPES>[],
1053+
),
1054+
login_type,
1055+
),
1056+
fetchParams.auth,
1057+
set,
1058+
fetchParams.auth_type,
1059+
);
1060+
1061+
return response;
1062+
},
1063+
{
1064+
detail: {
1065+
description: `Request repository contributions in the ${login_type} project.`,
1066+
tags: ["github"],
1067+
}
1068+
}
1069+
)
10221070
)
10231071

10241072
/**

src/v1/adapters/github/scopes.ts

+106-33
Original file line numberDiff line numberDiff line change
@@ -440,18 +440,20 @@ export class Repository extends FetcherExtended {
440440
#doFetchMilestones = false;
441441
#doFetchIssues = false;
442442
#doFetchCollaborators = false;
443+
#doFetchContributions = false;
443444

444445
static defaultPageSize = 10;
445-
#rootPageSize: number;
446-
#vulnerabilitiesPageSize: number;
447-
#topicsPageSize: number;
448-
#labelsPageSize: number;
449-
#releasesPageSize: number;
450-
#deploymentsPageSize: number;
451-
#languagesPageSize: number;
452-
#milestonesPageSize: number;
453-
#issuesPageSize: number;
454-
#collaboratorsPageSize: number;
446+
#rootPageSize: number = Repository.defaultPageSize;
447+
#vulnerabilitiesPageSize: number = Repository.defaultPageSize;
448+
#topicsPageSize: number = Repository.defaultPageSize;
449+
#labelsPageSize: number = Repository.defaultPageSize;
450+
#releasesPageSize: number = Repository.defaultPageSize;
451+
#deploymentsPageSize: number = Repository.defaultPageSize;
452+
#languagesPageSize: number = Repository.defaultPageSize;
453+
#milestonesPageSize: number = Repository.defaultPageSize;
454+
#issuesPageSize: number = Repository.defaultPageSize;
455+
#collaboratorsPageSize: number = Repository.defaultPageSize;
456+
#contributionsPageSize: number = Repository.defaultPageSize;
455457

456458
#rootContinueAfter: string | undefined | null = null;
457459
#vulnerabilitiesContinueAfter: string | undefined | null = null;
@@ -463,6 +465,7 @@ export class Repository extends FetcherExtended {
463465
#milestonesContinueAfter: string | undefined | null = null;
464466
#issuesContinueAfter: string | undefined | null = null;
465467
#collaboratorsContinueAfter: string | undefined | null = null;
468+
#contributionsContinueAfter: string | undefined | null = null;
466469

467470
#count_nodes = false;
468471
#log = false;
@@ -474,18 +477,7 @@ export class Repository extends FetcherExtended {
474477
) {
475478
super(("name" in args) ? args.name : null);
476479

477-
this.#log = DEV_MODE;
478-
479-
this.#rootPageSize = Repository.defaultPageSize;
480-
this.#vulnerabilitiesPageSize = Repository.defaultPageSize;
481-
this.#topicsPageSize = Repository.defaultPageSize;
482-
this.#labelsPageSize = Repository.defaultPageSize;
483-
this.#releasesPageSize = Repository.defaultPageSize;
484-
this.#deploymentsPageSize = Repository.defaultPageSize;
485-
this.#languagesPageSize = Repository.defaultPageSize;
486-
this.#milestonesPageSize = Repository.defaultPageSize;
487-
this.#issuesPageSize = Repository.defaultPageSize;
488-
this.#collaboratorsPageSize = Repository.defaultPageSize;
480+
this.#log = DEV_MODE
489481

490482
this.#parseScopes(args.scopes);
491483
}
@@ -567,6 +559,10 @@ export class Repository extends FetcherExtended {
567559
this.#collaboratorsPageSize = ps.pageSize ?? this.#collaboratorsPageSize;
568560
this.#collaboratorsContinueAfter = this.#validateCursor(ps.continueAfter);
569561
break;
562+
case GITHUB_REPOSITORY_SCOPES.CONTRIBUTIONS:
563+
this.#doFetchContributions = true;
564+
this.#contributionsPageSize = ps.pageSize ?? this.#contributionsPageSize;
565+
this.#contributionsContinueAfter = this.#validateCursor(ps.continueAfter);
570566
default:
571567
break;
572568
}
@@ -625,7 +621,8 @@ export class Repository extends FetcherExtended {
625621
${this.#releasesBody()}
626622
${this.#deploymentsBody()}
627623
${this.#languagesBody()}
628-
${this.#collaboratorsBody()}
624+
${this.#collaboratorsBody()}
625+
${this.#contributionsBody()}
629626
}
630627
`;
631628
}
@@ -651,7 +648,8 @@ export class Repository extends FetcherExtended {
651648
${this.#releasesBody()}
652649
${this.#deploymentsBody()}
653650
${this.#languagesBody()}
654-
${this.#collaboratorsBody()}
651+
${this.#collaboratorsBody()}
652+
${this.#contributionsBody()}
655653
}
656654
}`;
657655
}
@@ -678,8 +676,10 @@ export class Repository extends FetcherExtended {
678676
${this.#milestonesBody(
679677
issues_states ?? [GITHUB_MILESTONE_ISSUE_STATES.OPEN],
680678
milestones_amount,
681-
milestone_number,
682-
)}
679+
milestone_number)}
680+
681+
${this.#collaboratorsBody()}
682+
${this.#contributionsBody()}
683683
}
684684
`;
685685
}
@@ -709,8 +709,10 @@ export class Repository extends FetcherExtended {
709709
${this.#milestonesBody(
710710
issues_states ?? [GITHUB_MILESTONE_ISSUE_STATES.OPEN],
711711
milestones_amount,
712-
milestone_number,
713-
)}
712+
milestone_number)}
713+
714+
${this.#collaboratorsBody()}
715+
${this.#contributionsBody()}
714716
}
715717
}`;
716718
}
@@ -886,8 +888,7 @@ export class Repository extends FetcherExtended {
886888
if (this.#log) console.info("fetching releases");
887889

888890
return `
889-
releases(first: ${this.#releasesPageSize}, after: ${this.#releasesContinueAfter
890-
}) {
891+
releases(first: ${this.#releasesPageSize}, after: ${this.#releasesContinueAfter}) {
891892
${this.#count_nodes ? "totalCount" : ""}
892893
893894
pageInfo {
@@ -951,8 +952,7 @@ export class Repository extends FetcherExtended {
951952
if (this.#log) console.info("fetching deployments");
952953

953954
return `
954-
deployments(first: ${this.#deploymentsPageSize}, after: ${this.#deploymentsContinueAfter
955-
}) {
955+
deployments(first: ${this.#deploymentsPageSize}, after: ${this.#deploymentsContinueAfter}) {
956956
${this.#count_nodes ? "totalCount" : ""}
957957
958958
pageInfo {
@@ -963,7 +963,6 @@ export class Repository extends FetcherExtended {
963963
nodes {
964964
updatedAt
965965
createdAt
966-
updatedAt
967966
description
968967
environment
969968
task
@@ -976,6 +975,7 @@ export class Repository extends FetcherExtended {
976975
state
977976
deployment {
978977
createdAt
978+
updatedAt
979979
description
980980
commit {
981981
additions
@@ -1007,6 +1007,7 @@ export class Repository extends FetcherExtended {
10071007
state
10081008
deployment {
10091009
createdAt
1010+
updatedAt
10101011
description
10111012
commit {
10121013
additions
@@ -1217,4 +1218,76 @@ export class Repository extends FetcherExtended {
12171218

12181219
return "";
12191220
}
1221+
1222+
#contributionsBody() {
1223+
if (this.#doFetchContributions) {
1224+
if (this.#log) console.info("fetching contributions");
1225+
1226+
return `
1227+
defaultBranchRef {
1228+
target {
1229+
... on Commit {
1230+
history(first: ${this.#contributionsPageSize}, after: ${this.#contributionsContinueAfter}) {
1231+
${this.#count_nodes ? "totalCount" : ""}
1232+
1233+
pageInfo {
1234+
endCursor
1235+
hasNextPage
1236+
}
1237+
1238+
edges {
1239+
node {
1240+
... on Commit {
1241+
abbreviatedOid
1242+
oid
1243+
id
1244+
1245+
messageHeadlineHTML
1246+
messageBodyHTML
1247+
1248+
additions
1249+
deletions
1250+
changedFilesIfAvailable
1251+
1252+
commitUrl
1253+
treeUrl
1254+
1255+
committedDate
1256+
1257+
deployments(first: 1, orderBy: {direction: DESC, field: CREATED_AT}, after: null) {
1258+
totalCount
1259+
1260+
pageInfo {
1261+
endCursor
1262+
hasNextPage
1263+
}
1264+
1265+
nodes {
1266+
createdAt
1267+
updatedAt
1268+
1269+
description
1270+
1271+
latestStatus {
1272+
createdAt
1273+
updatedAt
1274+
state
1275+
description
1276+
environmentUrl
1277+
logUrl
1278+
}
1279+
}
1280+
}
1281+
}
1282+
}
1283+
}
1284+
}
1285+
}
1286+
}
1287+
}
1288+
`;
1289+
}
1290+
1291+
return "";
1292+
}
12201293
}

src/v1/adapters/github/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface RestResponse<T> {
3636
type?: string | undefined;
3737
}
3838

39-
export interface GraphqlResponse<T> extends RestResponse<T> {}
39+
export interface GraphqlResponse<T> extends RestResponse<T> { }
4040

4141
// in type GraphQlQueryResponse<ResponseData> of @octokit/graphql (has string as type...)
4242
export enum GraphqlResponseErrorCode {
@@ -89,6 +89,7 @@ export enum GITHUB_REPOSITORY_SCOPES {
8989
MILESTONES = "milestones",
9090
ISSUES = "issues",
9191
COLLABORATORS = "collaborators",
92+
CONTRIBUTIONS = "contributions",
9293
}
9394

9495
export enum GITHUB_MILESTONE_ISSUE_STATES {

src/v1/index.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ export const v1 = new Elysia({ prefix: `/${V1_PATH}` })
3535
.use(
3636
swagger({
3737
/* Stable: 1.17.16 */
38-
/* Modern UI: 1.25.25 */
39-
scalarVersion: "1.25.58",
38+
/* Modern UI: 1.25.25, 1.25.58 */
39+
scalarVersion: "1.25.68", // https://github.com/scalar/scalar/issues/3956
4040
path: SWAGGER_PATH,
4141
exclude: [
4242
...ROOT_PATHS,
@@ -49,7 +49,7 @@ export const v1 = new Elysia({ prefix: `/${V1_PATH}` })
4949
title: "Propromo RestAPI Documentation",
5050
description:
5151
"A RestAPI for the scopes of the Github GraphqlAPI, that Propromo needs (latest).",
52-
version: "1.1.0",
52+
version: "1.2.0",
5353
},
5454
tags: [
5555
{

0 commit comments

Comments
 (0)