neonctl 1.28.0 → 1.29.1

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.
Files changed (184) hide show
  1. package/.bump +1 -0
  2. package/.editorconfig +7 -0
  3. package/.eslintrc.cjs +15 -0
  4. package/.github/workflows/commitlint.yml +46 -0
  5. package/.github/workflows/pr.yml +25 -0
  6. package/.github/workflows/release.yml +30 -0
  7. package/.husky/commit-msg +4 -0
  8. package/.husky/pre-commit +4 -0
  9. package/.nvmrc +1 -0
  10. package/.prettierignore +3 -0
  11. package/.prettierrc.json +3 -0
  12. package/.releaserc.json +47 -0
  13. package/LICENSE +202 -0
  14. package/commitlint.config.cjs +7 -0
  15. package/generateOptionsFromSpec.ts +68 -0
  16. package/jest/setup.js +5 -0
  17. package/jest.config.ts +199 -0
  18. package/mocks/bin/psql.cjs +9 -0
  19. package/mocks/main/projects/GET.js +27 -0
  20. package/mocks/main/projects/POST.js +22 -0
  21. package/mocks/main/projects/shared/GET.js +16 -0
  22. package/mocks/main/projects/test/DELETE.json +7 -0
  23. package/mocks/main/projects/test/GET.json +13 -0
  24. package/mocks/main/projects/test/PATCH.js +18 -0
  25. package/mocks/main/projects/test/branches/GET.json +25 -0
  26. package/mocks/main/projects/test/branches/POST.js +83 -0
  27. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/DELETE.json +7 -0
  28. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/GET.json +9 -0
  29. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/PATCH.js +14 -0
  30. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/databases/GET.json +6 -0
  31. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/databases/POST.js +13 -0
  32. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/databases/test_db/DELETE.json +6 -0
  33. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/endpoints/GET.json +26 -0
  34. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/endpoints/POST.json +6 -0
  35. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/GET.json +3 -0
  36. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/POST.js +14 -0
  37. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/test_role/DELETE.json +6 -0
  38. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/test_role/reveal_password/GET.json +3 -0
  39. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/set_as_primary/POST.json +9 -0
  40. package/mocks/main/projects/test/branches/br-numbered-branch-123456/GET.json +10 -0
  41. package/mocks/main/projects/test/branches/br-sunny-branch-123456/DELETE.json +7 -0
  42. package/mocks/main/projects/test/branches/br-sunny-branch-123456/GET.json +10 -0
  43. package/mocks/main/projects/test/branches/br-sunny-branch-123456/PATCH.js +14 -0
  44. package/mocks/main/projects/test/branches/br-sunny-branch-123456/databases/GET.json +6 -0
  45. package/mocks/main/projects/test/branches/br-sunny-branch-123456/databases/POST.js +13 -0
  46. package/mocks/main/projects/test/branches/br-sunny-branch-123456/databases/test_db/DELETE.json +6 -0
  47. package/mocks/main/projects/test/branches/br-sunny-branch-123456/endpoints/GET.json +26 -0
  48. package/mocks/main/projects/test/branches/br-sunny-branch-123456/endpoints/POST.json +6 -0
  49. package/mocks/main/projects/test/branches/br-sunny-branch-123456/restore/POST.js +16 -0
  50. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/GET.json +3 -0
  51. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/POST.js +14 -0
  52. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/test_role/DELETE.json +6 -0
  53. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/test_role/reveal_password/GET.json +3 -0
  54. package/mocks/main/projects/test/branches/br-sunny-branch-123456/set_as_primary/POST.json +9 -0
  55. package/mocks/main/projects/test/endpoints/GET.json +9 -0
  56. package/mocks/main/projects/test/endpoints/POST.js +32 -0
  57. package/mocks/main/projects/test/endpoints/test_endpoint_id/DELETE.json +7 -0
  58. package/mocks/main/projects/test/endpoints/test_endpoint_id/GET.json +9 -0
  59. package/mocks/main/projects/test/endpoints/test_endpoint_id/PATCH.js +17 -0
  60. package/mocks/main/projects/test/operations/GET.json +22 -0
  61. package/mocks/main/users/me/GET.json +5 -0
  62. package/mocks/restore/projects/test/branches/GET.json +21 -0
  63. package/mocks/restore/projects/test/branches/br-another-branch-123456/GET.json +6 -0
  64. package/mocks/restore/projects/test/branches/br-another-branch-123456/restore/POST.js +13 -0
  65. package/mocks/restore/projects/test/branches/br-any-branch-123456/GET.json +6 -0
  66. package/mocks/restore/projects/test/branches/br-parent-tots-123456/GET.json +7 -0
  67. package/mocks/restore/projects/test/branches/br-parent-tots-123456/restore/POST.js +14 -0
  68. package/mocks/restore/projects/test/branches/br-self-tolsn-123456/GET.json +6 -0
  69. package/mocks/restore/projects/test/branches/br-self-tolsn-123456/restore/POST.js +15 -0
  70. package/mocks/single_project/projects/GET.json +10 -0
  71. package/mocks/single_project/projects/test-project-123456/GET.json +14 -0
  72. package/mocks/single_project/projects/test-project-123456/branches/GET.json +11 -0
  73. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/databases/GET.json +3 -0
  74. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/endpoints/GET.json +10 -0
  75. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/roles/GET.json +3 -0
  76. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/roles/test_role/reveal_password/GET.json +3 -0
  77. package/package.json +6 -5
  78. package/pkg.js +45 -3
  79. package/rollup.config.js +20 -0
  80. package/snapshots/commands/branches.test.snap +221 -0
  81. package/snapshots/commands/connection_string.test.snap +70 -0
  82. package/snapshots/commands/databases.test.snap +20 -0
  83. package/snapshots/commands/ip_allow.test.snap +55 -0
  84. package/snapshots/commands/operations.test.snap +17 -0
  85. package/snapshots/commands/projects.test.snap +141 -0
  86. package/snapshots/commands/roles.test.snap +19 -0
  87. package/snapshots/commands/set_context.test.snap +30 -0
  88. package/snapshots/writer.test.snap +60 -0
  89. package/snapshotsResolver.cjs +32 -0
  90. package/src/analytics.ts +95 -0
  91. package/src/api.ts +44 -0
  92. package/src/auth.ts +137 -0
  93. package/{cli.js → src/cli.ts} +1 -0
  94. package/src/commands/auth.test.ts +62 -0
  95. package/src/commands/auth.ts +148 -0
  96. package/src/commands/branches.test.ts +354 -0
  97. package/src/commands/branches.ts +451 -0
  98. package/src/commands/connection_string.test.ts +250 -0
  99. package/src/commands/connection_string.ts +210 -0
  100. package/src/commands/databases.test.ts +55 -0
  101. package/src/commands/databases.ts +129 -0
  102. package/src/commands/help.test.ts +13 -0
  103. package/{commands/index.js → src/commands/index.ts} +11 -10
  104. package/src/commands/ip_allow.test.ts +86 -0
  105. package/src/commands/ip_allow.ts +202 -0
  106. package/src/commands/operations.test.ts +13 -0
  107. package/src/commands/operations.ts +41 -0
  108. package/src/commands/projects.test.ts +147 -0
  109. package/src/commands/projects.ts +275 -0
  110. package/src/commands/roles.test.ts +46 -0
  111. package/src/commands/roles.ts +100 -0
  112. package/src/commands/set_context.test.ts +64 -0
  113. package/src/commands/set_context.ts +27 -0
  114. package/src/commands/user.ts +21 -0
  115. package/src/config.ts +22 -0
  116. package/src/context.ts +61 -0
  117. package/src/env.ts +7 -0
  118. package/src/errors.ts +24 -0
  119. package/src/help.ts +185 -0
  120. package/src/index.ts +180 -0
  121. package/src/log.ts +16 -0
  122. package/src/parameters.gen.ts +332 -0
  123. package/src/pkg.ts +9 -0
  124. package/src/test_utils/mock_server.ts +27 -0
  125. package/src/test_utils/oauth_server.ts +10 -0
  126. package/src/test_utils/test_cli_command.ts +117 -0
  127. package/src/types.ts +25 -0
  128. package/src/utils/enrichers.ts +73 -0
  129. package/src/utils/formats.test.ts +41 -0
  130. package/src/utils/formats.ts +11 -0
  131. package/src/utils/middlewares.ts +23 -0
  132. package/src/utils/point_in_time.ts +86 -0
  133. package/src/utils/psql.ts +29 -0
  134. package/src/utils/string.ts +8 -0
  135. package/src/utils/ui.ts +64 -0
  136. package/src/writer.test.ts +98 -0
  137. package/src/writer.ts +131 -0
  138. package/tsconfig.json +17 -0
  139. package/analytics.js +0 -78
  140. package/api.js +0 -35
  141. package/auth.js +0 -101
  142. package/commands/auth.js +0 -102
  143. package/commands/auth.test.js +0 -42
  144. package/commands/branches.js +0 -303
  145. package/commands/branches.test.js +0 -321
  146. package/commands/connection_string.js +0 -137
  147. package/commands/connection_string.test.js +0 -204
  148. package/commands/databases.js +0 -79
  149. package/commands/databases.test.js +0 -51
  150. package/commands/help.test.js +0 -11
  151. package/commands/ip_allow.js +0 -135
  152. package/commands/ip_allow.test.js +0 -78
  153. package/commands/operations.js +0 -28
  154. package/commands/operations.test.js +0 -11
  155. package/commands/projects.js +0 -170
  156. package/commands/projects.test.js +0 -132
  157. package/commands/roles.js +0 -57
  158. package/commands/roles.test.js +0 -42
  159. package/commands/set_context.js +0 -22
  160. package/commands/set_context.test.js +0 -53
  161. package/commands/user.js +0 -15
  162. package/config.js +0 -11
  163. package/context.js +0 -48
  164. package/env.js +0 -6
  165. package/errors.js +0 -16
  166. package/help.js +0 -146
  167. package/index.js +0 -168
  168. package/log.js +0 -15
  169. package/parameters.gen.js +0 -322
  170. package/test_utils/mock_server.js +0 -16
  171. package/test_utils/oauth_server.js +0 -9
  172. package/test_utils/test_cli_command.js +0 -80
  173. package/types.js +0 -1
  174. package/utils/enrichers.js +0 -49
  175. package/utils/formats.js +0 -5
  176. package/utils/formats.test.js +0 -32
  177. package/utils/middlewares.js +0 -20
  178. package/utils/point_in_time.js +0 -44
  179. package/utils/psql.js +0 -24
  180. package/utils/string.js +0 -5
  181. package/utils/ui.js +0 -59
  182. package/writer.js +0 -87
  183. package/writer.test.js +0 -86
  184. /package/{callback.html → src/callback.html} +0 -0
@@ -1,28 +0,0 @@
1
- import { fillSingleProject } from '../utils/enrichers.js';
2
- import { writer } from '../writer.js';
3
- const OPERATIONS_FIELDS = ['id', 'action', 'status', 'created_at'];
4
- export const command = 'operations';
5
- export const describe = 'Manage operations';
6
- export const aliases = ['operation'];
7
- export const builder = (argv) => argv
8
- .usage('$0 operations <sub-command> [options]')
9
- .options({
10
- 'project-id': {
11
- describe: 'Project ID',
12
- type: 'string',
13
- },
14
- })
15
- .middleware(fillSingleProject)
16
- .command('list', 'List operations', (yargs) => yargs, async (args) => await list(args));
17
- export const handler = (args) => {
18
- return args;
19
- };
20
- export const list = async (props) => {
21
- const { data } = await props.apiClient.listProjectOperations({
22
- projectId: props.projectId,
23
- limit: props.limit,
24
- });
25
- writer(props).end(data.operations, {
26
- fields: OPERATIONS_FIELDS,
27
- });
28
- };
@@ -1,11 +0,0 @@
1
- import { describe } from '@jest/globals';
2
- import { testCliCommand } from '../test_utils/test_cli_command.js';
3
- describe('operations', () => {
4
- testCliCommand({
5
- name: 'list',
6
- args: ['operations', 'list', '--project-id', 'test'],
7
- expected: {
8
- snapshot: true,
9
- },
10
- });
11
- });
@@ -1,170 +0,0 @@
1
- import { log } from '../log.js';
2
- import { projectCreateRequest, projectUpdateRequest, } from '../parameters.gen.js';
3
- import { writer } from '../writer.js';
4
- import { psql } from '../utils/psql.js';
5
- import { updateContextFile } from '../context.js';
6
- const PROJECT_FIELDS = ['id', 'name', 'region_id', 'created_at'];
7
- const REGIONS = [
8
- 'aws-us-west-2',
9
- 'aws-ap-southeast-1',
10
- 'aws-eu-central-1',
11
- 'aws-us-east-2',
12
- 'aws-us-east-1',
13
- ];
14
- const PROJECTS_LIST_LIMIT = 100;
15
- export const command = 'projects';
16
- export const describe = 'Manage projects';
17
- export const aliases = ['project'];
18
- export const builder = (argv) => {
19
- return argv
20
- .usage('$0 projects <sub-command> [options]')
21
- .command('list', 'List projects', (yargs) => yargs, async (args) => {
22
- await list(args);
23
- })
24
- .command('create', 'Create a project', (yargs) => yargs.options({
25
- name: {
26
- describe: projectCreateRequest['project.name'].description,
27
- type: 'string',
28
- },
29
- 'region-id': {
30
- describe: `The region ID. Possible values: ${REGIONS.join(', ')}`,
31
- type: 'string',
32
- },
33
- psql: {
34
- type: 'boolean',
35
- describe: 'Connect to a new project via psql',
36
- default: false,
37
- },
38
- database: {
39
- describe: projectCreateRequest['project.branch.database_name'].description,
40
- type: 'string',
41
- },
42
- role: {
43
- describe: projectCreateRequest['project.branch.role_name'].description,
44
- type: 'string',
45
- },
46
- 'set-context': {
47
- type: 'boolean',
48
- describe: 'Set the current context to the new project',
49
- default: false,
50
- },
51
- }), async (args) => {
52
- await create(args);
53
- })
54
- .command('update <id>', 'Update a project', (yargs) => yargs.options({
55
- name: {
56
- describe: projectCreateRequest['project.name'].description,
57
- type: 'string',
58
- },
59
- 'ip-allow': {
60
- describe: projectUpdateRequest['project.settings.allowed_ips.ips']
61
- .description,
62
- type: 'string',
63
- array: true,
64
- deprecated: "Deprecated. Use 'ip-allow' command",
65
- },
66
- 'ip-primary-only': {
67
- describe: projectUpdateRequest['project.settings.allowed_ips.primary_branch_only'].description,
68
- type: 'boolean',
69
- deprecated: "Deprecated. Use 'ip-allow' command",
70
- },
71
- }), async (args) => {
72
- await update(args);
73
- })
74
- .command('delete <id>', 'Delete a project', (yargs) => yargs, async (args) => {
75
- await deleteProject(args);
76
- })
77
- .command('get <id>', 'Get a project', (yargs) => yargs, async (args) => {
78
- await get(args);
79
- });
80
- };
81
- export const handler = (args) => {
82
- return args;
83
- };
84
- const list = async (props) => {
85
- const result = [];
86
- let cursor;
87
- let end = false;
88
- while (!end) {
89
- const { data } = await props.apiClient.listProjects({
90
- limit: PROJECTS_LIST_LIMIT,
91
- cursor,
92
- });
93
- result.push(...data.projects);
94
- cursor = data.pagination?.cursor;
95
- log.debug('Got %d projects, with cursor: %s', data.projects.length, cursor);
96
- if (data.projects.length < PROJECTS_LIST_LIMIT) {
97
- end = true;
98
- }
99
- }
100
- writer(props).end(result, { fields: PROJECT_FIELDS });
101
- };
102
- const create = async (props) => {
103
- const project = {};
104
- if (props.name) {
105
- project.name = props.name;
106
- }
107
- if (props.regionId) {
108
- project.region_id = props.regionId;
109
- }
110
- project.branch = {};
111
- if (props.database) {
112
- project.branch.database_name = props.database;
113
- }
114
- if (props.role) {
115
- project.branch.role_name = props.role;
116
- }
117
- const { data } = await props.apiClient.createProject({
118
- project,
119
- });
120
- if (props.setContext) {
121
- updateContextFile(props.contextFile, {
122
- projectId: data.project.id,
123
- branchId: data.branch.id,
124
- });
125
- }
126
- const out = writer(props);
127
- out.write(data.project, { fields: PROJECT_FIELDS, title: 'Project' });
128
- out.write(data.connection_uris, {
129
- fields: ['connection_uri'],
130
- title: 'Connection URIs',
131
- });
132
- out.end();
133
- if (props.psql) {
134
- const connection_uri = data.connection_uris[0].connection_uri;
135
- const psqlArgs = props['--'];
136
- await psql(connection_uri, psqlArgs);
137
- }
138
- };
139
- const deleteProject = async (props) => {
140
- const { data } = await props.apiClient.deleteProject(props.id);
141
- writer(props).end(data.project, {
142
- fields: PROJECT_FIELDS,
143
- });
144
- };
145
- const update = async (props) => {
146
- const project = {};
147
- if (props.name) {
148
- project.name = props.name;
149
- }
150
- if (props.ipAllow || props.ipPrimaryOnly != undefined) {
151
- const { data } = await props.apiClient.getProject(props.id);
152
- const existingAllowedIps = data.project.settings?.allowed_ips;
153
- project.settings = {
154
- allowed_ips: {
155
- ips: props.ipAllow ?? existingAllowedIps?.ips ?? [],
156
- primary_branch_only: props.ipPrimaryOnly ??
157
- existingAllowedIps?.primary_branch_only ??
158
- false,
159
- },
160
- };
161
- }
162
- const { data } = await props.apiClient.updateProject(props.id, {
163
- project,
164
- });
165
- writer(props).end(data.project, { fields: PROJECT_FIELDS });
166
- };
167
- const get = async (props) => {
168
- const { data } = await props.apiClient.getProject(props.id);
169
- writer(props).end(data.project, { fields: PROJECT_FIELDS });
170
- };
@@ -1,132 +0,0 @@
1
- import { afterAll, describe, expect, test } from '@jest/globals';
2
- import { readFileSync, rmSync } from 'node:fs';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
- import { testCliCommand } from '../test_utils/test_cli_command.js';
6
- const CONTEXT_FILE = join(tmpdir(), `neon_project_create_ctx_${Date.now()}`);
7
- describe('projects', () => {
8
- testCliCommand({
9
- name: 'list',
10
- args: ['projects', 'list'],
11
- expected: {
12
- snapshot: true,
13
- },
14
- });
15
- testCliCommand({
16
- name: 'create',
17
- args: ['projects', 'create', '--name', 'test_project'],
18
- expected: {
19
- snapshot: true,
20
- },
21
- });
22
- testCliCommand({
23
- name: 'create with database and role',
24
- args: [
25
- 'projects',
26
- 'create',
27
- '--name',
28
- 'test_project',
29
- '--database',
30
- 'test_db',
31
- '--role',
32
- 'test_role',
33
- ],
34
- expected: {
35
- snapshot: true,
36
- },
37
- });
38
- testCliCommand({
39
- name: 'create and connect with psql',
40
- args: ['projects', 'create', '--name', 'test_project', '--psql'],
41
- expected: {
42
- snapshot: true,
43
- },
44
- });
45
- testCliCommand({
46
- name: 'create and connect with psql and psql args',
47
- args: [
48
- 'projects',
49
- 'create',
50
- '--name',
51
- 'test_project',
52
- '--psql',
53
- '--',
54
- '-c',
55
- 'SELECT 1',
56
- ],
57
- expected: {
58
- snapshot: true,
59
- },
60
- });
61
- testCliCommand({
62
- name: 'create project with setting the context',
63
- args: [
64
- 'projects',
65
- 'create',
66
- '--name',
67
- 'test_project',
68
- '--context-file',
69
- CONTEXT_FILE,
70
- '--set-context',
71
- ],
72
- expected: {
73
- snapshot: true,
74
- },
75
- });
76
- afterAll(() => {
77
- rmSync(CONTEXT_FILE);
78
- });
79
- test('context file should exist and contain the project id', () => {
80
- expect(readFileSync(CONTEXT_FILE, 'utf-8')).toContain('new-project-123456');
81
- });
82
- testCliCommand({
83
- name: 'delete',
84
- args: ['projects', 'delete', 'test'],
85
- expected: {
86
- snapshot: true,
87
- },
88
- });
89
- testCliCommand({
90
- name: 'update name',
91
- args: ['projects', 'update', 'test', '--name', 'test_project_new_name'],
92
- expected: {
93
- snapshot: true,
94
- },
95
- });
96
- testCliCommand({
97
- name: 'update ip allow',
98
- args: [
99
- 'projects',
100
- 'update',
101
- 'test',
102
- '--ip-allow',
103
- '127.0.0.1',
104
- '192.168.1.2/22',
105
- '--ip-primary-only',
106
- ],
107
- expected: {
108
- snapshot: true,
109
- },
110
- });
111
- testCliCommand({
112
- name: 'update ip allow primary only flag',
113
- args: ['projects', 'update', 'test', '--ip-primary-only', 'false'],
114
- expected: {
115
- snapshot: true,
116
- },
117
- });
118
- testCliCommand({
119
- name: 'update ip allow remove',
120
- args: ['projects', 'update', 'test', '--ip-allow'],
121
- expected: {
122
- snapshot: true,
123
- },
124
- });
125
- testCliCommand({
126
- name: 'get',
127
- args: ['projects', 'get', 'test'],
128
- expected: {
129
- snapshot: true,
130
- },
131
- });
132
- });
package/commands/roles.js DELETED
@@ -1,57 +0,0 @@
1
- import { retryOnLock } from '../api.js';
2
- import { branchIdFromProps, fillSingleProject } from '../utils/enrichers.js';
3
- import { writer } from '../writer.js';
4
- const ROLES_FIELDS = ['name', 'created_at'];
5
- export const command = 'roles';
6
- export const describe = 'Manage roles';
7
- export const aliases = ['role'];
8
- export const builder = (argv) => argv
9
- .usage('$0 roles <sub-command> [options]')
10
- .options({
11
- 'project-id': {
12
- describe: 'Project ID',
13
- type: 'string',
14
- },
15
- branch: {
16
- describe: 'Branch ID or name',
17
- type: 'string',
18
- },
19
- })
20
- .middleware(fillSingleProject)
21
- .command('list', 'List roles', (yargs) => yargs, async (args) => await list(args))
22
- .command('create', 'Create a role', (yargs) => yargs.options({
23
- name: {
24
- describe: 'Role name',
25
- type: 'string',
26
- demandOption: true,
27
- },
28
- }), async (args) => await create(args))
29
- .command('delete <role>', 'Delete a role', (yargs) => yargs, async (args) => await deleteRole(args));
30
- export const handler = (args) => {
31
- return args;
32
- };
33
- export const list = async (props) => {
34
- const branchId = await branchIdFromProps(props);
35
- const { data } = await props.apiClient.listProjectBranchRoles(props.projectId, branchId);
36
- writer(props).end(data.roles, {
37
- fields: ROLES_FIELDS,
38
- });
39
- };
40
- export const create = async (props) => {
41
- const branchId = await branchIdFromProps(props);
42
- const { data } = await retryOnLock(() => props.apiClient.createProjectBranchRole(props.projectId, branchId, {
43
- role: {
44
- name: props.name,
45
- },
46
- }));
47
- writer(props).end(data.role, {
48
- fields: ROLES_FIELDS,
49
- });
50
- };
51
- export const deleteRole = async (props) => {
52
- const branchId = await branchIdFromProps(props);
53
- const { data } = await retryOnLock(() => props.apiClient.deleteProjectBranchRole(props.projectId, branchId, props.role));
54
- writer(props).end(data.role, {
55
- fields: ROLES_FIELDS,
56
- });
57
- };
@@ -1,42 +0,0 @@
1
- import { describe } from '@jest/globals';
2
- import { testCliCommand } from '../test_utils/test_cli_command.js';
3
- describe('roles', () => {
4
- testCliCommand({
5
- name: 'list',
6
- args: ['roles', 'list', '--project-id', 'test', '--branch', 'test_branch'],
7
- expected: {
8
- snapshot: true,
9
- },
10
- });
11
- testCliCommand({
12
- name: 'create',
13
- args: [
14
- 'roles',
15
- 'create',
16
- '--project-id',
17
- 'test',
18
- '--branch',
19
- 'test_branch',
20
- '--name',
21
- 'test_role',
22
- ],
23
- expected: {
24
- snapshot: true,
25
- },
26
- });
27
- testCliCommand({
28
- name: 'delete',
29
- args: [
30
- 'roles',
31
- 'delete',
32
- 'test_role',
33
- '--project-id',
34
- 'test',
35
- '--branch',
36
- 'test_branch',
37
- ],
38
- expected: {
39
- snapshot: true,
40
- },
41
- });
42
- });
@@ -1,22 +0,0 @@
1
- import { updateContextFile } from '../context.js';
2
- import { branchIdFromProps } from '../utils/enrichers.js';
3
- export const command = 'set-context';
4
- export const describe = 'Set the current context';
5
- export const builder = (argv) => argv.usage('$0 set-context [options]').options({
6
- 'project-id': {
7
- describe: 'Project ID',
8
- type: 'string',
9
- },
10
- branch: {
11
- describe: 'Branch ID or name',
12
- type: 'string',
13
- },
14
- });
15
- export const handler = async (props) => {
16
- const branchId = await branchIdFromProps(props);
17
- const context = {
18
- projectId: props.projectId,
19
- branchId,
20
- };
21
- updateContextFile(props.contextFile, context);
22
- };
@@ -1,53 +0,0 @@
1
- import { tmpdir } from 'node:os';
2
- import { join } from 'node:path';
3
- import { rmSync, writeFileSync } from 'node:fs';
4
- import { afterAll, describe } from '@jest/globals';
5
- import { testCliCommand } from '../test_utils/test_cli_command';
6
- const CONTEXT_FILE = join(tmpdir(), `neon_${Date.now()}`);
7
- describe('set_context', () => {
8
- afterAll(() => {
9
- rmSync(CONTEXT_FILE);
10
- });
11
- describe('should set the context', () => {
12
- testCliCommand({
13
- name: 'set-context',
14
- args: [
15
- 'set-context',
16
- '--project-id',
17
- 'test',
18
- '--context-file',
19
- CONTEXT_FILE,
20
- ],
21
- });
22
- testCliCommand({
23
- name: 'list branches selecting project from the context',
24
- args: ['branches', 'list', '--context-file', CONTEXT_FILE],
25
- expected: {
26
- snapshot: true,
27
- },
28
- });
29
- const overrideContextFile = join(tmpdir(), `neon_override_ctx_${Date.now()}`);
30
- testCliCommand({
31
- name: 'get branch id overrides context set branch',
32
- before: async () => {
33
- writeFileSync(overrideContextFile, JSON.stringify({
34
- projectId: 'test',
35
- branchId: 'br-cloudy-branch-12345678',
36
- }));
37
- },
38
- after: async () => {
39
- rmSync(overrideContextFile);
40
- },
41
- args: [
42
- 'branches',
43
- 'get',
44
- 'br-sunny-branch-123456',
45
- '--context-file',
46
- overrideContextFile,
47
- ],
48
- expected: {
49
- snapshot: true,
50
- },
51
- });
52
- });
53
- });
package/commands/user.js DELETED
@@ -1,15 +0,0 @@
1
- import { writer } from '../writer.js';
2
- export const command = 'me';
3
- export const describe = 'Show current user';
4
- export const builder = (yargs) => yargs.option('context-file', {
5
- hidden: true,
6
- });
7
- export const handler = async (args) => {
8
- await me(args);
9
- };
10
- const me = async (props) => {
11
- const { data } = await props.apiClient.getCurrentUserInfo();
12
- writer(props).end(data, {
13
- fields: ['login', 'email', 'name', 'projects_limit'],
14
- });
15
- };
package/config.js DELETED
@@ -1,11 +0,0 @@
1
- import { join } from 'node:path';
2
- import { homedir } from 'node:os';
3
- import { existsSync, mkdirSync } from 'node:fs';
4
- import { isCi } from './env.js';
5
- export const CREDENTIALS_FILE = 'credentials.json';
6
- export const defaultDir = join(process.env.XDG_CONFIG_HOME || join(homedir(), '.config'), 'neonctl');
7
- export const ensureConfigDir = async ({ 'config-dir': configDir, 'force-auth': forceAuth, }) => {
8
- if (!existsSync(configDir) && (!isCi() || forceAuth)) {
9
- mkdirSync(configDir, { recursive: true });
10
- }
11
- };
package/context.js DELETED
@@ -1,48 +0,0 @@
1
- import { accessSync, readFileSync, writeFileSync } from 'node:fs';
2
- import { homedir } from 'node:os';
3
- import { normalize, resolve } from 'node:path';
4
- const CONTEXT_FILE = '.neon';
5
- const CHECK_FILES = [CONTEXT_FILE, 'package.json', '.git'];
6
- const wrapWithContextFile = (dir) => resolve(dir, CONTEXT_FILE);
7
- export const currentContextFile = () => {
8
- const cwd = process.cwd();
9
- let currentDir = cwd;
10
- const root = normalize('/');
11
- const home = homedir();
12
- while (currentDir !== root && currentDir !== home) {
13
- for (const file of CHECK_FILES) {
14
- try {
15
- accessSync(resolve(currentDir, file));
16
- return wrapWithContextFile(currentDir);
17
- }
18
- catch (e) {
19
- // ignore
20
- }
21
- }
22
- currentDir = resolve(currentDir, '..');
23
- }
24
- return wrapWithContextFile(cwd);
25
- };
26
- export const readContextFile = (file) => {
27
- try {
28
- return JSON.parse(readFileSync(file, 'utf-8'));
29
- }
30
- catch (e) {
31
- return {};
32
- }
33
- };
34
- export const enrichFromContext = (args) => {
35
- if (args._[0] === 'set-context') {
36
- return;
37
- }
38
- const context = readContextFile(args.contextFile);
39
- if (!args.branch && !args.id && !args.name) {
40
- args.branch = context.branchId;
41
- }
42
- if (!args.projectId) {
43
- args.projectId = context.projectId;
44
- }
45
- };
46
- export const updateContextFile = (file, context) => {
47
- writeFileSync(file, JSON.stringify(context, null, 2));
48
- };
package/env.js DELETED
@@ -1,6 +0,0 @@
1
- export const isCi = () => {
2
- return process.env.CI !== 'false' && Boolean(process.env.CI);
3
- };
4
- export const isDebug = () => {
5
- return Boolean(process.env.DEBUG);
6
- };
package/errors.js DELETED
@@ -1,16 +0,0 @@
1
- const ERROR_MATCHERS = [
2
- [/^Unknown command: (.*)$/, 'UNKNOWN_COMMAND'],
3
- [/^Missing required argument: (.*)$/, 'MISSING_ARGUMENT'],
4
- ];
5
- export const matchErrorCode = (message) => {
6
- if (!message) {
7
- return 'UNKNOWN_ERROR';
8
- }
9
- for (const [matcher, code] of ERROR_MATCHERS) {
10
- const match = message.match(matcher);
11
- if (match) {
12
- return code;
13
- }
14
- }
15
- return 'UNKNOWN_ERROR';
16
- };