@lightdash/cli 0.2645.0 → 0.2646.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/dist/.tsbuildinfo +1 -1
- package/dist/handlers/download.d.ts +6 -1
- package/dist/handlers/download.d.ts.map +1 -1
- package/dist/handlers/download.js +88 -22
- package/dist/handlers/metadataFile.d.ts +9 -0
- package/dist/handlers/metadataFile.d.ts.map +1 -0
- package/dist/handlers/metadataFile.js +34 -0
- package/package.json +3 -3
|
@@ -14,8 +14,13 @@ export type DownloadHandlerOptions = {
|
|
|
14
14
|
concurrency: number;
|
|
15
15
|
gzip?: boolean;
|
|
16
16
|
};
|
|
17
|
+
type MetadataEntry = {
|
|
18
|
+
slug: string;
|
|
19
|
+
type: 'charts' | 'dashboards';
|
|
20
|
+
downloadedAt: string;
|
|
21
|
+
};
|
|
17
22
|
type DownloadContentType = 'charts' | 'dashboards' | 'sqlCharts';
|
|
18
|
-
export declare const downloadContent: (ids: string[], type: DownloadContentType, projectId: string, projectName: string, customPath?: string, languageMap?: boolean, nested?: boolean) => Promise<[number, string[]]>;
|
|
23
|
+
export declare const downloadContent: (ids: string[], type: DownloadContentType, projectId: string, projectName: string, customPath?: string, languageMap?: boolean, nested?: boolean) => Promise<[number, string[], MetadataEntry[]]>;
|
|
19
24
|
export declare const downloadHandler: (options: DownloadHandlerOptions) => Promise<void>;
|
|
20
25
|
export declare const uploadHandler: (options: DownloadHandlerOptions) => Promise<void>;
|
|
21
26
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/handlers/download.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/handlers/download.ts"],"names":[],"mappings":"AA2CA,MAAM,MAAM,sBAAsB,GAAG;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AA2FF,KAAK,aAAa,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,YAAY,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;CACxB,CAAC;AAyOF,KAAK,mBAAmB,GAAG,QAAQ,GAAG,YAAY,GAAG,WAAW,CAAC;AAkDjE,eAAO,MAAM,eAAe,GACxB,KAAK,MAAM,EAAE,EACb,MAAM,mBAAmB,EACzB,WAAW,MAAM,EACjB,aAAa,MAAM,EACnB,aAAa,MAAM,EACnB,cAAa,OAAe,EAC5B,SAAQ,OAAe,KACxB,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,CAAC,CA+G7C,CAAC;AAEF,eAAO,MAAM,eAAe,GACxB,SAAS,sBAAsB,KAChC,OAAO,CAAC,IAAI,CAmMd,CAAC;AA4ZF,eAAO,MAAM,aAAa,GACtB,SAAS,sBAAsB,KAChC,OAAO,CAAC,IAAI,CAkJd,CAAC"}
|
|
@@ -15,6 +15,7 @@ const config_1 = require("../config");
|
|
|
15
15
|
const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
16
16
|
const styles = tslib_1.__importStar(require("../styles"));
|
|
17
17
|
const apiClient_1 = require("./dbt/apiClient");
|
|
18
|
+
const metadataFile_1 = require("./metadataFile");
|
|
18
19
|
const selectProject_1 = require("./selectProject");
|
|
19
20
|
const getDownloadFolder = (customPath) => {
|
|
20
21
|
if (customPath) {
|
|
@@ -71,29 +72,69 @@ const getFileExtension = (contentType) => {
|
|
|
71
72
|
const writeContent = async (contentAsCode, outputDir, languageMap) => {
|
|
72
73
|
const extension = getFileExtension(contentAsCode.type);
|
|
73
74
|
const itemPath = path.join(outputDir, `${contentAsCode.content.slug}${extension}`);
|
|
74
|
-
|
|
75
|
+
// Strip timestamps — they go to .lightdash-metadata.json instead
|
|
76
|
+
const { updatedAt, downloadedAt, ...cleanContent } = contentAsCode.content;
|
|
77
|
+
const chartYml = yaml.dump(cleanContent, {
|
|
75
78
|
quotingType: '"',
|
|
79
|
+
sortKeys: true,
|
|
76
80
|
});
|
|
77
81
|
await fs_1.promises.writeFile(itemPath, chartYml);
|
|
78
82
|
if (contentAsCode.translationMap && languageMap) {
|
|
79
83
|
const translationPath = path.join(outputDir, `${contentAsCode.content.slug}.language.map.yml`);
|
|
80
|
-
await fs_1.promises.writeFile(translationPath, yaml.dump(contentAsCode.translationMap));
|
|
84
|
+
await fs_1.promises.writeFile(translationPath, yaml.dump(contentAsCode.translationMap, { sortKeys: true }));
|
|
81
85
|
}
|
|
86
|
+
const metadataType = contentAsCode.type === 'dashboard' ? 'dashboards' : 'charts';
|
|
87
|
+
let downloadedAtString;
|
|
88
|
+
if (downloadedAt instanceof Date) {
|
|
89
|
+
downloadedAtString = downloadedAt.toISOString();
|
|
90
|
+
}
|
|
91
|
+
else if (typeof downloadedAt === 'string') {
|
|
92
|
+
downloadedAtString = downloadedAt;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
downloadedAtString = new Date().toISOString();
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
slug: contentAsCode.content.slug,
|
|
99
|
+
type: metadataType,
|
|
100
|
+
downloadedAt: downloadedAtString,
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
const hasUnsortedKeys = (obj) => {
|
|
104
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
105
|
+
if (Array.isArray(obj)) {
|
|
106
|
+
return obj.some(hasUnsortedKeys);
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
const keys = Object.keys(obj);
|
|
111
|
+
const sorted = [...keys].sort();
|
|
112
|
+
if (keys.some((key, i) => key !== sorted[i])) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
return Object.values(obj).some(hasUnsortedKeys);
|
|
82
116
|
};
|
|
83
117
|
const isLightdashContentFile = (folder, entry) => entry.isFile() &&
|
|
84
118
|
entry.parentPath &&
|
|
85
119
|
entry.parentPath.endsWith(path.sep + folder) &&
|
|
86
120
|
entry.name.endsWith('.yml') &&
|
|
87
121
|
!entry.name.endsWith('.language.map.yml');
|
|
88
|
-
const loadYamlFile = async (file) => {
|
|
122
|
+
const loadYamlFile = async (file, folder, metadata) => {
|
|
89
123
|
const filePath = path.join(file.parentPath, file.name);
|
|
90
124
|
const [fileContent, stats] = await Promise.all([
|
|
91
125
|
fs_1.promises.readFile(filePath, 'utf-8'),
|
|
92
126
|
fs_1.promises.stat(filePath),
|
|
93
127
|
]);
|
|
94
128
|
const item = yaml.load(fileContent);
|
|
95
|
-
|
|
96
|
-
|
|
129
|
+
if (hasUnsortedKeys(item)) {
|
|
130
|
+
globalState_1.default.log(styles.warning(`Warning: ${file.name} has unsorted YAML keys. Re-download to fix, or sort keys alphabetically.`));
|
|
131
|
+
}
|
|
132
|
+
const metadataSection = folder === 'dashboards' ? metadata.dashboards : metadata.charts;
|
|
133
|
+
const downloadedAtRaw = metadataSection[item.slug] ?? item.downloadedAt;
|
|
134
|
+
const downloadedAt = downloadedAtRaw
|
|
135
|
+
? new Date(downloadedAtRaw instanceof Date
|
|
136
|
+
? downloadedAtRaw.getTime()
|
|
137
|
+
: downloadedAtRaw)
|
|
97
138
|
: undefined;
|
|
98
139
|
const needsUpdating = downloadedAt &&
|
|
99
140
|
Math.abs(stats.mtime.getTime() - downloadedAt.getTime()) > 30000;
|
|
@@ -111,13 +152,14 @@ const readCodeFiles = async (folder, customPath) => {
|
|
|
111
152
|
throw new Error(`Node.js v20.12.0 or later is required for this command (current: ${process.version}).`);
|
|
112
153
|
}
|
|
113
154
|
try {
|
|
155
|
+
const metadata = await (0, metadataFile_1.readMetadataFile)(baseDir);
|
|
114
156
|
const allEntries = await fs_1.promises.readdir(baseDir, {
|
|
115
157
|
recursive: true,
|
|
116
158
|
withFileTypes: true,
|
|
117
159
|
});
|
|
118
160
|
const items = await Promise.all(allEntries
|
|
119
161
|
.filter((entry) => isLightdashContentFile(folder, entry))
|
|
120
|
-
.map((file) => loadYamlFile(file)));
|
|
162
|
+
.map((file) => loadYamlFile(file, folder, metadata)));
|
|
121
163
|
if (items.length === 0) {
|
|
122
164
|
console.error(styles.warning(`Unable to upload ${folder}, no files found in "${baseDir}". Run download command first.`));
|
|
123
165
|
}
|
|
@@ -140,16 +182,19 @@ const groupBySpace = (items) => {
|
|
|
140
182
|
};
|
|
141
183
|
const writeSpaceContent = async ({ projectName, spaceSlug, folder, contentType, contentInSpace, contentAsCode, customPath, languageMap, folderScheme, }) => {
|
|
142
184
|
const outputDir = await createDirForContent(projectName, spaceSlug, folder, customPath, folderScheme);
|
|
185
|
+
const entries = [];
|
|
143
186
|
for (const { item, index } of contentInSpace) {
|
|
144
187
|
const translationMap = 'languageMap' in contentAsCode
|
|
145
188
|
? contentAsCode.languageMap?.[index]
|
|
146
189
|
: undefined;
|
|
147
|
-
await writeContent({
|
|
190
|
+
const entry = await writeContent({
|
|
148
191
|
type: contentType,
|
|
149
192
|
content: item,
|
|
150
193
|
translationMap,
|
|
151
194
|
}, outputDir, languageMap);
|
|
195
|
+
entries.push(entry);
|
|
152
196
|
}
|
|
197
|
+
return entries;
|
|
153
198
|
};
|
|
154
199
|
const getContentTypeConfig = (type, projectId) => {
|
|
155
200
|
switch (type) {
|
|
@@ -191,6 +236,7 @@ const downloadContent = async (ids, type, projectId, projectName, customPath, la
|
|
|
191
236
|
let offset = 0;
|
|
192
237
|
let total = 0;
|
|
193
238
|
let chartSlugs = [];
|
|
239
|
+
let allMetadataEntries = [];
|
|
194
240
|
do {
|
|
195
241
|
globalState_1.default.debug(`Downloading ${config.displayName} with offset "${offset}" and filters "${contentFilters}"`);
|
|
196
242
|
const commonParams = config.supportsLanguageMap
|
|
@@ -214,7 +260,7 @@ const downloadContent = async (ids, type, projectId, projectName, customPath, la
|
|
|
214
260
|
if ('sqlCharts' in results) {
|
|
215
261
|
const sqlChartsBySpace = groupBySpace(results.sqlCharts);
|
|
216
262
|
for (const [spaceSlug, sqlChartsInSpace] of Object.entries(sqlChartsBySpace)) {
|
|
217
|
-
await writeSpaceContent({
|
|
263
|
+
const entries = await writeSpaceContent({
|
|
218
264
|
projectName,
|
|
219
265
|
spaceSlug,
|
|
220
266
|
folder: 'charts',
|
|
@@ -225,12 +271,13 @@ const downloadContent = async (ids, type, projectId, projectName, customPath, la
|
|
|
225
271
|
languageMap,
|
|
226
272
|
folderScheme,
|
|
227
273
|
});
|
|
274
|
+
allMetadataEntries = [...allMetadataEntries, ...entries];
|
|
228
275
|
}
|
|
229
276
|
}
|
|
230
277
|
else if ('dashboards' in results) {
|
|
231
278
|
const dashboardsBySpace = groupBySpace(results.dashboards);
|
|
232
279
|
for (const [spaceSlug, dashboardsInSpace] of Object.entries(dashboardsBySpace)) {
|
|
233
|
-
await writeSpaceContent({
|
|
280
|
+
const entries = await writeSpaceContent({
|
|
234
281
|
projectName,
|
|
235
282
|
spaceSlug,
|
|
236
283
|
folder: 'dashboards',
|
|
@@ -241,6 +288,7 @@ const downloadContent = async (ids, type, projectId, projectName, customPath, la
|
|
|
241
288
|
languageMap,
|
|
242
289
|
folderScheme,
|
|
243
290
|
});
|
|
291
|
+
allMetadataEntries = [...allMetadataEntries, ...entries];
|
|
244
292
|
}
|
|
245
293
|
chartSlugs = [
|
|
246
294
|
...chartSlugs,
|
|
@@ -250,7 +298,7 @@ const downloadContent = async (ids, type, projectId, projectName, customPath, la
|
|
|
250
298
|
else {
|
|
251
299
|
const chartsBySpace = groupBySpace(results.charts);
|
|
252
300
|
for (const [spaceSlug, chartsInSpace] of Object.entries(chartsBySpace)) {
|
|
253
|
-
await writeSpaceContent({
|
|
301
|
+
const entries = await writeSpaceContent({
|
|
254
302
|
projectName,
|
|
255
303
|
spaceSlug,
|
|
256
304
|
folder: 'charts',
|
|
@@ -261,12 +309,13 @@ const downloadContent = async (ids, type, projectId, projectName, customPath, la
|
|
|
261
309
|
languageMap,
|
|
262
310
|
folderScheme,
|
|
263
311
|
});
|
|
312
|
+
allMetadataEntries = [...allMetadataEntries, ...entries];
|
|
264
313
|
}
|
|
265
314
|
}
|
|
266
315
|
offset = results.offset;
|
|
267
316
|
total = results.total;
|
|
268
317
|
} while (offset < total);
|
|
269
|
-
return [total, [...new Set(chartSlugs)]];
|
|
318
|
+
return [total, [...new Set(chartSlugs)], allMetadataEntries];
|
|
270
319
|
};
|
|
271
320
|
exports.downloadContent = downloadContent;
|
|
272
321
|
const downloadHandler = async (options) => {
|
|
@@ -310,20 +359,21 @@ const downloadHandler = async (options) => {
|
|
|
310
359
|
},
|
|
311
360
|
});
|
|
312
361
|
try {
|
|
313
|
-
// If any filter is provided, we skip those items without filters
|
|
314
|
-
// eg: if a --charts filter is provided, we skip dashboards if no --dashboards filter is provided
|
|
315
362
|
const hasFilters = options.charts.length > 0 || options.dashboards.length > 0;
|
|
363
|
+
let allMetadataEntries = [];
|
|
316
364
|
// Download regular charts
|
|
317
365
|
if (hasFilters && options.charts.length === 0) {
|
|
318
366
|
console.info(styles.warning(`No charts filters provided, skipping`));
|
|
319
367
|
}
|
|
320
368
|
else {
|
|
321
|
-
const [regularChartTotal] = await (0, exports.downloadContent)(options.charts, 'charts', projectId, projectName, options.path, options.languageMap, options.nested);
|
|
369
|
+
const [regularChartTotal, , regularChartMeta] = await (0, exports.downloadContent)(options.charts, 'charts', projectId, projectName, options.path, options.languageMap, options.nested);
|
|
322
370
|
spinner.succeed(`Downloaded ${regularChartTotal} charts`);
|
|
371
|
+
allMetadataEntries = [...allMetadataEntries, ...regularChartMeta];
|
|
323
372
|
// Download SQL charts
|
|
324
373
|
spinner.start(`Downloading SQL charts`);
|
|
325
|
-
const [sqlChartTotal] = await (0, exports.downloadContent)(options.charts, 'sqlCharts', projectId, projectName, options.path, options.languageMap, options.nested);
|
|
374
|
+
const [sqlChartTotal, , sqlChartMeta] = await (0, exports.downloadContent)(options.charts, 'sqlCharts', projectId, projectName, options.path, options.languageMap, options.nested);
|
|
326
375
|
spinner.succeed(`Downloaded ${sqlChartTotal} SQL charts`);
|
|
376
|
+
allMetadataEntries = [...allMetadataEntries, ...sqlChartMeta];
|
|
327
377
|
chartTotal = regularChartTotal + sqlChartTotal;
|
|
328
378
|
}
|
|
329
379
|
// Download dashboards
|
|
@@ -332,18 +382,34 @@ const downloadHandler = async (options) => {
|
|
|
332
382
|
}
|
|
333
383
|
else {
|
|
334
384
|
let chartSlugs = [];
|
|
335
|
-
|
|
385
|
+
let dashMeta;
|
|
386
|
+
[dashboardTotal, chartSlugs, dashMeta] = await (0, exports.downloadContent)(options.dashboards, 'dashboards', projectId, projectName, options.path, options.languageMap, options.nested);
|
|
387
|
+
allMetadataEntries = [...allMetadataEntries, ...dashMeta];
|
|
336
388
|
spinner.succeed(`Downloaded ${dashboardTotal} dashboards`);
|
|
337
|
-
// If any filter is provided, we download all charts linked to these dashboards
|
|
338
|
-
// We don't need to do this if we download everything (no filters)
|
|
339
389
|
if (hasFilters && chartSlugs.length > 0) {
|
|
340
390
|
spinner.start(`Downloading ${chartSlugs.length} charts linked to dashboards`);
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
391
|
+
const [regularCharts, , linkedChartMeta] = await (0, exports.downloadContent)(chartSlugs, 'charts', projectId, projectName, options.path, options.languageMap, options.nested);
|
|
392
|
+
allMetadataEntries = [
|
|
393
|
+
...allMetadataEntries,
|
|
394
|
+
...linkedChartMeta,
|
|
395
|
+
];
|
|
396
|
+
const [sqlCharts, , linkedSqlMeta] = await (0, exports.downloadContent)(chartSlugs, 'sqlCharts', projectId, projectName, options.path, options.languageMap, options.nested);
|
|
397
|
+
allMetadataEntries = [...allMetadataEntries, ...linkedSqlMeta];
|
|
344
398
|
spinner.succeed(`Downloaded ${regularCharts + sqlCharts} charts linked to dashboards`);
|
|
345
399
|
}
|
|
346
400
|
}
|
|
401
|
+
// Write metadata file with all downloadedAt timestamps
|
|
402
|
+
const metadataToWrite = {
|
|
403
|
+
version: 1,
|
|
404
|
+
charts: {},
|
|
405
|
+
dashboards: {},
|
|
406
|
+
};
|
|
407
|
+
for (const entry of allMetadataEntries) {
|
|
408
|
+
metadataToWrite[entry.type][entry.slug] = entry.downloadedAt;
|
|
409
|
+
}
|
|
410
|
+
const baseDir = getDownloadFolder(options.path);
|
|
411
|
+
await (0, metadataFile_1.writeMetadataFile)(baseDir, metadataToWrite);
|
|
412
|
+
globalState_1.default.log(styles.warning(`\nNote: ${metadataFile_1.METADATA_FILENAME} was written to ${baseDir}. Consider adding it to your .gitignore.`));
|
|
347
413
|
const end = Date.now();
|
|
348
414
|
await analytics_1.LightdashAnalytics.track({
|
|
349
415
|
event: 'download.completed',
|
|
@@ -353,7 +419,7 @@ const downloadHandler = async (options) => {
|
|
|
353
419
|
projectId,
|
|
354
420
|
chartsNum: chartTotal,
|
|
355
421
|
dashboardsNum: dashboardTotal,
|
|
356
|
-
timeToCompleted: (end - start) / 1000,
|
|
422
|
+
timeToCompleted: (end - start) / 1000,
|
|
357
423
|
},
|
|
358
424
|
});
|
|
359
425
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const METADATA_FILENAME = ".lightdash-metadata.json";
|
|
2
|
+
export type LightdashMetadata = {
|
|
3
|
+
version: 1;
|
|
4
|
+
charts: Record<string, string>;
|
|
5
|
+
dashboards: Record<string, string>;
|
|
6
|
+
};
|
|
7
|
+
export declare const readMetadataFile: (baseDir: string) => Promise<LightdashMetadata>;
|
|
8
|
+
export declare const writeMetadataFile: (baseDir: string, metadata: LightdashMetadata) => Promise<void>;
|
|
9
|
+
//# sourceMappingURL=metadataFile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadataFile.d.ts","sourceRoot":"","sources":["../../src/handlers/metadataFile.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,iBAAiB,6BAA6B,CAAC;AAE5D,MAAM,MAAM,iBAAiB,GAAG;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC,CAAC;AAQF,eAAO,MAAM,gBAAgB,GACzB,SAAS,MAAM,KAChB,OAAO,CAAC,iBAAiB,CAQ3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC1B,SAAS,MAAM,EACf,UAAU,iBAAiB,KAC5B,OAAO,CAAC,IAAI,CASd,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeMetadataFile = exports.readMetadataFile = exports.METADATA_FILENAME = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path = tslib_1.__importStar(require("path"));
|
|
7
|
+
exports.METADATA_FILENAME = '.lightdash-metadata.json';
|
|
8
|
+
const emptyMetadata = () => ({
|
|
9
|
+
version: 1,
|
|
10
|
+
charts: {},
|
|
11
|
+
dashboards: {},
|
|
12
|
+
});
|
|
13
|
+
const readMetadataFile = async (baseDir) => {
|
|
14
|
+
const filePath = path.join(baseDir, exports.METADATA_FILENAME);
|
|
15
|
+
try {
|
|
16
|
+
const content = await fs_1.promises.readFile(filePath, 'utf-8');
|
|
17
|
+
return JSON.parse(content);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return emptyMetadata();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
exports.readMetadataFile = readMetadataFile;
|
|
24
|
+
const writeMetadataFile = async (baseDir, metadata) => {
|
|
25
|
+
const existing = await (0, exports.readMetadataFile)(baseDir);
|
|
26
|
+
const merged = {
|
|
27
|
+
version: 1,
|
|
28
|
+
charts: { ...existing.charts, ...metadata.charts },
|
|
29
|
+
dashboards: { ...existing.dashboards, ...metadata.dashboards },
|
|
30
|
+
};
|
|
31
|
+
const filePath = path.join(baseDir, exports.METADATA_FILENAME);
|
|
32
|
+
await fs_1.promises.writeFile(filePath, JSON.stringify(merged, null, 2));
|
|
33
|
+
};
|
|
34
|
+
exports.writeMetadataFile = writeMetadataFile;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightdash/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2646.0",
|
|
4
4
|
"description": "Lightdash CLI tool",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"unique-names-generator": "^4.7.1",
|
|
41
41
|
"uuid": "^11.0.3",
|
|
42
42
|
"yaml": "^2.7.0",
|
|
43
|
-
"@lightdash/common": "0.
|
|
44
|
-
"@lightdash/warehouses": "0.
|
|
43
|
+
"@lightdash/common": "0.2646.0",
|
|
44
|
+
"@lightdash/warehouses": "0.2646.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/inquirer": "^8.2.1",
|