@testream/dotnet-reporter 1.0.0 → 1.0.1
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.
- package/README.md +1 -1
- package/dist/index.js +80 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,4 +23,4 @@ Run .NET tests and send the results from your codebase to Jira via Testream.
|
|
|
23
23
|
|
|
24
24
|
This installs the reporter, runs your .NET tests, and uploads results to Testream.
|
|
25
25
|
|
|
26
|
-
For CLI options and CI examples, see https://testream.
|
|
26
|
+
For CLI options and CI examples, see https://docs.testream.app/reporters/dotnet.
|
package/dist/index.js
CHANGED
|
@@ -2299,6 +2299,7 @@ exports.ensureReportId = ensureReportId;
|
|
|
2299
2299
|
exports.uploadTestRun = uploadTestRun;
|
|
2300
2300
|
exports.mapAttachmentsToTestResults = mapAttachmentsToTestResults;
|
|
2301
2301
|
exports.uploadArtifacts = uploadArtifacts;
|
|
2302
|
+
const ci_detection_1 = __nccwpck_require__(406);
|
|
2302
2303
|
const DEFAULT_API_URL = 'https://test-manager-backend.fly.dev';
|
|
2303
2304
|
function ensureReportId(report) {
|
|
2304
2305
|
if (typeof report.reportId === 'string' && report.reportId.trim().length > 0) {
|
|
@@ -2335,6 +2336,52 @@ function normalizeApiUrl(value) {
|
|
|
2335
2336
|
}
|
|
2336
2337
|
return trimmed.replace(/\/+$/, '');
|
|
2337
2338
|
}
|
|
2339
|
+
function isReportAlreadyExistsConflict(error) {
|
|
2340
|
+
return error.errorCode === 'report_already_exists';
|
|
2341
|
+
}
|
|
2342
|
+
function formatUploadError(error) {
|
|
2343
|
+
const detail = error.detail || error.title || error.rawBody || 'Unknown error';
|
|
2344
|
+
const codeLabel = error.errorCode ? `, code=${error.errorCode}` : '';
|
|
2345
|
+
return `Upload failed (HTTP ${error.statusCode}${codeLabel}): ${detail}`;
|
|
2346
|
+
}
|
|
2347
|
+
async function parseHttpError(response) {
|
|
2348
|
+
const rawBody = await response.text();
|
|
2349
|
+
const contentType = response.headers.get('content-type') || '';
|
|
2350
|
+
if (contentType.toLowerCase().includes('json') && rawBody.trim().length > 0) {
|
|
2351
|
+
try {
|
|
2352
|
+
const parsed = JSON.parse(rawBody);
|
|
2353
|
+
return {
|
|
2354
|
+
statusCode: response.status,
|
|
2355
|
+
title: parsed.title,
|
|
2356
|
+
detail: parsed.detail || parsed.details || parsed.error,
|
|
2357
|
+
errorCode: parsed.errorCode,
|
|
2358
|
+
rawBody,
|
|
2359
|
+
};
|
|
2360
|
+
}
|
|
2361
|
+
catch {
|
|
2362
|
+
// Fall through to raw body handling
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
return {
|
|
2366
|
+
statusCode: response.status,
|
|
2367
|
+
rawBody,
|
|
2368
|
+
};
|
|
2369
|
+
}
|
|
2370
|
+
function resolveUploadContext(options) {
|
|
2371
|
+
const ciContext = (0, ci_detection_1.detectCIContext)();
|
|
2372
|
+
return {
|
|
2373
|
+
commitSha: options.commitSha ?? ciContext.commitSha,
|
|
2374
|
+
branch: options.branch ?? ciContext.branch,
|
|
2375
|
+
repositoryUrl: options.repositoryUrl ?? ciContext.repositoryUrl,
|
|
2376
|
+
buildName: options.buildName,
|
|
2377
|
+
buildNumber: options.buildNumber ?? ciContext.buildNumber,
|
|
2378
|
+
buildUrl: options.buildUrl ?? ciContext.buildUrl,
|
|
2379
|
+
testEnvironment: options.testEnvironment,
|
|
2380
|
+
appName: options.appName,
|
|
2381
|
+
appVersion: options.appVersion,
|
|
2382
|
+
testType: options.testType,
|
|
2383
|
+
};
|
|
2384
|
+
}
|
|
2338
2385
|
/**
|
|
2339
2386
|
* Upload test run to Testream backend API
|
|
2340
2387
|
*/
|
|
@@ -2342,20 +2389,12 @@ async function uploadTestRun(options) {
|
|
|
2342
2389
|
const { report, apiKey } = options;
|
|
2343
2390
|
const apiUrl = resolveApiUrl(options.apiUrl);
|
|
2344
2391
|
const reportId = ensureReportId(report);
|
|
2392
|
+
const uploadContext = resolveUploadContext(options);
|
|
2345
2393
|
// Build type-safe IngestRequest payload
|
|
2346
2394
|
const ingestPayload = {
|
|
2347
2395
|
report,
|
|
2348
2396
|
reportId,
|
|
2349
|
-
|
|
2350
|
-
branch: options.branch,
|
|
2351
|
-
repositoryUrl: options.repositoryUrl,
|
|
2352
|
-
buildName: options.buildName,
|
|
2353
|
-
buildNumber: options.buildNumber,
|
|
2354
|
-
buildUrl: options.buildUrl,
|
|
2355
|
-
testEnvironment: options.testEnvironment,
|
|
2356
|
-
appName: options.appName,
|
|
2357
|
-
appVersion: options.appVersion,
|
|
2358
|
-
testType: options.testType,
|
|
2397
|
+
...uploadContext,
|
|
2359
2398
|
};
|
|
2360
2399
|
// Professional logging
|
|
2361
2400
|
console.log('Uploading test results...');
|
|
@@ -2372,34 +2411,41 @@ async function uploadTestRun(options) {
|
|
|
2372
2411
|
}
|
|
2373
2412
|
catch (error) {
|
|
2374
2413
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2414
|
+
const connectionError = `Connection failed: ${errorMessage}`;
|
|
2415
|
+
console.error(connectionError);
|
|
2375
2416
|
return {
|
|
2376
2417
|
success: false,
|
|
2377
2418
|
reportId,
|
|
2378
|
-
error:
|
|
2419
|
+
error: connectionError,
|
|
2379
2420
|
};
|
|
2380
2421
|
}
|
|
2381
|
-
// Handle 409 (report already exists) - idempotent
|
|
2382
|
-
if (response.status === 409) {
|
|
2383
|
-
console.warn('Report already exists (workflow may have been re-run)');
|
|
2384
|
-
return {
|
|
2385
|
-
success: true,
|
|
2386
|
-
reportId,
|
|
2387
|
-
summary: {
|
|
2388
|
-
passed: report.results.summary.passed,
|
|
2389
|
-
failed: report.results.summary.failed,
|
|
2390
|
-
skipped: report.results.summary.skipped,
|
|
2391
|
-
total: report.results.summary.tests,
|
|
2392
|
-
},
|
|
2393
|
-
alreadyExists: true,
|
|
2394
|
-
};
|
|
2395
|
-
}
|
|
2396
|
-
// Handle other errors
|
|
2397
2422
|
if (!response.ok) {
|
|
2398
|
-
const
|
|
2423
|
+
const parsedError = await parseHttpError(response);
|
|
2424
|
+
if (response.status === 409 && isReportAlreadyExistsConflict(parsedError)) {
|
|
2425
|
+
console.warn('Report already exists (workflow may have been re-run)');
|
|
2426
|
+
return {
|
|
2427
|
+
success: true,
|
|
2428
|
+
reportId,
|
|
2429
|
+
summary: {
|
|
2430
|
+
passed: report.results.summary.passed,
|
|
2431
|
+
failed: report.results.summary.failed,
|
|
2432
|
+
skipped: report.results.summary.skipped,
|
|
2433
|
+
total: report.results.summary.tests,
|
|
2434
|
+
},
|
|
2435
|
+
alreadyExists: true,
|
|
2436
|
+
statusCode: parsedError.statusCode,
|
|
2437
|
+
errorCode: parsedError.errorCode,
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
const formattedError = formatUploadError(parsedError);
|
|
2441
|
+
console.error(formattedError);
|
|
2399
2442
|
return {
|
|
2400
2443
|
success: false,
|
|
2401
2444
|
reportId,
|
|
2402
|
-
error:
|
|
2445
|
+
error: formattedError,
|
|
2446
|
+
statusCode: parsedError.statusCode,
|
|
2447
|
+
errorCode: parsedError.errorCode,
|
|
2448
|
+
errorDetail: parsedError.detail || parsedError.rawBody,
|
|
2403
2449
|
};
|
|
2404
2450
|
}
|
|
2405
2451
|
// Success
|
|
@@ -2958,26 +3004,18 @@ async function main() {
|
|
|
2958
3004
|
logger.info('='.repeat(60));
|
|
2959
3005
|
return;
|
|
2960
3006
|
}
|
|
2961
|
-
// Detect CI context from environment
|
|
2962
|
-
const ciContext = (0, uploader_1.detectGitContext)();
|
|
2963
|
-
// Merge CLI options with auto-detected CI context (CLI takes precedence)
|
|
2964
|
-
const branch = options.branch || ciContext.branch;
|
|
2965
|
-
const commitSha = options.commitSha || ciContext.commitSha;
|
|
2966
|
-
const repositoryUrl = options.repositoryUrl || ciContext.repositoryUrl;
|
|
2967
|
-
const buildNumber = options.buildNumber || ciContext.buildNumber;
|
|
2968
|
-
const buildUrl = options.buildUrl || ciContext.buildUrl;
|
|
2969
3007
|
// Upload to API
|
|
2970
3008
|
const result = await (0, uploader_1.uploadToApi)({
|
|
2971
3009
|
report,
|
|
2972
3010
|
apiKey: options.apiKey,
|
|
2973
3011
|
// Git context
|
|
2974
|
-
branch,
|
|
2975
|
-
commitSha,
|
|
2976
|
-
repositoryUrl,
|
|
3012
|
+
branch: options.branch,
|
|
3013
|
+
commitSha: options.commitSha,
|
|
3014
|
+
repositoryUrl: options.repositoryUrl,
|
|
2977
3015
|
// Build metadata
|
|
2978
3016
|
buildName: options.buildName,
|
|
2979
|
-
buildNumber,
|
|
2980
|
-
buildUrl,
|
|
3017
|
+
buildNumber: options.buildNumber,
|
|
3018
|
+
buildUrl: options.buildUrl,
|
|
2981
3019
|
// Environment metadata
|
|
2982
3020
|
testEnvironment: options.testEnvironment,
|
|
2983
3021
|
appName: options.appName,
|