bump-cli
Version:
The Bump CLI is used to interact with your API documentation hosted on Bump.sh by using the API of developers.bump.sh
161 lines (160 loc) • 5.9 kB
JavaScript
import { Config } from '@oclif/core';
import { CLIError } from '@oclif/core/errors';
import debug from 'debug';
import { resolve } from 'node:path';
import { BumpApi } from '../api/index.js';
import { API } from '../definition.js';
export class Diff {
// 120 seconds = 2 minutes
static TIMEOUT = 120;
_bump;
_config;
constructor(config) {
if (config) {
this._config = config;
}
}
get bumpClient() {
if (!this._bump)
this._bump = new BumpApi(this._config);
return this._bump;
}
get pollingPeriod() {
return process.env.BUMP_POLLING_PERIOD ? Number(process.env.BUMP_POLLING_PERIOD) : 1000;
}
async createDiff(file1, file2, expires, overlays) {
const api = await API.load(file1);
const [previous_definition, previous_references] = await api.extractDefinition(undefined, overlays);
const api2 = await API.load(file2);
const [definition, references] = await api2.extractDefinition(undefined, overlays);
const request = {
definition,
expires_at: expires,
previous_definition,
previous_references,
references,
};
const response = await this.bumpClient.postDiff(request);
switch (response.status) {
case 201: {
this.d(`Diff created with ID ${response.data.id}`);
this.d(response.data);
return response.data;
break;
}
case 204: {
break;
}
}
}
async createVersion(file, documentation, token, hub, branch_name, previous_version_id = undefined, overlays) {
const api = await API.load(file);
const [definition, references] = await api.extractDefinition(undefined, overlays);
const request = {
branch_name,
definition,
documentation,
hub,
previous_version_id,
references,
unpublished: true,
};
const response = await this.bumpClient.postVersion(request, token);
switch (response.status) {
case 201: {
this.d(`Unpublished version created with ID ${response.data.id}`);
return response.data;
break;
}
case 204: {
break;
}
}
}
// Function signature type taken from @types/debug
// Debugger(formatter: any, ...args: any[]): void;
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
d(formatter, ...args) {
return debug(`bump-cli:core:diff`)(formatter, ...args);
}
extractDiff(versionWithDiff) {
// TODO: return a real diff_id in the GET /version API
return {
breaking: versionWithDiff.diff_breaking,
details: versionWithDiff.diff_details,
id: versionWithDiff.id,
markdown: versionWithDiff.diff_markdown,
public_url: versionWithDiff.diff_public_url,
text: versionWithDiff.diff_summary,
};
}
isVersion(result) {
return result.doc_public_url !== undefined;
}
isVersionWithDiff(result) {
const { diff_details, diff_markdown, diff_summary } = result;
return (diff_summary || diff_markdown || diff_details) !== undefined;
}
async pollingDelay() {
await this.delay(this.pollingPeriod);
}
async run(file1, file2, documentation, hub, branch, token, format, expires, overlays) {
if (!this._config)
this._config = await Config.load(resolve(import.meta.dirname, './../../'));
let diffVersion;
if (file2 && (!documentation || !token)) {
diffVersion = await this.createDiff(file1, file2, expires, overlays);
}
else {
if (!documentation || !token) {
throw new Error('Please login to bump (with documentation & token) when using a single file argument');
}
diffVersion = await this.createVersion(file1, documentation, token, hub, branch, undefined, overlays);
if (file2) {
diffVersion = await this.createVersion(file2, documentation, token, hub, branch, diffVersion && diffVersion.id, overlays);
}
}
if (diffVersion) {
return this.waitResult(diffVersion, token, {
format,
timeout: Diff.TIMEOUT,
});
}
return undefined;
}
async waitResult(result, token, opts) {
const pollingResponse = await (this.isVersion(result) && token
? this.bumpClient.getVersion(result.id, token)
: this.bumpClient.getDiff(result.id, opts.format));
if (opts.timeout <= 0) {
throw new CLIError('We were unable to compute your documentation diff. Sorry about that. Please try again later. If the error persists, please contact support at https://bump.sh.');
}
switch (pollingResponse.status) {
case 200: {
let diff = pollingResponse.data;
if (this.isVersionWithDiff(diff)) {
diff = this.extractDiff(diff);
}
this.d('Received diff:');
this.d(diff);
return diff;
break;
}
case 202: {
this.d('Waiting 1 sec before next poll');
await this.pollingDelay();
return this.waitResult(result, token, {
format: opts.format,
timeout: opts.timeout - 1,
});
break;
}
}
return {};
}
async delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
}