Contributions in the C programming language should align with the Linux Kernel coding guidelines. Source files can be converted to a patch file that can be checked for formatting and syntax issues using the Linux Kernel checkpatches.sh
script. Or, the checkpatch.pl
script can validate individual source files when executed as follows:
./checkpatch.pl --no-tree -f <sourcefile>
Go is very specific about using whitespaces in code. All code should be formatted using the Gofmt tool prior to committing. Many editors have plugins to automatically format your code correctly upon each save (e.g. "Go Plus" for the Atom editor).
In addition to using the Gofmt tool, all style mistakes indicated by the Golint tool must be addressed before committing. The Golint tool is also a standard tool in Golang suites for IDE's like VSCode and Atom.
New to Go? Follow this guide to get started!
-
Install Go 1.12.13 or higher: https://golang.org/dl/
-
Setup your Go workspace: https://golang.org/doc/code.html Recommend setting the following environment variables in your
.bashrc
or.zshrc
:export GOPATH=$HOME/go export PATH=$GOPATH/bin:$PATH
If you use fish, you can put this in your
.config/fish/config.fish
:set -x GOPATH "$HOME/go" set PATH "$GOPATH/bin" $PATH
-
Install your editor of choice a. VSCode with Go extension b. VIM with vim-go
It is not recommended to use
go get
to get your dependencies, to clone your source repositories or to manage your dependencies. Thego get
client is very simple and will populate your$GOPATH/src
path with clones of the dependencies at the latest branch from the master branch (or the default branch if the source is from a VCS other than git). It also places all dependencies in$GOPATH/src
which is shared with all projects and can affect the version of dependencies used of projects in an unexpected manner.
It is highly recommended to clone your Go projects with git
(or your preferred VCS tool) rather than using go get
. An example of this is (using SSH for cloning):
mkdir -p $GOPATH/src/gitserver/group
git clone ssh://git@gitserver/proj.git \
$GOPATH/src/gitserver/group/proj
cd $GOPATH/src/gitserver/group/proj.git
Doing this allows you to choose to use HTTPS or SSH for cloning your repository, depending on the clone URL you use.
It is not recommended to use go get
to clone your repository.
It is highly recommended to use Go Modules to manage dependencies. To initialize a new module:
go mod init github.com/you/hello
go: creating new go.mod: module github.com/you/hello
This will produce a go.mod
file. To add dependencies, you can use a command such as go get [email protected]
, or edit the go.mod
file.
When a contributor pulls the repository and starts to build the project, go build
will automatically fetch dependencies defined in go.mod.
Alternatively, you can run the following to download dependencies:
go mod download
In your project repository, commit both the go.mod
and the go.sum
files.
See the Go Modules documentation for more information.
You can view documentation for all code in your workspace by running the Godoc web server:
godoc -http=:6060
The preceding command will allow you to view the documentation at http://localhost:6060 You can also view documentation using a Go plugin for your IDE/editor.
At a minimum, all documentation errors indicated by the Golint tool must be addressed before committing code. This will include documentation for any public package variables, functions, types, and methods.
Additionally, it is strongly encouraged to write package overviews in a special Go file named doc.go
. Any multi-line comment preceding the package declaration will be included in the package overview when viewed in Godoc
.
Simple examples of usage can be demonstrated using testable examples.
One of the unique features of Go is that it is designed to always build a relatively static binary. We emphasize relatively because Go still has external dependencies such as C-libraries for networking. In order to produce truly static binaries, we need to take a few extra steps when building:
- Ensure that the standard C library you are using to statically compile is not copylefted (e.g. GNU Stdlib is not okay, but MIT Musl is okay).
- Use the
netgo
option to include the Golang native DNS resolver - Pass arguments to compilation to statically bake values into the binary, such as Version or CI Build number.
Here is an example of a complete compile command:
GOOS=linux go build -a --ldflags '-extldflags "-static"' -tags netgo -installsuffix netgo ./cmd/agentsvc
Some guidelines for using errors:
- When a new error occurs, use
errors.New
orerrors.Errorf
. - When you get an error from an external library, use
errors.Wrap
and add a descriptive message. - When you get an error from an internal library, just return it with
errors.WithStack
- When actually handling the error (e.g. logging it or determining the next action) use
%v
to print it, or%+v
to print a stack trace. - Logging at the INFO level should never print a stack trace. Stack traces are appropriate at the DEBUG level.
For more background information and tips, see these articles:
Whenever a function call blocks for extended periods of time (most commonly because of network IO, waiting for an async event, or polling activity) a context should be the first parameter so that the operation may be cancelled by the parent context. Here is an example:
func WaitForResponse(ctx context.Context) error {
select {
case <-ctx.Done():
return ctx.Err():
case response := <-responseChannel:
fmt.Printf("Response received: %s\n", response)
return nil
}
}
Note that the context parameter is typically named ctx
as a common Go convention.
Also note that when a context is cancelled, the corresponding cancellation error, ctx.Err()
, should be returned so that the caller knows the function returned early due to cancellation.
REST APIs must be compliant with OpenAPI specification. Swagger Editor is a nice tool for editing and validating the RESTful API definitions. The generated schema files must be in JSON format; the YAML format is optional. For OpenAPI Specification Version 2.0 (OAS 2.0), the schema file(s) should be named as:
./<schema-name>.swagger.json
./<schema-name>.swagger.yaml
For OpenAPI Specification Version 3.0 (OAS 3.0), the schema file(s) should be be named as:
./<schema-name>.openapi.json
./<schema-name>.openapi.yaml
Each service that hosts a gRPC service should also host the protobuf definition and source code stubs in the pb
directory at the top level of the repo. This convention allows other services to easily find the definition files in case a new client must be written. The grpc
directory contains a server abstraction at the top level and within subdirectories contains implementations of that server based on the PB server definition and the server abstraction.
myApp
├── cmd
│ └── myApp
│ └── myApp.go
├── myApp_suite_test.go
├── myApp_test.go
├── pb
│ └── myApp.proto
| └── myApp.pb.go
├── grpc
│ └── grpc_generated.go
│ └── myApp
│ └── myApp.go
└── pkg
├── myApp.go
└── myApp_test.go
Assuming the above directory structure, you can generate the client and server code by running:
pwd
/Users/csmith/go/src/myApp
protoc -I pb/ pb/myApp.proto --go_out=plugins=grpc:pb
When writing service definitions, it is sometimes useful to use the Empty
type as a parameter/result in endpoints from which you do not need further information. This is okay to do and will not create issues later when the Empty
type is replaced with a different type.
Use grpc.Errorf
.
Make sure that your $GOPATH
and $GOBIN
are set and are in your $PATH
(see this documentation for more info on usage of these variables in Go). For example, here's my ~/.bash_profile
on my Mac. You may have to call source ~/.bash_profile
if you want this to take effect in your current terminal session:
export GOPATH=$HOME/go
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOPATH:$GOBIN
Next, perform the installation instructions at this link: https://github.com/grpc/grpc-go. Specifically, run the following:
go get -u google.golang.org/grpc
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
Then, go to this link and download the compiled binaries for your OS (for example, there's one for macOS): https://github.com/protocolbuffers/protobuf/releases
After you download the binaries, copy them inside the folder bin
called protoc
in your folder $GOBIN
. Copy the contents of the folder include
(which should just be a folder called google
) to your $GOPATH/src
folder.
Now, you have all the necessary tools. Be sure that your project has all of its dependencies by running dep ensure
(or whatever its dependency tool is). Some projects allow you to run go generate
, which will pick up on commented generate commands. Others will require you to call protoc
directly. Here's an example of what it would look like if the code supported go generate
:
//go:generate protoc -I $GOPATH/src/../proj/pb -I $GOPATH/src -I $GOPATH/src/../proj --go_out=plugins=grpc:../../../pb/progname $GOPATH/src/.../proj/pb/progname.proto
All files must be headed at the first line with SPDX short identifier: Apache-2.0. In the case of #!scripts
, SPDX identifier can be placed in the second line of the file. Here are some examples:
For Golang files:
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) [YEAR] [CORPORATION]
For C/C++ files:
/* SPDX-License-Identifier: Apache-2.0
* Copyright(c) [YEAR] [CORPORATION]
*/
For Makefile, Dockerfile, YAML, JSON or Ansible files:
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) [YEAR] [CORPORATION]
For Shell scripts:
#!/bin/sh
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) [YEAR] [CORPORATION]
For Python scripts:
#!/usr/bin/env python
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) [YEAR] [CORPORATION]