Skip to content

Commit

Permalink
Submodules step 2/2: draw the rest of the owl (#5609)
Browse files Browse the repository at this point in the history
# What

Step 1 was in PR #5597

This second commit essentially:
1. splits the gcloud-only dependencies into a submodule which imports the main `github.com/uber/cadence` module, and not the reverse
2. also splits the "main" server build (`cmd/server`) into a submodule which imports the gcloud plugin and the main module (so that binary is unchanged)
3. removes `cloud.google.com/*` dependencies from the main `go.mod` (requires both 1 and 2)
4. adjusts things to work like they did before

Ultimately reducing our "main" (truly required) dependencies, while not making major changes to using or developing Cadence.

# Why

Part on principle, and part due to internal version conflicts.

In principle, "plugins" are "optional" and we should not be forcing _all_ optional dependencies on _all_ users of _any_ of Cadence.  
Splitting dependencies into choose-your-own-adventure submodules is simply good library design for the ecosystem, and it's something we should be doing more of.

In practice, this is essentially being forced because the gcloud archiver plugin pulls in some `cloud.google.com/*` stuff, which we upgraded, which forces breaking `google.golang.org/genproto` upgrades, which conflicts with other things in our internal monorepo.  
Removing this requirement (we do not use the gcloud archiver internally) allows us to continue using these incompatible libraries elsewhere, unblocking us while we wait for them to upgrade.  
This may also be true for [waves in the direction of The Internet] all of You, so rejoice!  Our pain is your gain.  We now no longer force you to use these libraries.

We will likely be doing this with more submodules in the future, this is just the first proof-of-concept and establishes a pattern to follow for the others.  
The client library will very likely also be doing this (or possibly in other repos) to separate out some of its more problematic dependencies.

# How

I intend to write a more detailed doc soon, but as a tl;dr this "create a new submodule to separate optional dependencies" can be recreated for other future submodules by following this sequence:

## 1: make sure all imports "into" the to-be-a-submodule folder are reversed, and instead go "out" from the submodule to the "main" module.

E.g. PR #5597 converts a hardcoded switch statement into a registration system, and then this commit uses that to reverse the direction of the code's imports.

This is generally best done _up front_, because very nearly all of it can be done without any dependency changes, which leaves you with only a small window where your IDE does not quite work (while tidying the modules the first time).  
This will also let you make a separate commit with most or all of your code changes in isolation, which is easier to review and verify as non-changing.

Technically you can put this off until later, but you may have to modify your code while you have no working refactoring / autocomplete / navigation tools, and that's just unnecessary pain.

## 2: create a `go.mod` in the to-be-a-submodule folder

That must look something like:
```
module github.com/uber/cadence/some/folder

// don't depend on a released library, depend on the current code:
replace github.com/uber/cadence => ../../

// and the thrift replace, any other replaces that may be necessary in other `go.mod`s, etc
```

## 3: `go mod tidy` in the repo root / the main `go.mod`

And confirm it removes the dependencies that only the submodule uses.

In particular, this **MUST NOT** add the new submodule to the dependencies, or you've got a main -> submodule import somewhere.  Grep for it if so, it should be very easy to find, and reverse that dependency somehow.

## 4: `go mod tidy` in the new submodule.

If this pulls in incompatible versions, I've had good luck "seeding" the new `go.mod` file with the contents of the main `go.mod` file.  It seems to keep versions more stable than replaces + `go mod tidy` alone.  
(these incompatible versions are _probably problematic somehow_ and may cause issues in the future, but we can at least use this trick or `replace` as necessary to ignore them for now)

## 5: add your new module to the root `go.work` so gopls and some other CLI tools continue to work.

Plus any makefile / CI / etc changes necessary.  Hopefully you can just mimic existing multi-module stuff.

## And that's essentially it!

In summary:
- adjust your code
- make a new `go.mod`
- tidy everything
- adjust tooling as needed

Bundle as much of ^ this as you care into a single commit, and it should all work _as long as anyone using the submodule also pulls the same version of all other modules_ (because that's what you developed against, with `replace ... => ../`).  Only same-version will be checked in CI, so only same-version should be expected to work, though other combinations _may_ work in practice.

# How others can use these new submodules

Because we _require_ `replace` directives, a "simple" `go get github.com/uber/cadence[/or/submodules]` does not work and essentially never has and never will.  
That's fine, they just have to add our replaces in a custom `go.mod`:

```
module their/project

// replace thrift (and any other replacements at version X, check our go.mod)
replace github.com/apache/thrift => github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7
```

And use a main.go to include the submodules:
```go
// optionally make it not buildable by default, makes some tools happier
//go:build just_for_gomod_purposes
package main
import (
  _ "github.com/uber/cadence/some/submodule"
  _ "github.com/uber/cadence/other/submodules/etc"
  _ "github.com/uber/cadence/cmd/server" // the main module, if you want it
)
func main() {} // does not need to be used / will not be run
```

And then `go get github.com/uber/cadence/{some/submodule,other/submodules/etc,cmd/server,}@version` to get all involved modules at the same version (as one command is most likely to work) which will merge all dependencies, update your `go.mod`, and you can now `go run github.com/uber/cadence/cmd/server` and it should work.  Or start using the various modules to make a new custom `main.go` or whatever is needed.

If necessary, you can also `replace` all `github.com/uber/cadence`-hosted modules with the same version / SHA, which should definitely force it to work.

Updating works similarly - `get` them all at the same version, make sure your replaces are up to date (as `go get` will not adjust those), and it should Just Work™ like it did with a single module.

---

This was originally planned to be landed over multiple commits to allow submodules to refer to the previously-merged commit(s) to set up dependencies, but relative `replace` directives simplify this a LOT, and bring a MUCH better development experience.

The main pros/cons of using a multi-commit + "refer to other-module@HEAD^ rather than relative paths" approach is:
- pro: people can `go get the/submodule@version` and they _could_ be guaranteed to get a working set of dependencies
    - ... at _some_ SHAs anyway.  in principle it could be e.g. at every released version or `@latest`, but it cannot be guaranteed at _all_ SHAs.
    - our thrift replace means this currently does not work anyway, and has not for a long time
- con: submodules can only refer to the _previous_ commit of other modules, as it must be a pushed SHA
    - this applies during development too, essentially requiring you to push a fork and `replace cadence => fork version` to do normal development
    - this "requires" multiple commits on master/somewhere permanent to truly release something stable.  or they can `go get` the same version of all modules.
- con: more complex dev and CI as things always refer to the _previous_ state at best, not the current
    - this can be worked around by manually `go get`ting / replacing in CI as needed to ensure the same versions, but that can become quite complex.

Filesystem-relative requires allow ^ all this in a single commit, immediately, without pushing, with the primary tradeoff being "_all_ submodule-users must manually ensure all repo-hosted modules are at the same version" rather than just _some_ (most of the time). 
 
That's pretty easy to automate, and `go get` doesn't work out-of-the-box anyway due to thrift, so we're not really losing anything by requiring that.
  • Loading branch information
Groxx authored Jan 23, 2024
1 parent 5e3da71 commit 08d5994
Show file tree
Hide file tree
Showing 25 changed files with 3,084 additions and 132 deletions.
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ WORKDIR /cadence
# Making sure that dependency is not touched
ENV GOFLAGS="-mod=readonly"

# Copy go mod dependencies and build cache
# Copy go mod dependencies and try to share the module download cache
COPY go.* ./
COPY cmd/server/go.* ./cmd/server/
COPY common/archiver/gcloud/go.* ./common/archiver/gcloud/
# go.work means this downloads everything, not just the top module
RUN go mod download

COPY . .
Expand Down
40 changes: 33 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ endif
# note that vars that do not yet exist are empty, so any prerequisites defined below are ineffective here.
$(BUILD)/lint: $(BUILD)/fmt # lint will fail if fmt fails, so fmt first
$(BUILD)/proto-lint:
$(BUILD)/gomod-lint:
$(BUILD)/fmt: $(BUILD)/copyright # formatting must occur only after all other go-file-modifications are done
$(BUILD)/copyright: $(BUILD)/codegen # must add copyright to generated code, sometimes needs re-formatting
$(BUILD)/codegen: $(BUILD)/thrift $(BUILD)/protoc
Expand Down Expand Up @@ -139,9 +140,13 @@ LINT_SRC := $(filter-out %_test.go ./.gen/%, $(ALL_SRC))

# downloads and builds a go-gettable tool, versioned by go.mod, and installs
# it into the build folder, named the same as the last portion of the URL.
#
# unfortunately go.work and `go list -modfile=sub/module/go.mod` seem to interact badly,
# and some versions complain about duplicates, while others simply block it outright.
# the good news is that you can just drop that and `cd` to the folder and it works.
define go_build_tool
$Q echo "building $(or $(2), $(notdir $(1))) from internal/tools/go.mod..."
$Q go build -mod=readonly -modfile=internal/tools/go.mod -o $(BIN)/$(or $(2), $(notdir $(1))) $(1)
$Q cd internal/tools; go build -mod=readonly -o ../../$(BIN)/$(or $(2), $(notdir $(1))) $(1)
endef

# same as go_build_tool, but uses our main module file, not the tools one.
Expand Down Expand Up @@ -333,9 +338,18 @@ $(BUILD)/proto-lint: $(PROTO_FILES) $(STABLE_BIN)/$(BUF_VERSION_BIN) | $(BUILD)
$Q cd $(PROTO_ROOT) && ../$(STABLE_BIN)/$(BUF_VERSION_BIN) lint
$Q touch $@

# lints that go modules are as expected, e.g. parent does not import submodule.
# tool builds that need to be in sync with the parent are partially checked through go_mod_build_tool, but should probably be checked here too
$(BUILD)/gomod-lint: go.mod internal/tools/go.mod common/archiver/gcloud/go.mod | $(BUILD)
$Q # this is likely impossible as it'd be a cycle
$Q if grep github.com/uber/cadence/common/archiver/gcloud go.mod; then echo "gcloud submodule cannot be imported by main module" >&2; exit 1; fi
$Q # intentionally kept separate so the server does not include tool-only dependencies
$Q if grep github.com/uber/cadence/internal go.mod; then echo "internal module cannot be imported by main module" >&2; exit 1; fi
$Q touch $@

# note that LINT_SRC is fairly fake as a prerequisite.
# it's a coarse "you probably don't need to re-lint" filter, nothing more.
$(BUILD)/lint: $(LINT_SRC) $(BIN)/revive | $(BUILD)
$(BUILD)/code-lint: $(LINT_SRC) $(BIN)/revive | $(BUILD)
$Q echo "lint..."
$Q $(BIN)/revive -config revive.toml -exclude './vendor/...' -exclude './.gen/...' -formatter stylish ./...
$Q touch $@
Expand Down Expand Up @@ -388,7 +402,7 @@ endef
# useful to actually re-run to get output again.
# reuse the intermediates for simplicity and consistency.
lint: ## (re)run the linter
$(call remake,proto-lint lint)
$(call remake,proto-lint gomod-lint code-lint)

# intentionally not re-making, it's a bit slow and it's clear when it's unnecessary
fmt: $(BUILD)/fmt ## run gofmt / organize imports / etc
Expand Down Expand Up @@ -468,12 +482,22 @@ release: ## Re-generate generated code and run tests
$(MAKE) --no-print-directory test

build: ## Build all packages and all tests (ensures everything compiles)
$Q echo 'Building all packages...'
$Q echo 'Building all packages and submodules...'
$Q go build ./...
$Q cd common/archiver/gcloud; go build ./...
$Q cd cmd/server; go build ./...
$Q # "tests" by building and then running `true`, and hides test-success output
$Q echo 'Building all tests (~5x slower)...'
$Q # intentionally not -race due to !race build tags
$Q go test -exec /usr/bin/true ./... >/dev/null
$Q cd common/archiver/gcloud; go test -exec /usr/bin/true ./... >/dev/null
$Q cd cmd/server; go test -exec /usr/bin/true ./... >/dev/null

tidy: ## go mod tidy all packages
$Q # tidy in dependency order
$Q go mod tidy
$Q cd common/archiver/gcloud; go mod tidy || (echo "failed to tidy gcloud plugin, try manually copying go.mod contents into common/archiver/gcloud/go.mod and rerunning" >&2; exit 1)
$Q cd cmd/server; go mod tidy || (echo "failed to tidy main server module, try manually copying go.mod and common/archiver/gcloud/go.mod contents into cmd/server/go.mod and rerunning" >&2; exit 1)

clean: ## Clean build products
rm -f $(BINS)
Expand Down Expand Up @@ -509,8 +533,9 @@ endif

# all directories with *_test.go files in them (exclude host/xdc)
TEST_DIRS := $(filter-out $(INTEG_TEST_XDC_ROOT)%, $(sort $(dir $(filter %_test.go,$(ALL_SRC)))))
# all tests other than end-to-end integration test fall into the pkg_test category
PKG_TEST_DIRS := $(filter-out $(INTEG_TEST_ROOT)% $(OPT_OUT_TEST), $(TEST_DIRS))
# all tests other than end-to-end integration test fall into the pkg_test category.
# ?= allows passing specific (space-separated) dirs for faster testing
PKG_TEST_DIRS ?= $(filter-out $(INTEG_TEST_ROOT)% $(OPT_OUT_TEST), $(TEST_DIRS))

# Code coverage output files
COVER_ROOT := $(BUILD)/coverage
Expand All @@ -536,11 +561,12 @@ COVER_PKGS = client common host service tools
# pkg -> pkg/... -> github.com/uber/cadence/pkg/... -> join with commas
GOCOVERPKG_ARG := -coverpkg="$(subst $(SPACE),$(COMMA),$(addprefix $(PROJECT_ROOT)/,$(addsuffix /...,$(COVER_PKGS))))"

test: bins ## Build and run all tests. This target is for local development. The pipeline is using cover_profile target
test: ## Build and run all tests. This target is for local development. The pipeline is using cover_profile target
$Q rm -f test
$Q rm -f test.log
$Q echo Running special test cases without race detector:
$Q go test -v ./cmd/server/cadence/
$Q # CAUTION: when changing to `go test ./...`, note that this DOES NOT test submodules. Those must be run separately.
$Q for dir in $(PKG_TEST_DIRS); do \
go test $(TEST_ARG) -coverprofile=$@ "$$dir" $(TEST_TAG) | tee -a test.log; \
done;
Expand Down
16 changes: 16 additions & 0 deletions cmd/server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
This is the primary "kitchen sink" server build, which includes all first-party optional plugins, and is used as our Docker-provided binary.

For the most part, this means that day-to-day library upgrades should:
1. Update the main `go.mod`'s dependencies
2. `make tidy`

New submodules we want to include by default should:
1. Add a replace in this `go.mod` like others
2. Import and register it somehow
3. `make tidy`

And if you have problems tidying:
1. Copy/paste all included modules into this `go.mod` (`/go.mod` + `/common/archiver/gcloud/go.mod` currently)
2. `go mod tidy` this submodule and it will probably be correct, `make build` to make sure
3. Commit to save your results!
4. `make tidy` to make sure it's stable
158 changes: 158 additions & 0 deletions cmd/server/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
module github.com/uber/cadence/cmd/server

go 1.20

// build against the current code in the "main" (and gcloud) module, not a specific SHA.
//
// anyone outside this repo using this needs to ensure that both the "main" module and this module
// are at the same SHA for consistency, but internally we can cheat by telling Go that it's at a
// relative file path.
replace github.com/uber/cadence => ../..

replace github.com/uber/cadence/common/archiver/gcloud => ../../common/archiver/gcloud

// ringpop-go and tchannel-go depends on older version of thrift, yarpc brings up newer version
replace github.com/apache/thrift => github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7

require (
github.com/Shopify/sarama v1.33.0 // indirect
github.com/VividCortex/mysqlerr v1.0.0 // indirect
github.com/aws/aws-sdk-go v1.44.180 // indirect
github.com/cactus/go-statsd-client/statsd v0.0.0-20191106001114-12b4e2b38748 // indirect
github.com/cch123/elasticsql v0.0.0-20190321073543-a1a440758eb9 // indirect
github.com/cristalhq/jwt/v3 v3.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/gocql/gocql v0.0.0-20211015133455-b225f9b53fa1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/hashicorp/go-version v1.2.0 // indirect
github.com/iancoleman/strcase v0.2.0 // indirect
github.com/jmoiron/sqlx v1.2.1-0.20200615141059-0794cb1f47ee // indirect
github.com/lib/pq v1.2.0 // indirect
github.com/m3db/prometheus_client_golang v0.8.1 // indirect
github.com/olivere/elastic v6.2.37+incompatible // indirect
github.com/olivere/elastic/v7 v7.0.21 // indirect
github.com/opensearch-project/opensearch-go/v2 v2.2.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 // indirect
github.com/robfig/cron v1.2.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/startreedata/pinot-client-go v0.0.0-20230303070132-3b84c28a9e95 // latest release doesn't support pinot v0.12, so use master branch
github.com/stretchr/testify v1.8.3
github.com/uber-go/tally v3.3.15+incompatible // indirect
github.com/uber/cadence-idl v0.0.0-20240119174829-b5c878f44825
github.com/uber/ringpop-go v0.8.5 // indirect
github.com/uber/tchannel-go v1.22.2 // indirect
github.com/urfave/cli v1.22.4
github.com/valyala/fastjson v1.4.1 // indirect
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/cadence v0.19.0
go.uber.org/config v1.4.0 // indirect
go.uber.org/fx v1.13.1 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/thriftrw v1.29.2 // indirect
go.uber.org/yarpc v1.70.3 // indirect
go.uber.org/zap v1.13.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.16.0 // indirect
gonum.org/v1/gonum v0.7.0 // indirect
google.golang.org/grpc v1.59.0 // indirect
gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
)

require (
github.com/uber/cadence v0.0.0-00010101000000-000000000000
github.com/uber/cadence/common/archiver/gcloud v0.0.0-00010101000000-000000000000
)

require (
cloud.google.com/go v0.110.8 // indirect
cloud.google.com/go/compute v1.23.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.3 // indirect
cloud.google.com/go/storage v1.30.1 // indirect
github.com/BurntSushi/toml v0.4.1 // indirect
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
github.com/apache/thrift v0.16.0 // indirect
github.com/benbjohnson/clock v0.0.0-20161215174838-7dc76406b6d3 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/eapache/go-resiliency v1.2.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/gogo/googleapis v1.3.2 // indirect
github.com/gogo/status v1.1.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.4 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.0.0 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jessevdk/go-flags v1.4.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kisielk/errcheck v1.5.0 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/m3db/prometheus_client_model v0.1.0 // indirect
github.com/m3db/prometheus_common v0.1.0 // indirect
github.com/m3db/prometheus_procfs v0.8.1 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.11.1 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.26.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/uber-common/bark v1.2.1 // indirect
github.com/uber-go/mapdecode v1.0.0 // indirect
github.com/xdg/stringprep v1.0.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/dig v1.10.0 // indirect
go.uber.org/net/metrics v1.3.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/oauth2 v0.11.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.128.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/tools v0.3.2 // indirect
)
Loading

0 comments on commit 08d5994

Please sign in to comment.