Skip to content

Migrating from v0.x to v1.0

This guide covers every breaking change accumulated during the v0.x development cycle. Changes are grouped by package. Each entry states what changed, shows before/after code, and provides a migration path.


Breaking Changes

Logger type: *slog.Logger / *log.Logger โ†’ logger.Logger interface

Packages affected: pkg/config, pkg/controls, pkg/errorhandling, pkg/http, pkg/grpc, pkg/props

All public factory functions and interface methods that previously accepted or returned *slog.Logger or *log.Logger now use the logger.Logger interface from pkg/logger.

Before:

import "log/slog"

container := config.NewFilesContainer(slogLogger, "yaml", paths...)
controller := controls.NewController(ctx, controls.WithLogger(slogLogger))
handler := errorhandling.New(slogLogger, nil)

After:

import "gitlab.com/phpboyscout/go-tool-base/pkg/logger"

l := logger.NewCharm(logger.InfoLevel, logger.TextFormatter)  // or your own impl
container := config.NewFilesContainer(l, "yaml", paths...)
controller := controls.NewController(ctx, controls.WithLogger(l))
handler := errorhandling.New(l, nil)

Migration:

  1. Replace *slog.Logger fields and parameters with logger.Logger.
  2. Replace construction with logger.NewCharm(level, formatter) or implement the logger.Logger interface for your own backend.
  3. If you use structured logging, call l.Handler() to obtain the underlying slog.Handler where *slog.Logger is still required (e.g. third-party libraries).

Config factory signatures: logger.Logger parameter required

Package: pkg/config

NewFilesContainer, NewReaderContainer, and LoadFilesContainer previously accepted no logger or accepted *log.Logger. They now require a logger.Logger as their first argument.

Before:

container := config.NewReaderContainer("yaml")
container, err := config.LoadFilesContainer("yaml", paths...)

After:

container := config.NewReaderContainer(l, "yaml")
container, err := config.LoadFilesContainer(l, "yaml", paths...)

Migration: Pass a logger.Logger instance as the first argument.


gRPC server: server.grpc.reflection config key required

Package: pkg/grpc

The gRPC server now checks server.grpc.reflection (bool) to conditionally enable server reflection. This key did not exist in v0.x, which caused the server to always register reflection.

Before: No config key โ€” reflection was always enabled.

After:

# config.yaml
server:
  grpc:
    reflection: true   # set to false to disable reflection in production

Migration: Add server.grpc.reflection: true to your embedded default config (or runtime config file) to preserve the previous behaviour. Set to false in production environments where reflection should be disabled for security reasons.


gRPC server port: server.grpc.port takes precedence

Package: pkg/grpc

Port resolution now checks server.grpc.port first, falling back to server.port if not set. In v0.x only server.port was consulted.

Before:

server:
  port: 9090

After (recommended):

server:
  grpc:
    port: 9090

Migration: Add server.grpc.port to your config. The old server.port key still works as a fallback, so this is not strictly required unless you are running both HTTP and gRPC servers on different ports.


HTTP server relocated: pkg/http

Package: pkg/http (previously pkg/server/http)

The HTTP server factory was moved to its own top-level package.

Before:

import "gitlab.com/phpboyscout/go-tool-base/pkg/server/http"

After:

import "gitlab.com/phpboyscout/go-tool-base/pkg/http"

Migration: Update import paths.


gRPC server relocated: pkg/grpc

Package: pkg/grpc (previously pkg/server/grpc)

The gRPC server factory was moved to its own top-level package.

Before:

import "gitlab.com/phpboyscout/go-tool-base/pkg/server/grpc"

After:

import "gitlab.com/phpboyscout/go-tool-base/pkg/grpc"

Migration: Update import paths.


controls.Controllable interface narrowed

Package: pkg/controls

The Controllable interface was split into four role-based interfaces: Runner, StateAccessor, Configurable, and ChannelProvider. The full Controllable interface still exists as a composition of all four, but ControllerOpt functions now accept Configurable rather than Controllable.

Before:

func MyOption(c controls.Controllable) {
    c.SetLogger(l)
}

After:

func MyOption(c controls.Configurable) {
    c.SetLogger(l)
}

Migration: Update custom ControllerOpt implementations to accept controls.Configurable. If you only use the provided options (e.g. WithLogger, WithoutSignals), no changes are required.


Error library: cockroachdb/errors replaces go-errors/errors

All packages

All GTB packages now use github.com/cockroachdb/errors for error creation and wrapping. The go-errors/errors dependency has been removed.

Before:

import "github.com/go-errors/errors"
err := errors.New("something went wrong")

After:

import "github.com/cockroachdb/errors"
err := errors.New("something went wrong")

Migration:

  1. Replace github.com/go-errors/errors with github.com/cockroachdb/errors in your import paths.
  2. errors.New, errors.Wrap, errors.Errorf are API-compatible.
  3. errors.Is / errors.As behave identically.
  4. Remove go-errors/errors from go.mod / go.sum after migration.

Deprecations

No APIs are deprecated at v1.0 โ€” the deprecations listed in individual v0.x specs have been fully removed. See the relevant v0.x release notes for details.


New Features in v1.0

  • pkg/logger โ€” Unified logger abstraction with charm/slog/noop backends.
  • pkg/controls self-healing โ€” WithRestartPolicy enables automatic service restarts with exponential backoff.
  • pkg/controls liveness/readiness probes โ€” WithLiveness and WithReadiness options for Kubernetes-compatible health checks.
  • pkg/http hardened client โ€” NewSecureClient() returns a pre-configured *http.Client with TLS verification, timeout, and redirect limits.
  • pkg/cmd/root middleware โ€” RegisterPreRunMiddleware allows packages to inject pre-run logic without modifying the root command.