specshield 3.4.7 → 3.4.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specshield",
3
- "version": "3.4.7",
3
+ "version": "3.4.8",
4
4
  "description": "Contract compatibility testing for APIs — catch breaking OpenAPI changes before they reach your consumers, with can-i-deploy deploy gating and GitHub PR checks. (a.k.a. bidirectional contract testing.)",
5
5
  "main": "src/cli.js",
6
6
  "homepage": "https://specshield.io",
@@ -6,6 +6,7 @@ const ora = require('ora');
6
6
  const path = require('path');
7
7
  const fsExtra = require('fs-extra');
8
8
  const logger = require('../utils/logger');
9
+ const exitAfterFlush = require('../utils/exitAfterFlush');
9
10
  const { getStoredApiKey } = require('../config/localConfig');
10
11
  const { applyBdctDefaults } = require('../core/projectConfig');
11
12
  const {
@@ -300,7 +301,8 @@ const verifyCommand = new Command('verify')
300
301
 
301
302
  if (opts.json) {
302
303
  process.stdout.write(JSON.stringify(result, null, 2) + '\n');
303
- process.exit(success ? 0 : 1);
304
+ exitAfterFlush(success ? 0 : 1);
305
+ return;
304
306
  }
305
307
 
306
308
  process.stdout.write('\n');
@@ -352,7 +354,7 @@ const verifyCommand = new Command('verify')
352
354
  }
353
355
 
354
356
  process.stdout.write('\n');
355
- process.exit(success ? 0 : 1);
357
+ exitAfterFlush(success ? 0 : 1);
356
358
  } catch (err) {
357
359
  if (spinner) spinner.fail('Verification failed');
358
360
  logger.error(err.message);
@@ -399,7 +401,8 @@ const canIDeployCommand = new Command('can-i-deploy')
399
401
 
400
402
  if (opts.json) {
401
403
  process.stdout.write(JSON.stringify(result, null, 2) + '\n');
402
- process.exit(deployable ? 0 : 1);
404
+ exitAfterFlush(deployable ? 0 : 1);
405
+ return;
403
406
  }
404
407
 
405
408
  // Idempotent `v` prefix on display — don't double it when the stored
@@ -433,10 +436,10 @@ const canIDeployCommand = new Command('can-i-deploy')
433
436
  process.stdout.write(chalk.gray(` ➜ Run: specshield bdct verify --consumer <NAME> --provider ${opts.service}\n`));
434
437
  process.stdout.write(chalk.gray(` ➜ to identify and resolve incompatibilities\n`));
435
438
  process.stdout.write('\n');
436
- process.exit(1);
439
+ exitAfterFlush(1);
437
440
  } else {
438
441
  process.stdout.write('\n');
439
- process.exit(0);
442
+ exitAfterFlush(0);
440
443
  }
441
444
  } catch (err) {
442
445
  if (spinner) spinner.fail('Check failed');
@@ -817,7 +820,8 @@ const verifyProviderCommand = new Command('verify-provider')
817
820
 
818
821
  if (opts.json) {
819
822
  process.stdout.write(JSON.stringify(report, null, 2) + '\n');
820
- process.exit(report.summary.fail + report.summary.error > 0 ? 1 : 0);
823
+ exitAfterFlush(report.summary.fail + report.summary.error > 0 ? 1 : 0);
824
+ return;
821
825
  }
822
826
 
823
827
  // Human report.
@@ -850,7 +854,7 @@ const verifyProviderCommand = new Command('verify-provider')
850
854
  const s = report.summary;
851
855
  process.stdout.write(' ' + '─'.repeat(60) + '\n');
852
856
  process.stdout.write(` ${s.pass} pass · ${s.fail} fail · ${s.error} error · ${s.skipped} skip (${s.total} probes)\n\n`);
853
- process.exit(s.fail + s.error > 0 ? 1 : 0);
857
+ exitAfterFlush(s.fail + s.error > 0 ? 1 : 0);
854
858
  });
855
859
 
856
860
  // Repeatable --header parser: collects into a map.
@@ -14,6 +14,7 @@ const { loadConfig } = require('../core/configLoader');
14
14
  const { resolveExitCode } = require('../core/exitCode');
15
15
  const { recordCompareAndMaybeRender } = require('../core/conversionPrompt');
16
16
  const logger = require('../utils/logger');
17
+ const exitAfterFlush = require('../utils/exitAfterFlush');
17
18
  const fsExtra = require('fs-extra');
18
19
  const { getStoredApiKey } = require('../config/localConfig');
19
20
 
@@ -129,7 +130,7 @@ compare
129
130
 
130
131
  // Exit code
131
132
  const code = resolveExitCode(result, options);
132
- process.exit(code);
133
+ exitAfterFlush(code);
133
134
 
134
135
  } catch (err) {
135
136
  logger.error(`Error: ${err.message}`);
@@ -5,6 +5,7 @@ const chalk = require('chalk');
5
5
  const ora = require('ora');
6
6
  const fsExtra = require('fs-extra');
7
7
  const logger = require('../utils/logger');
8
+ const exitAfterFlush = require('../utils/exitAfterFlush');
8
9
  const { loadSpec } = require('../core/loadSpec');
9
10
  const { getStoredApiKey } = require('../config/localConfig');
10
11
  const { governanceGate } = require('../api/bdctClient');
@@ -80,8 +81,8 @@ const govern = new Command('govern')
80
81
  if (opts.output) await fsExtra.outputFile(opts.output, JSON.stringify(resp, null, 2));
81
82
  }
82
83
 
83
- if (opts.advisory) process.exit(0);
84
- process.exit(resp.passed ? 0 : 1);
84
+ if (opts.advisory) exitAfterFlush(0);
85
+ else exitAfterFlush(resp.passed ? 0 : 1);
85
86
  } catch (err) {
86
87
  if (err.status === 402) {
87
88
  logger.error('API governance requires a paid plan (Team or above). See https://specshield.io/pricing');
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ // process.exit() discards whatever is still buffered in stdout. Writes to a
4
+ // pipe are asynchronous, so `specshield <cmd> --json | jq` truncated large
5
+ // output mid-JSON and still exited 0. Queue an empty chunk and exit from its
6
+ // callback: stream callbacks run in order, so ours fires once every earlier
7
+ // chunk has reached the OS.
8
+ //
9
+ // Use this instead of process.exit() anywhere the command has already written
10
+ // to stdout. See tests/compareStdoutFlush.test.js.
11
+ function exitAfterFlush(code) {
12
+ process.stdout.write('', () => process.exit(code));
13
+ }
14
+
15
+ module.exports = exitAfterFlush;