neonctl 1.35.0 → 1.37.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 +18 -19
- package/commands/projects.js +27 -10
- package/commands/projects.test.js +13 -0
- package/commands/set_context.js +5 -0
- package/commands/set_context.test.js +64 -1
- package/context.js +3 -0
- package/index.js +1 -0
- package/log.js +3 -0
- package/package.json +1 -1
package/commands/branches.js
CHANGED
|
@@ -187,17 +187,16 @@ const list = async (props) => {
|
|
|
187
187
|
});
|
|
188
188
|
};
|
|
189
189
|
const create = async (props) => {
|
|
190
|
-
const
|
|
190
|
+
const branches = await props.apiClient
|
|
191
|
+
.listProjectBranches(props.projectId)
|
|
192
|
+
.then(({ data }) => data.branches);
|
|
193
|
+
const parentProps = (() => {
|
|
191
194
|
if (!props.parent) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
throw new Error('No default branch found');
|
|
198
|
-
}
|
|
199
|
-
return { parent_id: branch.id };
|
|
200
|
-
});
|
|
195
|
+
const branch = branches.find((b) => b.default);
|
|
196
|
+
if (!branch) {
|
|
197
|
+
throw new Error('No default branch found');
|
|
198
|
+
}
|
|
199
|
+
return { parent_id: branch.id };
|
|
201
200
|
}
|
|
202
201
|
if (looksLikeLSN(props.parent)) {
|
|
203
202
|
return { parent_lsn: props.parent };
|
|
@@ -208,15 +207,11 @@ const create = async (props) => {
|
|
|
208
207
|
if (looksLikeBranchId(props.parent)) {
|
|
209
208
|
return { parent_id: props.parent };
|
|
210
209
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
throw new Error(`Branch ${props.parent} not found`);
|
|
217
|
-
}
|
|
218
|
-
return { parent_id: branch.id };
|
|
219
|
-
});
|
|
210
|
+
const branch = branches.find((b) => b.name === props.parent);
|
|
211
|
+
if (!branch) {
|
|
212
|
+
throw new Error(`Branch ${props.parent} not found`);
|
|
213
|
+
}
|
|
214
|
+
return { parent_id: branch.id };
|
|
220
215
|
})();
|
|
221
216
|
const { data } = await retryOnLock(() => props.apiClient.createProjectBranch(props.projectId, {
|
|
222
217
|
branch: {
|
|
@@ -236,6 +231,10 @@ const create = async (props) => {
|
|
|
236
231
|
? JSON.parse(props.annotation)
|
|
237
232
|
: undefined,
|
|
238
233
|
}));
|
|
234
|
+
const parent = branches.find((b) => b.id === data.branch.parent_id);
|
|
235
|
+
if (parent?.protected) {
|
|
236
|
+
log.warning('The parent branch is protected; a unique role password has been generated for the new branch.');
|
|
237
|
+
}
|
|
239
238
|
const out = writer(props);
|
|
240
239
|
out.write(data.branch, {
|
|
241
240
|
fields: BRANCH_FIELDS,
|
package/commands/projects.js
CHANGED
|
@@ -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';
|
|
@@ -24,7 +26,12 @@ export const aliases = ['project'];
|
|
|
24
26
|
export const builder = (argv) => {
|
|
25
27
|
return argv
|
|
26
28
|
.usage('$0 projects <sub-command> [options]')
|
|
27
|
-
.command('list', 'List projects', (yargs) => yargs
|
|
29
|
+
.command('list', 'List projects', (yargs) => yargs.options({
|
|
30
|
+
'org-id': {
|
|
31
|
+
describe: 'List projects of a given organization',
|
|
32
|
+
type: 'string',
|
|
33
|
+
},
|
|
34
|
+
}), async (args) => {
|
|
28
35
|
await list(args);
|
|
29
36
|
})
|
|
30
37
|
.command('create', 'Create a project', (yargs) => yargs.options({
|
|
@@ -36,6 +43,10 @@ export const builder = (argv) => {
|
|
|
36
43
|
describe: `The region ID. Possible values: ${REGIONS.join(', ')}`,
|
|
37
44
|
type: 'string',
|
|
38
45
|
},
|
|
46
|
+
'org-id': {
|
|
47
|
+
describe: "The project's organization ID",
|
|
48
|
+
type: 'string',
|
|
49
|
+
},
|
|
39
50
|
psql: {
|
|
40
51
|
type: 'boolean',
|
|
41
52
|
describe: 'Connect to a new project via psql',
|
|
@@ -103,6 +114,7 @@ const list = async (props) => {
|
|
|
103
114
|
while (!end) {
|
|
104
115
|
const { data } = await fn({
|
|
105
116
|
limit: PROJECTS_LIST_LIMIT,
|
|
117
|
+
org_id: props.orgId,
|
|
106
118
|
cursor,
|
|
107
119
|
});
|
|
108
120
|
result.push(...data.projects);
|
|
@@ -114,19 +126,21 @@ const list = async (props) => {
|
|
|
114
126
|
}
|
|
115
127
|
return result;
|
|
116
128
|
};
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
129
|
+
const ownedProjects = getList(props.apiClient.listProjects);
|
|
130
|
+
const sharedProjects = props.orgId
|
|
131
|
+
? undefined
|
|
132
|
+
: getList(props.apiClient.listSharedProjects);
|
|
121
133
|
const out = writer(props);
|
|
122
|
-
out.write(ownedProjects, {
|
|
134
|
+
out.write(await ownedProjects, {
|
|
123
135
|
fields: PROJECT_FIELDS,
|
|
124
136
|
title: 'Projects',
|
|
125
137
|
});
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
138
|
+
if (sharedProjects) {
|
|
139
|
+
out.write(await sharedProjects, {
|
|
140
|
+
fields: PROJECT_FIELDS,
|
|
141
|
+
title: 'Shared with you',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
130
144
|
out.end();
|
|
131
145
|
};
|
|
132
146
|
const create = async (props) => {
|
|
@@ -137,6 +151,9 @@ const create = async (props) => {
|
|
|
137
151
|
if (props.regionId) {
|
|
138
152
|
project.region_id = props.regionId;
|
|
139
153
|
}
|
|
154
|
+
if (props.orgId) {
|
|
155
|
+
project.org_id = props.orgId;
|
|
156
|
+
}
|
|
140
157
|
project.branch = {};
|
|
141
158
|
if (props.database) {
|
|
142
159
|
project.branch.database_name = props.database;
|
|
@@ -7,9 +7,22 @@ describe('projects', () => {
|
|
|
7
7
|
test('list', async ({ testCliCommand }) => {
|
|
8
8
|
await testCliCommand(['projects', 'list']);
|
|
9
9
|
});
|
|
10
|
+
test('list with org id', async ({ testCliCommand }) => {
|
|
11
|
+
await testCliCommand(['projects', 'list', '--org-id', 'org-2']);
|
|
12
|
+
});
|
|
10
13
|
test('create', async ({ testCliCommand }) => {
|
|
11
14
|
await testCliCommand(['projects', 'create', '--name', 'test_project']);
|
|
12
15
|
});
|
|
16
|
+
test('create with org id', async ({ testCliCommand }) => {
|
|
17
|
+
await testCliCommand([
|
|
18
|
+
'projects',
|
|
19
|
+
'create',
|
|
20
|
+
'--name',
|
|
21
|
+
'test_project',
|
|
22
|
+
'--org-id',
|
|
23
|
+
'org-2',
|
|
24
|
+
]);
|
|
25
|
+
});
|
|
13
26
|
test('create with database and role', async ({ testCliCommand }) => {
|
|
14
27
|
await testCliCommand([
|
|
15
28
|
'projects',
|
package/commands/set_context.js
CHANGED
|
@@ -6,10 +6,15 @@ export const builder = (argv) => argv.usage('$0 set-context [options]').options(
|
|
|
6
6
|
describe: 'Project ID',
|
|
7
7
|
type: 'string',
|
|
8
8
|
},
|
|
9
|
+
'org-id': {
|
|
10
|
+
describe: 'Organization ID',
|
|
11
|
+
type: 'string',
|
|
12
|
+
},
|
|
9
13
|
});
|
|
10
14
|
export const handler = (props) => {
|
|
11
15
|
const context = {
|
|
12
16
|
projectId: props.projectId,
|
|
17
|
+
orgId: props.orgId,
|
|
13
18
|
};
|
|
14
19
|
updateContextFile(props.contextFile, context);
|
|
15
20
|
};
|
|
@@ -28,7 +28,7 @@ const test = originalTest.extend({
|
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
30
|
describe('set_context', () => {
|
|
31
|
-
describe('should set the context', () => {
|
|
31
|
+
describe('should set the context to project', () => {
|
|
32
32
|
test('set-context', async ({ testCliCommand, readFile }) => {
|
|
33
33
|
await testCliCommand([
|
|
34
34
|
'set-context',
|
|
@@ -93,4 +93,67 @@ describe('set_context', () => {
|
|
|
93
93
|
});
|
|
94
94
|
});
|
|
95
95
|
});
|
|
96
|
+
describe('should set the context to organization', () => {
|
|
97
|
+
test('set-context', async ({ testCliCommand, readFile }) => {
|
|
98
|
+
await testCliCommand([
|
|
99
|
+
'set-context',
|
|
100
|
+
'--org-id',
|
|
101
|
+
'org-2',
|
|
102
|
+
'--context-file',
|
|
103
|
+
CONTEXT_FILE,
|
|
104
|
+
]);
|
|
105
|
+
expect(readFile(CONTEXT_FILE)).toMatchSnapshot();
|
|
106
|
+
});
|
|
107
|
+
test('list projects selecting organization from the context', async ({ testCliCommand, writeFile, }) => {
|
|
108
|
+
writeFile(CONTEXT_FILE, {
|
|
109
|
+
orgId: 'org-2',
|
|
110
|
+
});
|
|
111
|
+
await testCliCommand([
|
|
112
|
+
'projects',
|
|
113
|
+
'list',
|
|
114
|
+
'--context-file',
|
|
115
|
+
CONTEXT_FILE,
|
|
116
|
+
]);
|
|
117
|
+
});
|
|
118
|
+
test('list projects with explicit org id overrides context', async ({ testCliCommand, writeFile, }) => {
|
|
119
|
+
writeFile(CONTEXT_FILE, {
|
|
120
|
+
orgId: 'org-2',
|
|
121
|
+
});
|
|
122
|
+
await testCliCommand([
|
|
123
|
+
'project',
|
|
124
|
+
'list',
|
|
125
|
+
'--org-id',
|
|
126
|
+
'org-3',
|
|
127
|
+
'--context-file',
|
|
128
|
+
CONTEXT_FILE,
|
|
129
|
+
]);
|
|
130
|
+
});
|
|
131
|
+
test('create projects selecting organization from the context', async ({ testCliCommand, writeFile, }) => {
|
|
132
|
+
writeFile(CONTEXT_FILE, {
|
|
133
|
+
orgId: 'org-2',
|
|
134
|
+
});
|
|
135
|
+
await testCliCommand([
|
|
136
|
+
'projects',
|
|
137
|
+
'create',
|
|
138
|
+
'--name',
|
|
139
|
+
'test_project',
|
|
140
|
+
'--context-file',
|
|
141
|
+
CONTEXT_FILE,
|
|
142
|
+
]);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe('can set the context to project and organization at the same time', () => {
|
|
146
|
+
test('set-context', async ({ testCliCommand, readFile }) => {
|
|
147
|
+
await testCliCommand([
|
|
148
|
+
'set-context',
|
|
149
|
+
'--project-id',
|
|
150
|
+
'test_project',
|
|
151
|
+
'--org-id',
|
|
152
|
+
'org-2',
|
|
153
|
+
'--context-file',
|
|
154
|
+
CONTEXT_FILE,
|
|
155
|
+
]);
|
|
156
|
+
expect(readFile(CONTEXT_FILE)).toMatchSnapshot();
|
|
157
|
+
});
|
|
158
|
+
});
|
|
96
159
|
});
|
package/context.js
CHANGED
package/index.js
CHANGED
package/log.js
CHANGED