neonctl 1.16.5 → 1.17.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.
package/README.md CHANGED
@@ -1,37 +1,15 @@
1
- Neon offers several methods for working with your projects. Utilizing the Neon Command Line Interface (CLI), you can operate Neon directly from a terminal or via automation. The Neon CLI facilitates numerous functions, such as Neon authentication, project creation and management, and more.
1
+ The Neon CLI supports numerous operations, such as authentication and management of Neon projects, branches, compute endpoints, databases, roles, and more.
2
2
 
3
- ## Synopsis
4
-
5
- The `neonctl` command can be called from command line. Without any arguments, it displays command usage and help:
6
-
7
- ```bash
8
- usage: neonctl <cmd> [args]
9
-
10
- Commands:
11
- neonctl auth Authenticate
12
- neonctl projects [command] Manage projects
13
- neonctl me Show current user
14
- neonctl branches Manage branches
15
-
16
- Options:
17
- --version Show version number [boolean]
18
- --help Show help [boolean]
19
- -o, --output Set output format
20
- [string] [choices: "json", "yaml", "table"] [default: "table"]
21
- --api-host The API host [default: "https://console.neon.tech/api/v2"]
22
- --config-dir Path to config directory
23
- [string] [default: "/home/eduard/.config/neonctl"]
24
- --oauth-host URL to Neon OAUTH host [default: "https://oauth2.neon.tech"]
25
- --client-id OAuth client id [string] [default: "neonctl"]
26
- --api-key API key [string] [default: ""]
27
- ```
3
+ The Neon CLI command name is `neonctl`. The GitHub repository for the Neon CLI is found [here](https://github.com/neondatabase/neonctl).
28
4
 
29
5
  ## Install the Neon CLI
30
6
 
31
- This topic describes how to install the `neonctl` command-line interface tool and connect to Neon.
7
+ This section describes how to install the Neon CLI.
32
8
 
33
9
  ### Prerequisites
34
10
 
11
+ Before installing, ensure that you have met the following prerequisites:
12
+
35
13
  - Node.js 16.0 or higher. To check if you already have Node.js, run the following command:
36
14
 
37
15
  ```shell
@@ -44,83 +22,114 @@ This topic describes how to install the `neonctl` command-line interface tool an
44
22
  npm -v
45
23
  ```
46
24
 
47
- If you need to install either `Node.js` or `npm`, refer to instructions on [official nodejs page](https://nodejs.org) or you can use [Node version manager](https://github.com/nvm-sh/nvm).
25
+ If you need to install `Node.js` or `npm`, refer to instructions on the [official nodejs page](https://nodejs.org) or use the [Node version manager](https://github.com/nvm-sh/nvm).
48
26
 
49
27
  ### Install
50
28
 
51
- To download and install Neon CLI, run the following command:
29
+ To install the Neon CLI, run the following command:
52
30
 
53
31
  ```shell
54
32
  npm i -g neonctl
55
33
  ```
56
34
 
57
- ### Connect
35
+ ### Upgrade
58
36
 
59
- To authenticate to Neon, run the following command:
37
+ To upgrade to the latest version of the Neon CLI, run the `npm i -g neonctl` command again.
60
38
 
61
- ```shell
39
+ ## Connect
40
+
41
+ Run the following command to authenticate a connection to Neon:
42
+
43
+ ```bash
62
44
  neonctl auth
63
45
  ```
64
46
 
65
- The command launches a browser window where you can authorize the Neon CLI to access your Neon account. After granting permission, your credentials are saved locally to a credentials file.
47
+ The `auth` command launches a browser window where you can authorize the Neon CLI to access your Neon account. Running a Neon CLI command without authenticating with [neonctl auth](https://neon.tech/docs/reference/cli-auth) automatically launches the browser authentication process.
66
48
 
67
- ## Commands
49
+ Alternatively, you can authenticate a connection with a Neon API key using the `--api-key` option when running a Neon CLI command. For example, an API key is used with the following `neonctl projects list` command:
68
50
 
69
- ### neonctl auth
51
+ ```bash
52
+ neonctl projects list --api-key <neon_api_key>
53
+ ```
70
54
 
71
- Authenticates the user or caller to Neon. See [Connect](#connect).
55
+ For information about obtaining an Neon API key, see [Authentication](https://api-docs.neon.tech/reference/authentication), in the _Neon API Reference_.
72
56
 
73
- ### neonctl me
57
+ ## Configure autocompletion
74
58
 
75
- Returns information about the authenticated user.
59
+ The Neon CLI supports autocompletion, which you can configure in a few easy steps. See [Neon CLI commands — completion](https://neon.tech/docs/reference/cli-completion) for instructions.
76
60
 
77
- ```bash
78
- $> neonctl me
79
- ┌────────────────┬──────────────────────────┬────────────┬────────────────┐
80
- │ Login │ Email │ Name │ Projects Limit │
81
- ├────────────────┼──────────────────────────┼────────────┼────────────────┤
82
- user1 │ user1@example.com │ User1 │ 1 │
83
- └────────────────┴──────────────────────────┴────────────┴────────────────┘
84
- ```
61
+ ## Commands
62
+
63
+ | Command | Subcommands | Description |
64
+ |---------------------------------------------------------|----------------------------------------|---------------------------|
65
+ | [auth](https://neon.tech/docs/reference/cli-auth) | | Authenticate |
66
+ | [projects](https://neon.tech/docs/reference/cli-projects) | `list`, `create`, `update`, `delete`, `get` | Manage projects |
67
+ | [me](../reference/cli-me) | | Show current user |
68
+ | [branches](https://neon.tech/docs/reference/cli-branches) | `list`, `create`, `rename`, `add-compute`, `set-primary`, `delete`, `get` | Manage branches |
69
+ | [databases](https://neon.tech/docs/reference/cli-databases) | `list`, `create`, `delete` | Manage databases |
70
+ | [roles](https://neon.tech/docs/reference/cli-roles) | `list`, `create`, `delete` | Manage roles |
71
+ | [operations](https://neon.tech/reference/cli-operations) | `list` | Manage operations |
72
+ | [connection-string](https://neon.tech/reference/cli-connection-string) | | Get connection string |
73
+ | [completion](https://neon.tech/reference/cli-completion) | | Generate a completion script |
74
+
75
+ ## Global options
85
76
 
77
+ Global options are supported with any Neon CLI command.
86
78
 
87
- ### neonctl projects
79
+ | Option | Description | Type | Default |
80
+ | :--------- | :---------------------------------- | :----- | :-------------------------------- |
81
+ | [-o, --output](#output)| Set the Neon CLI output format (`json`, `yaml`, or `table`) | string | table |
82
+ | [--config-dir](#config-dir)| Path to the Neon CLI configuration directory | string | `/home/<user>/.config/neonctl` |
83
+ | [--api-key](#api-key) | Neon API key | string | "" |
84
+ | [--analytics](#analytics) | Manage analytics | boolean| true |
85
+ | [-v, --version](#version) | Show the Neon CLI version number | boolean| - |
86
+ | [-h, --help](#help) | Show the Neon CLI help | boolean| - |
88
87
 
89
- For creating and managing Neon projects.
88
+ - <a id="output"></a>`-o, --output`
90
89
 
91
- ## neonctl branches
92
- For creating and managing Neon branches.
90
+ Sets the output format. Supported options are `json`, `yaml`, and `table`. The default is `table`. Table output may be limited. The `json` and `yaml` output formats show all data.
93
91
 
94
- ## Options
92
+ ```bash
93
+ neonctl me --output json
94
+ ```
95
95
 
96
- ### version
96
+ - <a id="config-dir"></a>`--config-dir`
97
97
 
98
- Shows the neonctl version number
98
+ Specifies the path to the `neonctl` configuration directory. To view the default configuration directory containing you `credentials.json` file, run `neonctl --help`. The credentials file is created when you authenticate using the `neonctl auth` command. This option is only necessary if you move your `neonctl` configuration file to a location other than the default.
99
99
 
100
- ### help
100
+ ```bash
101
+ neonctl projects list --config-dir /home/dtprice/.config/neonctl
102
+ ```
101
103
 
102
- Shows the neonctl command-line help
104
+ - <a id="api-key"></a>`--api-key`
103
105
 
104
- ### output, o
106
+ Specifies your Neon API key. You can authenticate using a Neon API key when running a Neon CLI command instead of using `neonctl auth`. For information about obtaining an Neon API key, see [Authentication](https://api-docs.neon.tech/reference/authentication), in the _Neon API Reference_.
105
107
 
106
- Sets the output format.
108
+ ```bash
109
+ neonctl <command> --api-key <neon_api_key>
110
+ ```
107
111
 
108
- ### api-host
112
+ - <a id="analytics"></a>`--analytics`
109
113
 
110
- Shows the API host
114
+ Analytics are enabled by default to gather information about the CLI commands and options that are used by our customers. This data collection assists in offering support, and allows for a better understanding of typical usage patterns so that we can improve user experience. Neon does not collect user-defined data, such as project IDs or command payloads. To opt-out of analytics data collection, specify `--no-analytics` or `--analytics false`.
111
115
 
112
- ### config-dir
116
+ - <a id="version"></a>`-v, --version`
113
117
 
114
- Sets the path to the `neonctl` configuration directory
118
+ Shows the Neon CLI version number.
115
119
 
116
- ### oauth-host
120
+ ```bash
121
+ $ neonctl --version
122
+ 1.15.0
123
+ ```
117
124
 
118
- Sets the URL of Neon OAuth host
125
+ - <a id="help"></a>`-h, --help`
119
126
 
120
- ### client-id
127
+ Shows the `neonctl` command-line help. You can view help for `neonctl`, a `neonctl` command, or a `neonctl` subcommand, as shown in the following examples:
121
128
 
122
- Sets the OAuth client id
129
+ ```bash
130
+ neonctl --help
123
131
 
124
- ### api-key
132
+ neonctl branches --help
125
133
 
126
- Sets the API key
134
+ neonctl branches create --help
135
+ ```
@@ -33,19 +33,29 @@ export const builder = (argv) => argv
33
33
  describe: 'Parent branch name or id or timestamp or LSN. Defaults to the primary branch',
34
34
  type: 'string',
35
35
  },
36
- endpoint: {
37
- describe: 'Create a branch with or without an endpoint. By default branch is created with a read-write endpoint. To create a branch without endpoint use --no-endpoint',
36
+ compute: {
37
+ describe: 'Create a branch with or without a compute. By default branch is created with a read-write compute. To create a branch without compute use --no-compute',
38
38
  type: 'boolean',
39
39
  default: true,
40
40
  },
41
- readonly: {
42
- describe: 'Create a read-only branch',
43
- type: 'boolean',
44
- implies: 'endpoint',
41
+ type: {
42
+ describe: 'Type of compute to add',
43
+ type: 'string',
44
+ implies: 'compute',
45
+ default: EndpointType.ReadWrite,
46
+ choices: Object.values(EndpointType),
45
47
  },
46
48
  }), async (args) => await create(args))
47
49
  .command('rename <id|name> <new-name>', 'Rename a branch', (yargs) => yargs, async (args) => await rename(args))
48
50
  .command('set-primary <id|name>', 'Set a branch as primary', (yargs) => yargs, async (args) => await setPrimary(args))
51
+ .command('add-compute <id|name>', 'Add a compute to a branch', (yargs) => yargs.options({
52
+ type: {
53
+ type: 'string',
54
+ choices: Object.values(EndpointType),
55
+ describe: 'Type of compute to add',
56
+ default: EndpointType.ReadOnly,
57
+ },
58
+ }), async (args) => await addCompute(args))
49
59
  .command('delete <id|name>', 'Delete a branch', (yargs) => yargs, async (args) => await deleteBranch(args))
50
60
  .command('get <id|name>', 'Get a branch', (yargs) => yargs, async (args) => await get(args));
51
61
  export const handler = (args) => {
@@ -94,12 +104,10 @@ const create = async (props) => {
94
104
  name: props.name,
95
105
  ...parentProps,
96
106
  },
97
- endpoints: props.endpoint
107
+ endpoints: props.compute
98
108
  ? [
99
109
  {
100
- type: props.readonly
101
- ? EndpointType.ReadOnly
102
- : EndpointType.ReadWrite,
110
+ type: props.type,
103
111
  },
104
112
  ]
105
113
  : [],
@@ -155,3 +163,15 @@ const get = async (props) => {
155
163
  fields: BRANCH_FIELDS,
156
164
  });
157
165
  };
166
+ const addCompute = async (props) => {
167
+ const branchId = await branchIdFromProps(props);
168
+ const { data } = await retryOnLock(() => props.apiClient.createProjectEndpoint(props.projectId, {
169
+ endpoint: {
170
+ branch_id: branchId,
171
+ type: props.type,
172
+ },
173
+ }));
174
+ writer(props).end(data.endpoint, {
175
+ fields: ['id', 'host'],
176
+ });
177
+ };
@@ -31,7 +31,8 @@ describe('branches', () => {
31
31
  'test',
32
32
  '--name',
33
33
  'test_branch',
34
- '--readonly',
34
+ '--type',
35
+ 'read_only',
35
36
  ],
36
37
  expected: {
37
38
  snapshot: true,
@@ -46,7 +47,7 @@ describe('branches', () => {
46
47
  'test',
47
48
  '--name',
48
49
  'test_branch',
49
- '--no-endpoint',
50
+ '--no-compute',
50
51
  ],
51
52
  expected: {
52
53
  snapshot: true,
@@ -154,4 +155,11 @@ describe('branches', () => {
154
155
  snapshot: true,
155
156
  },
156
157
  });
158
+ testCliCommand({
159
+ name: 'add compute',
160
+ args: ['branches', 'add-compute', 'test_branch', '--project-id', 'test'],
161
+ expected: {
162
+ snapshot: true,
163
+ },
164
+ });
157
165
  });
@@ -63,7 +63,7 @@ export const handler = async (props) => {
63
63
  if (data.roles.length === 1) {
64
64
  return data.roles[0].name;
65
65
  }
66
- throw new Error(`Multiple roles found for the branch, please provide one with the --role.name option: ${data.roles
66
+ throw new Error(`Multiple roles found for the branch, please provide one with the --role-name option: ${data.roles
67
67
  .map((r) => r.name)
68
68
  .join(', ')}`);
69
69
  }));
@@ -77,7 +77,7 @@ export const handler = async (props) => {
77
77
  if (data.databases.length === 1) {
78
78
  return data.databases[0].name;
79
79
  }
80
- throw new Error(`Multiple databases found for the branch, please provide one with the --database.name option: ${data.databases
80
+ throw new Error(`Multiple databases found for the branch, please provide one with the --database-name option: ${data.databases
81
81
  .map((d) => d.name)
82
82
  .join(', ')}`);
83
83
  }));
package/config.js CHANGED
@@ -2,9 +2,9 @@ import { join } from 'node:path';
2
2
  import { homedir } from 'node:os';
3
3
  import { existsSync, mkdirSync } from 'node:fs';
4
4
  import { isCi } from './env.js';
5
- export const defaultDir = join(homedir(), process.env.XDG_CONFIG_HOME || '.config', 'neonctl');
5
+ export const defaultDir = join(process.env.XDG_CONFIG_HOME || join(homedir(), '.config'), 'neonctl');
6
6
  export const ensureConfigDir = async ({ 'config-dir': configDir, }) => {
7
7
  if (!existsSync(configDir) && !isCi()) {
8
- mkdirSync(configDir);
8
+ mkdirSync(configDir, { recursive: true });
9
9
  }
10
10
  };
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "url": "git@github.com:neondatabase/neonctl.git"
6
6
  },
7
7
  "type": "module",
8
- "version": "1.16.5",
8
+ "version": "1.17.1",
9
9
  "description": "CLI tool for NeonDB Cloud management",
10
10
  "main": "index.js",
11
11
  "author": "NeonDB",
package/writer.js CHANGED
@@ -48,17 +48,18 @@ export const writer = (props) => {
48
48
  }
49
49
  chunks.forEach(({ data, config }) => {
50
50
  const arrayData = Array.isArray(data) ? data : [data];
51
+ const fields = config.fields.filter((field) => arrayData.some((item) => item[field] !== undefined && item[field] !== ''));
51
52
  const table = new Table({
52
53
  style: {
53
54
  head: ['green'],
54
55
  },
55
- head: config.fields.map((field) => field
56
+ head: fields.map((field) => field
56
57
  .split('_')
57
58
  .map((word) => word[0].toUpperCase() + word.slice(1))
58
59
  .join(' ')),
59
60
  });
60
61
  arrayData.forEach((item) => {
61
- table.push(config.fields.map((field) => item[field] ?? ''));
62
+ table.push(fields.map((field) => item[field]));
62
63
  });
63
64
  if (config.title) {
64
65
  out.write((isCi() ? config.title : chalk.bold(config.title)) + '\n');