diff --git a/.env.template b/.env.template index 7395d162..371d953e 100644 --- a/.env.template +++ b/.env.template @@ -1,20 +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 - -#GITEA_PERSONAL_ACCESS_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -#GITEA_BASEURL=http://localhost:3000 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= +#GITEA_BASEURL=http://localhost:3000 +#GOGS_PERSONAL_ACCESS_TOKEN= +#GOGS_BASEURL=http://localhost:3000 + +#GITLAB_BASEURL=http://localhost:3080 +#GITLAB_PERSONAL_ACCESS_TOKEN=glpat- + +#BITBUCKET_USERNAME=XXXXXXXXX +#BITBUCKET_APP_PASSWORD= + + +################################################ +# authentication section +# #GITHUB_CLIENT_SECRET= #GITHUB_CLIENT_ID= #GITHUB_CLIENT_CALLBACKURL=http://kubero.lacolhost.com/api/auth/github/callback @@ -26,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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3aaa149c..afc15790 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,9 @@ # 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. + +Want to contribute, but dont know where to start? Have a look into the Roadmap. ## Development setup ### Requirements diff --git a/README.md b/README.md index 7dff2a83..37717f39 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@

-![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 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. It enables you to deploy your applications within some clicks. It also provides a dashboard and CLI to manage your applications.
-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.

-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,8 @@ 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 + ## 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. @@ -47,26 +46,39 @@ So far tested languages/frameworks: - Rust (including Rocket) - ... +## Preconfigured Buildpacks 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 more Screenshots

-# Usage +## 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 +## Documentation https://github.com/kubero-dev/kubero/wiki -## Stargazers over time +## Roadmap +https://github.com/orgs/kubero-dev/projects/1/views/3 + +## 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 diff --git a/client/src/components/apps/new.vue b/client/src/components/apps/new.vue index 0e86110a..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'"> @@ -484,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, /* @@ -507,6 +517,7 @@ export default { ssh_url: 'git@github.com:kubero-dev/template-nodeapp.git', }, branch: 'main', + branchesList: [], docker: { image: 'ghcr.io/kubero-dev/template-nodeapp', tag: 'main', @@ -559,15 +570,10 @@ 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"', ], - 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', @@ -584,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(); @@ -605,6 +618,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 +638,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++) { @@ -667,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; @@ -696,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, @@ -745,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, diff --git a/client/src/components/pipelines/new.vue b/client/src/components/pipelines/new.vue index 54a2e2a2..cca34b31 100644 --- a/client/src/components/pipelines/new.vue +++ b/client/src/components/pipelines/new.vue @@ -30,13 +30,13 @@ cols="12" md="8" > - + Github mdi-github Gitea Gitlab mdi-gitlab - oneDev - Gogs - Bitbucket mdi-bitbucket + + Gogs + Bitbucket mdi-bitbucket @@ -188,6 +188,7 @@ export default { keys: {}, repository: {}, webhooks: {}, + provider: "" }, repository_status: { error: false, @@ -236,12 +237,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"', ], @@ -288,37 +289,43 @@ 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; break; case 'gitea': - this.connectGitea(); + 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 'gitlab': - this.connectGitlab(); - return; - /* - this.repositoriesList.gitea = false; + 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; break; - */ - case 'bitbucket': - this.connectBitbucket(); + case 'gitlab': + this.connectRepository('gitlab') + this.repositoriesList.github = false; + this.repositoriesList.gitea = false; + this.repositoriesList.gogs = false; + this.repositoriesList.bitbucket = false; + this.repositoriesList.docker = false; 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; } @@ -373,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/docker-compose.yaml b/docker-compose.yaml index c8257ba9..7612da7c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -27,4 +27,37 @@ 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' + + 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/docs/screenshots/gitrepositories.png b/docs/screenshots/gitrepositories.png new file mode 100644 index 00000000..2f0bdc8e Binary files /dev/null and b/docs/screenshots/gitrepositories.png differ diff --git a/package.json b/package.json index d3493df0..0d1efedd 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,11 @@ }, "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", + "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..424dde9a --- /dev/null +++ b/src/git/bitbucket.ts @@ -0,0 +1,310 @@ +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; + } + + 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 ab741fe2..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, } @@ -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) } @@ -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 a3013bbb..299b7f17 100644 --- a/src/git/gitlab.ts +++ b/src/git/gitlab.ts @@ -1,2 +1,335 @@ // 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 { 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"); + + console.log("Gitlab API: "+baseURL) + console.log("Gitlab token: "+token) + + this.gitlab = new GitlabClient({ + token: token, + host: baseURL || 'https://gitlab.com', + }); + } + + 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, token: string, body: any): IWebhook | boolean { + let secret = process.env.KUBERO_WEBHOOK_SECRET as string; + + let verified = false; + if (secret === token) { + debug.debug('Gitlab webhook signature is valid for event: '+delivery); + verified = true; + } else { + 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; + if (body.ref != undefined) { + let ref = body.ref + let refs = ref.split('/') + branch = refs[refs.length - 1] + 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.project.git_ssh_url + } + + try { + let webhook: IWebhook = { + repoprovider: 'gitlab', + action: action, + event: github_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', { membership: true }) + .catch((error: any) => { + console.log(error) + return ret; + }) + + for (let repo of repos) { + ret.push(repo.ssh_url_to_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 new file mode 100644 index 00000000..b338d5a2 --- /dev/null +++ b/src/git/gogs.ts @@ -0,0 +1,294 @@ +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 { + 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; + } + + 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/git/types.ts b/src/git/types.ts index d2a86d58..85a59197 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, @@ -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 9d06385f..dfb01d03 100644 --- a/src/kubero.ts +++ b/src/kubero.ts @@ -3,7 +3,10 @@ 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'; import { IWebhook} from './git/types'; import YAML from 'yaml'; import * as fs from 'fs'; @@ -21,6 +24,9 @@ export class Kubero { private _io: Server; private githubApi: GithubApi; private giteaApi: GiteaApi; + private gogsApi: GogsApi; + private gitlabApi: GitlabApi; + private bitbucketApi: BitbucketApi; private appStateList: IApp[] = []; private pipelineStateList: IPipeline[] = []; private podLogStreams: string[]= [] @@ -32,7 +38,10 @@ 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); + 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)); } @@ -292,6 +301,13 @@ 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 'bitbucket': + return this.bitbucketApi.listRepos(); + case 'ondev': default: return {'error': 'unknown repo provider'}; } @@ -305,6 +321,13 @@ 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 'bitbucket': + return this.bitbucketApi.connectRepo(repoAddress); + case 'ondev': default: return {'error': 'unknown repo provider'}; } @@ -317,11 +340,19 @@ 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 'gogs': + webhook = this.gogsApi.getWebhook(event, delivery, signature, body); + break; + case 'gitlab': + webhook = this.gitlabApi.getWebhook(event, delivery, signature, body); + break; + case 'bitbucket': + webhook = this.bitbucketApi.getWebhook(event, delivery, body); // Bitbucket has no signature + break; + case 'ondev': default: break; } @@ -367,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[] = []; @@ -564,6 +627,8 @@ export class Kubero { github: false, gitea: false, gitlab: false, + gogs: false, + onedev: false, bitbucket: false, docker: true } @@ -580,7 +645,15 @@ export class Kubero { repositories.gitlab = true; } - if (process.env.BITBUCKET_PERSONAL_ACCESS_TOKEN) { + if (process.env.GOGS_PERSONAL_ACCESS_TOKEN) { + repositories.gogs = true; + } + + if (process.env.ONEDEV_PERSONAL_ACCESS_TOKEN) { + repositories.onedev = true; + } + + 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 cb386b18..4ac7b92f 100644 --- a/src/routes/repo.ts +++ b/src/routes/repo.ts @@ -19,8 +19,14 @@ 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.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){ @@ -38,19 +44,35 @@ Router.post('/repo/webhooks/:repoprovider', async function (req: Request, res: R //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": - //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 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); - ret = "bitbucket not supported yet"; + 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 75e40755..032790ab 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" @@ -203,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" @@ -337,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" @@ -373,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" @@ -395,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" @@ -487,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== @@ -503,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" "*" @@ -604,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" @@ -690,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== @@ -700,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" @@ -866,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" @@ -1068,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" @@ -1325,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" @@ -1348,7 +1366,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== @@ -1650,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" @@ -1664,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" @@ -1779,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" @@ -1819,7 +1844,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== @@ -2326,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" @@ -2337,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== @@ -2346,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" @@ -2466,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" @@ -2551,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" @@ -2576,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" @@ -2631,6 +2656,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" @@ -2726,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" @@ -2742,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"