@lightdash/cli 1.125.0 → 1.127.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.
@@ -0,0 +1,154 @@
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
+ });
@@ -0,0 +1,69 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://lightdash.com/schemas/release-safety-index/v1.json",
4
+ "title": "Lightdash cumulative release-safety index",
5
+ "description": "Derived summaries of per-release v2 artifacts. unknown MUST be treated as unsafe. Per-release artifacts remain the source of truth.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "schemaVersion",
10
+ "generatedAt",
11
+ "backfillFloorVersion",
12
+ "entries"
13
+ ],
14
+ "properties": {
15
+ "schemaVersion": { "type": "string", "const": "1" },
16
+ "generatedAt": { "type": "string", "format": "date-time" },
17
+ "backfillFloorVersion": {
18
+ "type": ["string", "null"],
19
+ "pattern": "^\\d+\\.\\d+\\.\\d+$"
20
+ },
21
+ "entries": {
22
+ "type": "array",
23
+ "items": {
24
+ "type": "object",
25
+ "additionalProperties": false,
26
+ "required": [
27
+ "version",
28
+ "previousVersion",
29
+ "releaseDate",
30
+ "rollingUpdateSafe",
31
+ "requiredStops",
32
+ "minPreviousVersion",
33
+ "backfilled",
34
+ "syntheticRequiredStop"
35
+ ],
36
+ "properties": {
37
+ "version": {
38
+ "type": "string",
39
+ "pattern": "^\\d+\\.\\d+\\.\\d+$"
40
+ },
41
+ "previousVersion": {
42
+ "type": ["string", "null"],
43
+ "pattern": "^\\d+\\.\\d+\\.\\d+$"
44
+ },
45
+ "releaseDate": { "type": "string", "format": "date-time" },
46
+ "rollingUpdateSafe": {
47
+ "oneOf": [
48
+ { "type": "boolean" },
49
+ { "type": "string", "const": "unknown" }
50
+ ]
51
+ },
52
+ "requiredStops": {
53
+ "type": "array",
54
+ "items": {
55
+ "type": "string",
56
+ "pattern": "^\\d+\\.\\d+\\.\\d+$"
57
+ }
58
+ },
59
+ "minPreviousVersion": {
60
+ "type": ["string", "null"],
61
+ "pattern": "^\\d+\\.\\d+\\.\\d+$"
62
+ },
63
+ "backfilled": { "type": "boolean" },
64
+ "syntheticRequiredStop": { "type": "boolean" }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,3 @@
1
+ export declare function isReleaseVersion(version: string): boolean;
2
+ export declare function compareVersions(left: string, right: string): number;
3
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/releaseSafety/version.ts"],"names":[],"mappings":"AAEA,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAuBnE"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isReleaseVersion = isReleaseVersion;
4
+ exports.compareVersions = compareVersions;
5
+ const RELEASE_VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
6
+ function isReleaseVersion(version) {
7
+ return RELEASE_VERSION_PATTERN.test(version);
8
+ }
9
+ function compareVersions(left, right) {
10
+ const invalidLeft = !isReleaseVersion(left);
11
+ const invalidRight = !isReleaseVersion(right);
12
+ if (invalidLeft || invalidRight) {
13
+ const invalidSides = [
14
+ ...(invalidLeft ? [`left=${left}`] : []),
15
+ ...(invalidRight ? [`right=${right}`] : []),
16
+ ];
17
+ throw new Error(`Invalid release version value(s): ${invalidSides.join(', ')}`);
18
+ }
19
+ const leftParts = left.split('.').map(Number);
20
+ const rightParts = right.split('.').map(Number);
21
+ for (let partIndex = 0; partIndex < 3; partIndex += 1) {
22
+ const difference = leftParts[partIndex] - rightParts[partIndex];
23
+ if (difference !== 0) {
24
+ return difference > 0 ? 1 : -1;
25
+ }
26
+ }
27
+ return 0;
28
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=version.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.test.d.ts","sourceRoot":"","sources":["../../src/releaseSafety/version.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/cli",
3
- "version": "1.125.0",
3
+ "version": "1.127.0",
4
4
  "description": "Lightdash CLI tool",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -41,8 +41,8 @@
41
41
  "unique-names-generator": "4.7.1",
42
42
  "uuid": "11.1.1",
43
43
  "yaml": "2.8.3",
44
- "@lightdash/common": "1.125.0",
45
- "@lightdash/warehouses": "1.125.0"
44
+ "@lightdash/common": "1.127.0",
45
+ "@lightdash/warehouses": "1.127.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/inquirer": "8.2.4",