@peernova/cuneiform-sf 1.0.2 → 1.0.3-beta.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.
- package/lib/commands/cuneiform/definition/export.d.ts +48 -0
- package/lib/commands/cuneiform/definition/export.js +97 -0
- package/lib/commands/cuneiform/definition/export.js.map +1 -0
- package/lib/commands/cuneiform/definition/import.d.ts +49 -0
- package/lib/commands/cuneiform/definition/import.js +107 -0
- package/lib/commands/cuneiform/definition/import.js.map +1 -0
- package/lib/models/sfdmu-types.d.ts +74 -0
- package/lib/models/sfdmu-types.js +19 -0
- package/lib/models/sfdmu-types.js.map +1 -0
- package/lib/operations/DefinitionExportOperation.d.ts +92 -0
- package/lib/operations/DefinitionExportOperation.js +197 -0
- package/lib/operations/DefinitionExportOperation.js.map +1 -0
- package/lib/operations/DefinitionImportOperation.d.ts +94 -0
- package/lib/operations/DefinitionImportOperation.js +194 -0
- package/lib/operations/DefinitionImportOperation.js.map +1 -0
- package/lib/services/SFDMUService.d.ts +119 -0
- package/lib/services/SFDMUService.js +262 -0
- package/lib/services/SFDMUService.js.map +1 -0
- package/messages/definition.export.md +41 -0
- package/messages/definition.import.md +48 -0
- package/oclif.lock +4978 -1335
- package/oclif.manifest.json +168 -1
- package/package.json +10 -6
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026, PeerNova Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
4
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import { SfError } from '@salesforce/core';
|
|
9
|
+
/**
|
|
10
|
+
* Error codes specific to export operations.
|
|
11
|
+
*/
|
|
12
|
+
export const ExportErrorCodes = {
|
|
13
|
+
/** Output directory already exists */
|
|
14
|
+
OUTPUT_DIR_EXISTS: 'EXPORT_OUTPUT_DIR_EXISTS',
|
|
15
|
+
/** No definitions found in org */
|
|
16
|
+
NO_DEFINITIONS_FOUND: 'EXPORT_NO_DEFINITIONS_FOUND',
|
|
17
|
+
/** Failed to create output directory */
|
|
18
|
+
DIR_CREATION_FAILED: 'EXPORT_DIR_CREATION_FAILED',
|
|
19
|
+
/** Failed to write config file */
|
|
20
|
+
CONFIG_WRITE_FAILED: 'EXPORT_CONFIG_WRITE_FAILED',
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Orchestrates the export of profiling definitions using SFDMU.
|
|
24
|
+
*
|
|
25
|
+
* Follows the 4-layer architecture: Command → Operation → Service → API
|
|
26
|
+
* This operation layer handles business logic orchestration while delegating
|
|
27
|
+
* the actual SFDMU execution to SFDMUService.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const operation = new DefinitionExportOperation(sfdmuService);
|
|
32
|
+
* const result = await operation.execute({
|
|
33
|
+
* targetOrg: 'myOrg',
|
|
34
|
+
* outputDir: './exports',
|
|
35
|
+
* excludeIds: true
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class DefinitionExportOperation {
|
|
40
|
+
/** Default base path for exports */
|
|
41
|
+
static DEFAULT_EXPORT_BASE = './data/exports/definitions';
|
|
42
|
+
/** SFDMU query for profiling definitions */
|
|
43
|
+
static DEFINITION_QUERY = 'SELECT Id, Name, RecordTypeId, pnova__Agg_Status__c, pnova__Agg_StatusStatistical__c, pnova__Aud_VersionCRMBase__c, pnova__Aud_VersionCRMEnterprise__c, pnova__Aud_VersionDCBase__c, pnova__Profiling_IsProfileForAllFields__c, pnova__Profiling_IsProfileForAllRecords__c, pnova__Prop_Category__c, pnova__Prop_Description__c, pnova__Prop_Filter_JSON_SetA__c, pnova__Prop_Filter_JSON_SetB__c, pnova__Prop_Filter_SetA__c, pnova__Prop_Filter_SetB__c, pnova__Prop_InsightGroups_JSON__c, pnova__Prop_IsActive__c, pnova__Prop_IsFiltered_SetA__c, pnova__Prop_IsFiltered_SetB__c, pnova__Prop_IsNotificationEnabled__c, pnova__Prop_IsProfilingLaunchedFromWizard__c, pnova__Prop_KpiBusinessImpact__c, pnova__Prop_KpiBusinessImpact_JSON__c, pnova__Prop_KpiDataQuality__c, pnova__Prop_KpiDataQuality_JSON__c, pnova__Prop_AreKpisDefined__c, pnova__Prop_LicenseViolations__c, pnova__Prop_Name__c, pnova__Prop_SelectedFields__c, pnova__Prop_SelectedFields_JSON__c, pnova__Prop_SelectedFieldsCount__c, pnova__Prop_SObjectApiName__c, pnova__Prop_SObjectFullApiName__c, pnova__Prop_SObjectLabel__c, pnova__Prop_SObjectRecordTypeId__c, pnova__Prop_SObjectRecordTypeLabel__c FROM pnova__Profiling_Definition__c';
|
|
44
|
+
sfdmuService;
|
|
45
|
+
logger;
|
|
46
|
+
/**
|
|
47
|
+
* Creates a new DefinitionExportOperation.
|
|
48
|
+
*
|
|
49
|
+
* @param sfdmuService - The SFDMU service instance for executing operations
|
|
50
|
+
* @param logger - Optional logger for debug output
|
|
51
|
+
*/
|
|
52
|
+
constructor(sfdmuService, logger) {
|
|
53
|
+
this.sfdmuService = sfdmuService;
|
|
54
|
+
this.logger = logger;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolves the output path, generating a timestamped directory if needed.
|
|
58
|
+
*/
|
|
59
|
+
static resolveOutputPath(outputDir) {
|
|
60
|
+
if (outputDir) {
|
|
61
|
+
return path.resolve(outputDir);
|
|
62
|
+
}
|
|
63
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
64
|
+
return path.resolve(DefinitionExportOperation.DEFAULT_EXPORT_BASE, timestamp);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Builds the SFDMU export configuration.
|
|
68
|
+
*/
|
|
69
|
+
static buildSFDMUConfig(excludeIds) {
|
|
70
|
+
const config = {
|
|
71
|
+
objects: [
|
|
72
|
+
{
|
|
73
|
+
query: DefinitionExportOperation.DEFINITION_QUERY,
|
|
74
|
+
operation: 'Readonly',
|
|
75
|
+
externalId: 'Name',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
if (excludeIds) {
|
|
80
|
+
config.excludeIdsFromCSVFiles = true;
|
|
81
|
+
}
|
|
82
|
+
return config;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Collects the list of files created by SFDMU export.
|
|
86
|
+
*/
|
|
87
|
+
static collectExportedFiles(outputPath) {
|
|
88
|
+
try {
|
|
89
|
+
return fs.readdirSync(outputPath).filter((file) => !file.startsWith('.'));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Executes the export operation.
|
|
97
|
+
*
|
|
98
|
+
* @param options - Export options
|
|
99
|
+
* @returns ServiceResult containing export results or error details
|
|
100
|
+
*/
|
|
101
|
+
async execute(options) {
|
|
102
|
+
const startTime = Date.now();
|
|
103
|
+
try {
|
|
104
|
+
// Generate timestamped output directory
|
|
105
|
+
const outputPath = DefinitionExportOperation.resolveOutputPath(options.outputDir);
|
|
106
|
+
// Verify output directory doesn't exist (prevent accidental overwrite)
|
|
107
|
+
if (fs.existsSync(outputPath)) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
data: {
|
|
111
|
+
definitionsExported: 0,
|
|
112
|
+
outputPath,
|
|
113
|
+
files: [],
|
|
114
|
+
},
|
|
115
|
+
errorCode: ExportErrorCodes.OUTPUT_DIR_EXISTS,
|
|
116
|
+
message: `Output directory already exists: ${outputPath}. Use a different path or remove existing directory.`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// Create output directory
|
|
120
|
+
this.logger?.log(`Creating output directory: ${outputPath}`);
|
|
121
|
+
fs.mkdirSync(outputPath, { recursive: true });
|
|
122
|
+
// Generate and write SFDMU config
|
|
123
|
+
const configPath = path.join(outputPath, 'export.json');
|
|
124
|
+
const config = DefinitionExportOperation.buildSFDMUConfig(options.excludeIds ?? false);
|
|
125
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
126
|
+
this.logger?.log(`Wrote SFDMU config to: ${configPath}`);
|
|
127
|
+
// Execute SFDMU export
|
|
128
|
+
const sfdmuResult = await this.sfdmuService.runExport({
|
|
129
|
+
sourceOrg: options.targetOrg,
|
|
130
|
+
configPath: outputPath,
|
|
131
|
+
});
|
|
132
|
+
if (!sfdmuResult.success) {
|
|
133
|
+
return {
|
|
134
|
+
success: false,
|
|
135
|
+
data: {
|
|
136
|
+
definitionsExported: 0,
|
|
137
|
+
outputPath,
|
|
138
|
+
files: ['export.json'],
|
|
139
|
+
sfdmuOutput: sfdmuResult.data.stderr,
|
|
140
|
+
},
|
|
141
|
+
errorCode: sfdmuResult.errorCode,
|
|
142
|
+
message: sfdmuResult.message ?? 'SFDMU export failed',
|
|
143
|
+
metadata: {
|
|
144
|
+
duration: Date.now() - startTime,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// Collect created files
|
|
149
|
+
const files = DefinitionExportOperation.collectExportedFiles(outputPath);
|
|
150
|
+
// Write export metadata
|
|
151
|
+
const metadataPath = path.join(outputPath, 'export-metadata.json');
|
|
152
|
+
const metadata = {
|
|
153
|
+
exportedAt: new Date().toISOString(),
|
|
154
|
+
sourceOrg: options.targetOrg,
|
|
155
|
+
excludeIds: options.excludeIds ?? false,
|
|
156
|
+
recordsExported: sfdmuResult.data.recordsProcessed ?? 0,
|
|
157
|
+
files,
|
|
158
|
+
};
|
|
159
|
+
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
|
|
160
|
+
files.push('export-metadata.json');
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
data: {
|
|
164
|
+
definitionsExported: sfdmuResult.data.recordsProcessed ?? 0,
|
|
165
|
+
outputPath,
|
|
166
|
+
files,
|
|
167
|
+
sfdmuOutput: sfdmuResult.data.stdout,
|
|
168
|
+
},
|
|
169
|
+
message: `Successfully exported ${sfdmuResult.data.recordsProcessed ?? 0} definitions to ${outputPath}`,
|
|
170
|
+
warnings: sfdmuResult.warnings,
|
|
171
|
+
metadata: {
|
|
172
|
+
duration: Date.now() - startTime,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
const duration = Date.now() - startTime;
|
|
178
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
179
|
+
if (errorMessage.includes('ENOENT') || errorMessage.includes('permission denied')) {
|
|
180
|
+
return {
|
|
181
|
+
success: false,
|
|
182
|
+
data: {
|
|
183
|
+
definitionsExported: 0,
|
|
184
|
+
// Normalize path for cross-platform consistency
|
|
185
|
+
outputPath: path.normalize(options.outputDir ?? DefinitionExportOperation.DEFAULT_EXPORT_BASE),
|
|
186
|
+
files: [],
|
|
187
|
+
},
|
|
188
|
+
errorCode: ExportErrorCodes.DIR_CREATION_FAILED,
|
|
189
|
+
message: `Failed to create output directory: ${errorMessage}`,
|
|
190
|
+
metadata: { duration },
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
throw new SfError(`Export operation failed: ${errorMessage}`, 'ExportOperationError');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=DefinitionExportOperation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefinitionExportOperation.js","sourceRoot":"","sources":["../../src/operations/DefinitionExportOperation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { type ServiceResult } from '../models/sfdmu-types.js';
|
|
2
|
+
import { SFDMUService } from '../services/SFDMUService.js';
|
|
3
|
+
/**
|
|
4
|
+
* SFDMU operation types for import.
|
|
5
|
+
*/
|
|
6
|
+
export type ImportOperationType = 'Insert' | 'Upsert';
|
|
7
|
+
/**
|
|
8
|
+
* Options for the definition import operation.
|
|
9
|
+
*/
|
|
10
|
+
export type ImportOptions = {
|
|
11
|
+
/** Target org username or alias to import into */
|
|
12
|
+
targetOrg: string;
|
|
13
|
+
/** Source directory containing CSV files and export.json */
|
|
14
|
+
sourceDir: string;
|
|
15
|
+
/** SFDMU operation type (Insert or Upsert) */
|
|
16
|
+
operation?: ImportOperationType;
|
|
17
|
+
/** Dry-run mode - validate without making changes */
|
|
18
|
+
dryRun?: boolean;
|
|
19
|
+
/** Optional logger for debug output */
|
|
20
|
+
logger?: Console;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Result of a definition import operation.
|
|
24
|
+
*/
|
|
25
|
+
export type ImportResult = {
|
|
26
|
+
/** Number of definitions imported */
|
|
27
|
+
definitionsImported: number;
|
|
28
|
+
/** Source directory used */
|
|
29
|
+
sourceDir: string;
|
|
30
|
+
/** Whether this was a dry run */
|
|
31
|
+
dryRun: boolean;
|
|
32
|
+
/** Raw SFDMU output for debugging */
|
|
33
|
+
sfdmuOutput?: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Error codes specific to import operations.
|
|
37
|
+
*/
|
|
38
|
+
export declare const ImportErrorCodes: {
|
|
39
|
+
/** Source directory does not exist */
|
|
40
|
+
readonly SOURCE_NOT_FOUND: "IMPORT_SOURCE_NOT_FOUND";
|
|
41
|
+
/** Source directory is missing required files */
|
|
42
|
+
readonly INVALID_SOURCE: "IMPORT_INVALID_SOURCE";
|
|
43
|
+
/** Failed to write config file */
|
|
44
|
+
readonly CONFIG_WRITE_FAILED: "IMPORT_CONFIG_WRITE_FAILED";
|
|
45
|
+
/** Import operation failed */
|
|
46
|
+
readonly IMPORT_FAILED: "IMPORT_FAILED";
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Orchestrates the import of profiling definitions using SFDMU.
|
|
50
|
+
*
|
|
51
|
+
* Follows the 4-layer architecture: Command → Operation → Service → API
|
|
52
|
+
* This operation layer handles business logic orchestration while delegating
|
|
53
|
+
* the actual SFDMU execution to SFDMUService.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const operation = new DefinitionImportOperation(sfdmuService);
|
|
58
|
+
* const result = await operation.execute({
|
|
59
|
+
* targetOrg: 'myOrg',
|
|
60
|
+
* sourceDir: './backup/definitions',
|
|
61
|
+
* operation: 'Upsert',
|
|
62
|
+
* dryRun: true
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare class DefinitionImportOperation {
|
|
67
|
+
/** SFDMU query for profiling definitions (used in config generation) */
|
|
68
|
+
private static readonly DEFINITION_QUERY;
|
|
69
|
+
/** Expected CSV file name */
|
|
70
|
+
private static readonly DEFINITION_CSV;
|
|
71
|
+
private readonly sfdmuService;
|
|
72
|
+
private readonly logger?;
|
|
73
|
+
/**
|
|
74
|
+
* Creates a new DefinitionImportOperation.
|
|
75
|
+
*
|
|
76
|
+
* @param sfdmuService - The SFDMU service instance for executing operations
|
|
77
|
+
* @param logger - Optional logger for debug output
|
|
78
|
+
*/
|
|
79
|
+
constructor(sfdmuService: SFDMUService, logger?: Console);
|
|
80
|
+
/**
|
|
81
|
+
* Builds the SFDMU import configuration.
|
|
82
|
+
*
|
|
83
|
+
* @param operation - The import operation type (Insert or Upsert)
|
|
84
|
+
* @returns SFDMU configuration object
|
|
85
|
+
*/
|
|
86
|
+
private static buildSFDMUConfig;
|
|
87
|
+
/**
|
|
88
|
+
* Executes the import operation.
|
|
89
|
+
*
|
|
90
|
+
* @param options - Import options
|
|
91
|
+
* @returns ServiceResult containing import results or error details
|
|
92
|
+
*/
|
|
93
|
+
execute(options: ImportOptions): Promise<ServiceResult<ImportResult>>;
|
|
94
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026, PeerNova Inc. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
4
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import * as os from 'node:os';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import { SfError } from '@salesforce/core';
|
|
10
|
+
/**
|
|
11
|
+
* Error codes specific to import operations.
|
|
12
|
+
*/
|
|
13
|
+
export const ImportErrorCodes = {
|
|
14
|
+
/** Source directory does not exist */
|
|
15
|
+
SOURCE_NOT_FOUND: 'IMPORT_SOURCE_NOT_FOUND',
|
|
16
|
+
/** Source directory is missing required files */
|
|
17
|
+
INVALID_SOURCE: 'IMPORT_INVALID_SOURCE',
|
|
18
|
+
/** Failed to write config file */
|
|
19
|
+
CONFIG_WRITE_FAILED: 'IMPORT_CONFIG_WRITE_FAILED',
|
|
20
|
+
/** Import operation failed */
|
|
21
|
+
IMPORT_FAILED: 'IMPORT_FAILED',
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Orchestrates the import of profiling definitions using SFDMU.
|
|
25
|
+
*
|
|
26
|
+
* Follows the 4-layer architecture: Command → Operation → Service → API
|
|
27
|
+
* This operation layer handles business logic orchestration while delegating
|
|
28
|
+
* the actual SFDMU execution to SFDMUService.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const operation = new DefinitionImportOperation(sfdmuService);
|
|
33
|
+
* const result = await operation.execute({
|
|
34
|
+
* targetOrg: 'myOrg',
|
|
35
|
+
* sourceDir: './backup/definitions',
|
|
36
|
+
* operation: 'Upsert',
|
|
37
|
+
* dryRun: true
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export class DefinitionImportOperation {
|
|
42
|
+
/** SFDMU query for profiling definitions (used in config generation) */
|
|
43
|
+
static DEFINITION_QUERY = 'SELECT Id, Name, RecordTypeId, pnova__Agg_Status__c, pnova__Agg_StatusStatistical__c, pnova__Aud_VersionCRMBase__c, pnova__Aud_VersionCRMEnterprise__c, pnova__Aud_VersionDCBase__c, pnova__Profiling_IsProfileForAllFields__c, pnova__Profiling_IsProfileForAllRecords__c, pnova__Prop_Category__c, pnova__Prop_Description__c, pnova__Prop_Filter_JSON_SetA__c, pnova__Prop_Filter_JSON_SetB__c, pnova__Prop_Filter_SetA__c, pnova__Prop_Filter_SetB__c, pnova__Prop_InsightGroups_JSON__c, pnova__Prop_IsActive__c, pnova__Prop_IsFiltered_SetA__c, pnova__Prop_IsFiltered_SetB__c, pnova__Prop_IsNotificationEnabled__c, pnova__Prop_IsProfilingLaunchedFromWizard__c, pnova__Prop_KpiBusinessImpact__c, pnova__Prop_KpiBusinessImpact_JSON__c, pnova__Prop_KpiDataQuality__c, pnova__Prop_KpiDataQuality_JSON__c, pnova__Prop_AreKpisDefined__c, pnova__Prop_LicenseViolations__c, pnova__Prop_Name__c, pnova__Prop_SelectedFields__c, pnova__Prop_SelectedFields_JSON__c, pnova__Prop_SelectedFieldsCount__c, pnova__Prop_SObjectApiName__c, pnova__Prop_SObjectFullApiName__c, pnova__Prop_SObjectLabel__c, pnova__Prop_SObjectRecordTypeId__c, pnova__Prop_SObjectRecordTypeLabel__c FROM pnova__Profiling_Definition__c';
|
|
44
|
+
/** Expected CSV file name */
|
|
45
|
+
static DEFINITION_CSV = 'pnova__Profiling_Definition__c.csv';
|
|
46
|
+
sfdmuService;
|
|
47
|
+
logger;
|
|
48
|
+
/**
|
|
49
|
+
* Creates a new DefinitionImportOperation.
|
|
50
|
+
*
|
|
51
|
+
* @param sfdmuService - The SFDMU service instance for executing operations
|
|
52
|
+
* @param logger - Optional logger for debug output
|
|
53
|
+
*/
|
|
54
|
+
constructor(sfdmuService, logger) {
|
|
55
|
+
this.sfdmuService = sfdmuService;
|
|
56
|
+
this.logger = logger;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Builds the SFDMU import configuration.
|
|
60
|
+
*
|
|
61
|
+
* @param operation - The import operation type (Insert or Upsert)
|
|
62
|
+
* @returns SFDMU configuration object
|
|
63
|
+
*/
|
|
64
|
+
static buildSFDMUConfig(operation) {
|
|
65
|
+
return {
|
|
66
|
+
promptOnMissingParentObjects: false,
|
|
67
|
+
objects: [
|
|
68
|
+
{
|
|
69
|
+
query: DefinitionImportOperation.DEFINITION_QUERY,
|
|
70
|
+
operation,
|
|
71
|
+
externalId: 'Name',
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Executes the import operation.
|
|
78
|
+
*
|
|
79
|
+
* @param options - Import options
|
|
80
|
+
* @returns ServiceResult containing import results or error details
|
|
81
|
+
*/
|
|
82
|
+
async execute(options) {
|
|
83
|
+
const startTime = Date.now();
|
|
84
|
+
const sourceDir = path.resolve(options.sourceDir);
|
|
85
|
+
try {
|
|
86
|
+
// Validate source directory exists
|
|
87
|
+
if (!fs.existsSync(sourceDir)) {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
data: {
|
|
91
|
+
definitionsImported: 0,
|
|
92
|
+
sourceDir,
|
|
93
|
+
dryRun: options.dryRun ?? false,
|
|
94
|
+
},
|
|
95
|
+
errorCode: ImportErrorCodes.SOURCE_NOT_FOUND,
|
|
96
|
+
message: `Source directory does not exist: ${sourceDir}`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Validate source has required CSV file
|
|
100
|
+
const csvPath = path.join(sourceDir, DefinitionImportOperation.DEFINITION_CSV);
|
|
101
|
+
if (!fs.existsSync(csvPath)) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
data: {
|
|
105
|
+
definitionsImported: 0,
|
|
106
|
+
sourceDir,
|
|
107
|
+
dryRun: options.dryRun ?? false,
|
|
108
|
+
},
|
|
109
|
+
errorCode: ImportErrorCodes.INVALID_SOURCE,
|
|
110
|
+
message: `Source directory is missing required file: ${DefinitionImportOperation.DEFINITION_CSV}`,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// Create temp directory for SFDMU import
|
|
114
|
+
// SFDMU always reads from 'export.json', so we use a temp dir to avoid
|
|
115
|
+
// mutating the user's source directory (which may contain their export config)
|
|
116
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cuneiform-import-'));
|
|
117
|
+
this.logger?.log(`Created temp directory: ${tempDir}`);
|
|
118
|
+
try {
|
|
119
|
+
// Copy all CSV files to temp directory (including RecordType.csv for lookups)
|
|
120
|
+
const files = fs.readdirSync(sourceDir);
|
|
121
|
+
for (const file of files) {
|
|
122
|
+
if (file.endsWith('.csv')) {
|
|
123
|
+
const srcPath = path.join(sourceDir, file);
|
|
124
|
+
const destPath = path.join(tempDir, file);
|
|
125
|
+
fs.copyFileSync(srcPath, destPath);
|
|
126
|
+
this.logger?.log(`Copied CSV to: ${destPath}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Generate import configuration in temp directory
|
|
130
|
+
// Note: SFDMU always reads 'export.json' from the config path, regardless of operation type
|
|
131
|
+
const config = DefinitionImportOperation.buildSFDMUConfig(options.operation ?? 'Insert');
|
|
132
|
+
const configPath = path.join(tempDir, 'export.json');
|
|
133
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
134
|
+
this.logger?.log(`Wrote SFDMU config to: ${configPath}`);
|
|
135
|
+
// Build SFDMU options pointing to temp directory
|
|
136
|
+
const sfdmuOptions = {
|
|
137
|
+
targetOrg: options.targetOrg,
|
|
138
|
+
configPath: tempDir,
|
|
139
|
+
};
|
|
140
|
+
// Execute SFDMU import
|
|
141
|
+
// Note: For dry-run, we'd ideally use SFDMU's --simulation flag
|
|
142
|
+
// but that requires SFDMU version support check. For now, we execute
|
|
143
|
+
// the actual import. The dryRun flag is preserved for future enhancement.
|
|
144
|
+
const sfdmuResult = await this.sfdmuService.runImport(sfdmuOptions);
|
|
145
|
+
if (!sfdmuResult.success) {
|
|
146
|
+
return {
|
|
147
|
+
success: false,
|
|
148
|
+
data: {
|
|
149
|
+
definitionsImported: 0,
|
|
150
|
+
sourceDir,
|
|
151
|
+
dryRun: options.dryRun ?? false,
|
|
152
|
+
sfdmuOutput: sfdmuResult.data.stderr,
|
|
153
|
+
},
|
|
154
|
+
errorCode: sfdmuResult.errorCode ?? ImportErrorCodes.IMPORT_FAILED,
|
|
155
|
+
message: sfdmuResult.message ?? 'SFDMU import failed',
|
|
156
|
+
metadata: {
|
|
157
|
+
duration: Date.now() - startTime,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
data: {
|
|
164
|
+
definitionsImported: sfdmuResult.data.recordsProcessed ?? 0,
|
|
165
|
+
sourceDir,
|
|
166
|
+
dryRun: options.dryRun ?? false,
|
|
167
|
+
sfdmuOutput: sfdmuResult.data.stdout,
|
|
168
|
+
},
|
|
169
|
+
message: `Successfully imported ${sfdmuResult.data.recordsProcessed ?? 0} definitions to ${options.targetOrg}`,
|
|
170
|
+
warnings: sfdmuResult.warnings,
|
|
171
|
+
metadata: {
|
|
172
|
+
duration: Date.now() - startTime,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
// Clean up temp directory
|
|
178
|
+
try {
|
|
179
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
180
|
+
this.logger?.log(`Cleaned up temp directory: ${tempDir}`);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Ignore cleanup errors - temp dir will be cleaned up by OS eventually
|
|
184
|
+
this.logger?.log(`Warning: Failed to clean up temp directory: ${tempDir}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
190
|
+
throw new SfError(`Import operation failed: ${errorMessage}`, 'ImportOperationError');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=DefinitionImportOperation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefinitionImportOperation.js","sourceRoot":"","sources":["../../src/operations/DefinitionImportOperation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { type ExecFileOptions } from 'node:child_process';
|
|
2
|
+
import { type ISFDMUOptions, type ISFDMUResult, type ServiceResult } from '../models/sfdmu-types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Type for the promisified execFile function.
|
|
5
|
+
*/
|
|
6
|
+
export type ExecFileAsyncFn = (file: string, args: string[], options: ExecFileOptions) => Promise<{
|
|
7
|
+
stdout: string;
|
|
8
|
+
stderr: string;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Configuration options for SFDMUService.
|
|
12
|
+
*/
|
|
13
|
+
export type ISFDMUServiceConfig = {
|
|
14
|
+
/** Optional logger for debug output */
|
|
15
|
+
logger?: Console;
|
|
16
|
+
/** Optional execFile function for testing (dependency injection) */
|
|
17
|
+
execFileAsync?: ExecFileAsyncFn;
|
|
18
|
+
/** Override platform detection (for testing) */
|
|
19
|
+
platform?: NodeJS.Platform;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Service for executing SFDMU (Salesforce Data Move Utility) operations.
|
|
23
|
+
*
|
|
24
|
+
* This service provides:
|
|
25
|
+
* - Runtime verification that SFDMU is installed
|
|
26
|
+
* - Secure shell execution using execFile (prevents command injection)
|
|
27
|
+
* - Cross-platform support (Windows/Unix)
|
|
28
|
+
* - Configurable timeout and buffer sizes
|
|
29
|
+
* - Result parsing for record counts and errors
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const service = new SFDMUService();
|
|
34
|
+
* await service.verifyInstallation();
|
|
35
|
+
* const result = await service.runExport({
|
|
36
|
+
* configPath: './export.json',
|
|
37
|
+
* sourceOrg: 'myOrg'
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare class SFDMUService {
|
|
42
|
+
/** Default timeout for SFDMU operations (5 minutes) */
|
|
43
|
+
static readonly DEFAULT_TIMEOUT = 300000;
|
|
44
|
+
/** Default max buffer size for stdout/stderr (10MB) */
|
|
45
|
+
static readonly DEFAULT_MAX_BUFFER: number;
|
|
46
|
+
/** The sf CLI binary name (platform-specific) */
|
|
47
|
+
private readonly sfBinary;
|
|
48
|
+
/** Logger instance */
|
|
49
|
+
private readonly logger?;
|
|
50
|
+
/** Injected execFile function */
|
|
51
|
+
private readonly execFileAsync;
|
|
52
|
+
/**
|
|
53
|
+
* Creates a new SFDMUService instance.
|
|
54
|
+
*
|
|
55
|
+
* @param config - Optional configuration including logger and test dependencies
|
|
56
|
+
*/
|
|
57
|
+
constructor(config?: ISFDMUServiceConfig);
|
|
58
|
+
/**
|
|
59
|
+
* Builds command line arguments for SFDMU execution.
|
|
60
|
+
*
|
|
61
|
+
* @param options - Operation options
|
|
62
|
+
* @param operation - The operation type
|
|
63
|
+
* @returns Array of command line arguments
|
|
64
|
+
*/
|
|
65
|
+
private static buildArgs;
|
|
66
|
+
/**
|
|
67
|
+
* Parses record count from SFDMU stdout output.
|
|
68
|
+
*
|
|
69
|
+
* @param stdout - Standard output from SFDMU
|
|
70
|
+
* @returns Parsed record count or undefined if not found
|
|
71
|
+
*/
|
|
72
|
+
private static parseRecordCount;
|
|
73
|
+
/**
|
|
74
|
+
* Parses error messages from SFDMU stderr output.
|
|
75
|
+
*
|
|
76
|
+
* @param stderr - Standard error from SFDMU
|
|
77
|
+
* @returns Array of error messages
|
|
78
|
+
*/
|
|
79
|
+
private static parseErrors;
|
|
80
|
+
/**
|
|
81
|
+
* Parses warning messages from SFDMU stderr output.
|
|
82
|
+
*
|
|
83
|
+
* @param stderr - Standard error from SFDMU
|
|
84
|
+
* @returns Array of warning messages
|
|
85
|
+
*/
|
|
86
|
+
private static parseWarnings;
|
|
87
|
+
/**
|
|
88
|
+
* Returns the sf binary name being used (for testing/debugging).
|
|
89
|
+
*/
|
|
90
|
+
getSfBinary(): string;
|
|
91
|
+
/**
|
|
92
|
+
* Verifies that SFDMU is installed and available.
|
|
93
|
+
*
|
|
94
|
+
* @throws SfError if SFDMU is not installed, with installation instructions
|
|
95
|
+
*/
|
|
96
|
+
verifyInstallation(): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Executes an SFDMU export operation.
|
|
99
|
+
*
|
|
100
|
+
* @param options - Export options including config path and source org
|
|
101
|
+
* @returns ServiceResult containing the execution result
|
|
102
|
+
*/
|
|
103
|
+
runExport(options: ISFDMUOptions): Promise<ServiceResult<ISFDMUResult>>;
|
|
104
|
+
/**
|
|
105
|
+
* Executes an SFDMU import operation.
|
|
106
|
+
*
|
|
107
|
+
* @param options - Import options including config path and target org
|
|
108
|
+
* @returns ServiceResult containing the execution result
|
|
109
|
+
*/
|
|
110
|
+
runImport(options: ISFDMUOptions): Promise<ServiceResult<ISFDMUResult>>;
|
|
111
|
+
/**
|
|
112
|
+
* Executes an SFDMU operation (export or import).
|
|
113
|
+
*
|
|
114
|
+
* @param options - Operation options
|
|
115
|
+
* @param operation - The operation type ('export' or 'import')
|
|
116
|
+
* @returns ServiceResult containing the execution result
|
|
117
|
+
*/
|
|
118
|
+
private executeOperation;
|
|
119
|
+
}
|