@topgroup/diginext
Version:
A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.
370 lines (369 loc) • 16.5 kB
JavaScript
;
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;