├── .bazelrc ├── .bazelversion ├── .circleci └── config.yml ├── .cirrus.yml ├── .gitignore ├── BUILD.bazel ├── README.md ├── WORKSPACE ├── grpc ├── client │ ├── BUILD.bazel │ └── main.go ├── common │ ├── BUILD.bazel │ └── port.go └── server │ ├── BUILD.bazel │ ├── README.md │ └── main.go ├── helloworld ├── BUILD.bazel ├── hello │ ├── BUILD.bazel │ ├── hello.go │ └── hello_test.go └── main.go └── protobufs └── helloworld ├── BUILD.bazel └── helloworld.proto /.bazelrc: -------------------------------------------------------------------------------- 1 | # .bazelrc contains default flags for the project when invoking Bazel 2 | 3 | test --test_output=errors 4 | -------------------------------------------------------------------------------- /.bazelversion: -------------------------------------------------------------------------------- 1 | 3.7.0 2 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Use the latest 2.1 version of CircleCI pipeline process engine. See: https://circleci.com/docs/2.0/configuration-reference 2 | version: 2.1 3 | jobs: 4 | build: 5 | docker: 6 | - image: gcr.io/cloud-builders/bazel@sha256:240b796c49e8c8a11c7fe49e83fd0d4fdaa32998accccd4465dfe2df3be13230 7 | steps: 8 | - checkout 9 | - run: 10 | command: bazel build //... --jobs=1 11 | name: Bazel Build 12 | workflows: 13 | build: 14 | jobs: 15 | - build 16 | -------------------------------------------------------------------------------- /.cirrus.yml: -------------------------------------------------------------------------------- 1 | container: 2 | image: gcr.io/cloud-builders/bazel@sha256:240b796c49e8c8a11c7fe49e83fd0d4fdaa32998accccd4465dfe2df3be13230 3 | task: 4 | build_script: bazel build //... --jobs=1 --remote_http_cache=http://$CIRRUS_HTTP_CACHE_HOST 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | 16 | # Bazel 17 | /bazel-* 18 | 19 | # Built-Binaries 20 | /golang-boilerplate 21 | -------------------------------------------------------------------------------- /BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_gazelle//:def.bzl", "gazelle") 2 | load("@com_github_bazelbuild_buildtools//buildifier:def.bzl", "buildifier") 3 | GO_PREFIX = "github.com/rickypai/golang-boilerplate" 4 | 5 | gazelle( 6 | name = "gazelle", 7 | external = "external", 8 | prefix = GO_PREFIX, 9 | ) 10 | 11 | buildifier( 12 | name = "buildifier", 13 | ) 14 | 15 | load("@com_github_atlassian_bazel_tools//goimports:def.bzl", "goimports") 16 | 17 | goimports( 18 | name = "goimports", 19 | display_diffs = True, 20 | prefix = GO_PREFIX, 21 | write = True, 22 | ) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # golang-boilerplate 2 | 3 | This is a boilerplate for starting a Golang project in Bazel. I use it for my personal Golang projects. 4 | 5 | This contains two examples: 6 | 7 | 1. Hello world binary for just printing hello world 8 | 2. Hello world gRPC example with client/server 9 | 10 | ## How to use 11 | 12 | ``` 13 | bazel run //:gazelle 14 | ``` 15 | 16 | ``` 17 | bazel build //... 18 | ``` 19 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 2 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 3 | 4 | http_archive( 5 | name = "io_bazel_rules_go", 6 | sha256 = "207fad3e6689135c5d8713e5a17ba9d1290238f47b9ba545b63d9303406209c6", 7 | urls = [ 8 | "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.24.7/rules_go-v0.24.7.tar.gz", 9 | "https://github.com/bazelbuild/rules_go/releases/download/v0.24.7/rules_go-v0.24.7.tar.gz", 10 | ], 11 | ) 12 | 13 | http_archive( 14 | name = "bazel_gazelle", 15 | sha256 = "b85f48fa105c4403326e9525ad2b2cc437babaa6e15a3fc0b1dbab0ab064bc7c", 16 | urls = [ 17 | "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", 18 | "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.22.2/bazel-gazelle-v0.22.2.tar.gz", 19 | ], 20 | ) 21 | 22 | # github_go_repository is a thin wrapper around gazelle's go_repository which supports some level of http caching 23 | http_archive( 24 | name = "github_go_repository", 25 | sha256 = "2e469317040f6a96a065109e6b7c68bfbf6eedd831b5ddd1d8bd62ed567f3a17", 26 | strip_prefix = "bazel_github_go_repository-0.1", 27 | urls = [ 28 | "https://github.com/rickypai/bazel_github_go_repository/archive/0.1.zip", 29 | ], 30 | ) 31 | 32 | load("@github_go_repository//:def.bzl", "github_go_repository") 33 | 34 | BAZEL_BUILD_TOOLS_SHA = "e6efbf6df90bec363c3cbd564b72be6c8a309f14" 35 | 36 | http_archive( 37 | name = "com_github_bazelbuild_buildtools", 38 | sha256 = "ec0e3f910b476b40e0ef26b1b163efa4d0dc56a79d700da81de3aa962ebb2f9e", 39 | strip_prefix = "buildtools-" + BAZEL_BUILD_TOOLS_SHA, 40 | url = "https://github.com/bazelbuild/buildtools/archive/" + BAZEL_BUILD_TOOLS_SHA + ".zip", 41 | ) 42 | 43 | ATLASSIAN_BAZEL_TOOLS_SHA = "6cb4f87bb5136762f2be00123f1739ab2f1cd263" 44 | 45 | http_archive( 46 | name = "com_github_atlassian_bazel_tools", 47 | sha256 = "104e4520e386ad13d8030121093f224a02628738d12ee82f72cf28a515c783f2", 48 | strip_prefix = "bazel-tools-" + ATLASSIAN_BAZEL_TOOLS_SHA, 49 | urls = ["https://github.com/atlassian/bazel-tools/archive/" + ATLASSIAN_BAZEL_TOOLS_SHA + ".zip"], 50 | ) 51 | 52 | http_archive( 53 | name = "io_bazel_rules_docker", 54 | sha256 = "4521794f0fba2e20f3bf15846ab5e01d5332e587e9ce81629c7f96c793bb7036", 55 | strip_prefix = "rules_docker-0.14.4", 56 | urls = ["https://github.com/bazelbuild/rules_docker/releases/download/v0.14.4/rules_docker-v0.14.4.tar.gz"], 57 | ) 58 | 59 | git_repository( 60 | name = "com_google_protobuf", 61 | commit = "fde7cf7358ec7cd69e8db9be4f1fa6a5c431386a", # v3.13.0 62 | remote = "https://github.com/protocolbuffers/protobuf", 63 | ) 64 | 65 | load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") 66 | 67 | protobuf_deps() 68 | 69 | load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") 70 | 71 | go_rules_dependencies() 72 | 73 | go_register_toolchains() 74 | 75 | load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") 76 | 77 | gazelle_dependencies() 78 | 79 | load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_dependencies") 80 | 81 | buildifier_dependencies() 82 | 83 | load("@com_github_atlassian_bazel_tools//goimports:deps.bzl", "goimports_dependencies") 84 | 85 | goimports_dependencies() 86 | 87 | load( 88 | "@io_bazel_rules_docker//repositories:repositories.bzl", 89 | container_repositories = "repositories", 90 | ) 91 | 92 | container_repositories() 93 | 94 | load( 95 | "@io_bazel_rules_docker//container:container.bzl", 96 | "container_pull", 97 | ) 98 | load( 99 | "@io_bazel_rules_docker//go:image.bzl", 100 | _go_image_repos = "repositories", 101 | ) 102 | 103 | _go_image_repos() 104 | 105 | github_go_repository( 106 | name = "org_golang_google_grpc", 107 | commit = "5e8f83304c0563d1ba74db05fee83d9c18ab9a58", # 1.32.0 108 | importpath = "google.golang.org/grpc", 109 | repo_url = "github.com/grpc/grpc-go", 110 | sha256 = "160fc44859435b70beb8e73f4144ba12511377993c34f6429f301a0121204638", 111 | ) 112 | 113 | github_go_repository( 114 | name = "org_golang_x_net", 115 | importpath = "golang.org/x/net", 116 | commit = "ab34263943818b32f575efc978a3d24e80b04bd7", # release-branch.go1.15 117 | repo_url = "github.com/golang/net", 118 | sha256 = "7f3c48e6aa4dfed3d52639e97d216b9393d31b4c5d6a2da7a898f025d9d41ac7", 119 | ) 120 | 121 | github_go_repository( 122 | name = "org_golang_x_text", 123 | importpath = "golang.org/x/text", 124 | commit = "afb9336c4530b4b18f37130eab53f245f7d6821e", # release-branch.go1.15 125 | repo_url = "github.com/golang/text", 126 | sha256 = "b8a3d423db1d9936925ef28270df384ab7e9c256841f9545f6233fcb3f397b1b", 127 | ) 128 | 129 | github_go_repository( 130 | name = "org_golang_x_mod", 131 | commit = "859b3ef565e237f9f1a0fb6b55385c497545680d", # release-branch.go1.15 132 | importpath = "golang.org/x/mod", 133 | repo_url = "github.com/golang/mod", 134 | sha256 = "0e93ead99da2660f235995b29559cc13f5268e2bace794aac87ccf83e6465a16", 135 | ) 136 | -------------------------------------------------------------------------------- /grpc/client/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = ["main.go"], 6 | importpath = "github.com/rickypai/golang-boilerplate/grpc/client", 7 | visibility = ["//visibility:private"], 8 | deps = [ 9 | "//grpc/common:go_default_library", 10 | "//protobufs/helloworld:go_default_library", 11 | "@org_golang_google_grpc//:go_default_library", 12 | "@org_golang_x_net//context:go_default_library", 13 | ], 14 | ) 15 | 16 | go_binary( 17 | name = "client", 18 | embed = [":go_default_library"], 19 | visibility = ["//visibility:public"], 20 | ) 21 | -------------------------------------------------------------------------------- /grpc/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2015 gRPC authors. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "fmt" 23 | "log" 24 | "os" 25 | "time" 26 | 27 | "github.com/rickypai/golang-boilerplate/grpc/common" 28 | pb "github.com/rickypai/golang-boilerplate/protobufs/helloworld" 29 | "golang.org/x/net/context" 30 | "google.golang.org/grpc" 31 | ) 32 | 33 | const ( 34 | host = "127.0.0.1" 35 | defaultName = "world" 36 | ) 37 | 38 | func main() { 39 | address := fmt.Sprintf("%s:%v", host, common.Port) 40 | 41 | // Set up a connection to the server. 42 | conn, err := grpc.Dial(address, grpc.WithInsecure()) 43 | if err != nil { 44 | log.Fatalf("did not connect: %v", err) 45 | } 46 | defer conn.Close() 47 | c := pb.NewGreeterClient(conn) 48 | 49 | // Contact the server and print out its response. 50 | name := defaultName 51 | if len(os.Args) > 1 { 52 | name = os.Args[1] 53 | } 54 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 55 | defer cancel() 56 | r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name}) 57 | if err != nil { 58 | log.Fatalf("could not greet: %v", err) 59 | } 60 | log.Printf("Greeting: %s", r.Message) 61 | } 62 | -------------------------------------------------------------------------------- /grpc/common/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = ["port.go"], 6 | importpath = "github.com/rickypai/golang-boilerplate/grpc/common", 7 | visibility = ["//visibility:public"], 8 | ) 9 | -------------------------------------------------------------------------------- /grpc/common/port.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | const Port = 50051 4 | -------------------------------------------------------------------------------- /grpc/server/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") 2 | load("@io_bazel_rules_docker//go:image.bzl", "go_image") 3 | 4 | go_library( 5 | name = "go_default_library", 6 | srcs = ["main.go"], 7 | importpath = "github.com/rickypai/golang-boilerplate/grpc/server", 8 | visibility = ["//visibility:private"], 9 | deps = [ 10 | "//grpc/common:go_default_library", 11 | "//protobufs/helloworld:go_default_library", 12 | "@org_golang_google_grpc//:go_default_library", 13 | "@org_golang_google_grpc//reflection:go_default_library", 14 | "@org_golang_x_net//context:go_default_library", 15 | ], 16 | ) 17 | 18 | go_binary( 19 | name = "server", 20 | embed = [":go_default_library"], 21 | visibility = ["//visibility:public"], 22 | ) 23 | 24 | # go_image( 25 | # name = "server_image", 26 | # embed = [":go_default_library"], 27 | # goarch = "amd64", 28 | # goos = "linux", 29 | # pure = "on", 30 | # ) 31 | -------------------------------------------------------------------------------- /grpc/server/README.md: -------------------------------------------------------------------------------- 1 | # Server 2 | 3 | ## Create ConfigMap 4 | 5 | ``` 6 | kubectl create configmap server-envoy-config --from-file=helloworld/server/envoy-config.yaml 7 | ``` 8 | -------------------------------------------------------------------------------- /grpc/server/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2015 gRPC authors. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | //go:generate protoc -I ../helloworld --go_out=plugins=grpc:../helloworld ../helloworld/helloworld.proto 20 | 21 | package main 22 | 23 | import ( 24 | "fmt" 25 | "log" 26 | "net" 27 | 28 | "github.com/rickypai/golang-boilerplate/grpc/common" 29 | pb "github.com/rickypai/golang-boilerplate/protobufs/helloworld" 30 | "golang.org/x/net/context" 31 | "google.golang.org/grpc" 32 | "google.golang.org/grpc/reflection" 33 | ) 34 | 35 | // server is used to implement helloworld.GreeterServer. 36 | type server struct{} 37 | 38 | // SayHello implements helloworld.GreeterServer 39 | func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { 40 | return &pb.HelloReply{Message: "Hello " + in.Name}, nil 41 | } 42 | 43 | func main() { 44 | lis, err := net.Listen("tcp", fmt.Sprintf(":%v", common.Port)) 45 | if err != nil { 46 | log.Fatalf("failed to listen: %v", err) 47 | } 48 | s := grpc.NewServer() 49 | pb.RegisterGreeterServer(s, &server{}) 50 | // Register reflection service on gRPC server. 51 | reflection.Register(s) 52 | if err := s.Serve(lis); err != nil { 53 | log.Fatalf("failed to serve: %v", err) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /helloworld/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = ["main.go"], 6 | importpath = "github.com/rickypai/golang-boilerplate/helloworld", 7 | visibility = ["//visibility:private"], 8 | deps = ["//helloworld/hello:go_default_library"], 9 | ) 10 | 11 | go_binary( 12 | name = "helloworld", 13 | embed = [":go_default_library"], 14 | visibility = ["//visibility:public"], 15 | ) 16 | -------------------------------------------------------------------------------- /helloworld/hello/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") 2 | 3 | go_library( 4 | name = "go_default_library", 5 | srcs = ["hello.go"], 6 | importpath = "github.com/rickypai/golang-boilerplate/helloworld/hello", 7 | visibility = ["//visibility:public"], 8 | ) 9 | 10 | go_test( 11 | name = "go_default_test", 12 | srcs = ["hello_test.go"], 13 | embed = [":go_default_library"], 14 | ) 15 | -------------------------------------------------------------------------------- /helloworld/hello/hello.go: -------------------------------------------------------------------------------- 1 | package hello 2 | 3 | // Hello returns the "hello" string 4 | func Hello() string { 5 | return "hello" 6 | } 7 | 8 | // HelloWorld returns the "hello world" string 9 | func HelloWorld() string { 10 | return "hello world" 11 | } 12 | -------------------------------------------------------------------------------- /helloworld/hello/hello_test.go: -------------------------------------------------------------------------------- 1 | package hello 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestHello(t *testing.T) { 8 | tests := []struct { 9 | name string 10 | want string 11 | }{ 12 | { 13 | "returns hello", 14 | "hello", 15 | }, 16 | } 17 | for _, tt := range tests { 18 | t.Run(tt.name, func(t *testing.T) { 19 | if got := Hello(); got != tt.want { 20 | t.Errorf("Hello() = %v, want %v", got, tt.want) 21 | } 22 | }) 23 | } 24 | } 25 | 26 | func TestHelloWorld(t *testing.T) { 27 | tests := []struct { 28 | name string 29 | want string 30 | }{ 31 | { 32 | "returns hello world", 33 | "hello world", 34 | }, 35 | } 36 | for _, tt := range tests { 37 | t.Run(tt.name, func(t *testing.T) { 38 | if got := HelloWorld(); got != tt.want { 39 | t.Errorf("HelloWorld() = %v, want %v", got, tt.want) 40 | } 41 | }) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /helloworld/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/rickypai/golang-boilerplate/helloworld/hello" 7 | ) 8 | 9 | func main() { 10 | fmt.Println(hello.HelloWorld()) 11 | } 12 | -------------------------------------------------------------------------------- /protobufs/helloworld/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("@io_bazel_rules_go//go:def.bzl", "go_library") 3 | load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") 4 | 5 | proto_library( 6 | name = "helloworld_proto", 7 | srcs = ["helloworld.proto"], 8 | visibility = ["//visibility:public"], 9 | ) 10 | 11 | go_proto_library( 12 | name = "helloworld_go_proto", 13 | compilers = ["@io_bazel_rules_go//proto:go_grpc"], 14 | importpath = "github.com/rickypai/golang-boilerplate/protobufs/helloworld", 15 | proto = ":helloworld_proto", 16 | visibility = ["//visibility:public"], 17 | ) 18 | 19 | go_library( 20 | name = "go_default_library", 21 | embed = [":helloworld_go_proto"], 22 | importpath = "github.com/rickypai/golang-boilerplate/protobufs/helloworld", 23 | visibility = ["//visibility:public"], 24 | ) 25 | -------------------------------------------------------------------------------- /protobufs/helloworld/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.helloworld"; 19 | option java_outer_classname = "HelloWorldProto"; 20 | 21 | package helloworld; 22 | 23 | // The greeting service definition. 24 | service Greeter { 25 | // Sends a greeting 26 | rpc SayHello (HelloRequest) returns (HelloReply) {} 27 | } 28 | 29 | // The request message containing the user's name. 30 | message HelloRequest { 31 | string name = 1; 32 | } 33 | 34 | // The response message containing the greetings 35 | message HelloReply { 36 | string message = 1; 37 | } 38 | --------------------------------------------------------------------------------