heroku
Version:
CLI to interact with Heroku
184 lines (183 loc) • 8.54 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const color_1 = require("@heroku-cli/color");
const core_1 = require("@oclif/core");
const heroku_cli_util_1 = require("@heroku/heroku-cli-util");
const util_1 = require("@oclif/core/lib/util");
const date_fns_1 = require("date-fns");
const http_call_1 = require("@heroku/http-call");
const util_2 = require("../lib/status/util");
const errorMessage = 'Heroku platform status is unavailable at this time. Refer to https://status.salesforce.com/products/Heroku or try again later.';
const printStatus = (status) => {
const colorize = color_1.default[status];
let message = (0, util_1.capitalize)(status);
if (status === 'green') {
message = 'No known issues at this time.';
}
return colorize(message);
};
const getTrustStatus = async () => {
const trustHost = process.env.SF_TRUST_STAGING ? 'https://status-api-stg.test.edgekey.net/v1' : 'https://api.status.salesforce.com/v1';
const currentDateTime = new Date(Date.now()).toISOString();
let instances = [];
let activeIncidents = [];
let maintenances = [];
let localizations = [];
try {
const [instanceResponse, activeIncidentsResponse, maintenancesResponse, localizationsResponse] = await Promise.all([
http_call_1.default.get(`${trustHost}/instances?products=Heroku`),
http_call_1.default.get(`${trustHost}/incidents/active`),
http_call_1.default.get(`${trustHost}/maintenances?startTime=${currentDateTime}&limit=10&offset=0&product=Heroku&locale=en`),
http_call_1.default.get(`${trustHost}/localizations?locale=en`),
]);
instances = instanceResponse.body;
activeIncidents = activeIncidentsResponse.body;
maintenances = maintenancesResponse.body;
localizations = localizationsResponse.body;
}
catch (_a) {
core_1.ux.error(errorMessage, { exit: 1 });
}
return formatTrustResponse(instances, activeIncidents, maintenances, localizations);
};
const determineIncidentSeverity = (incidents) => {
const severityArray = [];
incidents.forEach(incident => {
incident.IncidentImpacts.forEach(impact => {
if (!impact.endTime && impact.severity) {
severityArray.push(impact.severity);
}
});
});
if (severityArray.includes('major'))
return 'red';
if (severityArray.includes('minor'))
return 'yellow';
return 'green';
};
const formatTrustResponse = (instances, activeIncidents, maintenances, localizations) => {
const systemStatus = [];
const incidents = [];
const scheduled = [];
const instanceKeyArray = new Set(instances.map(instance => instance.key));
const herokuActiveIncidents = activeIncidents.filter(incident => {
return incident.instanceKeys.some(key => instanceKeyArray.has(key));
});
const toolsIncidents = herokuActiveIncidents.filter(incident => {
const tools = ['TOOLS', 'Tools', 'CLI', 'Dashboard', 'Platform API'];
return tools.some(tool => incident.serviceKeys.includes(tool));
});
const appsIncidents = herokuActiveIncidents.filter(incident => {
return incident.serviceKeys.includes('HerokuApps') || incident.serviceKeys.includes('Apps');
});
const dataIncidents = herokuActiveIncidents.filter(incident => {
return incident.serviceKeys.includes('HerokuData') || incident.serviceKeys.includes('Data');
});
if (appsIncidents.length > 0) {
const severity = determineIncidentSeverity(appsIncidents);
systemStatus.push({ system: 'Apps', status: severity });
incidents.push(...appsIncidents);
}
else {
systemStatus.push({ system: 'Apps', status: 'green' });
}
if (dataIncidents.length > 0) {
const severity = determineIncidentSeverity(dataIncidents);
systemStatus.push({ system: 'Data', status: severity });
incidents.push(...dataIncidents);
}
else {
systemStatus.push({ system: 'Data', status: 'green' });
}
if (toolsIncidents.length > 0) {
const severity = determineIncidentSeverity(toolsIncidents);
systemStatus.push({ system: 'Tools', status: severity });
incidents.push(...toolsIncidents);
}
else {
systemStatus.push({ system: 'Tools', status: 'green' });
}
if (maintenances.length > 0)
scheduled.push(...maintenances);
if (incidents.length > 0) {
incidents.forEach(incident => {
incident.IncidentEvents.forEach(event => {
var _a;
event.localizedType = (_a = localizations.find((l) => l.modelKey === event.type)) === null || _a === void 0 ? void 0 : _a.text;
});
});
}
return {
status: systemStatus,
incidents,
scheduled,
};
};
class Status extends core_1.Command {
async run() {
var _a;
const { flags } = await this.parse(Status);
const herokuApiPath = '/api/v4/current-status';
let herokuStatus;
let formattedTrustStatus;
if (process.env.TRUST_ONLY) {
formattedTrustStatus = await getTrustStatus();
}
else {
try {
// Try calling the Heroku status API first
const herokuHost = process.env.HEROKU_STATUS_HOST || 'https://status.heroku.com';
const herokuStatusResponse = await http_call_1.default.get(herokuHost + herokuApiPath);
herokuStatus = herokuStatusResponse.body;
}
catch (_b) {
// If the Heroku status API call fails, call the SF Trust API
formattedTrustStatus = await getTrustStatus();
}
}
if (!herokuStatus && !formattedTrustStatus)
core_1.ux.error(errorMessage, { exit: 1 });
if (flags.json) {
heroku_cli_util_1.hux.styledJSON(herokuStatus !== null && herokuStatus !== void 0 ? herokuStatus : formattedTrustStatus);
return;
}
const systemStatus = herokuStatus ? herokuStatus.status : formattedTrustStatus === null || formattedTrustStatus === void 0 ? void 0 : formattedTrustStatus.status;
if (systemStatus) {
for (const item of systemStatus) {
const message = printStatus(item.status);
this.log(`${(item.system + ':').padEnd(11)}${message}`);
}
}
else {
core_1.ux.error(errorMessage, { exit: 1 });
}
if (herokuStatus) {
for (const incident of herokuStatus.incidents) {
core_1.ux.log();
heroku_cli_util_1.hux.styledHeader(`${incident.title} ${color_1.default.yellow(incident.created_at)} ${color_1.default.cyan(incident.full_url)}`);
const padding = (0, util_2.getMaxUpdateTypeLength)(incident.updates.map(update => update.update_type));
for (const u of incident.updates) {
core_1.ux.log(`${color_1.default.yellow(u.update_type.padEnd(padding))} ${new Date(u.updated_at).toISOString()} (${(0, date_fns_1.formatDistanceToNow)(new Date(u.updated_at))} ago)`);
core_1.ux.log(`${u.contents}\n`);
}
}
}
else if (formattedTrustStatus) {
for (const incident of formattedTrustStatus.incidents) {
core_1.ux.log();
heroku_cli_util_1.hux.styledHeader(`${incident.id} ${color_1.default.yellow(incident.createdAt)} ${color_1.default.cyan(`https://status.salesforce.com/incidents/${incident.id}`)}`);
const padding = (0, util_2.getMaxUpdateTypeLength)(incident.IncidentEvents.map(event => { var _a; return (_a = event.localizedType) !== null && _a !== void 0 ? _a : event.type; }));
for (const event of incident.IncidentEvents) {
const eventType = (_a = event.localizedType) !== null && _a !== void 0 ? _a : event.type;
core_1.ux.log(`${color_1.default.yellow(eventType.padEnd(padding))} ${new Date(event.createdAt).toISOString()} (${(0, date_fns_1.formatDistanceToNow)(new Date(event.createdAt))} ago)`);
core_1.ux.log(`${event.message}\n`);
}
}
}
}
}
exports.default = Status;
Status.description = 'display current status of the Heroku platform';
Status.flags = {
json: core_1.Flags.boolean({ description: 'output in json format' }),
};
;