Skip to content

Commit 2d545d0

Browse files
Merge branch 'master' into fix-received-misspelled
2 parents a756d14 + 646bd9d commit 2d545d0

File tree

11 files changed

+80
-380
lines changed

11 files changed

+80
-380
lines changed

docs/pages/reference/data-model/pre-aggregations.mdx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,12 @@ To have a pre-aggregation rebuild at a specific time of day, you can use a CRON
926926

927927
You can also use `every` with `sql`:
928928

929+
<WarningBox>
930+
931+
Using CRON strings and `sql` is not supported and will result in a compilation error.
932+
933+
</WarningBox>
934+
929935
<CodeTabs>
930936

931937
```javascript
@@ -1756,4 +1762,4 @@ cubes:
17561762
[ref-aggregating-indexes]: /product/caching/using-pre-aggregations#aggregating-indexes
17571763
[ref-pre-aggs]: /product/caching/using-pre-aggregations
17581764
[ref-ref-cubes]: /reference/data-model/cube
1759-
[ref-custom-granularity]: /reference/data-model/dimensions#granularities
1765+
[ref-custom-granularity]: /reference/data-model/dimensions#granularities

packages/cubejs-backend-cloud/src/cloud.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import fetch, { RequestInit } from 'node-fetch';
22
import FormData from 'form-data';
33
import path from 'path';
44
import { ReadStream } from 'fs';
5+
import { DotenvParseOutput } from '@cubejs-backend/dotenv';
56

67
export type AuthObject = {
78
auth: string,
@@ -113,22 +114,18 @@ export class CubeCloudClient {
113114
const formData = new FormData();
114115
formData.append('transaction', JSON.stringify(transaction));
115116
formData.append('fileName', fileName);
116-
formData.append('file', {
117-
value: data,
118-
options: {
119-
filename: path.basename(fileName),
120-
contentType: 'application/octet-stream'
121-
}
117+
formData.append('file', data, {
118+
filename: path.basename(fileName),
119+
contentType: 'application/octet-stream'
122120
});
123121

124122
// Get the form data buffer and headers
125-
const formDataBuffer = formData.getBuffer();
126123
const formDataHeaders = formData.getHeaders();
127124

128125
return this.request({
129126
url: (deploymentId: string) => `build/deploy/${deploymentId}/upload-file${this.extendRequestByLivePreview()}`,
130127
method: 'POST',
131-
body: formDataBuffer,
128+
body: formData,
132129
headers: {
133130
...formDataHeaders,
134131
},
@@ -149,9 +146,10 @@ export class CubeCloudClient {
149146
});
150147
}
151148

152-
public setEnvVars({ envVariables, auth }: { envVariables: any, auth?: AuthObject }) {
149+
public setEnvVars({ envVariables, auth, replaceEnv }: { envVariables: DotenvParseOutput, auth?: AuthObject, replaceEnv?: boolean }) {
150+
const params = new URLSearchParams({ replaceEnv: Boolean(replaceEnv).toString() });
153151
return this.request({
154-
url: (deploymentId) => `build/deploy/${deploymentId}/set-env`,
152+
url: (deploymentId) => `build/deploy/${deploymentId}/set-env?${params.toString()}`,
155153
method: 'POST',
156154
body: JSON.stringify({ envVariables: JSON.stringify(envVariables) }),
157155
headers: {

packages/cubejs-backend-cloud/src/deploy.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import crypto from 'crypto';
22
import path from 'path';
33
import fs from 'fs-extra';
4+
import { DotenvParseOutput } from '@cubejs-backend/dotenv';
45
import { CubeCloudClient } from './cloud';
56

67
type DeployDirectoryOptions = {
@@ -64,10 +65,10 @@ export class DeployDirectory {
6465
}
6566

6667
type DeployHooks = {
67-
onStart?: Function,
68-
onUpdate?: Function,
69-
onUpload?: Function,
70-
onFinally?: Function
68+
onStart?: (deploymentName: string, files: string[]) => void,
69+
onUpdate?: (i: number, { file }: { file: string}) => void,
70+
onUpload?: (files: string[], file: string) => void,
71+
onFinally?: () => void
7172
};
7273

7374
export interface DeployResponse {
@@ -78,6 +79,7 @@ export interface DeployResponse {
7879
export class DeployController {
7980
public constructor(
8081
protected readonly cubeCloudClient: CubeCloudClient,
82+
protected readonly envs: { envVariables?: DotenvParseOutput, replaceEnv?: boolean } = {},
8183
protected readonly hooks: DeployHooks = {}
8284
) {
8385
}
@@ -90,6 +92,13 @@ export class DeployController {
9092
const upstreamHashes = await this.cubeCloudClient.getUpstreamHashes();
9193
const { transaction, deploymentName } = await this.cubeCloudClient.startUpload();
9294

95+
if (this.envs.envVariables) {
96+
const { envVariables, replaceEnv } = this.envs;
97+
if (Object.keys(this.envs.envVariables).length) {
98+
await this.cubeCloudClient.setEnvVars({ envVariables, replaceEnv });
99+
}
100+
}
101+
93102
const files = Object.keys(fileHashes);
94103
const fileHashesPosix: Record<string, any> = {};
95104
if (this.hooks.onStart) this.hooks.onStart(deploymentName, files);

packages/cubejs-base-driver/src/BaseDriver.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,20 +470,20 @@ export abstract class BaseDriver implements DriverInterface {
470470
}
471471
}
472472

473-
public getSchemas() {
473+
public getSchemas(): Promise<QuerySchemasResult[]> {
474474
const query = this.getSchemasQuery();
475475
return this.query<QuerySchemasResult>(query);
476476
}
477477

478-
public getTablesForSpecificSchemas(schemas: QuerySchemasResult[]) {
478+
public getTablesForSpecificSchemas(schemas: QuerySchemasResult[]): Promise<QueryTablesResult[]> {
479479
const schemasPlaceholders = schemas.map((_, idx) => this.param(idx)).join(', ');
480480
const schemaNames = schemas.map(s => s.schema_name);
481481

482482
const query = this.getTablesForSpecificSchemasQuery(schemasPlaceholders);
483483
return this.query<QueryTablesResult>(query, schemaNames);
484484
}
485485

486-
public async getColumnsForSpecificTables(tables: QueryTablesResult[]) {
486+
public async getColumnsForSpecificTables(tables: QueryTablesResult[]): Promise<QueryColumnsResult[]> {
487487
const groupedBySchema: Record<string, string[]> = {};
488488
tables.forEach((t) => {
489489
if (!groupedBySchema[t.schema_name]) {

packages/cubejs-bigquery-driver/src/BigQueryDriver.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,14 +222,14 @@ export class BigQueryDriver extends BaseDriver implements DriverInterface {
222222
return dataSetsColumns.reduce((prev, current) => Object.assign(prev, current), {});
223223
}
224224

225-
public async getSchemas(): Promise<QuerySchemasResult[]> {
225+
public override async getSchemas(): Promise<QuerySchemasResult[]> {
226226
const dataSets = await this.bigquery.getDatasets();
227227
return dataSets[0].filter((dataSet) => dataSet.id).map((dataSet) => ({
228228
schema_name: dataSet.id!,
229229
}));
230230
}
231231

232-
public async getTablesForSpecificSchemas(schemas: QuerySchemasResult[]): Promise<QueryTablesResult[]> {
232+
public override async getTablesForSpecificSchemas(schemas: QuerySchemasResult[]): Promise<QueryTablesResult[]> {
233233
try {
234234
const allTablePromises = schemas.map(async schema => {
235235
const tables = await this.getTablesQuery(schema.schema_name);
@@ -247,7 +247,7 @@ export class BigQueryDriver extends BaseDriver implements DriverInterface {
247247
}
248248
}
249249

250-
public async getColumnsForSpecificTables(tables: QueryTablesResult[]): Promise<QueryColumnsResult[]> {
250+
public override async getColumnsForSpecificTables(tables: QueryTablesResult[]): Promise<QueryColumnsResult[]> {
251251
try {
252252
const allColumnPromises = tables.map(async table => {
253253
const tableName = `${table.schema_name}.${table.table_name}`;

packages/cubejs-cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
],
3232
"dependencies": {
3333
"@cubejs-backend/dotenv": "^9.0.2",
34+
"@cubejs-backend/cloud": "1.1.13",
3435
"@cubejs-backend/schema-compiler": "1.1.15",
3536
"@cubejs-backend/shared": "1.1.12",
3637
"chalk": "^2.4.2",

packages/cubejs-cli/src/command/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { CommanderStatic } from 'commander';
2+
import { Config } from '@cubejs-backend/cloud';
23

34
import { displayError, event } from '../utils';
4-
import { Config } from '../config';
55

66
const authenticate = async (currentToken: string) => {
77
const config = new Config();

packages/cubejs-cli/src/command/deploy.ts

Lines changed: 33 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,72 @@
1-
import FormData from 'form-data';
21
import fs from 'fs-extra';
32
import path from 'path';
43
import cliProgress from 'cli-progress';
54
import { CommanderStatic } from 'commander';
5+
import { AuthObject, CubeCloudClient, DeployController } from '@cubejs-backend/cloud';
6+
import { ConfigCli } from '../config';
67

7-
import { DeployDirectory } from '../deploy';
88
import { logStage, displayError, event } from '../utils';
9-
import { Config } from '../config';
109

11-
interface Hashes {
12-
[key: string]: {
13-
hash: string;
14-
};
15-
}
16-
17-
interface CloudReqResult {
18-
transaction: string;
19-
deploymentName: string;
20-
}
10+
type DeployOptions = {
11+
directory: string,
12+
auth: AuthObject,
13+
uploadEnv: boolean,
14+
replaceEnv: boolean,
15+
token: string
16+
};
2117

22-
const deploy = async ({ directory, auth, uploadEnv, token }: any) => {
18+
const deploy = async ({ directory, auth, uploadEnv, replaceEnv, token }: DeployOptions) => {
2319
if (!(await fs.pathExists(path.join(process.cwd(), 'node_modules', '@cubejs-backend/server-core')))) {
2420
await displayError(
2521
'@cubejs-backend/server-core dependency not found. Please run deploy command from project root directory and ensure npm install has been run.'
2622
);
2723
}
2824

25+
const config = new ConfigCli();
2926
if (token) {
30-
const config = new Config();
3127
await config.addAuthToken(token);
32-
33-
await event({
34-
event: 'Cube Cloud CLI Authenticate'
35-
});
36-
28+
await event({ event: 'Cube Cloud CLI Authenticate' });
3729
console.log('Token successfully added!');
3830
}
3931

40-
const config = new Config();
4132
const bar = new cliProgress.SingleBar({
4233
format: '- Uploading files | {bar} | {percentage}% || {value} / {total} | {file}',
4334
barCompleteChar: '\u2588',
4435
barIncompleteChar: '\u2591',
4536
hideCursor: true
4637
});
4738

48-
const deployDir = new DeployDirectory({ directory });
49-
const fileHashes: any = await deployDir.fileHashes();
50-
51-
const upstreamHashes: Hashes = await config.cloudReq({
52-
url: (deploymentId: string) => `build/deploy/${deploymentId}/files`,
53-
method: 'GET',
54-
auth
55-
});
56-
57-
const { transaction, deploymentName }: CloudReqResult = await config.cloudReq({
58-
url: (deploymentId: string) => `build/deploy/${deploymentId}/start-upload`,
59-
method: 'POST',
60-
auth
61-
});
62-
63-
if (uploadEnv) {
64-
const envVariables = await config.envFile(`${directory}/.env`);
65-
await config.cloudReq({
66-
url: (deploymentId) => `build/deploy/${deploymentId}/set-env`,
67-
method: 'POST',
68-
body: JSON.stringify({
69-
envVariables: JSON.stringify(envVariables),
70-
}),
71-
headers: {
72-
'Content-type': 'application/json'
73-
},
74-
auth
75-
});
76-
}
77-
78-
await logStage(`Deploying ${deploymentName}...`, 'Cube Cloud CLI Deploy');
79-
80-
const files = Object.keys(fileHashes);
81-
const fileHashesPosix = {};
82-
83-
bar.start(files.length, 0, {
84-
file: ''
85-
});
86-
87-
try {
88-
for (let i = 0; i < files.length; i++) {
89-
const file = files[i];
39+
const envVariables = uploadEnv || replaceEnv ? await config.envFile(`${directory}/.env`) : {};
40+
41+
const cubeCloudClient = new CubeCloudClient(auth || (await config.deployAuthForCurrentDir()));
42+
const deployController = new DeployController(cubeCloudClient, { envVariables, replaceEnv }, {
43+
onStart: async (deploymentName, files) => {
44+
await logStage(`Deploying ${deploymentName}...`, 'Cube Cloud CLI Deploy');
45+
bar.start(files.length, 0, {
46+
file: ''
47+
});
48+
},
49+
onUpdate: (i, { file }) => {
9050
bar.update(i, { file });
91-
92-
const filePosix = file.split(path.sep).join(path.posix.sep);
93-
fileHashesPosix[filePosix] = fileHashes[file];
94-
95-
if (!upstreamHashes[filePosix] || upstreamHashes[filePosix].hash !== fileHashes[file].hash) {
96-
const formData = new FormData();
97-
formData.append('transaction', JSON.stringify(transaction));
98-
formData.append('fileName', filePosix);
99-
formData.append('file', fs.createReadStream(path.join(directory, file)), {
100-
filename: path.basename(file),
101-
contentType: 'application/octet-stream'
102-
});
103-
104-
await config.cloudReq({
105-
url: (deploymentId: string) => `build/deploy/${deploymentId}/upload-file`,
106-
method: 'POST',
107-
body: formData,
108-
auth,
109-
headers: formData.getHeaders()
110-
});
111-
}
51+
},
52+
onUpload: (files) => {
53+
bar.update(files.length, { file: 'Post processing...' });
54+
},
55+
onFinally: () => {
56+
bar.stop();
11257
}
113-
bar.update(files.length, { file: 'Post processing...' });
114-
await config.cloudReq({
115-
url: (deploymentId: string) => `build/deploy/${deploymentId}/finish-upload`,
116-
method: 'POST',
117-
body: JSON.stringify({
118-
transaction,
119-
files: fileHashesPosix
120-
}),
121-
headers: { 'Content-type': 'application/json' },
122-
auth
123-
});
124-
} finally {
125-
bar.stop();
126-
}
58+
});
12759

60+
await deployController.deploy(directory);
12861
await logStage('Done 🎉', 'Cube Cloud CLI Deploy Success');
12962
};
13063

13164
export function configureDeployCommand(program: CommanderStatic) {
13265
program
13366
.command('deploy')
13467
.description('Deploy project to Cube Cloud')
135-
.option('--upload-env', 'Upload .env file to CubeCloud')
68+
.option('--upload-env', 'Use .env file to populate environment variables in Cube Cloud. Only set them once during the very first upload for this deployment')
69+
.option('--replace-env', 'Use .env file to populate environment variables in Cube Cloud. Replace them with new ones during every upload for this deployment')
13670
.option('--token <token>', 'Add auth token to CubeCloud')
13771
.option('--directory [path]', 'Specify path to conf directory', './')
13872
.action(

0 commit comments

Comments
 (0)