@ibm-cloud/cd-tools 1.2.2 → 1.2.4
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/cmd/check-secrets.js +7 -3
- package/cmd/copy-toolchain.js +6 -4
- package/cmd/utils/import-terraform.js +9 -2
- package/cmd/utils/requests.js +8 -1
- package/cmd/utils/terraform.js +9 -5
- package/cmd/utils/validate.js +10 -8
- package/config.js +59 -59
- package/index.js +3 -2
- package/package.json +2 -2
- package/test/README.md +9 -8
- package/test/config/local.template.json +2 -1
- package/test/copy-toolchain/functionalities.test.js +198 -0
- package/test/copy-toolchain/{validation.test.js → input-validation.test.js} +45 -15
- package/test/copy-toolchain/tf-import.test.js +117 -0
- package/test/copy-toolchain/tool-validation.test.js +107 -0
- package/test/data/mocks.js +21 -1
- package/test/data/test-toolchains.js +44 -6
- package/test/setup.js +22 -5
- package/test/utils/testUtils.js +109 -7
- package/test/copy-toolchain/import.test.js +0 -11
- package/test/copy-toolchain/terraform.test.js +0 -11
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ The tools are provided as an [npx](https://docs.npmjs.com/cli/commands/npx) comm
|
|
|
48
48
|
|
|
49
49
|
```shell-session
|
|
50
50
|
$ npx @ibm-cloud/cd-tools
|
|
51
|
-
Usage:
|
|
51
|
+
Usage: @ibm-cloud/cd-tools [options] [command]
|
|
52
52
|
|
|
53
53
|
Tools for migrating Toolchains, Delivery Pipelines, and Git Repos and Issue Tracking projects.
|
|
54
54
|
|
package/cmd/check-secrets.js
CHANGED
|
@@ -49,11 +49,15 @@ async function main(options) {
|
|
|
49
49
|
for (let i = 0; i < getToolsRes.tools.length; i++) {
|
|
50
50
|
const tool = getToolsRes.tools[i];
|
|
51
51
|
|
|
52
|
+
// Skip iff it's GitHub/GitLab/GRIT integration with OAuth
|
|
53
|
+
if (['githubconsolidated', 'github_integrated', 'gitlab', 'hostedgit'].includes(tool.tool_type_id) && (tool.parameters?.auth_type === '' || tool.parameters?.auth_type === 'oauth'))
|
|
54
|
+
continue;
|
|
55
|
+
|
|
52
56
|
// Check tool integrations for any plain text secret values
|
|
53
57
|
if (SECRET_KEYS_MAP[tool.tool_type_id]) {
|
|
54
58
|
SECRET_KEYS_MAP[tool.tool_type_id].forEach((entry) => {
|
|
55
59
|
const updateableSecretParam = entry.key;
|
|
56
|
-
if (tool.parameters[updateableSecretParam] && !isSecretReference(tool.parameters[updateableSecretParam])) {
|
|
60
|
+
if (tool.parameters[updateableSecretParam] && !isSecretReference(tool.parameters[updateableSecretParam]) && tool.parameters[updateableSecretParam].length > 0) {
|
|
57
61
|
toolResults.push({
|
|
58
62
|
'Tool ID': tool.id,
|
|
59
63
|
'Tool Type': tool.tool_type_id,
|
|
@@ -68,7 +72,7 @@ async function main(options) {
|
|
|
68
72
|
const pipelineData = await getPipelineData(token, tool.id, region);
|
|
69
73
|
|
|
70
74
|
pipelineData?.properties.forEach((prop) => {
|
|
71
|
-
if (prop.type === 'secure' && !isSecretReference(prop.value)) {
|
|
75
|
+
if (prop.type === 'secure' && !isSecretReference(prop.value) && prop.value.length > 0) {
|
|
72
76
|
pipelineResults.push({
|
|
73
77
|
'Pipeline ID': pipelineData.id,
|
|
74
78
|
'Trigger Name': '-',
|
|
@@ -79,7 +83,7 @@ async function main(options) {
|
|
|
79
83
|
|
|
80
84
|
pipelineData?.triggers.forEach((trigger) => {
|
|
81
85
|
trigger.properties?.forEach((prop) => {
|
|
82
|
-
if (prop.type === 'secure' && !isSecretReference(prop.value)) {
|
|
86
|
+
if (prop.type === 'secure' && !isSecretReference(prop.value) && prop.value.length > 0) {
|
|
83
87
|
pipelineResults.push({
|
|
84
88
|
'Pipeline ID': pipelineData.id,
|
|
85
89
|
'Trigger Name': trigger.name,
|
package/cmd/copy-toolchain.js
CHANGED
|
@@ -106,7 +106,7 @@ async function main(options) {
|
|
|
106
106
|
|
|
107
107
|
// check for existing .tf files in output directory
|
|
108
108
|
if (fs.existsSync(outputDir)) {
|
|
109
|
-
let files = readdirSync(outputDir, { recursive: true });
|
|
109
|
+
let files = fs.readdirSync(outputDir, { recursive: true });
|
|
110
110
|
files = files.filter((f) => f.endsWith('.tf'));
|
|
111
111
|
if (files.length > 0) throw Error(`Output directory already has ${files.length} '.tf' files, please specify a different output directory`);
|
|
112
112
|
}
|
|
@@ -237,7 +237,7 @@ async function main(options) {
|
|
|
237
237
|
}, 5000);
|
|
238
238
|
|
|
239
239
|
await initProviderFile(sourceRegion, TEMP_DIR);
|
|
240
|
-
await runTerraformInit(TEMP_DIR);
|
|
240
|
+
await runTerraformInit(TEMP_DIR, verbosity);
|
|
241
241
|
|
|
242
242
|
nonSecretRefs = await importTerraform(bearer, apiKey, sourceRegion, sourceToolchainId, targetToolchainName, policyIds, TEMP_DIR, isCompact, verbosity);
|
|
243
243
|
};
|
|
@@ -249,7 +249,8 @@ async function main(options) {
|
|
|
249
249
|
LOG_STAGES.import
|
|
250
250
|
);
|
|
251
251
|
|
|
252
|
-
if (nonSecretRefs.length > 0) logger.warn(`\nWarning! The following generated terraform resource contains
|
|
252
|
+
if (nonSecretRefs.length > 0) logger.warn(`\nWarning! The following generated terraform resource contains hashed secret(s) that cannot be migrated, applying without changes may result in error(s):`);
|
|
253
|
+
logger.table(nonSecretRefs);
|
|
253
254
|
|
|
254
255
|
} catch (err) {
|
|
255
256
|
if (err.message && err.stack) {
|
|
@@ -302,7 +303,8 @@ async function main(options) {
|
|
|
302
303
|
'Running terraform init...',
|
|
303
304
|
'Terraform successfully initialized',
|
|
304
305
|
LOG_STAGES.tf,
|
|
305
|
-
outputDir
|
|
306
|
+
outputDir,
|
|
307
|
+
verbosity
|
|
306
308
|
);
|
|
307
309
|
|
|
308
310
|
logger.info(`DRY_RUN: ${dryRun}, running terraform apply...`, LOG_STAGES.tf);
|
|
@@ -70,8 +70,15 @@ export async function importTerraform(token, apiKey, region, toolchainId, toolch
|
|
|
70
70
|
if (isSecretReference(tool.parameters[key])) {
|
|
71
71
|
additionalProps[block.name].push({ param: tfKey, value: tool.parameters[key] });
|
|
72
72
|
} else {
|
|
73
|
-
|
|
74
|
-
if (required)
|
|
73
|
+
const newFileName = SUPPORTED_TOOLS_MAP[tool.tool_type_id].split('ibm_')[1];
|
|
74
|
+
if (required) {
|
|
75
|
+
nonSecretRefs.push({
|
|
76
|
+
resource_name: block.name,
|
|
77
|
+
property_name: tfKey,
|
|
78
|
+
file_name: isCompact ? 'resources.tf' : `${newFileName}.tf`
|
|
79
|
+
});
|
|
80
|
+
additionalProps[block.name].push({ param: tfKey, value: `<${tfKey}>` });
|
|
81
|
+
}
|
|
75
82
|
}
|
|
76
83
|
});
|
|
77
84
|
}
|
package/cmd/utils/requests.js
CHANGED
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
import axios from 'axios';
|
|
11
11
|
import axiosRetry from 'axios-retry';
|
|
12
12
|
|
|
13
|
+
import mocks from '../../test/data/mocks.js'
|
|
13
14
|
import { logger, LOG_STAGES } from './logger.js';
|
|
14
15
|
|
|
16
|
+
const MOCK_ALL_REQUESTS = process.env.MOCK_ALL_REQUESTS === 'true' || 'false';
|
|
17
|
+
|
|
15
18
|
axiosRetry(axios, {
|
|
16
19
|
retries: 3,
|
|
17
20
|
retryDelay: axiosRetry.exponentialDelay,
|
|
@@ -142,6 +145,10 @@ async function getToolchainsByName(bearer, accountId, toolchainName) {
|
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
async function getCdInstanceByRegion(bearer, accountId, region) {
|
|
148
|
+
if (MOCK_ALL_REQUESTS && process.env.MOCK_GET_CD_INSTANCE_BY_REGION_SCENARIO) {
|
|
149
|
+
return mocks.getCdInstanceByRegionResponses[process.env.MOCK_GET_CD_INSTANCE_BY_REGION_SCENARIO].data.items.length > 0;
|
|
150
|
+
}
|
|
151
|
+
|
|
145
152
|
const apiBaseUrl = 'https://api.global-search-tagging.cloud.ibm.com/v3';
|
|
146
153
|
const options = {
|
|
147
154
|
url: apiBaseUrl + '/resources/search',
|
|
@@ -403,7 +410,7 @@ async function deleteToolchain(bearer, toolchainId, region) {
|
|
|
403
410
|
};
|
|
404
411
|
const response = await axios(options);
|
|
405
412
|
switch (response.status) {
|
|
406
|
-
case
|
|
413
|
+
case 204:
|
|
407
414
|
return toolchainId;
|
|
408
415
|
default:
|
|
409
416
|
throw Error(response.statusText);
|
package/cmd/utils/terraform.js
CHANGED
|
@@ -15,7 +15,7 @@ import { parse as tfToJson } from '@cdktf/hcl2json'
|
|
|
15
15
|
import { jsonToTf } from 'json-to-tf';
|
|
16
16
|
|
|
17
17
|
import { validateToolchainId, validateGritUrl } from './validate.js';
|
|
18
|
-
import { logger } from './logger.js';
|
|
18
|
+
import { logger, LOG_STAGES } from './logger.js';
|
|
19
19
|
import { getRandChars, promptUserInput, replaceUrlRegion } from './utils.js';
|
|
20
20
|
|
|
21
21
|
// promisify
|
|
@@ -300,12 +300,16 @@ async function setupTerraformFiles({ token, srcRegion, targetRegion, targetTag,
|
|
|
300
300
|
return Promise.all(promises);
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
-
async function
|
|
304
|
-
|
|
303
|
+
async function runTerraformInit(dir, verbosity) {
|
|
304
|
+
logger.log('Running command \'terraform init\'', LOG_STAGES.tf);
|
|
305
|
+
const out = await execPromise('terraform init', { cwd: dir });
|
|
306
|
+
if (verbosity >= 2) logger.print(out, '\n');
|
|
307
|
+
logger.log('Command \'terraform init\' completed', LOG_STAGES.tf);
|
|
308
|
+
return out;
|
|
305
309
|
}
|
|
306
310
|
|
|
307
|
-
async function
|
|
308
|
-
return await execPromise(
|
|
311
|
+
async function runTerraformPlanGenerate(dir, fileName) {
|
|
312
|
+
return await execPromise(`terraform plan -generate-config-out="${fileName}"`, { cwd: dir });
|
|
309
313
|
}
|
|
310
314
|
|
|
311
315
|
// primarily used to get number of resources to be used
|
package/cmd/utils/validate.js
CHANGED
|
@@ -11,7 +11,7 @@ import { execSync } from 'child_process';
|
|
|
11
11
|
import { logger, LOG_STAGES } from './logger.js'
|
|
12
12
|
import { RESERVED_GRIT_PROJECT_NAMES, RESERVED_GRIT_GROUP_NAMES, RESERVED_GRIT_SUBGROUP_NAME, TERRAFORM_REQUIRED_VERSION, SECRET_KEYS_MAP } from '../../config.js';
|
|
13
13
|
import { getToolchainsByName, getToolchainTools, getPipelineData, getAppConfigHealthcheck, getSecretsHealthcheck, getGitOAuth, getGritUserProject, getGritGroup, getGritGroupProject } from './requests.js';
|
|
14
|
-
import { promptUserConfirmation, promptUserInput } from './utils.js';
|
|
14
|
+
import { promptUserConfirmation, promptUserInput, isSecretReference } from './utils.js';
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
function validatePrereqsVersions() {
|
|
@@ -146,7 +146,6 @@ async function validateTools(token, tcId, region, skipPrompt) {
|
|
|
146
146
|
const toolsWithHashedParams = [];
|
|
147
147
|
const patTools = [];
|
|
148
148
|
const classicPipelines = [];
|
|
149
|
-
const secretPattern = /^hash:SHA3-512:[a-zA-Z0-9]{128}$/;
|
|
150
149
|
|
|
151
150
|
for (const tool of allTools.tools) {
|
|
152
151
|
const toolName = (tool.name || tool.parameters?.name || tool.parameters?.label || '').replace(/\s+/g, '+');
|
|
@@ -203,7 +202,7 @@ async function validateTools(token, tcId, region, skipPrompt) {
|
|
|
203
202
|
url: toolUrl
|
|
204
203
|
});
|
|
205
204
|
}
|
|
206
|
-
else if (['githubconsolidated', 'github_integrated', 'gitlab'].includes(tool.tool_type_id) && (tool.parameters?.auth_type === '' || tool.parameters?.auth_type === 'oauth')) {
|
|
205
|
+
else if (['githubconsolidated', 'github_integrated', 'gitlab', 'hostedgit'].includes(tool.tool_type_id) && (tool.parameters?.auth_type === '' || tool.parameters?.auth_type === 'oauth')) { // Skip secret check iff it's GitHub/GitLab/GRIT integration with OAuth
|
|
207
206
|
continue;
|
|
208
207
|
}
|
|
209
208
|
else {
|
|
@@ -212,20 +211,23 @@ async function validateTools(token, tcId, region, skipPrompt) {
|
|
|
212
211
|
const pipelineData = await getPipelineData(token, tool.id, region);
|
|
213
212
|
|
|
214
213
|
pipelineData.properties.forEach((prop) => {
|
|
215
|
-
if (prop.type === 'secure' &&
|
|
214
|
+
if (prop.type === 'secure' && !isSecretReference(prop.value) && prop.value.length > 0)
|
|
215
|
+
secrets.push(['properties', prop.name].join('.').replace(/\s+/g, '+'));
|
|
216
216
|
});
|
|
217
217
|
|
|
218
218
|
pipelineData.triggers.forEach((trigger) => {
|
|
219
|
-
if ((trigger?.secret?.type === 'token_matches' || trigger?.secret?.type === 'digest_matches') &&
|
|
219
|
+
if ((trigger?.secret?.type === 'token_matches' || trigger?.secret?.type === 'digest_matches') && !isSecretReference(trigger.secret.value) && trigger.secret.value.length > 0)
|
|
220
|
+
secrets.push([trigger.name, trigger.secret.key_name].join('.').replace(/\s+/g, '+'));
|
|
220
221
|
trigger.properties.forEach((prop) => {
|
|
221
|
-
if (prop.type === 'secure' &&
|
|
222
|
+
if (prop.type === 'secure' && !isSecretReference(prop.value) && prop.value.length > 0)
|
|
223
|
+
secrets.push([trigger.name, 'properties', prop.name].join('.').replace(/\s+/g, '+'));
|
|
222
224
|
});
|
|
223
225
|
});
|
|
224
226
|
}
|
|
225
227
|
else {
|
|
226
228
|
const secretsToCheck = (SECRET_KEYS_MAP[tool.tool_type_id] || []).map((entry) => entry.key); // Check for secrets in the rest of the tools
|
|
227
229
|
Object.entries(tool.parameters).forEach(([key, value]) => {
|
|
228
|
-
if (
|
|
230
|
+
if (!isSecretReference(value) && value.length > 0 && secretsToCheck.includes(key)) secrets.push(key);
|
|
229
231
|
});
|
|
230
232
|
}
|
|
231
233
|
if (secrets.length > 0) {
|
|
@@ -260,7 +262,7 @@ async function validateTools(token, tcId, region, skipPrompt) {
|
|
|
260
262
|
}
|
|
261
263
|
|
|
262
264
|
if (toolsWithHashedParams.length > 0) {
|
|
263
|
-
logger.warn('Warning! The following tools contain secrets that cannot be migrated, please use the \'check-
|
|
265
|
+
logger.warn('Warning! The following tools contain secrets that cannot be migrated, please use the \'check-secrets\' command to export the secrets: \n', LOG_STAGES.setup, true);
|
|
264
266
|
logger.table(toolsWithHashedParams);
|
|
265
267
|
}
|
|
266
268
|
|
package/config.js
CHANGED
|
@@ -126,90 +126,90 @@ Format:
|
|
|
126
126
|
{
|
|
127
127
|
key: str, // tool parameter key
|
|
128
128
|
tfKey?: str, // terraform-equivalent key
|
|
129
|
-
prereq?: { key: string, values: [string] }, // proceed only if tool parameter
|
|
129
|
+
prereq?: { key: string, values: [string] }, // proceed only if tool parameter 'prereq.key' is one of 'values'
|
|
130
130
|
required?: bool // is this key required for terraform?
|
|
131
131
|
}
|
|
132
132
|
... which represents a secret/sensitive value
|
|
133
133
|
*/
|
|
134
134
|
const SECRET_KEYS_MAP = {
|
|
135
|
-
|
|
136
|
-
{ key:
|
|
135
|
+
'artifactory': [
|
|
136
|
+
{ key: 'token', tfKey: 'token' }
|
|
137
137
|
],
|
|
138
|
-
|
|
139
|
-
{ key:
|
|
140
|
-
{ key:
|
|
141
|
-
{ key:
|
|
138
|
+
'cloudobjectstorage': [
|
|
139
|
+
{ key: 'cos_api_key', tfKey: 'cos_api_key', prereq: { key: 'auth_type', values: ['apikey'] } },
|
|
140
|
+
{ key: 'hmac_access_key_id', tfKey: 'hmac_access_key_id', prereq: { key: 'auth_type', values: ['hmac'] } },
|
|
141
|
+
{ key: 'hmac_secret_access_key', tfKey: 'hmac_secret_access_key', prereq: { key: 'auth_type', values: ['hmac'] } },
|
|
142
142
|
],
|
|
143
|
-
|
|
144
|
-
{ key:
|
|
143
|
+
'github_integrated': [
|
|
144
|
+
{ key: 'api_token' } // no terraform equivalent
|
|
145
145
|
],
|
|
146
|
-
|
|
147
|
-
{ key:
|
|
146
|
+
'githubconsolidated': [
|
|
147
|
+
{ key: 'api_token', tfKey: 'api_token', prereq: { key: 'auth_type', values: ['pat'] } },
|
|
148
148
|
],
|
|
149
|
-
|
|
150
|
-
{ key:
|
|
149
|
+
'gitlab': [
|
|
150
|
+
{ key: 'api_token', tfKey: 'api_token', prereq: { key: 'auth_type', values: ['pat'] } },
|
|
151
151
|
],
|
|
152
|
-
|
|
153
|
-
{ key:
|
|
154
|
-
{ key:
|
|
155
|
-
{ key:
|
|
156
|
-
{ key:
|
|
152
|
+
'hashicorpvault': [
|
|
153
|
+
{ key: 'token', tfKey: 'token', prereq: { key: 'authentication_method', values: ['github', 'token'] } },
|
|
154
|
+
{ key: 'role_id', tfKey: 'role_id', prereq: { key: 'authentication_method', values: ['approle'] } },
|
|
155
|
+
{ key: 'secret_id', tfKey: 'secret_id', prereq: { key: 'authentication_method', values: ['approle'] } },
|
|
156
|
+
{ key: 'password', tfKey: 'password', prereq: { key: 'authentication_method', values: ['userpass'] } },
|
|
157
157
|
],
|
|
158
|
-
|
|
159
|
-
{ key:
|
|
158
|
+
'hostedgit': [
|
|
159
|
+
{ key: 'api_token', tfKey: 'api_token', prereq: { key: 'auth_type', values: ['pat'] } },
|
|
160
160
|
],
|
|
161
|
-
|
|
162
|
-
{ key:
|
|
161
|
+
'jenkins': [
|
|
162
|
+
{ key: 'api_token', tfKey: 'api_token' },
|
|
163
163
|
],
|
|
164
|
-
|
|
165
|
-
{ key:
|
|
164
|
+
'jira': [
|
|
165
|
+
{ key: 'password', tfKey: 'api_token' },
|
|
166
166
|
],
|
|
167
|
-
|
|
168
|
-
{ key:
|
|
167
|
+
'nexus': [
|
|
168
|
+
{ key: 'token', tfKey: 'token' },
|
|
169
169
|
],
|
|
170
|
-
|
|
171
|
-
{ key:
|
|
170
|
+
'pagerduty': [
|
|
171
|
+
{ key: 'service_key', tfKey: 'service_key', required: true },
|
|
172
172
|
],
|
|
173
|
-
|
|
174
|
-
{ key:
|
|
173
|
+
'private_worker': [
|
|
174
|
+
{ key: 'workerQueueCredentials', tfKey: 'worker_queue_credentials', required: true },
|
|
175
175
|
],
|
|
176
|
-
|
|
177
|
-
{ key:
|
|
176
|
+
'saucelabs': [
|
|
177
|
+
{ key: 'key', tfKey: 'access_key', required: true },
|
|
178
178
|
],
|
|
179
|
-
|
|
180
|
-
{ key:
|
|
179
|
+
'security_compliance': [
|
|
180
|
+
{ key: 'scc_api_key', tfKey: 'scc_api_key', prereq: { key: 'use_profile_attachment', values: ['enabled'] } },
|
|
181
181
|
],
|
|
182
|
-
|
|
183
|
-
{ key:
|
|
182
|
+
'slack': [
|
|
183
|
+
{ key: 'api_token', tfKey: 'webhook', required: true },
|
|
184
184
|
],
|
|
185
|
-
|
|
186
|
-
{ key:
|
|
185
|
+
'sonarqube': [
|
|
186
|
+
{ key: 'user_password', tfKey: 'user_password' },
|
|
187
187
|
]
|
|
188
188
|
};
|
|
189
189
|
|
|
190
190
|
// maps tool parameter tool_type_id to terraform resource type
|
|
191
191
|
const SUPPORTED_TOOLS_MAP = {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
192
|
+
'appconfig': 'ibm_cd_toolchain_tool_appconfig',
|
|
193
|
+
'artifactory': 'ibm_cd_toolchain_tool_artifactory',
|
|
194
|
+
'bitbucketgit': 'ibm_cd_toolchain_tool_bitbucketgit',
|
|
195
|
+
'private_worker': 'ibm_cd_toolchain_tool_privateworker',
|
|
196
|
+
'draservicebroker': 'ibm_cd_toolchain_tool_devopsinsights',
|
|
197
|
+
'eventnotifications': 'ibm_cd_toolchain_tool_eventnotifications',
|
|
198
|
+
'hostedgit': 'ibm_cd_toolchain_tool_hostedgit',
|
|
199
|
+
'githubconsolidated': 'ibm_cd_toolchain_tool_githubconsolidated',
|
|
200
|
+
'gitlab': 'ibm_cd_toolchain_tool_gitlab',
|
|
201
|
+
'hashicorpvault': 'ibm_cd_toolchain_tool_hashicorpvault',
|
|
202
|
+
'jenkins': 'ibm_cd_toolchain_tool_jenkins',
|
|
203
|
+
'jira': 'ibm_cd_toolchain_tool_jira',
|
|
204
|
+
'keyprotect': 'ibm_cd_toolchain_tool_keyprotect',
|
|
205
|
+
'nexus': 'ibm_cd_toolchain_tool_nexus',
|
|
206
|
+
'customtool': 'ibm_cd_toolchain_tool_custom',
|
|
207
|
+
'saucelabs': 'ibm_cd_toolchain_tool_saucelabs',
|
|
208
|
+
'secretsmanager': 'ibm_cd_toolchain_tool_secretsmanager',
|
|
209
|
+
'security_compliance': 'ibm_cd_toolchain_tool_securitycompliance',
|
|
210
|
+
'slack': 'ibm_cd_toolchain_tool_slack',
|
|
211
|
+
'sonarqube': 'ibm_cd_toolchain_tool_sonarqube',
|
|
212
|
+
'pipeline': 'ibm_cd_toolchain_tool_pipeline'
|
|
213
213
|
};
|
|
214
214
|
|
|
215
215
|
const VAULT_REGEX = [
|
package/index.js
CHANGED
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
import { program } from 'commander';
|
|
12
12
|
import * as commands from './cmd/index.js'
|
|
13
|
+
import packageJson from './package.json' with { type: "json" };
|
|
13
14
|
|
|
14
15
|
program
|
|
15
|
-
.name('index.js')
|
|
16
|
+
.name(process.env.npm_package_name ?? 'index.js')
|
|
16
17
|
.description('Tools and utilities for the IBM Cloud Continuous Delivery service and resources.')
|
|
17
|
-
.version(
|
|
18
|
+
.version(packageJson.version)
|
|
18
19
|
.showHelpAfterError();
|
|
19
20
|
|
|
20
21
|
for (let i in commands) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ibm-cloud/cd-tools",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.4",
|
|
4
4
|
"description": "Tools and utilities for the IBM Cloud Continuous Delivery service and resources",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"author": "IBM Corp.",
|
|
16
16
|
"license": "Apache-2.0",
|
|
17
17
|
"scripts": {
|
|
18
|
-
"test": "mocha --require \"test/setup.js\" \"test/copy-toolchain/*.test.js\""
|
|
18
|
+
"test": "mocha --require \"test/setup.js\" --retries 3 --parallel \"test/copy-toolchain/*.test.js\""
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@cdktf/hcl2json": "^0.21.0",
|
package/test/README.md
CHANGED
|
@@ -30,11 +30,12 @@ Before running tests, ensure that you have completed the setup steps in the main
|
|
|
30
30
|
### Test Configuration
|
|
31
31
|
You can customize the behavior of the tests by defining configuration properties in the `test/config/local.json` file.
|
|
32
32
|
|
|
33
|
-
| Property | Type | Default
|
|
34
|
-
| ------------------ | --------- |
|
|
35
|
-
| `TEST_DEBUG_MODE` | `boolean` | `false`
|
|
36
|
-
| `TEST_TEMP_DIR` | `string` | `test/.tmp`
|
|
37
|
-
| `TEST_LOG_DIR` | `string` | `test/.logs` | The directory to store test run log files |
|
|
38
|
-
| `IBMCLOUD_API_KEY` | `string` | `null`
|
|
39
|
-
| `LOG_DUMP` | `boolean` | `false`
|
|
40
|
-
| `DISABLE_SPINNER` | `boolean` | `true`
|
|
33
|
+
| Property | Type | Default | Description |
|
|
34
|
+
| ------------------ | --------- | ------------------| ---------------------------------------------------------------------------------------------------------------------------- |
|
|
35
|
+
| `TEST_DEBUG_MODE` | `boolean` | `false` | When set to `true`, files generated by test cases in `TEST_TEMP_DIR` and log files generated in `TEST_LOG_DIR` are preserved |
|
|
36
|
+
| `TEST_TEMP_DIR` | `string` | `test/.tmp` | The directory to store temporary files generated by test cases |
|
|
37
|
+
| `TEST_LOG_DIR` | `string` | `test/.test-logs` | The directory to store test run log files |
|
|
38
|
+
| `IBMCLOUD_API_KEY` | `string` | `null` | The IBM Cloud API Key used to run the tests |
|
|
39
|
+
| `LOG_DUMP` | `boolean` | `false` | When set to `true`, individual test case's process's log file generation is enabled |
|
|
40
|
+
| `DISABLE_SPINNER` | `boolean` | `true` | When set to `true`, visual spinner is disabled across all test cases' processes |
|
|
41
|
+
| `VERBOSE_MODE` | `boolean` | `false` | When set to `true`, each test case's log output increases |
|