UNPKG

@topgroup/diginext

Version:

A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.

370 lines (369 loc) 16.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.listRepoBranches = exports.deleteGitRepository = void 0; const axios_1 = __importDefault(require("axios")); const log_1 = require("diginext-utils/dist/xconsole/log"); const lodash_1 = require("lodash"); const interfaces_1 = require("../../interfaces"); const slug_1 = require("../../plugins/slug"); const githubApiBaseURL = "https://api.github.com"; const bitbucketApiBaseURL = "https://api.bitbucket.org/2.0"; const userApiPath = (provider, org) => (provider === "bitbucket" ? "/user" : provider === "github" ? "/user" : undefined); const userOrgApiPath = (provider, org) => provider === "bitbucket" ? "/workspaces" : provider === "github" ? "/user/orgs" : undefined; const repoApiPath = (provider, org, slug) => provider === "bitbucket" ? `/repositories/${org}${slug ? `/${slug}` : ""}` : provider === "github" ? `/repos/${org}/${slug}` : undefined; const userRepoApiPath = (provider, username, slug) => provider === "bitbucket" ? `/repositories/${username}${slug ? `/${slug}` : ""}` : provider === "github" ? `/user${username ? `/${username}` : ""}/repos` : undefined; const orgRepoApiPath = (provider, org, slug) => provider === "bitbucket" ? `/repositories/${org}${slug ? `/${slug}` : ""}` : provider === "github" ? `/orgs/${org}/repos` : undefined; const repoDeleteApiPath = (provider, org, slug) => provider === "bitbucket" ? `/repositories/${org}/${slug}` : `/repos/${org}/${slug}`; const repoBranchApiPath = (provider, org, slug) => provider === "bitbucket" ? `/repositories/${org}/${slug}/refs/branches` : `/repos/${org}/${slug}/branches`; /** * Only applicable for Bitbucket */ const orgProjectApiPath = (provider) => `/workspaces/${provider.org}/projects/DXP`; const bitbucketRefeshToken = async (provider) => { const { refresh_token, bitbucket_oauth: options } = provider; const digested = Buffer.from(`${options.consumer_key}:${options.consumer_secret}`, "utf8").toString("base64"); const bitbucketTokenRes = await (0, axios_1.default)({ url: "https://bitbucket.org/site/oauth2/access_token", method: "POST", headers: { Authorization: `Basic ${digested}`, "Cache-Control": "no-cache", "Content-Type": "application/json", Accept: "application/json", }, data: JSON.stringify({ grant_type: "refresh_token", refresh_token: refresh_token, }), }); const data = bitbucketTokenRes.data; if (data.error) throw new Error(`[BITBUCKET_API_ERROR] Refresh token was expired, can't refresh the access token.`); return { access_token: data.access_token, refresh_token: data.refresh_token, }; }; const api = async (provider, path, options) => { var _a, _b; if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("Git Provider API > provider :>> ", provider); const { DB } = await Promise.resolve().then(() => __importStar(require("../api/DB"))); const { method = "GET", data, headers = {} } = options || {}; const baseURL = provider.type === "github" ? githubApiBaseURL : bitbucketApiBaseURL; const func = `[${provider.type.toUpperCase()}_API_ERROR]`; if (provider.type === "github") headers.Accept = "application/vnd.github+json"; if (provider.type === "bitbucket") headers.Accept = "application/json"; headers.Authorization = `${(0, lodash_1.upperFirst)(provider.method)} ${provider.access_token}`; if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log("Git Provider API > headers :>> ", headers); const url = `${baseURL}${path}`; if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log(`Git Provider API > [${method}] :>> `, url); if (options === null || options === void 0 ? void 0 : options.isDebugging) console.log(`Git Provider API > data :>> `, data); try { const response = await (0, axios_1.default)({ url, headers, method, data }); // if (options?.isDebugging) console.log("Git Provider API > response :>> ", response); const resData = response.data; // catch errors if (provider.type === "bitbucket" && resData.error) throw new Error(`${func} "${path}" > ${resData.error.message}`); if (provider.type === "github" && resData.message) throw new Error(`${func} "${path}" > ${resData.message}`); // [BITBUCKET ONLY] if access_token is expired -> try to refresh it: if (provider.type === "bitbucket" && ((_b = (_a = resData.error) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.indexOf("expired")) > -1) { const tokens = await bitbucketRefeshToken(provider); // save new tokens to database const updatedProvider = await DB.updateOne("git", { _id: provider._id }, tokens, options); if (!updatedProvider) throw new Error(`[${provider.type.toUpperCase()}_API_ERROR] "${path}" > Can't update tokens to "${provider.name}" git provider.`); // fetch api again return api(updatedProvider, path, options); } // [DELETE ONLY] translate HTTP response if (method === "DELETE") return response.status === 204 ? (0, interfaces_1.respondSuccess)({ data: true }) : (0, interfaces_1.respondFailure)(response.status === 403 ? "Unauthorized." : "404 Not found."); return resData; } catch (e) { console.log(url); throw new Error(e); } }; const getProfile = async (provider, options) => { if (provider.type === "bitbucket") { const profile = (await api(provider, userApiPath(provider.type), options)); return { id: profile.uuid, username: profile.username, display_name: profile.display_name, url: profile.links.html.href, // no email for bitbucket user? }; } else if (provider.type === "github") { const profile = (await api(provider, userApiPath(provider.type), options)); return { id: profile.id.toString(), username: profile.login, display_name: profile.name, url: profile.html_url, email: profile.email, }; } else { throw new Error(`Git provider "${provider.type}" is not supported yet.`); } }; const listOrgs = async (provider) => { if (provider.type === "bitbucket") { const bitbucketOrgsRes = (await api(provider, userOrgApiPath(provider.type))); // console.log("bitbucketOrgsRes :>> ", bitbucketOrgsRes); return bitbucketOrgsRes.values.map((org) => { return { id: org.uuid, name: org.slug, description: "", url: org.links.html.href, is_org: true, }; }); } if (provider.type === "github") { const githubOrgs = (await api(provider, userOrgApiPath(provider.type))); const profile = await getProfile(provider); const orgList = githubOrgs.map((org) => { return { id: org.id.toString(), name: org.login, description: org.description, url: org.url, is_org: true, }; }); // push personal git provider orgList.push({ id: profile.id, name: profile.username, description: `Personal Github account.`, url: profile.url, is_org: false, }); return orgList; } throw new Error(`Git provider "${provider.type}" is not supported yet.`); }; const createGitRepository = async (provider, data, options) => { // validation if (!data.name) data.name = (0, slug_1.makeSlug)(data.name).toLocaleLowerCase(); // process if (provider.type === "bitbucket") { // check if "Diginext" project existed const bitbucketProjectRes = (await api(provider, orgProjectApiPath(provider))); let dxProject; if (bitbucketProjectRes.error) { (0, log_1.logWarn)(`[BITBUCKET_API_ERROR] ${bitbucketProjectRes.error.message}`); } else { dxProject = bitbucketProjectRes; } // if not, create "Diginext" project if (!dxProject) { const projectData = { name: "Diginext", key: "DXP", description: "Contains all repositories that created by Diginext platform.", is_private: true, }; const dxProjectRes = (await api(provider, orgProjectApiPath(provider), { data: projectData, method: "POST", })); if (dxProjectRes.error) throw new Error(`[BITBUCKET_API_ERROR] ${bitbucketProjectRes.error.message}`); dxProject = dxProjectRes; } // console.log("dxProject :>> ", dxProject); // create new repository const newBitbucketRepo = (await api(provider, orgRepoApiPath(provider.type, provider.org, data.name), { data: { name: data.name, description: data.description, is_private: data.private, scm: "git", // assign "DXP" project to new repository: project: { key: dxProject.key }, }, method: "POST", })); // console.log("newBitbucketRepo :>> ", newBitbucketRepo); return { provider: provider.type, id: newBitbucketRepo.uuid, name: newBitbucketRepo.name, full_name: newBitbucketRepo.full_name, description: newBitbucketRepo.description, private: newBitbucketRepo.is_private, repo_url: newBitbucketRepo.links.html.href, ssh_url: newBitbucketRepo.links.clone.find((link) => link.name === "ssh").href, created_at: newBitbucketRepo.created_on, updated_at: newBitbucketRepo.updated_on, fork: newBitbucketRepo.fork_policy !== "no_public_forks", owner: { id: newBitbucketRepo.owner.uuid, username: newBitbucketRepo.owner.username, url: newBitbucketRepo.owner.links.html.href, type: newBitbucketRepo.owner.type, }, }; } if (provider.type === "github") { const url = provider.isOrg ? orgRepoApiPath(provider.type, provider.org) : userRepoApiPath(provider.type); const newGithubRepo = (await api(provider, url, { data: { ...data, has_issues: true, has_wiki: true, }, method: "POST", isDebugging: options === null || options === void 0 ? void 0 : options.isDebugging, })); if (newGithubRepo.message) throw new Error(`[GITHUB_API_ERROR] ${newGithubRepo.message}`); return { provider: provider.type, id: newGithubRepo.id.toString(), name: newGithubRepo.name, full_name: newGithubRepo.full_name, description: newGithubRepo.description, private: newGithubRepo.private, repo_url: newGithubRepo.html_url, ssh_url: newGithubRepo.ssh_url, created_at: newGithubRepo.created_at, updated_at: newGithubRepo.updated_at, fork: newGithubRepo.fork, owner: { id: newGithubRepo.owner.id.toString(), username: newGithubRepo.owner.login, url: newGithubRepo.owner.url, type: newGithubRepo.owner.type, }, }; } throw new Error(`Git provider "${provider.type}" is not supported yet.`); }; const listGitRepositories = async (provider, options) => { if (provider.type === "bitbucket") { const { values: bitbucketRepos } = (await api(provider, orgRepoApiPath(provider.type, provider.org))); return bitbucketRepos.map((repo) => { return { id: repo.uuid, name: repo.name, full_name: repo.full_name, description: repo.description, private: repo.is_private, repo_url: repo.links.html.href, ssh_url: repo.links.clone.find((link) => link.name === "ssh").href, created_at: repo.created_on, updated_at: repo.updated_on, fork: repo.fork_policy !== "no_public_forks", owner: { id: repo.owner.uuid, username: repo.owner.username, url: repo.owner.links.html.href, type: repo.owner.type, }, }; }); } if (provider.type === "github") { const apiUrl = provider.isOrg ? orgRepoApiPath(provider.type, provider.org) : userRepoApiPath(provider.type, provider.org); // console.log("apiUrl :>> ", apiUrl); const githubRepos = (await api(provider, apiUrl)); // console.log("githubRepos :>> ", githubRepos); return githubRepos.map((repo) => { return { id: repo.id.toString(), name: repo.name, full_name: repo.full_name, description: repo.description, private: repo.private, repo_url: repo.html_url, ssh_url: repo.ssh_url, created_at: repo.created_at, updated_at: repo.updated_at, fork: repo.fork, owner: { id: repo.owner.id.toString(), username: repo.owner.login, url: repo.owner.url, type: repo.owner.type, }, }; }); } throw new Error(`Git provider "${provider.type}" is not supported yet.`); }; const deleteGitRepository = async (provider, org, slug, options) => { const apiPath = repoDeleteApiPath(provider.type, org, slug); const res = await api(provider, apiPath, { method: "DELETE" }); return res; }; exports.deleteGitRepository = deleteGitRepository; const listRepoBranches = async (provider, org, slug, options) => { const apiPath = repoBranchApiPath(provider.type, org, slug); const res = await api(provider, apiPath); if (provider.type === "bitbucket") { return res.values.map((branch) => ({ name: branch.name, url: branch.links.html.href })); } if (provider.type === "github") { return res.map((branch) => ({ name: branch.name, url: `https://github.com/${org}/${slug}/tree/${branch.name}` })); } throw new Error(`Git provider "${provider.type}" is not supported.`); }; exports.listRepoBranches = listRepoBranches; const GitProviderAPI = { getProfile, listOrgs, listGitRepositories, createGitRepository, deleteGitRepository: exports.deleteGitRepository, listRepoBranches: exports.listRepoBranches, }; exports.default = GitProviderAPI;