You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: Update to reflect the current state of the project (#347)
Updates the developer docs with current information about the state
of the project.
Some of the information removed from the STYLEGUIDE.md will be moved
to cloud-sdk-go where it is relevant.
Copy file name to clipboardExpand all lines: developer_docs/NEW_COMMAND.md
+33-55Lines changed: 33 additions & 55 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,67 +10,53 @@ into the `app` package for business logic and returns results.
10
10
11
11
[`cmd/root.go`](../cmd/root.go) contains the root command (`ecctl`) and global flags.
12
12
[`cmd/commands.go`](../cmd/commands.go) attaches the top level commands (`deployment`, `platform`, etc) to the root command.
13
-
The subdirectories define the subcommand structure (e.g. `platform` -> `proxy`). The lowest level`command.go`
14
-
(e.g. [`cmd/platform/proxy/command.go`](../cmd/platform/proxy/command.go)) contains the definition of the actual command
15
-
(e.g. `platform proxy list`).
13
+
The subdirectories define the subcommand structure (e.g. `deployment` -> `list`). The lowest level
14
+
(e.g. [`cmd/deployment/list.go`](../cmd/deployment/list.go)) contains the definition of the actual command
15
+
(e.g. `deployment list`).
16
16
17
-
### Example: adding a new command to list proxies
17
+
### Example: adding a new command to list deployments
18
18
19
-
Create a new subdirectory `cmd/platform/proxy`, and add a `command.go` file to it. (Some of these files/directories
20
-
might already exist, e.g. if you are adding a new operation for an existing entity.) You will define your new command here.
19
+
Create a new subdirectory `cmd/deployment`, and add a `list.go` file to it. Some of these files/directories
20
+
might already exist (i.e. if you are adding a new operation for an existing entity). You will define your new command here.
21
21
22
-
First, you need to define the `proxy` command:
22
+
Define the `list` subcommand in `cmd/deployment/list.go`:
23
23
24
24
```go
25
-
varCommand = &cobra.Command{
26
-
Use: "proxy",
27
-
// ...
28
-
}
29
-
```
30
-
31
-
Next, define the `list` subcommand:
32
-
33
-
```go
34
-
varlistProxiesCmd = &cobra.Command{
25
+
varlistCmd = &cobra.Command{
35
26
Use: "list",
36
27
// ...
37
28
}
38
29
```
39
30
40
31
There are a few things to note about the `list` command:
41
32
42
-
- The `list` command will contain a call to the `proxy.List()`method from the `pkg/platform/proxy` package which you have
43
-
not defined yet. You will define this method later. You will also need to define the parameters struct used to pass
44
-
arguments to this method - e.g. `proxy.ListParams`.
45
-
- Ideally, you would implement a custom text formatter to present the proxy list in a user-friendly way. We currently
33
+
- The `list` command will contain a call to the `deploymentapi.List()`function from the [`/pkg/api/deploymentapi`](https://github.com/elastic/cloud-sdk-go/tree/master/pkg/api/deploymentapi)
34
+
package found in the cloud-sdk-go. You will define this function later. You will also need to define the parameters
35
+
struct used to pass arguments to this function - e.g. `deploymentapi.ListParams`.
36
+
- Ideally, you would implement a custom text formatter to present the deployment list in a user-friendly way. We currently
46
37
support two types of output: json and text. Absent a custom formatter, the output defaults to *json*. If you choose to add
47
38
a formatter to support *text* output, you'll need to create a template such as
48
-
[`pkg/formatter/templates/text/proxy/list.gotmpl`](../pkg/formatter/templates/text/proxy/list.gotmpl). To ensure this template
49
-
gets used, invoke a `ecctl.Get().Formatter.Format()` from the [`listProxiesCmd`](https://github.com/elastic/ecctl/blob/a90daa0c4411905c8d5c3fa06f5b6250395c4730/cmd/platform/proxy/command.go#L60).
39
+
[`pkg/formatter/templates/text/deployment/list.gotmpl`](../pkg/formatter/templates/text/deployment/list.gotmpl). To ensure this template
40
+
gets used, invoke a `ecctl.Get().Formatter.Format()` from the [`listCmd`](https://github.com/elastic/ecctl/blob/master/cmd/deployment/list.go#L39).
50
41
51
-
Next, the `init()` function attaches the `list` subcommand to the `proxy` command, and adds any custom
42
+
Next, the `init()` function attaches the `list` subcommand to the `deployment` command, and adds any custom
52
43
command line parameters.
53
44
54
45
```go
55
46
funcinit() {
56
-
Command.AddCommand(listProxiesCmd)
47
+
Command.AddCommand(listCmd)
57
48
// ...
58
49
}
59
50
60
51
```
61
52
62
-
Finally, you need to attach the `proxy` subcommand to the `platform` command, by adding a reference to it
63
-
in [`cmd/platform/platform.go`](../cmd/platform/platform.go).
53
+
Finally, you need to attach the `deployment` subcommand to the `ecctl` command, by adding a reference to it
54
+
in [`cmd/commands.go`](../cmd/commands.go).
64
55
65
56
## The `pkg` package
66
57
67
58
The [`pkg`](../pkg) package is used by the `cmd` package to create commands and is library code that's ok to use by external applications.
68
59
69
-
### [`deployment`](../pkg/deployment)
70
-
71
-
Business logic behind `deployment` commands. Typically, methods in this package are called from the `cmd` package,
72
-
they accept parameters and call into the ES Cloud API, process and return results to the commands.
73
-
74
60
### [`ecctl`](../pkg/ecctl)
75
61
76
62
Contains the business logic and configuration for the ecctl app.
@@ -79,39 +65,32 @@ Contains the business logic and configuration for the ecctl app.
79
65
80
66
Functions and templates to format command output from json into user friendly text.
81
67
82
-
### [`platform`](../pkg/platform)
83
-
84
-
Business logic behind `platform` commands. Typically, methods in this package are called from the `cmd` package,
85
-
they accept parameters and call into the ES Cloud API, process and return results to the commands.
86
-
87
68
### [`util`](../pkg/util)
88
69
89
70
Common resources, such as utility functions, constants, parameters, that are shared among different packages.
90
71
91
-
### Example: adding a new command to list proxies (application logic)
72
+
### Example: adding a new command to list deployments (application logic)
92
73
93
-
Next, you need to add the business logic to your `platform proxy list` command. That's the `List()`
94
-
method mentioned earlier. It should go into the `pkg/platform/proxy/proxy.go` file (that you'll need create if it does
95
-
not already exist):
74
+
Next, you need to add the business logic to your `ecctl deployment list` command. That's the `List()`
75
+
function mentioned earlier. These APIs can be found in [cloud-sdk-go](https://github.com/elastic/cloud-sdk-go/tree/master/pkg/api).
76
+
The API for our list command should go in the [`cloud-sdk-go/pkg/api/deploymentapi/list.go`](https://github.com/elastic/cloud-sdk-go/tree/master/pkg/api/deploymentapi/list.go) file
77
+
which you'll need create if it does not already exist:
- This is where the main business logic happens: it should include a call to the cloud API to retrieve all the
106
-
proxies and return them to the calling function.
107
-
- Make sure to properly catch and handle all possible errors. Consider using the `multierror`
108
-
library if that makes sense. In this simple case, where we only have one API call, and not much else in terms of processing,
109
-
it's probably fine to use regular `errors`.
110
-
- For a general set of guidelines on how to write good Go code, see our [Style Guide](https://github.com/elastic/ecctl/blob/master/developer_docs/STYLEGUIDE.md).
87
+
- This is where the main business logic happens: it should include a call to the Elastic Cloud API to retrieve all the
88
+
deployments and return them to the calling function.
89
+
- Make sure to properly catch and handle all possible validation errors. Use the [`multierror`](https://github.com/elastic/cloud-sdk-go/blob/master/pkg/api/deploymentapi/get.go#L46-L57)
90
+
package even if you're returning a single error. This provides consistency and good UX since the errors will be be properly prefixed.
91
+
- For a general set of guidelines on the project's code style, see our [Style Guide](https://github.com/elastic/ecctl/blob/master/developer_docs/STYLEGUIDE.md).
111
92
112
-
You'll also need to define the `ListParams` struct, as we normally use structs to pass several arguments to functions. If you only have one or two
113
-
functions and corresponding parameter structs, it's ok to define the parameters structs in the same file. If it starts growing beyond that,
114
-
a good practice is to define parameter structs in their own file - in this case it would be `pkg/platform/proxy/proxy_params.go`.
93
+
You'll also need to define the `ListParams` struct, as we normally use structs to pass several arguments to API functions.
The above line would return an error only if the flag is not defined, or the datatype does not match the flag declaration data type.
46
+
The above line would return an error only if the flag is not defined, or the data type does not match the flag declaration data type.
47
47
Adding many `if err` checks will make the code a little bit noisy so we can ignore the errors in these cases.
48
48
49
-
### API Errors
50
-
51
-
API errors should always be encapsulated with `apierr.Unwrap()`, this function tries to break down and inspect the encapsulated and multi-layer wraps that the API errors contain.
52
-
53
49
### Multiple errors
54
50
55
51
When multiple errors can be returned, it is preferable to use the `mutlierror.Prefixed` type to return all the possible errors with a prefixed string to include some context.
A package per context, a context applies to any of the high level containers like `platform`, `deployment`, etc. When a context becomes too large to be contained in a package we can start breaking it down into sub-packages.
88
+
### Command Structure
95
89
96
-
An example would be [pkg/deployment/elasticsearch/plan](../pkg/deployment/elasticsearch/plan).
90
+
Commands are defined following the structure of the Elastic Cloud API. If a request to the API is `GET /api/v1/deployments/{deployment_id}`, the corresponding command will be `ecctl deployment show <deployment_id>`.
97
91
98
92
### Util packages
99
93
100
-
When a function can be made generic it should go in one of the utils packages (e.g. [pkg/util](../pkg/util), [pkg/util](../pkg/util)) to remove complexity and give the ability to be reused.
94
+
When a function can be made generic it should go in one of the utils packages (e.g. [cmd/util](../cmd/util), [pkg/util](../pkg/util)) to remove complexity and give the ability to be reused.
101
95
102
96
If the function is not specific to `ecctl`, it should be part of [cloud-sdk-go](https://github.com/elastic/cloud-sdk-go) or a standalone repository if the functionality is big enough.
103
97
@@ -107,40 +101,11 @@ If the function is not specific to `ecctl`, it should be part of [cloud-sdk-go](
107
101
108
102
All files containing functions or methods must have a corresponding unit test file, and we aim to have 100% coverage.
109
103
110
-
#### API Mocks
104
+
#### Testing commands
111
105
112
-
When unit testing functions which will call the external API, please use the provided `api.NewMock` in conjunction with `mock.Response`.
106
+
When writing unit tests for commands, we use the `testutils.RunCmdAssertion()` function which tests a `*cobra.Command` and uses the testing.T struct to return any unmatched assertions..
113
107
114
-
yes! :smile:
115
-
116
-
```go
117
-
import (
118
-
"net/http"
119
-
120
-
"github.com/elastic/cloud-sdk-go/pkg/api"
121
-
"github.com/elastic/cloud-sdk-go/pkg/api/mock"
122
-
)
123
-
124
-
//Test case
125
-
{
126
-
name: "succeeds",
127
-
args: args{params{
128
-
API: api.NewMock(mock.Response{
129
-
Response: http.Response{
130
-
Body: mock.NewStringBody(`{}`),
131
-
StatusCode: 200,
132
-
},
133
-
}),
134
-
}},
135
-
},
136
-
// More tests ...
137
-
```
138
-
139
-
### Testing commands
140
-
141
-
When writing unit tests for commands, we only look to assert that the command is constructing the correct API call. API responses are mocked and tested only in the `pkg/` directory.
142
-
143
-
See [TestRunShowKibanaClusterCmd()](./cmd/kibana/show_test.go) as a good example to base your tests on.
108
+
See [Test_listCmd()](../cmd/deployment/template/list_test.go) as a good example to base your tests on.
144
109
145
110
## General Style
146
111
@@ -179,33 +144,13 @@ Names should be descriptive and we should avoid redundancy.
179
144
yes! :smile:
180
145
181
146
```go
182
-
kibana.Create()
183
-
```
184
-
185
-
preferably not :confused:
186
-
187
-
```go
188
-
kibana.CreateKibanaDeployment()
189
-
```
190
-
191
-
When using method chaining make sure to put each method in it's own line to improve readability.
When possible we try to avoid `else` and nested `if`s. This makes our code more readable and removes complexity.
@@ -241,7 +186,7 @@ if params.Hide {
241
186
242
187
We use `make docs` to automatically generate documentation for our commands which live in the `cmd` folder.
243
188
244
-
It is important when writing the descriptions to our commands or flags, that we use simple language and are as clear as possible to provide good UX. If you need to explain more about the command or give examples, please do so using the `Example` field, a good example is the [deployment elasticsearch list](cmd/deployment/elasticsearch/list.go) command.
189
+
It is important when writing the descriptions to our commands or flags, that we use simple language and are as clear as possible to provide good UX. If you need to explain more about the command or give examples, please do so using the `Example` field, a good example is the [deployment list](../cmd/deployment/create.go) command.
245
190
246
191
The package wide description and documentation is provided in a godoc `doc.go` file. Aside form packages with a very small context, all packages should have this file.
0 commit comments