@teamscale/coverage-collector 1.0.0-beta.7 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,337 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.DataStorage = exports.CoverageBucket = void 0;
40
- exports.formatTimestamp = formatTimestamp;
41
- const RemoteProfilerConfig_1 = require("../config/RemoteProfilerConfig");
42
- const commons_1 = require("@cqse/commons");
43
- const fs = __importStar(require("fs"));
44
- const path_1 = __importDefault(require("path"));
45
- class CoverageBucket {
46
- appId;
47
- commit;
48
- coveredLinesByFile;
49
- constructor(appId, commit) {
50
- this.coveredLinesByFile = new Map();
51
- this.appId = appId;
52
- this.commit = commit;
53
- }
54
- putLine(sourceFile, line) {
55
- let targetSet = this.coveredLinesByFile.get(sourceFile);
56
- if (!targetSet) {
57
- targetSet = new Set();
58
- this.coveredLinesByFile.set(sourceFile, targetSet);
59
- }
60
- targetSet.add(line);
61
- }
62
- getCoverage() {
63
- function* iterate(iterable, transform) {
64
- for (const e of iterable) {
65
- yield transform(e);
66
- }
67
- }
68
- return iterate(this.coveredLinesByFile.entries(), ([file, lines]) => {
69
- return {
70
- sourceFile: file,
71
- coveredLines: lines
72
- };
73
- });
74
- }
75
- clear() {
76
- this.coveredLinesByFile.clear();
77
- }
78
- }
79
- exports.CoverageBucket = CoverageBucket;
80
- class DataStorage {
81
- coverageBuckets;
82
- configPerApp;
83
- validatedPerApp;
84
- configIdPerApp;
85
- logger;
86
- baseConfig;
87
- reconfigurableParameters;
88
- allParameters;
89
- beforeConfigUpdateCallbacks;
90
- constructor(logger, allParameters, reconfigurableParameters, baseConfig) {
91
- this.coverageBuckets = new Map();
92
- this.configIdPerApp = new Map();
93
- this.configPerApp = new Map();
94
- this.validatedPerApp = new Map();
95
- this.logger = commons_1.Contract.requireDefined(logger);
96
- this.baseConfig = commons_1.Contract.requireDefined(baseConfig);
97
- this.allParameters = commons_1.Contract.requireDefined(allParameters);
98
- this.reconfigurableParameters = commons_1.Contract.requireDefined(reconfigurableParameters);
99
- this.beforeConfigUpdateCallbacks = [];
100
- }
101
- async setupCoverageBucket(bucketSpecifier) {
102
- this.getBucketFor(bucketSpecifier);
103
- try {
104
- if (bucketSpecifier.configId) {
105
- await this.changeAppConfiguration(bucketSpecifier.appId, bucketSpecifier.configId);
106
- }
107
- if (!bucketSpecifier.configOptions) {
108
- return;
109
- }
110
- const configOptions = bucketSpecifier.configOptions.split(/\r?\n/).map(line => line.trim());
111
- for (const option of configOptions) {
112
- if (option.length === 0 || option.startsWith('#')) {
113
- continue;
114
- }
115
- const splitted = option.split('=');
116
- if (splitted.length === 1) {
117
- this.setConfigurationParameter(bucketSpecifier.appId, splitted[0], undefined);
118
- }
119
- if (splitted.length === 2) {
120
- const [key, value] = splitted;
121
- this.setConfigurationParameter(bucketSpecifier.appId, key.trim(), value.trim());
122
- }
123
- else {
124
- throw new Error(`Invalid configuration option '${option}'. Expected format <key>=<value>.`);
125
- }
126
- }
127
- }
128
- catch (error) {
129
- this.logger.error("Setting up a the configuration of a coverage bucket failed. "
130
- + "Your profiler configuration seems to be invalid: " + error?.message);
131
- }
132
- }
133
- async changeAppConfiguration(appId, configId) {
134
- const assignedConfigId = this.configIdPerApp.get(appId);
135
- if (!assignedConfigId || assignedConfigId !== configId) {
136
- await this.refreshApplicationConfiguration(appId, configId);
137
- }
138
- }
139
- async refreshAllRemoteConfigurations() {
140
- (0, RemoteProfilerConfig_1.clearConfigurationCache)();
141
- for (const appId of this.getApplicationIDs()) {
142
- await this.refreshApplicationConfiguration(appId);
143
- }
144
- }
145
- async refreshApplicationConfiguration(appId, newConfigId) {
146
- const assignedConfigId = newConfigId ?? this.configIdPerApp.get(appId);
147
- if (!assignedConfigId) {
148
- return;
149
- }
150
- try {
151
- const remoteConfig = await RemoteProfilerConfig_1.RemoteProfilerConfig.queryConfiguration(this.baseConfig, assignedConfigId, this.logger);
152
- const appConfigCopy = this.getOrCreateAppConfig(appId).copy();
153
- for (const [key, value] of remoteConfig.entries()) {
154
- try {
155
- appConfigCopy.overwriteConfig(key, value);
156
- }
157
- catch (e) {
158
- this.logger.error(`Failed to set configuration parameter ${key}=${value} for app ${appId}: ${e}`);
159
- }
160
- }
161
- const existingAppConfigHash = this.validatedPerApp.get(appId);
162
- const wasConfigChanged = existingAppConfigHash !== undefined && appConfigCopy.getHash() !== existingAppConfigHash;
163
- this.validateConfiguration(appId, appConfigCopy);
164
- if (wasConfigChanged) {
165
- for (const beforeConfigUpdateCallback of this.beforeConfigUpdateCallbacks) {
166
- await beforeConfigUpdateCallback(appId, this);
167
- }
168
- }
169
- this.configPerApp.set(appId, appConfigCopy);
170
- }
171
- catch (e) {
172
- this.logger.error(`Failed to retrieve configuration for app ${appId} with ID ${assignedConfigId}: ${e}`);
173
- this.logger.error(e);
174
- throw e;
175
- }
176
- this.configIdPerApp.set(appId, assignedConfigId);
177
- }
178
- getOrCreateAppConfig(appId) {
179
- let appConfig = this.configPerApp.get(appId);
180
- if (!appConfig) {
181
- appConfig = new commons_1.ConfigurationWithOverwrites(this.allParameters, this.reconfigurableParameters, this.baseConfig);
182
- this.configPerApp.set(appId, appConfig);
183
- }
184
- return appConfig;
185
- }
186
- setConfigurationParameter(appId, parameter, value) {
187
- const appConfig = this.getOrCreateAppConfig(appId);
188
- appConfig.overwriteConfig(parameter, value);
189
- }
190
- validateConfiguration(appId, appConfig) {
191
- if (appConfig === undefined) {
192
- throw new Error(`Configuration for app "${appId}" not found`);
193
- }
194
- const alreadyValidatedHash = this.validatedPerApp.get(appId);
195
- const configHash = appConfig.getHash();
196
- if (alreadyValidatedHash !== configHash) {
197
- (0, commons_1.checkArguments)(this.reconfigurableParameters, (0, commons_1.makeConfigProxy)(appConfig), (message) => this.logger.error(message));
198
- this.validatedPerApp.set(appId, configHash);
199
- }
200
- }
201
- getAppConfiguration(appId) {
202
- let result = this.configPerApp.get(appId);
203
- if (!result) {
204
- result = new commons_1.ConfigurationWithOverwrites(this.allParameters, this.reconfigurableParameters, this.baseConfig);
205
- this.configPerApp.set(appId, result);
206
- }
207
- return (0, commons_1.makeConfigProxy)(result);
208
- }
209
- getBucketFor(bucketSpecifier) {
210
- const bucketId = getBucketId(bucketSpecifier.appId, bucketSpecifier.commit);
211
- let bucket = this.coverageBuckets.get(bucketId);
212
- if (!bucket) {
213
- bucket = new CoverageBucket(bucketSpecifier.appId, bucketSpecifier.commit);
214
- this.coverageBuckets.set(bucketId, bucket);
215
- }
216
- return bucketId;
217
- }
218
- getBucket(appId, commit) {
219
- return this.coverageBuckets.get(getBucketId(appId, commit));
220
- }
221
- getAppBuckets(appId) {
222
- return Array.from(this.coverageBuckets.values())
223
- .filter(bucket => appId === undefined || bucket.appId === appId);
224
- }
225
- putCoverage(appId, commit, sourceFilePath, coveredOriginalLines) {
226
- const uniformPath = DataStorage.normalizeSourceFileName(sourceFilePath);
227
- const bucketId = getBucketId(appId, commit);
228
- let projectCoverage = this.coverageBuckets.get(bucketId);
229
- if (!projectCoverage) {
230
- projectCoverage = new CoverageBucket(appId, commit);
231
- this.coverageBuckets.set(bucketId, projectCoverage);
232
- }
233
- coveredOriginalLines.forEach(line => projectCoverage?.putLine(sourceFilePath, line));
234
- this.logger.trace(`Mapped Coverage: ${appId} ${commit} ${uniformPath} ${coveredOriginalLines}`);
235
- }
236
- static normalizeSourceFileName(sourceFile) {
237
- return (0, commons_1.removePrefix)('webpack:///', sourceFile.replace('\\', '/'));
238
- }
239
- dumpToSimpleCoverageFile(coverageFolder, date, dumpForAppIdOnly) {
240
- coverageFolder = coverageFolder.trim();
241
- const details = new Array();
242
- let hadCoverageToDump = false;
243
- const appsToDumpFor = dumpForAppIdOnly ? [dumpForAppIdOnly] : this.getApplicationIDs();
244
- for (const appId of appsToDumpFor) {
245
- const coveragePerCommit = this.toSimpleCoverage(appId);
246
- for (const [commit, [lineCount, content]] of coveragePerCommit) {
247
- hadCoverageToDump = hadCoverageToDump || lineCount > 0;
248
- if (lineCount > 0) {
249
- const finalFilePath = this.prepareValidCoverageFileName(coverageFolder, date, commit, appId);
250
- fs.writeFileSync(finalFilePath, content, { flag: 'w', encoding: 'utf8' });
251
- this.logger.debug(`Simple coverage with length ${content.length} dumped to file ${finalFilePath}.`);
252
- details.push({ appId, simpleCoverageFile: finalFilePath, simpleCoverageFileLines: lineCount, commit });
253
- }
254
- }
255
- this.resetCoverage(appId);
256
- }
257
- return {
258
- hadCoverageToDump,
259
- details
260
- };
261
- }
262
- resetCoverage(appId) {
263
- this.getAppBuckets(appId).forEach(bucket => bucket.clear());
264
- }
265
- prepareValidCoverageFileName(coverageFolder, date, commit, appId) {
266
- if (!fs.existsSync(coverageFolder)) {
267
- fs.mkdirSync(coverageFolder);
268
- }
269
- const formattedDate = formatTimestamp(date);
270
- if (appId) {
271
- return path_1.default.join(coverageFolder, sanitizeFileName(`coverage-${appId}-${formattedDate}-${commit}.simple`));
272
- }
273
- return path_1.default.join(coverageFolder, `coverage-${formattedDate}.simple`);
274
- }
275
- toSimpleCoverage(appId) {
276
- const simpleCoveragePerCommit = new Map();
277
- for (const bucket of this.getAppBuckets(appId)) {
278
- let linesForCommit = simpleCoveragePerCommit.get(bucket.commit);
279
- if (!linesForCommit) {
280
- linesForCommit = [];
281
- simpleCoveragePerCommit.set(bucket.commit, linesForCommit);
282
- }
283
- const projectCoverage = bucket.getCoverage();
284
- for (const entry of projectCoverage) {
285
- linesForCommit.push(DataStorage.normalizeSourceFileName(entry.sourceFile));
286
- for (const lineNo of entry.coveredLines) {
287
- linesForCommit.push(String(lineNo));
288
- }
289
- }
290
- }
291
- const result = new Map();
292
- for (const [commit, lines] of simpleCoveragePerCommit) {
293
- result.set(commit, [lines.length, lines.join('\n')]);
294
- }
295
- return result;
296
- }
297
- getApplicationIDs() {
298
- return new Set(Array.from(this.coverageBuckets.values())
299
- .map(bucket => bucket.appId));
300
- }
301
- getApplicationsWithConfig(configId) {
302
- return new Set(Array.from(this.coverageBuckets.values())
303
- .filter(bucket => {
304
- const appConfigId = this.configIdPerApp.get(bucket.appId);
305
- return appConfigId === configId;
306
- })
307
- .map(bucket => bucket.appId));
308
- }
309
- discardCollectedCoverage(appId) {
310
- if (!getBucketId) {
311
- this.coverageBuckets.clear();
312
- }
313
- else {
314
- this.getAppBuckets(appId).forEach(bucket => bucket.clear());
315
- }
316
- }
317
- addBeforeConfigUpdateCallback(callback) {
318
- this.beforeConfigUpdateCallbacks.push(callback);
319
- }
320
- }
321
- exports.DataStorage = DataStorage;
322
- function getBucketId(appId, commit) {
323
- return `${appId}-${commit}`;
324
- }
325
- function sanitizeFileName(name) {
326
- return name.replace(/[^a-zA-Z0-9._-]/g, '_');
327
- }
328
- function formatTimestamp(date) {
329
- const pad = (num) => num.toString().padStart(2, '0');
330
- const year = date.getFullYear();
331
- const month = pad(date.getMonth() + 1);
332
- const day = pad(date.getDate());
333
- const hours = pad(date.getHours());
334
- const minutes = pad(date.getMinutes());
335
- const seconds = pad(date.getSeconds());
336
- return `${year}-${month}-${day}-${hours}-${minutes}-${seconds}`;
337
- }
@@ -1,3 +0,0 @@
1
- import { CollectorOptions } from '@cqse/commons';
2
- import Logger from "bunyan";
3
- export declare function uploadToArtifactory(config: CollectorOptions, logger: Logger, coverageFile: string, lines: number, commit: string): Promise<boolean>;
@@ -1,60 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.uploadToArtifactory = uploadToArtifactory;
7
- const RestApis_1 = require("../utils/RestApis");
8
- const axios_1 = __importDefault(require("axios"));
9
- async function uploadToArtifactory(config, logger, coverageFile, lines, commit) {
10
- if (!(config.artifactoryAccessToken || (config.artifactoryUser && config.artifactoryPassword))) {
11
- throw new RestApis_1.UploadError('API key or user name and password must be configured!');
12
- }
13
- if (lines === 0) {
14
- return false;
15
- }
16
- logger.debug('Preparing upload to Artifactory');
17
- const form = (0, RestApis_1.prepareReportFileUploadFormData)(coverageFile);
18
- await performArtifactoryUpload(config, form, logger, commit);
19
- return true;
20
- }
21
- async function performArtifactoryUpload(config, form, logger, commit) {
22
- const branchAndTimestamp = commit.split(':');
23
- if (branchAndTimestamp.length !== 2) {
24
- throw new RestApis_1.UploadError(`The commit "${commit}" does not contain a branch and timestamp; this is needed for the Artifactory upload. Please use the format "branch:timestamp".`);
25
- }
26
- if (branchAndTimestamp[0].length === 0) {
27
- throw new RestApis_1.UploadError(`The branch of the commit "${commit}" is empty. Please use the format "branch:timestamp".`);
28
- }
29
- let url = `${(0, RestApis_1.removeTrailingUrlSlash)(config.artifactoryServerUrl)}/uploads/${branchAndTimestamp[0]}/${branchAndTimestamp[1]}`;
30
- url = url + `/${config.teamscalePartition}/simple`;
31
- if (config.artifactoryPathSuffix !== undefined) {
32
- url = `${url}/${config.artifactoryPathSuffix}`;
33
- }
34
- url = `${url}/report.simple`;
35
- await (0, RestApis_1.performFormDataRequest)(url, form, prepareArtifactoryConfig(config, form), axios_1.default.put, logger);
36
- }
37
- function prepareArtifactoryConfig(config, form) {
38
- const proxyConfig = (0, RestApis_1.extractProxyOptions)(config);
39
- if (config.artifactoryAccessToken) {
40
- return {
41
- headers: {
42
- Accept: '*/*',
43
- 'X-JFrog-Art-Api': config.artifactoryAccessToken,
44
- 'Content-Type': `multipart/form-data; boundary=${form.getBoundary()}`
45
- },
46
- proxy: proxyConfig
47
- };
48
- }
49
- return {
50
- auth: {
51
- username: config.artifactoryUser ?? 'no Artifactory username provided',
52
- password: config.artifactoryPassword ?? 'no Artifactory access token provided'
53
- },
54
- headers: {
55
- Accept: '*/*',
56
- 'Content-Type': `multipart/form-data; boundary=${form.getBoundary()}`
57
- },
58
- proxy: proxyConfig
59
- };
60
- }
@@ -1,5 +0,0 @@
1
- import Logger from 'bunyan';
2
- import { CollectorOptions } from '@cqse/commons';
3
- export declare function checkTeamscaleCredentials(config: CollectorOptions, logger: Logger): Promise<boolean>;
4
- export declare function uploadToTeamscale(config: CollectorOptions, logger: Logger, coverageFile: string, lines: number, commit: string): Promise<boolean>;
5
- export declare function isTimestampArgument(commitOrRevision: string): boolean;
@@ -1,83 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.checkTeamscaleCredentials = checkTeamscaleCredentials;
7
- exports.uploadToTeamscale = uploadToTeamscale;
8
- exports.isTimestampArgument = isTimestampArgument;
9
- const QueryParameters_1 = __importDefault(require("../utils/QueryParameters"));
10
- const RestApis_1 = require("../utils/RestApis");
11
- const axios_1 = __importDefault(require("axios"));
12
- async function checkTeamscaleCredentials(config, logger) {
13
- if (config.teamscaleAccessToken === undefined) {
14
- logger.error("No valid access token provided for accessing the Teamscale server.");
15
- return false;
16
- }
17
- if (config.teamscaleUser === undefined) {
18
- logger.error("No valid user name provided for accessing the Teamscale server.");
19
- return false;
20
- }
21
- const checkUrl = `${(0, RestApis_1.removeTrailingUrlSlash)(config.teamscaleServerUrl)}/api/${RestApis_1.TEAMSCALE_API_VERSION}/auth/login/access-key`;
22
- try {
23
- await (0, RestApis_1.performRequest)(checkUrl, JSON.stringify({
24
- username: config.teamscaleUser,
25
- password: config.teamscaleAccessToken,
26
- stayLoggedIn: false,
27
- }), (0, RestApis_1.prepareTeamscaleApiRequestConfig)(config, { 'Content-Type': `application/json` }), axios_1.default.post, logger);
28
- return true;
29
- }
30
- catch (e) {
31
- logger.error('Teamscale authentication failed.', e);
32
- return false;
33
- }
34
- }
35
- async function uploadToTeamscale(config, logger, coverageFile, lines, commit) {
36
- if (!(config.teamscaleAccessToken && config.teamscaleUser && config.teamscaleServerUrl)) {
37
- throw new RestApis_1.UploadError('API key and user name must be configured!');
38
- }
39
- if (!config.teamscaleProject && !config.teamscalePartition) {
40
- throw new RestApis_1.UploadError('Teamscale project and partition must be configured!');
41
- }
42
- if (lines === 0) {
43
- return false;
44
- }
45
- logger.debug('Preparing upload to Teamscale');
46
- const form = (0, RestApis_1.prepareReportFileUploadFormData)(coverageFile);
47
- const queryParameters = prepareQueryParameters(config, commit);
48
- await performTeamscaleUpload(config, queryParameters, form, logger);
49
- return true;
50
- }
51
- async function performTeamscaleUpload(config, parameters, form, logger) {
52
- const uploadUrl = `${(0, RestApis_1.removeTrailingUrlSlash)(config.teamscaleServerUrl)}/api/${RestApis_1.TEAMSCALE_API_VERSION}/projects/${config.teamscaleProject}/external-analysis/session/auto-create/report?${parameters.toString()}`;
53
- await (0, RestApis_1.performFormDataRequest)(uploadUrl, form, (0, RestApis_1.prepareTeamscaleApiFormRequestConfig)(config, form), axios_1.default.post, logger);
54
- }
55
- function prepareQueryParameters(config, commitOrRevision) {
56
- const parameters = new QueryParameters_1.default();
57
- parameters.addIfDefined('format', 'SIMPLE');
58
- parameters.addIfDefined('message', config.teamscaleMessage);
59
- parameters.addIfDefined('repository', config.teamscaleRepository);
60
- if (isTimestampArgument(commitOrRevision)) {
61
- parameters.addIfDefined('t', commitOrRevision);
62
- }
63
- else {
64
- parameters.addIfDefined('revision', commitOrRevision);
65
- }
66
- parameters.addIfDefined('partition', config.teamscalePartition);
67
- return parameters;
68
- }
69
- function isTimestampArgument(commitOrRevision) {
70
- const parts = commitOrRevision.split(":");
71
- if (parts.length === 2) {
72
- if (parts[1].toUpperCase() === "HEAD") {
73
- return true;
74
- }
75
- else {
76
- return /^\d+$/.test(parts[1]);
77
- }
78
- }
79
- else if (parts.length === 1) {
80
- return /^\d+$/.test(commitOrRevision);
81
- }
82
- return false;
83
- }
@@ -1,8 +0,0 @@
1
- import 'dotenv/config';
2
- import { WriteStream } from 'fs';
3
- export declare class PrettyFileLogger {
4
- outputStream: WriteStream;
5
- constructor(outputStream: WriteStream);
6
- write(rec: any): void;
7
- end(): void;
8
- }
@@ -1,21 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.PrettyFileLogger = void 0;
7
- const bunyan_1 = __importDefault(require("bunyan"));
8
- require("dotenv/config");
9
- class PrettyFileLogger {
10
- outputStream;
11
- constructor(outputStream) {
12
- this.outputStream = outputStream;
13
- }
14
- write(rec) {
15
- this.outputStream.write(`[${rec.time.toISOString()}] ${bunyan_1.default.nameFromLevel[rec.level].toUpperCase()}: ${rec.msg}\n`);
16
- }
17
- end() {
18
- this.outputStream.close();
19
- }
20
- }
21
- exports.PrettyFileLogger = PrettyFileLogger;
@@ -1,3 +0,0 @@
1
- export default class QueryParameters extends URLSearchParams {
2
- addIfDefined(key: string, value: string | undefined): void;
3
- }
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- class QueryParameters extends URLSearchParams {
4
- addIfDefined(key, value) {
5
- if (value) {
6
- this.append(key, value);
7
- }
8
- else {
9
- this.delete(key);
10
- }
11
- }
12
- }
13
- exports.default = QueryParameters;
@@ -1,14 +0,0 @@
1
- import { CollectorOptions } from '@cqse/commons';
2
- import FormData from 'form-data';
3
- import Logger from 'bunyan';
4
- import axios, { AxiosProxyConfig, AxiosRequestConfig, AxiosResponse } from 'axios';
5
- export declare const TEAMSCALE_API_VERSION = "v2025.2";
6
- export declare class UploadError extends Error {
7
- }
8
- export declare function prepareReportFileUploadFormData(reportFileToUpload: string): FormData;
9
- export declare function performFormDataRequest(url: string, form: FormData, config: AxiosRequestConfig<FormData>, uploadFunction: <T = unknown, R = AxiosResponse<T>, D = FormData>(url: string, data?: D, config?: AxiosRequestConfig<D>) => Promise<R>, logger: Logger): Promise<void>;
10
- export declare function performRequest<B, R>(url: string, bodyData: B | undefined, config: AxiosRequestConfig<unknown>, requestFunction: typeof axios.get | typeof axios.post | typeof axios.put, logger: Logger): Promise<R>;
11
- export declare function prepareTeamscaleApiFormRequestConfig(config: CollectorOptions, form: FormData): AxiosRequestConfig<FormData>;
12
- export declare function prepareTeamscaleApiRequestConfig(config: CollectorOptions, headers: Record<string, string>): AxiosRequestConfig<FormData>;
13
- export declare function extractProxyOptions(config: CollectorOptions): AxiosProxyConfig | undefined;
14
- export declare function removeTrailingUrlSlash(url: string | undefined): string | undefined;
@@ -1,111 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.UploadError = exports.TEAMSCALE_API_VERSION = void 0;
7
- exports.prepareReportFileUploadFormData = prepareReportFileUploadFormData;
8
- exports.performFormDataRequest = performFormDataRequest;
9
- exports.performRequest = performRequest;
10
- exports.prepareTeamscaleApiFormRequestConfig = prepareTeamscaleApiFormRequestConfig;
11
- exports.prepareTeamscaleApiRequestConfig = prepareTeamscaleApiRequestConfig;
12
- exports.extractProxyOptions = extractProxyOptions;
13
- exports.removeTrailingUrlSlash = removeTrailingUrlSlash;
14
- const form_data_1 = __importDefault(require("form-data"));
15
- const fs_1 = __importDefault(require("fs"));
16
- const axios_1 = __importDefault(require("axios"));
17
- const util_1 = require("util");
18
- const url_1 = __importDefault(require("url"));
19
- exports.TEAMSCALE_API_VERSION = 'v2025.2';
20
- class UploadError extends Error {
21
- }
22
- exports.UploadError = UploadError;
23
- function prepareReportFileUploadFormData(reportFileToUpload) {
24
- const form = new form_data_1.default();
25
- form.append('report', fs_1.default.readFileSync(reportFileToUpload), 'coverage.simple');
26
- return form;
27
- }
28
- async function performFormDataRequest(url, form, config, uploadFunction, logger) {
29
- return performRequest(url, form, config, uploadFunction, logger);
30
- }
31
- async function performRequest(url, bodyData, config, requestFunction, logger) {
32
- try {
33
- logger.debug("Requesting via URL: " + url);
34
- let response;
35
- if (requestFunction === axios_1.default.get) {
36
- response = await axios_1.default.get(url, config);
37
- }
38
- else if (requestFunction === axios_1.default.put) {
39
- response = await axios_1.default.put(url, bodyData, config);
40
- }
41
- else if (requestFunction === axios_1.default.post) {
42
- response = await axios_1.default.post(url, bodyData, config);
43
- }
44
- else {
45
- throw new Error(`Unsupported request function: ${requestFunction}`);
46
- }
47
- logger.debug(`Request finished with code ${response.status}.`);
48
- return response.data;
49
- }
50
- catch (error) {
51
- if (axios_1.default.isAxiosError(error)) {
52
- let userMessage;
53
- if (error.message) {
54
- logger.error(`Request error ${error.status ?? 'UNDEFINED'}: ${error.message}\n\tRequested URL: ${url}`);
55
- }
56
- if (error.response) {
57
- logger.error('Request error response data:', error.response.data);
58
- logger.error('Request error response status:', error.response.status);
59
- logger.debug('Request error response headers:', JSON.stringify(error.response.headers));
60
- userMessage = `Request failed with status ${error.response.status}: ${error.response.data ?? ''}`;
61
- }
62
- else if (error.request) {
63
- userMessage = 'No response received for the request. ' + (error.message ?? error.code);
64
- }
65
- else {
66
- userMessage = 'Request setup failed.';
67
- }
68
- throw new UploadError(`Something went wrong when interacting with the API: ${userMessage}`);
69
- }
70
- throw new UploadError(`Something went wrong: ${(0, util_1.inspect)(error)}`);
71
- }
72
- }
73
- function prepareTeamscaleApiFormRequestConfig(config, form) {
74
- return prepareTeamscaleApiRequestConfig(config, { 'Content-Type': `multipart/form-data; boundary=${form.getBoundary()}` });
75
- }
76
- function prepareTeamscaleApiRequestConfig(config, headers) {
77
- return {
78
- auth: {
79
- username: config.teamscaleUser ?? 'no username provided',
80
- password: config.teamscaleAccessToken ?? 'no password provided'
81
- },
82
- headers: {
83
- Accept: '*/*',
84
- ...headers
85
- },
86
- timeout: 15000,
87
- proxy: extractProxyOptions(config)
88
- };
89
- }
90
- function extractProxyOptions(config) {
91
- const proxy = config.httpProxy;
92
- if (!proxy) {
93
- return undefined;
94
- }
95
- const proxyAddress = new url_1.default.URL(proxy);
96
- const proxyConfig = {
97
- protocol: proxyAddress.protocol.replace(':', ''),
98
- host: proxyAddress.hostname,
99
- port: +proxyAddress.port,
100
- };
101
- if (proxyAddress.username && proxyAddress.password) {
102
- proxyConfig.auth = {
103
- username: proxyAddress.username,
104
- password: proxyAddress.password
105
- };
106
- }
107
- return proxyConfig;
108
- }
109
- function removeTrailingUrlSlash(url) {
110
- return url?.replace(/\/$/, '');
111
- }
@@ -1,4 +0,0 @@
1
- import 'dotenv/config';
2
- export declare class StdConsoleLogger {
3
- write(rec: any): void;
4
- }