@unito/integration-cli 1.2.0 → 1.3.0

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,7 +1,7 @@
1
1
  import { GetCredentialAccountHandler } from '@unito/integration-sdk';
2
2
 
3
3
  // eslint-disable-next-line @typescript-eslint/require-await -- Remove when adding async provider calls
4
- export const getCredentialAccount: GetCredentialAccountHandler = async () => {
4
+ const getCredentialAccount: GetCredentialAccountHandler = async function getCredentialAccount() {
5
5
  return {
6
6
  id: 'me',
7
7
  displayName: 'Me',
@@ -9,3 +9,5 @@ export const getCredentialAccount: GetCredentialAccountHandler = async () => {
9
9
  partition: undefined,
10
10
  };
11
11
  };
12
+
13
+ export { getCredentialAccount };
@@ -1,9 +1,11 @@
1
1
  import { GetItemHandler } from '@unito/integration-sdk';
2
2
 
3
3
  // eslint-disable-next-line @typescript-eslint/require-await -- Remove when adding async provider calls
4
- export const getItem: GetItemHandler = async () => {
4
+ const getItem: GetItemHandler = async function getItem() {
5
5
  return {
6
6
  fields: {},
7
7
  relations: [],
8
8
  };
9
9
  };
10
+
11
+ export { getItem };
@@ -94,6 +94,12 @@
94
94
  }
95
95
  },
96
96
  "additionalProperties": false
97
+ },
98
+ "visibility": {
99
+ "type": "string",
100
+ "enum": ["private", "public"],
101
+ "tsEnumNames": ["Private", "Public"],
102
+ "description": "The visibility of the integration."
97
103
  }
98
104
  }
99
105
  }
@@ -1,5 +1,6 @@
1
1
  import { BaseCommand } from '../baseCommand';
2
2
  import * as GlobalConfiguration from '../resources/globalConfiguration';
3
+ import { Visibility } from '../configurationTypes';
3
4
  export default class Publish extends BaseCommand<typeof Publish> {
4
5
  static description: string;
5
6
  static examples: string[];
@@ -8,6 +9,8 @@ export default class Publish extends BaseCommand<typeof Publish> {
8
9
  'registry-only': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
10
  preview: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
11
  'live-preview': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ visibility: import("@oclif/core/lib/interfaces").OptionFlag<Visibility | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ 'display-name': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
14
  'config-path': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
15
  force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
16
  };
@@ -16,6 +16,7 @@ const integrations_1 = require("../resources/integrations");
16
16
  const GlobalConfiguration = tslib_1.__importStar(require("../resources/globalConfiguration"));
17
17
  const IntegrationsPlatform = tslib_1.__importStar(require("../services/integrationsPlatform"));
18
18
  const IntegrationConfiguration = tslib_1.__importStar(require("../resources/configuration"));
19
+ const configurationTypes_1 = require("../configurationTypes");
19
20
  const fileSystem_1 = require("../resources/fileSystem");
20
21
  const integrationsPlatform_1 = require("../resources/integrationsPlatform");
21
22
  class Publish extends baseCommand_1.BaseCommand {
@@ -42,6 +43,15 @@ class Publish extends baseCommand_1.BaseCommand {
42
43
  default: false,
43
44
  exclusive: ['registry-only', 'preview'],
44
45
  }),
46
+ visibility: core_1.Flags.custom({
47
+ description: 'visibility of the preview integration. Accepts "public" or "private" (default). Only valid with --preview. --visibility=public is additionally restricted to --environment=staging or --environment=local.',
48
+ options: Object.values(configurationTypes_1.Visibility),
49
+ exclusive: ['live-preview', 'registry-only'],
50
+ })(),
51
+ 'display-name': core_1.Flags.string({
52
+ description: 'override the integration display name. Only valid with --preview, --live-preview, or --environment=local. On preview flows, the mode suffix (e.g. "Preview - {hash}", "Live Preview - {hash}") is still appended.',
53
+ exclusive: ['registry-only'],
54
+ }),
45
55
  'config-path': core_1.Flags.string({
46
56
  summary: 'relative path to a custom ".unito.json" file',
47
57
  description: `Use a custom configuration file instead of the default '.unito.json' or other environment specific
@@ -71,7 +81,36 @@ class Publish extends baseCommand_1.BaseCommand {
71
81
  // Read the configurations.
72
82
  const globalConfiguration = await GlobalConfiguration.read(this.config.configDir);
73
83
  const environment = flags.environment ?? GlobalConfiguration.Environment.Production;
84
+ // Runtime guards. oclif's dependsOn/relationships can't be used for the
85
+ // "--visibility=public requires --preview" rule because --preview has
86
+ // `default: false` and oclif treats defaulted booleans as "present".
87
+ if (flags.visibility === configurationTypes_1.Visibility.Public) {
88
+ if (!flags.preview) {
89
+ core_1.ux.log(chalk_1.default.redBright('--visibility=public is only supported in combination with --preview.'));
90
+ this.exit(-1);
91
+ }
92
+ if (environment === GlobalConfiguration.Environment.Production) {
93
+ core_1.ux.log(chalk_1.default.redBright('--visibility=public is not supported on --environment=production. ' +
94
+ 'Publish privately first; changing visibility on production is handled by a separate process.'));
95
+ this.exit(-1);
96
+ }
97
+ }
98
+ if (flags['display-name'] !== undefined &&
99
+ !flags.preview &&
100
+ !flags['live-preview'] &&
101
+ environment !== GlobalConfiguration.Environment.Local) {
102
+ core_1.ux.log(chalk_1.default.redBright('--display-name is only supported with --preview, --live-preview, or --environment=local.'));
103
+ this.exit(-1);
104
+ }
74
105
  const integrationConfiguration = await IntegrationConfiguration.getConfiguration(environment, flags['config-path']);
106
+ if (flags['display-name'] !== undefined) {
107
+ // Set the base display name. Mode-specific suffixes ("Preview - {hash}", "Live Preview - {hash}")
108
+ // are appended later inside the corresponding preview methods.
109
+ integrationConfiguration.ui = { ...(integrationConfiguration.ui ?? {}), displayName: flags['display-name'] };
110
+ }
111
+ if (flags.visibility !== undefined) {
112
+ integrationConfiguration.visibility = flags.visibility;
113
+ }
75
114
  if (integrationConfiguration.authorizations) {
76
115
  integrationConfiguration.authorizations = integrationConfiguration.authorizations.filter(authorization => !authorization.development);
77
116
  }
@@ -220,18 +259,13 @@ class Publish extends baseCommand_1.BaseCommand {
220
259
  child_process_1.default.execSync('git init . --initial-branch=main');
221
260
  }
222
261
  async previewIntegration(integrationConfiguration) {
223
- // Get the profile.
224
262
  core_1.ux.action.start('Get profile', undefined, { stdout: true });
225
263
  const profile = await IntegrationsPlatform.getProfile();
226
264
  core_1.ux.action.stop();
227
- // Generate a new name.
228
265
  const newName = `${integrationConfiguration.name}-preview-${this.hashEmail(profile.email)}`;
229
- // Update the secrets.
230
266
  const updatedConfiguration = await this.generateNewSecrets(integrationConfiguration, newName);
231
267
  core_1.ux.action.start('Creating preview', undefined, { stdout: true });
232
- // Update the name.
233
268
  updatedConfiguration.name = newName;
234
- // Update the display name.
235
269
  if (updatedConfiguration.ui?.displayName) {
236
270
  updatedConfiguration.ui.displayName = [
237
271
  updatedConfiguration.ui.displayName,
@@ -239,10 +273,8 @@ class Publish extends baseCommand_1.BaseCommand {
239
273
  this.hashEmail(profile.email),
240
274
  ].join(' - ');
241
275
  }
242
- // Write the updated configuration on disk.
243
276
  await IntegrationConfiguration.writeConfiguration(updatedConfiguration);
244
277
  core_1.ux.action.stop();
245
- // Publish the integration.
246
278
  await this.publishIntegration(updatedConfiguration);
247
279
  }
248
280
  async publishIntegration(integrationConfiguration) {
@@ -53,7 +53,8 @@ class Upgrade extends baseCommand_1.BaseCommand {
53
53
  //
54
54
  core_1.ux.action.start(`${latestVersion ? 'Validating' : 'Upgrading'} the package`, undefined, { stdout: true });
55
55
  // To make sure we have a clean version of the CLI, with updated packages, we force the re-installation.
56
- child_process_1.default.execSync(`npm install --force ${npmOptions} ${packageName}`, {
56
+ // --min-release-age=0 bypasses the npm release age safeguard for this internal trusted package.
57
+ child_process_1.default.execSync(`npm install --force --min-release-age=0 ${npmOptions} ${packageName}`, {
57
58
  ...execOptions,
58
59
  stdio: ['ignore', 'ignore', 'inherit'],
59
60
  });
@@ -85,6 +85,7 @@ export interface Configuration {
85
85
  */
86
86
  [k: string]: string;
87
87
  };
88
+ visibility?: Visibility;
88
89
  }
89
90
  /**
90
91
  * An authorization is a way to obtain and generate credentials for an integration
@@ -231,3 +232,10 @@ export declare enum Format {
231
232
  EMAIL = "email",
232
233
  URI = "uri"
233
234
  }
235
+ /**
236
+ * The visibility of the integration.
237
+ */
238
+ export declare enum Visibility {
239
+ Private = "private",
240
+ Public = "public"
241
+ }
@@ -6,7 +6,7 @@
6
6
  * and run json-schema-to-typescript to regenerate this file.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.Format = exports.Type = exports.PkceCodeChallengeMethod = exports.RequestContentType = exports.GrantType = exports.Method = void 0;
9
+ exports.Visibility = exports.Format = exports.Type = exports.PkceCodeChallengeMethod = exports.RequestContentType = exports.GrantType = exports.Method = void 0;
10
10
  /**
11
11
  * The method of authorization
12
12
  */
@@ -57,3 +57,11 @@ var Format;
57
57
  Format["EMAIL"] = "email";
58
58
  Format["URI"] = "uri";
59
59
  })(Format || (exports.Format = Format = {}));
60
+ /**
61
+ * The visibility of the integration.
62
+ */
63
+ var Visibility;
64
+ (function (Visibility) {
65
+ Visibility["Private"] = "private";
66
+ Visibility["Public"] = "public";
67
+ })(Visibility || (exports.Visibility = Visibility = {}));
@@ -153,6 +153,7 @@ async function updateIntegration(integrationId, configuration) {
153
153
  authorizations: authorizationsToCreate.concat(authorizationsToArchive).concat(authorizationsToUpdate),
154
154
  secrets: configuration.secrets,
155
155
  ui: configuration.ui,
156
+ visibility: configuration.visibility,
156
157
  archived: configuration.archived,
157
158
  });
158
159
  }
@@ -360,4 +360,191 @@ describe('Publish', () => {
360
360
  (0, test_1.expect)(ctx.stdout).to.contain('image: <unset>');
361
361
  (0, test_1.expect)(ctx.stdout).to.contain('markdown: <unset>');
362
362
  });
363
+ test_1.test
364
+ .stdout()
365
+ .stderr()
366
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKey: 'foo' }))
367
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo' }))
368
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
369
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
370
+ .command(['publish', '--preview', '--visibility=public', '--environment=production'])
371
+ .exit(-1)
372
+ .it('rejects --visibility=public on production', ctx => {
373
+ (0, test_1.expect)((0, styles_1.uncolorize)(ctx.stdout)).to.contain('--visibility=public is not supported on --environment=production');
374
+ });
375
+ test_1.test
376
+ .stdout()
377
+ .stderr()
378
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKeyStaging: 'foo' }))
379
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo' }))
380
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
381
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
382
+ .command(['publish', '--visibility=public', '--environment=staging'])
383
+ .exit(-1)
384
+ .it('rejects --visibility=public without --preview', ctx => {
385
+ (0, test_1.expect)((0, styles_1.uncolorize)(ctx.stdout)).to.contain('--visibility=public is only supported in combination with --preview');
386
+ });
387
+ test_1.test
388
+ .stdout()
389
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKeyStaging: 'foo' }))
390
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo', ui: { displayName: 'Foo' } }))
391
+ .stub(IntegrationConfiguration, 'writeConfiguration', stub => stub.returns(integration))
392
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
393
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
394
+ .command(['publish', '--preview', '--visibility=public', '--environment=staging'])
395
+ .it('--preview --visibility=public on staging writes visibility into the archive config', ctx => {
396
+ (0, test_1.expect)((0, styles_1.uncolorize)(ctx.stdout)).to.contain('foo-preview-9c88 is being published');
397
+ ctx.sandbox.assert.calledWithMatch(
398
+ // @ts-expect-error syntax accepted by sinon.
399
+ IntegrationConfiguration.writeConfiguration, {
400
+ name: 'foo-preview-9c88',
401
+ ui: { displayName: 'Foo - Preview - 9c88' },
402
+ visibility: 'public',
403
+ });
404
+ });
405
+ test_1.test
406
+ .stdout()
407
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKeyLocal: 'foo' }))
408
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo', ui: { displayName: 'Foo' } }))
409
+ .stub(IntegrationConfiguration, 'writeConfiguration', stub => stub.returns(integration))
410
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
411
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
412
+ .command(['publish', '--preview', '--visibility=public', '--environment=local'])
413
+ .it('--preview --visibility=public on local — also allowed', ctx => {
414
+ (0, test_1.expect)((0, styles_1.uncolorize)(ctx.stdout)).to.contain('foo-preview-9c88 is being published');
415
+ ctx.sandbox.assert.calledWithMatch(
416
+ // @ts-expect-error syntax accepted by sinon.
417
+ IntegrationConfiguration.writeConfiguration, { visibility: 'public' });
418
+ });
419
+ test_1.test
420
+ .stdout()
421
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKeyStaging: 'foo' }))
422
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({
423
+ name: 'myIntegration',
424
+ authorizations: [{ name: 'oauth2', oauth2: { clientSecret: 'unito-secret-' } }],
425
+ secrets: { secret1: 'unito-secret-', invalidSecret: 'Should never happen anyway' },
426
+ }))
427
+ .stub(IntegrationConfiguration, 'writeConfiguration', stub => stub.returns({
428
+ name: 'myIntegration',
429
+ authorizations: [{ name: 'oauth2', oauth2: { clientSecret: 'unito-secret-' } }],
430
+ secrets: { secret1: 'unito-secret-', invalidSecret: 'Should never happen anyway' },
431
+ }))
432
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
433
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
434
+ .command(['publish', '--preview', '--visibility=public', '--environment=staging'])
435
+ .it('reencrypts the clientSecret on --preview --visibility=public', ctx => {
436
+ (0, test_1.expect)(ctx.stdout).to.contain('Reencrypting oauth2:clientSecret');
437
+ (0, test_1.expect)(ctx.stdout).to.contain('Reencrypting secrets:secret1');
438
+ (0, test_1.expect)(ctx.stdout).to.contain('Skipping secrets:invalidSecret');
439
+ });
440
+ test_1.test
441
+ .stdout()
442
+ .stderr()
443
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKey: 'foo' }))
444
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo' }))
445
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
446
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
447
+ .command(['publish', '--display-name', 'PR-1234'])
448
+ .exit(-1)
449
+ .it('rejects --display-name without --preview or --live-preview', ctx => {
450
+ (0, test_1.expect)((0, styles_1.uncolorize)(ctx.stdout)).to.contain('--display-name is only supported with --preview, --live-preview, or --environment=local');
451
+ });
452
+ test_1.test
453
+ .stdout()
454
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKeyStaging: 'foo' }))
455
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo', ui: { displayName: 'Foo' } }))
456
+ .stub(IntegrationConfiguration, 'writeConfiguration', stub => stub.returns(integration))
457
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
458
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
459
+ .command(['publish', '--preview', '--visibility=public', '--environment=staging', '--display-name', 'PR-1234'])
460
+ .it('public preview with --display-name — overrides base, Preview+hash suffix still appended', ctx => {
461
+ (0, test_1.expect)((0, styles_1.uncolorize)(ctx.stdout)).to.contain('foo-preview-9c88 is being published');
462
+ ctx.sandbox.assert.calledWithMatch(
463
+ // @ts-expect-error syntax accepted by sinon.
464
+ IntegrationConfiguration.writeConfiguration, {
465
+ name: 'foo-preview-9c88',
466
+ ui: { displayName: 'PR-1234 - Preview - 9c88' },
467
+ visibility: 'public',
468
+ });
469
+ });
470
+ test_1.test
471
+ .stdout()
472
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKey: 'foo' }))
473
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo', ui: { displayName: 'Foo' } }))
474
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
475
+ .stub(IntegrationConfiguration, 'writeConfiguration', stub => stub.returns(integration))
476
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
477
+ .command(['publish', '--preview', '--display-name', 'PR-1234'])
478
+ .it('private preview - --display-name overrides the base, hash suffix still appended', ctx => {
479
+ (0, test_1.expect)((0, styles_1.uncolorize)(ctx.stdout)).to.contain('foo-preview-9c88 is being published');
480
+ ctx.sandbox.assert.calledWithMatch(
481
+ // @ts-expect-error syntax accepted by sinon.
482
+ IntegrationConfiguration.writeConfiguration, {
483
+ name: 'foo-preview-9c88',
484
+ ui: { displayName: 'PR-1234 - Preview - 9c88' },
485
+ });
486
+ });
487
+ test_1.test
488
+ .stdout()
489
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKeyLocal: 'foo' }))
490
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo', ui: { displayName: 'Foo' } }))
491
+ .stub(IntegrationConfiguration, 'writeConfiguration', stub => stub.returns(integration))
492
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
493
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
494
+ .command(['publish', '--environment=local', '--display-name', 'PR-1234'])
495
+ .it('--display-name on a plain publish is allowed on local and overrides displayName', ctx => {
496
+ (0, test_1.expect)(ctx.stdout).to.contain('published');
497
+ ctx.sandbox.assert.calledWithMatch(
498
+ // @ts-expect-error syntax accepted by sinon.
499
+ IntegrationConfiguration.writeConfiguration, {
500
+ name: 'foo',
501
+ ui: { displayName: 'PR-1234' },
502
+ });
503
+ });
504
+ // oclif-declared constraints — verify they fire at parse time (exit 2).
505
+ // Error messages go to the real process.stderr and aren't captured by fancy-test.
506
+ test_1.test
507
+ .stdout()
508
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKeyStaging: 'foo' }))
509
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo', ui: { displayName: 'Foo' } }))
510
+ .stub(IntegrationConfiguration, 'writeConfiguration', stub => stub.returns(integration))
511
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
512
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
513
+ .command(['publish', '--preview', '--visibility=private', '--environment=staging'])
514
+ .it('accepts --visibility=private as explicit intent and publishes normally', ctx => {
515
+ (0, test_1.expect)((0, styles_1.uncolorize)(ctx.stdout)).to.contain('foo-preview-9c88 is being published');
516
+ ctx.sandbox.assert.calledWithMatch(
517
+ // @ts-expect-error syntax accepted by sinon.
518
+ IntegrationConfiguration.writeConfiguration, { visibility: 'private' });
519
+ });
520
+ test_1.test
521
+ .stdout()
522
+ .stderr()
523
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKeyStaging: 'foo' }))
524
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo' }))
525
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
526
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
527
+ .command(['publish', '--visibility=public', '--live-preview', '--environment=staging'])
528
+ .exit(2)
529
+ .it('oclif rejects --visibility + --live-preview (exclusive)', _ctx => { });
530
+ test_1.test
531
+ .stdout()
532
+ .stderr()
533
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKey: 'foo' }))
534
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo' }))
535
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
536
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
537
+ .command(['publish', '--visibility=public', '--registry-only'])
538
+ .exit(2)
539
+ .it('oclif rejects --visibility + --registry-only (exclusive)', _ctx => { });
540
+ test_1.test
541
+ .stdout()
542
+ .stderr()
543
+ .stub(GlobalConfiguration, 'read', stub => stub.returns({ apiKey: 'foo' }))
544
+ .stub(IntegrationConfiguration, 'getConfiguration', stub => stub.returns({ name: 'foo' }))
545
+ .stub(IntegrationsPlatform, 'getIntegrationByName', stub => stub.returns(undefined))
546
+ .stub(FileSystem, 'getFileBuffer', stub => stub.resolves(Buffer.from('')))
547
+ .command(['publish', '--display-name=Foo', '--registry-only'])
548
+ .exit(2)
549
+ .it('oclif rejects --display-name + --registry-only (exclusive)', _ctx => { });
363
550
  });
@@ -151,6 +151,7 @@ describe('integrations platform', function () {
151
151
  credentialAccountRelativeUrl: '/me',
152
152
  graphRelativeUrl: '/',
153
153
  secrets: configuration.secrets,
154
+ visibility: undefined,
154
155
  webhookAcknowledgeRelativeUrl: undefined,
155
156
  webhookParsingRelativeUrl: undefined,
156
157
  webhookSubscriptionsRelativeUrl: undefined,
@@ -176,6 +177,7 @@ describe('integrations platform', function () {
176
177
  credentialAccountRelativeUrl: '/me',
177
178
  graphRelativeUrl: '/',
178
179
  secrets: configuration.secrets,
180
+ visibility: undefined,
179
181
  webhookAcknowledgeRelativeUrl: undefined,
180
182
  webhookParsingRelativeUrl: undefined,
181
183
  webhookSubscriptionsRelativeUrl: undefined,
@@ -663,6 +663,31 @@
663
663
  "allowNo": false,
664
664
  "type": "boolean"
665
665
  },
666
+ "visibility": {
667
+ "description": "visibility of the preview integration. Accepts \"public\" or \"private\" (default). Only valid with --preview. --visibility=public is additionally restricted to --environment=staging or --environment=local.",
668
+ "exclusive": [
669
+ "live-preview",
670
+ "registry-only"
671
+ ],
672
+ "name": "visibility",
673
+ "hasDynamicHelp": false,
674
+ "multiple": false,
675
+ "options": [
676
+ "private",
677
+ "public"
678
+ ],
679
+ "type": "option"
680
+ },
681
+ "display-name": {
682
+ "description": "override the integration display name. Only valid with --preview, --live-preview, or --environment=local. On preview flows, the mode suffix (e.g. \"Preview - {hash}\", \"Live Preview - {hash}\") is still appended.",
683
+ "exclusive": [
684
+ "registry-only"
685
+ ],
686
+ "name": "display-name",
687
+ "hasDynamicHelp": false,
688
+ "multiple": false,
689
+ "type": "option"
690
+ },
666
691
  "config-path": {
667
692
  "description": "Use a custom configuration file instead of the default '.unito.json' or other environment specific\n ones.\n\n If you want to force the CLI to use a specific configuration file, you can use this flag to specify the relative\n path from your integration's root folder (with a leading '/').\n\n Usage: <%= config.bin %> <%= command.id %> --config-path=/myCustomConfig.json",
668
693
  "name": "config-path",
@@ -1005,5 +1030,5 @@
1005
1030
  ]
1006
1031
  }
1007
1032
  },
1008
- "version": "1.2.0"
1033
+ "version": "1.3.0"
1009
1034
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unito/integration-cli",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Integration CLI",
5
5
  "bin": {
6
6
  "integration-cli": "./bin/run"