Read sentry_dsn from SENTRY_DSN environment variable
What
The runner now reads the Sentry DSN from the SENTRY_DSN environment
variable when sentry_dsn is not set in config.toml. If both are set,
the config file wins.
Why
The DSN was only configurable through config.toml. In containerized
deployments the config is often templated or read-only, and operators
expect to point error reporting at a Sentry project through an
environment variable without editing the file.
Why not the env: struct tag
The runner already has an env: annotation, so the obvious question is
why this doesn't use it. The env: tag is not a generic "read from the
environment" mechanism. It is consumed only by golang-cli-helpers
GetFlagsFromStruct, which turns command structs into urfave/cli flags,
and urfave/cli is what reads the variable. It applies to fields that
become command-line flags, such as those on DockerConfig and
RunnerSettings.
SentryDSN lives on the global common.Config, which is populated by
the TOML decoder in LoadConfig. The decoder ignores env: tags, so
annotating the field would have no effect. Using the tag would mean
adding a --sentry-dsn flag to the run command and then merging that
flag back into the loaded config with its own precedence rules against
config.toml. That is a larger change and a different feature: a flag
plus a variable, rather than environment support for the existing
config field.
Reading the variable in LoadConfig keeps precedence explicit and
re-evaluates on every config reload, so changing the environment and
reloading behaves the same as the initial load. The tradeoff is that the
variable does not show up in --help the way a flag would.
Notes
The fallback uses os.LookupEnv, so an explicitly empty SENTRY_DSN=""
is still treated as set. That keeps the existing nil versus non-nil
contract that commands/multi.go relies on: an unset variable leaves
SentryDSN nil and Sentry stays off, while an empty string is a
deliberate override.