blob: becaf44db424e9fa5ac0eb3b58996b8c2827a667 [file] [log] [blame] [view]
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +02001# Contributing to gophercloud
2
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +02003- [Getting started](#getting-started)
4- [Tests](#tests)
5- [Style guide](#basic-style-guide)
Jamie Hannaford54bbe992014-10-07 16:50:32 +02006- [5 ways to get involved](#5-ways-to-get-involved)
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +02007
Jamie Hannafordd2773f22014-10-07 16:06:23 +02008## Setting up your git workspace
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +02009
Jamie Hannafordd2773f22014-10-07 16:06:23 +020010As a contributor you will need to setup your workspace in a slightly different
11way than just downloading it. Here are the basic installation instructions:
12
Jamie Hannafordbc35d052014-10-07 16:27:30 +0200131. Configure your `$GOPATH` and run `go get` as described in the main
Jamie Hannaforda8004de2014-11-13 12:55:14 +010014[README](/README.md#how-to-install).
Jamie Hannafordd2773f22014-10-07 16:06:23 +020015
162. Move into the directory that houses your local repository:
17
Jamie Hannaford54bbe992014-10-07 16:50:32 +020018 ```bash
jrperritt55fb5842016-04-13 14:16:08 -050019 cd ${GOPATH}/src/github.com/gophercloud/gophercloud
Jamie Hannaford54bbe992014-10-07 16:50:32 +020020 ```
Jamie Hannafordd2773f22014-10-07 16:06:23 +020021
jrperritt55fb5842016-04-13 14:16:08 -0500223. Fork the `gophercloud/gophercloud` repository and update your remote refs. You
Jamie Hannafordd2773f22014-10-07 16:06:23 +020023will need to rename the `origin` remote branch to `upstream`, and add your
24fork as `origin` instead:
25
Jamie Hannaford54bbe992014-10-07 16:50:32 +020026 ```bash
27 git remote rename origin upstream
28 git remote add origin git@github.com/<my_username>/gophercloud
29 ```
Jamie Hannafordd2773f22014-10-07 16:06:23 +020030
jrperritt1d8b6f12015-08-14 12:17:09 -0600314. Checkout the latest development branch:
Jamie Hannafordd2773f22014-10-07 16:06:23 +020032
Jamie Hannaford54bbe992014-10-07 16:50:32 +020033 ```bash
jrperritt1d8b6f12015-08-14 12:17:09 -060034 git checkout master
Jamie Hannaford54bbe992014-10-07 16:50:32 +020035 ```
Jamie Hannafordd2773f22014-10-07 16:06:23 +020036
375. If you're working on something (discussed more in detail below), you will
38need to checkout a new feature branch:
39
Jamie Hannaford54bbe992014-10-07 16:50:32 +020040 ```bash
41 git checkout -b my-new-feature
42 ```
Jamie Hannafordd2773f22014-10-07 16:06:23 +020043
44Another thing to bear in mind is that you will need to add a few extra
45environment variables for acceptance tests - this is documented in our
46[acceptance tests readme](/acceptance).
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020047
48## Tests
49
50When working on a new or existing feature, testing will be the backbone of your
51work since it helps uncover and prevent regressions in the codebase. There are
jrperritt55fb5842016-04-13 14:16:08 -050052two types of test we use in Gophercloud: unit tests and acceptance tests, which
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020053are both described below.
54
55### Unit tests
56
jrperritt55fb5842016-04-13 14:16:08 -050057Unit tests are the fine-grained tests that establish and ensure the behavior
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020058of individual units of functionality. We usually test on an
59operation-by-operation basis (an operation typically being an API action) with
60the use of mocking to set up explicit expectations. Each operation will set up
61its HTTP response expectation, and then test how the system responds when fed
62this controlled, pre-determined input.
63
64To make life easier, we've introduced a bunch of test helpers to simplify the
65process of testing expectations with assertions:
66
67```go
68import (
69 "testing"
70
jrperritt55fb5842016-04-13 14:16:08 -050071 "github.com/gophercloud/gophercloud/testhelper"
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020072)
73
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020074func TestSomething(t *testing.T) {
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020075 result, err := Operation()
76
77 testhelper.AssertEquals(t, "foo", result.Bar)
78 testhelper.AssertNoErr(t, err)
79}
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +020080
81func TestSomethingElse(t *testing.T) {
82 testhelper.CheckEquals(t, "expected", "actual")
83}
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020084```
85
86`AssertEquals` and `AssertNoErr` will throw a fatal error if a value does not
87match an expected value or if an error has been declared, respectively. You can
88also use `CheckEquals` and `CheckNoErr` for the same purpose; the only difference
89being that `t.Errorf` is raised rather than `t.Fatalf`.
90
91Here is a truncated example of mocked HTTP responses:
92
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +020093```go
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020094import (
95 "testing"
96
jrperritt55fb5842016-04-13 14:16:08 -050097 th "github.com/gophercloud/gophercloud/testhelper"
98 fake "github.com/gophercloud/gophercloud/testhelper/client"
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020099)
100
101func TestGet(t *testing.T) {
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200102 // Setup the HTTP request multiplexer and server
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200103 th.SetupHTTP()
104 defer th.TeardownHTTP()
105
106 th.Mux.HandleFunc("/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
107 // Test we're using the correct HTTP method
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200108 th.TestMethod(t, r, "GET")
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200109
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200110 // Test we're setting the auth token
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200111 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
112
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200113 // Set the appropriate headers for our mocked response
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200114 w.Header().Add("Content-Type", "application/json")
115 w.WriteHeader(http.StatusOK)
116
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200117 // Set the HTTP body
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200118 fmt.Fprintf(w, `
119{
120 "network": {
121 "status": "ACTIVE",
122 "name": "private-network",
123 "admin_state_up": true,
124 "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
125 "shared": true,
126 "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22"
127 }
128}
129 `)
130 })
131
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200132 // Call our API operation
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200133 network, err := Get(fake.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract()
134
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200135 // Assert no errors and equality
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200136 th.AssertNoErr(t, err)
137 th.AssertEquals(t, n.Status, "ACTIVE")
138}
139```
140
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200141### Acceptance tests
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200142
143As we've already mentioned, unit tests have a very narrow and confined focus -
jrperritt55fb5842016-04-13 14:16:08 -0500144they test small units of behavior. Acceptance tests on the other hand have a
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200145far larger scope: they are fully functional tests that test the entire API of a
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200146service in one fell swoop. They don't care about unit isolation or mocking
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200147expectations, they instead do a full run-through and consequently test how the
148entire system _integrates_ together. When an API satisfies expectations, it
149proves by default that the requirements for a contract have been met.
150
Jamie Hannafordd2773f22014-10-07 16:06:23 +0200151Please be aware that acceptance tests will hit a live API - and may incur
152service charges from your provider. Although most tests handle their own
153teardown procedures, it is always worth manually checking that resources are
154deleted after the test suite finishes.
155
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200156### Running tests
157
158To run all tests:
159
160```bash
161go test ./...
162```
163
164To run all tests with verbose output:
165
166```bash
167go test -v ./...
168```
169
170To run tests that match certain [build tags]():
171
172```bash
173go test -tags "foo bar" ./...
174```
175
176To run tests for a particular sub-package:
177
178```bash
179cd ./path/to/package && go test .
180```
181
jrperritt55fb5842016-04-13 14:16:08 -0500182## Style guide
183
184
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200185
186We follow the standard formatting recommendations and language idioms set out
187in the [Effective Go](https://golang.org/doc/effective_go.html) guide. It's
188definitely worth reading - but the relevant sections are
189[formatting](https://golang.org/doc/effective_go.html#formatting)
190and [names](https://golang.org/doc/effective_go.html#names).
191
Jamie Hannafordd2773f22014-10-07 16:06:23 +0200192## 5 ways to get involved
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200193
Jamie Hannafordd2773f22014-10-07 16:06:23 +0200194There are five main ways you can get involved in our open-source project, and
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200195each is described briefly below. Once you've made up your mind and decided on
196your fix, you will need to follow the same basic steps that all submissions are
197required to adhere to:
198
jrperritt55fb5842016-04-13 14:16:08 -05001991. [fork](https://help.github.com/articles/fork-a-repo/) the `gophercloud/gophercloud` repository
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +02002002. checkout a [new branch](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches)
Jamie Hannafordd2773f22014-10-07 16:06:23 +02002013. submit your branch as a [pull request](https://help.github.com/articles/creating-a-pull-request/)
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200202
Jamie Hannafordd2773f22014-10-07 16:06:23 +0200203### 1. Providing feedback
204
205On of the easiest ways to get readily involved in our project is to let us know
206about your experiences using our SDK. Feedback like this is incredibly useful
207to us, because it allows us to refine and change features based on what our
208users want and expect of us. There are a bunch of ways to get in contact! You
Jon Perritt9ba988a2015-03-16 09:42:48 -0600209can [ping us](https://developer.rackspace.com/support/) via e-mail, talk to us on irc
Jamie Hannafordd2773f22014-10-07 16:06:23 +0200210(#rackspace-dev on freenode), [tweet us](https://twitter.com/rackspace), or
211submit an issue on our [bug tracker](/issues). Things you might like to tell us
212are:
213
214* how easy was it to start using our SDK?
215* did it meet your expectations? If not, why not?
216* did our documentation help or hinder you?
217* what could we improve in general?
218
219### 2. Fixing bugs
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200220
221If you want to start fixing open bugs, we'd really appreciate that! Bug fixing
222is central to any project. The best way to get started is by heading to our
jrperritt55fb5842016-04-13 14:16:08 -0500223[bug tracker](https://github.com/gophercloud/gophercloud/issues) and finding open
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200224bugs that you think nobody is working on. It might be useful to comment on the
225thread to see the current state of the issue and if anybody has made any
226breakthroughs on it so far.
227
Jamie Hannafordd2773f22014-10-07 16:06:23 +0200228### 3. Improving documentation
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200229
230We have three forms of documentation:
231
232* short README documents that briefly introduce a topic
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200233* reference documentation on [godoc.org](http://godoc.org) that is automatically
234generated from source code comments
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200235* user documentation on our [homepage](http://gophercloud.io) that includes
236getting started guides, installation guides and code samples
237
Jamie Hannafordbc35d052014-10-07 16:27:30 +0200238If you feel that a certain section could be improved - whether it's to clarify
239ambiguity, correct a technical mistake, or to fix a grammatical error - please
240feel entitled to do so! We welcome doc pull requests with the same childlike
241enthusiasm as any other contribution!
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200242
Jamie Hannafordd2773f22014-10-07 16:06:23 +0200243### 4. Optimizing existing features
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200244
245If you would like to improve or optimize an existing feature, please be aware
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200246that we adhere to [semantic versioning](http://semver.org) - which means that
247we cannot introduce breaking changes to the API without a major version change
248(v1.x -> v2.x). Making that leap is a big step, so we encourage contributors to
249refactor rather than rewrite. Running tests will prevent regression and avoid
250the possibility of breaking somebody's current implementation.
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200251
Jamie Hannafordd2773f22014-10-07 16:06:23 +0200252Another tip is to keep the focus of your work as small as possible - try not to
253introduce a change that affects lots and lots of files because it introduces
254added risk and increases the cognitive load on the reviewers checking your
255work. Change-sets which are easily understood and will not negatively impact
256users are more likely to be integrated quickly.
257
258Lastly, if you're seeking to optimize a particular operation, you should try to
jrperritt55fb5842016-04-13 14:16:08 -0500259demonstrate a negative performance impact - perhaps using Go's inbuilt
Jamie Hannafordd2773f22014-10-07 16:06:23 +0200260[benchmark capabilities](http://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go).
261
262### 5. Working on a new feature
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200263
264If you've found something we've left out, definitely feel free to start work on
Jamie Hannafordd2773f22014-10-07 16:06:23 +0200265introducing that feature. It's always useful to open an issue or submit a pull
266request early on to indicate your intent to a core contributor - this enables
267quick/early feedback and can help steer you in the right direction by avoiding
268known issues. It might also help you avoid losing time implementing something
269that might not ever work. One tip is to prefix your Pull Request issue title
270with [wip] - then people know it's a work in progress.
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200271
272You must ensure that all of your work is well tested - both in terms of unit
273and acceptance tests. Untested code will not be merged because it introduces
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200274too much of a risk to end-users.
275
276Happy hacking!