Skip to content

Instantly share code, notes, and snippets.

@dims
Last active April 24, 2026 15:08
Show Gist options
  • Select an option

  • Save dims/8fdfd022d555525490384eddd6aed611 to your computer and use it in GitHub Desktop.

Select an option

Save dims/8fdfd022d555525490384eddd6aed611 to your computer and use it in GitHub Desktop.
Kubernetes Dependency Analysis (v1.36.0-alpha) -- depstat

Kubernetes Dependency Analysis

Generated by depstat at commit d8d43a90343 on branch master. Analysis date: 2026-04-24. Compared against: v1.35.4. depstat version: 45eb8b409b5280a128d6bcbc974952c599954e1d (Fix why --svg/--dot timeout on highly-connected deps like OTel).


1. Executive Summary

Metric Value
Total unique dependencies 255
Direct dependencies 178
Transitive-only dependencies 222
Test-only dependencies 31
Non-test dependencies 224
Dependency graph max depth 19
Dependency cycles 19
Archived dependencies 5
Main modules (go.work) 34 (1 root + 33 staging)

Key Findings

  • Master is leaner than v1.35.4. −11 total dependencies net (17 removed, 6 added). This continues the multi-release trend of reducing the dependency surface rather than growing it.
  • github.com/pkg/errors finally retired. The long-standing archived error-wrapping library has been removed from master. All callers now use native Go fmt.Errorf/%w wrapping.
  • github.com/docker/docker split into github.com/moby/moby/api + github.com/moby/moby/client, establishing cleaner module boundaries aligned with the Moby project's own restructuring.
  • github.com/bufbuild/protovalidate-gobuf.build/go/protovalidate: module path migrated to the buf.build registry, reflecting the Buf ecosystem's move to a canonical registry domain.
  • go-grpc-prometheus removed, consolidated into grpc-middleware/providers/prometheus (already a dependency since v1.35.x).
  • Two new staging modulesk8s.io/cri-streaming and k8s.io/streaming — extract CRI streaming functionality into dedicated, independently importable packages.
  • gRPC jumped 8 minor versions (v1.72.2 → v1.80.0), the largest single-library leap in this cycle.
  • OTel contrib packages advanced 7–24 minor/patch versions (e.g., otelrestful from v0.44 → v0.68).
  • Go 1.26 — a significant toolchain upgrade.
  • github.com/go-logr/logr is the single highest-fan-in non-toolchain external library at 80 direct dependents — nearly every staging module depends on it for structured logging.
  • gopkg.in/yaml.v3 has 91 direct dependents but remains on Kubernetes' unwanted-dependencies list; it persists purely as a transitive dependency through etcd, testify, and OTel modules.

2. Module Architecture

Kubernetes uses a go.work monorepo with vendored dependencies and a staging publication mechanism that makes it unique in the Go ecosystem.

k8s.io/kubernetes/
├── go.work              -> workspace covering root + 33 staging modules
├── go.mod               -> k8s.io/kubernetes  (root module)
├── vendor/              -> vendored copy of all external dependencies
└── staging/src/         -> 33 k8s.io/* and sigs.k8s.io/* staging repos
    ├── k8s.io/api/
    ├── k8s.io/apimachinery/
    ├── k8s.io/apiserver/
    ├── k8s.io/client-go/
    ├── k8s.io/cri-streaming/      <-- NEW in this cycle
    ├── k8s.io/streaming/          <-- NEW in this cycle
    └── ... 28 more

Key architectural properties:

  • All k8s.io/* staging modules are part of the workspace and share a single vendor directory
  • External dependencies are vendored at the root, deduplicated across all 34 modules
  • depstat traverses the full go.work graph, not just the root module

34 modules detected in go.work: k8s.io/api, k8s.io/apiextensions-apiserver, k8s.io/apimachinery, k8s.io/apiserver, k8s.io/cli-runtime, k8s.io/client-go, k8s.io/cloud-provider, k8s.io/cluster-bootstrap, k8s.io/code-generator, k8s.io/component-base, k8s.io/component-helpers, k8s.io/controller-manager, k8s.io/cri-api, k8s.io/cri-client, k8s.io/cri-streaming (new), k8s.io/csi-translation-lib, k8s.io/dynamic-resource-allocation, k8s.io/endpointslice, k8s.io/externaljwt, k8s.io/kms, k8s.io/kube-aggregator, k8s.io/kube-controller-manager, k8s.io/kube-proxy, k8s.io/kube-scheduler, k8s.io/kubectl, k8s.io/kubelet, k8s.io/kubernetes, k8s.io/metrics, k8s.io/mount-utils, k8s.io/pod-security-admission, k8s.io/sample-apiserver, k8s.io/sample-cli-plugin, k8s.io/sample-controller, k8s.io/streaming (new)


3. Dependency Statistics

Direct Dependencies:    178
Transitive-only:        222
Total (deduplicated):   255
Max Depth:               19

Test-only:               31
Non-test:               224

The 31 test-only dependencies are unchanged from v1.35.4, meaning all of the net −11 reduction came from the non-test (production) dependency surface — a clean signal that this cycle's pruning was disciplined and targeted.


4. Fan-in Ranking (Top 25 External Dependencies)

Fan-in = number of modules in the workspace that directly depend on a package. Higher fan-in = more structural load-bearing.

Rank Fan-in Module
1 105 github.com/davecgh/go-spew ⚠️ unwanted
2 97 gopkg.in/yaml.v3 ⚠️ unwanted
3 96 github.com/stretchr/testify
4 96 github.com/pmezard/go-difflib
5 88 google.golang.org/protobuf
6 80 github.com/go-logr/logr
7 64 github.com/google/go-cmp
8 59 go.yaml.in/yaml/v2
9 55 github.com/modern-go/reflect2 ⚠️ unwanted
10 55 github.com/modern-go/concurrent ⚠️ unwanted
11 54 github.com/json-iterator/go ⚠️ unwanted
12 53 github.com/google/uuid
13 52 gopkg.in/inf.v0
14 52 google.golang.org/genproto/googleapis/rpc
15 52 github.com/x448/float16
16 51 github.com/spf13/pflag
17 51 github.com/fxamacker/cbor/v2
18 48 google.golang.org/grpc
19 48 go.opentelemetry.io/otel

⚠️ = listed in hack/unwanted-dependencies.json; present only as transitive dependencies pulled by other libraries, not directly by Kubernetes code.

The high fan-in of unwanted modules like go-spew (105), yaml.v3 (97), and json-iterator/go (54) reflects how deeply embedded these are in the transitive dependency graph — they appear because popular libraries like testify, etcd, and OTel all require them.


5. Dependency Cycles

All 19 cycles detected originate in upstream ecosystem packages. Kubernetes's own k8s.io/* staging repos maintain perfectly acyclic internal layering.

Cycle Length Count
2 7
3 6
4 4
5 2

All 19 Cycles

# Cycle
1 github.com/golang/protobufgoogle.golang.org/protobufgithub.com/golang/protobuf
2 github.com/onsi/ginkgo/v2github.com/onsi/gomegagithub.com/onsi/ginkgo/v2
3 github.com/prometheus/client_golanggithub.com/prometheus/commongithub.com/prometheus/client_golang
4 github.com/stretchr/objxgithub.com/stretchr/testifygithub.com/stretchr/objx
5 go.opentelemetry.io/auto/sdkgo.opentelemetry.io/otelgo.opentelemetry.io/auto/sdk
6 go.opentelemetry.io/auto/sdkgo.opentelemetry.io/otelgo.opentelemetry.io/otel/metricgo.opentelemetry.io/auto/sdk
7 go.opentelemetry.io/auto/sdkgo.opentelemetry.io/otel/tracego.opentelemetry.io/otelgo.opentelemetry.io/auto/sdk
8 go.opentelemetry.io/auto/sdkgo.opentelemetry.io/otel/tracego.opentelemetry.io/otelgo.opentelemetry.io/otel/metricgo.opentelemetry.io/auto/sdk
9 go.opentelemetry.io/otelgo.opentelemetry.io/otel/metricgo.opentelemetry.io/otel
10 go.opentelemetry.io/otelgo.opentelemetry.io/otel/metricgo.opentelemetry.io/otel/tracego.opentelemetry.io/otel
11 go.opentelemetry.io/otelgo.opentelemetry.io/otel/tracego.opentelemetry.io/otel
12 go.opentelemetry.io/otel/sdkgo.opentelemetry.io/otel/sdk/metricgo.opentelemetry.io/otel/sdk
13 golang.org/x/cryptogolang.org/x/netgolang.org/x/crypto
14 golang.org/x/cryptogolang.org/x/textgolang.org/x/toolsgolang.org/x/netgolang.org/x/crypto
15 golang.org/x/cryptogolang.org/x/textgolang.org/x/modgolang.org/x/toolsgolang.org/x/netgolang.org/x/crypto
16 golang.org/x/modgolang.org/x/toolsgolang.org/x/mod
17 golang.org/x/modgolang.org/x/toolsgolang.org/x/netgolang.org/x/textgolang.org/x/mod
18 golang.org/x/netgolang.org/x/textgolang.org/x/toolsgolang.org/x/net
19 google.golang.org/genproto/googleapis/apigoogle.golang.org/grpcgoogle.golang.org/genproto/googleapis/api

Top Cycle Participants

Module Cycle Count
go.opentelemetry.io/otel 7
go.opentelemetry.io/auto/sdk 4
go.opentelemetry.io/otel/metric 4
go.opentelemetry.io/otel/trace 4
golang.org/x/net 5
golang.org/x/tools 5
golang.org/x/text 4
golang.org/x/crypto 4

OpenTelemetry accounts for 9 of the 19 cycles — nearly half. This is a known upstream design: the OTel Go SDK splits its API surface across otel, otel/metric, otel/trace, otel/sdk, otel/sdk/metric, and otel/auto/sdk modules that mutually depend on each other for interface definitions and default no-op implementations.

The diagram below shows the 9 OTel cycles with exact version numbers on each edge. Dashed red arrows show where auto/sdk requires an older version (v1.38.0) that MVS resolves upward to v1.43.0:

OTel dependency cycles

The golang.org/x packages account for 6 cycles through a well-known pattern: x/crypto, x/net, x/text, x/tools, and x/mod form a web of mutual test imports and toolchain dependencies.


6. Archived Dependencies

Current State (5 archived modules)

Module Version Risk Notes
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 Low Simple shell lexer; stable, minimal attack surface
github.com/google/btree v1.1.3 Low Functionally complete B-tree; no security surface
github.com/google/gofuzz v1.0.0 Low Active replacement (sigs.k8s.io/randfill) in progress
github.com/json-iterator/go v1.1.12 Medium Production JSON serialization in API server hot paths
github.com/kr/pty v1.1.1 Low Superseded by github.com/creack/pty; minimal API

Notable: github.com/pkg/errors Removed

github.com/pkg/errors — the archived error-wrapping library — has been removed in this cycle. All call sites now use native Go error wrapping (fmt.Errorf with %w, errors.Is, errors.As). This reduces the archived count from 6 (v1.35.4) to 5 on master.

Unresolved Archived Detection (non-GitHub hosts)

depstat archived can only check GitHub-hosted repos. The following are hosted outside GitHub and could not be verified programmatically: bitbucket.org/bertimus9/systemstat, buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go, cyphar.com/go-pathrs, gonum.org/v1/gonum, google.golang.org/protobuf, gopkg.in/* variants. All are actively maintained.


7. Release Diff: v1.35.4 → master (d8d43a90343)

Summary Metrics

┌────────────────────────┬──────────┬─────────────────┬─────────┐
│ Metric                 │  v1.35.4 │  master HEAD    │  Delta  │
├────────────────────────┼──────────┼─────────────────┼─────────┤
│ Direct Dependencies    │      186 │             178 │      −8 │
│ Transitive Dependencies│      228 │             222 │      −6 │
│ Total (deduplicated)   │      266 │             255 │     −11 │
│ Max Depth              │       19 │              19 │       0 │
└────────────────────────┴──────────┴─────────────────┴─────────┘

7.1 Dependencies Added (+6)

Module Notes
buf.build/go/protovalidate Replaces github.com/bufbuild/protovalidate-go (module path migration)
github.com/cenkalti/backoff/v5 Upgraded from v4 (vendor-only); v5 is a direct dependency
github.com/moby/moby/api Split from github.com/docker/docker
github.com/moby/moby/client Split from github.com/docker/docker
go.opentelemetry.io/otel/exporters/stdout/stdouttrace New OTel stdout trace exporter
gonum.org/v1/gonum Numerical/scientific computing library (new)

7.2 Dependencies Removed (−17)

Module Notes
github.com/armon/circbuf Unmaintained; call site removed
github.com/bufbuild/protovalidate-go Replaced by buf.build/go/protovalidate
github.com/docker/docker Split into moby/moby/api + moby/moby/client
github.com/gregjones/httpcache Unmaintained; call site removed
github.com/grpc-ecosystem/go-grpc-prometheus Consolidated into grpc-middleware/providers/prometheus
github.com/karrick/godirwalk Removed
github.com/libopenstorage/openstorage Removed
github.com/moby/sys/atomicwriter Removed
github.com/mohae/deepcopy Removed
github.com/morikuni/aec Removed
github.com/mrunalp/fileutils Removed
github.com/pkg/errors Archived — migrated to stdlib error wrapping
github.com/zeebo/errs Removed
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp HTTP OTLP exporter removed
go.uber.org/automaxprocs Removed
golang.org/x/xerrors Removed (use stdlib errors)
gotest.tools/v3 Removed

7.3 Notable Version Bumps

Module Before After Notes
go toolchain 1.25.0 1.26.0 Major toolchain upgrade
google.golang.org/grpc v1.72.2 v1.80.0 +8 minor versions — largest leap
go.opentelemetry.io/otel v1.41.0 v1.43.0 Core OTel
go.opentelemetry.io/otel/sdk v1.36.0 v1.43.0 +7 versions
go.etcd.io/etcd/*/v3 v3.6.5 v3.6.8 All etcd modules
github.com/google/cel-go v0.26.0 v0.27.0 CEL engine
github.com/google/cadvisor v0.53.0 v0.56.2 cAdvisor
sigs.k8s.io/kustomize/* v0.20.1/v5.7.1 v0.21.1/v5.8.1 Kustomize suite

7.4 Vendor Changes

Vendored Modules: 214 → 208 (−6)
Added (3):   cenkalti/backoff/v5, k8s.io/cri-streaming, k8s.io/streaming
Removed (9): armon/circbuf, cenkalti/backoff/v4, gregjones/httpcache,
             grpc-ecosystem/go-grpc-prometheus, karrick/godirwalk,
             libopenstorage/openstorage, mohae/deepcopy, mrunalp/fileutils,
             stoewer/go-strcase
Vendor-only removals (not in go.mod): cenkalti/backoff/v4, stoewer/go-strcase

7.5 Diff Graph: v1.35.4 → master

Green = added, Red = removed, Yellow = version changed.

Dependency diff: v1.35.4 → master HEAD

View raw SVG


8. Full Dependency Graph

Full Kubernetes dependency graph — 255 nodes, master HEAD d8d43a90343

View raw SVG

The full graph shows the characteristic hub-and-spoke structure: k8s.io/kubernetes at the center with its 178 direct edges, surrounded by a ring of staging repos each pulling 60–110 dependencies, and an outer shell of third-party dependencies. The k8s.io staging cluster is densely interconnected but perfectly acyclic — all detected cycles originate in upstream ecosystem packages.


9. Why-Traces: Key Dependencies

Why-trace targets were selected by fan-in rank (computed from go mod graph) — the packages with the most modules depending on them. Targets exclude golang.org/x/* (toolchain cross-deps) and k8s.io/* (workspace-internal). Pure plumbing (test utilities, protobuf internals) is noted but deprioritized for narrative.

9.1 Why is github.com/go-logr/logr included?

Fan-in rank: #6 | Direct dependents: 80 total (63 k8s.io/*)

go-logr/logr is the structured logging interface used throughout Kubernetes and virtually all of its staging modules. It provides an abstract logging API that decouples logging call sites from the backend implementation — in Kubernetes, klog/v2 serves as the concrete backend. Nearly every k8s.io staging module imports it directly, making it the single highest-fan-in non-plumbing external library in the workspace. It is stable, actively maintained, and has no known replacement.

Why go-logr/logr

View raw SVG


9.2 Why is gopkg.in/yaml.v3 included?

Fan-in rank: #2 | Direct dependents: 91 total (54 k8s.io/*)

yaml.v3 is on Kubernetes' unwanted-dependencies list — the preferred alternative is sigs.k8s.io/yaml. However, it persists in the workspace graph at 91 fan-in because major transitive dependencies require it: go.etcd.io/etcd/*, go.opentelemetry.io/*, github.com/stretchr/testify, and many gRPC-ecosystem packages all depend on yaml.v3 directly. Eliminating it would require upstream changes across multiple unrelated projects simultaneously. The unwanted-dependencies status correctly flags this as aspirational rather than immediately actionable.

Why gopkg.in/yaml.v3

View raw SVG


9.3 Why is google.golang.org/grpc included?

Fan-in rank: #18 | Direct dependents: 48 total (31 k8s.io/*)

gRPC is Kubernetes' core RPC transport. It is used by the API server (aggregated APIs, CRI, CSI, device plugins), etcd client, OTel exporters, and konnectivity. Jumped from v1.72.2 to v1.80.0 (+8 minor versions) in this cycle.

Why gRPC

View raw SVG


9.4 Why is go.opentelemetry.io/otel included?

Fan-in rank: #19 | Direct dependents: 48 total (35 k8s.io/*)

OTel is the distributed tracing and metrics framework adopted by Kubernetes for observability. The API server, kubelet, scheduler, and controller-manager all emit spans and metrics via OTel. The high k8s.io/* count (35 of 48) shows how pervasively the OTel instrumentation has been applied across staging modules. Also pulled transitively by gRPC ≥ v1.64 (which bundles OTel as a default dependency for metrics).

Why OpenTelemetry

View raw SVG


9.5 Why is github.com/prometheus/client_golang included?

Direct dependents: 33 total (27 k8s.io/*)

Prometheus client_golang is the metrics exposition library. All Kubernetes components expose /metrics endpoints in Prometheus format. Also pulled transitively by the gRPC middleware and OTel Prometheus exporter bridge.

Why Prometheus client_golang

View raw SVG


9.6 Why is github.com/google/cel-go included?

Direct dependents: 20 total (19 k8s.io/*)

CEL (Common Expression Language) is the expression engine powering ValidatingAdmissionPolicy, AuthorizationPolicy, and CRD validation rules. It is used only by apiserver-tier staging modules; the low absolute count (20) with high k8s proportion (19) shows it is a first-party Kubernetes dependency with minimal transitive spread.

Why cel-go

View raw SVG


9.7 Why is go.etcd.io/etcd/client/v3 included?

Direct dependents: 16 total (15 k8s.io/*)

etcd is Kubernetes' primary storage backend. The API server depends on etcd/client/v3 directly; integration test utilities also pull it. The low fan-in (16) reflects that only apiserver-tier modules deal with etcd directly — kubelet, scheduler, and client-facing modules are etcd-agnostic. Updated v3.6.5 → v3.6.8 in this cycle.

Why etcd client/v3

View raw SVG


10. Recommendations

High Priority

  • github.com/json-iterator/go (archived, medium risk): Production JSON in API server hot paths. Track upstream encoding/json performance improvements in Go 1.26 as a potential replacement path.
  • gopkg.in/yaml.v3 (91 dependents, unwanted): Requires upstream changes in etcd, testify, and OTel. File tracking issues upstream; block new direct uses in Kubernetes code.

Medium Priority

  • github.com/google/gofuzz (archived): Replacement sigs.k8s.io/randfill is in progress. Complete migration in the next cycle.
  • github.com/davecgh/go-spew (105 dependents, unwanted): Pulled by testify. Once testify drops go-spew (tracked upstream), this disappears automatically.
  • github.com/modern-go/{concurrent,reflect2} (55 dependents each, unwanted): Pulled by json-iterator/go. Will drop once json-iterator is removed.

Low Priority

  • github.com/flynn/go-shlex, github.com/google/btree, github.com/kr/pty: All archived, all low risk. Monitor for supply-chain events but no urgent action needed.
  • Vendor-only removals: cenkalti/backoff/v4 and stoewer/go-strcase were removed from vendor but not go.mod — verify these don't re-appear in future go mod tidy runs.

11. Reproducibility

All commands run from k8s.io/kubernetes at commit d8d43a90343 (Merge pull request #138565 from skitt/drop-otel-semconv-v1.12.0).

depstat version: 45eb8b409b5280a128d6bcbc974952c599954e1d (built from sigs.k8s.io/depstat)

Fan-in ranking command (determines why-trace selection):

go mod graph | awk '{print $2}' | sed 's/@.*//' \
  | grep -v '^k8s.io/' | grep -v '^golang.org/x/' \
  | sort | uniq -c | sort -rn | head -25

Why-trace targets selected (data-driven from fan-in top-25):

  • github.com/go-logr/logr (80, rank #6)
  • gopkg.in/yaml.v3 (91, rank #2 — unwanted, shown to explain persistence)
  • google.golang.org/grpc (48, rank #18)
  • go.opentelemetry.io/otel (48, rank #19)
  • github.com/prometheus/client_golang (33)
  • github.com/google/cel-go (20)
  • go.etcd.io/etcd/client/v3 (16)

SVG commands:

# Full graph and diff (awk filter strips depstat diagnostic prefix)
/tmp/depstat graph -d . --svg | awk '/^<\?xml/{found=1} found' > k8s-full-graph.svg
/tmp/depstat diff -d . v1.35.4 HEAD --svg | awk '/^<\?xml/{found=1} found' > k8s-diff-v1354-master.svg

# Why-traces (no awk filter needed — why --svg emits clean SVG)
/tmp/depstat why -d . github.com/go-logr/logr --svg --max-paths 50 > k8s-why-github_com_go-logr_logr.svg
/tmp/depstat why -d . gopkg.in/yaml.v3 --svg --max-paths 50 > k8s-why-gopkg_in_yaml_v3.svg
/tmp/depstat why -d . google.golang.org/grpc --svg --max-paths 50 > k8s-why-google_golang_org_grpc.svg
/tmp/depstat why -d . go.opentelemetry.io/otel --svg --max-paths 50 > k8s-why-go_opentelemetry_io_otel.svg
/tmp/depstat why -d . github.com/prometheus/client_golang --svg --max-paths 50 > k8s-why-github_com_prometheus_client_golang.svg
/tmp/depstat why -d . github.com/google/cel-go --svg --max-paths 50 > k8s-why-github_com_google_cel-go.svg
/tmp/depstat why -d . go.etcd.io/etcd/client/v3 --svg --max-paths 50 > k8s-why-go_etcd_io_etcd_client_v3.svg
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment