neonctl 1.36.0 → 2.0.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/bootstrap/index.js +1 -1
- package/commands/branches.js +23 -22
- package/commands/branches.test.js +0 -10
- package/commands/ip_allow.js +0 -11
- package/commands/ip_allow.test.js +0 -11
- package/commands/orgs.js +1 -0
- package/commands/projects.js +12 -32
- package/commands/projects.test.js +0 -23
- package/index.js +1 -0
- package/log.js +3 -0
- package/package.json +1 -1
- package/writer.js +4 -0
|
@@ -495,7 +495,7 @@ const bootstrap = async (props) => {
|
|
|
495
495
|
let projectCreateRequest;
|
|
496
496
|
let project;
|
|
497
497
|
let devConnectionString;
|
|
498
|
-
const devBranchName = `dev
|
|
498
|
+
const devBranchName = `dev/${cryptoRandomString({
|
|
499
499
|
length: 10,
|
|
500
500
|
type: 'url-safe',
|
|
501
501
|
})}`;
|
package/commands/branches.js
CHANGED
|
@@ -12,7 +12,6 @@ import { getComputeUnits } from '../utils/compute_units.js';
|
|
|
12
12
|
export const BRANCH_FIELDS = [
|
|
13
13
|
'id',
|
|
14
14
|
'name',
|
|
15
|
-
'primary',
|
|
16
15
|
'default',
|
|
17
16
|
'created_at',
|
|
18
17
|
'updated_at',
|
|
@@ -20,7 +19,6 @@ export const BRANCH_FIELDS = [
|
|
|
20
19
|
const BRANCH_FIELDS_RESET = [
|
|
21
20
|
'id',
|
|
22
21
|
'name',
|
|
23
|
-
'primary',
|
|
24
22
|
'default',
|
|
25
23
|
'created_at',
|
|
26
24
|
'last_reset_at',
|
|
@@ -121,7 +119,6 @@ export const builder = (argv) => argv
|
|
|
121
119
|
],
|
|
122
120
|
]), (args) => restore(args))
|
|
123
121
|
.command('rename <id|name> <new-name>', 'Rename a branch', (yargs) => yargs, (args) => rename(args))
|
|
124
|
-
.command('set-primary <id|name>', 'DEPRECATED: Use set-default. Set a branch as primary', (yargs) => yargs, (args) => setDefault(args))
|
|
125
122
|
.command('set-default <id|name>', 'Set a branch as default', (yargs) => yargs, (args) => setDefault(args))
|
|
126
123
|
.command('add-compute <id|name>', 'Add a compute to a branch', (yargs) => yargs.options({
|
|
127
124
|
type: {
|
|
@@ -187,17 +184,16 @@ const list = async (props) => {
|
|
|
187
184
|
});
|
|
188
185
|
};
|
|
189
186
|
const create = async (props) => {
|
|
190
|
-
const
|
|
187
|
+
const branches = await props.apiClient
|
|
188
|
+
.listProjectBranches(props.projectId)
|
|
189
|
+
.then(({ data }) => data.branches);
|
|
190
|
+
const parentProps = (() => {
|
|
191
191
|
if (!props.parent) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
throw new Error('No default branch found');
|
|
198
|
-
}
|
|
199
|
-
return { parent_id: branch.id };
|
|
200
|
-
});
|
|
192
|
+
const branch = branches.find((b) => b.default);
|
|
193
|
+
if (!branch) {
|
|
194
|
+
throw new Error('No default branch found');
|
|
195
|
+
}
|
|
196
|
+
return { parent_id: branch.id };
|
|
201
197
|
}
|
|
202
198
|
if (looksLikeLSN(props.parent)) {
|
|
203
199
|
return { parent_lsn: props.parent };
|
|
@@ -208,15 +204,11 @@ const create = async (props) => {
|
|
|
208
204
|
if (looksLikeBranchId(props.parent)) {
|
|
209
205
|
return { parent_id: props.parent };
|
|
210
206
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
throw new Error(`Branch ${props.parent} not found`);
|
|
217
|
-
}
|
|
218
|
-
return { parent_id: branch.id };
|
|
219
|
-
});
|
|
207
|
+
const branch = branches.find((b) => b.name === props.parent);
|
|
208
|
+
if (!branch) {
|
|
209
|
+
throw new Error(`Branch ${props.parent} not found`);
|
|
210
|
+
}
|
|
211
|
+
return { parent_id: branch.id };
|
|
220
212
|
})();
|
|
221
213
|
const { data } = await retryOnLock(() => props.apiClient.createProjectBranch(props.projectId, {
|
|
222
214
|
branch: {
|
|
@@ -236,21 +228,28 @@ const create = async (props) => {
|
|
|
236
228
|
? JSON.parse(props.annotation)
|
|
237
229
|
: undefined,
|
|
238
230
|
}));
|
|
231
|
+
const parent = branches.find((b) => b.id === data.branch.parent_id);
|
|
232
|
+
if (parent?.protected) {
|
|
233
|
+
log.warning('The parent branch is protected; a unique role password has been generated for the new branch.');
|
|
234
|
+
}
|
|
239
235
|
const out = writer(props);
|
|
240
236
|
out.write(data.branch, {
|
|
241
237
|
fields: BRANCH_FIELDS,
|
|
242
238
|
title: 'branch',
|
|
239
|
+
emptyMessage: 'No branches have been found.',
|
|
243
240
|
});
|
|
244
241
|
if (data.endpoints?.length > 0) {
|
|
245
242
|
out.write(data.endpoints, {
|
|
246
243
|
fields: ['id', 'created_at'],
|
|
247
244
|
title: 'endpoints',
|
|
245
|
+
emptyMessage: 'No endpoints have been found.',
|
|
248
246
|
});
|
|
249
247
|
}
|
|
250
248
|
if (data.connection_uris?.length) {
|
|
251
249
|
out.write(data.connection_uris, {
|
|
252
250
|
fields: ['connection_uri'],
|
|
253
251
|
title: 'connection_uris',
|
|
252
|
+
emptyMessage: 'No connection uris have been found',
|
|
254
253
|
});
|
|
255
254
|
}
|
|
256
255
|
out.end();
|
|
@@ -353,6 +352,7 @@ const restore = async (props) => {
|
|
|
353
352
|
const writeInst = writer(props).write(data.branch, {
|
|
354
353
|
title: 'Restored branch',
|
|
355
354
|
fields: ['id', 'name', 'last_reset_at'],
|
|
355
|
+
emptyMessage: 'No branches have been restored.',
|
|
356
356
|
});
|
|
357
357
|
const parentId = data.branch.parent_id;
|
|
358
358
|
if (props.preserveUnderName && parentId) {
|
|
@@ -360,6 +360,7 @@ const restore = async (props) => {
|
|
|
360
360
|
writeInst.write(data.branch, {
|
|
361
361
|
title: 'Backup branch',
|
|
362
362
|
fields: ['id', 'name'],
|
|
363
|
+
emptyMessage: 'Backup branch has not been found.',
|
|
363
364
|
});
|
|
364
365
|
}
|
|
365
366
|
writeInst.end();
|
|
@@ -157,16 +157,6 @@ describe('branches', () => {
|
|
|
157
157
|
'test',
|
|
158
158
|
]);
|
|
159
159
|
});
|
|
160
|
-
/* set primary */
|
|
161
|
-
test('set primary by id', async ({ testCliCommand }) => {
|
|
162
|
-
await testCliCommand([
|
|
163
|
-
'branches',
|
|
164
|
-
'set-primary',
|
|
165
|
-
'br-sunny-branch-123456',
|
|
166
|
-
'--project-id',
|
|
167
|
-
'test',
|
|
168
|
-
]);
|
|
169
|
-
});
|
|
170
160
|
/* set default */
|
|
171
161
|
test('set default by id', async ({ testCliCommand }) => {
|
|
172
162
|
await testCliCommand([
|
package/commands/ip_allow.js
CHANGED
|
@@ -36,13 +36,6 @@ export const builder = (argv) => {
|
|
|
36
36
|
describe: projectUpdateRequest['project.settings.allowed_ips.protected_branches_only'].description,
|
|
37
37
|
type: 'boolean',
|
|
38
38
|
},
|
|
39
|
-
})
|
|
40
|
-
.options({
|
|
41
|
-
'primary-only': {
|
|
42
|
-
describe: projectUpdateRequest['project.settings.allowed_ips.primary_branch_only'].description,
|
|
43
|
-
type: 'boolean',
|
|
44
|
-
deprecated: 'See --protected-only',
|
|
45
|
-
},
|
|
46
39
|
}), async (args) => {
|
|
47
40
|
await add(args);
|
|
48
41
|
})
|
|
@@ -83,7 +76,6 @@ const add = async (props) => {
|
|
|
83
76
|
project.settings = {
|
|
84
77
|
allowed_ips: {
|
|
85
78
|
ips: [...new Set(props.ips.concat(existingAllowedIps?.ips ?? []))],
|
|
86
|
-
primary_branch_only: props.primaryOnly ?? existingAllowedIps?.primary_branch_only ?? false,
|
|
87
79
|
protected_branches_only: props.protectedOnly ??
|
|
88
80
|
existingAllowedIps?.protected_branches_only ??
|
|
89
81
|
false,
|
|
@@ -106,7 +98,6 @@ const remove = async (props) => {
|
|
|
106
98
|
project.settings = {
|
|
107
99
|
allowed_ips: {
|
|
108
100
|
ips: existingAllowedIps?.ips?.filter((ip) => !props.ips.includes(ip)) ?? [],
|
|
109
|
-
primary_branch_only: existingAllowedIps?.primary_branch_only ?? false,
|
|
110
101
|
protected_branches_only: existingAllowedIps?.protected_branches_only ?? false,
|
|
111
102
|
},
|
|
112
103
|
};
|
|
@@ -122,7 +113,6 @@ const reset = async (props) => {
|
|
|
122
113
|
project.settings = {
|
|
123
114
|
allowed_ips: {
|
|
124
115
|
ips: props.ips,
|
|
125
|
-
primary_branch_only: false,
|
|
126
116
|
protected_branches_only: false,
|
|
127
117
|
},
|
|
128
118
|
};
|
|
@@ -142,7 +132,6 @@ const parse = (project) => {
|
|
|
142
132
|
id: project.id,
|
|
143
133
|
name: project.name,
|
|
144
134
|
IP_addresses: ips,
|
|
145
|
-
primary_branch_only: project.settings?.allowed_ips?.primary_branch_only ?? false,
|
|
146
135
|
protected_branches_only: project.settings?.allowed_ips?.protected_branches_only ?? false,
|
|
147
136
|
};
|
|
148
137
|
};
|
|
@@ -16,17 +16,6 @@ describe('ip-allow', () => {
|
|
|
16
16
|
Example: neonctl ip-allow add 192.168.1.1, 192.168.1.20-192.168.1.50, 192.168.1.0/24 --project-id <id>`,
|
|
17
17
|
});
|
|
18
18
|
});
|
|
19
|
-
test('Add IP allow - Primary', async ({ testCliCommand }) => {
|
|
20
|
-
await testCliCommand([
|
|
21
|
-
'ip-allow',
|
|
22
|
-
'add',
|
|
23
|
-
'127.0.0.1',
|
|
24
|
-
'192.168.10.1-192.168.10.15',
|
|
25
|
-
'--primary-only',
|
|
26
|
-
'--project-id',
|
|
27
|
-
'test',
|
|
28
|
-
]);
|
|
29
|
-
});
|
|
30
19
|
test('Add IP allow - Protected', async ({ testCliCommand }) => {
|
|
31
20
|
await testCliCommand([
|
|
32
21
|
'ip-allow',
|
package/commands/orgs.js
CHANGED
package/commands/projects.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { log } from '../log.js';
|
|
2
|
-
import { projectCreateRequest
|
|
2
|
+
import { projectCreateRequest } from '../parameters.gen.js';
|
|
3
3
|
import { writer } from '../writer.js';
|
|
4
4
|
import { psql } from '../utils/psql.js';
|
|
5
5
|
import { updateContextFile } from '../context.js';
|
|
@@ -13,9 +13,11 @@ export const PROJECT_FIELDS = [
|
|
|
13
13
|
const REGIONS = [
|
|
14
14
|
'aws-us-west-2',
|
|
15
15
|
'aws-ap-southeast-1',
|
|
16
|
+
'aws-ap-southeast-2',
|
|
16
17
|
'aws-eu-central-1',
|
|
17
18
|
'aws-us-east-2',
|
|
18
19
|
'aws-us-east-1',
|
|
20
|
+
'azure-eastus2',
|
|
19
21
|
];
|
|
20
22
|
const PROJECTS_LIST_LIMIT = 100;
|
|
21
23
|
export const command = 'projects';
|
|
@@ -75,18 +77,6 @@ export const builder = (argv) => {
|
|
|
75
77
|
describe: projectCreateRequest['project.name'].description,
|
|
76
78
|
type: 'string',
|
|
77
79
|
},
|
|
78
|
-
'ip-allow': {
|
|
79
|
-
describe: projectUpdateRequest['project.settings.allowed_ips.ips']
|
|
80
|
-
.description,
|
|
81
|
-
type: 'string',
|
|
82
|
-
array: true,
|
|
83
|
-
deprecated: "Deprecated. Use 'ip-allow' command",
|
|
84
|
-
},
|
|
85
|
-
'ip-primary-only': {
|
|
86
|
-
describe: projectUpdateRequest['project.settings.allowed_ips.primary_branch_only'].description,
|
|
87
|
-
type: 'boolean',
|
|
88
|
-
deprecated: "Deprecated. Use 'ip-allow' command",
|
|
89
|
-
},
|
|
90
80
|
cu: {
|
|
91
81
|
describe: 'The number of Compute Units. Could be a fixed size (e.g. "2") or a range delimited by a dash (e.g. "0.5-3").',
|
|
92
82
|
type: 'string',
|
|
@@ -124,19 +114,21 @@ const list = async (props) => {
|
|
|
124
114
|
}
|
|
125
115
|
return result;
|
|
126
116
|
};
|
|
127
|
-
const ownedProjects = getList(props.apiClient.listProjects);
|
|
117
|
+
const ownedProjects = await getList(props.apiClient.listProjects);
|
|
128
118
|
const sharedProjects = props.orgId
|
|
129
|
-
?
|
|
130
|
-
: getList(props.apiClient.listSharedProjects);
|
|
119
|
+
? []
|
|
120
|
+
: await getList(props.apiClient.listSharedProjects);
|
|
131
121
|
const out = writer(props);
|
|
132
|
-
out.write(
|
|
122
|
+
out.write(ownedProjects, {
|
|
133
123
|
fields: PROJECT_FIELDS,
|
|
134
124
|
title: 'Projects',
|
|
125
|
+
emptyMessage: "You don't have any projects yet. See how to create a new project:\n> neonctl projects create --help",
|
|
135
126
|
});
|
|
136
|
-
if (
|
|
137
|
-
out.write(
|
|
127
|
+
if (!props.orgId) {
|
|
128
|
+
out.write(sharedProjects, {
|
|
138
129
|
fields: PROJECT_FIELDS,
|
|
139
|
-
title: 'Shared with
|
|
130
|
+
title: 'Shared with you',
|
|
131
|
+
emptyMessage: 'No projects have been shared with you',
|
|
140
132
|
});
|
|
141
133
|
}
|
|
142
134
|
out.end();
|
|
@@ -196,18 +188,6 @@ const update = async (props) => {
|
|
|
196
188
|
if (props.name) {
|
|
197
189
|
project.name = props.name;
|
|
198
190
|
}
|
|
199
|
-
if (props.ipAllow || props.ipPrimaryOnly != undefined) {
|
|
200
|
-
const { data } = await props.apiClient.getProject(props.id);
|
|
201
|
-
const existingAllowedIps = data.project.settings?.allowed_ips;
|
|
202
|
-
project.settings = {
|
|
203
|
-
allowed_ips: {
|
|
204
|
-
ips: props.ipAllow ?? existingAllowedIps?.ips ?? [],
|
|
205
|
-
primary_branch_only: props.ipPrimaryOnly ??
|
|
206
|
-
existingAllowedIps?.primary_branch_only ??
|
|
207
|
-
false,
|
|
208
|
-
},
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
191
|
if (props.cu) {
|
|
212
192
|
project.default_endpoint_settings = props.cu
|
|
213
193
|
? getComputeUnits(props.cu)
|
|
@@ -102,29 +102,6 @@ describe('projects', () => {
|
|
|
102
102
|
'test_project_new_name',
|
|
103
103
|
]);
|
|
104
104
|
});
|
|
105
|
-
test('update ip allow', async ({ testCliCommand }) => {
|
|
106
|
-
await testCliCommand([
|
|
107
|
-
'projects',
|
|
108
|
-
'update',
|
|
109
|
-
'test',
|
|
110
|
-
'--ip-allow',
|
|
111
|
-
'127.0.0.1',
|
|
112
|
-
'192.168.1.2/22',
|
|
113
|
-
'--ip-primary-only',
|
|
114
|
-
]);
|
|
115
|
-
});
|
|
116
|
-
test('update ip allow primary only flag', async ({ testCliCommand }) => {
|
|
117
|
-
await testCliCommand([
|
|
118
|
-
'projects',
|
|
119
|
-
'update',
|
|
120
|
-
'test',
|
|
121
|
-
'--ip-primary-only',
|
|
122
|
-
'false',
|
|
123
|
-
]);
|
|
124
|
-
});
|
|
125
|
-
test('update ip allow remove', async ({ testCliCommand }) => {
|
|
126
|
-
await testCliCommand(['projects', 'update', 'test', '--ip-allow']);
|
|
127
|
-
});
|
|
128
105
|
test('update project with default fixed size CU', async ({ testCliCommand, }) => {
|
|
129
106
|
await testCliCommand([
|
|
130
107
|
'projects',
|
package/index.js
CHANGED
package/log.js
CHANGED
package/package.json
CHANGED
package/writer.js
CHANGED
|
@@ -22,6 +22,10 @@ const writeJson = (chunks) => {
|
|
|
22
22
|
const writeTable = (chunks, out) => {
|
|
23
23
|
chunks.forEach(({ data, config }) => {
|
|
24
24
|
const arrayData = Array.isArray(data) ? data : [data];
|
|
25
|
+
if (!arrayData.length && config.emptyMessage) {
|
|
26
|
+
out.write('\n' + config.emptyMessage + '\n');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
25
29
|
const fields = config.fields.filter((field) => arrayData.some((item) => item[field] !== undefined && item[field] !== ''));
|
|
26
30
|
const table = new Table({
|
|
27
31
|
style: {
|