@teleporthq/teleport-github-gateway 0.19.17 → 0.19.19

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,59 +37,77 @@ 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
  }
@@ -101,37 +117,83 @@ export default class GithubInstance {
101
117
  per_page: meta.perPage ?? undefined,
102
118
  }
103
119
 
104
- return repository.listCommits(params)
120
+ const commits = await this.octokit.rest.repos.listCommits(params)
121
+ return commits.data
122
+ }
123
+
124
+ public async mergeRepositoryBranches(meta: RepositoryMergeMeta) {
125
+ const { owner, repo } = meta
126
+ const repository = await this.octokit.rest.repos.get({ owner, repo })
127
+
128
+ if (!repository) {
129
+ throw new Error('Repository does not exist')
130
+ }
131
+
132
+ const { base, head } = meta
133
+ const mergeResult = await this.octokit.rest.repos.merge({ owner, repo, base, head })
134
+ return mergeResult.data
135
+ }
136
+
137
+ public async deleteBranch(meta: RemoveBranchMeta) {
138
+ const { owner, repo } = meta
139
+ const repository = await this.octokit.rest.repos.get({ owner, repo })
140
+
141
+ if (!repository) {
142
+ throw new Error('Repository does not exist')
143
+ }
144
+
145
+ const removeResult = await this.octokit.rest.git.deleteRef({
146
+ owner,
147
+ repo,
148
+ ref: `heads/${meta.branch}`,
149
+ })
150
+ return removeResult.status
105
151
  }
106
152
 
107
153
  public async getCommitData(meta: RepositoryCommitMeta) {
108
154
  const { owner, repo, ref } = meta
109
- const repository = await this.githubApi.getRepo(owner, repo)
155
+ const repository = await this.octokit.rest.repos.get({ owner, repo })
110
156
  if (!repository) {
111
157
  throw new Error('Repository does not exist')
112
158
  }
113
159
 
114
- const commitDetails = await repository.getSingleCommit(ref)
115
-
116
- const fileContentPromises = commitDetails.data.files.map(async (file: { raw_url: string }) => {
160
+ const commitDetails = await this.octokit.rest.repos.getCommit({ ref, repo, owner })
161
+ const fileContentPromises = commitDetails.data.files?.map(async (file: { raw_url: string }) => {
117
162
  const response = await fetch(file.raw_url)
118
163
  return response.text()
119
164
  })
120
- const fileContents = await Promise.all(fileContentPromises)
121
165
 
122
- commitDetails.data.files.forEach((file: { content?: string }, index: number) => {
123
- file.content = fileContents[index] as string
166
+ const fileContents = await Promise.all(fileContentPromises)
167
+ commitDetails.data.files.forEach((file, index: number) => {
168
+ Object.assign(file, { content: fileContents[index] })
124
169
  })
125
170
 
126
- return commitDetails
171
+ return commitDetails.data
127
172
  }
128
173
 
129
174
  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')
175
+ let page = 1
176
+
177
+ const allBranches = []
178
+ let currentPageBranches = await this.octokit.rest.repos.listBranches({
179
+ owner,
180
+ repo,
181
+ page,
182
+ per_page: 50,
183
+ })
184
+
185
+ while (currentPageBranches.data.length) {
186
+ page++
187
+ allBranches.push(...currentPageBranches.data)
188
+ currentPageBranches = await this.octokit.rest.repos.listBranches({
189
+ owner,
190
+ repo,
191
+ page,
192
+ per_page: 50,
193
+ })
133
194
  }
134
- return repository.listBranches()
195
+
196
+ return allBranches
135
197
  }
136
198
 
137
199
  public async commitFilesToRepo(commitMeta: GithubCommitMeta): Promise<string> {
@@ -145,94 +207,117 @@ export default class GithubInstance {
145
207
  const { repo, ref = DEFAULT_REF } = repositoryIdentity
146
208
 
147
209
  // 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
210
+ let owner = repositoryIdentity.owner
211
+ if (!owner) {
212
+ const user = await this.octokit.rest.users.getAuthenticated()
213
+ owner = user.data.login
153
214
  }
154
215
 
155
216
  // 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)
217
+ const repository = await this.ensureRepoExists(owner, repo, isPrivate)
158
218
 
159
219
  // Step 1: Create branch if it does not exist
160
- await this.ensureBranchExists(repository, ref, branchName)
220
+ await this.ensureBranchExists(owner, repo, ref, branchName)
161
221
 
162
222
  // Step 2: Get branch commit SHA
163
- const commitSHA = await this.getBranchHeadCommitSHA(repository, branchName)
223
+ const commitSHA = await this.getBranchHeadCommitSHA(owner, repo, branchName)
164
224
 
165
225
  // Step 3: Get current tree SHA
166
- const treeSHA = await this.getCommitTreeSHA(repository, commitSHA)
226
+ const treeSHA = await this.getCommitTreeSHA(owner, repo, commitSHA)
167
227
 
168
228
  // Step 4: Prepare files for github
169
- const filesForGithub = await this.createFiles(repository, files)
229
+ const filesForGithub = await this.createFiles(owner, repo, files)
170
230
 
171
231
  // Step 5: Create new github tree
172
- const newTreeSHA = await this.createTree(repository, filesForGithub, treeSHA)
232
+ const newTreeSHA = await this.createTree(owner, repo, filesForGithub, treeSHA)
173
233
 
174
234
  // Step 6: Create commit
175
- const newCommit = await repository.commit(commitSHA, newTreeSHA, commitMessage)
235
+ const newCommit = await this.octokit.rest.git.createCommit({
236
+ owner,
237
+ repo,
238
+ message: commitMessage,
239
+ parents: [commitSHA],
240
+ tree: newTreeSHA,
241
+ })
176
242
  const newCommitSHA = newCommit.data.sha
177
243
 
178
244
  // Step 7: Update head
179
- await repository.updateHead(`heads/${branchName}`, newCommitSHA)
245
+ await this.octokit.rest.git.updateRef({
246
+ owner,
247
+ repo,
248
+ ref: `heads/${branchName}`,
249
+ sha: newCommitSHA,
250
+ })
180
251
 
181
- return `${GITHUB_REPOSITORY_BASE_URL}/${repository.__fullname}`
252
+ return `${GITHUB_REPOSITORY_BASE_URL}/${repository.full_name}`
182
253
  }
183
254
 
184
255
  private async ensureRepoExists(
185
256
  username: string,
186
257
  repo: string,
187
258
  isPrivate: boolean
188
- ): Promise<void> {
259
+ ): Promise<GithubRepositoryData> {
189
260
  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 } })
261
+ const existingRepo = repositories.find(
262
+ (repoMeta: GithubRepositoryData) => repoMeta.name === repo
263
+ )
264
+ if (existingRepo) {
265
+ return existingRepo
194
266
  }
267
+
268
+ return this.createRepository({ username, meta: { name: repo, private: isPrivate } })
195
269
  }
196
270
 
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)
271
+ private async ensureBranchExists(owner: string, repo: string, ref: string, branch: string) {
272
+ const existingBranches = await this.getRepositoryBranches(owner, repo)
273
+ const branchExists = existingBranches.some((branchMeta) => branchMeta.name === branch)
204
274
 
205
275
  if (!branchExists) {
206
- await repo.createBranch(ref, branch)
276
+ this.octokit.rest.git.createRef({
277
+ owner,
278
+ repo,
279
+ ref: `refs/heads/${branch}`,
280
+ sha: ref,
281
+ })
207
282
  }
208
283
  }
209
284
 
210
- private async getBranchHeadCommitSHA(repo: GithubRepository, branch: string): Promise<string> {
211
- const { data } = await repo.getRef(`heads/${branch}`)
285
+ private async getBranchHeadCommitSHA(
286
+ owner: string,
287
+ repo: string,
288
+ branch: string
289
+ ): Promise<string> {
290
+ const { data } = await this.octokit.rest.git.getRef({ owner, repo, ref: `heads/${branch}` })
212
291
  return data.object.sha
213
292
  }
214
293
 
215
- private async getCommitTreeSHA(repo: GithubRepository, commitSHA: string): Promise<string> {
216
- const { data } = await repo.getCommit(commitSHA)
294
+ private async getCommitTreeSHA(owner: string, repo: string, commitSHA: string): Promise<string> {
295
+ const { data } = await this.octokit.rest.git.getCommit({
296
+ owner,
297
+ repo,
298
+ commit_sha: commitSHA,
299
+ })
300
+
217
301
  return data.tree.sha
218
302
  }
219
303
 
220
304
  private async createFiles(
221
- repo: GithubRepository,
305
+ owner: string,
306
+ repo: string,
222
307
  files: GithubFile[]
223
308
  ): Promise<GithubFileMeta[]> {
224
309
  const promises = files.map((file) => {
225
- return this.createFile(repo, file)
310
+ return this.createFile(owner, repo, file)
226
311
  })
227
312
 
228
313
  return Promise.all(promises)
229
314
  }
230
315
 
231
- private async createFile(repo: GithubRepository, file: GithubFile): Promise<GithubFileMeta> {
316
+ private async createFile(owner: string, repo: string, file: GithubFile): Promise<GithubFileMeta> {
232
317
  const { data } =
233
318
  file.encoding === 'base64'
234
- ? await createBase64GithubFileBlob(file, repo.__fullname, this.auth)
235
- : await repo.createBlob(file.content)
319
+ ? await createBase64GithubFileBlob(file, repo, this.auth)
320
+ : await this.octokit.rest.git.createBlob({ owner, repo, content: file.content })
236
321
 
237
322
  return {
238
323
  sha: file.status === 'deleted' ? null : data.sha,
@@ -243,11 +328,18 @@ export default class GithubInstance {
243
328
  }
244
329
 
245
330
  private async createTree(
246
- repo: GithubRepository,
331
+ owner: string,
332
+ repo: string,
247
333
  files: GithubFileMeta[],
248
334
  treeSHA?: string
249
335
  ): Promise<string> {
250
- const tree = await repo.createTree(files, treeSHA)
336
+ const tree = await this.octokit.rest.git.createTree({
337
+ owner,
338
+ repo,
339
+ base_tree: treeSHA,
340
+ // @ts-ignore
341
+ tree: files,
342
+ })
251
343
  return tree.data.sha
252
344
  }
253
345
  }
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