github-repository-provider 7.24.0 → 7.24.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-repository-provider",
3
- "version": "7.24.0",
3
+ "version": "7.24.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -42,7 +42,7 @@
42
42
  "ava": "^3.15.0",
43
43
  "c8": "^7.10.0",
44
44
  "documentation": "^13.2.5",
45
- "repository-provider-test-support": "^1.8.11",
45
+ "repository-provider-test-support": "^1.8.12",
46
46
  "semantic-release": "^18.0.1"
47
47
  },
48
48
  "engines": {
@@ -123,7 +123,6 @@ export class GithubProvider extends MultiGroupProvider {
123
123
  if (!response.ok) {
124
124
  this.error(`Unable to fetch ${response.status} ${response.url}`);
125
125
  throw new Error(`Unable to fetch ${response.status} ${response.url}`);
126
- //break;
127
126
  }
128
127
  return await response.json();
129
128
  } catch (e) {
@@ -138,26 +137,16 @@ export class GithubProvider extends MultiGroupProvider {
138
137
  */
139
138
  async initializeRepositories() {
140
139
  for (let page = 1; ; page++) {
141
- const response = await this.fetch(
142
- `user/repos?page=${page}&per_page=30`,
143
- {
144
- headers: {
145
- accept: "application/vnd.github.baptiste-preview+json"
146
- // accept: "application/vnd.github.v3+json"
140
+ try {
141
+ const json = await this.fetchJSON(
142
+ `user/repos?page=${page}&per_page=100`,
143
+ {
144
+ headers: {
145
+ accept: "application/vnd.github.baptiste-preview+json"
146
+ // accept: "application/vnd.github.v3+json"
147
+ }
147
148
  }
148
- }
149
- );
150
-
151
- if (!response.ok) {
152
- this.error(
153
- `Unable to fetch repositories ${response.status} ${response.url}`
154
149
  );
155
- return;
156
- }
157
-
158
- try {
159
- const json = await response.json();
160
-
161
150
  if (json.length === 0 || !Array.isArray(json)) {
162
151
  break;
163
152
  }
@@ -170,7 +159,7 @@ export class GithubProvider extends MultiGroupProvider {
170
159
  );
171
160
  });
172
161
  } catch (e) {
173
- this.error(e);
162
+ return;
174
163
  }
175
164
  }
176
165
  }
@@ -1,194 +0,0 @@
1
- import { matcher } from "matching-iterator";
2
- import { Branch } from "repository-provider";
3
- import {
4
- BaseCollectionEntry,
5
- BufferContentEntry,
6
- BufferContentEntryMixin,
7
- ContentEntry
8
- } from "content-entry";
9
-
10
- /**
11
- * Branch on GitHub.
12
- */
13
- export class GithubBranch extends Branch {
14
- /**
15
- * Writes content into the branch
16
- * {@link https://developer.github.com/v3/git/blobs/#get-a-blob}
17
- * @param {ConentEntry} entry
18
- * @return {Promise<Entry>} written content with sha values set
19
- */
20
- async writeEntry(entry) {
21
- const res = await this.provider.fetch(`repos/${this.slug}/git/blobs`, {
22
- method: "POST",
23
- body: JSON.stringify({
24
- content: await entry.string,
25
- encoding: "utf8"
26
- })
27
- });
28
- const json = await res.json();
29
-
30
- entry.sha = json.sha;
31
-
32
- return entry;
33
- }
34
-
35
- /**
36
- * {@link https://developer.github.com/v3/git/commits/#get-a-commit}
37
- * @param {string} sha
38
- */
39
- async baseTreeSha(sha) {
40
- const json = await this.provider.fetchJSON(
41
- `repos/${this.slug}/git/commits/${sha}`
42
- );
43
- return json.tree;
44
- }
45
-
46
- /**
47
- * {@link https://developer.github.com/v3/git/trees/#create-a-tree}
48
- * {@link https://developer.github.com/v3/git/commits/#create-a-commit}
49
- * {@link https://developer.github.com/v3/git/refs/#update-a-reference}
50
- * @param {string} message
51
- * @param {ContentEntry[]} entries
52
- * @param {Object} options
53
- */
54
- async commit(message, entries, options = {}) {
55
- const updates = await Promise.all(
56
- entries.map(entry => this.writeEntry(entry))
57
- );
58
-
59
- /*
60
- * 1st. commit on empty tree
61
- * https://stackoverflow.com/questions/9765453/is-gits-semi-secret-empty-tree-object-reliable-and-why-is-there-not-a-symbolic/9766506#9766506
62
- * empty_tree=$(git mktree </dev/null)
63
- * sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904
64
- * sha256:6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321
65
- */
66
-
67
- const shaLatestCommit = await this.refId();
68
- const shaBaseTree = await this.baseTreeSha(shaLatestCommit);
69
-
70
- let json = await this.provider.fetchJSON(`repos/${this.slug}/git/trees`, {
71
- method: "POST",
72
- body: JSON.stringify({
73
- base_tree: shaBaseTree,
74
- tree: updates.map(u => {
75
- return {
76
- path: u.name,
77
- sha: u.sha,
78
- type: "blob",
79
- mode: "100" + u.mode.toString(8)
80
- };
81
- })
82
- })
83
- });
84
-
85
- const shaNewTree = json.sha;
86
-
87
- json = await this.provider.fetchJSON(`repos/${this.slug}/git/commits`, {
88
- method: "POST",
89
- body: JSON.stringify({
90
- message,
91
- tree: shaNewTree,
92
- parents: [shaLatestCommit]
93
- })
94
- });
95
- const sha = json.sha;
96
-
97
- return this.provider.fetchJSON(
98
- `repos/${this.slug}/git/refs/heads/${this.name}`,
99
- {
100
- method: "PATCH",
101
- body: JSON.stringify({
102
- ...options,
103
- sha
104
- })
105
- }
106
- );
107
- }
108
-
109
- /**
110
- * {@link https://developer.github.com/v3/repos/contents/#get-repository-content}
111
- * @param {string} name
112
- */
113
- async entry(name) {
114
- const json = await this.provider.fetchJSON(
115
- `repos/${this.slug}/contents/${name}?ref=${this.ref}`
116
- );
117
-
118
- return new this.entryClass(name, Buffer.from(json.content, "base64"));
119
- }
120
-
121
- /** @inheritdoc */
122
- async maybeEntry(name) {
123
- const json = await this.provider.fetchJSON(
124
- `repos/${this.slug}/contents/${name}?ref=${this.ref}`
125
- );
126
- return new this.entryClass(name, Buffer.from(json.content, "base64"));
127
- }
128
-
129
- /**
130
- * @see https://developer.github.com/v3/git/trees/
131
- * @param {string } treeSha
132
- * @return {Object[]}
133
- */
134
- async tree(treeSha) {
135
- const json = await this.provider.fetchJSON(
136
- `repos/${this.slug}/git/trees/${treeSha}?recursive=1`
137
- );
138
- return json.tree;
139
- }
140
-
141
- async *entries(patterns) {
142
- const shaBaseTree = await this.baseTreeSha(await this.refId());
143
-
144
- for (const entry of matcher(await this.tree(shaBaseTree), patterns, {
145
- name: "path"
146
- })) {
147
- yield entry.type === "tree"
148
- ? new BaseCollectionEntry(entry.path)
149
- : new LazyBufferContentEntry(entry.path, this);
150
- }
151
- }
152
-
153
- /**
154
- * https://developer.github.com/v3/repos/contents/
155
- * @param {Iterator<ContentEntry>} entries
156
- */
157
- async removeEntries(entries) {
158
- for await (const entry of entries) {
159
- await this.provider.fetch(`repos/${this.slug}/contents/${entry.name}`, {
160
- method: "DELETE",
161
- body: JSON.stringify({ branch: this.name, message: "", sha: "" })
162
- });
163
- }
164
- }
165
-
166
- get entryClass() {
167
- return BufferContentEntry;
168
- }
169
- }
170
-
171
- class LazyBufferContentEntry extends BufferContentEntryMixin(ContentEntry) {
172
- constructor(name, branch) {
173
- super(name);
174
- this.branch = branch;
175
- }
176
-
177
- get buffer() {
178
- return this.getBuffer();
179
- }
180
-
181
- async getBuffer() {
182
- if (this._buffer) {
183
- return this._buffer;
184
- }
185
-
186
- const branch = this.branch;
187
- const json = await branch.provider.fetchJSON(
188
- `repos/${branch.slug}/contents/${this.name}?ref=${branch.ref}`
189
- );
190
-
191
- this._buffer = Buffer.from(json.content, "base64");
192
- return this._buffer;
193
- }
194
- }
@@ -1,199 +0,0 @@
1
- import fetch from "node-fetch";
2
- import { replaceWithOneTimeExecutionMethod } from "one-time-execution-method";
3
- import { rateLimitHandler, defaultWaitDecide } from "fetch-rate-limit-util";
4
-
5
- import { MultiGroupProvider } from "repository-provider";
6
- import { GithubRepository } from "./github-repository.mjs";
7
- import { GithubBranch } from "./github-branch.mjs";
8
- import { GithubOwner } from "./github-owner.mjs";
9
- import { GithubPullRequest } from "./github-pull-request.mjs";
10
- export { GithubRepository, GithubBranch, GithubOwner, GithubPullRequest };
11
-
12
- const domain = "github.com";
13
-
14
- /**
15
- * <!-- skip-example -->
16
- * GitHub provider.
17
- * Lookup a repository.
18
- * known environment variables
19
- * - GITHUB_TOKEN or GH_TOKEN api token
20
- * @example
21
- * import GithubProvider from 'github-repository-provider';
22
- *
23
- * const ghp = new GithubProvider();
24
- * const r1 = ghp.repository('git@github.com:arlac77/github-repository-provider.git');
25
- * const r2 = ghp.repository('git://github.com/arlac77/github-repository-provider.git');
26
- * const r3 = ghp.repository('git+ssh://github.com/arlac77/github-repository-provider.git');
27
- * const r4 = ghp.repository('https://github.com/arlac77/github-repository-provider.git#master');
28
- * const r5 = ghp.repository('git+https://github.com/arlac77/github-repository-provider.git#master');
29
- * const r6 = ghp.repository('arlac77/github-repository-provider');
30
- * // different ways to address the same repository
31
- */
32
- export class GithubProvider extends MultiGroupProvider {
33
- /**
34
- * We are called github.
35
- * @return {string} github
36
- */
37
- static get name() {
38
- return "github";
39
- }
40
-
41
- /**
42
- * @return {string} default instance environment name prefix
43
- */
44
- static get instanceIdentifier() {
45
- return "GITHUB_";
46
- }
47
-
48
- static get attributes() {
49
- return {
50
- ...super.attributes,
51
- ssh: {
52
- type: "url",
53
- default: `git@${domain}:`
54
- },
55
- url: {
56
- type: "url",
57
- env: ["{{instanceIdentifier}}SERVER_URL"],
58
- set: value => (value.endsWith("/") ? value : value + "/"),
59
- default: `https://${domain}/`
60
- },
61
- api: {
62
- type: "url",
63
- env: ["{{instanceIdentifier}}API_URL"],
64
- set: value => value.replace(/\/$/, ""),
65
- default: `https://api.${domain}`
66
- },
67
- "authentication.token": {
68
- type: "string",
69
- env: ["{{instanceIdentifier}}TOKEN", "GH_TOKEN"],
70
- additionalAttributes: { "authentication.type": "token" },
71
- private: true,
72
- mandatory: true
73
- },
74
- priority: { default: 1000.0 },
75
- reateLimitRemaining: { writable: true, default: 5000 }
76
- };
77
- }
78
-
79
- get repositoryClass() {
80
- return GithubRepository;
81
- }
82
-
83
- get branchClass() {
84
- return GithubBranch;
85
- }
86
-
87
- get repositoryGroupClass() {
88
- return GithubOwner;
89
- }
90
-
91
- fetch(url, options = {}) {
92
- return rateLimitHandler(
93
- () =>
94
- fetch(new URL(url, this.api), {
95
- ...options,
96
- headers: {
97
- authorization: `token ${this.authentication.token}`,
98
- ...options.headers
99
- }
100
- }),
101
- (millisecondsToWait, rateLimitRemaining, nthTry, response) => {
102
- this.rateLimitRemaining = rateLimitRemaining;
103
-
104
- const msecs = defaultWaitDecide(
105
- millisecondsToWait,
106
- rateLimitRemaining,
107
- nthTry,
108
- response
109
- );
110
-
111
- if (msecs > 0) {
112
- this.warn(`Rate limit reached: waiting for ${msecs / 1000}s`);
113
- }
114
- return msecs;
115
- }
116
- );
117
- }
118
-
119
- async fetchJSON(url, options) {
120
- for (let i = 0; i < 3; i++) {
121
- try {
122
- const response = await this.fetch(url, options);
123
- if (!response.ok) {
124
- this.error(`Unable to fetch ${response.status} ${response.url}`);
125
- throw new Error(`Unable to fetch ${response.status} ${response.url}`);
126
- //break;
127
- }
128
- return await response.json();
129
- } catch (e) {
130
- this.error(e);
131
- throw e;
132
- }
133
- }
134
- }
135
-
136
- /**
137
- * {@link https://developer.github.com/v3/repos/#list-repositories-for-the-authenticated-user}
138
- */
139
- async initializeRepositories() {
140
- for (let page = 1; ; page++) {
141
- const json = await this.fetchJSON(
142
- `user/repos?page=${page}`,
143
- {
144
- headers: {
145
- accept: "application/vnd.github.v3+json"
146
- }
147
- }
148
- );
149
-
150
- if (json.length === 0 || !Array.isArray(json)) {
151
- break;
152
- }
153
-
154
- json.forEach(r => {
155
- const [groupName, repoName] = r.full_name.split(/\//);
156
- this.addRepositoryGroup(groupName, r.owner).addRepository(repoName, r);
157
- });
158
- }
159
- }
160
-
161
- /**
162
- * All possible base urls.
163
- * - github:
164
- * - git@github.com
165
- * - git://github.com
166
- * - git+ssh://github.com
167
- * - https://github.com
168
- * - git+https://github.com
169
- * @return {string[]} common base urls of all repositories
170
- */
171
- get repositoryBases() {
172
- return super.repositoryBases.concat([
173
- this.url,
174
- "git+" + this.url,
175
- `git+ssh://${domain}`,
176
- `git://${domain}/`,
177
- `git@${domain}:`
178
- ]);
179
- }
180
-
181
- get areRepositoryNamesCaseSensitive() {
182
- return false;
183
- }
184
-
185
- get areGroupNamesCaseSensitive() {
186
- return false;
187
- }
188
-
189
- get pullRequestClass() {
190
- return GithubPullRequest;
191
- }
192
- }
193
-
194
- replaceWithOneTimeExecutionMethod(
195
- GithubProvider.prototype,
196
- "initializeRepositories"
197
- );
198
-
199
- export default GithubProvider;
@@ -1,235 +0,0 @@
1
- import { replaceWithOneTimeExecutionMethod } from "one-time-execution-method";
2
- import { Repository } from "repository-provider";
3
- import { getHeaderLink } from "fetch-link-util";
4
-
5
- /**
6
- * Repository on GitHub.
7
- */
8
- export class GithubRepository extends Repository {
9
- static get attributeMapping() {
10
- return {
11
- ...super.attributeMapping,
12
- archived: "isArchived",
13
- is_template: "isTemplate",
14
- private: "isPrivate",
15
- fork: "isFork",
16
- default_branch: "defaultBranchName"
17
- };
18
- }
19
-
20
- static get attributes() {
21
- return {
22
- ...super.attributes,
23
- auto_init: { type: "boolean", writable: true },
24
- allow_squash_merge: { type: "boolean", writable: true },
25
- allow_merge_commit: { type: "boolean", writable: true },
26
- allow_rebase_merge: { type: "boolean", writable: true },
27
- allow_auto_merge: { type: "boolean", writable: true },
28
- delete_branch_on_merge: { type: "boolean", writable: true }
29
- };
30
- }
31
-
32
- get defaultBranchName() {
33
- return "main";
34
- }
35
-
36
- async _initializeSlot(typeName, addMethodName) {
37
- let next = `repos/${this.slug}/${typeName}`;
38
-
39
- do {
40
- const response = await this.provider.fetch(next);
41
-
42
- if (!response.ok) {
43
- this.error(
44
- `Unable to fetch ${typeName} ${response.status} ${response.url}`
45
- );
46
- return;
47
- }
48
-
49
- const json = await response.json();
50
- json.forEach(b => this[addMethodName](b.name, b));
51
- next = getHeaderLink(response.headers);
52
- } while (next);
53
- }
54
-
55
- /**
56
- * {@link https://developer.github.com/v3/repos/branches/#list-branches}
57
- */
58
- async initializeBranches() {
59
- return this._initializeSlot("branches", "addBranch");
60
- }
61
-
62
- /**
63
- * {@link https://docs.github.com/en/rest/reference/repos#list-repository-tags}
64
- */
65
- async initializeTags() {
66
- return this._initializeSlot("tags", "addTag");
67
- }
68
-
69
- /**
70
- * @return {string[]} github https url
71
- */
72
- get urls() {
73
- return [`${this.provider.url}${this.fullName}.git`];
74
- }
75
-
76
- /**
77
- * Deliver the url of issue tracking system.
78
- * @return {string}
79
- */
80
- get issuesURL() {
81
- return `${this.provider.url}${this.fullName}/issues`;
82
- }
83
-
84
- /**
85
- * Deliver the url of the repositories home page.
86
- * @return {string}
87
- */
88
- get homePageURL() {
89
- return `${this.provider.url}${this.fullName}#readme`;
90
- }
91
-
92
- /**
93
- * {@link https://developer.github.com/v3/repos/#update-a-repository}
94
- */
95
- async update() {
96
- return this.provider.fetch(`repos/${this.slug}`, {
97
- method: "PATCH",
98
- body: JSON.stringify(
99
- mapAttributesInverse(
100
- optionJSON(this, undefined, this.constructor.writableAttributes),
101
- this.constructor.attributeMapping
102
- )
103
- )
104
- });
105
- }
106
-
107
- /**
108
- * {@link https://developer.github.com/v3/git/refs/}
109
- * @param {string} ref
110
- * @return {string} sha of the ref
111
- */
112
- async refId(ref) {
113
- ref = ref.replace(/^refs\//, "");
114
-
115
- const json = await this.provider.fetchJSON(`repos/${this.slug}/git/ref/${ref}`);
116
-
117
- // TODO why does this happen ?
118
- if (!json.object.sha) {
119
- throw new Error(`No refId for '${this.name}' '${ref}'`);
120
- }
121
-
122
- return json.object.sha;
123
- }
124
-
125
- async createBranch(name, from, options) {
126
- const branch = this._branches.get(name);
127
- if (branch) {
128
- return branch;
129
- }
130
-
131
- let sha;
132
-
133
- if (this._branches.size === 0) {
134
- /*
135
- * https://stackoverflow.com/questions/9765453/is-gits-semi-secret-empty-tree-object-reliable-and-why-is-there-not-a-symbolic/9766506#9766506
136
- * sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904
137
- * sha256:6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321
138
- */
139
- sha = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
140
- /*const res = await this.provider.fetch(`repos/${this.slug}/git/commits`, {
141
- method: "POST",
142
- body: JSON.stringify({
143
- message: "Initial commit",
144
- tree: sha
145
- })
146
- });
147
- console.log(res);
148
- */
149
- } else {
150
- const json = await this.provider.fetchJSON(
151
- `repos/${this.slug}/git/ref/heads/${
152
- from === undefined ? this.defaultBranchName : from.name
153
- }`
154
- );
155
- sha = json.object.sha;
156
- }
157
-
158
- const res = await this.provider.fetch(`repos/${this.slug}/git/refs`, {
159
- method: "POST",
160
- body: JSON.stringify({
161
- ref: `refs/heads/${name}`,
162
- sha
163
- })
164
- });
165
-
166
- if (res.ok) {
167
- return this.addBranch(name, options);
168
- }
169
- }
170
-
171
- async deleteBranch(name) {
172
- const res = await this.provider.fetch(
173
- `repos/${this.slug}/git/refs/heads/${name}`,
174
- {
175
- method: "DELETE"
176
- }
177
- );
178
-
179
- if (res.ok) {
180
- return super.deleteBranch(name);
181
- }
182
- }
183
-
184
- /**
185
- * {@link https://developer.github.com/v3/pulls/#update-a-pull-request}
186
- *
187
- * @param {string} name
188
- */
189
- async deletePullRequest(name) {
190
- const res = await this.provider.fetch(`repos/${this.slug}/pulls/${name}`, {
191
- method: "PATCH",
192
- body: JSON.stringify({ state: "closed" })
193
- });
194
-
195
- if (res.ok) {
196
- this._pullRequests.delete(name);
197
- }
198
- }
199
-
200
- /**
201
- * {@link https://developer.github.com/v3/repos/hooks/}
202
- */
203
- async initializeHooks() {
204
- let next = `repos/${this.slug}/hooks`;
205
-
206
- do {
207
- const response = await this.provider.fetch(next);
208
-
209
- for (const h of await response.json()) {
210
- const id = h.id;
211
- delete h.id;
212
- new this.hookClass(this, id, new Set(h.events), {
213
- ...h,
214
- ...h.config
215
- });
216
- }
217
- next = getHeaderLink(response.headers);
218
- } while (next);
219
- }
220
- }
221
-
222
- replaceWithOneTimeExecutionMethod(
223
- GithubRepository.prototype,
224
- "initializeBranches"
225
- );
226
-
227
- replaceWithOneTimeExecutionMethod(
228
- GithubRepository.prototype,
229
- "initializeHooks"
230
- );
231
-
232
- replaceWithOneTimeExecutionMethod(
233
- GithubRepository.prototype,
234
- "initializePullRequests"
235
- );