@lightdash/cli 2.228.1 → 2.229.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.build +1 -0
- package/package.json +4 -4
- package/dist/.tsbuildinfo +0 -1
- package/dist/config.test.d.ts +0 -2
- package/dist/config.test.d.ts.map +0 -1
- package/dist/config.test.js +0 -72
- package/dist/dbt/context.test.d.ts +0 -2
- package/dist/dbt/context.test.d.ts.map +0 -1
- package/dist/dbt/context.test.js +0 -152
- package/dist/dbt/manifest.test.d.ts +0 -2
- package/dist/dbt/manifest.test.d.ts.map +0 -1
- package/dist/dbt/manifest.test.js +0 -170
- package/dist/dbt/models.test.d.ts +0 -2
- package/dist/dbt/models.test.d.ts.map +0 -1
- package/dist/dbt/models.test.js +0 -139
- package/dist/dbt/profiles.test.d.ts +0 -2
- package/dist/dbt/profiles.test.d.ts.map +0 -1
- package/dist/dbt/profiles.test.js +0 -50
- package/dist/dbt/targets/athena.test.d.ts +0 -2
- package/dist/dbt/targets/athena.test.d.ts.map +0 -1
- package/dist/dbt/targets/athena.test.js +0 -78
- package/dist/dbt/targets/duckdb.test.d.ts +0 -2
- package/dist/dbt/targets/duckdb.test.d.ts.map +0 -1
- package/dist/dbt/targets/duckdb.test.js +0 -149
- package/dist/dbt/targets/redshift.test.d.ts +0 -2
- package/dist/dbt/targets/redshift.test.d.ts.map +0 -1
- package/dist/dbt/targets/redshift.test.js +0 -198
- package/dist/dbt/templating.test.d.ts +0 -2
- package/dist/dbt/templating.test.d.ts.map +0 -1
- package/dist/dbt/templating.test.js +0 -51
- package/dist/dbt/validation.test.d.ts +0 -2
- package/dist/dbt/validation.test.d.ts.map +0 -1
- package/dist/dbt/validation.test.js +0 -67
- package/dist/handlers/apps/appCodeFiles.test.d.ts +0 -2
- package/dist/handlers/apps/appCodeFiles.test.d.ts.map +0 -1
- package/dist/handlers/apps/appCodeFiles.test.js +0 -391
- package/dist/handlers/apps/appsDownload.test.d.ts +0 -2
- package/dist/handlers/apps/appsDownload.test.d.ts.map +0 -1
- package/dist/handlers/apps/appsDownload.test.js +0 -639
- package/dist/handlers/apps/build.test.d.ts +0 -2
- package/dist/handlers/apps/build.test.d.ts.map +0 -1
- package/dist/handlers/apps/build.test.js +0 -252
- package/dist/handlers/apps/createApp.test.d.ts +0 -2
- package/dist/handlers/apps/createApp.test.d.ts.map +0 -1
- package/dist/handlers/apps/createApp.test.js +0 -340
- package/dist/handlers/apps/pathContainment.test.d.ts +0 -2
- package/dist/handlers/apps/pathContainment.test.d.ts.map +0 -1
- package/dist/handlers/apps/pathContainment.test.js +0 -66
- package/dist/handlers/apps/preview.test.d.ts +0 -2
- package/dist/handlers/apps/preview.test.d.ts.map +0 -1
- package/dist/handlers/apps/preview.test.js +0 -353
- package/dist/handlers/apps/previewProxy.test.d.ts +0 -2
- package/dist/handlers/apps/previewProxy.test.d.ts.map +0 -1
- package/dist/handlers/apps/previewProxy.test.js +0 -178
- package/dist/handlers/apps/scaffolding.test.d.ts +0 -2
- package/dist/handlers/apps/scaffolding.test.d.ts.map +0 -1
- package/dist/handlers/apps/scaffolding.test.js +0 -151
- package/dist/handlers/apps/uploadRetry.test.d.ts +0 -2
- package/dist/handlers/apps/uploadRetry.test.d.ts.map +0 -1
- package/dist/handlers/apps/uploadRetry.test.js +0 -103
- package/dist/handlers/apps/validate.test.d.ts +0 -2
- package/dist/handlers/apps/validate.test.d.ts.map +0 -1
- package/dist/handlers/apps/validate.test.js +0 -526
- package/dist/handlers/compile.test.d.ts +0 -2
- package/dist/handlers/compile.test.d.ts.map +0 -1
- package/dist/handlers/compile.test.js +0 -151
- package/dist/handlers/compileProject.test.d.ts +0 -2
- package/dist/handlers/compileProject.test.d.ts.map +0 -1
- package/dist/handlers/compileProject.test.js +0 -637
- package/dist/handlers/compileWarehouseColumnValidation.test.d.ts +0 -2
- package/dist/handlers/compileWarehouseColumnValidation.test.d.ts.map +0 -1
- package/dist/handlers/compileWarehouseColumnValidation.test.js +0 -493
- package/dist/handlers/connectSnowflake.test.d.ts +0 -2
- package/dist/handlers/connectSnowflake.test.d.ts.map +0 -1
- package/dist/handlers/connectSnowflake.test.js +0 -320
- package/dist/handlers/contentAsCode/fileNames.test.d.ts +0 -2
- package/dist/handlers/contentAsCode/fileNames.test.d.ts.map +0 -1
- package/dist/handlers/contentAsCode/fileNames.test.js +0 -79
- package/dist/handlers/contentAsCode/registry.test.d.ts +0 -2
- package/dist/handlers/contentAsCode/registry.test.d.ts.map +0 -1
- package/dist/handlers/contentAsCode/registry.test.js +0 -18
- package/dist/handlers/contentAsCode/resource.test.d.ts +0 -2
- package/dist/handlers/contentAsCode/resource.test.d.ts.map +0 -1
- package/dist/handlers/contentAsCode/resource.test.js +0 -121
- package/dist/handlers/dbt/getDbtVersion.test.d.ts +0 -2
- package/dist/handlers/dbt/getDbtVersion.test.d.ts.map +0 -1
- package/dist/handlers/dbt/getDbtVersion.test.js +0 -106
- package/dist/handlers/deploy.test.d.ts +0 -2
- package/dist/handlers/deploy.test.d.ts.map +0 -1
- package/dist/handlers/deploy.test.js +0 -244
- package/dist/handlers/download.test.d.ts +0 -2
- package/dist/handlers/download.test.d.ts.map +0 -1
- package/dist/handlers/download.test.js +0 -1739
- package/dist/handlers/exportChartImage.test.d.ts +0 -2
- package/dist/handlers/exportChartImage.test.d.ts.map +0 -1
- package/dist/handlers/exportChartImage.test.js +0 -55
- package/dist/handlers/homepagesAsCode.test.d.ts +0 -2
- package/dist/handlers/homepagesAsCode.test.d.ts.map +0 -1
- package/dist/handlers/homepagesAsCode.test.js +0 -72
- package/dist/handlers/lint.test.d.ts +0 -2
- package/dist/handlers/lint.test.d.ts.map +0 -1
- package/dist/handlers/lint.test.js +0 -221
- package/dist/handlers/login.test.d.ts +0 -2
- package/dist/handlers/login.test.d.ts.map +0 -1
- package/dist/handlers/login.test.js +0 -24
- package/dist/handlers/metadataFile.test.d.ts +0 -2
- package/dist/handlers/metadataFile.test.d.ts.map +0 -1
- package/dist/handlers/metadataFile.test.js +0 -46
- package/dist/handlers/organizationContent/customRoles.test.d.ts +0 -2
- package/dist/handlers/organizationContent/customRoles.test.d.ts.map +0 -1
- package/dist/handlers/organizationContent/customRoles.test.js +0 -179
- package/dist/handlers/organizationContent/groups.test.d.ts +0 -2
- package/dist/handlers/organizationContent/groups.test.d.ts.map +0 -1
- package/dist/handlers/organizationContent/groups.test.js +0 -135
- package/dist/handlers/organizationContent/index.test.d.ts +0 -2
- package/dist/handlers/organizationContent/index.test.d.ts.map +0 -1
- package/dist/handlers/organizationContent/index.test.js +0 -212
- package/dist/handlers/organizationContent/themes.test.d.ts +0 -2
- package/dist/handlers/organizationContent/themes.test.d.ts.map +0 -1
- package/dist/handlers/organizationContent/themes.test.js +0 -180
- package/dist/handlers/organizationContent/users.test.d.ts +0 -2
- package/dist/handlers/organizationContent/users.test.d.ts.map +0 -1
- package/dist/handlers/organizationContent/users.test.js +0 -155
- package/dist/handlers/preAggregateAudit.test.d.ts +0 -2
- package/dist/handlers/preAggregateAudit.test.d.ts.map +0 -1
- package/dist/handlers/preAggregateAudit.test.js +0 -102
- package/dist/handlers/renameHandler.test.d.ts +0 -2
- package/dist/handlers/renameHandler.test.d.ts.map +0 -1
- package/dist/handlers/renameHandler.test.js +0 -189
- package/dist/handlers/resolveProjectFlag.test.d.ts +0 -2
- package/dist/handlers/resolveProjectFlag.test.d.ts.map +0 -1
- package/dist/handlers/resolveProjectFlag.test.js +0 -48
- package/dist/handlers/selectProject.test.d.ts +0 -2
- package/dist/handlers/selectProject.test.d.ts.map +0 -1
- package/dist/handlers/selectProject.test.js +0 -224
- package/dist/handlers/setProject.test.d.ts +0 -2
- package/dist/handlers/setProject.test.d.ts.map +0 -1
- package/dist/handlers/setProject.test.js +0 -63
- package/dist/handlers/slugUpdate.test.d.ts +0 -2
- package/dist/handlers/slugUpdate.test.d.ts.map +0 -1
- package/dist/handlers/slugUpdate.test.js +0 -265
- package/dist/handlers/timestampConversion.test.d.ts +0 -2
- package/dist/handlers/timestampConversion.test.d.ts.map +0 -1
- package/dist/handlers/timestampConversion.test.js +0 -87
- package/dist/handlers/upgradeCheck.test.d.ts +0 -2
- package/dist/handlers/upgradeCheck.test.d.ts.map +0 -1
- package/dist/handlers/upgradeCheck.test.js +0 -227
- package/dist/handlers/validate.test.d.ts +0 -2
- package/dist/handlers/validate.test.d.ts.map +0 -1
- package/dist/handlers/validate.test.js +0 -318
- package/dist/handlers/validateSpaceFilter.test.d.ts +0 -2
- package/dist/handlers/validateSpaceFilter.test.d.ts.map +0 -1
- package/dist/handlers/validateSpaceFilter.test.js +0 -79
- package/dist/handlers/warehouseConnection.test.d.ts +0 -2
- package/dist/handlers/warehouseConnection.test.d.ts.map +0 -1
- package/dist/handlers/warehouseConnection.test.js +0 -75
- package/dist/lightdash-config/lightdash-config.test.d.ts +0 -2
- package/dist/lightdash-config/lightdash-config.test.d.ts.map +0 -1
- package/dist/lightdash-config/lightdash-config.test.js +0 -69
- package/dist/prompts/fuzzySearchPrompt.test.d.ts +0 -2
- package/dist/prompts/fuzzySearchPrompt.test.d.ts.map +0 -1
- package/dist/prompts/fuzzySearchPrompt.test.js +0 -53
- package/dist/refsArgument.test.d.ts +0 -2
- package/dist/refsArgument.test.d.ts.map +0 -1
- package/dist/refsArgument.test.js +0 -42
- package/dist/releaseSafety/index.test.d.ts +0 -2
- package/dist/releaseSafety/index.test.d.ts.map +0 -1
- package/dist/releaseSafety/index.test.js +0 -154
- package/dist/releaseSafety/version.test.d.ts +0 -2
- package/dist/releaseSafety/version.test.d.ts.map +0 -1
- package/dist/releaseSafety/version.test.js +0 -22
- package/dist/skills.test.d.ts +0 -2
- package/dist/skills.test.d.ts.map +0 -1
- package/dist/skills.test.js +0 -112
- package/dist/terminal/contentAsCodeOutput.test.d.ts +0 -2
- package/dist/terminal/contentAsCodeOutput.test.d.ts.map +0 -1
- package/dist/terminal/contentAsCodeOutput.test.js +0 -231
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const common_1 = require("@lightdash/common");
|
|
4
|
-
const apiClient_1 = require("./dbt/apiClient");
|
|
5
|
-
const refresh_1 = require("./dbt/refresh");
|
|
6
|
-
const warehouseConnection_1 = require("./warehouseConnection");
|
|
7
|
-
vi.mock('./dbt/apiClient', () => ({
|
|
8
|
-
lightdashApi: vi.fn(),
|
|
9
|
-
}));
|
|
10
|
-
vi.mock('./dbt/refresh', () => ({
|
|
11
|
-
getFinalJobState: vi.fn(),
|
|
12
|
-
}));
|
|
13
|
-
const mockLightdashApi = apiClient_1.lightdashApi;
|
|
14
|
-
const mockGetFinalJobState = refresh_1.getFinalJobState;
|
|
15
|
-
const PROJECT_UUID = '00000000-0000-0000-0000-000000000001';
|
|
16
|
-
const project = {
|
|
17
|
-
projectUuid: PROJECT_UUID,
|
|
18
|
-
name: 'my-preview',
|
|
19
|
-
dbtConnection: { type: common_1.DbtProjectType.NONE },
|
|
20
|
-
dbtVersion: common_1.SupportedDbtVersions.V1_10,
|
|
21
|
-
};
|
|
22
|
-
const credentials = {
|
|
23
|
-
type: common_1.WarehouseTypes.POSTGRES,
|
|
24
|
-
host: 'localhost',
|
|
25
|
-
user: 'refreshed-user',
|
|
26
|
-
password: 'refreshed-password',
|
|
27
|
-
port: 5432,
|
|
28
|
-
dbname: 'db',
|
|
29
|
-
schema: 'public',
|
|
30
|
-
};
|
|
31
|
-
describe('getWarehouseCredentialsSource', () => {
|
|
32
|
-
it('loads from profiles by default', () => {
|
|
33
|
-
expect((0, warehouseConnection_1.getWarehouseCredentialsSource)({})).toEqual({
|
|
34
|
-
source: 'profiles',
|
|
35
|
-
});
|
|
36
|
-
expect((0, warehouseConnection_1.getWarehouseCredentialsSource)({ warehouseCredentials: true })).toEqual({ source: 'profiles' });
|
|
37
|
-
});
|
|
38
|
-
it('skips when --no-warehouse-credentials is set', () => {
|
|
39
|
-
expect((0, warehouseConnection_1.getWarehouseCredentialsSource)({ warehouseCredentials: false })).toEqual({ source: 'none' });
|
|
40
|
-
});
|
|
41
|
-
it('prefers organization credentials over profiles', () => {
|
|
42
|
-
expect((0, warehouseConnection_1.getWarehouseCredentialsSource)({
|
|
43
|
-
organizationCredentials: 'shared-redshift',
|
|
44
|
-
warehouseCredentials: false,
|
|
45
|
-
})).toEqual({ source: 'organization', name: 'shared-redshift' });
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
describe('updateProjectWarehouseConnection', () => {
|
|
49
|
-
beforeEach(() => {
|
|
50
|
-
vi.clearAllMocks();
|
|
51
|
-
});
|
|
52
|
-
it('patches the project with the new credentials and waits for the job', async () => {
|
|
53
|
-
mockLightdashApi.mockResolvedValueOnce({ jobUuid: 'job-1' });
|
|
54
|
-
mockGetFinalJobState.mockResolvedValueOnce({
|
|
55
|
-
jobStatus: common_1.JobStatusType.DONE,
|
|
56
|
-
});
|
|
57
|
-
await (0, warehouseConnection_1.updateProjectWarehouseConnection)(project, credentials, 'Refreshing warehouse credentials');
|
|
58
|
-
expect(mockLightdashApi).toHaveBeenCalledTimes(1);
|
|
59
|
-
const call = mockLightdashApi.mock.calls[0][0];
|
|
60
|
-
expect(call.method).toBe('PATCH');
|
|
61
|
-
expect(call.url).toBe(`/api/v1/projects/${PROJECT_UUID}`);
|
|
62
|
-
expect(JSON.parse(call.body)).toEqual({
|
|
63
|
-
name: 'my-preview',
|
|
64
|
-
dbtConnection: { type: common_1.DbtProjectType.NONE },
|
|
65
|
-
dbtVersion: common_1.SupportedDbtVersions.V1_10,
|
|
66
|
-
warehouseConnection: credentials,
|
|
67
|
-
});
|
|
68
|
-
expect(mockGetFinalJobState).toHaveBeenCalledWith('job-1', 'Refreshing warehouse credentials');
|
|
69
|
-
});
|
|
70
|
-
it('surfaces a failed adapter test', async () => {
|
|
71
|
-
mockLightdashApi.mockResolvedValueOnce({ jobUuid: 'job-2' });
|
|
72
|
-
mockGetFinalJobState.mockRejectedValueOnce(new Error('Your Redshift IAM AWS session has expired'));
|
|
73
|
-
await expect((0, warehouseConnection_1.updateProjectWarehouseConnection)(project, credentials, 'label')).rejects.toThrow('session has expired');
|
|
74
|
-
});
|
|
75
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lightdash-config.test.d.ts","sourceRoot":"","sources":["../../src/lightdash-config/lightdash-config.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
const common_1 = require("@lightdash/common");
|
|
5
|
-
const promises_1 = tslib_1.__importDefault(require("fs/promises"));
|
|
6
|
-
const _1 = require(".");
|
|
7
|
-
const VALID_CONFIG_CONTENTS = 'spotlight:\n' +
|
|
8
|
-
' default_visibility: show # Optional, defaults to "show"\n' +
|
|
9
|
-
' categories:\n' +
|
|
10
|
-
' core:\n' +
|
|
11
|
-
' label: "Core Metrics"\n' +
|
|
12
|
-
' color: blue\n' +
|
|
13
|
-
' experimental:\n' +
|
|
14
|
-
' label: "Experimental Metrics"\n' +
|
|
15
|
-
' color: orange\n' +
|
|
16
|
-
' sales:\n' +
|
|
17
|
-
' label: "Sales"\n' +
|
|
18
|
-
' color: green\n';
|
|
19
|
-
const VALID_CONFIG = {
|
|
20
|
-
spotlight: {
|
|
21
|
-
default_visibility: 'show',
|
|
22
|
-
categories: {
|
|
23
|
-
core: { label: 'Core Metrics', color: 'blue' },
|
|
24
|
-
experimental: { label: 'Experimental Metrics', color: 'orange' },
|
|
25
|
-
sales: { label: 'Sales', color: 'green' },
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
const INVALID_CONFIG_CONTENTS = 'spotlight:\n default_visibility: invalid_value';
|
|
30
|
-
const readFileSpy = vi.spyOn(promises_1.default, 'readFile');
|
|
31
|
-
// Mock getConfig
|
|
32
|
-
vi.mock('../config', () => ({
|
|
33
|
-
getConfig: vi.fn().mockResolvedValue({ user: null, context: null }),
|
|
34
|
-
}));
|
|
35
|
-
describe('Existing lightdash.config.yml file', () => {
|
|
36
|
-
describe('when valid', () => {
|
|
37
|
-
it('should load the config file', async () => {
|
|
38
|
-
readFileSpy.mockResolvedValueOnce(VALID_CONFIG_CONTENTS);
|
|
39
|
-
const config = await (0, _1.readAndLoadLightdashProjectConfig)('');
|
|
40
|
-
expect(config).toEqual(VALID_CONFIG);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
describe('when invalid', () => {
|
|
44
|
-
it('should throw an error', async () => {
|
|
45
|
-
readFileSpy.mockResolvedValueOnce(INVALID_CONFIG_CONTENTS);
|
|
46
|
-
await expect((0, _1.readAndLoadLightdashProjectConfig)('')).rejects.toThrow(/Invalid lightdash.config.yml with errors/);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
class MockedFSError extends Error {
|
|
51
|
-
code;
|
|
52
|
-
constructor(message, code) {
|
|
53
|
-
super(message);
|
|
54
|
-
this.code = code;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
describe('Missing lightdash.config.yml file', () => {
|
|
58
|
-
it('should load the default config', async () => {
|
|
59
|
-
// Mock rejection: the loader handles ENOENT by falling back to defaults
|
|
60
|
-
readFileSpy.mockRejectedValueOnce(new MockedFSError('file not found', 'ENOENT'));
|
|
61
|
-
const config = await (0, _1.readAndLoadLightdashProjectConfig)('./some/path/to/nonexisting/file');
|
|
62
|
-
expect(config).toEqual({
|
|
63
|
-
spotlight: common_1.DEFAULT_SPOTLIGHT_CONFIG,
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
afterAll(() => {
|
|
68
|
-
vi.restoreAllMocks();
|
|
69
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fuzzySearchPrompt.test.d.ts","sourceRoot":"","sources":["../../src/prompts/fuzzySearchPrompt.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const fuzzySearchPrompt_1 = require("./fuzzySearchPrompt");
|
|
4
|
-
const buildChoices = (names) => names.map((name) => ({ name, value: name }));
|
|
5
|
-
describe('fuzzyFilterChoices', () => {
|
|
6
|
-
it('returns every choice when the search is empty', () => {
|
|
7
|
-
const choices = buildChoices(['alpha', 'beta']);
|
|
8
|
-
expect((0, fuzzySearchPrompt_1.fuzzyFilterChoices)(choices, '')).toEqual(choices);
|
|
9
|
-
expect((0, fuzzySearchPrompt_1.fuzzyFilterChoices)(choices, ' ')).toEqual(choices);
|
|
10
|
-
});
|
|
11
|
-
it('matches case-insensitively on substrings', () => {
|
|
12
|
-
const choices = buildChoices(['Jaffle Shop', 'Internal analytics']);
|
|
13
|
-
expect((0, fuzzySearchPrompt_1.fuzzyFilterChoices)(choices, 'analytics').map((c) => c.name)).toEqual(['Internal analytics']);
|
|
14
|
-
});
|
|
15
|
-
it('matches out-of-order tokens', () => {
|
|
16
|
-
const choices = buildChoices([
|
|
17
|
-
'production-eu',
|
|
18
|
-
'production-us',
|
|
19
|
-
'staging-eu',
|
|
20
|
-
]);
|
|
21
|
-
expect((0, fuzzySearchPrompt_1.fuzzyFilterChoices)(choices, 'eu prod').map((c) => c.name)).toEqual(['production-eu']);
|
|
22
|
-
});
|
|
23
|
-
it('matches subsequences', () => {
|
|
24
|
-
const choices = buildChoices(['production-europe', 'staging']);
|
|
25
|
-
expect((0, fuzzySearchPrompt_1.fuzzyFilterChoices)(choices, 'pdeu').map((c) => c.name)).toEqual([
|
|
26
|
-
'production-europe',
|
|
27
|
-
]);
|
|
28
|
-
});
|
|
29
|
-
it('ranks prefix matches above substring and subsequence matches', () => {
|
|
30
|
-
const choices = buildChoices([
|
|
31
|
-
'my-prod-clone',
|
|
32
|
-
'production',
|
|
33
|
-
'p-r-o-d',
|
|
34
|
-
]);
|
|
35
|
-
expect((0, fuzzySearchPrompt_1.fuzzyFilterChoices)(choices, 'prod').map((c) => c.name)).toEqual([
|
|
36
|
-
'production',
|
|
37
|
-
'my-prod-clone',
|
|
38
|
-
'p-r-o-d',
|
|
39
|
-
]);
|
|
40
|
-
});
|
|
41
|
-
it('keeps the original order between equally-ranked choices', () => {
|
|
42
|
-
const choices = buildChoices(['prod-a', 'prod-b', 'prod-c']);
|
|
43
|
-
expect((0, fuzzySearchPrompt_1.fuzzyFilterChoices)(choices, 'prod').map((c) => c.name)).toEqual([
|
|
44
|
-
'prod-a',
|
|
45
|
-
'prod-b',
|
|
46
|
-
'prod-c',
|
|
47
|
-
]);
|
|
48
|
-
});
|
|
49
|
-
it('returns nothing when a token does not match', () => {
|
|
50
|
-
const choices = buildChoices(['alpha', 'beta']);
|
|
51
|
-
expect((0, fuzzySearchPrompt_1.fuzzyFilterChoices)(choices, 'zzz')).toEqual([]);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"refsArgument.test.d.ts","sourceRoot":"","sources":["../src/refsArgument.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const commander_1 = require("commander");
|
|
4
|
-
const refsArgument_1 = require("./refsArgument");
|
|
5
|
-
const buildCommand = () => {
|
|
6
|
-
const command = new commander_1.Command('upload')
|
|
7
|
-
.exitOverride()
|
|
8
|
-
.configureOutput({ writeErr: () => { } })
|
|
9
|
-
.option('--force', 'force upload', false)
|
|
10
|
-
.option('-c, --charts <charts...>', 'chart refs', refsArgument_1.parseRefsArgument, [])
|
|
11
|
-
.option('--chart-types <chartTypeReferences...>', 'chart type refs', refsArgument_1.parseRefsArgument);
|
|
12
|
-
return command;
|
|
13
|
-
};
|
|
14
|
-
describe('parseRefsArgument', () => {
|
|
15
|
-
it('rejects a bare flag followed by another option', () => {
|
|
16
|
-
const command = buildCommand();
|
|
17
|
-
expect(() => command.parse(['--chart-types', '--force'], { from: 'user' })).toThrow(/argument '--force' is invalid/);
|
|
18
|
-
});
|
|
19
|
-
it('does not consume the following boolean flag as a value', () => {
|
|
20
|
-
const command = buildCommand();
|
|
21
|
-
command.parse(['--chart-types', 'one', 'two', '--force'], {
|
|
22
|
-
from: 'user',
|
|
23
|
-
});
|
|
24
|
-
expect(command.opts().chartTypes).toEqual(['one', 'two']);
|
|
25
|
-
expect(command.opts().force).toBe(true);
|
|
26
|
-
});
|
|
27
|
-
it('rejects option-like values on options with array defaults', () => {
|
|
28
|
-
const command = buildCommand();
|
|
29
|
-
expect(() => command.parse(['--charts', '--force'], { from: 'user' })).toThrow(/argument '--force' is invalid/);
|
|
30
|
-
});
|
|
31
|
-
it('accumulates values onto the default array', () => {
|
|
32
|
-
const command = buildCommand();
|
|
33
|
-
command.parse(['-c', 'a', '-c', 'b'], { from: 'user' });
|
|
34
|
-
expect(command.opts().charts).toEqual(['a', 'b']);
|
|
35
|
-
});
|
|
36
|
-
it('leaves unset options at their defaults', () => {
|
|
37
|
-
const command = buildCommand();
|
|
38
|
-
command.parse([], { from: 'user' });
|
|
39
|
-
expect(command.opts().charts).toEqual([]);
|
|
40
|
-
expect(command.opts().chartTypes).toBeUndefined();
|
|
41
|
-
});
|
|
42
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/releaseSafety/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const _1 = require(".");
|
|
4
|
-
const index = {
|
|
5
|
-
schemaVersion: _1.INDEX_SCHEMA_VERSION,
|
|
6
|
-
generatedAt: '2026-08-11T00:00:00.000Z',
|
|
7
|
-
backfillFloorVersion: null,
|
|
8
|
-
entries: [
|
|
9
|
-
{
|
|
10
|
-
version: '1.0.0',
|
|
11
|
-
previousVersion: '0.9.0',
|
|
12
|
-
releaseDate: '2026-07-31T00:00:00.000Z',
|
|
13
|
-
rollingUpdateSafe: true,
|
|
14
|
-
requiredStops: [],
|
|
15
|
-
minPreviousVersion: null,
|
|
16
|
-
backfilled: true,
|
|
17
|
-
syntheticRequiredStop: false,
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
version: '1.1.0',
|
|
21
|
-
previousVersion: '1.0.0',
|
|
22
|
-
releaseDate: '2026-08-01T00:00:00.000Z',
|
|
23
|
-
rollingUpdateSafe: true,
|
|
24
|
-
requiredStops: [],
|
|
25
|
-
minPreviousVersion: null,
|
|
26
|
-
backfilled: true,
|
|
27
|
-
syntheticRequiredStop: false,
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
version: '1.2.0',
|
|
31
|
-
previousVersion: '1.1.0',
|
|
32
|
-
releaseDate: '2026-08-02T00:00:00.000Z',
|
|
33
|
-
rollingUpdateSafe: true,
|
|
34
|
-
requiredStops: [],
|
|
35
|
-
minPreviousVersion: null,
|
|
36
|
-
backfilled: true,
|
|
37
|
-
syntheticRequiredStop: false,
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
version: '1.3.0',
|
|
41
|
-
previousVersion: '1.2.0',
|
|
42
|
-
releaseDate: '2026-08-03T00:00:00.000Z',
|
|
43
|
-
rollingUpdateSafe: 'unknown',
|
|
44
|
-
requiredStops: [],
|
|
45
|
-
minPreviousVersion: null,
|
|
46
|
-
backfilled: true,
|
|
47
|
-
syntheticRequiredStop: false,
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
};
|
|
51
|
-
describe('composeReleaseSafetySpan', () => {
|
|
52
|
-
it('composes a safe forward span', () => {
|
|
53
|
-
expect((0, _1.composeReleaseSafetySpan)(index, '1.0.0', '1.2.0')).toEqual({
|
|
54
|
-
verdict: true,
|
|
55
|
-
safe: true,
|
|
56
|
-
requiredStops: [],
|
|
57
|
-
minPreviousVersion: null,
|
|
58
|
-
coveredVersions: ['1.1.0', '1.2.0'],
|
|
59
|
-
missingRanges: [],
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
it('fails closed for an unknown release', () => {
|
|
63
|
-
expect((0, _1.composeReleaseSafetySpan)(index, '1.0.0', '1.3.0')).toMatchObject({ verdict: 'unknown', safe: false });
|
|
64
|
-
});
|
|
65
|
-
it('normalizes a reverse span to the same covered edges', () => {
|
|
66
|
-
expect((0, _1.composeReleaseSafetySpan)(index, '1.2.0', '1.0.0')).toEqual((0, _1.composeReleaseSafetySpan)(index, '1.0.0', '1.2.0'));
|
|
67
|
-
});
|
|
68
|
-
it('fails closed when the target version is absent', () => {
|
|
69
|
-
expect((0, _1.composeReleaseSafetySpan)(index, '1.0.0', '1.4.0')).toMatchObject({
|
|
70
|
-
verdict: 'unknown',
|
|
71
|
-
safe: false,
|
|
72
|
-
missingRanges: [
|
|
73
|
-
{ afterVersion: '1.3.0', beforeVersion: '1.4.0' },
|
|
74
|
-
],
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
it('fails closed across an internal coverage gap', () => {
|
|
78
|
-
const indexWithGap = {
|
|
79
|
-
...index,
|
|
80
|
-
entries: index.entries.filter((entry) => entry.version !== '1.2.0'),
|
|
81
|
-
};
|
|
82
|
-
expect((0, _1.composeReleaseSafetySpan)(indexWithGap, '1.0.0', '1.3.0')).toMatchObject({
|
|
83
|
-
verdict: 'unknown',
|
|
84
|
-
safe: false,
|
|
85
|
-
missingRanges: [{ afterVersion: '1.1.0', beforeVersion: '1.3.0' }],
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
it('allows a same-version span when the endpoint is known', () => {
|
|
89
|
-
expect((0, _1.composeReleaseSafetySpan)(index, '1.2.0', '1.2.0')).toMatchObject({
|
|
90
|
-
verdict: true,
|
|
91
|
-
safe: true,
|
|
92
|
-
coveredVersions: [],
|
|
93
|
-
missingRanges: [],
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
it('fails closed for an absent same-version endpoint', () => {
|
|
97
|
-
expect((0, _1.composeReleaseSafetySpan)(index, '1.4.0', '1.4.0')).toMatchObject({
|
|
98
|
-
verdict: 'unknown',
|
|
99
|
-
safe: false,
|
|
100
|
-
coveredVersions: [],
|
|
101
|
-
missingRanges: [
|
|
102
|
-
{ afterVersion: '1.4.0', beforeVersion: '1.4.0' },
|
|
103
|
-
],
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
it('fails closed when a same-version endpoint only appears as a predecessor', () => {
|
|
107
|
-
expect((0, _1.composeReleaseSafetySpan)(index, '0.9.0', '0.9.0')).toMatchObject({
|
|
108
|
-
verdict: 'unknown',
|
|
109
|
-
safe: false,
|
|
110
|
-
missingRanges: [
|
|
111
|
-
{ afterVersion: '0.9.0', beforeVersion: '0.9.0' },
|
|
112
|
-
],
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
it('fails closed when the source endpoint only appears as a predecessor', () => {
|
|
116
|
-
expect((0, _1.composeReleaseSafetySpan)(index, '0.9.0', '1.0.0')).toMatchObject({
|
|
117
|
-
verdict: 'unknown',
|
|
118
|
-
safe: false,
|
|
119
|
-
missingRanges: [
|
|
120
|
-
{ afterVersion: '0.9.0', beforeVersion: '0.9.0' },
|
|
121
|
-
],
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
it('applies required stops and minimum versions from the normalized lower endpoint', () => {
|
|
125
|
-
const constrainedIndex = {
|
|
126
|
-
...index,
|
|
127
|
-
entries: index.entries.map((entry) => entry.version === '1.2.0'
|
|
128
|
-
? {
|
|
129
|
-
...entry,
|
|
130
|
-
requiredStops: ['1.1.0'],
|
|
131
|
-
minPreviousVersion: '1.1.0',
|
|
132
|
-
}
|
|
133
|
-
: entry),
|
|
134
|
-
};
|
|
135
|
-
const forward = (0, _1.composeReleaseSafetySpan)(constrainedIndex, '1.0.0', '1.2.0');
|
|
136
|
-
const reverse = (0, _1.composeReleaseSafetySpan)(constrainedIndex, '1.2.0', '1.0.0');
|
|
137
|
-
expect(forward).toMatchObject({
|
|
138
|
-
verdict: true,
|
|
139
|
-
safe: false,
|
|
140
|
-
requiredStops: ['1.1.0'],
|
|
141
|
-
minPreviousVersion: '1.1.0',
|
|
142
|
-
});
|
|
143
|
-
expect(reverse).toEqual(forward);
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
describe('parseReleaseSafetyIndex', () => {
|
|
147
|
-
it('strictly rejects invalid versions and additional properties', () => {
|
|
148
|
-
expect(() => (0, _1.parseReleaseSafetyIndex)({
|
|
149
|
-
...index,
|
|
150
|
-
entries: [{ ...index.entries[0], version: 'v1.1.0' }],
|
|
151
|
-
})).toThrow('Invalid release-safety index');
|
|
152
|
-
expect(() => (0, _1.parseReleaseSafetyIndex)({ ...index, unexpected: true })).toThrow('Invalid release-safety index');
|
|
153
|
-
});
|
|
154
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"version.test.d.ts","sourceRoot":"","sources":["../../src/releaseSafety/version.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const vitest_1 = require("vitest");
|
|
4
|
-
const version_1 = require("./version");
|
|
5
|
-
(0, vitest_1.describe)('compareVersions', () => {
|
|
6
|
-
(0, vitest_1.it)('throws on malformed left input', () => {
|
|
7
|
-
(0, vitest_1.expect)(() => (0, version_1.compareVersions)('1.2', '1.2.3')).toThrowError('Invalid release version value(s): left=1.2');
|
|
8
|
-
});
|
|
9
|
-
(0, vitest_1.it)('throws on malformed right input', () => {
|
|
10
|
-
(0, vitest_1.expect)(() => (0, version_1.compareVersions)('1.2.3', 'bad-right')).toThrowError('Invalid release version value(s): right=bad-right');
|
|
11
|
-
});
|
|
12
|
-
(0, vitest_1.it)('throws on malformed both inputs', () => {
|
|
13
|
-
(0, vitest_1.expect)(() => (0, version_1.compareVersions)('left', 'right')).toThrowError('Invalid release version value(s): left=left, right=right');
|
|
14
|
-
});
|
|
15
|
-
vitest_1.it.each([
|
|
16
|
-
['1.2.3', '2.0.0', -1],
|
|
17
|
-
['1.2.3', '1.2.3', 0],
|
|
18
|
-
['2.0.0', '1.2.3', 1],
|
|
19
|
-
])('compares %s and %s as %s', (left, right, expected) => {
|
|
20
|
-
(0, vitest_1.expect)((0, version_1.compareVersions)(left, right)).toBe(expected);
|
|
21
|
-
});
|
|
22
|
-
});
|
package/dist/skills.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"skills.test.d.ts","sourceRoot":"","sources":["../src/skills.test.ts"],"names":[],"mappings":""}
|
package/dist/skills.test.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
const fs = tslib_1.__importStar(require("fs"));
|
|
5
|
-
const path = tslib_1.__importStar(require("path"));
|
|
6
|
-
// Repo-root `skills/` packages are baked into the writeback sandbox by
|
|
7
|
-
// `lightdash install-skills` (see handlers/installSkills.ts). Unlike the
|
|
8
|
-
// chat-agent copies under packages/backend/.../builtInSkills, nothing else
|
|
9
|
-
// validates these at build time, so this test guards their shape: valid
|
|
10
|
-
// frontmatter, name matching the directory, and no dead resource links.
|
|
11
|
-
const SKILLS_DIR = path.resolve(__dirname, '../../../skills');
|
|
12
|
-
const listSkillDirs = () => fs
|
|
13
|
-
.readdirSync(SKILLS_DIR, { withFileTypes: true })
|
|
14
|
-
.filter((entry) => entry.isDirectory())
|
|
15
|
-
.map((entry) => entry.name);
|
|
16
|
-
// Minimal YAML-frontmatter reader — the CLI package has no gray-matter dep and
|
|
17
|
-
// we only need the two scalar fields the skill contract requires.
|
|
18
|
-
const parseFrontmatter = (markdown) => {
|
|
19
|
-
const match = markdown.match(/^---\n([\s\S]*?)\n---/);
|
|
20
|
-
if (!match) {
|
|
21
|
-
return { name: null, description: null };
|
|
22
|
-
}
|
|
23
|
-
const readField = (field) => {
|
|
24
|
-
const line = match[1]
|
|
25
|
-
.split('\n')
|
|
26
|
-
.find((l) => l.startsWith(`${field}:`));
|
|
27
|
-
if (!line) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
return line.slice(field.length + 1).trim() || null;
|
|
31
|
-
};
|
|
32
|
-
return { name: readField('name'), description: readField('description') };
|
|
33
|
-
};
|
|
34
|
-
describe('repo-root skills packages', () => {
|
|
35
|
-
const skillDirs = listSkillDirs();
|
|
36
|
-
it('has at least one skill package', () => {
|
|
37
|
-
expect(skillDirs.length).toBeGreaterThan(0);
|
|
38
|
-
});
|
|
39
|
-
it.each(skillDirs)('skill "%s" has valid frontmatter, matching name, and resolvable resource links', (dir) => {
|
|
40
|
-
const skillPath = path.join(SKILLS_DIR, dir, 'SKILL.md');
|
|
41
|
-
expect(fs.existsSync(skillPath)).toBe(true);
|
|
42
|
-
const markdown = fs.readFileSync(skillPath, 'utf-8');
|
|
43
|
-
const { name, description } = parseFrontmatter(markdown);
|
|
44
|
-
expect(name).toBe(dir);
|
|
45
|
-
expect(description).toEqual(expect.any(String));
|
|
46
|
-
expect((description ?? '').length).toBeGreaterThan(0);
|
|
47
|
-
// Every ./resources/*.md link referenced in SKILL.md must resolve.
|
|
48
|
-
const linked = [
|
|
49
|
-
...markdown.matchAll(/\]\((\.\/resources\/[^)]+)\)/g),
|
|
50
|
-
].map((m) => m[1]);
|
|
51
|
-
linked.forEach((rel) => {
|
|
52
|
-
const resolved = path.join(SKILLS_DIR, dir, rel);
|
|
53
|
-
expect(fs.existsSync(resolved), `dead resource link ${rel} in ${dir}/SKILL.md`).toBe(true);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
describe('effective-dbt-sql skill content policy', () => {
|
|
58
|
-
const skillDir = path.join(SKILLS_DIR, 'effective-dbt-sql');
|
|
59
|
-
const skillMd = fs.readFileSync(path.join(skillDir, 'SKILL.md'), 'utf-8');
|
|
60
|
-
it('exists', () => {
|
|
61
|
-
expect(fs.existsSync(skillDir)).toBe(true);
|
|
62
|
-
});
|
|
63
|
-
it('encodes the core semantic rules', () => {
|
|
64
|
-
const body = skillMd.toLowerCase();
|
|
65
|
-
expect(body).toContain('correlated subquer');
|
|
66
|
-
expect(body).toContain('cte');
|
|
67
|
-
expect(body).toContain('reuse');
|
|
68
|
-
});
|
|
69
|
-
it('carries the "match the target repo" fallback-defaults guardrail', () => {
|
|
70
|
-
expect(skillMd.toLowerCase()).toContain('fallback default');
|
|
71
|
-
expect(skillMd.toLowerCase()).toMatch(/match the (target )?repo/);
|
|
72
|
-
});
|
|
73
|
-
it('declares itself semantics-only (defers naming/formatting to the repo)', () => {
|
|
74
|
-
// The skill deliberately drops house-style opinions so it never fights
|
|
75
|
-
// the target repo's conventions. Assert the contract is stated rather
|
|
76
|
-
// than grepping for banned tokens (a disclaimer legitimately names
|
|
77
|
-
// them), so the semantics-only scope can't silently drift into
|
|
78
|
-
// prescribing naming or formatting.
|
|
79
|
-
const body = skillMd.toLowerCase();
|
|
80
|
-
expect(body).toContain('semantics only');
|
|
81
|
-
expect(body).toMatch(/does not prescribe|not in scope/);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
describe('developing-in-lightdash routed workflows', () => {
|
|
85
|
-
const skillDir = path.join(SKILLS_DIR, 'developing-in-lightdash');
|
|
86
|
-
const skillMd = fs.readFileSync(path.join(skillDir, 'SKILL.md'), 'utf-8');
|
|
87
|
-
const workflowPath = path.join(skillDir, 'resources', 'creating-from-warehouse-catalog.md');
|
|
88
|
-
const workflow = fs.readFileSync(workflowPath, 'utf-8');
|
|
89
|
-
it('routes catalog bootstrapping through the conditional workflow', () => {
|
|
90
|
-
expect(skillMd).toContain('./resources/creating-from-warehouse-catalog.md');
|
|
91
|
-
expect(skillMd).toMatch(/no usable dbt project[\s\S]*always read and follow/i);
|
|
92
|
-
});
|
|
93
|
-
it('routes organization Data App theme work through its focused reference', () => {
|
|
94
|
-
const { description } = parseFrontmatter(skillMd);
|
|
95
|
-
expect(description?.toLowerCase()).toContain('organization data app themes');
|
|
96
|
-
expect(skillMd).toContain('./resources/data-app-themes-reference.md');
|
|
97
|
-
expect(skillMd).toMatch(/any task that creates, edits, migrates, downloads, uploads, or tests an organization Data App theme,[\s\S]*always read and follow/i);
|
|
98
|
-
});
|
|
99
|
-
it('keeps the workflow credential-safe, additive, and project-pinned', () => {
|
|
100
|
-
expect(workflow).toContain('Never request, read, print, copy, or edit warehouse credentials.');
|
|
101
|
-
expect(workflow).toContain('Immediately before deploy, the selected UUID must equal `EXPECTED_PROJECT_UUID`.');
|
|
102
|
-
expect(workflow).toContain('On reruns, merge into the existing model by name: update evidenced definitions, add missing definitions, and never duplicate a dimension, metric, join, or model.');
|
|
103
|
-
expect(workflow).toContain('A rerun with unchanged evidence should produce no YAML diff.');
|
|
104
|
-
});
|
|
105
|
-
it('supports existing Snowflake and GCP CLI connections safely', () => {
|
|
106
|
-
expect(workflow).toMatch(/already-authenticated warehouse CLI session[^.]+for read-only metadata and aggregate queries\./);
|
|
107
|
-
expect(workflow).toContain('snow sql --format json');
|
|
108
|
-
expect(workflow).toContain('bq query --use_legacy_sql=false --dry_run');
|
|
109
|
-
expect(workflow).toContain('If there is no usable Lightdash catalog connection and the user has no authenticated warehouse CLI, stop: the catalog cannot be inspected safely, so this workflow cannot continue.');
|
|
110
|
-
expect(workflow).toContain("The direct CLI supplies evidence for the YAML; it does not configure the Lightdash project's warehouse connection.");
|
|
111
|
-
});
|
|
112
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contentAsCodeOutput.test.d.ts","sourceRoot":"","sources":["../../src/terminal/contentAsCodeOutput.test.ts"],"names":[],"mappings":""}
|