@knapsack-pro/core
Version:
Knapsack Pro Core library splits tests across CI nodes and makes sure that tests will run in optimal time on each CI node. This library gives core features like communication with KnapsackPro.com API. This library is a dependency for other projects specif
242 lines (241 loc) • 10.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 () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ciProvider = exports.commitAuthors = exports.isShallowRepository = exports.buildAuthor = exports.KnapsackProEnvConfig = void 0;
const child_process_1 = require("child_process");
const _1 = require(".");
const knapsack_pro_logger_1 = require("../knapsack-pro-logger");
const Urls = __importStar(require("../urls"));
function logLevel() {
if (process.env.KNAPSACK_PRO_LOG_LEVEL) {
return process.env.KNAPSACK_PRO_LOG_LEVEL;
}
return 'info';
}
const knapsackProLogger = new knapsack_pro_logger_1.KnapsackProLogger(logLevel());
const mask = (string) => {
const regexp = /(?<=\w{2})[a-zA-Z]/g;
const maskingChar = '*';
return string.replace(regexp, maskingChar);
};
class KnapsackProEnvConfig {
static $fixedQueueSplit;
static $knapsackProLogger = knapsackProLogger;
static get endpoint() {
if (process.env.KNAPSACK_PRO_ENDPOINT) {
return process.env.KNAPSACK_PRO_ENDPOINT;
}
return 'https://api.knapsackpro.com';
}
static get testSuiteToken() {
if (process.env.KNAPSACK_PRO_TEST_SUITE_TOKEN) {
return process.env.KNAPSACK_PRO_TEST_SUITE_TOKEN;
}
throw new Error(`Please set test suite API token in CI environment variables.
Please check README for the Knapsack Pro client library.`);
}
static get fixedQueueSplit() {
if (this.$fixedQueueSplit !== undefined) {
return this.$fixedQueueSplit;
}
const envValue = this.envFor('KNAPSACK_PRO_FIXED_QUEUE_SPLIT', 'fixedQueueSplit');
this.$fixedQueueSplit = this.parseBoolean(envValue, 'KNAPSACK_PRO_FIXED_QUEUE_SPLIT');
if (!('KNAPSACK_PRO_FIXED_QUEUE_SPLIT' in process.env)) {
this.$knapsackProLogger.info(`KNAPSACK_PRO_FIXED_QUEUE_SPLIT is not set. Using default value: ${this.$fixedQueueSplit}. Learn more at ${Urls.FIXED_QUEUE_SPLIT}`);
}
return this.$fixedQueueSplit;
}
static parseBoolean(value, name) {
if (typeof value === 'boolean') {
return value;
}
switch (value.toLowerCase()) {
case 'true':
return true;
case 'false':
return false;
default:
throw new Error(`'${value}' is not a valid value for ${name}. Use either 'true' or 'false'.`);
}
}
static logOverwrittenEnv(envName, envValue, ciEnvValue) {
this.$knapsackProLogger.info(`You have set the environment variable ${envName} to ${envValue} which could be automatically determined from the CI environment as ${ciEnvValue}.`);
}
static envFor(knapsackEnvName, ciEnvFunction) {
const knapsackEnvValue = process.env[knapsackEnvName];
const ciEnvValue = _1.CIEnvConfig[ciEnvFunction];
if (knapsackEnvValue !== undefined &&
ciEnvValue !== undefined &&
knapsackEnvValue !== ciEnvValue.toString()) {
this.logOverwrittenEnv(knapsackEnvName, knapsackEnvValue, ciEnvValue.toString());
}
return knapsackEnvValue !== undefined ? knapsackEnvValue : ciEnvValue;
}
static get ciNodeTotal() {
const envValue = this.envFor('KNAPSACK_PRO_CI_NODE_TOTAL', 'ciNodeTotal');
if (envValue) {
return parseInt(envValue, 10);
}
throw new Error('Undefined number of total CI nodes! Please set KNAPSACK_PRO_CI_NODE_TOTAL environment variable.');
}
static get ciNodeIndex() {
const envValue = this.envFor('KNAPSACK_PRO_CI_NODE_INDEX', 'ciNodeIndex');
if (envValue) {
return parseInt(envValue, 10);
}
throw new Error('Undefined CI node index! Please set KNAPSACK_PRO_CI_NODE_INDEX environment variable.');
}
static get ciNodeBuildId() {
const envValue = this.envFor('KNAPSACK_PRO_CI_NODE_BUILD_ID', 'ciNodeBuildId');
if (envValue) {
return envValue;
}
throw new Error(`Missing environment variable KNAPSACK_PRO_CI_NODE_BUILD_ID. Read more at ${Urls.KNAPSACK_PRO_CI_NODE_BUILD_ID}`);
}
static get ciNodeRetryCount() {
const envValue = this.envFor('KNAPSACK_PRO_CI_NODE_RETRY_COUNT', 'ciNodeRetryCount');
if (envValue) {
return parseInt(envValue, 10);
}
return 0;
}
static get commitHash() {
const envValue = this.envFor('KNAPSACK_PRO_COMMIT_HASH', 'commitHash');
if (envValue) {
return envValue;
}
const gitProcess = (0, child_process_1.spawnSync)('git', ['rev-parse', 'HEAD']);
if (gitProcess.status === 0) {
const gitCommitHash = gitProcess.stdout.toString().trim();
process.env.KNAPSACK_PRO_COMMIT_HASH = gitCommitHash;
return gitCommitHash;
}
if (gitProcess.stderr === null) {
knapsackProLogger.error('We tried to detect commit hash using git but it failed. Please ensure you have have git installed or set KNAPSACK_PRO_COMMIT_HASH environment variable.');
}
else {
const gitErrorMessage = gitProcess.stderr.toString();
knapsackProLogger.error('There was error in detecting commit hash using git installed on the machine:');
knapsackProLogger.error(gitErrorMessage);
}
throw new Error('Undefined commit hash! Please set KNAPSACK_PRO_COMMIT_HASH environment variable.');
}
static get branch() {
const envValue = this.envFor('KNAPSACK_PRO_BRANCH', 'branch');
if (envValue) {
return envValue;
}
const gitProcess = (0, child_process_1.spawnSync)('git', ['rev-parse', '--abbrev-ref', 'HEAD']);
if (gitProcess.status === 0) {
const gitBranch = gitProcess.stdout.toString().trim();
process.env.KNAPSACK_PRO_BRANCH = gitBranch;
return gitBranch;
}
if (gitProcess.stderr === null) {
knapsackProLogger.error('We tried to detect branch name using git but it failed. Please ensure you have have git installed or set KNAPSACK_PRO_BRANCH environment variable.');
}
else {
const gitErrorMessage = gitProcess.stderr.toString();
knapsackProLogger.error('There was error in detecting branch name using git installed on the machine:');
knapsackProLogger.error(gitErrorMessage);
}
throw new Error('Undefined branch name! Please set KNAPSACK_PRO_BRANCH environment variable.');
}
static get logLevel() {
return logLevel();
}
static get testFileListSourceFile() {
return process.env.KNAPSACK_PRO_TEST_FILE_LIST_SOURCE_FILE;
}
static get maskedUserSeat() {
const envValue = this.envFor('KNAPSACK_PRO_USER_SEAT', 'userSeat');
if (envValue) {
return mask(envValue);
}
return undefined;
}
}
exports.KnapsackProEnvConfig = KnapsackProEnvConfig;
const $buildAuthor = (command) => {
try {
const author = command().toString().trim();
return mask(author);
}
catch (error) {
return 'no git <no.git@example.com>';
}
};
const gitBuildAuthor = () => (0, child_process_1.execSync)('git log --format="%aN <%aE>" -1 2>/dev/null');
const buildAuthor = (command = gitBuildAuthor) => $buildAuthor(command);
exports.buildAuthor = buildAuthor;
const gitIsShallowRepository = () => (0, child_process_1.execSync)(`git rev-parse --is-shallow-repository 2>/dev/null`);
const $isShallowRepository = (command) => command().toString().trim() === 'true';
const isShallowRepository = (command = gitIsShallowRepository) => $isShallowRepository(command);
exports.isShallowRepository = isShallowRepository;
const $commitAuthors = (command) => {
try {
return command()
.toString()
.split('\n')
.filter((line) => line !== '')
.map((line) => line.trim())
.map((line) => line.split('\t'))
.map(([commits, author]) => ({
commits: parseInt(commits, 10),
author: mask(author),
}));
}
catch (error) {
return [];
}
};
const gitCommitAuthors = () => {
if ((0, _1.isCI)() && (0, exports.isShallowRepository)()) {
const gitFetchShallowSinceCommand = 'git fetch --shallow-since "one month ago" --quiet 2>/dev/null';
try {
(0, child_process_1.execSync)(gitFetchShallowSinceCommand, {
timeout: 5000,
});
}
catch (error) {
knapsackProLogger.debug(`Skip the \`${gitFetchShallowSinceCommand}\` command because it took too long. Error: ${error.message}`);
}
}
return (0, child_process_1.execSync)(`git log --since "one month ago" 2>/dev/null | git shortlog --summary --email 2>/dev/null`);
};
const commitAuthors = (command = gitCommitAuthors) => $commitAuthors(command);
exports.commitAuthors = commitAuthors;
const ciProvider = () => (0, _1.detectCI)().ciProvider;
exports.ciProvider = ciProvider;