From bd090c29c70e2e62a951367273dc56b383912307 Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Mon, 28 Nov 2022 21:03:40 +0100 Subject: [PATCH 01/17] add gitlab to docker-compose --- docker-compose.yaml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index c8257ba9..fce5e898 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -27,4 +27,21 @@ services: - /etc/localtime:/etc/localtime:ro ports: - "3000:3000" - - "222:22" \ No newline at end of file + - "222:22" + gitlab: + image: 'gitlab/gitlab-ee:latest' + restart: always + hostname: 'gitlab.lacolhost.com' + environment: + GITLAB_OMNIBUS_CONFIG: | + external_url 'http://gitlab.lacolhost.com' + # Add any other gitlab.rb configuration here, each on its own line + ports: + - '3080:80' + - '3443:443' + - '3022:22' + volumes: + - './.dockerdata/gitlab/config:/etc/gitlab' + - './.dockerdata/gitlab/logs:/var/log/gitlab' + - './.dockerdata/gitlab/data:/var/opt/gitlab' + shm_size: '256m' \ No newline at end of file From 434a4666e66d6be175431b47eef229eec6dd7eae Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Tue, 29 Nov 2022 11:23:36 +0100 Subject: [PATCH 02/17] add gitlab selfhosted support --- client/src/components/pipelines/new.vue | 10 +- package.json | 1 + src/git/gitlab.ts | 297 +++++++++++++++++++++++- src/kubero.ts | 7 + yarn.lock | 9 +- 5 files changed, 317 insertions(+), 7 deletions(-) diff --git a/client/src/components/pipelines/new.vue b/client/src/components/pipelines/new.vue index 54a2e2a2..f8b03796 100644 --- a/client/src/components/pipelines/new.vue +++ b/client/src/components/pipelines/new.vue @@ -30,7 +30,7 @@ cols="12" md="8" > - + Github mdi-github Gitea Gitlab mdi-gitlab @@ -236,12 +236,12 @@ export default { ], nameRules: [ v => !!v || 'Name is required', - v => v.length <= 60 || 'Name must be less than 10 characters', + v => v.length <= 60 || 'Name must be less than 60 characters', v => /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(v) || 'Allowed characters : [a-zA-Z0-9_-]', ], repositoryRules: [ v => !!v || 'Repository is required', - v => v.length <= 60 || 'Repository must be less than 10 characters', + v => v.length <= 120 || 'Repository must be less than 120 characters', // ((git|ssh|http(s)?)|(git@[\w\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)(/)? v => /((git|ssh|http(s)?)|(git@[\w.]+))(:(\/\/)?)([\w.@:/\-~]+)(\.git)(\/)?/.test(v) || 'Format "owner/repository"', ], @@ -293,14 +293,14 @@ export default { this.repositoriesList.docker = false; break; case 'gitea': - this.connectGitea(); + this.connectRepository('gitea') this.repositoriesList.github = false; this.repositoriesList.gitlab = false; this.repositoriesList.bitbucket = false; this.repositoriesList.docker = false; break; case 'gitlab': - this.connectGitlab(); + this.connectRepository('gitlab') return; /* this.repositoriesList.gitea = false; diff --git a/package.json b/package.json index d3493df0..c99e3161 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ }, "dependencies": { "@kubernetes/client-node": "^0.16.3", + "@nerdvision/gitlab-js": "^1.0.0-alpha.12", "@octokit/core": "^3.6.0", "@octokit/webhooks": "^9.26.0", "axios": "^0.27.2", diff --git a/src/git/gitlab.ts b/src/git/gitlab.ts index a3013bbb..c9c07ca2 100644 --- a/src/git/gitlab.ts +++ b/src/git/gitlab.ts @@ -1,2 +1,297 @@ // https://www.nerd.vision/post/nerdvision-gitlab-js-an-easier-way-to-access-the-gitlab-api-in-javascript -// https://www.npmjs.com/package/@nerdvision/gitlab-js \ No newline at end of file +// https://www.npmjs.com/package/@nerdvision/gitlab-js +import debug from 'debug'; +import * as crypto from "crypto" +import { IWebhook, IRepository, IWebhookR, IDeploykeyR} from './types'; +import { Repo } from './repo'; +import {Client as GitlabClient} from '@nerdvision/gitlab-js'; +import {Options} from 'got'; + + +export class GitlabApi extends Repo { + private gitlab: GitlabClient; + private opt = { + headers: { + 'Content-Type': 'application/json', + }, + } as Options; + + constructor(baseURL: string, token: string) { + super("gitlab"); + + this.gitlab = new GitlabClient({ + token: token, + host: baseURL, + }); + } + + protected async getRepository(gitrepo: string): Promise { + //https://docs.gitlab.com/ee/api/projects.html + let ret: IRepository = { + status: 500, + statusText: 'error', + data: { + owner: 'unknown', + name: 'unknown', + admin: false, + push: false, + } + } + + // TODO : Improve matching here + let owner = gitrepo.match(/^git@.*:(.*)\/.*$/)?.[1] as string; + let repo = gitrepo.match(/^git@.*:.*\/(.*)\.git$/)?.[1] as string; + + let res: any = await this.gitlab.get(`projects/${owner}%2F${repo}`) + .catch((error: any) => { + console.log(error) + return ret; + }) + //console.log(res) + + res.private = false; + if (res.visibility === 'private') { + res.private = true; + } + + // TODO: this is a workaround since the information is not available + res.permissions.admin = true; + res.permissions.push = true; + + ret = { + status: 200, + statusText: 'found', + data: { + id: res.id, + node_id: res.path_with_namespace, + name: res.path, + description: res.description, + owner: res.namespace.path, + private : res.private, + ssh_url: res.ssh_url_to_repo, + language: res.language, + homepage: res.namespace.web_url, + admin: res.permissions.admin, + push: res.permissions.push, + visibility: res.visibility, + default_branch: res.default_branch, + } + } + return ret; + + } + + + protected async addWebhook(owner: string, repo: string, url: string, secret: string): Promise { + // https://docs.gitlab.com/ee/api/projects.html#list-project-hooks + let ret: IWebhookR = { + status: 500, + statusText: 'error', + data: { + id: 0, + active: false, + created_at: '2020-01-01T00:00:00Z', + url: '', + insecure: true, + events: [], + } + } + + const webhooksList: any = await this.gitlab.get(`projects/${owner}%2F${repo}/hooks`) + .catch((error: any) => { + console.log(error) + return ret; + }) + // try to find the webhook + for (let webhook of webhooksList) { + if (webhook.url === url && + webhook.disabled_until === null) { + ret = { + status: 422, + statusText: 'found', + data: { + id: webhook.id, + active: true, + created_at: webhook.created_at, + url: webhook.url, + insecure: false, //TODO use the inverted enable_ssl_verification field + events: ["pull_request", "push"], + } + } + return ret; + } + } + + // create the webhook since it does not exist + try { + let res: any = await this.gitlab.post(`projects/${owner}%2F${repo}/hooks`, JSON.stringify({ + url: url, + token: secret, + merge_requests_events: true, + push_events: true, + }), + undefined, + this.opt, + ); + + ret = { + status: 201, + statusText: 'created', + data: { + id: res.id, + active: res.active, + created_at: res.created_at, + url: res.url, + insecure: false, + events: ["pull_request", "push"], + } + } + } catch (e) { + console.log("Failed to create Webhook") + console.log(e) + } + return ret; + } + + async addDeployKey(owner: string, repo: string): Promise { + + const keyPair = this.createDeployKeyPair(); + + const title: string = "bot@kubero"; + + let ret: IDeploykeyR = { + status: 500, + statusText: 'error', + data: { + id: 0, + title: title, + verified: false, + created_at: '2020-01-01T00:00:00Z', + url: '', + read_only: true, + pub: keyPair.pubKeyBase64, + priv: keyPair.privKeyBase64 + } + } + // https://docs.gitlab.com/ee/api/deploy_keys.html#list-deploy-keys-for-project + const keysList:any = await this.gitlab.get(`projects/${owner}%2F${repo}/deploy_keys`) + .catch((error: any) => { + console.log(error) + return ret; + }) + + // try to find the key + for (let key of keysList) { + if (key.title === title && + key.read_only === true) { + ret = { + status: 422, + statusText: 'found', + data: key, + } + return ret; + } + } + + try { + // https://docs.gitlab.com/ee/api/deploy_keys.html#add-deploy-key + let res:any = await this.gitlab.post(`projects/${owner}%2F${repo}/deploy_keys`, JSON.stringify({ + title: title, + key: keyPair.pubKey, + can_push: false + }), + undefined, + this.opt, + ); + + console.log(res) + + ret = { + status: 201, + statusText: 'created', + data: { + id: res.id, + title: res.title, + verified: res.verified, + created_at: res.created_at, + url: res.url, + read_only: res.read_only, + pub: keyPair.pubKeyBase64, + priv: keyPair.privKeyBase64 + } + } + } catch (e) { + console.log(e) + } + + return ret + } + + public getWebhook(event: string, delivery: string, signature: string, body: any): IWebhook | boolean { + let secret = process.env.KUBERO_WEBHOOK_SECRET as string; + let hash = 'sha256='+crypto.createHmac('sha256', secret).update(JSON.stringify(body)).digest('hex') + + let verified = false; + if (hash === signature) { + debug.debug('Gitlab webhook signature is valid for event: '+delivery); + verified = true; + } else { + debug.log('ERROR: invalid signature for event: '+delivery); + debug.log('Hash: '+hash); + debug.log('Signature: '+signature); + verified = false; + return false; + } + + let branch: string = 'main'; + let ssh_url: string = ''; + let action; + if (body.ref != undefined) { + let ref = body.ref + let refs = ref.split('/') + branch = refs[refs.length - 1] + ssh_url = body.repository.ssh_url + } else if (body.pull_request != undefined) { + action = body.action, + branch = body.pull_request.head.ref + ssh_url = body.pull_request.head.repo.ssh_url + } else { + ssh_url = body.repository.ssh_url + } + + try { + let webhook: IWebhook = { + repoprovider: 'gitlab', + action: action, + event: event, + delivery: delivery, + body: body, + branch: branch, + verified: verified, + repo: { + ssh_url: ssh_url, + } + } + + return webhook; + } catch (error) { + debug.log(error) + return false; + } + } + + public async listRepos(): Promise { + let ret: string[] = []; + const repos:any = await this.gitlab.get('projects', {}) + .catch((error: any) => { + console.log(error) + return ret; + }) + + for (let repo of repos) { + ret.push(repo.ssh_url_to_repo) + } + return ret; + } + +} \ No newline at end of file diff --git a/src/kubero.ts b/src/kubero.ts index 9d06385f..14d98650 100644 --- a/src/kubero.ts +++ b/src/kubero.ts @@ -4,6 +4,7 @@ import { IApp, IPipeline, IPipelineList, IKubectlAppList, IDeployKeyPair, IKubec import { App } from './modules/application'; import { GithubApi } from './git/github'; import { GiteaApi } from './git/gitea'; +import { GitlabApi } from './git/gitlab'; import { IWebhook} from './git/types'; import YAML from 'yaml'; import * as fs from 'fs'; @@ -21,6 +22,7 @@ export class Kubero { private _io: Server; private githubApi: GithubApi; private giteaApi: GiteaApi; + private gitlabApi: GitlabApi; private appStateList: IApp[] = []; private pipelineStateList: IPipeline[] = []; private podLogStreams: string[]= [] @@ -33,6 +35,7 @@ export class Kubero { this.giteaApi = new GiteaApi(process.env.GITEA_BASEURL as string, process.env.GITEA_PERSONAL_ACCESS_TOKEN as string); this.githubApi = new GithubApi(process.env.GITHUB_PERSONAL_ACCESS_TOKEN as string); + this.gitlabApi = new GitlabApi(process.env.GITLAB_BASEURL as string, process.env.GITLAB_PERSONAL_ACCESS_TOKEN as string); debug.debug('Kubero Config: '+JSON.stringify(this.config)); } @@ -292,6 +295,8 @@ export class Kubero { return this.githubApi.listRepos(); case 'gitea': return this.giteaApi.listRepos(); + case 'gitlab': + return this.gitlabApi.listRepos(); default: return {'error': 'unknown repo provider'}; } @@ -305,6 +310,8 @@ export class Kubero { return this.githubApi.connectRepo(repoAddress); case 'gitea': return this.giteaApi.connectRepo(repoAddress); + case 'gitlab': + return this.gitlabApi.connectRepo(repoAddress); default: return {'error': 'unknown repo provider'}; } diff --git a/yarn.lock b/yarn.lock index 75e40755..34c556b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -55,6 +55,13 @@ underscore "^1.9.1" ws "^7.3.1" +"@nerdvision/gitlab-js@^1.0.0-alpha.12": + version "1.0.0-alpha.12" + resolved "https://registry.yarnpkg.com/@nerdvision/gitlab-js/-/gitlab-js-1.0.0-alpha.12.tgz#2e869b9cb8302284bc2940b3878accc8db17a040" + integrity sha512-+Svx3uo/lX+lQ2E3/wn1aOtNcTdcSfycIXwfGv7/rrk6gZ770E/jiyCYUoTSaHKS0nW0lnx7tZeXZfwaEElzBw== + dependencies: + got "^11.8.1" + "@octokit/auth-token@^2.4.4": version "2.5.0" resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" @@ -1348,7 +1355,7 @@ glob@^7.0.0, glob@^7.1.3, glob@^7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -got@^11.8.0: +got@^11.8.0, got@^11.8.1: version "11.8.5" resolved "https://registry.yarnpkg.com/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046" integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ== From c7ad95668145ad22aa5fe3064aa61c8fa1526f39 Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Tue, 29 Nov 2022 13:11:34 +0100 Subject: [PATCH 03/17] limit list of repositories --- src/git/gitlab.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/git/gitlab.ts b/src/git/gitlab.ts index c9c07ca2..0183eb53 100644 --- a/src/git/gitlab.ts +++ b/src/git/gitlab.ts @@ -19,9 +19,12 @@ export class GitlabApi extends Repo { constructor(baseURL: string, token: string) { super("gitlab"); + console.log("Gitlab API: "+baseURL) + console.log("Gitlab token: "+token) + this.gitlab = new GitlabClient({ token: token, - host: baseURL, + host: baseURL || 'https://gitlab.com', }); } @@ -282,7 +285,7 @@ export class GitlabApi extends Repo { public async listRepos(): Promise { let ret: string[] = []; - const repos:any = await this.gitlab.get('projects', {}) + const repos:any = await this.gitlab.get('projects', { membership: true }) .catch((error: any) => { console.log(error) return ret; From e524f9ea98d0917dd7d97a973524078d5a0d3bbf Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Tue, 29 Nov 2022 16:27:38 +0100 Subject: [PATCH 04/17] listen to gitlab events --- src/git/gitlab.ts | 29 ++++++++++++++++++++--------- src/kubero.ts | 4 +++- src/routes/repo.ts | 11 +++++++---- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/git/gitlab.ts b/src/git/gitlab.ts index 0183eb53..8881c14c 100644 --- a/src/git/gitlab.ts +++ b/src/git/gitlab.ts @@ -230,22 +230,33 @@ export class GitlabApi extends Repo { return ret } - public getWebhook(event: string, delivery: string, signature: string, body: any): IWebhook | boolean { + public getWebhook(event: string, delivery: string, token: string, body: any): IWebhook | boolean { let secret = process.env.KUBERO_WEBHOOK_SECRET as string; - let hash = 'sha256='+crypto.createHmac('sha256', secret).update(JSON.stringify(body)).digest('hex') let verified = false; - if (hash === signature) { + if (secret === token) { debug.debug('Gitlab webhook signature is valid for event: '+delivery); verified = true; } else { - debug.log('ERROR: invalid signature for event: '+delivery); - debug.log('Hash: '+hash); - debug.log('Signature: '+signature); + debug.log('ERROR: invalid token/secret for event: '+delivery); + debug.log('Secret: '+secret); + debug.log('Token : '+token); verified = false; return false; } + // use github and gitea naming for the event + let github_event = event; + if (event === 'Push Hook') { + github_event = 'push'; + } else if (event === 'Merge Request Hook') { + github_event = 'pull_request'; + } else { + debug.log('ERROR: unknown event: '+event); + return false; + } + + let branch: string = 'main'; let ssh_url: string = ''; let action; @@ -253,20 +264,20 @@ export class GitlabApi extends Repo { let ref = body.ref let refs = ref.split('/') branch = refs[refs.length - 1] - ssh_url = body.repository.ssh_url + ssh_url = body.project.git_ssh_url } else if (body.pull_request != undefined) { action = body.action, branch = body.pull_request.head.ref ssh_url = body.pull_request.head.repo.ssh_url } else { - ssh_url = body.repository.ssh_url + ssh_url = body.project.git_ssh_url } try { let webhook: IWebhook = { repoprovider: 'gitlab', action: action, - event: event, + event: github_event, delivery: delivery, body: body, branch: branch, diff --git a/src/kubero.ts b/src/kubero.ts index 14d98650..a1ccef99 100644 --- a/src/kubero.ts +++ b/src/kubero.ts @@ -324,10 +324,12 @@ export class Kubero { case 'github': webhook = this.githubApi.getWebhook(event, delivery, signature, body); break; - case 'gitea': webhook = this.giteaApi.getWebhook(event, delivery, signature, body); break; + case 'gitlab': + webhook = this.gitlabApi.getWebhook(event, delivery, signature, body); + break; default: break; diff --git a/src/routes/repo.ts b/src/routes/repo.ts index cb386b18..450b1095 100644 --- a/src/routes/repo.ts +++ b/src/routes/repo.ts @@ -20,7 +20,7 @@ Router.post('/repo/:repoprovider/connect', async function (req: Request, res: Re }); // get github webhook events -Router.post('/repo/webhooks/:repoprovider', async function (req: Request, res: Response) { +Router.all('/repo/webhooks/:repoprovider', async function (req: Request, res: Response) { let ret: string = 'ok'; switch (req.params.repoprovider){ @@ -45,12 +45,15 @@ Router.post('/repo/webhooks/:repoprovider', async function (req: Request, res: R req.app.locals.kubero.handleWebhook('gitea', gitea_event, gitea_delivery, gitea_signature, gitea_body); break; case "gitlab": - //req.app.locals.kubero.handleGitlabWebhook(req.body); - ret = "gitlab not supported yet"; + let gitlab_event = req.headers['x-gitlab-event'] + let gitlab_delivery = req.headers['x-gitlab-event-uuid'] + //let hookId = req.headers['x-github-hook-id'] + let gitlab_signature = req.headers['x-gitlab-token'] + let gitlab_body = req.body + req.app.locals.kubero.handleWebhook('gitlab', gitlab_event, gitlab_delivery, gitlab_signature, gitlab_body); break; case "bitbucket": //req.app.locals.kubero.handleBitbucketWebhook(req.body); - ret = "bitbucket not supported yet"; break; default: ret = "unknown repoprovider "+encodeURI(req.params.repoprovider); From 998632dd5c89f6e5dfa3f7d50ae566af7b132894 Mon Sep 17 00:00:00 2001 From: Gianni C Date: Wed, 30 Nov 2022 10:02:05 +0100 Subject: [PATCH 05/17] add gogs support (#15) --- .env.template | 3 + client/src/components/pipelines/new.vue | 14 +- docker-compose.yaml | 18 +- src/git/gitea.ts | 2 +- src/git/gitlab.ts | 1 - src/git/gogs.ts | 277 ++++++++++++++++++++++++ src/git/types.ts | 2 +- src/kubero.ts | 27 ++- src/routes/repo.ts | 12 +- 9 files changed, 347 insertions(+), 9 deletions(-) create mode 100644 src/git/gogs.ts diff --git a/.env.template b/.env.template index 7395d162..93d9ce83 100644 --- a/.env.template +++ b/.env.template @@ -9,6 +9,9 @@ GITHUB_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #GITEA_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #GITEA_BASEURL=http://localhost:3000 +#GOGS_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +#GOGS_BASEURL=http://localhost:3000 + KUBECONFIG_PATH=./kubeconfig KUBERO_CONFIG_PATH=./config.yaml KUBERO_CONTEXT=kind-kubero diff --git a/client/src/components/pipelines/new.vue b/client/src/components/pipelines/new.vue index f8b03796..54743dc6 100644 --- a/client/src/components/pipelines/new.vue +++ b/client/src/components/pipelines/new.vue @@ -34,8 +34,8 @@ Github mdi-github Gitea Gitlab mdi-gitlab - oneDev - Gogs + oneDev + Gogs Bitbucket mdi-bitbucket @@ -288,6 +288,7 @@ export default { case 'github': this.connectRepository('github') this.repositoriesList.gitea = false; + this.repositoriesList.gogs = false; this.repositoriesList.gitlab = false; this.repositoriesList.bitbucket = false; this.repositoriesList.docker = false; @@ -295,6 +296,15 @@ export default { case 'gitea': this.connectRepository('gitea') this.repositoriesList.github = false; + this.repositoriesList.gogs = false; + this.repositoriesList.gitlab = false; + this.repositoriesList.bitbucket = false; + this.repositoriesList.docker = false; + break; + case 'gogs': + this.connectRepository('gogs') + this.repositoriesList.github = false; + this.repositoriesList.gitea = false; this.repositoriesList.gitlab = false; this.repositoriesList.bitbucket = false; this.repositoriesList.docker = false; diff --git a/docker-compose.yaml b/docker-compose.yaml index fce5e898..7612da7c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -44,4 +44,20 @@ services: - './.dockerdata/gitlab/config:/etc/gitlab' - './.dockerdata/gitlab/logs:/var/log/gitlab' - './.dockerdata/gitlab/data:/var/opt/gitlab' - shm_size: '256m' \ No newline at end of file + shm_size: '256m' + + gogs: + image: gogs/gogs:latest + container_name: gogs + hostname: 'localhost' + environment: + - USER_UID=1000 + - USER_GID=1000 + restart: always + volumes: + - ./.dockerdata/gogs:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "3000:3000" + - "22:22" \ No newline at end of file diff --git a/src/git/gitea.ts b/src/git/gitea.ts index ab741fe2..46985df8 100644 --- a/src/git/gitea.ts +++ b/src/git/gitea.ts @@ -265,7 +265,7 @@ export class GiteaApi extends Repo { public async listRepos(): Promise { let ret: string[] = []; try { - const repos = await this.gitea.request('GET /user/repos', {}) + const repos = await this.gitea.user.userCurrentListRepos() for (let repo of repos.data) { ret.push(repo.ssh_url) } diff --git a/src/git/gitlab.ts b/src/git/gitlab.ts index 8881c14c..0c2bee55 100644 --- a/src/git/gitlab.ts +++ b/src/git/gitlab.ts @@ -1,7 +1,6 @@ // https://www.nerd.vision/post/nerdvision-gitlab-js-an-easier-way-to-access-the-gitlab-api-in-javascript // https://www.npmjs.com/package/@nerdvision/gitlab-js import debug from 'debug'; -import * as crypto from "crypto" import { IWebhook, IRepository, IWebhookR, IDeploykeyR} from './types'; import { Repo } from './repo'; import {Client as GitlabClient} from '@nerdvision/gitlab-js'; diff --git a/src/git/gogs.ts b/src/git/gogs.ts new file mode 100644 index 00000000..c85259de --- /dev/null +++ b/src/git/gogs.ts @@ -0,0 +1,277 @@ +import debug from 'debug'; +import * as crypto from "crypto" +import { IWebhook, IRepository, IWebhookR, IDeploykeyR} from './types'; +import { Repo } from './repo'; +debug('app:kubero:gogs:api') + +//https://www.npmjs.com/package/gitea-js +import { giteaApi, Api } from "gitea-js" +import { fetch as fetchGitea } from 'cross-fetch'; + +export class GogsApi extends Repo { + private gitea: any; + + constructor(baseURL: string, token: string) { + super("gogs"); + this.gitea = giteaApi(baseURL, { + token: token, + customFetch: fetchGitea, + }); + } + + protected async getRepository(gitrepo: string): Promise { + let ret: IRepository = { + status: 500, + statusText: 'error', + data: { + owner: 'unknown', + name: 'unknown', + admin: false, + push: false, + } + } + + // TODO : Improve matching here + let owner = gitrepo.match(/^git@.*:(.*)\/.*$/)?.[1] as string; + let repo = gitrepo.match(/^git@.*:.*\/(.*)\.git$/)?.[1] as string; + + let res = await this.gitea.repos.repoGet(owner, repo) + .catch((error: any) => { + console.log(error) + return ret; + }) + + ret = { + status: res.status, + statusText: 'found', + data: { + id: res.data.id, + node_id: res.data.node_id, + name: res.data.name, + description: res.data.description, + owner: res.data.owner.login, + private : res.data.private, + ssh_url: res.data.ssh_url, + language: res.data.language, + homepage: res.data.homepage, + admin: res.data.permissions.admin, + push: res.data.permissions.push, + visibility: res.data.visibility, + default_branch: res.data.default_branch, + } + } + return ret; + + } + + protected async addWebhook(owner: string, repo: string, url: string, secret: string): Promise { + + let ret: IWebhookR = { + status: 500, + statusText: 'error', + data: { + id: 0, + active: false, + created_at: '2020-01-01T00:00:00Z', + url: '', + insecure: true, + events: [], + } + } + + //https://try.gitea.io/api/swagger#/repository/repoListHooks + const webhooksList = await this.gitea.repos.repoListHooks(owner, repo) + .catch((error: any) => { + console.log(error) + return ret; + }) + + // try to find the webhook + for (let webhook of webhooksList.data) { + if (webhook.config.url === url && + webhook.config.content_type === 'json' && + webhook.active === true) { + ret = { + status: 422, + statusText: 'found', + data: webhook, + } + return ret; + } + } + //console.log(webhooksList) + + // create the webhook since it does not exist + try { + + //https://try.gitea.io/api/swagger#/repository/repoCreateHook + let res = await this.gitea.repos.repoCreateHook(owner, repo, { + active: true, + config: { + url: url, + content_type: "json", + secret: secret, + insecure_ssl: '0' + }, + events: [ + "push", + "pull_request" + ], + type: "gogs" + }); + + ret = { + status: res.status, + statusText: 'created', + data: { + id: res.data.id, + active: res.data.active, + created_at: res.data.created_at, + url: res.data.url, + insecure: res.data.config.insecure_ssl, + events: res.data.events, + } + } + } catch (e) { + console.log(e) + } + return ret; + } + + + protected async addDeployKey(owner: string, repo: string): Promise { + + const keyPair = this.createDeployKeyPair(); + + const title: string = "bot@kubero"; + + let ret: IDeploykeyR = { + status: 500, + statusText: 'error', + data: { + id: 0, + title: title, + verified: false, + created_at: '2020-01-01T00:00:00Z', + url: '', + read_only: true, + pub: keyPair.pubKeyBase64, + priv: keyPair.privKeyBase64 + } + } + //https://try.gitea.io/api/swagger#/repository/repoListKeys + const keysList = await this.gitea.repos.repoListKeys(owner, repo) + .catch((error: any) => { + console.log(error) + return ret; + }) + + // try to find the key + for (let key of keysList.data) { + if (key.title === title && + key.read_only === true) { + ret = { + status: 422, + statusText: 'found', + data: key, + } + return ret; + } + } + + try { + //https://try.gitea.io/api/swagger#/repository/repoCreateKey + let res = await this.gitea.repos.repoCreateKey(owner, repo, { + title: title, + key: keyPair.pubKey, + read_only: true + }); + + ret = { + status: res.status, + statusText: 'created', + data: { + id: res.data.id, + title: res.data.title, + verified: res.data.verified, + created_at: res.data.created_at, + url: res.data.url, + read_only: res.data.read_only, + pub: keyPair.pubKeyBase64, + priv: keyPair.privKeyBase64 + } + } + } catch (e) { + console.log(e) + } + + return ret + } + + public getWebhook(event: string, delivery: string, signature: string, body: any): IWebhook | boolean { + //https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks + let secret = process.env.KUBERO_WEBHOOK_SECRET as string; + let hash = 'sha256='+crypto.createHmac('sha256', secret).update(JSON.stringify(body, null, ' ')).digest('hex') + + let verified = false; + if (hash === signature) { + debug.debug('Gitea webhook signature is valid for event: '+delivery); + verified = true; + } else { + debug.log('ERROR: invalid signature for event: '+delivery); + debug.log('Hash: '+hash); + debug.log('Signature: '+signature); + verified = false; + return false; + } + + let branch: string = 'main'; + let ssh_url: string = ''; + let action; + if (body.pull_request == undefined) { + let ref = body.ref + let refs = ref.split('/') + branch = refs[refs.length - 1] + ssh_url = body.repository.ssh_url + } else if (body.pull_request != undefined) { + action = body.action, + branch = body.pull_request.head.ref + ssh_url = body.pull_request.head.repo.ssh_url + } else { + ssh_url = body.repository.ssh_url + } + + try { + let webhook: IWebhook = { + repoprovider: 'gogs', + action: action, + event: event, + delivery: delivery, + body: body, + branch: branch, + verified: verified, + repo: { + ssh_url: ssh_url, + } + } + + return webhook; + } catch (error) { + console.log(error) + return false; + } + } + + public async listRepos(): Promise { + let ret: string[] = []; + try { + const repos = await this.gitea.user.userCurrentListRepos() + for (let repo of repos.data) { + ret.push(repo.ssh_url) + } + } catch (error) { + console.log(error) + } + return ret; + } +} diff --git a/src/git/types.ts b/src/git/types.ts index d2a86d58..b117cb29 100644 --- a/src/git/types.ts +++ b/src/git/types.ts @@ -1,5 +1,5 @@ export interface IWebhook { - repoprovider: 'gitea' | 'gitlab' | 'github', + repoprovider: 'gitea' | 'gitlab' | 'github' | 'bitbucket' | 'gogs' | 'onedev', action: 'opened' | 'reopened' | 'closed' | undefined, event: string, delivery: string, diff --git a/src/kubero.ts b/src/kubero.ts index a1ccef99..e11a6f40 100644 --- a/src/kubero.ts +++ b/src/kubero.ts @@ -4,6 +4,7 @@ import { IApp, IPipeline, IPipelineList, IKubectlAppList, IDeployKeyPair, IKubec import { App } from './modules/application'; import { GithubApi } from './git/github'; import { GiteaApi } from './git/gitea'; +import { GogsApi } from './git/gogs'; import { GitlabApi } from './git/gitlab'; import { IWebhook} from './git/types'; import YAML from 'yaml'; @@ -22,6 +23,7 @@ export class Kubero { private _io: Server; private githubApi: GithubApi; private giteaApi: GiteaApi; + private gogsApi: GogsApi; private gitlabApi: GitlabApi; private appStateList: IApp[] = []; private pipelineStateList: IPipeline[] = []; @@ -34,6 +36,7 @@ export class Kubero { this._io = io; this.giteaApi = new GiteaApi(process.env.GITEA_BASEURL as string, process.env.GITEA_PERSONAL_ACCESS_TOKEN as string); + this.gogsApi = new GogsApi(process.env.GOGS_BASEURL as string, process.env.GOGS_PERSONAL_ACCESS_TOKEN as string); this.githubApi = new GithubApi(process.env.GITHUB_PERSONAL_ACCESS_TOKEN as string); this.gitlabApi = new GitlabApi(process.env.GITLAB_BASEURL as string, process.env.GITLAB_PERSONAL_ACCESS_TOKEN as string); debug.debug('Kubero Config: '+JSON.stringify(this.config)); @@ -295,8 +298,12 @@ export class Kubero { return this.githubApi.listRepos(); case 'gitea': return this.giteaApi.listRepos(); + case 'gogs': + return this.gogsApi.listRepos(); case 'gitlab': return this.gitlabApi.listRepos(); + case 'ondev': + case 'bitbucket': default: return {'error': 'unknown repo provider'}; } @@ -310,8 +317,12 @@ export class Kubero { return this.githubApi.connectRepo(repoAddress); case 'gitea': return this.giteaApi.connectRepo(repoAddress); + case 'gogs': + return this.gogsApi.connectRepo(repoAddress); case 'gitlab': return this.gitlabApi.connectRepo(repoAddress); + case 'ondev': + case 'bitbucket': default: return {'error': 'unknown repo provider'}; } @@ -327,10 +338,14 @@ export class Kubero { case 'gitea': webhook = this.giteaApi.getWebhook(event, delivery, signature, body); break; + case 'gogs': + webhook = this.gogsApi.getWebhook(event, delivery, signature, body); + break; case 'gitlab': webhook = this.gitlabApi.getWebhook(event, delivery, signature, body); break; - + case 'ondev': + case 'bitbucket': default: break; } @@ -573,6 +588,8 @@ export class Kubero { github: false, gitea: false, gitlab: false, + gogs: false, + onedev: false, bitbucket: false, docker: true } @@ -589,6 +606,14 @@ export class Kubero { repositories.gitlab = true; } + if (process.env.GOGS_PERSONAL_ACCESS_TOKEN) { + repositories.gogs = true; + } + + if (process.env.ONEDEV_PERSONAL_ACCESS_TOKEN) { + repositories.onedev = true; + } + if (process.env.BITBUCKET_PERSONAL_ACCESS_TOKEN) { repositories.bitbucket = true; } diff --git a/src/routes/repo.ts b/src/routes/repo.ts index 450b1095..e049474d 100644 --- a/src/routes/repo.ts +++ b/src/routes/repo.ts @@ -38,20 +38,28 @@ Router.all('/repo/webhooks/:repoprovider', async function (req: Request, res: Re //console.log(req.headers) let gitea_event = req.headers['x-gitea-event'] let gitea_delivery = req.headers['x-gitea-delivery'] - //let hookId = req.headers['x-github-hook-id'] let gitea_signature = req.headers['x-hub-signature-256'] let gitea_body = req.body req.app.locals.kubero.handleWebhook('gitea', gitea_event, gitea_delivery, gitea_signature, gitea_body); break; + case "gogs": + //console.log(req.headers) + let gogs_event = req.headers['x-gogs-event'] + let gogs_delivery = req.headers['x-gogs-delivery'] + let gogs_signature = req.headers['x-hub-signature-256'] + let gogs_body = req.body + + req.app.locals.kubero.handleWebhook('gogs', gogs_event, gogs_delivery, gogs_signature, gogs_body); + break; case "gitlab": let gitlab_event = req.headers['x-gitlab-event'] let gitlab_delivery = req.headers['x-gitlab-event-uuid'] - //let hookId = req.headers['x-github-hook-id'] let gitlab_signature = req.headers['x-gitlab-token'] let gitlab_body = req.body req.app.locals.kubero.handleWebhook('gitlab', gitlab_event, gitlab_delivery, gitlab_signature, gitlab_body); break; + case "ondev": case "bitbucket": //req.app.locals.kubero.handleBitbucketWebhook(req.body); break; From f4d429383c36794ce11f38593f960e7ecc90a1ee Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Wed, 30 Nov 2022 18:04:46 +0100 Subject: [PATCH 06/17] add bitbucket implementation --- client/src/components/pipelines/new.vue | 20 +- package.json | 1 + src/git/bitbucket.ts | 288 ++++++++++++++++++++++++ src/git/types.ts | 4 +- src/kubero.ts | 15 +- src/routes/repo.ts | 7 +- yarn.lock | 20 +- 7 files changed, 334 insertions(+), 21 deletions(-) create mode 100644 src/git/bitbucket.ts diff --git a/client/src/components/pipelines/new.vue b/client/src/components/pipelines/new.vue index 54743dc6..ac1f9586 100644 --- a/client/src/components/pipelines/new.vue +++ b/client/src/components/pipelines/new.vue @@ -36,7 +36,7 @@ Gitlab mdi-gitlab oneDev Gogs - Bitbucket mdi-bitbucket + Bitbucket mdi-bitbucket @@ -311,24 +311,20 @@ export default { break; case 'gitlab': this.connectRepository('gitlab') - return; - /* - this.repositoriesList.gitea = false; this.repositoriesList.github = false; + this.repositoriesList.gitea = false; + this.repositoriesList.gogs = false; this.repositoriesList.bitbucket = false; this.repositoriesList.docker = false; - break; - */ - case 'bitbucket': - this.connectBitbucket(); return; - /* + case 'bitbucket': + this.connectRepository('bitbucket') + this.repositoriesList.github = false; this.repositoriesList.gitea = false; this.repositoriesList.gitlab = false; - this.repositoriesList.github = false; + this.repositoriesList.gogs = false; this.repositoriesList.docker = false; - break; - */ + return; default: break; } diff --git a/package.json b/package.json index c99e3161..0d1efedd 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@octokit/core": "^3.6.0", "@octokit/webhooks": "^9.26.0", "axios": "^0.27.2", + "bitbucket": "^2.9.0", "connect-history-api-fallback": "^1.6.0", "cors": "^2.8.5", "cross-fetch": "^3.1.5", diff --git a/src/git/bitbucket.ts b/src/git/bitbucket.ts new file mode 100644 index 00000000..8ef39089 --- /dev/null +++ b/src/git/bitbucket.ts @@ -0,0 +1,288 @@ +import debug from 'debug'; +import * as crypto from "crypto" +import { IWebhook, IRepository, IWebhookR, IDeploykeyR} from './types'; +import { Repo } from './repo'; +debug('app:kubero:bitbucket:api') + +//const { Octokit } = require("@octokit/core"); +import { Bitbucket, APIClient } from "bitbucket" +import { RequestError } from '@octokit/types'; + +export class BitbucketApi extends Repo { + private bitbucket: APIClient; + + constructor(username: string, appPassword: string) { + super("bitbucket"); + const clientOptions = { + auth: { + username: username, + password: appPassword + }, + } + + this.bitbucket = new Bitbucket(clientOptions) + } + + protected async getRepository(gitrepo: string): Promise { + let ret: IRepository = { + status: 500, + statusText: 'error', + data: { + owner: 'unknown', + name: 'unknown', + admin: false, + push: false, + } + } + + // TODO : Improve matching here + let owner = gitrepo.match(/^git@bitbucket.org:(.*)\/.*$/)?.[1] as string; + let repo = gitrepo.match(/^git@bitbucket.org:.*\/(.*).git$/)?.[1] as string; + + console.log(owner, repo); + try { + // https://bitbucketjs.netlify.app/#api-repositories-repositories_get + let res = await this.bitbucket.repositories.get({ + repo_slug: repo, + workspace: owner + }) + console.log(res.data); + + ret = { + status: res.status, + statusText: 'found', + data: { + id: res.data.uuid, + node_id: res.data.full_name as string, + name: res.data.slug as string, + description: res.data.description, + owner: res.data.owner?.nickname as string, + private : res.data.is_private, + ssh_url: res.data.links?.clone?.find((c: any) => c.name === 'ssh')?.href as string, + clone_url: res.data.links?.clone?.find((c: any) => c.name === 'https')?.href as string, + language: res.data.language, + homepage: res.data.website as string, + admin: true, // assumed since we ar loading only owned repos + push: true, // assumed since we ar loading only owned repos + //visibility: res.data.visibility, + default_branch: res.data.mainbranch?.name as string, + } + } + + } catch (e) { + let res = e as RequestError; + debug.log("Repository not found: "+ gitrepo); + ret = { + status: res.status, + statusText: 'not found', + data: { + owner: owner, + name: repo, + admin: false, + push: false, + } + } + } + return ret; + } + + public async getRepositories() { + let res = await this.bitbucket.request('GET /user/repos', {}) + return res.data; + } + + protected async addWebhook(owner: string, repo: string, url: string, secret: string): Promise { + + let ret: IWebhookR = { + status: 500, + statusText: 'error', + data: { + id: 0, + active: false, + created_at: '2020-01-01T00:00:00Z', + url: '', + insecure: true, + events: [], + } + } + + + let webhooksList = await this.bitbucket.repositories.listWebhooks({ + repo_slug: repo, + workspace: owner + }) + + let webhook = webhooksList.data.values?.find((w: any) => w.url === url); + if (webhook == undefined) { + try { + let res = await this.bitbucket.repositories.createWebhook({ + repo_slug: repo, + workspace: owner, + _body: { + description: "Kubero webhook", + url: url, + active: true, + //skip_cert_verification: false, + events: ["pullrequest:created", "repo:push"] + } + }) + ret = { + status: 201, + statusText: 'created', + data: { + id: res.data.uuid as string, + active: res.data.active as boolean, + created_at: res.data.created_at as string, + url: res.data.url as string, + insecure: !res.data.skip_cert_verification as boolean, + events: res.data.events as string[], + } + } + } catch (e) { + console.log(e) + } + } else { + console.log("Webhook already exists") + console.log(webhook) + + ret = { + status: 422, + statusText: 'created', + data: { + id: webhook.uuid as string, + active: webhook.active as boolean, + created_at: webhook.created_at as string, + url: webhook.url as string, + insecure: !webhook.skip_cert_verification as boolean, + events: webhook.events as string[], + } + } + + } + + return ret; + } + + protected async addDeployKey(owner: string, repo: string): Promise { + + const keyPair = this.createDeployKeyPair(); + + let ret: IDeploykeyR = { + status: 500, + statusText: 'error', + data: { + id: 0, + title: "bot@kubero", + verified: false, + created_at: '2020-01-01T00:00:00Z', + url: '', + read_only: true, + pub: keyPair.pubKeyBase64, + priv: keyPair.privKeyBase64 + } + } + + try { + // https://bitbucketjs.netlify.app/#api-repositories-repositories_createDeployKey + let res = await this.bitbucket.repositories.createDeployKey({ + label: "bot@kubero", + key: keyPair.pubKey, + repo_slug: repo, + workspace: owner + }); + + console.log(res); + + + ret = { + status: res.status, + statusText: 'created', + data: { + id: res.data.id as number, + title: res.data.label as string, + verified: true, + created_at: res.data.created_on as string, + url: '', + read_only: false, + pub: keyPair.pubKeyBase64, + priv: keyPair.privKeyBase64 + } + } + } catch (e) { + let res = e as RequestError; + debug.log("Error adding deploy key: "+ res); + } + + return ret + } + + public getWebhook(event: string, delivery: string, body: any): IWebhook | boolean { + + // use github and gitea naming for the event + let github_event = event; + if (event === 'repo:push') { + github_event = 'push'; + } else if (event === 'pullrequest:created') { + github_event = 'pull_request'; + } else { + debug.log('ERROR: untranslated Bitbucket event: '+event); + return false; + } + + let branch: string = 'main'; + let ssh_url: string = ''; + let action; + if (body.ref != undefined) { + let ref = body.ref + let refs = ref.split('/') + branch = refs[refs.length - 1] + ssh_url = body.repository.ssh_url + } else if (body.pull_request != undefined) { + action = body.action, + branch = body.pull_request.head.ref + ssh_url = body.pull_request.head.repo.ssh_url + } else { + ssh_url = body.repository.ssh_url + } + + try { + let webhook: IWebhook = { + repoprovider: 'bitbucket', + action: action, + event: github_event, + delivery: delivery, + body: body, + branch: branch, + verified: true, // bitbucket does not support verification with signatures :( + repo: { + ssh_url: ssh_url, + } + } + + return webhook; + } catch (error) { + debug.log(error) + return false; + } + } + + public async listRepos(): Promise { + let ret: string[] = []; + try { + // https://bitbucketjs.netlify.app/#api-repositories-repositories_listGlobal + const repos = await this.bitbucket.repositories.listGlobal({ role: 'member' }) + + if (repos.data.values != undefined) { + for (let repo of repos.data.values) { + if (repo.links != undefined && repo.links.clone != undefined) { + ret.push(repo.links.clone[1].href as string); + } + } + } + + } catch (error) { + debug.log(error) + } + return ret; + } +} \ No newline at end of file diff --git a/src/git/types.ts b/src/git/types.ts index b117cb29..85a59197 100644 --- a/src/git/types.ts +++ b/src/git/types.ts @@ -15,7 +15,7 @@ export interface IRepository { status: number, statusText: 'error' | 'not found' | 'found', data: { - id?: number, + id?: number | string, // bitbucket uses UUID's node_id?: string, name: string, description?: string, @@ -36,7 +36,7 @@ export interface IWebhookR { status: number, statusText: 'error' | 'created' | 'not found' | 'found', data: { - id?: number, + id?: number | string, // bitbucket uses UUID's active: boolean, created_at: string, url: string, diff --git a/src/kubero.ts b/src/kubero.ts index e11a6f40..66759a44 100644 --- a/src/kubero.ts +++ b/src/kubero.ts @@ -3,6 +3,7 @@ import { Server } from "socket.io"; import { IApp, IPipeline, IPipelineList, IKubectlAppList, IDeployKeyPair, IKubectlPipelineList, IKubectlApp, IPodSize, IKuberoConfig} from './types'; import { App } from './modules/application'; import { GithubApi } from './git/github'; +import { BitbucketApi } from './git/bitbucket'; import { GiteaApi } from './git/gitea'; import { GogsApi } from './git/gogs'; import { GitlabApi } from './git/gitlab'; @@ -25,6 +26,7 @@ export class Kubero { private giteaApi: GiteaApi; private gogsApi: GogsApi; private gitlabApi: GitlabApi; + private bitbucketApi: BitbucketApi; private appStateList: IApp[] = []; private pipelineStateList: IPipeline[] = []; private podLogStreams: string[]= [] @@ -39,6 +41,7 @@ export class Kubero { this.gogsApi = new GogsApi(process.env.GOGS_BASEURL as string, process.env.GOGS_PERSONAL_ACCESS_TOKEN as string); this.githubApi = new GithubApi(process.env.GITHUB_PERSONAL_ACCESS_TOKEN as string); this.gitlabApi = new GitlabApi(process.env.GITLAB_BASEURL as string, process.env.GITLAB_PERSONAL_ACCESS_TOKEN as string); + this.bitbucketApi = new BitbucketApi(process.env.BITBUCKET_USERNAME as string, process.env.BITBUCKET_APP_PASSWORD as string); debug.debug('Kubero Config: '+JSON.stringify(this.config)); } @@ -302,8 +305,9 @@ export class Kubero { return this.gogsApi.listRepos(); case 'gitlab': return this.gitlabApi.listRepos(); - case 'ondev': case 'bitbucket': + return this.bitbucketApi.listRepos(); + case 'ondev': default: return {'error': 'unknown repo provider'}; } @@ -321,8 +325,9 @@ export class Kubero { return this.gogsApi.connectRepo(repoAddress); case 'gitlab': return this.gitlabApi.connectRepo(repoAddress); - case 'ondev': case 'bitbucket': + return this.bitbucketApi.connectRepo(repoAddress); + case 'ondev': default: return {'error': 'unknown repo provider'}; } @@ -344,8 +349,10 @@ export class Kubero { case 'gitlab': webhook = this.gitlabApi.getWebhook(event, delivery, signature, body); break; - case 'ondev': case 'bitbucket': + webhook = this.bitbucketApi.getWebhook(event, delivery, body); // Bitbucket has no signature + break; + case 'ondev': default: break; } @@ -614,7 +621,7 @@ export class Kubero { repositories.onedev = true; } - if (process.env.BITBUCKET_PERSONAL_ACCESS_TOKEN) { + if (process.env.BITBUCKET_USERNAME && process.env.BITBUCKET_APP_PASSWORD) { repositories.bitbucket = true; } diff --git a/src/routes/repo.ts b/src/routes/repo.ts index e049474d..20a8e7d5 100644 --- a/src/routes/repo.ts +++ b/src/routes/repo.ts @@ -61,7 +61,12 @@ Router.all('/repo/webhooks/:repoprovider', async function (req: Request, res: Re break; case "ondev": case "bitbucket": - //req.app.locals.kubero.handleBitbucketWebhook(req.body); + case "gitlab": + console.log(req.headers) + let bitbucket_event = req.headers['x-event-key'] + let bitbucket_delivery = req.headers['x-request-uuid'] + let bitbucket_body = req.body + req.app.locals.kubero.handleWebhook('bitbucket', bitbucket_event, bitbucket_delivery, "", bitbucket_body); break; default: ret = "unknown repoprovider "+encodeURI(req.params.repoprovider); diff --git a/yarn.lock b/yarn.lock index 34c556b1..0e4de092 100644 --- a/yarn.lock +++ b/yarn.lock @@ -697,7 +697,7 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -before-after-hook@^2.2.0: +before-after-hook@^2.1.0, before-after-hook@^2.2.0: version "2.2.3" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== @@ -707,6 +707,17 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +bitbucket@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/bitbucket/-/bitbucket-2.9.0.tgz#29c0f96ca59db74f3b7429c071be1e0646372fda" + integrity sha512-ITr0bQaKezsiQbE19ISGr93IoXotoyv/XaBqImpKKnoVeO3ClWGQxSziSq7wh+4JBQ6aEFVaeoLGINjsgvkjHA== + dependencies: + before-after-hook "^2.1.0" + deepmerge "^4.2.2" + is-plain-object "^3.0.0" + node-fetch "^2.6.0" + url-template "^2.0.8" + body-parser@1.20.1: version "1.20.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" @@ -1826,7 +1837,7 @@ negotiator@0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -node-fetch@2.6.7, node-fetch@^2.6.7: +node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -2638,6 +2649,11 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +url-template@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" + integrity sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw== + utils-merge@1.0.1, utils-merge@1.x.x: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" From 507a2df8344e7816baa3da3ac7df4bacc9f43856 Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Wed, 30 Nov 2022 18:13:56 +0100 Subject: [PATCH 07/17] hide onedev tab for now --- client/src/components/pipelines/new.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/pipelines/new.vue b/client/src/components/pipelines/new.vue index ac1f9586..89a9b81b 100644 --- a/client/src/components/pipelines/new.vue +++ b/client/src/components/pipelines/new.vue @@ -34,7 +34,7 @@ Github mdi-github Gitea Gitlab mdi-gitlab - oneDev + Gogs Bitbucket mdi-bitbucket From 0878b77011cc220038fe66f84a2377b4ba355754 Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Wed, 30 Nov 2022 19:33:57 +0100 Subject: [PATCH 08/17] update server --- yarn.lock | 153 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 80 insertions(+), 73 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0e4de092..032790ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -210,14 +210,14 @@ "@types/node" "*" "@types/cacheable-request@^6.0.1": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9" - integrity sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA== + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== dependencies: "@types/http-cache-semantics" "*" - "@types/keyv" "*" + "@types/keyv" "^3.1.4" "@types/node" "*" - "@types/responselike" "*" + "@types/responselike" "^1.0.0" "@types/caseless@*": version "0.12.2" @@ -344,12 +344,12 @@ resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" integrity sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw== -"@types/keyv@*": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-4.2.0.tgz#65b97868ab757906f2dbb653590d7167ad023fa0" - integrity sha512-xoBtGl5R9jeKUhc8ZqeYaRDx04qqJ10yhhXYGmJ4Jr8qKpvMsDQQrNUvF/wUJ4klOtmJeJM+p2Xo3zp9uaC3tw== +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== dependencies: - keyv "*" + "@types/node" "*" "@types/koa-compose@*": version "3.2.5" @@ -380,9 +380,9 @@ "@types/lodash" "*" "@types/lodash@*": - version "4.14.186" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.186.tgz#862e5514dd7bd66ada6c70ee5fce844b06c8ee97" - integrity sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw== + version "4.14.190" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.190.tgz#d8e99647af141c63902d0ca53cf2b34d2df33545" + integrity sha512-5iJ3FBJBvQHQ8sFhEhJfjUP+G+LalhavTkYyrAYqz5MEJG+erSv0k9KJLb6q7++17Lafk1scaTIFXcMJlwK8Mw== "@types/mime@*": version "3.0.1" @@ -402,9 +402,9 @@ integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== "@types/node@*", "@types/node@>=10.0.0": - version "18.11.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.2.tgz#c59b7641832531264fda3f1ba610362dc9a7dfc8" - integrity sha512-BWN3M23gLO2jVG8g/XHIRFWiiV4/GckeFIqbU/C4V3xpoBBWSMk4OZomouN0wCkfQFPqgZikyLr7DOYDysIkkw== + version "18.11.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" + integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== "@types/node@^10.12.0": version "10.17.60" @@ -494,7 +494,7 @@ "@types/tough-cookie" "*" form-data "^2.5.0" -"@types/responselike@*", "@types/responselike@^1.0.0": +"@types/responselike@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== @@ -510,9 +510,9 @@ "@types/node" "*" "@types/sshpk@^1.17.0": - version "1.17.0" - resolved "https://registry.yarnpkg.com/@types/sshpk/-/sshpk-1.17.0.tgz#2391f7845b554ee309a28f60f56e0abd10dfdfa1" - integrity sha512-yHxVn9o5r9g4qd6HByA3ydIdHGzxw5NFQCwY7uS4aM1b4RLnexdtLwp08Dq5n0W/asrDpvbX0+C+tzep4tVDZQ== + version "1.17.1" + resolved "https://registry.yarnpkg.com/@types/sshpk/-/sshpk-1.17.1.tgz#2eb4fee514dc41fa9b904390a20eb02a58de5e10" + integrity sha512-bOJek/W++DvWRNAeHmpvgX8Q1ypAq4nmeVi3nJ+pjDcMB214S8kSGkxRUw/Uz+zau4VwxcfNp0xUq4s/3DLjLw== dependencies: "@types/asn1" "*" "@types/node" "*" @@ -611,9 +611,9 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: color-convert "^2.0.1" anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -884,9 +884,9 @@ concat-map@0.0.1: integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== concurrently@^7.2.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-7.4.0.tgz#bb0e344964bc172673577c420db21e963f2f7368" - integrity sha512-M6AfrueDt/GEna/Vg9BqQ+93yuvzkSKmoTixnwEJkH0LlcGrRC2eCmjeG1tLLHIYfpYJABokqSGyMcXjm96AFA== + version "7.6.0" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-7.6.0.tgz#531a6f5f30cf616f355a4afb8f8fcb2bba65a49a" + integrity sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw== dependencies: chalk "^4.1.0" date-fns "^2.29.1" @@ -1086,10 +1086,10 @@ engine.io-parser@~5.0.3: resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg== -engine.io@~6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.0.tgz#003bec48f6815926f2b1b17873e576acd54f41d0" - integrity sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg== +engine.io@~6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.1.tgz#e3f7826ebc4140db9bbaa9021ad6b1efb175878f" + integrity sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA== dependencies: "@types/cookie" "^0.4.1" "@types/cors" "^2.8.12" @@ -1343,9 +1343,9 @@ getpass@^0.1.1: assert-plus "^1.0.0" gitea-js@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/gitea-js/-/gitea-js-1.2.0.tgz#b118b003c1ca4499d9ad0a4f15f343967a362cb4" - integrity sha512-/1Xqs8wVWnSTtIJ3JffXbPwVtmJjA+qjVnmdZ0DShj1RKgKzYlqfXT8JUJ7lBdLHXauZrp5VFqldIKrbmWCqKg== + version "1.19.1" + resolved "https://registry.yarnpkg.com/gitea-js/-/gitea-js-1.19.1.tgz#7c604513ab8f963be852a9e0145a93c40d1977d4" + integrity sha512-+aU/j31u2NNQDqpEHIFp5fdDWk+mc+L7z6fXyB9vlVOzdKYR32MosYIuPicVFiq8wyGOjZ46QhXsjjVFjJrj0w== glob-parent@~5.1.2: version "5.1.2" @@ -1668,13 +1668,6 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" -keyv@*, keyv@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.0.tgz#dbce9ade79610b6e641a9a65f2f6499ba06b9bc6" - integrity sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA== - dependencies: - json-buffer "3.0.1" - keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -1682,6 +1675,13 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" +keyv@^4.0.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56" + integrity sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g== + dependencies: + json-buffer "3.0.1" + kubernetes-client@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/kubernetes-client/-/kubernetes-client-9.0.0.tgz#f72e6c71aaa20548b3d6466f1dc88dfa61fb3ba4" @@ -1797,10 +1797,17 @@ minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minipass@*, minipass@^3.0.0: - version "3.3.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.4.tgz#ca99f95dd77c43c7a76bf51e6d200025eee0ffae" - integrity sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw== +minipass@*: + version "4.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.0.0.tgz#7cebb0f9fa7d56f0c5b17853cbe28838a8dbbd3b" + integrity sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw== + dependencies: + yallist "^4.0.0" + +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== dependencies: yallist "^4.0.0" @@ -2344,9 +2351,9 @@ signal-exit@^3.0.3: integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== simple-update-notifier@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz#7edf75c5bdd04f88828d632f762b2bc32996a9cc" - integrity sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew== + version "1.1.0" + resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82" + integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg== dependencies: semver "~7.0.0" @@ -2355,7 +2362,7 @@ socket.io-adapter@~2.4.0: resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== -socket.io-parser@~4.2.0: +socket.io-parser@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5" integrity sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g== @@ -2364,16 +2371,16 @@ socket.io-parser@~4.2.0: debug "~4.3.1" socket.io@^4.5.1: - version "4.5.3" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.3.tgz#44dffea48d7f5aa41df4a66377c386b953bc521c" - integrity sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg== + version "4.5.4" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.4.tgz#a4513f06e87451c17013b8d13fdfaf8da5a86a90" + integrity sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ== dependencies: accepts "~1.3.4" base64id "~2.0.0" debug "~4.3.2" - engine.io "~6.2.0" + engine.io "~6.2.1" socket.io-adapter "~2.4.0" - socket.io-parser "~4.2.0" + socket.io-parser "~4.2.1" spawn-command@^0.0.2-1: version "0.0.2-1" @@ -2484,21 +2491,21 @@ swagger-fluent@^5.0.3: request "^2.88.0" swagger-ui-dist@>=4.11.0: - version "4.14.3" - resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-4.14.3.tgz#02aeaf61ec35aa85a4ed17f4b6b7417c00526c1f" - integrity sha512-Y7Sta24I9r+G6dX3ZTIq9Psr55cDC3myCB0E00ZnVkB0Wn3cO77NdLXSM0f90WZh9VpgTetKpMPR3n2VqKr+lQ== + version "4.15.5" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-4.15.5.tgz#cda226a79db2a9192579cc1f37ec839398a62638" + integrity sha512-V3eIa28lwB6gg7/wfNvAbjwJYmDXy1Jo1POjyTzlB6wPcHiGlRxq39TSjYGVjQrUSAzpv+a7nzp7mDxgNy57xA== swagger-ui-express@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-4.5.0.tgz#feb1314627092eb9c7e6b65ee018927011445530" - integrity sha512-DHk3zFvsxrkcnurGvQlAcLuTDacAVN1JHKDgcba/gr2NFRE4HGwP1YeHIXMiGznkWR4AeS7X5vEblNn4QljuNA== + version "4.6.0" + resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-4.6.0.tgz#fc297d80c614c80f5d7def3dab50b56428cfe1c9" + integrity sha512-ZxpQFp1JR2RF8Ar++CyJzEDdvufa08ujNUJgMVTMWPi86CuQeVdBtvaeO/ysrz6dJAYXf9kbVNhWD7JWocwqsA== dependencies: swagger-ui-dist ">=4.11.0" tar@^6.1.11: - version "6.1.11" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" - integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + version "6.1.12" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.12.tgz#3b742fb05669b55671fb769ab67a7791ea1a62e6" + integrity sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -2569,9 +2576,9 @@ tslib@^1.9.3: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== tunnel-agent@^0.6.0: version "0.6.0" @@ -2594,9 +2601,9 @@ type-is@~1.6.18: mime-types "~2.1.24" typescript@^4.6.4: - version "4.8.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" - integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + version "4.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" + integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== uid-safe@~2.1.5: version "2.1.5" @@ -2749,15 +2756,15 @@ yaml@^2.1.1: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.3.tgz#9b3a4c8aff9821b696275c79a8bee8399d945207" integrity sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg== -yargs-parser@^21.0.0: +yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== yargs@^17.3.1: - version "17.6.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.0.tgz#e134900fc1f218bc230192bdec06a0a5f973e46c" - integrity sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g== + version "17.6.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.2.tgz#2e23f2944e976339a1ee00f18c77fedee8332541" + integrity sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw== dependencies: cliui "^8.0.1" escalade "^3.1.1" @@ -2765,4 +2772,4 @@ yargs@^17.3.1: require-directory "^2.1.1" string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^21.0.0" + yargs-parser "^21.1.1" From 5e27fc8f8262a6077d7ade1694491ae3a9a0ea70 Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Wed, 30 Nov 2022 22:02:39 +0100 Subject: [PATCH 09/17] add supported repositories to README --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7dff2a83..ed7825f8 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ ![GitHub package.json version](https://img.shields.io/github/package-json/v/kubero-dev/kubero?style=flat-square)
+Kubero brings the convinience of Heroku to your kubernetes cluster. Your developers should not need to worry about the underlying infrastructure and deployment.
-Kubero brings the convinience of Heroku/platform.sh to your kubernetes cluster. Your developers should not need to worry about the underlying infrastructure and deployment. +
+Kubero is Kubernetes native and runs on every Kubernetes. It cpmes with a UI, API and a CLI.

-Kubero runs as a operator and has a UI, API and soon a CLI. - ## What can Kubero do for you? - Create a CI pipeline with up to 4 separate environments for all your applications: review apps -> testing -> stageing -> production @@ -30,9 +30,13 @@ Kubero runs as a operator and has a UI, API and soon a CLI. - Install and manage your operators - Give access to your container CLI -## Which heroku features are still missing? -- Dataclips -- CLI (Work in progress: https://github.com/kubero-dev/kubero-cli ) +## Supported GIT repositories +- Github +- Bitbucket +- Gilab (hosted and self hosted) +- Gitea (hosted and self hosted) +- Gogs (hosted and self hosted) +--> need more? Open an issue. ## Which languages are supported Basicly *everything* that can be shipped in a single container. Kubero uses official images to build and run the apps. But they can be replaced or extended to fit your needs. @@ -60,13 +64,13 @@ https://github.com/kubero-dev/buildpacks # Usage 1. Create a pipeline with all your phases -2. Connect the Pipeline to your git repository ( not required with pre-build image deployment ) +2. Connect the Pipeline to your git repository (Github, Bitbucket, Gitlab, Gitea, Gogs) 3. Create your apps with cronjobs and addons # Full documentation https://github.com/kubero-dev/kubero/wiki -## Stargazers over time +## Support Staring this projects helps a lot. ⭐ Thank you! [![Stargazers over time](https://starchart.cc/kubero-dev/kubero.svg)](https://starchart.cc/kubero-dev/kubero) From 98fc00affc9f4f034aa8c9fd68409db223828f27 Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Thu, 1 Dec 2022 04:45:50 +0100 Subject: [PATCH 10/17] update readme --- README.md | 15 +++++---------- docs/screenshots/gitrepositories.png | Bin 0 -> 19839 bytes 2 files changed, 5 insertions(+), 10 deletions(-) create mode 100644 docs/screenshots/gitrepositories.png diff --git a/README.md b/README.md index ed7825f8..57f1549e 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,14 @@

-![GitHub](https://img.shields.io/github/license/kubero-dev/kubero?style=flat-square) -![GitHub package.json version](https://img.shields.io/github/package-json/v/kubero-dev/kubero?style=flat-square) +![GitHub](https://img.shields.io/github/license/kubero-dev/kubero?style=flat-square&color=brightgreen) +![GitHub package.json version](https://img.shields.io/github/package-json/v/kubero-dev/kubero?style=flat-square&color=brightgreen)
Kubero brings the convinience of Heroku to your kubernetes cluster. Your developers should not need to worry about the underlying infrastructure and deployment.

-Kubero is Kubernetes native and runs on every Kubernetes. It cpmes with a UI, API and a CLI. +Kubero is Kubernetes native and runs on every Kubernetes. It comes with a UI, API and a CLI.

@@ -31,12 +31,7 @@ Kubero is Kubernetes native and runs on every Kubernetes. It cpmes with a UI, AP - Give access to your container CLI ## Supported GIT repositories -- Github -- Bitbucket -- Gilab (hosted and self hosted) -- Gitea (hosted and self hosted) -- Gogs (hosted and self hosted) ---> need more? Open an issue. + ## Which languages are supported Basicly *everything* that can be shipped in a single container. Kubero uses official images to build and run the apps. But they can be replaced or extended to fit your needs. @@ -55,7 +50,7 @@ You find the preconfigured buildpacks and examples here: https://github.com/kubero-dev/buildpacks ## Quickstart -1) Download and unpack the Kubero CLI here

+1) Download and unpack the Kubero CLI

2) Run `kubero install` to install all components on your cluster ## Screenshots diff --git a/docs/screenshots/gitrepositories.png b/docs/screenshots/gitrepositories.png new file mode 100644 index 0000000000000000000000000000000000000000..2f0bdc8ec3a43fbf8882e326da4ebe9293f43af0 GIT binary patch literal 19839 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

C%HLMOKbAxc92gL- zHSu5d`#X+?^Ns+)nJAn7AEx;KY5m8VMGGmjw?XXq1?$5G0<@hL5$CYyO-qcOiGKlk C Date: Thu, 1 Dec 2022 05:12:12 +0100 Subject: [PATCH 11/17] update readme --- README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 57f1549e..a41a8f2c 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@
![GitHub](https://img.shields.io/github/license/kubero-dev/kubero?style=flat-square&color=brightgreen) -![GitHub package.json version](https://img.shields.io/github/package-json/v/kubero-dev/kubero?style=flat-square&color=brightgreen) +![GitHub release (latest by date)](https://img.shields.io/github/v/release/kubero-dev/kubero?style=flat-square&color=brightgreen)
-Kubero brings the convinience of Heroku to your kubernetes cluster. Your developers should not need to worry about the underlying infrastructure and deployment. +Kubero brings the convinience of Heroku to your kubernetes cluster. Your developers should not need to worry about the underlying infrastructure and deployment. It enables you to deploy your applications within some clicks. It also provides a dashboard and CLI to manage your applications.

-Kubero is Kubernetes native and runs on every Kubernetes. It comes with a UI, API and a CLI. +Kubero is Kubernetes native and runs on every Kubernetes.

@@ -65,7 +65,16 @@ https://github.com/kubero-dev/buildpacks # Full documentation https://github.com/kubero-dev/kubero/wiki +# Contributing +All contributions are welcome! + - Open an issue + - Add a feature or open a feature request + - Discuss ideas in the discussions + - Fix typos + - Contribute code + - Write articles + ## Support Staring this projects helps a lot. ⭐ Thank you! -[![Stargazers over time](https://starchart.cc/kubero-dev/kubero.svg)](https://starchart.cc/kubero-dev/kubero) +[![Stargazers over time](https://starchart.cc/kubero-dev/kubero.svg)](https://starchart.cc/kubero-dev/kubero) \ No newline at end of file From 4dd9ff70001af5e1914ca938e253c66951e43726 Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Thu, 1 Dec 2022 05:16:02 +0100 Subject: [PATCH 12/17] update readme --- CONTRIBUTING.md | 2 +- README.md | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3aaa149c..91f1cad6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ # How to contribute All contributions are welcome. For simple typos, just open a PR. -For bigger ideas it might be better to open a issue first before you put a lot of work into it. This way we can discuss the idea first. +For bigger ideas it might be better to open a issue first before you put a lot of work into it. ## Development setup ### Requirements diff --git a/README.md b/README.md index a41a8f2c..eccf12b4 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ So far tested languages/frameworks: - Rust (including Rocket) - ... +# Preconfigured Buildpacks You find the preconfigured buildpacks and examples here: https://github.com/kubero-dev/buildpacks @@ -62,9 +63,12 @@ https://github.com/kubero-dev/buildpacks 2. Connect the Pipeline to your git repository (Github, Bitbucket, Gitlab, Gitea, Gogs) 3. Create your apps with cronjobs and addons -# Full documentation +# Documentation https://github.com/kubero-dev/kubero/wiki +# Roadmap +https://github.com/orgs/kubero-dev/projects/1/views/3 + # Contributing All contributions are welcome! - Open an issue From 058fd4f71ff82ca135230c11fc05ba2450e3a2cc Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Thu, 1 Dec 2022 05:17:12 +0100 Subject: [PATCH 13/17] update readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index eccf12b4..37717f39 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ So far tested languages/frameworks: - Rust (including Rocket) - ... -# Preconfigured Buildpacks +## Preconfigured Buildpacks You find the preconfigured buildpacks and examples here: https://github.com/kubero-dev/buildpacks @@ -58,18 +58,18 @@ https://github.com/kubero-dev/buildpacks more Screenshots

-# Usage +## Usage 1. Create a pipeline with all your phases 2. Connect the Pipeline to your git repository (Github, Bitbucket, Gitlab, Gitea, Gogs) 3. Create your apps with cronjobs and addons -# Documentation +## Documentation https://github.com/kubero-dev/kubero/wiki -# Roadmap +## Roadmap https://github.com/orgs/kubero-dev/projects/1/views/3 -# Contributing +## Contributing All contributions are welcome! - Open an issue - Add a feature or open a feature request From e759e4ff360844bfb550d0af70ddc33dfb394bba Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Fri, 2 Dec 2022 04:49:54 +0100 Subject: [PATCH 14/17] add branch listing suggestions --- CONTRIBUTING.md | 2 ++ client/src/components/apps/new.vue | 34 +++++++++++++++++-------- client/src/components/pipelines/new.vue | 2 ++ src/git/bitbucket.ts | 22 ++++++++++++++++ src/git/gitea.ts | 22 +++++++++++++++- src/git/github.ts | 30 +++++++++++++++++----- src/git/gitlab.ts | 25 ++++++++++++++++++ src/git/gogs.ts | 19 +++++++++++++- src/git/repo.ts | 7 +++++ src/kubero.ts | 32 +++++++++++++++++++++++ src/routes/repo.ts | 6 +++++ 11 files changed, 181 insertions(+), 20 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 91f1cad6..afc15790 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,8 @@ All contributions are welcome. For simple typos, just open a PR. For bigger ideas it might be better to open a issue first before you put a lot of work into it. +Want to contribute, but dont know where to start? Have a look into the Roadmap. + ## Development setup ### Requirements - docker diff --git a/client/src/components/apps/new.vue b/client/src/components/apps/new.vue index 0e86110a..221f10b8 100644 --- a/client/src/components/apps/new.vue +++ b/client/src/components/apps/new.vue @@ -58,7 +58,6 @@ - + > /((git|ssh|http(s)?)|(git@[\w.]+))(:(\/\/)?)([\w.@:/\-~]+)(\.git)(\/)?/.test(v) || 'Format "owner/repository"', ], - branchRules: [ - //v => !!v || 'Branch is required', - v => v.length <= 60 || 'Name must be less than 60 characters', - v => /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(v) || 'Allowed characters : [a-zA-Z0-9_-]', - ], domainRules: [ v => !!v || 'Domain is required', v => v.length <= 60 || 'Name must be less than 60 characters', @@ -605,6 +598,8 @@ export default { this.buildpack = this.pipelineData.buildpack; this.gitrepo.ssh_url = this.pipelineData.git.repository.ssh_url; + + this.loadBranches(); /* if (this.app == 'new') { switch (this.pipelineData.github.repository.language) { @@ -623,6 +618,23 @@ export default { */ }); }, + loadBranches() { + + // encode string to base64 (for ssh url) + const gitrepoB64 = btoa(this.pipelineData.git.repository.ssh_url); + const gitprovider = this.pipelineData.git.provider; + + axios.get('/api/repo/'+gitprovider+"/"+gitrepoB64+"/branches/list").then(response => { + for (let i = 0; i < response.data.length; i++) { + this.branchesList.push({ + text: response.data[i], + value: response.data[i], + }); + } + }); + }, + + loadPodsizeList() { axios.get('/api/config/podsize').then(response => { for (let i = 0; i < response.data.length; i++) { diff --git a/client/src/components/pipelines/new.vue b/client/src/components/pipelines/new.vue index 89a9b81b..cca34b31 100644 --- a/client/src/components/pipelines/new.vue +++ b/client/src/components/pipelines/new.vue @@ -188,6 +188,7 @@ export default { keys: {}, repository: {}, webhooks: {}, + provider: "" }, repository_status: { error: false, @@ -379,6 +380,7 @@ export default { this.repository_status.connected = false; this.repository_status.statusTxt = "Repository Not Connected"; } + this.git.provider = this.repotab; }).catch(error => { console.log(error); diff --git a/src/git/bitbucket.ts b/src/git/bitbucket.ts index 8ef39089..424dde9a 100644 --- a/src/git/bitbucket.ts +++ b/src/git/bitbucket.ts @@ -285,4 +285,26 @@ export class BitbucketApi extends Repo { } return ret; } + + public async getBranches(gitrepo: string): Promise { + //https://bitbucketjs.netlify.app/#api-repositories-repositories_listBranches + + let repo = "template-nodeapp" + let owner = "gicara" + try { + const branches = await this.bitbucket.repositories.listBranches({ + repo_slug: repo, + workspace: owner, + sort: '-name' + }) + if (branches.data.values != undefined) { + return branches.data.values.map((branch: any) => branch.name); + } + } catch (error) { + debug.log(error) + } + + return []; + + } } \ No newline at end of file diff --git a/src/git/gitea.ts b/src/git/gitea.ts index 46985df8..421970e1 100644 --- a/src/git/gitea.ts +++ b/src/git/gitea.ts @@ -171,7 +171,7 @@ export class GiteaApi extends Repo { if (key.title === title && key.read_only === true) { ret = { - status: 422, + status: 200, statusText: 'found', data: key, } @@ -274,4 +274,24 @@ export class GiteaApi extends Repo { } return ret; } + + public async getBranches(gitrepo: string): Promise{ + // https://try.gitea.io/api/swagger#/repository/repoListBranches + let ret: string[] = []; + + //let repo = "template-nodeapp" + //let owner = "gicara" + + let {repo, owner} = this.parseRepo(gitrepo) + try { + const branches = await this.gitea.repos.repoListBranches(owner, repo) + for (let branch of branches.data) { + ret.push(branch.name) + } + } catch (error) { + console.log(error) + } + + return ret; + } } diff --git a/src/git/github.ts b/src/git/github.ts index 68930a69..e819fbab 100644 --- a/src/git/github.ts +++ b/src/git/github.ts @@ -30,7 +30,7 @@ export class GithubApi extends Repo { } } - // TODO : Improve matching here + // TODO : Improve matching here or use default function in Superclass let owner = gitrepo.match(/^git@github.com:(.*)\/.*$/)?.[1] as string; let repo = gitrepo.match(/^git@github.com:.*\/(.*).git$/)?.[1] as string; @@ -84,12 +84,6 @@ export class GithubApi extends Repo { } /* - public async getRepositoryBranches(owner: string, repo: string) { - return await this.octokit.git.listBranches({ - owner: owner, - repo: repo - }); - } public async getRepositoryCommits(owner: string, repo: string, branch: string) { return await this.octokit.git.listCommits({ @@ -290,4 +284,26 @@ export class GithubApi extends Repo { } return ret; } + + public async getBranches(gitrepo: string): Promise{ + + let ret: string[] = []; + + let repo = "template-nodeapp" + let owner = "kubero-dev" + try { + const branches = await this.octokit.request('GET /repos/{owner}/{repo}/branches', { + owner: owner, + repo: repo, + }) + for (let branch of branches.data) { + ret.push(branch.name) + } + } catch (error) { + debug.log(error) + } + + return ret; + + } } \ No newline at end of file diff --git a/src/git/gitlab.ts b/src/git/gitlab.ts index 0c2bee55..299b7f17 100644 --- a/src/git/gitlab.ts +++ b/src/git/gitlab.ts @@ -307,4 +307,29 @@ export class GitlabApi extends Repo { return ret; } + public async getBranches(gitrepo: string): Promise{ + // https://docs.gitlab.com/ee/api/branches.html#list-repository-branches + // not implemented yet + let ret: string[] = []; + + let repo = "template-nodeapp" + let owner = "gicara" + try { + const branches:any = await this.gitlab.get(`projects/${owner}%2F${repo}/repository/branches`) + .catch((error: any) => { + console.log(error) + return ret; + }) + + for (let branch of branches) { + ret.push(branch.name) + } + } catch (error) { + console.log(error) + } + + + return ret; + } + } \ No newline at end of file diff --git a/src/git/gogs.ts b/src/git/gogs.ts index c85259de..b338d5a2 100644 --- a/src/git/gogs.ts +++ b/src/git/gogs.ts @@ -209,7 +209,6 @@ export class GogsApi extends Repo { } public getWebhook(event: string, delivery: string, signature: string, body: any): IWebhook | boolean { - //https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks let secret = process.env.KUBERO_WEBHOOK_SECRET as string; let hash = 'sha256='+crypto.createHmac('sha256', secret).update(JSON.stringify(body, null, ' ')).digest('hex') @@ -274,4 +273,22 @@ export class GogsApi extends Repo { } return ret; } + + public async getBranches(gitrepo: string): Promise{ + // https://try.gitea.io/api/swagger#/repository/repoListBranches + let ret: string[] = []; + + let repo = "template-nodeapp" + let owner = "gicara" + try { + const branches = await this.gitea.repos.repoListBranches(owner, repo) + for (let branch of branches.data) { + ret.push(branch.name) + } + } catch (error) { + console.log(error) + } + + return ret; + } } diff --git a/src/git/repo.ts b/src/git/repo.ts index d3a6b748..8f933d24 100644 --- a/src/git/repo.ts +++ b/src/git/repo.ts @@ -106,8 +106,15 @@ export abstract class Repo { } + protected parseRepo(gitrepo: string): {owner: string, repo: string} { + let owner = gitrepo.match(/^git@.*:(.*)\/.*$/)?.[1] as string; + let repo = gitrepo.match(/^git@.*:.*\/(.*).git$/)?.[1] as string; + return { owner: owner, repo: repo }; + } + protected abstract addDeployKey(owner: string, repo: string): Promise protected abstract getRepository(gitrepo: string): Promise; protected abstract addWebhook(owner: string, repo: string, url: string, secret: string): Promise; protected abstract getWebhook(event: string, delivery: string, signature: string, body: any): IWebhook | boolean; + protected abstract getBranches(repo: string): Promise | undefined; } \ No newline at end of file diff --git a/src/kubero.ts b/src/kubero.ts index 66759a44..dfb01d03 100644 --- a/src/kubero.ts +++ b/src/kubero.ts @@ -398,6 +398,38 @@ export class Kubero { } } + public async listRepoBranches(repoProvider: string, repoB64: string ): Promise { + //return this.git.listRepoBranches(repo, repoProvider); + let branches: Promise = new Promise((resolve, reject) => { + resolve([]); + }); + + const repo = Buffer.from(repoB64, 'base64').toString('ascii'); + + switch (repoProvider) { + case 'github': + branches = this.githubApi.getBranches(repo); + break; + case 'gitea': + branches = this.giteaApi.getBranches(repo); + break; + case 'gogs': + branches = this.gogsApi.getBranches(repo); + break; + case 'gitlab': + branches = this.gitlabApi.getBranches(repo); + break; + case 'bitbucket': + branches = this.bitbucketApi.getBranches(repo); + break; + case 'ondev': + default: + break; + } + + return branches + } + private async getAppsByBranch(branch: string) { debug.log('getAppsByBranch: '+branch); let apps: IApp[] = []; diff --git a/src/routes/repo.ts b/src/routes/repo.ts index 20a8e7d5..4ac7b92f 100644 --- a/src/routes/repo.ts +++ b/src/routes/repo.ts @@ -19,6 +19,12 @@ Router.post('/repo/:repoprovider/connect', async function (req: Request, res: Re res.send(con); }); +// connect pipeline with repository +Router.get('/repo/:repoprovider/:gitrepob64/branches/list', async function (req: Request, res: Response) { + let branches = await req.app.locals.kubero.listRepoBranches(req.params.repoprovider, req.params.gitrepob64); + res.send(branches); +}); + // get github webhook events Router.all('/repo/webhooks/:repoprovider', async function (req: Request, res: Response) { From afceb462e7e5c556241f2c28718f1235435f6c83 Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Fri, 2 Dec 2022 17:56:54 +0100 Subject: [PATCH 15/17] add deployment strategy switch --- client/src/components/apps/new.vue | 60 +++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/client/src/components/apps/new.vue b/client/src/components/apps/new.vue index 221f10b8..33aaea5b 100644 --- a/client/src/components/apps/new.vue +++ b/client/src/components/apps/new.vue @@ -49,8 +49,22 @@

Deployment

+ + + + + + + v-if="appDeploymentStrategy == 'git'"> + v-if="appDeploymentStrategy == 'git'"> + v-if="appDeploymentStrategy == 'git'"> + v-if="appDeploymentStrategy == 'docker'"> + v-if="appDeploymentStrategy == 'docker'"> @@ -481,16 +496,14 @@ export default { data: () => ({ valid: false, buildpack: undefined, - /* - buildpackDisabled: true, - buildpackList: [ - "Docker", - "NodeJS", - //"Python", - //"Ruby", - ], - */ - pipelineData: {}, + deploymentstrategyGit: true, + pipelineData: { + git: { + repository: { + ssh_url: "", + } + }, + }, appname: '', resourceVersion: undefined, /* @@ -557,7 +570,7 @@ export default { ], repositoryRules: [ //v => !!v || 'Repository is required', - v => v.length <= 60 || 'Repository must be less than 10 characters', + v => v.length <= 60 || 'Repository must be less than 60 characters', // ((git|ssh|http(s)?)|(git@[\w\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)(/)? v => /((git|ssh|http(s)?)|(git@[\w.]+))(:(\/\/)?)([\w.@:/\-~]+)(\.git)(\/)?/.test(v) || 'Format "owner/repository"', ], @@ -577,6 +590,13 @@ export default { ], */ }), + computed: { + // a computed getter + appDeploymentStrategy() { + // `this` points to the component instance + return this.deploymentstrategyGit ? 'git' : 'docker' + } + }, mounted() { this.loadApp(); this.loadPodsizeList(); @@ -679,13 +699,15 @@ export default { axios.get(`/api/pipelines/${this.pipeline}/${this.phase}/${this.app}`).then(response => { this.resourceVersion = response.data.metadata.resourceVersion; + + this.deploymentstrategyGit = response.data.spec.deploymentstrategy == 'git'; this.appname = response.data.spec.name; this.buildpack = response.data.spec.buildpack; this.gitrepo = response.data.spec.gitrepo; this.branch = response.data.spec.branch; this.imageTag= response.data.spec.imageTag; this.docker.image = response.data.spec.image.repository || ''; - this.docker.tag = response.data.spec.image.tag || 'main'; + this.docker.tag = response.data.spec.image.tag || 'latest'; this.autodeploy = response.data.spec.autodeploy; this.domain = response.data.spec.domain; this.envvars = response.data.spec.envVars; @@ -708,6 +730,7 @@ export default { appname: this.appname, gitrepo: this.pipelineData.git.repository, branch: this.branch, + deploymentstrategy: this.appDeploymentStrategy, image : { containerport: this.containerPort, repository: this.docker.image, @@ -757,6 +780,7 @@ export default { appname: this.appname.toLowerCase(), gitrepo: this.pipelineData.git.repository, branch: this.branch, + deploymentstrategy: this.appDeploymentStrategy, image : { containerport: this.containerPort, repository: this.docker.image, From 0fe2fe56e23bf5f7ca220f07ef375f02c3cbaef6 Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Sat, 3 Dec 2022 00:21:54 +0100 Subject: [PATCH 16/17] add example env vars --- .env.template | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.env.template b/.env.template index 93d9ce83..86443736 100644 --- a/.env.template +++ b/.env.template @@ -4,6 +4,7 @@ KUBERO_WEBHOOK_SECRET=mysecret # Github webhook configuration KUBERO_WEBHOOK_URL=https://kuberoXXXXXXXXXXXXX.loca.lt/api/repo/webhooks + GITHUB_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #GITEA_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -12,6 +13,12 @@ GITHUB_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #GOGS_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #GOGS_BASEURL=http://localhost:3000 +#GITLAB_BASEURL=http://localhost:3080 +#GITLAB_PERSONAL_ACCESS_TOKEN=glpat-XXXXXXXXXXXXXXXXXXXXXX + +BITBUCKET_USERNAME=XXXXXXXXX +BITBUCKET_APP_PASSWORD=ATBXXXXXXXXXXXXXXXXXXXXXXX + KUBECONFIG_PATH=./kubeconfig KUBERO_CONFIG_PATH=./config.yaml KUBERO_CONTEXT=kind-kubero From c4fca661348b2ee701c358d0c5e41f7a91186b21 Mon Sep 17 00:00:00 2001 From: Gianni Carafa Date: Sat, 3 Dec 2022 22:11:46 +0100 Subject: [PATCH 17/17] cleanup env session --- .env.template | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/.env.template b/.env.template index 86443736..371d953e 100644 --- a/.env.template +++ b/.env.template @@ -1,30 +1,37 @@ PORT=2000 -# git deployment key's KUBERO_WEBHOOK_SECRET=mysecret -# Github webhook configuration +# webhook configuration KUBERO_WEBHOOK_URL=https://kuberoXXXXXXXXXXXXX.loca.lt/api/repo/webhooks -GITHUB_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +KUBECONFIG_PATH=./kubeconfig +KUBERO_CONFIG_PATH=./config.yaml +KUBERO_CONTEXT=kind-kubero +KUBERO_NAMESPACE=kubero-dev +KUBERO_SESSION_KEY=randomString +DEBUG=*.* + +########################################## +# git repository configuration +# +#GITHUB_PERSONAL_ACCESS_TOKEN= -#GITEA_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +#GITEA_PERSONAL_ACCESS_TOKEN= #GITEA_BASEURL=http://localhost:3000 -#GOGS_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +#GOGS_PERSONAL_ACCESS_TOKEN= #GOGS_BASEURL=http://localhost:3000 #GITLAB_BASEURL=http://localhost:3080 -#GITLAB_PERSONAL_ACCESS_TOKEN=glpat-XXXXXXXXXXXXXXXXXXXXXX +#GITLAB_PERSONAL_ACCESS_TOKEN=glpat- -BITBUCKET_USERNAME=XXXXXXXXX -BITBUCKET_APP_PASSWORD=ATBXXXXXXXXXXXXXXXXXXXXXXX +#BITBUCKET_USERNAME=XXXXXXXXX +#BITBUCKET_APP_PASSWORD= -KUBECONFIG_PATH=./kubeconfig -KUBERO_CONFIG_PATH=./config.yaml -KUBERO_CONTEXT=kind-kubero -KUBERO_NAMESPACE=kubero-dev -KUBERO_SESSION_KEY=randomString +################################################ +# authentication section +# #GITHUB_CLIENT_SECRET= #GITHUB_CLIENT_ID= #GITHUB_CLIENT_CALLBACKURL=http://kubero.lacolhost.com/api/auth/github/callback @@ -36,5 +43,3 @@ KUBERO_SESSION_KEY=randomString #OAUTH2_CLIENT_ID= #OAUTH2_CLIENT_SECRET= #OAUTH2_CLIENT_CALLBACKURL=http://kubero.lacolhost.com/api/auth/oauth2/callback - -DEBUG=*.* \ No newline at end of file