@contentstack/cli-cm-seed
Version:
create a Stack from existing content types, entries, assets, etc.
141 lines (140 loc) • 5.17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tar = require("tar");
const zlib = require("zlib");
const https = require("https");
const mkdirp = require("mkdirp");
const cli_utilities_1 = require("@contentstack/cli-utilities");
const error_1 = require("./error");
class GitHubClient {
static parsePath(path) {
const result = {
username: '',
repo: '',
};
if (path) {
const parts = path.split('/');
result.username = parts[0];
if (parts.length === 2) {
result.repo = parts[1];
}
}
return result;
}
constructor(username, defaultStackPattern) {
this.username = username;
this.gitHubRepoUrl = `https://api.github.com/repos/${username}`;
this.gitHubUserUrl = `https://api.github.com/search/repositories?q=org%3A${username}+in:name+${defaultStackPattern}`;
this.httpClient = cli_utilities_1.HttpClient.create();
}
async getAllRepos(count = 100) {
try {
const response = await this.httpClient.get(`${this.gitHubUserUrl}&per_page=${count}`);
return response.data.items;
}
catch (error) {
throw this.buildError(error);
}
}
async getLatest(repo, destination) {
const tarballUrl = await this.getLatestTarballUrl(repo);
const releaseStream = await this.streamRelease(tarballUrl);
await mkdirp(destination);
return this.extract(destination, releaseStream);
}
makeHeadApiCall(repo) {
return new Promise((resolve, reject) => {
const { host, pathname } = new URL(this.gitHubRepoUrl);
const options = {
host,
method: 'HEAD',
path: `${pathname}/${repo}/contents`,
headers: { 'user-agent': 'node.js' },
};
https.request(options, resolve).on('error', reject).end();
});
}
makeGetApiCall(repo) {
return new Promise((resolve, reject) => {
const { host, pathname } = new URL(this.gitHubRepoUrl);
const options = {
host,
method: 'GET',
path: `${pathname}/${repo}/contents`,
headers: { 'user-agent': 'node.js' },
};
https.request(options, (response) => {
let responseBody = '';
const data = { statusCode: response.statusCode, };
if (data.statusCode === 403) {
const xRateLimitReset = response.rawHeaders[response.rawHeaders.indexOf('X-RateLimit-Reset') + 1];
const startDate = (new Date()).getTime() / 1000;
const diffInSeconds = Number(xRateLimitReset) - startDate;
data.statusMessage = `Exceeded requests limit. Please try again after ${(diffInSeconds / 60).toFixed(1)} minutes.`;
}
response.on('data', (chunk) => {
responseBody += chunk.toString();
});
response.on('end', () => {
const body = JSON.parse(responseBody);
resolve(Object.assign(Object.assign({}, data), { data: body }));
});
}).on('error', reject).end();
});
}
async checkIfRepoExists(repo) {
try {
/**
* Old code. Keeping it for reference.
*
* `const response: any = await this.httpClient.send('HEAD', `${this.gitHubRepoUrl}/${repo}/contents`);`
*
* `return response.status === 200;`
*/
const response = await this.makeHeadApiCall(repo);
return response.statusCode === 200;
}
catch (error) {
console.log(error);
// do nothing
}
return false;
}
async getLatestTarballUrl(repo) {
try {
const response = await this.httpClient.get(`${this.gitHubRepoUrl}/${repo}/releases/latest`);
return response.data.tarball_url;
}
catch (error) {
throw this.buildError(error);
}
}
async streamRelease(url) {
const response = await this.httpClient
.options({
responseType: 'stream',
})
.get(url);
this.httpClient.resetConfig();
return response.data;
}
async extract(destination, stream) {
return new Promise((resolve, reject) => {
stream
.pipe(zlib.createUnzip())
.pipe(tar.extract({
cwd: destination,
strip: 1,
}))
.on('end', () => resolve())
.on('error', reject);
});
}
buildError(error) {
var _a;
const message = ((_a = error.response.data) === null || _a === void 0 ? void 0 : _a.error_message) || error.response.statusText;
const status = error.response.status;
return new error_1.default(message, status);
}
}
exports.default = GitHubClient;