Thank you for your interest in golang-samples
!
This repository hosts code samples linked in cloud.google.com documentation. Because samples will be accompanied by separate documentation, we do not typically welcome unsolicited new samples. However, if you feel a specific sample is missing or incorrect, please file an issue, and we can discuss the available options.
If you'd like to contribute to existing samples, have a look at our issues list to see where we could use your help. Leave a comment on the issue to let others know you are interested.
Before we can accept your contributions, you'll need to sign a Contributor License Agreement (CLA):
- If you are an individual writing original source code and you own the intellectual property, then you'll need to sign an individual CLA.
- If you work for a company that wants to allow you to contribute your work, then you'll need to sign a corporate CLA.
You can sign these electronically (just scroll to the bottom). After that, we'll be able to accept your pull requests.
-
To contribute your changes, you'll most likely need to fork the repository. This can be done from the "Fork" menu in the Github UI, or with the Github CLI command:
gh repo fork GoogleCloudPlatform/golang-samples
. -
Clone the repo. Replace
${GITHUB_OWNER}
with your own github user name to clone your fork.git clone https://github.com/${GITHUB_OWNER}/golang-samples.git
-
Change into the checked out source:
cd golang-samples
-
You are now ready to make your changes. See Pull Request Lifecycle to learn how to send your changes for review.
All code must be formatted with gofmt
(with the latest Go version) and pass
go vet
. To run these tools on samples in the iam
directory, you would run make lint dir=iam
from the root of the repository.
The Google Cloud Samples Style Guide is considered the primary guidelines for all Google Cloud samples. This section details some additional, Go-specific rules that will be merged into the Samples Style Guide in the near future.
Please read and follow https://github.com/golang/go/wiki/CodeReviewComments for all Go code in this repo.
The following style guidelines are specific to writing Go samples.
If a project ID is needed, snippets should have a projectID string
argument.
Tests that require a Project ID should use testutil
helper functions, or
consult the GOLANG_SAMPLES_PROJECT_ID
environment variable.
The top level directory should be the product the sample is for (e.g.
functions
or dlp
).
Sub-directories can be used to keep different groups of samples for the product separate.
The package name should match the directory name, as is standard go practice.
Files should be named after the sample in them (e.g. hello.go
). No need to
include the product name or "sample" in the filename.
If there are many samples to write in the same directory, use filename prefixes to group the files acting on similar types (for example, when writing create/update/delete type samples).
Hosting platform samples may require a different directory and file structure. When possible, follow the pattern of existing samples for that product.
For snippets, the region should not include the package declaration.
Do not print to stdout
or stderr
. Pass w io.Writer
as the first argument
to the sample function and print to it with fmt.Fprintf(w, ...)
.
This pattern matches http.Handler
s, which print to an http.ResponseWriter
, normally named
w
.
func hello(w io.Writer) {
fmt.Fprintln(w, "Hello, World.")
}
The output can be verified during testing using a buffer.
func TestInspectString(t *testing.T) {
tc := testutil.SystemTest(t)
buf := new(bytes.Buffer)
err := inspectString(buf, tc.ProjectID, "I'm Gary and my email is gary@example.com")
if err != nil {
t.Errorf("TestInspectFile: %v", err)
}
got := buf.String()
if want := "Info type: EMAIL_ADDRESS"; !strings.Contains(got, want) {
t.Errorf("got %q, want %q", got, want)
}
}
Don't pass a context.Context
as an argument. New Go developers may not
understand where the ctx
comes from.
- func hello(ctx context.Context, w io.Writer) { ... }
+ func hello(w io.Writer) {
+ ctx := context.Background()
+ // ...
+ }
There should be as few function arguments as possible. An io.Writer
and
project ID are the most common. If you need additional arguments (for example,
the ID of a resource to get or delete), there should be an example value in the
body of the sample function.
// delete deletes the resource identified by name.
func delete(w io.Writer, name string) error {
// name := "/projects/my-project/resources/my-resource"
ctx := context.Background()
client, err := foo.NewClient(ctx)
if err != nil {
return fmt.Errorf("foo.NewClient: %v", err)
}
if err := client.Delete(name); err != nil {
return fmt.Errorf("Delete: %v", err)
}
return nil
}
Sample functions should not be exported. Users should not be depending directly on this sample code. So, the function name should start with a lower case letter.
Where possible, prefer a single declaration when initializing a proto value.
Request values should usually be named req
and be declared on their own so the
API call (which uses req
) is easier to understand.
- myRequest := &pb.Request{}
- myRequest.Parent = projectID
+ req := &pb.Request{
+ Parent: projectID,
+ }
Generally, Go code does not have a strict line length limit. See the Code Review Comments wiki. However, sample code is embedded on cloud.google.com and very long lines can be difficult to read in the embedded code viewer.
Keep lines under around 100 characters, keeping in mind the general rules in the wiki.
If the sample can run into errors, return the errors with additional context.
Don't call log.Fatal
or friends.
log.Fatal
is difficult to test because it will stop the entire test suite.
Use fmt.Errorf
to add information when returning errors. Usually, the name of
the package.Function
or just Function
that returned the error is enough. It
may also help to include any arguments that were passed to the function.
Prefer inline error declaration when they aren't needed outside the if
statement.
// delete deletes the resource identified by resourceID.
func delete(w io.Writer, resourceID string) error {
// resource := fmt.Sprintf("/projects/my-project/resources/%s", resourceID)
ctx := context.Background()
client, err := foo.NewClient(ctx)
- if err != nil {
- log.Fatal(err)
- }
- err := client.Delete(resourceID)
- if err != nil {
- log.Fatal(err)
- }
+ if err != nil {
+ return fmt.Errorf("foo.NewClient: %w", err)
+ }
+ if err := client.Delete(resourceID); err != nil {
+ return fmt.Errorf("Delete: %w", err)
+ }
return nil
}
The Go version in go.mod
files is the minimum version of Go supported by the
module. Generally, this should be the minimum version supported & tested by the
repo. There are some cases where we need a higher minimum version.
Do not update the minimum version unless required.
Tests are required for all samples. When writing a pull request, be sure to write and run the tests in any modified directories.
To run the system test yourself, you will need a Google Cloud Project, and valid authentication.
- Ensure you are logged in using
gcloud auth login --update-adc
.- the
--update-adc
flag refreshes Application Default Credentials.
- the
- Set the
GOLANG_SAMPLES_PROJECT_ID
environment variable to a suitable test project. - To run all tests in a directory, run
make test dir=relative/dir
All tests should use testutil.SystemTest
or variants. testutil
checks the
GOLANG_SAMPLES_PROJECT_ID
environment variable exists, and skips the test if
not.
If the test takes longer than ~2 minutes, use testutil.EndToEndTest
.
If you can't use testutil
for some reason, be sure to skip tests if
GOLANG_SAMPLES_PROJECT_ID
is not set. This makes sure tests pass when someone
clones the repo and runs tests.
Tests are responsible for creating any resources they require, and destroying them once testing is complete. Names of these resources should be unique enough to avoid conflicts in the event of multiple concurrent test runs - this typically means suffixing them with some thing unique, like a timestamp.
-
Before creating a Pull Request, ensure that your code meets style guidelines, and the tests pass. From the root of the repository, run
make lint test dir=relative/dir
. -
Create a pull request with your changes.
- PR titles should follow Conventional
Commits style (e.g.
feat(functions): add gophers codelab
). - You may wish to enable automerge on your PR, so it submits when all PR checks are passing (including review).
- PR titles should follow Conventional
Commits style (e.g.
-
Within 2-5 days, a reviewer will review your PR. They may approve it, or request changes. When requesting changes, reviewers should self-assign the PR to ensure they are aware of any updates.
-
If additional changes are needed, push additional commits to your PR branch - this helps the reviewer know which parts of the PR have changed. Commits will be squashed when merged.
- Please follow up with changes promptly. If a PR is awaiting changes by the author for more than 10 days, maintainers may mark that PR as Draft. PRs that are inactive for more than 30 days may be closed.