neonctl 2.17.1 → 2.18.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/commands/branches.js +23 -5
- package/commands/branches.test.js +6 -1
- package/package.json +1 -1
- package/test_utils/fixtures.js +1 -1
- package/writer.js +11 -8
- package/writer.test.js +49 -31
package/commands/branches.js
CHANGED
|
@@ -10,16 +10,15 @@ import { log } from '../log.js';
|
|
|
10
10
|
import { parseSchemaDiffParams, schemaDiff } from './schema_diff.js';
|
|
11
11
|
import { getComputeUnits } from '../utils/compute_units.js';
|
|
12
12
|
export const BRANCH_FIELDS = [
|
|
13
|
-
'id',
|
|
14
13
|
'name',
|
|
15
|
-
'
|
|
14
|
+
'id',
|
|
16
15
|
'current_state',
|
|
17
16
|
'created_at',
|
|
18
17
|
'expires_at',
|
|
19
18
|
];
|
|
20
19
|
const BRANCH_FIELDS_RESET = [
|
|
21
|
-
'id',
|
|
22
20
|
'name',
|
|
21
|
+
'id',
|
|
23
22
|
'default',
|
|
24
23
|
'current_state',
|
|
25
24
|
'created_at',
|
|
@@ -211,11 +210,30 @@ export const handler = (args) => {
|
|
|
211
210
|
return args;
|
|
212
211
|
};
|
|
213
212
|
const list = async (props) => {
|
|
214
|
-
const { data } = await props.apiClient.listProjectBranches({
|
|
213
|
+
const { data: { branches, annotations }, } = await props.apiClient.listProjectBranches({
|
|
215
214
|
projectId: props.projectId,
|
|
216
215
|
});
|
|
217
|
-
writer(props).end(
|
|
216
|
+
writer(props).end(branches, {
|
|
218
217
|
fields: BRANCH_FIELDS,
|
|
218
|
+
renderColumns: {
|
|
219
|
+
expires_at: (br) => br.expires_at || 'never',
|
|
220
|
+
name: (br) => {
|
|
221
|
+
const annotation = annotations[br.id];
|
|
222
|
+
const isAnon = annotation?.value.anonymized;
|
|
223
|
+
const result = [];
|
|
224
|
+
if (br.default) {
|
|
225
|
+
result.push('✱');
|
|
226
|
+
}
|
|
227
|
+
if (br.protected) {
|
|
228
|
+
result.push('⛨');
|
|
229
|
+
}
|
|
230
|
+
if (isAnon) {
|
|
231
|
+
result.push('[anon]');
|
|
232
|
+
}
|
|
233
|
+
result.push(br.name);
|
|
234
|
+
return result.join(' ');
|
|
235
|
+
},
|
|
236
|
+
},
|
|
219
237
|
});
|
|
220
238
|
};
|
|
221
239
|
const create = async (props) => {
|
|
@@ -2,9 +2,14 @@ import { describe } from 'vitest';
|
|
|
2
2
|
import { test } from '../test_utils/fixtures';
|
|
3
3
|
describe('branches', () => {
|
|
4
4
|
/* list */
|
|
5
|
-
test('list', async ({ testCliCommand }) => {
|
|
5
|
+
test('list/yaml', async ({ testCliCommand }) => {
|
|
6
6
|
await testCliCommand(['branches', 'list', '--project-id', 'test']);
|
|
7
7
|
});
|
|
8
|
+
test('list/table output', async ({ testCliCommand }) => {
|
|
9
|
+
await testCliCommand(['branches', 'list', '--project-id', 'test'], {
|
|
10
|
+
outputTable: true,
|
|
11
|
+
});
|
|
12
|
+
});
|
|
8
13
|
/* create */
|
|
9
14
|
test('create by default with r/w endpoint', async ({ testCliCommand }) => {
|
|
10
15
|
await testCliCommand([
|
package/package.json
CHANGED
package/test_utils/fixtures.js
CHANGED
package/writer.js
CHANGED
|
@@ -20,25 +20,28 @@ const writeJson = (chunks) => {
|
|
|
20
20
|
])), null, 2);
|
|
21
21
|
};
|
|
22
22
|
const writeTable = (chunks, out) => {
|
|
23
|
-
chunks.forEach(({ data, config }) => {
|
|
23
|
+
chunks.forEach(({ data, config: { emptyMessage, fields, title, renderColumns = {} } }) => {
|
|
24
24
|
const arrayData = Array.isArray(data) ? data : [data];
|
|
25
|
-
if (!arrayData.length &&
|
|
26
|
-
out.write('\n' +
|
|
25
|
+
if (!arrayData.length && emptyMessage) {
|
|
26
|
+
out.write('\n' + emptyMessage + '\n');
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
|
-
const
|
|
29
|
+
const fieldsFiltered = fields.filter((field) => arrayData.some((item) => item[field] !== undefined && item[field] !== ''));
|
|
30
30
|
const table = new Table({
|
|
31
31
|
style: {
|
|
32
32
|
head: ['green'],
|
|
33
33
|
},
|
|
34
|
-
head:
|
|
34
|
+
head: fieldsFiltered.map((field) => field
|
|
35
35
|
.split('_')
|
|
36
36
|
.map((word) => word[0].toUpperCase() + word.slice(1))
|
|
37
37
|
.join(' ')),
|
|
38
38
|
});
|
|
39
39
|
arrayData.forEach((item) => {
|
|
40
|
-
table.push(
|
|
40
|
+
table.push(fieldsFiltered.map((field) => {
|
|
41
41
|
const value = item[field];
|
|
42
|
+
if (renderColumns[field]) {
|
|
43
|
+
return renderColumns[field]?.(item);
|
|
44
|
+
}
|
|
42
45
|
return Array.isArray(value)
|
|
43
46
|
? value.join('\n')
|
|
44
47
|
: isObject(value)
|
|
@@ -46,8 +49,8 @@ const writeTable = (chunks, out) => {
|
|
|
46
49
|
: value;
|
|
47
50
|
}));
|
|
48
51
|
});
|
|
49
|
-
if (
|
|
50
|
-
out.write((isCi() ?
|
|
52
|
+
if (title) {
|
|
53
|
+
out.write((isCi() ? title : chalk.bold(title)) + '\n');
|
|
51
54
|
}
|
|
52
55
|
out.write(table.toString());
|
|
53
56
|
out.write('\n');
|
package/writer.test.js
CHANGED
|
@@ -1,86 +1,104 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PassThrough } from 'node:stream';
|
|
2
2
|
import { describe, it, expect } from 'vitest';
|
|
3
3
|
import { writer } from './writer.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
4
|
+
const getMockWritable = () => {
|
|
5
|
+
const chunks = [];
|
|
6
|
+
const stream = new PassThrough();
|
|
7
|
+
stream.on('data', (chunk) => {
|
|
8
|
+
chunks.push(chunk.toString());
|
|
9
|
+
});
|
|
10
|
+
return {
|
|
11
|
+
stream,
|
|
12
|
+
getData: () => {
|
|
13
|
+
return chunks.join('');
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
};
|
|
16
17
|
describe('writer', () => {
|
|
17
18
|
describe('outputs yaml', () => {
|
|
18
19
|
it('outputs single data', () => {
|
|
19
|
-
const stream =
|
|
20
|
+
const { stream, getData } = getMockWritable();
|
|
20
21
|
const out = writer({ output: 'yaml', out: stream });
|
|
21
22
|
out.end({ foo: 'bar' }, { fields: ['foo'] });
|
|
22
|
-
expect(
|
|
23
|
+
expect(getData()).toMatchSnapshot();
|
|
23
24
|
});
|
|
24
25
|
it('outputs single data with title', () => {
|
|
25
|
-
const stream =
|
|
26
|
+
const { stream, getData } = getMockWritable();
|
|
26
27
|
const out = writer({ output: 'yaml', out: stream });
|
|
27
28
|
out.end({ foo: 'bar' }, { fields: ['foo'], title: 'baz' });
|
|
28
|
-
expect(
|
|
29
|
+
expect(getData()).toMatchSnapshot();
|
|
29
30
|
});
|
|
30
31
|
it('outputs multiple data', () => {
|
|
31
|
-
const stream =
|
|
32
|
+
const { stream, getData } = getMockWritable();
|
|
32
33
|
const out = writer({ output: 'yaml', out: stream });
|
|
33
34
|
out
|
|
34
35
|
.write({ foo: 'bar' }, { fields: ['foo'], title: 'T1' })
|
|
35
36
|
.write({ baz: 'xyz' }, { fields: ['baz'], title: 'T2' })
|
|
36
37
|
.end();
|
|
37
|
-
expect(
|
|
38
|
+
expect(getData()).toMatchSnapshot();
|
|
38
39
|
});
|
|
39
40
|
});
|
|
40
41
|
describe('outputs json', () => {
|
|
41
42
|
it('outputs single data', () => {
|
|
42
|
-
const stream =
|
|
43
|
+
const { stream, getData } = getMockWritable();
|
|
43
44
|
const out = writer({ output: 'json', out: stream });
|
|
44
45
|
out.end({ foo: 'bar' }, { fields: ['foo'] });
|
|
45
|
-
expect(
|
|
46
|
+
expect(getData()).toMatchSnapshot();
|
|
46
47
|
});
|
|
47
48
|
it('outputs single data with title', () => {
|
|
48
|
-
const stream =
|
|
49
|
+
const { stream, getData } = getMockWritable();
|
|
49
50
|
const out = writer({ output: 'json', out: stream });
|
|
50
51
|
out.end({ foo: 'bar' }, { fields: ['foo'], title: 'baz' });
|
|
51
|
-
expect(
|
|
52
|
+
expect(getData()).toMatchSnapshot();
|
|
52
53
|
});
|
|
53
54
|
it('outputs multiple data', () => {
|
|
54
|
-
const stream =
|
|
55
|
+
const { stream, getData } = getMockWritable();
|
|
55
56
|
const out = writer({ output: 'json', out: stream });
|
|
56
57
|
out
|
|
57
58
|
.write({ foo: 'bar' }, { fields: ['foo'], title: 'T1' })
|
|
58
59
|
.write({ baz: 'xyz' }, { fields: ['baz'], title: 'T2' })
|
|
59
60
|
.end();
|
|
60
|
-
expect(
|
|
61
|
+
expect(getData()).toMatchSnapshot();
|
|
61
62
|
});
|
|
62
63
|
});
|
|
63
64
|
describe('outputs table', () => {
|
|
64
65
|
it('outputs single data', () => {
|
|
65
|
-
const stream =
|
|
66
|
+
const { stream, getData } = getMockWritable();
|
|
66
67
|
const out = writer({ output: 'table', out: stream });
|
|
67
68
|
out.end({ foo: 'bar', extra: 'extra' }, { fields: ['foo'] });
|
|
68
|
-
expect(
|
|
69
|
+
expect(getData()).toMatchSnapshot();
|
|
69
70
|
});
|
|
70
71
|
it('outputs single data with title', () => {
|
|
71
|
-
const stream =
|
|
72
|
+
const { stream, getData } = getMockWritable();
|
|
72
73
|
const out = writer({ output: 'table', out: stream });
|
|
73
74
|
out.end({ foo: 'bar', extra: 'extra' }, { fields: ['foo'], title: 'baz' });
|
|
74
|
-
expect(
|
|
75
|
+
expect(getData()).toMatchSnapshot();
|
|
75
76
|
});
|
|
76
77
|
it('outputs multiple data', () => {
|
|
77
|
-
const stream =
|
|
78
|
+
const { stream, getData } = getMockWritable();
|
|
78
79
|
const out = writer({ output: 'table', out: stream });
|
|
79
80
|
out
|
|
80
81
|
.write({ foo: 'bar', extra: 'extra' }, { fields: ['foo'], title: 'T1' })
|
|
81
82
|
.write({ baz: 'xyz', extra: 'extra' }, { fields: ['baz'], title: 'T2' })
|
|
82
83
|
.end();
|
|
83
|
-
expect(
|
|
84
|
+
expect(getData()).toMatchSnapshot();
|
|
85
|
+
});
|
|
86
|
+
it('outputs table with custom renderer', () => {
|
|
87
|
+
const { stream, getData } = getMockWritable();
|
|
88
|
+
const out = writer({
|
|
89
|
+
output: 'table',
|
|
90
|
+
out: stream,
|
|
91
|
+
});
|
|
92
|
+
out
|
|
93
|
+
.write({ foo: 'bar' }, {
|
|
94
|
+
fields: ['foo'],
|
|
95
|
+
title: 'T1',
|
|
96
|
+
renderColumns: {
|
|
97
|
+
foo: ({ foo }) => `Here is: ${foo}`,
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
.end();
|
|
101
|
+
expect(getData()).toMatchSnapshot();
|
|
84
102
|
});
|
|
85
103
|
});
|
|
86
104
|
});
|