@lightdash/cli 0.2420.0 → 0.2422.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 +128 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/dbt/models.js +1 -1
- package/dist/globalState.d.ts +3 -0
- package/dist/globalState.d.ts.map +1 -1
- package/dist/globalState.js +7 -0
- package/dist/handlers/createProject.d.ts +1 -0
- package/dist/handlers/createProject.d.ts.map +1 -1
- package/dist/handlers/createProject.js +26 -15
- package/dist/handlers/dbt/getDbtVersion.js +2 -2
- package/dist/handlers/deploy.d.ts +1 -0
- package/dist/handlers/deploy.d.ts.map +1 -1
- package/dist/handlers/deploy.js +2 -1
- package/dist/handlers/login.d.ts +2 -0
- package/dist/handlers/login.d.ts.map +1 -1
- package/dist/handlers/login.js +87 -1
- package/dist/handlers/setProject.d.ts.map +1 -1
- package/dist/handlers/setProject.js +4 -1
- package/dist/index.js +11 -0
- package/package.json +3 -3
package/dist/dbt/models.js
CHANGED
|
@@ -155,7 +155,7 @@ const findAndUpdateModelYaml = async ({ model, table, docs, includeMeta, project
|
|
|
155
155
|
});
|
|
156
156
|
// Delete columns that no longer exist in the warehouse
|
|
157
157
|
const deletedColumnNames = existingColumnNames.filter((c) => !generatedModel.columns.map((gc) => gc.name).includes(c));
|
|
158
|
-
if (deletedColumnNames.length > 0 &&
|
|
158
|
+
if (deletedColumnNames.length > 0 && !globalState_1.default.isNonInteractive()) {
|
|
159
159
|
let answers = { isConfirm: assumeYes };
|
|
160
160
|
if (!assumeYes) {
|
|
161
161
|
const spinner = globalState_1.default.getActiveSpinner();
|
package/dist/globalState.d.ts
CHANGED
|
@@ -6,9 +6,12 @@ type PromptAnswer = {
|
|
|
6
6
|
};
|
|
7
7
|
declare class GlobalState {
|
|
8
8
|
private verbose;
|
|
9
|
+
private nonInteractive;
|
|
9
10
|
private activeSpinner;
|
|
10
11
|
private savedPromptAnswers;
|
|
11
12
|
constructor();
|
|
13
|
+
setNonInteractive(value: boolean): void;
|
|
14
|
+
isNonInteractive(): boolean;
|
|
12
15
|
getActiveSpinner(): ora.Ora | undefined;
|
|
13
16
|
startSpinner(options?: ora.Options | string): ora.Ora;
|
|
14
17
|
log(message: unknown, ...optionalParams: unknown[]): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"globalState.d.ts","sourceRoot":"","sources":["../src/globalState.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,KAAK,YAAY,GAAG;IAChB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC;AAEF,cAAM,WAAW;IACb,OAAO,CAAC,OAAO,CAAkB;IAEjC,OAAO,CAAC,aAAa,CAAsB;IAE3C,OAAO,CAAC,kBAAkB,CAAe;;IAMzC,gBAAgB;IAIhB,YAAY,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,MAAM,GAAG,GAAG,CAAC,GAAG;IAMrD,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,OAAO,EAAE;IAUlD,UAAU,CAAC,OAAO,EAAE,OAAO;IAI3B,oBAAoB,CAAC,CAAC,SAAS,MAAM,YAAY,EAC7C,MAAM,EAAE,CAAC,GACV,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS;IAI9B,gBAAgB,CAAC,CAAC,SAAS,MAAM,YAAY,EACzC,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAK1B,iBAAiB;IAIjB,KAAK,CAAC,OAAO,EAAE,MAAM;IAMrB,cAAc,CAAC,MAAM,EAAE,MAAM;CAKhC;;AAED,wBAAiC"}
|
|
1
|
+
{"version":3,"file":"globalState.d.ts","sourceRoot":"","sources":["../src/globalState.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,KAAK,YAAY,GAAG;IAChB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC;AAEF,cAAM,WAAW;IACb,OAAO,CAAC,OAAO,CAAkB;IAEjC,OAAO,CAAC,cAAc,CAAkB;IAExC,OAAO,CAAC,aAAa,CAAsB;IAE3C,OAAO,CAAC,kBAAkB,CAAe;;IAMzC,iBAAiB,CAAC,KAAK,EAAE,OAAO;IAIhC,gBAAgB,IAAI,OAAO;IAI3B,gBAAgB;IAIhB,YAAY,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,MAAM,GAAG,GAAG,CAAC,GAAG;IAMrD,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,OAAO,EAAE;IAUlD,UAAU,CAAC,OAAO,EAAE,OAAO;IAI3B,oBAAoB,CAAC,CAAC,SAAS,MAAM,YAAY,EAC7C,MAAM,EAAE,CAAC,GACV,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS;IAI9B,gBAAgB,CAAC,CAAC,SAAS,MAAM,YAAY,EACzC,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAK1B,iBAAiB;IAIjB,KAAK,CAAC,OAAO,EAAE,MAAM;IAMrB,cAAc,CAAC,MAAM,EAAE,MAAM;CAKhC;;AAED,wBAAiC"}
|
package/dist/globalState.js
CHANGED
|
@@ -5,11 +5,18 @@ const ora_1 = tslib_1.__importDefault(require("ora"));
|
|
|
5
5
|
const styles = tslib_1.__importStar(require("./styles"));
|
|
6
6
|
class GlobalState {
|
|
7
7
|
verbose = false;
|
|
8
|
+
nonInteractive = false;
|
|
8
9
|
activeSpinner;
|
|
9
10
|
savedPromptAnswers;
|
|
10
11
|
constructor() {
|
|
11
12
|
this.savedPromptAnswers = {};
|
|
12
13
|
}
|
|
14
|
+
setNonInteractive(value) {
|
|
15
|
+
this.nonInteractive = value;
|
|
16
|
+
}
|
|
17
|
+
isNonInteractive() {
|
|
18
|
+
return this.nonInteractive || process.env.CI === 'true';
|
|
19
|
+
}
|
|
13
20
|
getActiveSpinner() {
|
|
14
21
|
return this.activeSpinner;
|
|
15
22
|
}
|
|
@@ -14,6 +14,7 @@ type CreateProjectOptions = {
|
|
|
14
14
|
warehouseCredentials?: boolean;
|
|
15
15
|
organizationCredentials?: string;
|
|
16
16
|
targetPath?: string;
|
|
17
|
+
assumeYes?: boolean;
|
|
17
18
|
};
|
|
18
19
|
export declare const createProject: (options: CreateProjectOptions) => Promise<ApiCreateProjectResults | undefined>;
|
|
19
20
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createProject.d.ts","sourceRoot":"","sources":["../../src/handlers/createProject.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,+BAA+B,EAI/B,WAAW,EAGX,KAAK,uBAAuB,EAI/B,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"createProject.d.ts","sourceRoot":"","sources":["../../src/handlers/createProject.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,+BAA+B,EAI/B,WAAW,EAGX,KAAK,uBAAuB,EAI/B,MAAM,mBAAmB,CAAC;AAgE3B,eAAO,MAAM,kCAAkC,SACrC,MAAM,KACb,OAAO,CAAC,MAAM,CAyChB,CAAC;AAEF,KAAK,oBAAoB,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,+BAA+B,CAAC;IACrD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAYF,eAAO,MAAM,aAAa,YACb,oBAAoB,KAC9B,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAmM7C,CAAC"}
|
|
@@ -28,8 +28,9 @@ const askToRememberAnswer = async () => {
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
|
-
const askPermissionToStoreWarehouseCredentials = async () => {
|
|
32
|
-
if (
|
|
31
|
+
const askPermissionToStoreWarehouseCredentials = async (assumeYes = false) => {
|
|
32
|
+
if (globalState_1.default.isNonInteractive() || assumeYes) {
|
|
33
|
+
globalState_1.default.debug('> Auto-accepting warehouse credentials storage');
|
|
33
34
|
return true;
|
|
34
35
|
}
|
|
35
36
|
const config = await (0, config_1.getConfig)();
|
|
@@ -151,7 +152,7 @@ const createProject = async (options) => {
|
|
|
151
152
|
target: options.target,
|
|
152
153
|
});
|
|
153
154
|
globalState_1.default.debug(`> Using target name ${targetName}`);
|
|
154
|
-
const canStoreWarehouseCredentials = await askPermissionToStoreWarehouseCredentials();
|
|
155
|
+
const canStoreWarehouseCredentials = await askPermissionToStoreWarehouseCredentials(options.assumeYes);
|
|
155
156
|
if (!canStoreWarehouseCredentials) {
|
|
156
157
|
globalState_1.default.debug('> User declined to store warehouse credentials use --no-warehouse-credentials to create a project without warehouse credentials');
|
|
157
158
|
return undefined;
|
|
@@ -168,19 +169,29 @@ const createProject = async (options) => {
|
|
|
168
169
|
if (credentials?.type === common_1.WarehouseTypes.BIGQUERY &&
|
|
169
170
|
credentials.keyfileContents.project_id &&
|
|
170
171
|
credentials.keyfileContents.project_id !== credentials.project) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
172
|
+
if (globalState_1.default.isNonInteractive() && !options.assumeYes) {
|
|
173
|
+
throw new Error(`BigQuery project mismatch: credentials file uses "${credentials.keyfileContents.project_id}" ` +
|
|
174
|
+
`but profiles.yml specifies "${credentials.project}". ` +
|
|
175
|
+
'This may cause permission issues. Use --assume-yes to bypass this warning.');
|
|
176
|
+
}
|
|
177
|
+
if (options.assumeYes) {
|
|
178
|
+
globalState_1.default.debug(`> Auto-accepting BigQuery project mismatch (credentials: ${credentials.keyfileContents.project_id}, profiles: ${credentials.project})`);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
const spinner = globalState_1.default.getActiveSpinner();
|
|
182
|
+
spinner?.stop();
|
|
183
|
+
const answers = await inquirer_1.default.prompt([
|
|
184
|
+
{
|
|
185
|
+
type: 'confirm',
|
|
186
|
+
name: 'isConfirm',
|
|
187
|
+
message: `${styles.title('Warning')}: Your project on your credentials file ${styles.title(credentials.keyfileContents.project_id)} does not match your project on your profiles.yml ${styles.title(credentials.project)}, this might cause permission issues when accessing data on the warehouse. Are you sure you want to continue?`,
|
|
188
|
+
},
|
|
189
|
+
]);
|
|
190
|
+
if (!answers.isConfirm) {
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
spinner?.start();
|
|
182
194
|
}
|
|
183
|
-
spinner?.start();
|
|
184
195
|
}
|
|
185
196
|
if (credentials?.type === common_1.WarehouseTypes.SNOWFLAKE &&
|
|
186
197
|
credentials?.authenticationType ===
|
|
@@ -77,7 +77,7 @@ const getDbtVersion = async () => {
|
|
|
77
77
|
const message = `We don't currently support version ${verboseVersion} on Lightdash. We'll interpret it as version ${fallbackVersionOption} instead, which might cause unexpected errors or behavior. For the best experience, please use a supported version (${supportedVersionsRangeMessage}).`;
|
|
78
78
|
const spinner = globalState_1.default.getActiveSpinner();
|
|
79
79
|
spinner?.stop();
|
|
80
|
-
if (
|
|
80
|
+
if (globalState_1.default.isNonInteractive()) {
|
|
81
81
|
console.error(styles.warning(message));
|
|
82
82
|
}
|
|
83
83
|
else {
|
|
@@ -101,7 +101,7 @@ const getDbtVersion = async () => {
|
|
|
101
101
|
const message = `Support for dbt Cloud CLI is still experimental and might not work as expected.`;
|
|
102
102
|
const spinner = globalState_1.default.getActiveSpinner();
|
|
103
103
|
spinner?.stop();
|
|
104
|
-
if (
|
|
104
|
+
if (globalState_1.default.isNonInteractive()) {
|
|
105
105
|
console.error(styles.warning(message));
|
|
106
106
|
}
|
|
107
107
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/handlers/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,OAAO,EACP,YAAY,EASf,MAAM,mBAAmB,CAAC;AAiB3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,KAAK,oBAAoB,GAAG,iBAAiB,GAAG;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/handlers/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,OAAO,EACP,YAAY,EASf,MAAM,mBAAmB,CAAC;AAiB3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,KAAK,oBAAoB,GAAG,iBAAiB,GAAG;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,KAAK,UAAU,GAAG,oBAAoB,GAAG;IACrC,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AAkCF,eAAO,MAAM,MAAM,aACL,CAAC,OAAO,GAAG,YAAY,CAAC,EAAE,WAC3B,UAAU,KACpB,OAAO,CAAC,IAAI,CAmEd,CAAC;AA+FF,eAAO,MAAM,aAAa,oBAA2B,oBAAoB,kBAwFxE,CAAC"}
|
package/dist/handlers/deploy.js
CHANGED
|
@@ -96,7 +96,7 @@ const createNewProject = async (executionId, options) => {
|
|
|
96
96
|
}
|
|
97
97
|
// If interactive and no name provided, prompt for project name
|
|
98
98
|
let projectName = defaultProjectName;
|
|
99
|
-
if (options.create === true &&
|
|
99
|
+
if (options.create === true && !globalState_1.default.isNonInteractive()) {
|
|
100
100
|
const answers = await inquirer_1.default.prompt([
|
|
101
101
|
{
|
|
102
102
|
type: 'input',
|
|
@@ -128,6 +128,7 @@ const createNewProject = async (executionId, options) => {
|
|
|
128
128
|
name: projectName,
|
|
129
129
|
type: common_1.ProjectType.DEFAULT,
|
|
130
130
|
warehouseCredentials: options.warehouseCredentials,
|
|
131
|
+
assumeYes: options.assumeYes,
|
|
131
132
|
});
|
|
132
133
|
const project = results?.project;
|
|
133
134
|
if (!project) {
|
package/dist/handlers/login.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/handlers/login.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/handlers/login.ts"],"names":[],"mappings":"AAkBA,KAAK,YAAY,GAAG;IAChB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;CACpB,CAAC;AA4JF,eAAO,MAAM,KAAK,aACJ,MAAM,GAAG,SAAS,WACnB,YAAY,kBAkJxB,CAAC"}
|
package/dist/handlers/login.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.login = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const common_1 = require("@lightdash/common");
|
|
6
|
+
const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
|
|
6
7
|
const node_fetch_1 = tslib_1.__importDefault(require("node-fetch"));
|
|
7
8
|
const url_1 = require("url");
|
|
8
9
|
const analytics_1 = require("../analytics/analytics");
|
|
@@ -49,6 +50,8 @@ const normalizeUrl = (input) => {
|
|
|
49
50
|
const getLoginMethod = (options) => {
|
|
50
51
|
if (options.token)
|
|
51
52
|
return 'token';
|
|
53
|
+
if (options.email)
|
|
54
|
+
return 'password';
|
|
52
55
|
return 'oauth';
|
|
53
56
|
};
|
|
54
57
|
const loginWithToken = async (url, token) => {
|
|
@@ -68,6 +71,63 @@ const loginWithToken = async (url, token) => {
|
|
|
68
71
|
token,
|
|
69
72
|
};
|
|
70
73
|
};
|
|
74
|
+
const loginWithEmailPassword = async (url, email, password) => {
|
|
75
|
+
const loginUrl = new url_1.URL('/api/v1/login', url).href;
|
|
76
|
+
const loginResponse = await (0, node_fetch_1.default)(loginUrl, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
headers: {
|
|
79
|
+
'Content-Type': 'application/json',
|
|
80
|
+
},
|
|
81
|
+
body: JSON.stringify({ email, password }),
|
|
82
|
+
});
|
|
83
|
+
if (loginResponse.status !== 200) {
|
|
84
|
+
const errorBody = await loginResponse.json().catch(() => ({}));
|
|
85
|
+
const errorMessage = errorBody.error?.message ||
|
|
86
|
+
'Invalid credentials';
|
|
87
|
+
throw new common_1.AuthorizationError(`Cannot sign in with email/password: ${errorMessage}\n\n` +
|
|
88
|
+
`🤖 Coding agents: If your password has special characters (like !), read:\n` +
|
|
89
|
+
` packages/cli/README.md#claude-code--agentic-tools-passwords-with-special-characters`);
|
|
90
|
+
}
|
|
91
|
+
const cookies = loginResponse.headers.get('set-cookie');
|
|
92
|
+
if (!cookies) {
|
|
93
|
+
throw new common_1.AuthorizationError('Login succeeded but no session cookie received');
|
|
94
|
+
}
|
|
95
|
+
const patUrl = new url_1.URL('/api/v1/user/me/personal-access-tokens', url).href;
|
|
96
|
+
const patResponse = await (0, node_fetch_1.default)(patUrl, {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
headers: {
|
|
99
|
+
'Content-Type': 'application/json',
|
|
100
|
+
Cookie: cookies,
|
|
101
|
+
},
|
|
102
|
+
body: JSON.stringify({
|
|
103
|
+
description: 'Lightdash CLI',
|
|
104
|
+
expiresAt: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(),
|
|
105
|
+
autoGenerated: false,
|
|
106
|
+
}),
|
|
107
|
+
});
|
|
108
|
+
if (patResponse.status !== 200) {
|
|
109
|
+
const errorBody = await patResponse.json().catch(() => ({}));
|
|
110
|
+
throw new common_1.AuthorizationError(`Failed to create personal access token: ${errorBody.error
|
|
111
|
+
?.message || 'Unknown error'}`);
|
|
112
|
+
}
|
|
113
|
+
const patBody = (await patResponse.json());
|
|
114
|
+
const { token } = patBody.results;
|
|
115
|
+
const userInfoUrl = new url_1.URL('/api/v1/user', url).href;
|
|
116
|
+
const userResponse = await (0, node_fetch_1.default)(userInfoUrl, {
|
|
117
|
+
method: 'GET',
|
|
118
|
+
headers: (0, utils_1.buildRequestHeaders)(token),
|
|
119
|
+
});
|
|
120
|
+
if (userResponse.status !== 200) {
|
|
121
|
+
throw new common_1.AuthorizationError('Failed to get user info after login');
|
|
122
|
+
}
|
|
123
|
+
const userBody = (await userResponse.json());
|
|
124
|
+
const { userUuid, organizationUuid } = userBody.results;
|
|
125
|
+
return {
|
|
126
|
+
userUuid,
|
|
127
|
+
organizationUuid,
|
|
128
|
+
token,
|
|
129
|
+
};
|
|
130
|
+
};
|
|
71
131
|
const login = async (urlInput, options) => {
|
|
72
132
|
globalState_1.default.setVerbose(options.verbose);
|
|
73
133
|
await (0, apiClient_1.checkLightdashVersion)();
|
|
@@ -101,10 +161,36 @@ const login = async (urlInput, options) => {
|
|
|
101
161
|
const cloudServer = url.replace('lightdash.com', 'lightdash.cloud');
|
|
102
162
|
console.error(`\n${styles.title('Warning')}: Login URL ${styles.secondary(url)} does not match a valid cloud server, perhaps you meant ${styles.secondary(cloudServer)} ?\n`);
|
|
103
163
|
}
|
|
164
|
+
const email = options.email || process.env.LIGHTDASH_CLI_EMAIL;
|
|
165
|
+
const password = process.env.LIGHTDASH_CLI_PASSWORD;
|
|
104
166
|
let loginResult;
|
|
105
167
|
if (options.token) {
|
|
106
168
|
loginResult = await loginWithToken(url, options.token);
|
|
107
169
|
}
|
|
170
|
+
else if (email) {
|
|
171
|
+
let finalPassword = password;
|
|
172
|
+
if (!finalPassword) {
|
|
173
|
+
if (globalState_1.default.isNonInteractive()) {
|
|
174
|
+
throw new common_1.AuthorizationError('Password is required when using --email in non-interactive mode.\n' +
|
|
175
|
+
'Set the LIGHTDASH_CLI_PASSWORD environment variable:\n\n' +
|
|
176
|
+
` export LIGHTDASH_CLI_PASSWORD='your_password'\n` +
|
|
177
|
+
` lightdash login ${url} --email ${email} --non-interactive\n`);
|
|
178
|
+
}
|
|
179
|
+
console.error(`\n${styles.secondary('💡 Tip for coding agents:')} To avoid interactive prompts, exit and run:\n` +
|
|
180
|
+
` export LIGHTDASH_CLI_PASSWORD='your_password'\n` +
|
|
181
|
+
` lightdash login ${url} --email ${email}\n`);
|
|
182
|
+
const answers = await inquirer_1.default.prompt([
|
|
183
|
+
{
|
|
184
|
+
type: 'password',
|
|
185
|
+
name: 'password',
|
|
186
|
+
message: 'Enter your password:',
|
|
187
|
+
mask: '*',
|
|
188
|
+
},
|
|
189
|
+
]);
|
|
190
|
+
finalPassword = answers.password;
|
|
191
|
+
}
|
|
192
|
+
loginResult = await loginWithEmailPassword(url, email, finalPassword);
|
|
193
|
+
}
|
|
108
194
|
else {
|
|
109
195
|
loginResult = await (0, oauthLogin_1.loginWithOauth)(url);
|
|
110
196
|
}
|
|
@@ -130,7 +216,7 @@ const login = async (urlInput, options) => {
|
|
|
130
216
|
if (options.project) {
|
|
131
217
|
await (0, setProject_1.setProjectCommand)(undefined, options.project);
|
|
132
218
|
}
|
|
133
|
-
else if (
|
|
219
|
+
else if (globalState_1.default.isNonInteractive()) {
|
|
134
220
|
await (0, setProject_1.setFirstProject)();
|
|
135
221
|
}
|
|
136
222
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setProject.d.ts","sourceRoot":"","sources":["../../src/handlers/setProject.ts"],"names":[],"mappings":"AAOA,KAAK,iBAAiB,GAAG;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,iBAAiB,UAAiB,MAAM,SAAS,MAAM,
|
|
1
|
+
{"version":3,"file":"setProject.d.ts","sourceRoot":"","sources":["../../src/handlers/setProject.ts"],"names":[],"mappings":"AAOA,KAAK,iBAAiB,GAAG;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,iBAAiB,UAAiB,MAAM,SAAS,MAAM,kBAuDnE,CAAC;AAEF,eAAO,MAAM,eAAe,qBAmB3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,YAAmB,iBAAiB,kBAGjE,CAAC"}
|
|
@@ -20,7 +20,10 @@ const setProjectCommand = async (name, uuid) => {
|
|
|
20
20
|
// --uuid or --name options
|
|
21
21
|
if (uuid !== undefined || name !== undefined) {
|
|
22
22
|
selectedProject = projects.find((project) => project.name === name || project.projectUuid === uuid);
|
|
23
|
-
|
|
23
|
+
}
|
|
24
|
+
else if (globalState_1.default.isNonInteractive()) {
|
|
25
|
+
globalState_1.default.debug('> Non-interactive mode: selecting first project');
|
|
26
|
+
[selectedProject] = projects;
|
|
24
27
|
}
|
|
25
28
|
else {
|
|
26
29
|
const answers = await inquirer_1.default.prompt([
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ const common_1 = require("@lightdash/common");
|
|
|
6
6
|
const commander_1 = require("commander");
|
|
7
7
|
const uuid_1 = require("uuid");
|
|
8
8
|
const env_1 = require("./env");
|
|
9
|
+
const globalState_1 = tslib_1.__importDefault(require("./globalState"));
|
|
9
10
|
const compile_1 = require("./handlers/compile");
|
|
10
11
|
const refresh_1 = require("./handlers/dbt/refresh");
|
|
11
12
|
const run_1 = require("./handlers/dbt/run");
|
|
@@ -68,6 +69,13 @@ commander_1.program
|
|
|
68
69
|
.version(env_1.CLI_VERSION)
|
|
69
70
|
.name(styles.title('⚡️lightdash'))
|
|
70
71
|
.description('Developer tools for dbt and Lightdash.\nSee https://docs.lightdash.com for more help and examples')
|
|
72
|
+
.option('--non-interactive', 'Disable all interactive prompts. Commands fail with helpful error if required input is missing.')
|
|
73
|
+
.hook('preAction', (thisCommand) => {
|
|
74
|
+
const opts = thisCommand.opts();
|
|
75
|
+
if (opts.nonInteractive) {
|
|
76
|
+
globalState_1.default.setNonInteractive(true);
|
|
77
|
+
}
|
|
78
|
+
})
|
|
71
79
|
.showHelpAfterError(styles.bold('Run ⚡️lightdash help [command] for more information'))
|
|
72
80
|
.addHelpText('after', `
|
|
73
81
|
${styles.bold('Examples:')}
|
|
@@ -98,9 +106,11 @@ ${styles.bold('Examples:')}
|
|
|
98
106
|
${styles.title('⚡')}️lightdash ${styles.bold('login')} https://custom.lightdash.domain/projects/123 ${styles.secondary('-- Strips path, uses https://custom.lightdash.domain (opens browser for OAuth)')}
|
|
99
107
|
${styles.title('⚡')}️lightdash ${styles.bold('login')} http://localhost:3000 ${styles.secondary('-- Preserves http protocol for local development')}
|
|
100
108
|
${styles.title('⚡')}️lightdash ${styles.bold('login')} --token 12345 ${styles.secondary('-- Logs in with API token using saved URL (bypasses OAuth)')}
|
|
109
|
+
${styles.title('⚡')}️lightdash ${styles.bold('login')} http://localhost:3000 --email demo@lightdash.com ${styles.secondary('-- Local dev only: prompts for password securely')}
|
|
101
110
|
`)
|
|
102
111
|
.option('--token <token>', 'Login with an API access token', undefined)
|
|
103
112
|
.option('--project <project uuid>', 'Select a project by UUID after login', parseProjectArgument, undefined)
|
|
113
|
+
.option('--email <email>', 'Login with email and password', undefined)
|
|
104
114
|
.option('--verbose', undefined, false)
|
|
105
115
|
.action(login_1.login);
|
|
106
116
|
// CONFIG
|
|
@@ -306,6 +316,7 @@ commander_1.program
|
|
|
306
316
|
.option('--no-warehouse-credentials', 'Create project without warehouse credentials. Skips dbt compile + warehouse catalog')
|
|
307
317
|
.option('--organization-credentials <name>', 'Use organization warehouse credentials with the specified name (Enterprise Edition feature)')
|
|
308
318
|
.option('--disable-timestamp-conversion [true|false]', 'Disable timestamp conversion to UTC for Snowflake warehouses. Only use this if your timestamp values are already in UTC.', parseDisableTimestampConversionOption, false)
|
|
319
|
+
.option('-y, --assume-yes', 'assume yes to prompts', false)
|
|
309
320
|
.action(deploy_1.deployHandler);
|
|
310
321
|
commander_1.program
|
|
311
322
|
.command('refresh')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightdash/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2422.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"unique-names-generator": "^4.7.1",
|
|
39
39
|
"uuid": "^11.0.3",
|
|
40
40
|
"yaml": "^2.7.0",
|
|
41
|
-
"@lightdash/common": "0.
|
|
42
|
-
"@lightdash/warehouses": "0.
|
|
41
|
+
"@lightdash/common": "0.2422.0",
|
|
42
|
+
"@lightdash/warehouses": "0.2422.0"
|
|
43
43
|
},
|
|
44
44
|
"description": "Lightdash CLI tool",
|
|
45
45
|
"devDependencies": {
|