@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 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.github.io/docs/reporters/dotnet.
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
- commitSha: options.commitSha,
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: `Connection failed: ${errorMessage}`,
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 errorText = await response.text();
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: `Upload failed (HTTP ${response.status}): ${errorText}`,
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,