@teleporthq/teleport-github-gateway 0.19.17 → 0.19.21

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.
@@ -1,6 +1,5 @@
1
- // @ts-ignore
2
- import Github from 'github-api'
3
1
  import fetch from 'cross-fetch'
2
+ import { Octokit } from 'octokit'
4
3
 
5
4
  import { ServiceAuth } from '@teleporthq/teleport-types'
6
5
 
@@ -12,23 +11,22 @@ import {
12
11
  } from './constants'
13
12
 
14
13
  import {
15
- RepositoryContentResponse,
16
14
  GithubFileMeta,
17
15
  GithubRepositoryData,
18
16
  NewRepository,
19
- GithubRepository,
20
17
  GithubCommitMeta,
21
18
  RepositoryIdentity,
22
19
  GithubFile,
23
20
  RepositoryCommitsListMeta,
24
21
  RepositoryCommitMeta,
25
22
  CreateBranchMeta,
23
+ RepositoryMergeMeta,
24
+ RemoveBranchMeta,
26
25
  } from './types'
27
26
  import { createBase64GithubFileBlob } from './utils'
28
27
 
29
28
  export default class GithubInstance {
30
- // @ts-ignore
31
- private githubApi = null
29
+ private octokit: Octokit | null = null
32
30
  private auth: ServiceAuth = null
33
31
 
34
32
  constructor(auth: ServiceAuth = {}) {
@@ -39,99 +37,192 @@ export default class GithubInstance {
39
37
  this.auth = auth
40
38
 
41
39
  if (auth.basic) {
42
- this.githubApi = new Github({ ...auth.basic })
40
+ this.octokit = new Octokit({ auth: auth.basic })
41
+
43
42
  return
44
43
  }
45
44
 
46
45
  if (auth.token) {
47
- this.githubApi = new Github({ token: auth.token })
46
+ this.octokit = new Octokit({ auth: auth.token })
48
47
  return
49
48
  }
50
49
 
51
- this.githubApi = new Github()
50
+ this.octokit = new Octokit()
52
51
  }
53
52
 
54
53
  public async getRepoContent(
55
54
  repoIdentity: RepositoryIdentity
56
- ): Promise<RepositoryContentResponse> {
57
- const { username, repo, ref = DEFAULT_REF, path = DEFAULT_PATH } = repoIdentity
55
+ ): Promise<GithubFile | GithubFile[]> {
56
+ const { owner: username, repo, ref = DEFAULT_REF, path = DEFAULT_PATH } = repoIdentity
58
57
 
59
- const repository = await this.githubApi.getRepo(username, repo)
60
- return repository.getContents(ref, path)
58
+ const content = await this.octokit.rest.repos.getContent({ owner: username, repo, ref, path })
59
+ return content.data as GithubFile | GithubFile[]
61
60
  }
62
61
 
63
62
  public async getUserRepositories(): Promise<GithubRepositoryData[]> {
64
- const user = await this.githubApi.getUser()
65
- const { data } = await user.listRepos()
66
- return data
63
+ let page = 1
64
+ const allRepos = []
65
+ let currentPageRepos = await this.octokit.rest.repos.listForAuthenticatedUser({
66
+ page,
67
+ per_page: 50,
68
+ })
69
+
70
+ while (currentPageRepos.data.length) {
71
+ page++
72
+ allRepos.push(...currentPageRepos.data)
73
+ currentPageRepos = await this.octokit.rest.repos.listForAuthenticatedUser({
74
+ page,
75
+ per_page: 50,
76
+ })
77
+ }
78
+
79
+ return allRepos as GithubRepositoryData[]
67
80
  }
68
81
 
69
82
  public async createBranch(meta: CreateBranchMeta) {
70
83
  const { repo, owner, sourceBranch, newBranch } = meta
71
- const repository = await this.githubApi.getRepo(owner, repo)
72
- if (!repository) {
73
- throw new Error('Repository does not exist')
74
- }
84
+ const ref = await this.octokit.rest.git.getRef({ owner, repo, ref: `heads/${sourceBranch}` })
85
+
86
+ const { data } = await this.octokit.rest.git.createRef({
87
+ owner,
88
+ repo,
89
+ ref: `refs/heads/${newBranch}`,
90
+ sha: ref.data.object.sha,
91
+ })
75
92
 
76
- return repository.createBranch(sourceBranch, newBranch)
93
+ return data
77
94
  }
78
95
 
79
96
  public async createRepository(repository: NewRepository): Promise<GithubRepositoryData> {
80
97
  const { meta } = repository
81
- const user = await this.githubApi.getUser()
82
98
 
83
99
  // Auto initialize repository by creating an initial commit with empty README
84
100
  if (typeof meta.auto_init === 'undefined' || meta.auto_init === null) {
85
101
  meta.auto_init = true
86
102
  }
87
103
 
88
- const { data } = await user.createRepo(meta)
89
- return data
104
+ const result = await this.octokit.rest.repos.createForAuthenticatedUser(meta)
105
+ return result.data as GithubRepositoryData
90
106
  }
91
107
 
92
108
  public async getRepositoryCommits(meta: RepositoryCommitsListMeta) {
93
109
  const { owner, repo } = meta
94
- const repository = await this.githubApi.getRepo(owner, repo)
110
+ const repository = await this.octokit.rest.repos.get({ owner, repo })
95
111
  if (!repository) {
96
112
  throw new Error('Repository does not exist')
97
113
  }
98
114
 
99
- const params = {
115
+ if (meta.page || meta.perPage) {
116
+ const params = {
117
+ ...meta,
118
+ per_page: meta.perPage ?? undefined,
119
+ }
120
+
121
+ const commits = await this.octokit.rest.repos.listCommits(params)
122
+ return commits.data
123
+ }
124
+
125
+ const allCommits = []
126
+ let page = 1
127
+ let currentPageCommits = await this.octokit.rest.repos.listCommits({
100
128
  ...meta,
101
- per_page: meta.perPage ?? undefined,
129
+ page,
130
+ per_page: 50,
131
+ })
132
+
133
+ while (currentPageCommits.data.length) {
134
+ page++
135
+ allCommits.push(...currentPageCommits.data)
136
+ currentPageCommits = await this.octokit.rest.repos.listCommits({
137
+ ...meta,
138
+ page,
139
+ per_page: 50,
140
+ })
141
+ }
142
+
143
+ return allCommits
144
+ }
145
+
146
+ public async mergeRepositoryBranches(meta: RepositoryMergeMeta) {
147
+ const { owner, repo } = meta
148
+ const repository = await this.octokit.rest.repos.get({ owner, repo })
149
+
150
+ if (!repository) {
151
+ throw new Error('Repository does not exist')
102
152
  }
103
153
 
104
- return repository.listCommits(params)
154
+ const { base, head } = meta
155
+ const mergeResult = await this.octokit.rest.repos.merge({ owner, repo, base, head })
156
+ return mergeResult.data
157
+ }
158
+
159
+ public async deleteBranch(meta: RemoveBranchMeta) {
160
+ const { owner, repo } = meta
161
+ const repository = await this.octokit.rest.repos.get({ owner, repo })
162
+
163
+ if (!repository) {
164
+ throw new Error('Repository does not exist')
165
+ }
166
+
167
+ const removeResult = await this.octokit.rest.git.deleteRef({
168
+ owner,
169
+ repo,
170
+ ref: `heads/${meta.branch}`,
171
+ })
172
+ return removeResult.status
105
173
  }
106
174
 
107
175
  public async getCommitData(meta: RepositoryCommitMeta) {
108
176
  const { owner, repo, ref } = meta
109
- const repository = await this.githubApi.getRepo(owner, repo)
177
+ const repository = await this.octokit.rest.repos.get({ owner, repo })
110
178
  if (!repository) {
111
179
  throw new Error('Repository does not exist')
112
180
  }
113
181
 
114
- const commitDetails = await repository.getSingleCommit(ref)
182
+ const commitDetails = await this.octokit.rest.repos.getCommit({ ref, repo, owner })
183
+ const fileContentPromises = commitDetails.data.files?.map(async (file) => {
184
+ const { data } = await this.octokit.rest.repos.getContent({
185
+ repo,
186
+ owner,
187
+ ref,
188
+ path: file.filename,
189
+ })
115
190
 
116
- const fileContentPromises = commitDetails.data.files.map(async (file: { raw_url: string }) => {
117
- const response = await fetch(file.raw_url)
191
+ const response = await fetch((data as { download_url: string }).download_url)
118
192
  return response.text()
119
193
  })
120
- const fileContents = await Promise.all(fileContentPromises)
121
194
 
122
- commitDetails.data.files.forEach((file: { content?: string }, index: number) => {
123
- file.content = fileContents[index] as string
195
+ const fileContents = await Promise.all(fileContentPromises)
196
+ commitDetails.data.files.forEach((file, index: number) => {
197
+ Object.assign(file, { content: fileContents[index] })
124
198
  })
125
199
 
126
- return commitDetails
200
+ return commitDetails.data
127
201
  }
128
202
 
129
203
  public async getRepositoryBranches(owner: string, repo: string) {
130
- const repository = await this.githubApi.getRepo(owner, repo)
131
- if (!repository) {
132
- throw new Error('Repository does not exist')
204
+ let page = 1
205
+
206
+ const allBranches = []
207
+ let currentPageBranches = await this.octokit.rest.repos.listBranches({
208
+ owner,
209
+ repo,
210
+ page,
211
+ per_page: 50,
212
+ })
213
+
214
+ while (currentPageBranches.data.length) {
215
+ page++
216
+ allBranches.push(...currentPageBranches.data)
217
+ currentPageBranches = await this.octokit.rest.repos.listBranches({
218
+ owner,
219
+ repo,
220
+ page,
221
+ per_page: 50,
222
+ })
133
223
  }
134
- return repository.listBranches()
224
+
225
+ return allBranches
135
226
  }
136
227
 
137
228
  public async commitFilesToRepo(commitMeta: GithubCommitMeta): Promise<string> {
@@ -145,94 +236,117 @@ export default class GithubInstance {
145
236
  const { repo, ref = DEFAULT_REF } = repositoryIdentity
146
237
 
147
238
  // Step -1: Make a separate request for the username if it is not provided
148
- let username = repositoryIdentity.username
149
- if (!username) {
150
- const user = await this.githubApi.getUser()
151
- const profile = await user.getProfile()
152
- username = profile.data.login
239
+ let owner = repositoryIdentity.owner
240
+ if (!owner) {
241
+ const user = await this.octokit.rest.users.getAuthenticated()
242
+ owner = user.data.login
153
243
  }
154
244
 
155
245
  // Step 0: Create repository if it does not exist
156
- await this.ensureRepoExists(username, repo, isPrivate)
157
- const repository: GithubRepository = await this.githubApi.getRepo(username, repo)
246
+ const repository = await this.ensureRepoExists(owner, repo, isPrivate)
158
247
 
159
248
  // Step 1: Create branch if it does not exist
160
- await this.ensureBranchExists(repository, ref, branchName)
249
+ await this.ensureBranchExists(owner, repo, ref, branchName)
161
250
 
162
251
  // Step 2: Get branch commit SHA
163
- const commitSHA = await this.getBranchHeadCommitSHA(repository, branchName)
252
+ const commitSHA = await this.getBranchHeadCommitSHA(owner, repo, branchName)
164
253
 
165
254
  // Step 3: Get current tree SHA
166
- const treeSHA = await this.getCommitTreeSHA(repository, commitSHA)
255
+ const treeSHA = await this.getCommitTreeSHA(owner, repo, commitSHA)
167
256
 
168
257
  // Step 4: Prepare files for github
169
- const filesForGithub = await this.createFiles(repository, files)
258
+ const filesForGithub = await this.createFiles(owner, repo, files)
170
259
 
171
260
  // Step 5: Create new github tree
172
- const newTreeSHA = await this.createTree(repository, filesForGithub, treeSHA)
261
+ const newTreeSHA = await this.createTree(owner, repo, filesForGithub, treeSHA)
173
262
 
174
263
  // Step 6: Create commit
175
- const newCommit = await repository.commit(commitSHA, newTreeSHA, commitMessage)
264
+ const newCommit = await this.octokit.rest.git.createCommit({
265
+ owner,
266
+ repo,
267
+ message: commitMessage,
268
+ parents: [commitSHA],
269
+ tree: newTreeSHA,
270
+ })
176
271
  const newCommitSHA = newCommit.data.sha
177
272
 
178
273
  // Step 7: Update head
179
- await repository.updateHead(`heads/${branchName}`, newCommitSHA)
274
+ await this.octokit.rest.git.updateRef({
275
+ owner,
276
+ repo,
277
+ ref: `heads/${branchName}`,
278
+ sha: newCommitSHA,
279
+ })
180
280
 
181
- return `${GITHUB_REPOSITORY_BASE_URL}/${repository.__fullname}`
281
+ return `${GITHUB_REPOSITORY_BASE_URL}/${repository.full_name}`
182
282
  }
183
283
 
184
284
  private async ensureRepoExists(
185
285
  username: string,
186
286
  repo: string,
187
287
  isPrivate: boolean
188
- ): Promise<void> {
288
+ ): Promise<GithubRepositoryData> {
189
289
  const repositories = await this.getUserRepositories()
190
- const repoExists = repositories.some((repoMeta: GithubRepositoryData) => repoMeta.name === repo)
191
-
192
- if (!repoExists) {
193
- await this.createRepository({ username, meta: { name: repo, private: isPrivate } })
290
+ const existingRepo = repositories.find(
291
+ (repoMeta: GithubRepositoryData) => repoMeta.name === repo
292
+ )
293
+ if (existingRepo) {
294
+ return existingRepo
194
295
  }
296
+
297
+ return this.createRepository({ username, meta: { name: repo, private: isPrivate } })
195
298
  }
196
299
 
197
- private async ensureBranchExists(
198
- repo: GithubRepository,
199
- ref: string,
200
- branch: string
201
- ): Promise<void> {
202
- const { data } = await repo.listBranches()
203
- const branchExists = data.some((branchMeta) => branchMeta.name === branch)
300
+ private async ensureBranchExists(owner: string, repo: string, ref: string, branch: string) {
301
+ const existingBranches = await this.getRepositoryBranches(owner, repo)
302
+ const branchExists = existingBranches.some((branchMeta) => branchMeta.name === branch)
204
303
 
205
304
  if (!branchExists) {
206
- await repo.createBranch(ref, branch)
305
+ this.octokit.rest.git.createRef({
306
+ owner,
307
+ repo,
308
+ ref: `refs/heads/${branch}`,
309
+ sha: ref,
310
+ })
207
311
  }
208
312
  }
209
313
 
210
- private async getBranchHeadCommitSHA(repo: GithubRepository, branch: string): Promise<string> {
211
- const { data } = await repo.getRef(`heads/${branch}`)
314
+ private async getBranchHeadCommitSHA(
315
+ owner: string,
316
+ repo: string,
317
+ branch: string
318
+ ): Promise<string> {
319
+ const { data } = await this.octokit.rest.git.getRef({ owner, repo, ref: `heads/${branch}` })
212
320
  return data.object.sha
213
321
  }
214
322
 
215
- private async getCommitTreeSHA(repo: GithubRepository, commitSHA: string): Promise<string> {
216
- const { data } = await repo.getCommit(commitSHA)
323
+ private async getCommitTreeSHA(owner: string, repo: string, commitSHA: string): Promise<string> {
324
+ const { data } = await this.octokit.rest.git.getCommit({
325
+ owner,
326
+ repo,
327
+ commit_sha: commitSHA,
328
+ })
329
+
217
330
  return data.tree.sha
218
331
  }
219
332
 
220
333
  private async createFiles(
221
- repo: GithubRepository,
334
+ owner: string,
335
+ repo: string,
222
336
  files: GithubFile[]
223
337
  ): Promise<GithubFileMeta[]> {
224
338
  const promises = files.map((file) => {
225
- return this.createFile(repo, file)
339
+ return this.createFile(owner, repo, file)
226
340
  })
227
341
 
228
342
  return Promise.all(promises)
229
343
  }
230
344
 
231
- private async createFile(repo: GithubRepository, file: GithubFile): Promise<GithubFileMeta> {
345
+ private async createFile(owner: string, repo: string, file: GithubFile): Promise<GithubFileMeta> {
232
346
  const { data } =
233
347
  file.encoding === 'base64'
234
- ? await createBase64GithubFileBlob(file, repo.__fullname, this.auth)
235
- : await repo.createBlob(file.content)
348
+ ? await createBase64GithubFileBlob(file, repo, this.auth)
349
+ : await this.octokit.rest.git.createBlob({ owner, repo, content: file.content })
236
350
 
237
351
  return {
238
352
  sha: file.status === 'deleted' ? null : data.sha,
@@ -243,11 +357,18 @@ export default class GithubInstance {
243
357
  }
244
358
 
245
359
  private async createTree(
246
- repo: GithubRepository,
360
+ owner: string,
361
+ repo: string,
247
362
  files: GithubFileMeta[],
248
363
  treeSHA?: string
249
364
  ): Promise<string> {
250
- const tree = await repo.createTree(files, treeSHA)
365
+ const tree = await this.octokit.rest.git.createTree({
366
+ owner,
367
+ repo,
368
+ base_tree: treeSHA,
369
+ // @ts-ignore
370
+ tree: files,
371
+ })
251
372
  return tree.data.sha
252
373
  }
253
374
  }
package/src/index.ts CHANGED
@@ -12,6 +12,8 @@ import {
12
12
  RepositoryCommitsListMeta,
13
13
  RepositoryCommitMeta,
14
14
  CreateBranchMeta,
15
+ RepositoryMergeMeta,
16
+ RemoveBranchMeta,
15
17
  } from './types'
16
18
 
17
19
  export const createGithubGateway: GithubGatewayFactory = (auth: ServiceAuth = {}) => {
@@ -20,7 +22,7 @@ export const createGithubGateway: GithubGatewayFactory = (auth: ServiceAuth = {}
20
22
  const getRepository = async (repoIdentity: RepositoryIdentity, authData?: ServiceAuth) => {
21
23
  authorizeGithubInstance(authData)
22
24
 
23
- const { data } = await githubInstance.getRepoContent(repoIdentity)
25
+ const data = await githubInstance.getRepoContent(repoIdentity)
24
26
 
25
27
  const { repo } = repoIdentity
26
28
  const emptyFolder = createEmptyFolder(repo)
@@ -54,11 +56,21 @@ export const createGithubGateway: GithubGatewayFactory = (auth: ServiceAuth = {}
54
56
  return githubInstance.createBranch(meta)
55
57
  }
56
58
 
59
+ const mergeRepositoryBranches = async (meta: RepositoryMergeMeta, authData: ServiceAuth) => {
60
+ authorizeGithubInstance(authData)
61
+ return githubInstance.mergeRepositoryBranches(meta)
62
+ }
63
+
57
64
  const getRepositoryBranches = async (owner: string, repo: string, authData: ServiceAuth) => {
58
65
  authorizeGithubInstance(authData)
59
66
  return githubInstance.getRepositoryBranches(owner, repo)
60
67
  }
61
68
 
69
+ const deleteRepositoryBranch = async (meta: RemoveBranchMeta, authData: ServiceAuth) => {
70
+ authorizeGithubInstance(authData)
71
+ return githubInstance.deleteBranch(meta)
72
+ }
73
+
62
74
  const getCommitData = async (meta: RepositoryCommitMeta, authData: ServiceAuth) => {
63
75
  authorizeGithubInstance(authData)
64
76
  return githubInstance.getCommitData(meta)
@@ -78,6 +90,8 @@ export const createGithubGateway: GithubGatewayFactory = (auth: ServiceAuth = {}
78
90
  getRepositoryCommits,
79
91
  createBranch,
80
92
  getRepositoryBranches,
93
+ mergeRepositoryBranches,
94
+ deleteRepositoryBranch,
81
95
  commitFilesToRepo,
82
96
  getCommitData,
83
97
  authorizeGithubInstance,
package/src/types.ts CHANGED
@@ -11,13 +11,15 @@ export interface GithubGateway {
11
11
  createRepository: (repository: NewRepository, auth?: ServiceAuth) => Promise<GithubRepositoryData>
12
12
  getRepositoryCommits: (meta: RepositoryCommitsListMeta, authData: ServiceAuth) => Promise<any>
13
13
  createBranch: (meta: CreateBranchMeta, authData: ServiceAuth) => Promise<any>
14
+ mergeRepositoryBranches: (meta: RepositoryMergeMeta, authData: ServiceAuth) => Promise<any>
15
+ deleteRepositoryBranch: (meta: RemoveBranchMeta, authData: ServiceAuth) => Promise<any>
14
16
  getRepositoryBranches: (owner: string, repo: string, authData: ServiceAuth) => Promise<any>
15
17
  getCommitData: (meta: RepositoryCommitMeta, authData: ServiceAuth) => Promise<any>
16
18
  authorizeGithubInstance: (authData?: ServiceAuth) => void
17
19
  }
18
20
 
19
21
  export interface RepositoryIdentity {
20
- username: string
22
+ owner: string
21
23
  repo: string
22
24
  ref?: string
23
25
  path?: string
@@ -53,9 +55,17 @@ export interface RepositoryCommitsListMeta {
53
55
  path?: string
54
56
  }
55
57
 
56
- export interface RepositoryContentResponse {
57
- data: GithubFile | GithubFile[]
58
- status: number
58
+ export interface RepositoryMergeMeta {
59
+ repo: string
60
+ owner: string
61
+ base: string
62
+ head: string
63
+ }
64
+
65
+ export interface RemoveBranchMeta {
66
+ repo: string
67
+ owner: string
68
+ branch: string
59
69
  }
60
70
 
61
71
  export interface GithubFile {
@@ -76,7 +86,6 @@ export interface GithubFileMeta {
76
86
  path: string
77
87
  mode: string
78
88
  type: string
79
- encoding?: FileEncoding
80
89
  }
81
90
 
82
91
  export interface NewRepository {
@@ -106,41 +115,8 @@ export interface FilesFetcherMeta {
106
115
  githubInstance: GithubInstance
107
116
  }
108
117
 
109
- export interface GithubRepository {
110
- __fullname: string
111
- getContents: (ref: string, path: string) => Promise<RepositoryContentResponse>
112
- listBranches: () => Promise<GithubBranchesResponse>
113
- createBranch: (ref: string, branchName: string) => Promise<GithubCreateResponse>
114
- getRef: (url: string) => Promise<GithubGetRefResponse>
115
- getCommit: (sha: string) => Promise<GithubGetCommitResponse>
116
- createTree: (files: GithubFileMeta[], sha?: string) => Promise<GithubCreateResponse>
117
- commit: (parentSHA: string, treeSHA: string, message: string) => Promise<GithubCreateResponse>
118
- updateHead: (ref: string, commitSHA: string) => Promise<void>
119
- createBlob: (fileContent: string) => Promise<GithubCreateResponse>
120
- }
121
-
122
118
  export interface GithubCreateResponse {
123
119
  data: {
124
120
  sha: string
125
121
  }
126
122
  }
127
-
128
- interface GithubBranchesResponse {
129
- data: Array<Record<string, string>>
130
- }
131
-
132
- interface GithubGetRefResponse {
133
- data: {
134
- object: {
135
- sha: string
136
- }
137
- }
138
- }
139
-
140
- interface GithubGetCommitResponse {
141
- data: {
142
- tree: {
143
- sha: string
144
- }
145
- }
146
- }
package/src/utils.ts CHANGED
@@ -32,7 +32,7 @@ export const fetchFilesContent = async (
32
32
  const { name, path } = directory
33
33
 
34
34
  const directoryFilesParams = { ...userRepositoryIdentity, path }
35
- const { data } = await githubInstance.getRepoContent(directoryFilesParams)
35
+ const data = await githubInstance.getRepoContent(directoryFilesParams)
36
36
 
37
37
  const newFolder = createEmptyFolder(name)
38
38
  const folderWithFiles = await fetchFilesContent(data as GithubFile[], newFolder, meta)
@@ -79,7 +79,7 @@ const getFileContent = async (
79
79
  const { ref = DEFAULT_REF } = userRepositoryIdentity
80
80
 
81
81
  const githubFileMetadata = { ...userRepositoryIdentity, ref, path }
82
- const { data } = await githubInstance.getRepoContent(githubFileMetadata)
82
+ const data = await githubInstance.getRepoContent(githubFileMetadata)
83
83
 
84
84
  let { content, encoding } = data as GithubFile
85
85