This document describes how to set up your development environment to build and test Qri, and
explains the basic mechanics of using git
, golint
and go test
.
Before you can build Qri, you must install and configure the following dependencies on your machine:
-
Git: The Github Guide to Installing Git is a good source of information.
-
The Go Programming Language: see golang.org to get started
-
golint: Golint is a linter for Go source code
To contribute code to Qri, you must have a GitHub account so you can push code to your own fork of Qri and open Pull Requests in the GitHub Repository.
To create a Github account, follow the instructions here. Afterwards, go ahead and fork the Qri frontend repository.
Check out this documentation on how to build Qri from source
When you push your branch to github and open up a pull request, it will automatically trigger CircleCI to lint and test your code.
In order to catch linting and testing errors before pushing the code to github, be sure to run golint
and go test
.
Use golint
to lint your code. Using ./...
indicates to golint
that you want to lint each file in the current directory, and each file in each sub-directory you must be in the top level directory of the project in order to lint every file in the project:
$ golint ./...
No output indicates everything is styled correctly. Otherwise, the output will point you to which files/lines need to be changed in order to meet the go linting format.
Use the built in go test
command to test your code. Like the above, you can use ./...
to run each test file, if you are in the top most directory of the project:
$ go test ./...
? github.com/qri-io/qri [no test files]
ok github.com/qri-io/qri/actions 1.180s
ok github.com/qri-io/qri/api 0.702s
ok github.com/qri-io/qri/base (cached)
ok github.com/qri-io/qri/cmd 17.557s
? github.com/qri-io/qri/cmd/generate [no test files]
ok github.com/qri-io/qri/config (cached)
? github.com/qri-io/qri/config/test [no test files]
? github.com/qri-io/qri/docs [no test files]
ok github.com/qri-io/qri/lib 1.064s
ok github.com/qri-io/qri/p2p (cached)
ok github.com/qri-io/qri/p2p/test (cached)
ok github.com/qri-io/qri/repo (cached)
ok github.com/qri-io/qri/repo/fs (cached)
ok github.com/qri-io/qri/profile (cached)
ok github.com/qri-io/qri/repo/test (cached)
ok github.com/qri-io/qri/rev (cached)
Depending on what work you are doing and what has changed, tests may take up to a minute.
If everything is marked "ok", you are in the clear. Any extended output is a sign that a test has failed. Be sure to fix any bugs that are indicated or tests that no longer pass.
You may run just the tests for a specific package by running the go test
command from that directory. You may also target specific tests to run based off a regex match of the test's name. For example, running go test --run TestSetup
will execute any test that has the TestSetup prefix (tests named TestsSetupOne, TestSetup, and TestSetupWithAnotherName would all run). To see a verbose printout of all tests regardless of pass/skip/fail status, you may add the -v
flag.
When creating or editing CLI commands, we try and follow a few style rules to keep things consistent:
-
Make sure to mention all the positional arguments in the
Use
string. Choose descriptive names in all capital letters, and put optional arguments in square brackets. -
Always include a
Short
description. It should be a phrase, not a sentence: it starts with a lower-case letter and ends without a period. -
Long descriptions should be full sentences and start with a captial letter unless the first word is the name of a command or special word that should never be upper-case.
-
Examples should be…
- Indented with two spaces.
- Example descriptions start with
#
. - Lines that should be typed start with
$
.
-
Long text fields should not have leading or trailing blank lines.
-
Try to use active, rather than passive, voice wherever possible.
-
Use the
Args
field for limiting the number of arguments (or even better, for doing more detailed validation). Cobra has some nice built-ins for this.
Example:
cmd := &cobra.Command{
Use: "add DATASET [DATASET...]",
Short: "add datasets from other peers",
Long: `Add retrieves datasets owned by other peers and adds them to your repo.
The reference names of the datasets will remain the same, including
the name of the peer that originally added the dataset. You must have
` + "`qri connect`" + ` running in another terminal to use this command.`,
Example: ` # Add a dataset named their_data, owned by other_peer:
$ qri add other_peer/their_data`,
Annotations: map[string]string{
"group": "dataset",
},
RunE: func(cmd *cobra.Command, args []string) error {
if err := o.Complete(f); err != nil {
return err
}
return o.Run(args)
},
}
We have very precise rules over how our git commit messages can be formatted. This leads to more readable messages that are easy to follow when looking through the project history. But also, we use the git commit messages to generate the Qri change log.
Each commit message consists of a header, a body and a footer. The header has a special format that includes a type, a scope and a subject:
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
The header is mandatory and the scope of the header is optional.
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier to read on GitHub as well as in various git tools.
If the commit reverts a previous commit, it should begin with revert:
, followed by the header
of the reverted commit.
In the body it should say: This reverts commit <hash>.
, where the hash is the SHA of the commit
being reverted.
A commit with this format is automatically created by the git revert
command.
Must be one of the following:
- feat: A new feature
- fix: A bug fix
- docs: Documentation only changes
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- refactor: A code change that neither fixes a bug nor adds a feature
- perf: A code change that improves performance
- test: Adding missing or correcting existing tests
- chore: Changes to the build process or auxiliary tools and libraries such as documentation generation
The scope could be anything specifying place of the commit change. For example, if I am refactoring something in the api
package, I may start my commit with "refactor(api)". If it's something more specific, like the ListHandler, I may write "refactor(api/ListHandler)", or something similar. As long as it gets the point across on the scope of the refactor.
You can use *
when the change affects more than a single scope.
The subject contains succinct description of the change:
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize first letter
- no dot (.) at the end
Just as in the subject, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior.
The footer should contain any information about Breaking Changes and is also the place to reference GitHub issues that this commit closes.
Breaking Changes should start with the word BREAKING CHANGE:
with a space or two newlines.
The rest of the commit message is then used for this.
A detailed explanation can be found in this document.
If, while running the test suite, you get failing tests with "too many open files", you may need to adjust the number of files your shell process is willing to open. This is particularly common with the p2p
and cmd
pacakges. Both rely heavily on interacting temporary directories on the file system to run tests.
Often this is caused by having too low a file limit for your shell. You can use the ulimit
command to check out or change the limits. Try the following command to set the shell limit to 1000 open files:
ulimit -S -n 1000
We recommend a ulimit value of at least 1000; feel free to go higher if you need. Some other software require values as high as 10000 to avoid the max open file issue.