decap-cms-backend-github 3.4.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/decap-cms-backend-github.js +70 -70
- package/dist/decap-cms-backend-github.js.map +1 -1
- package/dist/esm/API.js +22 -11
- package/dist/esm/implementation.js +13 -6
- package/dist/esm/rateLimitLink.js +24 -0
- package/dist/esm/types/githubPullRequests.js +1 -0
- package/package.json +2 -2
- package/src/API.ts +131 -108
- package/src/GraphQLAPI.ts +8 -5
- package/src/__tests__/API.spec.js +15 -3
- package/src/implementation.tsx +16 -9
package/src/API.ts
CHANGED
|
@@ -39,14 +39,29 @@ import type {
|
|
|
39
39
|
ApiRequest,
|
|
40
40
|
} from 'decap-cms-lib-util';
|
|
41
41
|
import type { Semaphore } from 'semaphore';
|
|
42
|
-
import type {
|
|
43
|
-
|
|
44
|
-
type GitHubUser =
|
|
45
|
-
type GitCreateTreeParamsTree =
|
|
46
|
-
|
|
47
|
-
type
|
|
48
|
-
|
|
49
|
-
type
|
|
42
|
+
import type { Endpoints } from '@octokit/types';
|
|
43
|
+
|
|
44
|
+
type GitHubUser = Endpoints['GET /user']['response']['data'];
|
|
45
|
+
type GitCreateTreeParamsTree =
|
|
46
|
+
Endpoints['POST /repos/{owner}/{repo}/git/trees']['request']['data']['tree'][0];
|
|
47
|
+
type GitHubCompareCommit =
|
|
48
|
+
Endpoints['GET /repos/{owner}/{repo}/compare/{base}...{head}']['response']['data']['commits'][0];
|
|
49
|
+
type GitHubAuthor = Omit<
|
|
50
|
+
Endpoints['POST /repos/{owner}/{repo}/git/commits']['request']['data']['author'],
|
|
51
|
+
'name' | 'email' | 'date'
|
|
52
|
+
> & { name: string; email: string; date?: string };
|
|
53
|
+
type GitHubCommitter = Omit<
|
|
54
|
+
Endpoints['POST /repos/{owner}/{repo}/git/commits']['request']['data']['committer'],
|
|
55
|
+
'name' | 'email' | 'date'
|
|
56
|
+
> & { name: string; email: string; date?: string };
|
|
57
|
+
type GitHubPull = Omit<
|
|
58
|
+
Endpoints['GET /repos/{owner}/{repo}/pulls']['response']['data'][0],
|
|
59
|
+
'labels'
|
|
60
|
+
> & { labels: GitHubLabel[] };
|
|
61
|
+
type GitHubLabel = Omit<
|
|
62
|
+
Endpoints['GET /repos/{owner}/{repo}/pulls/{pull_number}']['response']['data']['labels'][0],
|
|
63
|
+
'description'
|
|
64
|
+
> & { description: string };
|
|
50
65
|
|
|
51
66
|
export const API_NAME = 'GitHub';
|
|
52
67
|
|
|
@@ -74,13 +89,20 @@ interface TreeFile {
|
|
|
74
89
|
raw?: string;
|
|
75
90
|
}
|
|
76
91
|
|
|
92
|
+
interface TreeFileForUpdate {
|
|
93
|
+
sha: string | null;
|
|
94
|
+
path: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
77
97
|
type Override<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;
|
|
78
98
|
|
|
79
99
|
type TreeEntry = Override<GitCreateTreeParamsTree, { sha: string | null }>;
|
|
80
100
|
|
|
81
101
|
type GitHubCompareCommits = GitHubCompareCommit[];
|
|
82
102
|
|
|
83
|
-
type GitHubCompareFile =
|
|
103
|
+
type GitHubCompareFile = NonNullable<
|
|
104
|
+
Endpoints['GET /repos/{owner}/{repo}/compare/{base}...{head}']['response']['data']['files']
|
|
105
|
+
>[0] & {
|
|
84
106
|
previous_filename?: string;
|
|
85
107
|
};
|
|
86
108
|
|
|
@@ -99,9 +121,10 @@ export enum PullRequestState {
|
|
|
99
121
|
All = 'all',
|
|
100
122
|
}
|
|
101
123
|
|
|
102
|
-
type GitHubCommitStatus =
|
|
103
|
-
|
|
104
|
-
|
|
124
|
+
type GitHubCommitStatus =
|
|
125
|
+
Endpoints['GET /repos/{owner}/{repo}/commits/{ref}/statuses']['response']['data'][0] & {
|
|
126
|
+
state: GitHubCommitStatusState;
|
|
127
|
+
};
|
|
105
128
|
|
|
106
129
|
interface MetaDataObjects {
|
|
107
130
|
entry: { path: string; sha: string };
|
|
@@ -164,7 +187,7 @@ function getTreeFiles(files: GitHubCompareFiles) {
|
|
|
164
187
|
arr.push({ sha: file.sha, path: file.filename });
|
|
165
188
|
}
|
|
166
189
|
return arr;
|
|
167
|
-
}, [] as
|
|
190
|
+
}, [] as TreeFileForUpdate[]);
|
|
168
191
|
|
|
169
192
|
return treeFiles;
|
|
170
193
|
}
|
|
@@ -234,15 +257,20 @@ export default class API {
|
|
|
234
257
|
if (!this._userPromise) {
|
|
235
258
|
this._userPromise = this.getUser({ token: this.token });
|
|
236
259
|
}
|
|
237
|
-
return this._userPromise
|
|
260
|
+
return this._userPromise.then(user => ({
|
|
261
|
+
name: user.name || 'Unknown',
|
|
262
|
+
login: user.login,
|
|
263
|
+
}));
|
|
238
264
|
}
|
|
239
265
|
|
|
240
266
|
async hasWriteAccess() {
|
|
241
267
|
try {
|
|
242
|
-
const result:
|
|
268
|
+
const result: Endpoints['GET /repos/{owner}/{repo}']['response']['data'] = await this.request(
|
|
269
|
+
this.repoURL,
|
|
270
|
+
);
|
|
243
271
|
// update config repoOwner to avoid case sensitivity issues with GitHub
|
|
244
272
|
this.repoOwner = result.owner.login;
|
|
245
|
-
return result.permissions
|
|
273
|
+
return result.permissions?.push ?? false;
|
|
246
274
|
} catch (error) {
|
|
247
275
|
console.error('Problem fetching repo data from GitHub');
|
|
248
276
|
throw error;
|
|
@@ -498,17 +526,15 @@ export default class API {
|
|
|
498
526
|
state: PullRequestState,
|
|
499
527
|
predicate: (pr: GitHubPull) => boolean,
|
|
500
528
|
) {
|
|
501
|
-
const pullRequests:
|
|
502
|
-
`${this.originRepoURL}/pulls`,
|
|
503
|
-
{
|
|
529
|
+
const pullRequests: Endpoints['GET /repos/{owner}/{repo}/pulls']['response']['data'] =
|
|
530
|
+
await this.requestAllPages(`${this.originRepoURL}/pulls`, {
|
|
504
531
|
params: {
|
|
505
532
|
...(head ? { head: await this.getHeadReference(head) } : {}),
|
|
506
533
|
base: this.branch,
|
|
507
534
|
state,
|
|
508
535
|
per_page: 100,
|
|
509
536
|
},
|
|
510
|
-
}
|
|
511
|
-
);
|
|
537
|
+
});
|
|
512
538
|
|
|
513
539
|
return pullRequests.filter(
|
|
514
540
|
pr => pr.head.ref.startsWith(`${CMS_BRANCH_PREFIX}/`) && predicate(pr),
|
|
@@ -544,7 +570,7 @@ export default class API {
|
|
|
544
570
|
? { name: statusToLabel(this.initialWorkflowStatus, this.cmsLabelPrefix) }
|
|
545
571
|
: { name: statusToLabel('pending_review', this.cmsLabelPrefix) };
|
|
546
572
|
|
|
547
|
-
pullRequest.labels.push(cmsLabel as
|
|
573
|
+
pullRequest.labels.push(cmsLabel as GitHubLabel);
|
|
548
574
|
return pullRequest;
|
|
549
575
|
}
|
|
550
576
|
}
|
|
@@ -569,9 +595,8 @@ export default class API {
|
|
|
569
595
|
return [];
|
|
570
596
|
}
|
|
571
597
|
try {
|
|
572
|
-
const commits:
|
|
573
|
-
`${this.originRepoURL}/pulls/${number}/commits
|
|
574
|
-
);
|
|
598
|
+
const commits: Endpoints['GET /repos/{owner}/{repo}/pulls/{pull_number}/commits']['response']['data'] =
|
|
599
|
+
await this.request(`${this.originRepoURL}/pulls/${number}/commits`);
|
|
575
600
|
return commits;
|
|
576
601
|
} catch (e) {
|
|
577
602
|
console.log(e);
|
|
@@ -579,7 +604,7 @@ export default class API {
|
|
|
579
604
|
}
|
|
580
605
|
}
|
|
581
606
|
|
|
582
|
-
async getPullRequestAuthor(pullRequest:
|
|
607
|
+
async getPullRequestAuthor(pullRequest: GitHubPull) {
|
|
583
608
|
if (!pullRequest.user?.login) {
|
|
584
609
|
return;
|
|
585
610
|
}
|
|
@@ -600,7 +625,7 @@ export default class API {
|
|
|
600
625
|
this.getDifferences(this.branch, pullRequest.head.sha),
|
|
601
626
|
this.getPullRequestAuthor(pullRequest),
|
|
602
627
|
]);
|
|
603
|
-
const diffs = await Promise.all(files.map(file => this.diffFromFile(file)));
|
|
628
|
+
const diffs = await Promise.all((files || []).map(file => this.diffFromFile(file)));
|
|
604
629
|
const label = pullRequest.labels.find(l => isCMSLabel(l.name, this.cmsLabelPrefix)) as {
|
|
605
630
|
name: string;
|
|
606
631
|
};
|
|
@@ -639,16 +664,14 @@ export default class API {
|
|
|
639
664
|
async readFileMetadata(path: string, sha: string | null | undefined) {
|
|
640
665
|
const fetchFileMetadata = async () => {
|
|
641
666
|
try {
|
|
642
|
-
const result:
|
|
643
|
-
`${this.originRepoURL}/commits`,
|
|
644
|
-
{
|
|
667
|
+
const result: Endpoints['GET /repos/{owner}/{repo}/commits']['response']['data'] =
|
|
668
|
+
await this.request(`${this.originRepoURL}/commits`, {
|
|
645
669
|
params: { path, sha: this.branch },
|
|
646
|
-
}
|
|
647
|
-
);
|
|
670
|
+
});
|
|
648
671
|
const { commit } = result[0];
|
|
649
672
|
return {
|
|
650
|
-
author: commit.author
|
|
651
|
-
updatedOn: commit.author
|
|
673
|
+
author: commit.author?.name || commit.author?.email || '',
|
|
674
|
+
updatedOn: commit.author?.date || '',
|
|
652
675
|
};
|
|
653
676
|
} catch (e) {
|
|
654
677
|
return { author: '', updatedOn: '' };
|
|
@@ -659,9 +682,10 @@ export default class API {
|
|
|
659
682
|
}
|
|
660
683
|
|
|
661
684
|
async fetchBlobContent({ sha, repoURL, parseText }: BlobArgs) {
|
|
662
|
-
const result:
|
|
663
|
-
|
|
664
|
-
|
|
685
|
+
const result: Endpoints['GET /repos/{owner}/{repo}/git/blobs/{file_sha}']['response']['data'] =
|
|
686
|
+
await this.request(`${repoURL}/git/blobs/${sha}`, {
|
|
687
|
+
cache: 'force-cache',
|
|
688
|
+
});
|
|
665
689
|
|
|
666
690
|
if (parseText) {
|
|
667
691
|
// treat content as a utf-8 string
|
|
@@ -685,24 +709,22 @@ export default class API {
|
|
|
685
709
|
): Promise<{ type: string; id: string; name: string; path: string; size: number }[]> {
|
|
686
710
|
const folder = trim(path, '/');
|
|
687
711
|
try {
|
|
688
|
-
const result:
|
|
689
|
-
`${repoURL}/git/trees/${branch}:${folder}`,
|
|
690
|
-
{
|
|
712
|
+
const result: Endpoints['GET /repos/{owner}/{repo}/git/trees/{tree_sha}']['response']['data'] =
|
|
713
|
+
await this.request(`${repoURL}/git/trees/${branch}:${folder}`, {
|
|
691
714
|
// GitHub API supports recursive=1 for getting the entire recursive tree
|
|
692
715
|
// or omitting it to get the non-recursive tree
|
|
693
716
|
params: depth > 1 ? { recursive: 1 } : {},
|
|
694
|
-
}
|
|
695
|
-
);
|
|
717
|
+
});
|
|
696
718
|
return (
|
|
697
719
|
result.tree
|
|
698
720
|
// filter only files and up to the required depth
|
|
699
|
-
.filter(file => file.type === 'blob' && file.path.split('/').length <= depth)
|
|
721
|
+
.filter(file => file.type === 'blob' && file.path && file.path.split('/').length <= depth)
|
|
700
722
|
.map(file => ({
|
|
701
723
|
type: file.type,
|
|
702
724
|
id: file.sha,
|
|
703
725
|
name: basename(file.path),
|
|
704
726
|
path: `${folder}/${file.path}`,
|
|
705
|
-
size: file.size
|
|
727
|
+
size: file.size || 0,
|
|
706
728
|
}))
|
|
707
729
|
);
|
|
708
730
|
} catch (err) {
|
|
@@ -821,9 +843,12 @@ export default class API {
|
|
|
821
843
|
}
|
|
822
844
|
|
|
823
845
|
async getOpenAuthoringBranches() {
|
|
824
|
-
const cmsBranches = await this.requestAllPages<
|
|
825
|
-
|
|
826
|
-
).catch(
|
|
846
|
+
const cmsBranches = await this.requestAllPages<
|
|
847
|
+
Endpoints['GET /repos/{owner}/{repo}/git/matching-refs/{ref}']['response']['data'][0]
|
|
848
|
+
>(`${this.repoURL}/git/refs/heads/cms/${this.repo}`).catch(
|
|
849
|
+
() =>
|
|
850
|
+
[] as Endpoints['GET /repos/{owner}/{repo}/git/matching-refs/{ref}']['response']['data'],
|
|
851
|
+
);
|
|
827
852
|
return cmsBranches;
|
|
828
853
|
}
|
|
829
854
|
|
|
@@ -836,7 +861,7 @@ export default class API {
|
|
|
836
861
|
let branches: string[];
|
|
837
862
|
if (this.useOpenAuthoring) {
|
|
838
863
|
// open authoring branches can exist without a pr
|
|
839
|
-
const cmsBranches:
|
|
864
|
+
const cmsBranches: Endpoints['GET /repos/{owner}/{repo}/git/matching-refs/{ref}']['response']['data'] =
|
|
840
865
|
await this.getOpenAuthoringBranches();
|
|
841
866
|
branches = cmsBranches.map(b => b.ref.slice('refs/heads/'.length));
|
|
842
867
|
// filter irrelevant branches
|
|
@@ -887,7 +912,7 @@ export default class API {
|
|
|
887
912
|
);
|
|
888
913
|
return resp.statuses.map(s => ({
|
|
889
914
|
context: s.context,
|
|
890
|
-
target_url: s.target_url,
|
|
915
|
+
target_url: s.target_url || '',
|
|
891
916
|
state:
|
|
892
917
|
s.state === GitHubCommitStatusState.Success ? PreviewState.Success : PreviewState.Other,
|
|
893
918
|
}));
|
|
@@ -930,7 +955,8 @@ export default class API {
|
|
|
930
955
|
const fileDataPath = encodeURIComponent(directory);
|
|
931
956
|
const fileDataURL = `${repoURL}/git/trees/${branch}:${fileDataPath}`;
|
|
932
957
|
|
|
933
|
-
const result:
|
|
958
|
+
const result: Endpoints['GET /repos/{owner}/{repo}/git/trees/{tree_sha}']['response']['data'] =
|
|
959
|
+
await this.request(fileDataURL);
|
|
934
960
|
const file = result.tree.find(file => file.path === filename);
|
|
935
961
|
if (file) {
|
|
936
962
|
return file.sha;
|
|
@@ -964,11 +990,11 @@ export default class API {
|
|
|
964
990
|
}
|
|
965
991
|
|
|
966
992
|
// async since it is overridden in a child class
|
|
967
|
-
async diffFromFile(diff:
|
|
993
|
+
async diffFromFile(diff: GitHubCompareFile): Promise<Diff> {
|
|
968
994
|
return {
|
|
969
995
|
path: diff.filename,
|
|
970
996
|
newFile: diff.status === 'added',
|
|
971
|
-
sha: diff.sha,
|
|
997
|
+
sha: diff.sha || '',
|
|
972
998
|
// media files diffs don't have a patch attribute, except svg files
|
|
973
999
|
// renamed files don't have a patch attribute too
|
|
974
1000
|
binary: (diff.status !== 'renamed' && !diff.patch) || diff.filename.endsWith('.svg'),
|
|
@@ -997,7 +1023,10 @@ export default class API {
|
|
|
997
1023
|
commitResponse.sha,
|
|
998
1024
|
options.commitMessage,
|
|
999
1025
|
);
|
|
1000
|
-
await this.setPullRequestStatus(
|
|
1026
|
+
await this.setPullRequestStatus(
|
|
1027
|
+
pr as GitHubPull,
|
|
1028
|
+
options.status || this.initialWorkflowStatus,
|
|
1029
|
+
);
|
|
1001
1030
|
}
|
|
1002
1031
|
} else {
|
|
1003
1032
|
// Entry is already on editorial review workflow - commit to existing branch
|
|
@@ -1006,7 +1035,7 @@ export default class API {
|
|
|
1006
1035
|
await this.getHeadReference(branch),
|
|
1007
1036
|
);
|
|
1008
1037
|
|
|
1009
|
-
const diffs = await Promise.all(diffFiles.map(file => this.diffFromFile(file)));
|
|
1038
|
+
const diffs = await Promise.all((diffFiles || []).map(file => this.diffFromFile(file)));
|
|
1010
1039
|
// mark media files to remove
|
|
1011
1040
|
const mediaFilesToRemove: { path: string; sha: string | null }[] = [];
|
|
1012
1041
|
for (const diff of diffs.filter(d => d.binary)) {
|
|
@@ -1030,9 +1059,8 @@ export default class API {
|
|
|
1030
1059
|
const attempts = this.useOpenAuthoring ? 10 : 1;
|
|
1031
1060
|
for (let i = 1; i <= attempts; i++) {
|
|
1032
1061
|
try {
|
|
1033
|
-
const result:
|
|
1034
|
-
`${this.originRepoURL}/compare/${from}...${to}
|
|
1035
|
-
);
|
|
1062
|
+
const result: Endpoints['GET /repos/{owner}/{repo}/compare/{base}...{head}']['response']['data'] =
|
|
1063
|
+
await this.request(`${this.originRepoURL}/compare/${from}...${to}`);
|
|
1036
1064
|
return result;
|
|
1037
1065
|
} catch (e) {
|
|
1038
1066
|
if (i === attempts) {
|
|
@@ -1061,8 +1089,12 @@ export default class API {
|
|
|
1061
1089
|
message,
|
|
1062
1090
|
tree.sha,
|
|
1063
1091
|
[baseCommit.sha],
|
|
1064
|
-
author
|
|
1065
|
-
|
|
1092
|
+
author
|
|
1093
|
+
? { name: author.name || '', email: author.email || '', date: author.date }
|
|
1094
|
+
: undefined,
|
|
1095
|
+
committer
|
|
1096
|
+
? { name: committer.name || '', email: committer.email || '', date: committer.date }
|
|
1097
|
+
: undefined,
|
|
1066
1098
|
);
|
|
1067
1099
|
return newCommit as unknown as GitHubCompareCommit;
|
|
1068
1100
|
} else {
|
|
@@ -1175,22 +1207,21 @@ export default class API {
|
|
|
1175
1207
|
}
|
|
1176
1208
|
|
|
1177
1209
|
async createRef(type: string, name: string, sha: string) {
|
|
1178
|
-
const result:
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1210
|
+
const result: Endpoints['POST /repos/{owner}/{repo}/git/refs']['response']['data'] =
|
|
1211
|
+
await this.request(`${this.repoURL}/git/refs`, {
|
|
1212
|
+
method: 'POST',
|
|
1213
|
+
body: JSON.stringify({ ref: `refs/${type}/${name}`, sha }),
|
|
1214
|
+
});
|
|
1182
1215
|
return result;
|
|
1183
1216
|
}
|
|
1184
1217
|
|
|
1185
1218
|
async patchRef(type: string, name: string, sha: string, opts: { force?: boolean } = {}) {
|
|
1186
1219
|
const force = opts.force || false;
|
|
1187
|
-
const result:
|
|
1188
|
-
`${this.repoURL}/git/refs/${type}/${encodeURIComponent(name)}`,
|
|
1189
|
-
{
|
|
1220
|
+
const result: Endpoints['PATCH /repos/{owner}/{repo}/git/refs/{ref}']['response']['data'] =
|
|
1221
|
+
await this.request(`${this.repoURL}/git/refs/${type}/${encodeURIComponent(name)}`, {
|
|
1190
1222
|
method: 'PATCH',
|
|
1191
1223
|
body: JSON.stringify({ sha, force }),
|
|
1192
|
-
}
|
|
1193
|
-
);
|
|
1224
|
+
});
|
|
1194
1225
|
return result;
|
|
1195
1226
|
}
|
|
1196
1227
|
|
|
@@ -1201,16 +1232,14 @@ export default class API {
|
|
|
1201
1232
|
}
|
|
1202
1233
|
|
|
1203
1234
|
async getBranch(branch: string) {
|
|
1204
|
-
const result:
|
|
1205
|
-
`${this.repoURL}/branches/${encodeURIComponent(branch)}
|
|
1206
|
-
);
|
|
1235
|
+
const result: Endpoints['GET /repos/{owner}/{repo}/branches/{branch}']['response']['data'] =
|
|
1236
|
+
await this.request(`${this.repoURL}/branches/${encodeURIComponent(branch)}`);
|
|
1207
1237
|
return result;
|
|
1208
1238
|
}
|
|
1209
1239
|
|
|
1210
1240
|
async getDefaultBranch() {
|
|
1211
|
-
const result:
|
|
1212
|
-
`${this.originRepoURL}/branches/${encodeURIComponent(this.branch)}
|
|
1213
|
-
);
|
|
1241
|
+
const result: Endpoints['GET /repos/{owner}/{repo}/branches/{branch}']['response']['data'] =
|
|
1242
|
+
await this.request(`${this.originRepoURL}/branches/${encodeURIComponent(this.branch)}`);
|
|
1214
1243
|
return result;
|
|
1215
1244
|
}
|
|
1216
1245
|
|
|
@@ -1285,61 +1314,56 @@ export default class API {
|
|
|
1285
1314
|
}
|
|
1286
1315
|
|
|
1287
1316
|
async createPR(title: string, head: string) {
|
|
1288
|
-
const result:
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1317
|
+
const result: Endpoints['POST /repos/{owner}/{repo}/pulls']['response']['data'] =
|
|
1318
|
+
await this.request(`${this.originRepoURL}/pulls`, {
|
|
1319
|
+
method: 'POST',
|
|
1320
|
+
body: JSON.stringify({
|
|
1321
|
+
title,
|
|
1322
|
+
body: DEFAULT_PR_BODY,
|
|
1323
|
+
head: await this.getHeadReference(head),
|
|
1324
|
+
base: this.branch,
|
|
1325
|
+
}),
|
|
1326
|
+
});
|
|
1297
1327
|
|
|
1298
1328
|
return result;
|
|
1299
1329
|
}
|
|
1300
1330
|
|
|
1301
1331
|
async openPR(number: number) {
|
|
1302
1332
|
console.log('%c Re-opening PR', 'line-height: 30px;text-align: center;font-weight: bold');
|
|
1303
|
-
const result:
|
|
1304
|
-
`${this.originRepoURL}/pulls/${number}`,
|
|
1305
|
-
{
|
|
1333
|
+
const result: Endpoints['PATCH /repos/{owner}/{repo}/pulls/{pull_number}']['response']['data'] =
|
|
1334
|
+
await this.request(`${this.originRepoURL}/pulls/${number}`, {
|
|
1306
1335
|
method: 'PATCH',
|
|
1307
1336
|
body: JSON.stringify({
|
|
1308
1337
|
state: PullRequestState.Open,
|
|
1309
1338
|
}),
|
|
1310
|
-
}
|
|
1311
|
-
);
|
|
1339
|
+
});
|
|
1312
1340
|
return result;
|
|
1313
1341
|
}
|
|
1314
1342
|
|
|
1315
1343
|
async closePR(number: number) {
|
|
1316
1344
|
console.log('%c Deleting PR', 'line-height: 30px;text-align: center;font-weight: bold');
|
|
1317
|
-
const result:
|
|
1318
|
-
`${this.originRepoURL}/pulls/${number}`,
|
|
1319
|
-
{
|
|
1345
|
+
const result: Endpoints['PATCH /repos/{owner}/{repo}/pulls/{pull_number}']['response']['data'] =
|
|
1346
|
+
await this.request(`${this.originRepoURL}/pulls/${number}`, {
|
|
1320
1347
|
method: 'PATCH',
|
|
1321
1348
|
body: JSON.stringify({
|
|
1322
1349
|
state: PullRequestState.Closed,
|
|
1323
1350
|
}),
|
|
1324
|
-
}
|
|
1325
|
-
);
|
|
1351
|
+
});
|
|
1326
1352
|
return result;
|
|
1327
1353
|
}
|
|
1328
1354
|
|
|
1329
1355
|
async mergePR(pullrequest: GitHubPull) {
|
|
1330
1356
|
console.log('%c Merging PR', 'line-height: 30px;text-align: center;font-weight: bold');
|
|
1331
1357
|
try {
|
|
1332
|
-
const result:
|
|
1333
|
-
`${this.originRepoURL}/pulls/${pullrequest.number}/merge`,
|
|
1334
|
-
{
|
|
1358
|
+
const result: Endpoints['PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge']['response']['data'] =
|
|
1359
|
+
await this.request(`${this.originRepoURL}/pulls/${pullrequest.number}/merge`, {
|
|
1335
1360
|
method: 'PUT',
|
|
1336
1361
|
body: JSON.stringify({
|
|
1337
1362
|
commit_message: MERGE_COMMIT_MESSAGE,
|
|
1338
1363
|
sha: pullrequest.head.sha,
|
|
1339
1364
|
merge_method: this.mergeMethod,
|
|
1340
1365
|
}),
|
|
1341
|
-
}
|
|
1342
|
-
);
|
|
1366
|
+
});
|
|
1343
1367
|
return result;
|
|
1344
1368
|
} catch (error) {
|
|
1345
1369
|
if (error instanceof APIError && error.status === 405) {
|
|
@@ -1355,7 +1379,7 @@ export default class API {
|
|
|
1355
1379
|
const files = getTreeFiles(result.files as GitHubCompareFiles);
|
|
1356
1380
|
|
|
1357
1381
|
let commitMessage = 'Automatically generated. Merged on Decap CMS\n\nForce merge of:';
|
|
1358
|
-
files.forEach(file => {
|
|
1382
|
+
files.forEach((file: TreeFileForUpdate) => {
|
|
1359
1383
|
commitMessage += `\n* "${file.path}"`;
|
|
1360
1384
|
});
|
|
1361
1385
|
console.log(
|
|
@@ -1439,10 +1463,11 @@ export default class API {
|
|
|
1439
1463
|
}
|
|
1440
1464
|
|
|
1441
1465
|
async createTree(baseSha: string, tree: TreeEntry[]) {
|
|
1442
|
-
const result:
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1466
|
+
const result: Endpoints['POST /repos/{owner}/{repo}/git/trees']['response']['data'] =
|
|
1467
|
+
await this.request(`${this.repoURL}/git/trees`, {
|
|
1468
|
+
method: 'POST',
|
|
1469
|
+
body: JSON.stringify({ base_tree: baseSha, tree }),
|
|
1470
|
+
});
|
|
1446
1471
|
return result;
|
|
1447
1472
|
}
|
|
1448
1473
|
|
|
@@ -1458,13 +1483,11 @@ export default class API {
|
|
|
1458
1483
|
author?: GitHubAuthor,
|
|
1459
1484
|
committer?: GitHubCommitter,
|
|
1460
1485
|
) {
|
|
1461
|
-
const result:
|
|
1462
|
-
`${this.repoURL}/git/commits`,
|
|
1463
|
-
{
|
|
1486
|
+
const result: Endpoints['POST /repos/{owner}/{repo}/git/commits']['response']['data'] =
|
|
1487
|
+
await this.request(`${this.repoURL}/git/commits`, {
|
|
1464
1488
|
method: 'POST',
|
|
1465
1489
|
body: JSON.stringify({ message, tree: treeSha, parents, author, committer }),
|
|
1466
|
-
}
|
|
1467
|
-
);
|
|
1490
|
+
});
|
|
1468
1491
|
return result;
|
|
1469
1492
|
}
|
|
1470
1493
|
|
package/src/GraphQLAPI.ts
CHANGED
|
@@ -27,7 +27,7 @@ import type { Config, BlobArgs } from './API';
|
|
|
27
27
|
import type { NormalizedCacheObject } from 'apollo-cache-inmemory';
|
|
28
28
|
import type { QueryOptions, MutationOptions, OperationVariables } from 'apollo-client';
|
|
29
29
|
import type { GraphQLError } from 'graphql';
|
|
30
|
-
import type {
|
|
30
|
+
import type { Endpoints } from '@octokit/types';
|
|
31
31
|
|
|
32
32
|
const NO_CACHE = 'no-cache';
|
|
33
33
|
const CACHE_FIRST = 'cache-first';
|
|
@@ -93,6 +93,7 @@ function transformPullRequest(pr: GraphQLPullRequest) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
type Error = GraphQLError & { type: string };
|
|
96
|
+
type GitHubPull = Endpoints['GET /repos/{owner}/{repo}/pulls']['response']['data'][0];
|
|
96
97
|
|
|
97
98
|
export default class GraphQLAPI extends API {
|
|
98
99
|
client: ApolloClient<NormalizedCacheObject>;
|
|
@@ -281,7 +282,7 @@ export default class GraphQLAPI extends API {
|
|
|
281
282
|
}
|
|
282
283
|
}
|
|
283
284
|
|
|
284
|
-
async getPullRequestAuthor(pullRequest:
|
|
285
|
+
async getPullRequestAuthor(pullRequest: GitHubPull) {
|
|
285
286
|
const user = pullRequest.user as unknown as GraphQLPullsListResponseItemUser;
|
|
286
287
|
return user?.name || user?.login;
|
|
287
288
|
}
|
|
@@ -289,7 +290,7 @@ export default class GraphQLAPI extends API {
|
|
|
289
290
|
async getPullRequests(
|
|
290
291
|
head: string | undefined,
|
|
291
292
|
state: PullRequestState,
|
|
292
|
-
predicate: (pr:
|
|
293
|
+
predicate: (pr: GitHubPull) => boolean,
|
|
293
294
|
) {
|
|
294
295
|
const { originRepoOwner: owner, originRepoName: name } = this;
|
|
295
296
|
let states;
|
|
@@ -319,7 +320,7 @@ export default class GraphQLAPI extends API {
|
|
|
319
320
|
|
|
320
321
|
const mapped = pullRequests.nodes.map(transformPullRequest);
|
|
321
322
|
|
|
322
|
-
return (mapped as unknown as
|
|
323
|
+
return (mapped as unknown as GitHubPull[]).filter(
|
|
323
324
|
pr => pr.head.ref.startsWith(`${CMS_BRANCH_PREFIX}/`) && predicate(pr),
|
|
324
325
|
);
|
|
325
326
|
}
|
|
@@ -692,7 +693,9 @@ export default class GraphQLAPI extends API {
|
|
|
692
693
|
},
|
|
693
694
|
});
|
|
694
695
|
const { pullRequest } = data!.createPullRequest;
|
|
695
|
-
return transformPullRequest(
|
|
696
|
+
return transformPullRequest(
|
|
697
|
+
pullRequest,
|
|
698
|
+
) as unknown as Endpoints['POST /repos/{owner}/{repo}/pulls']['response']['data'];
|
|
696
699
|
}
|
|
697
700
|
|
|
698
701
|
async getFileSha(path: string, { repoURL = this.repoURL, branch = this.branch } = {}) {
|
|
@@ -717,8 +717,8 @@ describe('github API', () => {
|
|
|
717
717
|
'message',
|
|
718
718
|
newTree.sha,
|
|
719
719
|
[baseCommit.sha],
|
|
720
|
-
{ name: 'author' },
|
|
721
|
-
{ name: 'committer' },
|
|
720
|
+
{ name: 'author', email: '', date: undefined },
|
|
721
|
+
{ name: 'committer', email: '', date: undefined },
|
|
722
722
|
);
|
|
723
723
|
});
|
|
724
724
|
});
|
|
@@ -756,6 +756,8 @@ describe('github API', () => {
|
|
|
756
756
|
path: 'posts/post.md',
|
|
757
757
|
type: 'blob',
|
|
758
758
|
name: 'post.md',
|
|
759
|
+
id: undefined,
|
|
760
|
+
size: 0,
|
|
759
761
|
},
|
|
760
762
|
]);
|
|
761
763
|
expect(api.request).toHaveBeenCalledTimes(1);
|
|
@@ -769,11 +771,15 @@ describe('github API', () => {
|
|
|
769
771
|
path: 'posts/post.md',
|
|
770
772
|
type: 'blob',
|
|
771
773
|
name: 'post.md',
|
|
774
|
+
id: undefined,
|
|
775
|
+
size: 0,
|
|
772
776
|
},
|
|
773
777
|
{
|
|
774
778
|
path: 'posts/dir1/nested-post.md',
|
|
775
779
|
type: 'blob',
|
|
776
780
|
name: 'nested-post.md',
|
|
781
|
+
id: undefined,
|
|
782
|
+
size: 0,
|
|
777
783
|
},
|
|
778
784
|
]);
|
|
779
785
|
expect(api.request).toHaveBeenCalledTimes(1);
|
|
@@ -787,16 +793,22 @@ describe('github API', () => {
|
|
|
787
793
|
path: 'posts/post.md',
|
|
788
794
|
type: 'blob',
|
|
789
795
|
name: 'post.md',
|
|
796
|
+
id: undefined,
|
|
797
|
+
size: 0,
|
|
790
798
|
},
|
|
791
799
|
{
|
|
792
800
|
path: 'posts/dir1/nested-post.md',
|
|
793
801
|
type: 'blob',
|
|
794
802
|
name: 'nested-post.md',
|
|
803
|
+
id: undefined,
|
|
804
|
+
size: 0,
|
|
795
805
|
},
|
|
796
806
|
{
|
|
797
807
|
path: 'posts/dir1/dir2/nested-post.md',
|
|
798
808
|
type: 'blob',
|
|
799
809
|
name: 'nested-post.md',
|
|
810
|
+
id: undefined,
|
|
811
|
+
size: 0,
|
|
800
812
|
},
|
|
801
813
|
]);
|
|
802
814
|
expect(api.request).toHaveBeenCalledTimes(1);
|
|
@@ -822,7 +834,7 @@ describe('github API', () => {
|
|
|
822
834
|
const slug = 'slug';
|
|
823
835
|
await expect(api.getStatuses(collection, slug)).resolves.toEqual([
|
|
824
836
|
{ context: 'deploy', state: 'success', target_url: 'deploy-url' },
|
|
825
|
-
{ context: 'build', state: 'other' },
|
|
837
|
+
{ context: 'build', state: 'other', target_url: '' },
|
|
826
838
|
]);
|
|
827
839
|
|
|
828
840
|
expect(api.getBranchPullRequest).toHaveBeenCalledTimes(1);
|