From 3be1d15009fd138543d81dcb84eb73e6561652f3 Mon Sep 17 00:00:00 2001
From: Vincent LI
Date: Sat, 7 Oct 2023 16:33:20 +0200
Subject: [PATCH] add gitlab provider
---
src/api/repository.controller.ts | 2 +-
src/api/repository.provider.ts | 6 ++-
src/api/repository.strategy.ts | 5 ++-
src/provider/gitlab.provider.ts | 73 ++++++++++++++++++++++++++++++++
4 files changed, 82 insertions(+), 4 deletions(-)
create mode 100644 src/provider/gitlab.provider.ts
diff --git a/src/api/repository.controller.ts b/src/api/repository.controller.ts
index 6d3793c..465eb43 100644
--- a/src/api/repository.controller.ts
+++ b/src/api/repository.controller.ts
@@ -12,7 +12,7 @@ interface LocalProviderConfig {
}
interface RemoteProviderConfig {
- type: 'github' /* | 'gitlab' */
+ type: 'github' | 'gitlab'
repositories: string[]
token?: string
}
diff --git a/src/api/repository.provider.ts b/src/api/repository.provider.ts
index 8b46c3a..ed39f63 100644
--- a/src/api/repository.provider.ts
+++ b/src/api/repository.provider.ts
@@ -1,9 +1,10 @@
import { GithubProvider } from '../provider/github.provider'
+import { GitlabProvider } from '../provider/gitlab.provider'
import { LocalProvider } from '../provider/local.provider'
import { FileSystemManager } from '../utils/fileSystem.utils'
import { ProviderConfig } from './repository.controller'
-export type Provider = LocalProvider | GithubProvider
+export type Provider = LocalProvider | GithubProvider | GitlabProvider
export class RepositoryProvider {
private provider!: Provider
@@ -19,6 +20,9 @@ export class RepositoryProvider {
case 'github':
this.provider = new GithubProvider(config.repositories, config.token)
break
+ case 'gitlab':
+ this.provider = new GitlabProvider(config.repositories, config.token)
+ break
default:
break
}
diff --git a/src/api/repository.strategy.ts b/src/api/repository.strategy.ts
index 861886e..d93975d 100644
--- a/src/api/repository.strategy.ts
+++ b/src/api/repository.strategy.ts
@@ -1,7 +1,7 @@
import { ErrorManager } from '../utils/error.utils'
import { ProviderConfig } from './repository.controller'
-const knownRepositories = ['github.com'] as const
+const knownRepositories = ['github.com', 'gitlab.com'] as const
export interface ProviderStrategy {
isMatch(docLocation: string): boolean
@@ -31,9 +31,10 @@ export class RepositoryProviderStrategy implements ProviderStrategy {
return { type: this.extractRepositoryName(domain), repositories: [docLocation] }
}
- private extractRepositoryName(domain: string): 'github' | never {
+ private extractRepositoryName(domain: string): 'github' | 'gitlab' | never {
const type = domain.split('.')[0]
if (type === 'github') return type
+ if (type === 'gitlab') return type
ErrorManager.outputError(`Unrecognized repository type: ${type}`)
throw new Error(`Unrecognized repository type: ${type}`)
diff --git a/src/provider/gitlab.provider.ts b/src/provider/gitlab.provider.ts
new file mode 100644
index 0000000..98352bb
--- /dev/null
+++ b/src/provider/gitlab.provider.ts
@@ -0,0 +1,73 @@
+import { Documentation } from '../association.manager'
+import { FileSystemManager } from '../utils/fileSystem.utils'
+import { ReplacerTextProvider } from '../utils/replacerText.utils'
+
+interface GitlabResponse {
+ type: string
+ name: string
+ path: string
+}
+
+export class GitlabProvider {
+ private baseUrl = 'https://gitlab.com/api/v4'
+ private fileSystem
+ private repository
+ private transformImageURL
+
+ constructor(repository: string[], token?: string) {
+ this.repository = this.getProjectId(repository)
+ this.fileSystem = new FileSystemManager()
+ this.transformImageURL = new ReplacerTextProvider(repository[0], token)
+ }
+
+ public async getDocumentations(): Promise {
+ const documentations: Documentation[] = []
+ const data = await this.getRepoContent(
+ `/projects/${this.repository.id.replace('/', '%2F')}/repository/tree?ref=main&recursive=true`
+ )
+
+ await this.fetchDocumentation(data, documentations)
+ return documentations
+ }
+
+ private fetchDocumentation = async (
+ repositoryContents: GitlabResponse[],
+ documentations: Documentation[]
+ ): Promise => {
+ for (const repositoryContent of repositoryContents) {
+ if (
+ repositoryContent.type === 'blob' &&
+ this.fileSystem.isFileOfInterest(repositoryContent.name)
+ ) {
+ const documentation = await this.getFile(repositoryContent)
+ documentation.content = this.transformImageURL.replacer(documentation.content)
+ documentations.push(documentation)
+ }
+ }
+ }
+
+ public async getRepoContent(route: string) {
+ const response = await fetch(this.baseUrl + route)
+ return await response.json()
+ }
+
+ public async getFile(file: GitlabResponse): Promise {
+ const projectIdEncoded = encodeURIComponent(this.repository.id)
+ const filePathEncoded = encodeURIComponent(file.path)
+ const url = `https://gitlab.com/api/v4/projects/${projectIdEncoded}/repository/files/${filePathEncoded}/raw`
+ const response = await fetch(url)
+ const content = await response.text()
+
+ return {
+ type: this.fileSystem.getExtension(file.name)!,
+ name: file.name,
+ content: content,
+ path: `https://gitlab.com/${this.repository.id}/-/blob/main/${file.path}`,
+ }
+ }
+
+ public getProjectId(repository: string[]) {
+ const urlParts = repository[0].split('/')
+ return { id: `${urlParts[3]}/${urlParts[4]}`, token: repository[1] }
+ }
+}