@jupiterone/integration-sdk-cli 8.24.0 → 8.25.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,4 +1,4 @@
1
- import { createCommand } from 'commander';
1
+ import { Command, createCommand, OptionValues } from 'commander';
2
2
  import path from 'path';
3
3
 
4
4
  import { Metric } from '@jupiterone/integration-sdk-core';
@@ -11,8 +11,6 @@ import {
11
11
  executeIntegrationInstance,
12
12
  FileSystemGraphObjectStore,
13
13
  finalizeSynchronization,
14
- getAccountFromEnvironment,
15
- getApiKeyFromEnvironment,
16
14
  initiateSynchronization,
17
15
  synchronizationStatus,
18
16
  } from '@jupiterone/integration-sdk-runtime';
@@ -21,77 +19,40 @@ import { createPersisterApiStepGraphObjectDataUploader } from '@jupiterone/integ
21
19
  import { loadConfig } from '../config';
22
20
  import * as log from '../log';
23
21
  import {
24
- getApiBaseUrlOption,
25
- getSynchronizationJobSourceOptions,
22
+ addApiClientOptionsToCommand,
23
+ addPathOptionsToCommand,
24
+ addSyncOptionsToCommand,
25
+ configureRuntimeFilesystem,
26
+ getApiClientOptions,
27
+ getSyncOptions,
28
+ validateApiClientOptions,
29
+ validateSyncOptions,
26
30
  } from './options';
27
31
 
28
32
  const DEFAULT_UPLOAD_CONCURRENCY = 5;
29
33
 
30
- export function run() {
31
- return createCommand('run')
32
- .description('collect and sync to upload entities and relationships')
33
- .option(
34
- '-i, --integrationInstanceId <id>',
35
- '_integrationInstanceId assigned to uploaded entities and relationships',
36
- )
37
- .option(
38
- '-p, --project-path <directory>',
39
- 'path to integration project directory',
40
- process.cwd(),
41
- )
42
- .option(
43
- '-d, --development',
44
- '"true" to target apps.dev.jupiterone.io',
45
- !!process.env.JUPITERONE_DEV,
46
- )
47
- .option('--api-base-url <url>', 'API base URL used during run operation')
48
- .option('--skip-finalize', 'skip synchronization finalization')
49
- .option(
50
- '--source <integration-managed|integration-external|api>',
51
- 'configure the synchronization job source value',
52
- 'integration-managed',
53
- )
54
- .option(
55
- '--scope <anystring>',
56
- 'configure the synchronization job scope value',
57
- )
58
- .option('-V, --disable-schema-validation', 'disable schema validation')
59
- .option(
60
- '-u, --upload-batch-size <number>',
61
- 'specify number of items per batch for upload (default 250)',
62
- )
63
- .option(
64
- '-ur, --upload-relationship-batch-size <number>',
65
- 'specify number of relationships per batch for upload (default 250)',
66
- )
67
- .action(async (options) => {
68
- const projectPath = path.resolve(options.projectPath);
69
- // Point `fileSystem.ts` functions to expected location relative to
70
- // integration project path.
71
- process.env.JUPITERONE_INTEGRATION_STORAGE_DIRECTORY = path.resolve(
72
- projectPath,
73
- '.j1-integration',
74
- );
34
+ export function run(): Command {
35
+ const command = createCommand('run');
75
36
 
76
- log.debug('Loading API Key from JUPITERONE_API_KEY environment variable');
77
- const accessToken = getApiKeyFromEnvironment();
37
+ addPathOptionsToCommand(command);
38
+ addApiClientOptionsToCommand(command);
39
+ addSyncOptionsToCommand(command);
78
40
 
79
- log.debug('Loading account from JUPITERONE_ACCOUNT environment variable');
80
- const account = getAccountFromEnvironment();
81
-
82
- const apiBaseUrl = getApiBaseUrlOption(options);
83
- log.debug(`Configuring client to access "${apiBaseUrl}"`);
41
+ return command
42
+ .description('collect and sync to upload entities and relationships')
43
+ .option('-V, --disable-schema-validation', 'disable schema validation')
44
+ .action(async (options: OptionValues, actionCommand: Command) => {
45
+ configureRuntimeFilesystem(actionCommand.opts());
46
+ validateApiClientOptions(actionCommand.opts());
47
+ validateSyncOptions(actionCommand.opts());
84
48
 
85
49
  const startTime = Date.now();
86
50
 
87
- const apiClient = createApiClient({
88
- apiBaseUrl,
89
- accessToken,
90
- account,
91
- });
92
-
93
- const synchronizationJobSourceOptions =
94
- getSynchronizationJobSourceOptions(options);
51
+ const clientApiOptions = getApiClientOptions(actionCommand.opts());
52
+ const apiClient = createApiClient(clientApiOptions);
53
+ log.debug(
54
+ `Configured JupiterOne API client. (apiBaseUrl: '${clientApiOptions.apiBaseUrl}', account: ${clientApiOptions.account})`,
55
+ );
95
56
 
96
57
  let logger = createIntegrationLogger({
97
58
  name: 'local',
@@ -101,7 +62,7 @@ export function run() {
101
62
  const synchronizationContext = await initiateSynchronization({
102
63
  logger,
103
64
  apiClient,
104
- ...synchronizationJobSourceOptions,
65
+ ...getSyncOptions(actionCommand.opts()),
105
66
  });
106
67
 
107
68
  logger = synchronizationContext.logger;
@@ -115,7 +76,9 @@ export function run() {
115
76
  .on('event', (event) => eventPublishingQueue.enqueue(event))
116
77
  .on('metric', (metric) => metrics.push(metric));
117
78
 
118
- const invocationConfig = await loadConfig(path.join(projectPath, 'src'));
79
+ const invocationConfig = await loadConfig(
80
+ path.resolve(options.projectPath, 'src'),
81
+ );
119
82
 
120
83
  const graphObjectStore = new FileSystemGraphObjectStore({
121
84
  prettifyFiles: true,
@@ -130,7 +93,7 @@ export function run() {
130
93
  invocationConfig,
131
94
  {
132
95
  current: {
133
- startedOn: startTime,
96
+ startedOn: synchronizationContext.job.startTimestamp,
134
97
  },
135
98
  },
136
99
  {
@@ -153,18 +116,18 @@ export function run() {
153
116
 
154
117
  log.displayExecutionResults(executionResults);
155
118
 
156
- if (!options.skipFinalize) {
157
- const synchronizationResult = await finalizeSynchronization({
158
- ...synchronizationContext,
159
- partialDatasets: executionResults.metadata.partialDatasets,
160
- });
161
- log.displaySynchronizationResults(synchronizationResult);
162
- } else {
119
+ if (options.skipFinalize) {
163
120
  log.info(
164
121
  'Skipping synchronization finalization. Job will remain in "AWAITING_UPLOADS" state.',
165
122
  );
166
123
  const jobStatus = await synchronizationStatus(synchronizationContext);
167
124
  log.displaySynchronizationResults(jobStatus);
125
+ } else {
126
+ const synchronizationResult = await finalizeSynchronization({
127
+ ...synchronizationContext,
128
+ partialDatasets: executionResults.metadata.partialDatasets,
129
+ });
130
+ log.displaySynchronizationResults(synchronizationResult);
168
131
  }
169
132
  } catch (err) {
170
133
  await eventPublishingQueue.onIdle();
@@ -1,93 +1,60 @@
1
- import { createCommand } from 'commander';
2
- import path from 'path';
1
+ import { Command, createCommand, OptionValues } from 'commander';
3
2
 
4
3
  import {
5
4
  createApiClient,
6
5
  createIntegrationLogger,
7
- getAccountFromEnvironment,
8
- getApiKeyFromEnvironment,
9
6
  synchronizeCollectedData,
10
7
  } from '@jupiterone/integration-sdk-runtime';
11
8
 
12
9
  import * as log from '../log';
13
10
  import {
14
- getApiBaseUrlOption,
15
- getSynchronizationJobSourceOptions,
11
+ addApiClientOptionsToCommand,
12
+ addPathOptionsToCommand,
13
+ addSyncOptionsToCommand,
14
+ configureRuntimeFilesystem,
15
+ getApiClientOptions,
16
+ getSyncOptions,
17
+ validateApiClientOptions,
18
+ validateSyncOptions,
16
19
  } from './options';
17
20
 
18
- export function sync() {
19
- return createCommand('sync')
21
+ export function sync(): Command {
22
+ const command = createCommand('sync');
23
+
24
+ addPathOptionsToCommand(command);
25
+ addApiClientOptionsToCommand(command);
26
+ addSyncOptionsToCommand(command);
27
+
28
+ return command
20
29
  .description(
21
30
  'sync collected data with JupiterOne, requires JUPITERONE_API_KEY, JUPITERONE_ACCOUNT',
22
31
  )
23
- .option(
24
- '-i, --integrationInstanceId <id>',
25
- '_integrationInstanceId assigned to uploaded entities and relationships',
26
- )
27
- .option(
28
- '-p, --project-path <directory>',
29
- 'path to integration project directory',
30
- process.cwd(),
31
- )
32
- .option(
33
- '-d, --development',
34
- '"true" to target apps.dev.jupiterone.io',
35
- !!process.env.JUPITERONE_DEV,
36
- )
37
- .option('--api-base-url <url>', 'API base URL used during sync operation.')
38
- .option(
39
- '--source <integration-managed|integration-external|api>',
40
- 'configure the synchronization job source value',
41
- 'integration-managed',
42
- )
43
- .option(
44
- '--scope <anystring>',
45
- 'configure the synchronization job scope value',
46
- )
47
- .option(
48
- '-u, --upload-batch-size <number>',
49
- 'specify number of items per batch for upload (default 250)',
50
- )
51
- .option(
52
- '-ur, --upload-relationship-batch-size <number>',
53
- 'specify number of relationships per batch for upload (default 250)',
54
- )
55
- .action(async (options) => {
56
- // Point `fileSystem.ts` functions to expected location relative to
57
- // integration project path.
58
- process.env.JUPITERONE_INTEGRATION_STORAGE_DIRECTORY = path.resolve(
59
- options.projectPath,
60
- '.j1-integration',
61
- );
62
-
63
- log.debug('Loading API Key from JUPITERONE_API_KEY environment variable');
64
- const accessToken = getApiKeyFromEnvironment();
65
-
66
- log.debug('Loading account from JUPITERONE_ACCOUNT environment variable');
67
- const account = getAccountFromEnvironment();
32
+ .action(async (options: OptionValues, actionCommand: Command) => {
33
+ configureRuntimeFilesystem(actionCommand.opts());
34
+ validateApiClientOptions(actionCommand.opts());
35
+ validateSyncOptions(actionCommand.opts());
68
36
 
69
- const apiBaseUrl = getApiBaseUrlOption(options);
70
- log.debug(`Configuring client to access "${apiBaseUrl}"`);
71
-
72
- const apiClient = createApiClient({
73
- apiBaseUrl,
74
- account,
75
- accessToken,
76
- });
77
-
78
- const synchronizationJobSourceOptions =
79
- getSynchronizationJobSourceOptions(options);
37
+ const clientApiOptions = getApiClientOptions(actionCommand.opts());
38
+ const apiClient = createApiClient(clientApiOptions);
39
+ log.debug(
40
+ `Configured JupiterOne API client. (apiBaseUrl: '${clientApiOptions.apiBaseUrl}', account: ${clientApiOptions.account})`,
41
+ );
80
42
 
81
43
  const logger = createIntegrationLogger({
82
44
  name: 'local',
83
45
  pretty: true,
84
46
  });
47
+
48
+ const syncOptions = getSyncOptions(actionCommand.opts());
49
+ if (syncOptions.skipFinalize)
50
+ log.info(
51
+ 'Skipping synchronization finalization. Job will remain in "AWAITING_UPLOADS" state.',
52
+ );
53
+
85
54
  const job = await synchronizeCollectedData({
86
- logger: logger.child(synchronizationJobSourceOptions),
55
+ logger: logger.child(syncOptions),
87
56
  apiClient,
88
- uploadBatchSize: options.uploadBatchSize,
89
- uploadRelationshipBatchSize: options.uploadRelationshipBatchSize,
90
- ...synchronizationJobSourceOptions,
57
+ ...syncOptions,
91
58
  });
92
59
 
93
60
  log.displaySynchronizationResults(job);
package/src/log.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  Metric,
12
12
  } from '@jupiterone/integration-sdk-core';
13
13
 
14
+ /* eslint-disable no-console */
14
15
  export function debug(msg: string) {
15
16
  console.log(`${chalk.gray(msg)}`);
16
17
  }