github.com/elopio/cli@v6.21.2-0.20160902224010-ea909d1fdb2f+incompatible/CONTRIBUTING.md (about) 1 # Contributing to CLI 2 3 The Cloud Foundry team uses GitHub and accepts code contributions via 4 [pull requests](https://help.github.com/articles/using-pull-requests). 5 If your contribution includes a change that is exposed to cf CLI users 6 (e.g. introducing a new command or flag), please submit an issue 7 to discuss it first. 8 Major new feature proposals generally entail a publicly viewable 9 google document with commenting allowed to be discussed on the [cf-dev](https://lists.cloudfoundry.org/archives/list/cf-dev@lists.cloudfoundry.org/) mailing list. 10 11 ## Contributor License Agreement 12 13 Follow these steps to make a contribution to any of our open source repositories: 14 15 1. Ensure that you have completed our CLA Agreement for 16 [individuals](https://www.cloudfoundry.org/wp-content/uploads/2015/09/CFF_Individual_CLA.pdf) or 17 [corporations](https://www.cloudfoundry.org/wp-content/uploads/2015/09/CFF_Corporate_CLA.pdf). 18 19 ## Setup 20 21 1. Install [Go 1.6.x](https://golang.org) 22 1. Create a directory where you would like to store the source for Go projects and their binaries (e.g. `$HOME/go`) 23 1. Set an environment variable, `GOPATH`, pointing at the directory you created 24 1. Get the `cf` source: `go get github.com/cloudfoundry/cli` 25 * (Ignore any warnings about "no buildable Go source files") 26 1. [Fork this repository](https://help.github.com/articles/fork-a-repo/), adding your fork as a remote 27 1. Run our bootstrap script, `bin/bootstrap` 28 29 ## Workflow 30 31 1. Run all the existing tests with `bin/test` to ensure they pass 32 1. Write a new test, see it fail when running `bin/test` (or `ginkgo -p path/to/the/package/being/tested`) 33 1. Write code to pass the test 34 1. Repeat the above two steps until the feature is complete 35 1. Run all the existing tests with `bin/test` to ensure they *still* pass 36 1. Submit a [pull request](https://help.github.com/articles/using-pull-requests/) to the `master` branch 37 38 **_*_ For development guide on writing a cli plugin, see [here](https://github.com/cloudfoundry/cli/tree/master/plugin_examples)** 39 40 ## Architecture Overview 41 42 A command is a struct that implements this interface: 43 44 ```Go 45 type Command interface { 46 MetaData() CommandMetadata 47 SetDependency(deps Dependency, pluginCall bool) Command 48 Requirements(requirementsFactory requirements.Factory, context flags.FlagContext) []requirements.Requirement 49 Execute(context flags.FlagContext) 50 } 51 ``` 52 [Source code](https://github.com/cloudfoundry/cli/blob/master/cf/commandregistry/command.go#L9) 53 54 `Metadata()` is just a description of the command name, usage and flags: 55 ```Go 56 type CommandMetadata struct { 57 Name string 58 ShortName string 59 Usage []string 60 Description string 61 Flags map[string]flags.FlagSet 62 SkipFlagParsing bool 63 TotalArgs int 64 Examples []string 65 } 66 ``` 67 [Source code](https://github.com/cloudfoundry/cli/blob/master/cf/commandregistry/command.go#L16) 68 69 The `Examples` field represents the set of lines to be printed when printing examples in the help text. 70 71 `Requirements()` returns a list of requirements that need to be met before a command can be invoked. 72 73 `Execute()` is the method that your command implements to do whatever it's supposed to do. The `context` object 74 provides flags and arguments. 75 76 When the command is run, it communicates with api using repositories (they are in [`cf/api`](https://github.com/cloudfoundry/cli/blob/master/cf/api)). 77 78 `SetDependency()` is where a command obtains its dependencies. Dependencies are typically declared as an interface type, and not a concrete type, so tests can inject a fake. 79 The bool argument `pluginCall` indicates whether the command is invoked by one of the CLI's plugin API methods. 80 81 Dependencies are injected into each command, so tests can inject a fake. This means that dependencies are 82 typically declared as an interface type, and not a concrete type. (see [`cf/commandregistry/dependency.go`](https://github.com/cloudfoundry/cli/blob/master/cf/commandregistry/dependency.go)) 83 84 Some dependencies are managed by a repository locator in [`cf/api/repository_locator.go`](https://github.com/cloudfoundry/cli/blob/master/cf/api/repository_locator.go). 85 86 Repositories communicate with the api endpoints through a Gateway (see [`cf/net`](https://github.com/cloudfoundry/cli/tree/master/cf/net)). 87 88 Models are data structures related to Cloud Foundry (see [`cf/models`](https://github.com/cloudfoundry/cli/tree/master/cf/models)). For example, some models are 89 apps, buildpacks, domains, etc. 90 91 ## Managing Dependencies 92 93 Command dependencies are managed by the command registry package. The app uses the package (in [`cf/commandregistry/dependency.go`](https://github.com/cloudfoundry/cli/blob/master/cf/commandregistry/dependency.go)) to instantiate them, this allows not sharing the knowledge of their dependencies with the app itself. 94 95 For commands that use another command as dependency, `commandregistry` is used for retrieving the command dependency. For example, the command `restart` has a dependency on command `start` and `stop`, and this is how the command dependency is retrieved: [`restart.go`](https://github.com/cloudfoundry/cli/blob/master/cf/commands/application/restart.go#L59) 96 97 As for repositories, we use the repository locator to handle their dependencies. You can find it in [`cf/api/repository_locator.go`](https://github.com/cloudfoundry/cli/blob/master/cf/api/repository_locator.go). 98 99 ## Example Command 100 101 Create Space is a good example of a command. Its tests include checking arguments, requiring the user 102 to be logged in, and the actual behavior of the command itself. You can find it in [`cf/commands/space/create_space.go`](https://github.com/cloudfoundry/cli/blob/master/cf/commands/space/create_space.go). 103 104 ## i18n 105 106 If you are adding new strings or updating existing strings within the CLI code, you'll need to update the binary representation of the translation files. This file is generated/maintained using [i18n4go](https://github.com/krishicks/i18n4go), [goi18n](https://github.com/nicksnyder/go-i18n), and `bin/generate-language-resources`. 107 108 After adding/changing strings supplied to the goi18n `T()` translation func, run the following to update the translations binary: 109 110 i18n4go -c fixup # answer any prompts appropriately 111 goi18n -outdir cf/i18n/resources cf/i18n/resources/*.all.json 112 bin/generate-language-resources 113 114 When running `i18n4go -c fixup`, you will be presented with the choices `new` or `upd` for each addition or update. Type in the appropriate choice. If `upd` is chosen, you will be asked to confirm which string is being updated using a numbered list. 115 116 After running the above, be sure to commit the translations binary, `cf/resources/i18n_resources.go`. 117 118 ## Current Conventions 119 120 ### Creating Commands 121 122 Resources that include several commands have been broken out into their own sub-package using the Resource name. An example of this convention is the Space resource and package (see `cf/commands/space`) 123 124 In addition, command file and methods naming follows a CRUD like convention. For example, the Space resource includes commands such a CreateSpace, ListSpaces, DeleteSpace, etc. 125 126 ### Creating Repositories 127 128 Although not ideal, we use the name "Repository" for API related operations as opposed to "Service". Repository was chosen 129 to avoid confusion with Service model objects (i.e. creating Services and Service Instances within Cloud Foundry). 130 131 By convention, Repository methods return a model object and an error. Models are used in both Commands and Repositories 132 to model Cloud Foundry data. This convention provides a consistent method signature across repositories.