@lightdash/cli 2.194.1 → 2.195.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/README.md +34 -18
- package/dist/.tsbuildinfo +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -0
- package/dist/config.test.js +32 -0
- package/dist/handlers/renameHandler.d.ts.map +1 -1
- package/dist/handlers/renameHandler.js +6 -5
- package/dist/handlers/renameHandler.test.js +41 -0
- package/dist/handlers/selectProject.d.ts +10 -3
- package/dist/handlers/selectProject.d.ts.map +1 -1
- package/dist/handlers/selectProject.js +35 -10
- package/dist/handlers/selectProject.test.js +89 -5
- package/package.json +3 -3
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,cAAc,QAAsC,CAAC;AAElE,MAAM,MAAM,MAAM,GAAG;IACjB,IAAI,CAAC,EAAE;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,OAAO,CAAC,EAAE;QACN,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB;;;WAGG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,OAAO,CAAC,EAAE;QACN,qCAAqC,CAAC,EAAE,OAAO,CAAC;QAChD,gCAAgC,CAAC,EAAE,OAAO,CAAC;KAC9C,CAAC;CACL,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,2BAA2B,aAC1B,MAAM,KACjB,OAAO,CAAC,IAAI,CAgBd,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,aAChB,MAAM,UACR,MAAM,KACf,OAAO,CAAC,IAAI,CAed,CAAC;AAiCF,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,cAAc,QAAsC,CAAC;AAElE,MAAM,MAAM,MAAM,GAAG;IACjB,IAAI,CAAC,EAAE;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,OAAO,CAAC,EAAE;QACN,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB;;;WAGG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,OAAO,CAAC,EAAE;QACN,qCAAqC,CAAC,EAAE,OAAO,CAAC;QAChD,gCAAgC,CAAC,EAAE,OAAO,CAAC;KAC9C,CAAC;CACL,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,2BAA2B,aAC1B,MAAM,KACjB,OAAO,CAAC,IAAI,CAgBd,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,aAChB,MAAM,UACR,MAAM,KACf,OAAO,CAAC,IAAI,CAed,CAAC;AAiCF,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,MAAM,CAwBhD,CAAC;AAEF,eAAO,MAAM,UAAU,gBAAuB,MAAM,eAAe,MAAM,kBAUxE,CAAC;AAEF,eAAO,MAAM,YAAY,qBAUxB,CAAC;AAEF,eAAO,MAAM,iBAAiB,gBAAuB,MAAM,QAAQ,MAAM,kBAUxE,CAAC;AAEF,eAAO,MAAM,mBAAmB,qBAU/B,CAAC;AAEF,eAAO,MAAM,cAAc,aACb,MAAM,oBACE,MAAM,kBAW3B,CAAC;AAEF,eAAO,MAAM,UAAU,YAAmB,MAAM,CAAC,SAAS,CAAC,kBAM1D,CAAC;AAEF,eAAO,MAAM,SAAS,WAAkB,MAAM,CAAC,SAAS,CAAC,kBAMxD,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -84,6 +84,10 @@ const getConfig = async () => {
|
|
|
84
84
|
...(rawConfig.context || {}),
|
|
85
85
|
apiKey: process.env.LIGHTDASH_API_KEY || rawConfig.context?.apiKey,
|
|
86
86
|
project: process.env.LIGHTDASH_PROJECT || rawConfig.context?.project,
|
|
87
|
+
projectName: process.env.LIGHTDASH_PROJECT &&
|
|
88
|
+
process.env.LIGHTDASH_PROJECT !== rawConfig.context?.project
|
|
89
|
+
? undefined
|
|
90
|
+
: rawConfig.context?.projectName,
|
|
87
91
|
serverUrl: process.env.LIGHTDASH_URL || rawConfig.context?.serverUrl,
|
|
88
92
|
proxyAuthorization: process.env.LIGHTDASH_PROXY_AUTHORIZATION ||
|
|
89
93
|
rawConfig.context?.proxyAuthorization,
|
package/dist/config.test.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
|
+
const yaml = tslib_1.__importStar(require("js-yaml"));
|
|
5
6
|
const os = tslib_1.__importStar(require("os"));
|
|
6
7
|
const path = tslib_1.__importStar(require("path"));
|
|
7
8
|
const config_1 = require("./config");
|
|
@@ -38,3 +39,34 @@ describePosix('CLI config permissions', () => {
|
|
|
38
39
|
expect(permissionBits((await fs_1.promises.stat(configPath)).mode)).toBe(0o600);
|
|
39
40
|
});
|
|
40
41
|
});
|
|
42
|
+
describe('CLI project environment override', () => {
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
vi.restoreAllMocks();
|
|
45
|
+
vi.unstubAllEnvs();
|
|
46
|
+
});
|
|
47
|
+
it.each([
|
|
48
|
+
['other-project', undefined],
|
|
49
|
+
['stored-project', 'Stored project'],
|
|
50
|
+
['', 'Stored project'],
|
|
51
|
+
[undefined, 'Stored project'],
|
|
52
|
+
])('only retains the cached name for its own project (override: %s)', async (projectOverride, expectedName) => {
|
|
53
|
+
vi.stubEnv('LIGHTDASH_PROJECT', projectOverride);
|
|
54
|
+
vi.spyOn(fs_1.promises, 'chmod').mockResolvedValue(undefined);
|
|
55
|
+
vi.spyOn(fs_1.promises, 'readFile').mockResolvedValue(yaml.dump({
|
|
56
|
+
user: { anonymousUuid: 'anonymous-user' },
|
|
57
|
+
context: {
|
|
58
|
+
project: 'stored-project',
|
|
59
|
+
projectName: 'Stored project',
|
|
60
|
+
previewProject: 'preview-project',
|
|
61
|
+
previewName: 'Preview project',
|
|
62
|
+
},
|
|
63
|
+
}));
|
|
64
|
+
const config = await (0, config_1.getConfig)();
|
|
65
|
+
expect(config.context).toMatchObject({
|
|
66
|
+
project: projectOverride || 'stored-project',
|
|
67
|
+
projectName: expectedName,
|
|
68
|
+
previewProject: 'preview-project',
|
|
69
|
+
previewName: 'Preview project',
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renameHandler.d.ts","sourceRoot":"","sources":["../../src/handlers/renameHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAMH,UAAU,EAEb,MAAM,mBAAmB,CAAC;AAmB3B,KAAK,oBAAoB,GAAG;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;CACrB,CAAC;AAwCF,eAAO,MAAM,aAAa,YAAmB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"renameHandler.d.ts","sourceRoot":"","sources":["../../src/handlers/renameHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAMH,UAAU,EAEb,MAAM,mBAAmB,CAAC;AAmB3B,KAAK,oBAAoB,GAAG;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;CACrB,CAAC;AAwCF,eAAO,MAAM,aAAa,YAAmB,oBAAoB,kBAwNhE,CAAC"}
|
|
@@ -13,7 +13,7 @@ const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
|
13
13
|
const styles = tslib_1.__importStar(require("../styles"));
|
|
14
14
|
const apiClient_1 = require("./dbt/apiClient");
|
|
15
15
|
const refresh_1 = require("./dbt/refresh");
|
|
16
|
-
const
|
|
16
|
+
const selectProject_1 = require("./selectProject");
|
|
17
17
|
const validate_1 = require("./validate");
|
|
18
18
|
const REFETCH_JOB_INTERVAL = 2000;
|
|
19
19
|
const waitUntilRenameFinished = (jobUuid) => (0, validate_1.waitUntilFinished)({
|
|
@@ -45,9 +45,10 @@ const renameHandler = async (options) => {
|
|
|
45
45
|
if (!config.context?.apiKey || !config.context.serverUrl) {
|
|
46
46
|
throw new common_1.AuthorizationError(`Not logged in. Run 'lightdash login --help'`);
|
|
47
47
|
}
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
const overrideProjectUuid = await (0, selectProject_1.resolveProjectOverride)(config, options.project);
|
|
49
|
+
const projectUuid = overrideProjectUuid ||
|
|
50
|
+
config.context.previewProject ||
|
|
51
|
+
config.context.project;
|
|
51
52
|
if (!projectUuid) {
|
|
52
53
|
throw new common_1.LightdashError({
|
|
53
54
|
message: 'No project selected. Run lightdash config set-project',
|
|
@@ -57,7 +58,7 @@ const renameHandler = async (options) => {
|
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
// Log current project info
|
|
60
|
-
if (
|
|
61
|
+
if (overrideProjectUuid) {
|
|
61
62
|
console.error(`\n${styles.success('Renaming in project:')} ${projectUuid}\n`);
|
|
62
63
|
}
|
|
63
64
|
else {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
3
4
|
const common_1 = require("@lightdash/common");
|
|
4
5
|
const analytics_1 = require("../analytics/analytics");
|
|
5
6
|
const config_1 = require("../config");
|
|
7
|
+
const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
6
8
|
const apiClient_1 = require("./dbt/apiClient");
|
|
7
9
|
const refresh_1 = require("./dbt/refresh");
|
|
8
10
|
const renameHandler_1 = require("./renameHandler");
|
|
@@ -29,6 +31,7 @@ const emptyResults = {
|
|
|
29
31
|
};
|
|
30
32
|
const RENAME_JOB_ID = 'rename-job-id';
|
|
31
33
|
const VALIDATION_JOB_ID = 'validation-job-id';
|
|
34
|
+
const PREVIEW_PROJECT = '33333333-3333-4333-8333-333333333333';
|
|
32
35
|
describe('renameHandler follow-up validation', () => {
|
|
33
36
|
let errorOutput;
|
|
34
37
|
const mockApi = (failingJobId) => {
|
|
@@ -54,11 +57,19 @@ describe('renameHandler follow-up validation', () => {
|
|
|
54
57
|
if (url.includes('/validate?jobId=')) {
|
|
55
58
|
return [];
|
|
56
59
|
}
|
|
60
|
+
if (method === 'GET' &&
|
|
61
|
+
url === `/api/v1/projects/${PREVIEW_PROJECT}`) {
|
|
62
|
+
return {
|
|
63
|
+
projectUuid: PREVIEW_PROJECT,
|
|
64
|
+
type: common_1.ProjectType.PREVIEW,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
57
67
|
throw new Error(`Unexpected API call: ${method} ${url}`);
|
|
58
68
|
});
|
|
59
69
|
};
|
|
60
70
|
beforeEach(() => {
|
|
61
71
|
vi.clearAllMocks();
|
|
72
|
+
vi.stubEnv('LIGHTDASH_PROJECT', undefined);
|
|
62
73
|
vi.mocked(apiClient_1.checkLightdashVersion).mockResolvedValue(undefined);
|
|
63
74
|
vi.mocked(config_1.getConfig).mockResolvedValue({
|
|
64
75
|
context: {
|
|
@@ -78,11 +89,41 @@ describe('renameHandler follow-up validation', () => {
|
|
|
78
89
|
});
|
|
79
90
|
afterEach(() => {
|
|
80
91
|
vi.restoreAllMocks();
|
|
92
|
+
vi.unstubAllEnvs();
|
|
81
93
|
});
|
|
82
94
|
const trackedEvents = () => vi.mocked(analytics_1.LightdashAnalytics.track).mock.calls.map(([payload]) => ({
|
|
83
95
|
event: payload.event,
|
|
84
96
|
properties: payload.properties,
|
|
85
97
|
}));
|
|
98
|
+
test.each([undefined, baseOptions.project])('targets the environment project unless --project overrides it (%s)', async (explicitProject) => {
|
|
99
|
+
const envProject = '22222222-2222-4222-8222-222222222222';
|
|
100
|
+
vi.stubEnv('LIGHTDASH_PROJECT', envProject);
|
|
101
|
+
vi.spyOn(globalState_1.default, 'isNonInteractive').mockReturnValue(true);
|
|
102
|
+
vi.mocked(config_1.getConfig).mockResolvedValue({
|
|
103
|
+
context: {
|
|
104
|
+
apiKey: 'test-key',
|
|
105
|
+
serverUrl: 'http://localhost',
|
|
106
|
+
project: envProject,
|
|
107
|
+
previewProject: PREVIEW_PROJECT,
|
|
108
|
+
previewName: 'Stale preview',
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
mockApi(null);
|
|
112
|
+
await (0, renameHandler_1.renameHandler)({ ...baseOptions, project: explicitProject });
|
|
113
|
+
const expectedProject = explicitProject || envProject;
|
|
114
|
+
expect(apiClient_1.lightdashApi).toHaveBeenCalledWith(expect.objectContaining({
|
|
115
|
+
method: 'POST',
|
|
116
|
+
url: `/api/v1/projects/${expectedProject}/rename`,
|
|
117
|
+
}));
|
|
118
|
+
const output = errorOutput.join('\n');
|
|
119
|
+
expect(output).toContain(`Renaming in project: ${expectedProject}`);
|
|
120
|
+
if (explicitProject) {
|
|
121
|
+
expect(output).not.toContain('Stale preview');
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
expect(output).toContain('active preview "Stale preview" ignored');
|
|
125
|
+
}
|
|
126
|
+
});
|
|
86
127
|
test('reports a failed validation job as a validation failure, not a rename failure', async () => {
|
|
87
128
|
mockApi(VALIDATION_JOB_ID);
|
|
88
129
|
await (0, renameHandler_1.renameHandler)({ ...baseOptions });
|
|
@@ -3,14 +3,21 @@ export type ProjectSelection = {
|
|
|
3
3
|
projectUuid: string;
|
|
4
4
|
isPreview: boolean;
|
|
5
5
|
};
|
|
6
|
+
/**
|
|
7
|
+
* Resolves an explicit project override: `--project` wins over
|
|
8
|
+
* LIGHTDASH_PROJECT, and either one bypasses an active preview.
|
|
9
|
+
* Returns undefined when neither is set.
|
|
10
|
+
*/
|
|
11
|
+
export declare const resolveProjectOverride: (config: Config, explicitProject: string | undefined) => Promise<string | undefined>;
|
|
6
12
|
/**
|
|
7
13
|
* Resolves which project to use, prompting the user if there's an active preview.
|
|
8
14
|
*
|
|
9
15
|
* Priority:
|
|
10
16
|
* 1. If `explicitProject` is provided (via --project flag), use it
|
|
11
|
-
* 2. If
|
|
12
|
-
* 3.
|
|
13
|
-
* 4.
|
|
17
|
+
* 2. If LIGHTDASH_PROJECT is set, use it (warns when a preview is ignored)
|
|
18
|
+
* 3. If there's an active preview and we're in interactive mode, ask the user
|
|
19
|
+
* 4. In non-interactive mode with active preview, use preview project
|
|
20
|
+
* 5. Fall back to the main project
|
|
14
21
|
*/
|
|
15
22
|
export declare const selectProject: (config: Config, explicitProject?: string) => Promise<ProjectSelection | undefined>;
|
|
16
23
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectProject.d.ts","sourceRoot":"","sources":["../../src/handlers/selectProject.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAuB,MAAM,WAAW,CAAC;AAMxD,MAAM,MAAM,gBAAgB,GAAG;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACtB,CAAC;
|
|
1
|
+
{"version":3,"file":"selectProject.d.ts","sourceRoot":"","sources":["../../src/handlers/selectProject.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAuB,MAAM,WAAW,CAAC;AAMxD,MAAM,MAAM,gBAAgB,GAAG;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACtB,CAAC;AAsDF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,WACvB,MAAM,mBACG,MAAM,GAAG,SAAS,KACpC,OAAO,CAAC,MAAM,GAAG,SAAS,CAW5B,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,WACd,MAAM,oBACI,MAAM,KACzB,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAmFtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,cAChB,gBAAgB,UACnB,MAAM,UACN,MAAM,KACf,IAsBF,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.logSelectedProject = exports.selectProject = void 0;
|
|
3
|
+
exports.logSelectedProject = exports.selectProject = exports.resolveProjectOverride = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const common_1 = require("@lightdash/common");
|
|
6
6
|
const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
|
|
@@ -34,22 +34,47 @@ const validatePreviewProject = async (previewProjectUuid) => {
|
|
|
34
34
|
return previewProjectUuid;
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
|
+
const warnIgnoredPreview = async (config, projectUuid) => {
|
|
38
|
+
const previewProject = await validatePreviewProject(config.context?.previewProject);
|
|
39
|
+
if (!previewProject || previewProject === projectUuid) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const previewName = config.context?.previewName;
|
|
43
|
+
const previewLabel = previewName ? `"${previewName}"` : previewProject;
|
|
44
|
+
globalState_1.default.log(styles.warning(`\nUsing project ${projectUuid} from LIGHTDASH_PROJECT; active preview ${previewLabel} ignored.\nPass --project ${previewProject} or unset LIGHTDASH_PROJECT to target the preview.\n`));
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Resolves an explicit project override: `--project` wins over
|
|
48
|
+
* LIGHTDASH_PROJECT, and either one bypasses an active preview.
|
|
49
|
+
* Returns undefined when neither is set.
|
|
50
|
+
*/
|
|
51
|
+
const resolveProjectOverride = async (config, explicitProject) => {
|
|
52
|
+
if (explicitProject) {
|
|
53
|
+
return (0, resolveProjectFlag_1.resolveProjectFlag)(explicitProject);
|
|
54
|
+
}
|
|
55
|
+
const envProject = process.env.LIGHTDASH_PROJECT;
|
|
56
|
+
if (!envProject) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
const projectUuid = await (0, resolveProjectFlag_1.resolveProjectFlag)(envProject);
|
|
60
|
+
await warnIgnoredPreview(config, projectUuid);
|
|
61
|
+
return projectUuid;
|
|
62
|
+
};
|
|
63
|
+
exports.resolveProjectOverride = resolveProjectOverride;
|
|
37
64
|
/**
|
|
38
65
|
* Resolves which project to use, prompting the user if there's an active preview.
|
|
39
66
|
*
|
|
40
67
|
* Priority:
|
|
41
68
|
* 1. If `explicitProject` is provided (via --project flag), use it
|
|
42
|
-
* 2. If
|
|
43
|
-
* 3.
|
|
44
|
-
* 4.
|
|
69
|
+
* 2. If LIGHTDASH_PROJECT is set, use it (warns when a preview is ignored)
|
|
70
|
+
* 3. If there's an active preview and we're in interactive mode, ask the user
|
|
71
|
+
* 4. In non-interactive mode with active preview, use preview project
|
|
72
|
+
* 5. Fall back to the main project
|
|
45
73
|
*/
|
|
46
74
|
const selectProject = async (config, explicitProject) => {
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
return {
|
|
50
|
-
projectUuid: await (0, resolveProjectFlag_1.resolveProjectFlag)(explicitProject),
|
|
51
|
-
isPreview: false,
|
|
52
|
-
};
|
|
75
|
+
const overrideProjectUuid = await (0, exports.resolveProjectOverride)(config, explicitProject);
|
|
76
|
+
if (overrideProjectUuid) {
|
|
77
|
+
return { projectUuid: overrideProjectUuid, isPreview: false };
|
|
53
78
|
}
|
|
54
79
|
const mainProject = config.context?.project;
|
|
55
80
|
const previewProject = await validatePreviewProject(config.context?.previewProject);
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
3
4
|
const common_1 = require("@lightdash/common");
|
|
5
|
+
const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
|
|
6
|
+
const config_1 = require("../config");
|
|
7
|
+
const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
4
8
|
const apiClient_1 = require("./dbt/apiClient");
|
|
5
9
|
const selectProject_1 = require("./selectProject");
|
|
6
10
|
vi.mock('inquirer');
|
|
@@ -22,8 +26,70 @@ const mockPreviewProjectResponse = (uuid) => {
|
|
|
22
26
|
});
|
|
23
27
|
};
|
|
24
28
|
describe('selectProject', () => {
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
vi.stubEnv('LIGHTDASH_PROJECT', undefined);
|
|
31
|
+
});
|
|
25
32
|
afterEach(() => {
|
|
26
|
-
vi.
|
|
33
|
+
vi.resetAllMocks();
|
|
34
|
+
vi.restoreAllMocks();
|
|
35
|
+
vi.unstubAllEnvs();
|
|
36
|
+
});
|
|
37
|
+
it.each([true, false])('uses LIGHTDASH_PROJECT instead of an active preview and warns (non-interactive: %s)', async (nonInteractive) => {
|
|
38
|
+
vi.stubEnv('LIGHTDASH_PROJECT', MAIN_UUID);
|
|
39
|
+
vi.spyOn(globalState_1.default, 'isNonInteractive').mockReturnValue(nonInteractive);
|
|
40
|
+
const log = vi
|
|
41
|
+
.spyOn(globalState_1.default, 'log')
|
|
42
|
+
.mockImplementation(() => { });
|
|
43
|
+
mockPreviewProjectResponse(PREVIEW_UUID);
|
|
44
|
+
const config = {
|
|
45
|
+
context: {
|
|
46
|
+
project: MAIN_UUID,
|
|
47
|
+
previewProject: PREVIEW_UUID,
|
|
48
|
+
previewName: 'My preview',
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
expect(await (0, selectProject_1.selectProject)(config)).toEqual({
|
|
52
|
+
projectUuid: MAIN_UUID,
|
|
53
|
+
isPreview: false,
|
|
54
|
+
});
|
|
55
|
+
expect(inquirer_1.default.prompt).not.toHaveBeenCalled();
|
|
56
|
+
expect(log).toHaveBeenCalledTimes(1);
|
|
57
|
+
const warning = String(log.mock.calls[0][0]);
|
|
58
|
+
expect(warning).toContain(`Using project ${MAIN_UUID} from LIGHTDASH_PROJECT`);
|
|
59
|
+
expect(warning).toContain('active preview "My preview" ignored');
|
|
60
|
+
expect(warning).toContain(`--project ${PREVIEW_UUID}`);
|
|
61
|
+
});
|
|
62
|
+
it('clears a deleted preview instead of warning when LIGHTDASH_PROJECT is set', async () => {
|
|
63
|
+
vi.stubEnv('LIGHTDASH_PROJECT', MAIN_UUID);
|
|
64
|
+
const log = vi.spyOn(globalState_1.default, 'log').mockImplementation(() => { });
|
|
65
|
+
mockLightdashApi.mockRejectedValueOnce(new common_1.LightdashError({
|
|
66
|
+
message: 'Not found',
|
|
67
|
+
name: 'NotFoundError',
|
|
68
|
+
statusCode: 404,
|
|
69
|
+
data: {},
|
|
70
|
+
}));
|
|
71
|
+
expect(await (0, selectProject_1.selectProject)({
|
|
72
|
+
context: { project: MAIN_UUID, previewProject: PREVIEW_UUID },
|
|
73
|
+
})).toEqual({ projectUuid: MAIN_UUID, isPreview: false });
|
|
74
|
+
expect(config_1.unsetPreviewProject).toHaveBeenCalledTimes(1);
|
|
75
|
+
expect(log).not.toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
it.each([
|
|
78
|
+
['no preview is active', { project: MAIN_UUID }],
|
|
79
|
+
[
|
|
80
|
+
'LIGHTDASH_PROJECT points at the preview itself',
|
|
81
|
+
{ project: MAIN_UUID, previewProject: PREVIEW_UUID },
|
|
82
|
+
],
|
|
83
|
+
])('does not warn when %s', async (_label, context) => {
|
|
84
|
+
const envProject = context.previewProject ?? MAIN_UUID;
|
|
85
|
+
vi.stubEnv('LIGHTDASH_PROJECT', envProject);
|
|
86
|
+
const log = vi.spyOn(globalState_1.default, 'log').mockImplementation(() => { });
|
|
87
|
+
mockPreviewProjectResponse(PREVIEW_UUID);
|
|
88
|
+
expect(await (0, selectProject_1.selectProject)({ context })).toEqual({
|
|
89
|
+
projectUuid: envProject,
|
|
90
|
+
isPreview: false,
|
|
91
|
+
});
|
|
92
|
+
expect(log).not.toHaveBeenCalled();
|
|
27
93
|
});
|
|
28
94
|
it('returns the preview project (without prompting) when the stored main and preview UUIDs are the same', async () => {
|
|
29
95
|
// This is the misconfigured state produced by an older `set-project`
|
|
@@ -45,7 +111,8 @@ describe('selectProject', () => {
|
|
|
45
111
|
isPreview: true,
|
|
46
112
|
});
|
|
47
113
|
});
|
|
48
|
-
it('uses an explicit --project UUID
|
|
114
|
+
it.each([undefined, MAIN_UUID])('uses an explicit --project UUID ahead of the environment (%s) and active preview', async (envProject) => {
|
|
115
|
+
vi.stubEnv('LIGHTDASH_PROJECT', envProject);
|
|
49
116
|
const config = {
|
|
50
117
|
context: {
|
|
51
118
|
project: MAIN_UUID,
|
|
@@ -60,7 +127,9 @@ describe('selectProject', () => {
|
|
|
60
127
|
});
|
|
61
128
|
expect(mockLightdashApi).not.toHaveBeenCalled();
|
|
62
129
|
});
|
|
63
|
-
it('resolves
|
|
130
|
+
it.each(['flag', 'env'])('resolves a project slug from the %s through the org projects list', async (source) => {
|
|
131
|
+
if (source === 'env')
|
|
132
|
+
vi.stubEnv('LIGHTDASH_PROJECT', 'jaffle-shop');
|
|
64
133
|
const config = {
|
|
65
134
|
context: { project: MAIN_UUID },
|
|
66
135
|
};
|
|
@@ -68,8 +137,23 @@ describe('selectProject', () => {
|
|
|
68
137
|
{ projectUuid: PREVIEW_UUID, slug: 'other', name: 'Other' },
|
|
69
138
|
{ projectUuid: MAIN_UUID, slug: 'jaffle-shop', name: 'Jaffle' },
|
|
70
139
|
]);
|
|
71
|
-
const selection = await (0, selectProject_1.selectProject)(config, 'jaffle-shop');
|
|
72
|
-
expect(selection).toEqual({
|
|
140
|
+
const selection = await (0, selectProject_1.selectProject)(config, source === 'flag' ? 'jaffle-shop' : undefined);
|
|
141
|
+
expect(selection).toEqual({
|
|
142
|
+
projectUuid: MAIN_UUID,
|
|
143
|
+
isPreview: false,
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
it.each([undefined, ''])('keeps the active preview default without an environment override (%s)', async (envProject) => {
|
|
147
|
+
vi.stubEnv('LIGHTDASH_PROJECT', envProject);
|
|
148
|
+
vi.spyOn(globalState_1.default, 'isNonInteractive').mockReturnValue(true);
|
|
149
|
+
mockPreviewProjectResponse(PREVIEW_UUID);
|
|
150
|
+
expect(await (0, selectProject_1.selectProject)({
|
|
151
|
+
context: {
|
|
152
|
+
project: MAIN_UUID,
|
|
153
|
+
previewProject: PREVIEW_UUID,
|
|
154
|
+
},
|
|
155
|
+
})).toEqual({ projectUuid: PREVIEW_UUID, isPreview: true });
|
|
156
|
+
expect(inquirer_1.default.prompt).not.toHaveBeenCalled();
|
|
73
157
|
});
|
|
74
158
|
it('returns the main project when only the main project is configured', async () => {
|
|
75
159
|
const config = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightdash/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.195.0",
|
|
4
4
|
"description": "Lightdash CLI tool",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"@actions/core": "1.11.1",
|
|
23
23
|
"@aws-sdk/credential-providers": "3.995.0",
|
|
24
24
|
"@casl/ability": "6.8.0",
|
|
25
|
-
"@lightdash/common": "2.
|
|
26
|
-
"@lightdash/warehouses": "2.
|
|
25
|
+
"@lightdash/common": "2.195.0",
|
|
26
|
+
"@lightdash/warehouses": "2.195.0",
|
|
27
27
|
"@sidvind/better-ajv-errors": "7.0.0",
|
|
28
28
|
"@types/columnify": "1.5.1",
|
|
29
29
|
"ajv": "8.18.0",
|