@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
118 lines (117 loc) • 6.33 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.KnapsackProCore = void 0;
const knapsack_pro_api_1 = require("./knapsack-pro-api");
const api_response_codes_1 = require("./api-response-codes");
const config_1 = require("./config");
const knapsack_pro_logger_1 = require("./knapsack-pro-logger");
const fallback_test_distributor_1 = require("./fallback-test-distributor");
const test_files_finder_1 = require("./test-files-finder");
const Urls = __importStar(require("./urls"));
class KnapsackProCore {
knapsackProAPI;
knapsackProLogger;
recordedTestFiles;
allTestFiles;
isTestSuiteGreen;
constructor(clientName, clientVersion, testFilesToExecute) {
this.recordedTestFiles = [];
this.allTestFiles =
test_files_finder_1.TestFilesFinder.testFilesFromSourceFile() ?? testFilesToExecute();
this.knapsackProAPI = new knapsack_pro_api_1.KnapsackProAPI(clientName, clientVersion);
this.knapsackProLogger = new knapsack_pro_logger_1.KnapsackProLogger();
this.isTestSuiteGreen = true;
}
runQueueMode(onSuccess, onFailure) {
this.fetchTestsFromQueue(true, true, onSuccess, onFailure);
}
fetchTestsFromQueue(initializeQueue = false, attemptConnectToQueue = false, onSuccess, onFailure) {
this.knapsackProAPI
.fetchTestsFromQueue(this.allTestFiles, initializeQueue, attemptConnectToQueue)
.then((response) => {
const apiCode = response.data.code;
if (apiCode === api_response_codes_1.QueueApiResponseCodes.AttemptConnectToQueueFailed) {
this.fetchTestsFromQueue(true, false, onSuccess, onFailure);
return;
}
const queueTestFiles = response.data.test_files;
const isQueueEmpty = queueTestFiles.length === 0;
if (isQueueEmpty) {
this.finishQueueMode();
return;
}
onSuccess(queueTestFiles).then(({ recordedTestFiles, isTestSuiteGreen }) => {
this.updateRecordedTestFiles(recordedTestFiles, isTestSuiteGreen);
this.fetchTestsFromQueue(false, false, onSuccess, onFailure);
});
})
.catch((error) => {
if (this.knapsackProAPI.isExpectedErrorStatus(error)) {
process.exitCode = 1;
throw new Error('Knapsack Pro API returned an error. See the above logs.');
}
onFailure(error);
if (config_1.KnapsackProEnvConfig.ciNodeRetryCount > 0) {
throw new Error(`No connection to Knapsack Pro API to determine the set of tests that should run on the retried CI node. Please retry the CI node to reconnect with the API or create a new commit to start another CI build that could run tests in Fallback Mode in case of persisting connection issues with the API. Learn more ${Urls.QUEUE_MODE_CONNECTION_ERROR_AND_POSITIVE_RETRY_COUNT}`);
}
this.knapsackProLogger.warn('Fallback Mode has started. We could not connect to Knapsack Pro API. Your tests will be executed based on test file names.\n\nIf other CI nodes were able to connect to Knapsack Pro API then you may notice that some of the test files were executed twice across CI nodes. Fallback Mode guarantees each of test files is run at least once as a part of CI build.');
const fallbackTestDistributor = new fallback_test_distributor_1.FallbackTestDistributor(this.allTestFiles, this.recordedTestFiles);
const testFiles = fallbackTestDistributor.testFilesForCiNode();
const executedTestFiles = knapsack_pro_logger_1.KnapsackProLogger.objectInspect(this.recordedTestFiles);
this.knapsackProLogger.debug(`Test files already executed:\n${executedTestFiles}`);
const inspectedTestFiles = knapsack_pro_logger_1.KnapsackProLogger.objectInspect(testFiles);
this.knapsackProLogger.debug(`Test files to be run in Fallback Mode:\n${inspectedTestFiles}`);
onSuccess(testFiles).then(({ recordedTestFiles, isTestSuiteGreen }) => {
this.updateRecordedTestFiles(recordedTestFiles, isTestSuiteGreen);
this.finishQueueMode();
});
});
}
updateRecordedTestFiles(recordedTestFiles, isTestSuiteGreen) {
this.recordedTestFiles = this.recordedTestFiles.concat(recordedTestFiles);
this.isTestSuiteGreen = this.isTestSuiteGreen && isTestSuiteGreen;
}
finishQueueMode() {
this.createBuildSubset(this.recordedTestFiles);
process.exitCode = this.isTestSuiteGreen ? 0 : 1;
}
createBuildSubset(testFiles) {
this.knapsackProAPI.createBuildSubset(testFiles).catch((error) => {
this.knapsackProLogger.error('Could not save recorded timing of tests due to failed request to Knapsack Pro API.');
});
}
}
exports.KnapsackProCore = KnapsackProCore;