|
5 | 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause |
6 | 6 | */ |
7 | 7 |
|
8 | | -import { Messages } from '@salesforce/core'; |
| 8 | +import { Messages, SfError } from '@salesforce/core'; |
9 | 9 | import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; |
| 10 | +import { ensureString, isObject } from '@salesforce/ts-types'; |
10 | 11 | import { importFromPlan } from '../../../api/data/tree/importPlan.js'; |
11 | 12 | import { importFromFiles } from '../../../api/data/tree/importFiles.js'; |
12 | 13 | import { orgFlags } from '../../../flags.js'; |
13 | | -import type { ImportResult } from '../../../api/data/tree/importTypes.js'; |
| 14 | +import type { ImportResult, TreeResponse } from '../../../api/data/tree/importTypes.js'; |
14 | 15 |
|
15 | 16 | Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); |
16 | 17 | const messages = Messages.loadMessages('@salesforce/plugin-data', 'tree.import'); |
@@ -49,19 +50,71 @@ export default class Import extends SfCommand<ImportResult[]> { |
49 | 50 | const { flags } = await this.parse(Import); |
50 | 51 |
|
51 | 52 | const conn = flags['target-org'].getConnection(flags['api-version']); |
52 | | - const results = flags.plan |
53 | | - ? await importFromPlan(conn, flags.plan) |
54 | | - : await importFromFiles(conn, flags.files ?? []); |
55 | 53 |
|
56 | | - this.table({ |
57 | | - data: results, |
58 | | - columns: [ |
59 | | - { key: 'refId', name: 'Reference ID' }, |
60 | | - { key: 'type', name: 'Type' }, |
61 | | - { key: 'id', name: 'ID' }, |
62 | | - ], |
63 | | - title: 'Import Results', |
64 | | - }); |
65 | | - return results; |
| 54 | + try { |
| 55 | + const results = flags.plan |
| 56 | + ? await importFromPlan(conn, flags.plan) |
| 57 | + : await importFromFiles(conn, flags.files ?? []); |
| 58 | + |
| 59 | + this.table({ |
| 60 | + data: results, |
| 61 | + columns: [ |
| 62 | + { key: 'refId', name: 'Reference ID' }, |
| 63 | + { key: 'type', name: 'Type' }, |
| 64 | + { key: 'id', name: 'ID' }, |
| 65 | + ], |
| 66 | + title: 'Import Results', |
| 67 | + }); |
| 68 | + return results; |
| 69 | + } catch (err) { |
| 70 | + const error = err as Error; |
| 71 | + if ( |
| 72 | + error.cause && |
| 73 | + error.cause instanceof Error && |
| 74 | + 'data' in error.cause && |
| 75 | + isObject(error.cause.data) && |
| 76 | + 'message' in error.cause.data |
| 77 | + ) { |
| 78 | + const getTreeResponse = (payload: string): TreeResponse => { |
| 79 | + try { |
| 80 | + return JSON.parse(payload) as TreeResponse; |
| 81 | + } catch (parseErr) { |
| 82 | + // throw original error on invalid JSON payload |
| 83 | + if (parseErr instanceof Error && parseErr.name === 'SyntaxError') { |
| 84 | + throw error; |
| 85 | + } |
| 86 | + throw parseErr; |
| 87 | + } |
| 88 | + }; |
| 89 | + const errorData = getTreeResponse(ensureString(error.cause.data.message)); |
| 90 | + |
| 91 | + if (errorData.hasErrors) { |
| 92 | + const errorResults = errorData.results |
| 93 | + .map((result) => |
| 94 | + result.errors.map((errors) => ({ |
| 95 | + referenceId: result.referenceId, |
| 96 | + StatusCode: errors.statusCode, |
| 97 | + Message: errors.message, |
| 98 | + fields: errors.fields.join(', ') || 'N/A', |
| 99 | + })) |
| 100 | + ) |
| 101 | + .flat(); |
| 102 | + this.table({ |
| 103 | + data: errorResults, |
| 104 | + columns: [ |
| 105 | + { key: 'referenceId', name: 'Reference ID' }, |
| 106 | + { key: 'StatusCode', name: 'Status Code' }, |
| 107 | + { key: 'Message', name: 'Error Message' }, |
| 108 | + { key: 'fields', name: 'Fields' }, |
| 109 | + ], |
| 110 | + title: 'Tree import errors', |
| 111 | + }); |
| 112 | + const errors = new SfError('Data Import failed'); |
| 113 | + errors.setData(errorResults); |
| 114 | + throw errors; |
| 115 | + } |
| 116 | + } |
| 117 | + throw error; |
| 118 | + } |
66 | 119 | } |
67 | 120 | } |
0 commit comments