neonctl 1.37.0 → 2.1.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/analytics.js +2 -1
- package/commands/bootstrap/index.js +1 -1
- package/commands/branches.js +5 -3
- 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 +9 -31
- package/commands/projects.test.js +0 -23
- package/env.js +36 -0
- package/env.test.js +56 -0
- package/package.json +1 -1
- package/writer.js +4 -0
package/analytics.js
CHANGED
|
@@ -3,7 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { Analytics } from '@segment/analytics-node';
|
|
4
4
|
import { isAxiosError } from 'axios';
|
|
5
5
|
import { CREDENTIALS_FILE } from './config.js';
|
|
6
|
-
import { isCi } from './env.js';
|
|
6
|
+
import { getGithubEnvVars, isCi } from './env.js';
|
|
7
7
|
import { log } from './log.js';
|
|
8
8
|
import pkg from './pkg.js';
|
|
9
9
|
import { getApiClient } from './api.js';
|
|
@@ -55,6 +55,7 @@ export const analyticsMiddleware = async (args) => {
|
|
|
55
55
|
output: args.output,
|
|
56
56
|
},
|
|
57
57
|
ci: isCi(),
|
|
58
|
+
githubEnvVars: getGithubEnvVars(process.env),
|
|
58
59
|
},
|
|
59
60
|
});
|
|
60
61
|
};
|
|
@@ -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: {
|
|
@@ -239,17 +236,20 @@ const create = async (props) => {
|
|
|
239
236
|
out.write(data.branch, {
|
|
240
237
|
fields: BRANCH_FIELDS,
|
|
241
238
|
title: 'branch',
|
|
239
|
+
emptyMessage: 'No branches have been found.',
|
|
242
240
|
});
|
|
243
241
|
if (data.endpoints?.length > 0) {
|
|
244
242
|
out.write(data.endpoints, {
|
|
245
243
|
fields: ['id', 'created_at'],
|
|
246
244
|
title: 'endpoints',
|
|
245
|
+
emptyMessage: 'No endpoints have been found.',
|
|
247
246
|
});
|
|
248
247
|
}
|
|
249
248
|
if (data.connection_uris?.length) {
|
|
250
249
|
out.write(data.connection_uris, {
|
|
251
250
|
fields: ['connection_uri'],
|
|
252
251
|
title: 'connection_uris',
|
|
252
|
+
emptyMessage: 'No connection uris have been found',
|
|
253
253
|
});
|
|
254
254
|
}
|
|
255
255
|
out.end();
|
|
@@ -352,6 +352,7 @@ const restore = async (props) => {
|
|
|
352
352
|
const writeInst = writer(props).write(data.branch, {
|
|
353
353
|
title: 'Restored branch',
|
|
354
354
|
fields: ['id', 'name', 'last_reset_at'],
|
|
355
|
+
emptyMessage: 'No branches have been restored.',
|
|
355
356
|
});
|
|
356
357
|
const parentId = data.branch.parent_id;
|
|
357
358
|
if (props.preserveUnderName && parentId) {
|
|
@@ -359,6 +360,7 @@ const restore = async (props) => {
|
|
|
359
360
|
writeInst.write(data.branch, {
|
|
360
361
|
title: 'Backup branch',
|
|
361
362
|
fields: ['id', 'name'],
|
|
363
|
+
emptyMessage: 'Backup branch has not been found.',
|
|
362
364
|
});
|
|
363
365
|
}
|
|
364
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';
|
|
@@ -77,18 +77,6 @@ export const builder = (argv) => {
|
|
|
77
77
|
describe: projectCreateRequest['project.name'].description,
|
|
78
78
|
type: 'string',
|
|
79
79
|
},
|
|
80
|
-
'ip-allow': {
|
|
81
|
-
describe: projectUpdateRequest['project.settings.allowed_ips.ips']
|
|
82
|
-
.description,
|
|
83
|
-
type: 'string',
|
|
84
|
-
array: true,
|
|
85
|
-
deprecated: "Deprecated. Use 'ip-allow' command",
|
|
86
|
-
},
|
|
87
|
-
'ip-primary-only': {
|
|
88
|
-
describe: projectUpdateRequest['project.settings.allowed_ips.primary_branch_only'].description,
|
|
89
|
-
type: 'boolean',
|
|
90
|
-
deprecated: "Deprecated. Use 'ip-allow' command",
|
|
91
|
-
},
|
|
92
80
|
cu: {
|
|
93
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").',
|
|
94
82
|
type: 'string',
|
|
@@ -126,19 +114,21 @@ const list = async (props) => {
|
|
|
126
114
|
}
|
|
127
115
|
return result;
|
|
128
116
|
};
|
|
129
|
-
const ownedProjects = getList(props.apiClient.listProjects);
|
|
117
|
+
const ownedProjects = await getList(props.apiClient.listProjects);
|
|
130
118
|
const sharedProjects = props.orgId
|
|
131
|
-
?
|
|
132
|
-
: getList(props.apiClient.listSharedProjects);
|
|
119
|
+
? []
|
|
120
|
+
: await getList(props.apiClient.listSharedProjects);
|
|
133
121
|
const out = writer(props);
|
|
134
|
-
out.write(
|
|
122
|
+
out.write(ownedProjects, {
|
|
135
123
|
fields: PROJECT_FIELDS,
|
|
136
124
|
title: 'Projects',
|
|
125
|
+
emptyMessage: "You don't have any projects yet. See how to create a new project:\n> neonctl projects create --help",
|
|
137
126
|
});
|
|
138
|
-
if (
|
|
139
|
-
out.write(
|
|
127
|
+
if (!props.orgId) {
|
|
128
|
+
out.write(sharedProjects, {
|
|
140
129
|
fields: PROJECT_FIELDS,
|
|
141
130
|
title: 'Shared with you',
|
|
131
|
+
emptyMessage: 'No projects have been shared with you',
|
|
142
132
|
});
|
|
143
133
|
}
|
|
144
134
|
out.end();
|
|
@@ -198,18 +188,6 @@ const update = async (props) => {
|
|
|
198
188
|
if (props.name) {
|
|
199
189
|
project.name = props.name;
|
|
200
190
|
}
|
|
201
|
-
if (props.ipAllow || props.ipPrimaryOnly != undefined) {
|
|
202
|
-
const { data } = await props.apiClient.getProject(props.id);
|
|
203
|
-
const existingAllowedIps = data.project.settings?.allowed_ips;
|
|
204
|
-
project.settings = {
|
|
205
|
-
allowed_ips: {
|
|
206
|
-
ips: props.ipAllow ?? existingAllowedIps?.ips ?? [],
|
|
207
|
-
primary_branch_only: props.ipPrimaryOnly ??
|
|
208
|
-
existingAllowedIps?.primary_branch_only ??
|
|
209
|
-
false,
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
191
|
if (props.cu) {
|
|
214
192
|
project.default_endpoint_settings = props.cu
|
|
215
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/env.js
CHANGED
|
@@ -4,3 +4,39 @@ export const isCi = () => {
|
|
|
4
4
|
export const isDebug = () => {
|
|
5
5
|
return Boolean(process.env.DEBUG);
|
|
6
6
|
};
|
|
7
|
+
export const getGithubEnvVars = (env) => {
|
|
8
|
+
const vars = [
|
|
9
|
+
// github action info
|
|
10
|
+
'GITHUB_ACTION',
|
|
11
|
+
'GITHUB_ACTION_PATH',
|
|
12
|
+
'GITHUB_ACTION_REPOSITORY',
|
|
13
|
+
// source github repository and actor info
|
|
14
|
+
'GITHUB_REF_TYPE',
|
|
15
|
+
'GITHUB_REF',
|
|
16
|
+
'GITHUB_REF_NAME',
|
|
17
|
+
'GITHUB_BASE_REF',
|
|
18
|
+
'GITHUB_HEAD_REF',
|
|
19
|
+
'GITHUB_JOB',
|
|
20
|
+
'GITHUB_SHA',
|
|
21
|
+
'GITHUB_REPOSITORY',
|
|
22
|
+
'GITHUB_REPOSITORY_ID',
|
|
23
|
+
'GITHUB_REPOSITORY_OWNER',
|
|
24
|
+
'GITHUB_REPOSITORY_OWNER_ID',
|
|
25
|
+
'GITHUB_TRIGGERING_ACTOR',
|
|
26
|
+
'GITHUB_ACTOR',
|
|
27
|
+
'GITHUB_ACTOR_ID',
|
|
28
|
+
'GITHUB_EVENT_NAME',
|
|
29
|
+
'GITHUB_RUN_NUMBER',
|
|
30
|
+
// reusable workflow info
|
|
31
|
+
'GITHUB_WORKFLOW',
|
|
32
|
+
'GITHUB_WORKFLOW_REF',
|
|
33
|
+
'GITHUB_WORKFLOW_SHA',
|
|
34
|
+
];
|
|
35
|
+
const map = new Map();
|
|
36
|
+
vars.forEach((v) => {
|
|
37
|
+
if (env[v]) {
|
|
38
|
+
map.set(v, env[v]);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return Object.fromEntries(map);
|
|
42
|
+
};
|
package/env.test.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { getGithubEnvVars } from './env';
|
|
3
|
+
describe('getGithubEnvVars', () => {
|
|
4
|
+
it('success all keys', () => {
|
|
5
|
+
const env = {
|
|
6
|
+
GITHUB_ACTION: '1',
|
|
7
|
+
GITHUB_ACTION_PATH: '2',
|
|
8
|
+
GITHUB_ACTION_REPOSITORY: '3',
|
|
9
|
+
GITHUB_REF_TYPE: '4',
|
|
10
|
+
GITHUB_REF: '5',
|
|
11
|
+
GITHUB_REF_NAME: '6',
|
|
12
|
+
GITHUB_BASE_REF: '7',
|
|
13
|
+
GITHUB_HEAD_REF: '8',
|
|
14
|
+
GITHUB_JOB: '9',
|
|
15
|
+
GITHUB_SHA: '10',
|
|
16
|
+
GITHUB_REPOSITORY: '11',
|
|
17
|
+
GITHUB_REPOSITORY_ID: '12',
|
|
18
|
+
GITHUB_REPOSITORY_OWNER: '13',
|
|
19
|
+
GITHUB_REPOSITORY_OWNER_ID: '14',
|
|
20
|
+
GITHUB_TRIGGERING_ACTOR: '15',
|
|
21
|
+
GITHUB_ACTOR: '16',
|
|
22
|
+
GITHUB_ACTOR_ID: '17',
|
|
23
|
+
GITHUB_EVENT_NAME: '18',
|
|
24
|
+
GITHUB_RUN_NUMBER: '19',
|
|
25
|
+
GITHUB_WORKFLOW: '20',
|
|
26
|
+
GITHUB_WORKFLOW_REF: '21',
|
|
27
|
+
GITHUB_WORKFLOW_SHA: '22',
|
|
28
|
+
unrelated: 'unrelated',
|
|
29
|
+
};
|
|
30
|
+
const ret = {
|
|
31
|
+
GITHUB_ACTION: '1',
|
|
32
|
+
GITHUB_ACTION_PATH: '2',
|
|
33
|
+
GITHUB_ACTION_REPOSITORY: '3',
|
|
34
|
+
GITHUB_REF_TYPE: '4',
|
|
35
|
+
GITHUB_REF: '5',
|
|
36
|
+
GITHUB_REF_NAME: '6',
|
|
37
|
+
GITHUB_BASE_REF: '7',
|
|
38
|
+
GITHUB_HEAD_REF: '8',
|
|
39
|
+
GITHUB_JOB: '9',
|
|
40
|
+
GITHUB_SHA: '10',
|
|
41
|
+
GITHUB_REPOSITORY: '11',
|
|
42
|
+
GITHUB_REPOSITORY_ID: '12',
|
|
43
|
+
GITHUB_REPOSITORY_OWNER: '13',
|
|
44
|
+
GITHUB_REPOSITORY_OWNER_ID: '14',
|
|
45
|
+
GITHUB_TRIGGERING_ACTOR: '15',
|
|
46
|
+
GITHUB_ACTOR: '16',
|
|
47
|
+
GITHUB_ACTOR_ID: '17',
|
|
48
|
+
GITHUB_EVENT_NAME: '18',
|
|
49
|
+
GITHUB_RUN_NUMBER: '19',
|
|
50
|
+
GITHUB_WORKFLOW: '20',
|
|
51
|
+
GITHUB_WORKFLOW_REF: '21',
|
|
52
|
+
GITHUB_WORKFLOW_SHA: '22',
|
|
53
|
+
};
|
|
54
|
+
expect(getGithubEnvVars(env)).toEqual(ret);
|
|
55
|
+
});
|
|
56
|
+
});
|
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: {
|