The following is a set of guidelines for contributing to the Flow CLI. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
Install the necessary dependencies:
go get ./...
Generate mocks:
go generate
To run the repo:
go run cmd/flow/main.go
- Search existing issues to see if the problem has already been reported. If it has and the issue is still open, add a comment to the existing issue instead of opening a new one.
Explain the problem and include additional details to help maintainers reproduce the problem:
- Use a clear and descriptive title for the issue to identify the problem.
- Describe the exact steps which reproduce the problem in as many details as possible. When listing steps, don't just say what you did, but explain how you did it.
- Provide specific examples to demonstrate the steps. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use Markdown code blocks.
- Describe the behavior you observed after following the steps and point out what exactly is the problem with that behavior.
- Explain which behavior you expected to see instead and why.
- Include error messages and stack traces which show the output / crash and clearly demonstrate the problem.
Provide more context by answering these questions:
- Can you reliably reproduce the issue? If not, provide details about how often the problem happens and under which conditions it normally happens.
Include details about your configuration and environment:
- What is the version of the CLI you're using?
- What's the name and version of the Operating System you're using?
- Perform a cursory search to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
Enhancement suggestions are tracked as GitHub issues. Create an issue and provide the following information:
- Use a clear and descriptive title for the issue to identify the suggestion.
- Provide a step-by-step description of the suggested enhancement in as many details as possible.
- Provide specific examples to demonstrate the steps. Include copy/pasteable snippets which you use in those examples, as Markdown code blocks.
- Describe the current behavior and explain which behavior you expected to see instead and why.
- Explain why this enhancement would be useful to CLI users.
Unsure where to begin contributing to the Flow CLI?
You can start by looking through these good-first-issue
and help-wanted
issues:
- Good first issues: issues which should only require a few lines of code, and a test or two.
- Help wanted issues:
issues which should be a bit more involved than
good-first-issue
issues.
Both issue lists are sorted by total number of comments. While not perfect, number of comments is a reasonable proxy for impact a given change will have.
The process described here has several goals:
- Maintain code quality
- Fix problems that are important to users
- Engage the community in working toward the best possible UX
- Enable a sustainable system for the CLI's maintainers to review contributions
Please follow the styleguides to have your contribution considered by the maintainers. Reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted.
Before contributing, make sure to examine the project to get familiar with the patterns and style already being used.
- Use the present tense ("Add feature" not "Added feature")
- Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
- Limit the first line to 72 characters or less
- Reference issues and pull requests liberally after the first line
The majority of this project is written Go.
We try to follow the coding guidelines from the Go community.
- Code should be formatted using
gofmt
- Code should pass the linter:
make lint
- Code should follow the guidelines covered in Effective Go and Go Code Review Comments
- Code should be commented
- Code should pass all tests:
make test
Releasing is automated by Github actions. Release action is triggered by creating a release on Github and publishing it.
You can also release manually although this is not recommended:
- Tag a new release and push it
- Build the binaries:
make versioned-binaries
- Test built binaries locally
- Upload the binaries:
make publish
- Update the Homebrew formula: e.g.
brew bump-formula-pr flow-cli --version=0.12.3
To make the new version the default version that is installed
- DEPRECATED Change
version.txt
and commit it. (This file is no longer user for versions of the Flow CLI later than v1.18.0, although it should still be maintained to support older versions of the CLI for a while)
You can add your own scaffold by creating a GitHub repository containing the scaffold content and then making a PR
to update the scaffolds.json
in the Flow CLI repository. You need to add an entry to the list
with the bellow content.
{
"name": "name of the scaffold",
"repo": "HTTP URL to the repository containing the scaffold",
"commit": "Hash of the (latest) commit in your scaffold repository",
"branch": "scaffold repository branch",
"description": "user friendly description of the scaffold (what it contains, why it is used...)"
}
This is a design guideline used for the development of the Flow CLI. The purpose of this guideline is to achieve consistency across new features and allow composability of commands that build the fundamentals of great CLI design.
Whatever software you’re building, you can be absolutely certain that people will use it in ways you didn’t anticipate. Your software will become a part in a larger system — your only choice is over whether it will be a well-behaved part. - Clig
Our interaction with the CLI is done by executing CLI commands and passing arguments and flags which need to be consistent. Consistency will allow interactions to be predictable and will with time feel natural even without resorting to reading instructions.
Be consistent across commands and subcommands. In case we define a subcommand we
should use noun verb
pattern. Don’t have ambiguous or similarly-named commands.
Naming and language should be the same as used in the rest of Flow's documentation.
Use only lowercase letters, and dashes if you really need to. Keep it short.
Users will be typing it all the time.
flow accounts
Flags are named parameters, denoted with either a hyphen, and a
single-letter name (-r
) or a double hyphen and a multiple-letter
name (--recursive
). The longer version is preferred for better readability
and simpler learning experience in the beginning but after a while users will
probably start using the shorter version.
Every flag should have a shorter version and they should be both presented in the help. Every flag that can have a default value should have a default value so users don’t have to specify all of them when not needed.
Support flags following a value delimited by a space or
equal (=) sign (ex: --username test
or --username=test
)
flow accounts get --filter "address"
Use common naming for default falgs such as:
--log
: Logging level.
--output
: Output format (JSON, inline etc...).
-h, --help
: Help. This should only mean help. See the help section.
--version
: Version.
Arguments, or args, are positional parameters to a command. There should be as few arguments as possible, because it is hard for users to remember the sequence of arguments.
Because they are relying on position, flags should be used where more than one argument would be required.
Arguments should be one word verbs following general naming guideline. Prefer flags to arguments.
Use an argument for the value that command requires in order to run.
flow accounts get <address>
CLI should feel robust. Long operation should also provide output as they are processing. Responsivness is more important than speed.
Warn before you make a non-additive change. Eventually, you’ll find that you can’t avoid breaking an interface. Before you do, forewarn your users in the program itself: when they pass the flag you’re looking to deprecate, tell them it’s going to change soon. Make sure there’s a way they can modify their usage today to make it future-proof, and tell them how to do it.
The CLI will respond to execution of commands by providing some output. Output should with the same reasons as input be consistent and predictable, even further it should follow some industry standards and thus allow great strength of CLI use: composability. Output should be served in the right dosage. We shouldn't output lines and lines of data because we will shadow the important part the same way we shouldn't let the CLI command run in background not providing any output for minutes as it is working because the user will start to doubt if the command is broken. It's important to get this balance right.
Commands must be stateless and idempotent, meaning they can be run without relying on external state. If we have some external state, like the configuration, each command must include an option to define it on the fly, but it must also work without it by first relying on the externally saved state in the configuration, and if not found, relying on a default value. When relying on a default value results in an error, there should be an explanation for the user that a configuration should be created.
We try to use default values first to get that “works like magic” feeling.
Never require a prompt for user input. Always offer a flag to provide that input. However, if a user doesn't provide required input we can offer a prompt as an alternative.
“Expect the output of every program to become the input to another, as yet unknown, program.” — Doug McIlroy
Output should use stdout. Output of commands should be presented in a clear formatted way for
users to easily scan it, but it must also be compatible with grep
command often used in
command chaining. Output should also be possible in json by using --output json
flag.
Default command response should be to the stdout and not saved to a file. Anytime we want
the output to be saved to a file we should explicitly specify so by using --save filename.txt
flag and providing the path.
Result output should include only information that is commonly used and relevant, don't use too much of user screen drowning what’s truly important, instead provide a way to include that data when the user requests by having include, exclude flags.
Address 179b6b1cb6755e31
Balance 0
Keys 2
Key 0 Public Key c8a2a318b9099cc6c872a0ec3dcd9f59d17837e4ffd6cd8a1f913ddfa769559605e1ad6ad603ebb511f5a6c8125f863abc2e9c600216edaa07104a0fe320dba7
Weight 1000
Signature Algorithm ECDSA_P256
Hash Algorithm SHA3_256
Code
access(all) contract Foo {
access(all) var bar: String
init() {
self.bar = "Hello, World!"
}
}
{"Address":"179b6b1cb6755e31","Balance":0,"Code":"CnB1YiBjb250cmFjdCBGb28gewoJcHViIHZhciBiYXI6IFN0cmluZwoKCWluaXQoKSB7CgkJc2VsZi5iYXIgPSAiSGVsbG8sIFdvcmxkISIKCX0KfQo=","Keys":[{"Index":0,"PublicKey":{},"SigAlgo":2,"HashAlgo":3,"Weight":1000,"SequenceNumber":0,"Revoked":false}],"Contracts":null}
Error should be human-readable, avoid printing out stack trace. It should give some
pointers as to what could have gone wrong and how to fix it.
Maybe try involving an example. However allow --log debug
flag for complete error info
with stack. Error messages should be sent to stderr
❌ Error while dialing dial tcp 127.0.0.1:3569: connect: connection refused"
🙏 Make sure your emulator is running or connection address is correct.
Saving output to files should be optional and never a default action unless it is
clear from the command name the output will be saved and that is
required for later use (example: flow init
). Output can be piped in files, and
our CLI should resort to that for default saving. If there is a specific format
that needs to be saved or converted to we should be able to display that format as
well hence again allowing us to pipe it to files.
Main help screen must contain a list of all commands with their own description, it must also include examples for commands. Help screen should include link to the documentation website.
Commands should have a description that is not too long (less than 100 characters). Help should be outputed if command is ran without any arguments. Help outline should be:
<description>
Usage:
<command> <action>
Examples:
An optional section of example(s) on how to run the command.
Commands:
<command>
<commandDescription>
<command>
<commandDescription>
…
Flags:
--<flag>
<flagDescription>
--<flag>
<flagDescription>
…
Show progress for longer running commands visually. Visual feedback on longer running commands is important so users don’t get confused if command is running or the CLI is hang up resulting in user quitting.
Loading 0x1fd892083b3e2a4c...⠼
Commands should provide feedback if there is no result to be presented.
If a command completes an operation that has no result to be shown it
should write out that command was executed. This is meant to assure the user
of the completion of the command.
If user is executing a destructive command they should be asked for approval
but this command should allow passing confirmation with a flag --yes
.
💾 result saved to: account.txt
CLI should return zero status unless it is shut down because of an error. This will allow chaining of commands and interfacing with other cli. If a command is long running then provide description how to exit it (e.g. "Press Ctrl+C to stop").
exit status 1
Base color should be white with yellow reserved for warnings and red for errors. Blue color can be used to accent some commands but it shouldn’t be used too much as it will confuse the user.
https://blog.developer.atlassian.com/10-design-principles-for-delightful-clis/
https://devcenter.heroku.com/articles/cli-style-guide
https://eng.localytics.com/exploring-cli-best-practices/
Thank you for your interest in contributing to the Flow CLI!