Stamp the git tag or short commit into the binary (closes #10) #11
+25
-10
@@ -1,19 +1,28 @@
|
||||
# .dockerignore does NOT use .gitignore semantics. Docker matches with
|
||||
# moby/patternmatcher: filepath.Match plus `**`, so `*` does not cross
|
||||
# `/` and an unprefixed pattern is anchored at the context root. Every
|
||||
# depth-independent pattern therefore needs `**/`; only genuinely
|
||||
# root-anchored entries go unprefixed. Never transplant these into
|
||||
# .gitignore, where `**/` is wrong.
|
||||
# depth-independent pattern therefore needs `**/`, or `config/.env` and
|
||||
# `certs/server.key` still ship while this file reads as solved. Only
|
||||
# genuinely root-anchored entries go unprefixed. Never transplant these
|
||||
# into .gitignore, where `**/` is wrong.
|
||||
#
|
||||
# Matching is case-sensitive, so secrets use character ranges rather
|
||||
# than an ALL-CAPS twin, which would still miss `Server.Key`.
|
||||
#
|
||||
# Extend with this repo's own host-built artifacts, written anchored:
|
||||
# `/myapp`, never `**/myapp`, which also matches `cmd/myapp/` and
|
||||
# deletes the package directory from the context.
|
||||
|
||||
# Excluding .git means `git describe` cannot run in any build stage and
|
||||
# fails quietly there; rtnetmon embeds no version, so this is safe.
|
||||
.git
|
||||
# .git is sent without its config. Without a VERSION build argument the
|
||||
# stage that compiles runs `git describe --tags --always` on .git, which
|
||||
# does not need .git/config; that file can hold a credential, such as a
|
||||
# password in a remote URL or the token the CI checkout step stores there.
|
||||
.git/config
|
||||
|
||||
# Agent scratch: one full checkout of the repo per in-flight agent.
|
||||
# Anchored because agents run at the repo root here.
|
||||
# Anchored because it occurs once where agents run at the repo root.
|
||||
# KNOWN GAP: a repo running agents in subdirectories still ships
|
||||
# `services/api/.claude/` and must add its own anchored entry.
|
||||
.claude
|
||||
|
||||
# This repo's own host-built artifacts, root-anchored so `bin/` is not
|
||||
@@ -22,12 +31,15 @@
|
||||
/rtnetmon
|
||||
main.go.old
|
||||
|
||||
# Environment files.
|
||||
# Environment files. `*.env` covers bare `.env` and the `prod.env`
|
||||
# convention. Re-include a committed template with a negation if the
|
||||
# build needs one: `!docs/example.env`.
|
||||
**/*.[eE][nN][vV]
|
||||
**/.[eE][nN][vV].*
|
||||
**/.[eE][nN][vV][rR][cC]
|
||||
|
||||
# Private keys and the bundles carrying them.
|
||||
# Private keys and the bundles carrying them. Public certificates
|
||||
# (*.crt, *.cer) are deliberately absent: they are legitimate inputs.
|
||||
**/*.[pP][eE][mM]
|
||||
**/*.[kK][eE][yY]
|
||||
**/*.[pP]12
|
||||
@@ -37,11 +49,14 @@ main.go.old
|
||||
**/[iI][dD]_[eE][cC][dD][sS][aA]
|
||||
**/[iI][dD]_[eE][dD]25519
|
||||
|
||||
# Dependencies: restored inside the image, never copied in.
|
||||
**/node_modules
|
||||
|
||||
# OS metadata.
|
||||
**/.DS_Store
|
||||
**/Thumbs.db
|
||||
|
||||
# Editor state.
|
||||
# Editor state: never a build input, and it churns COPY.
|
||||
**/*.swp
|
||||
**/*.swo
|
||||
**/*~
|
||||
|
||||
+15
-1
@@ -34,4 +34,18 @@ WORKDIR /src
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 go build -trimpath -o /rtnetmon ./cmd/rtnetmon/
|
||||
# The version stamped into the binary: the VERSION build argument when one
|
||||
# is given, otherwise `git describe --tags --always` of the .git the build
|
||||
# context carries: the tag on a tagged commit, tag-N-gHASH on a commit after
|
||||
# one, the short commit when no tag is reachable. git ships in this base
|
||||
# image. A context that carries .git and still yields no version fails the
|
||||
# build. With neither, as from a source tarball, the binary reports dev.
|
||||
ARG VERSION
|
||||
RUN version="${VERSION:-$(git describe --tags --always)}"; \
|
||||
if [ -e .git ] && { [ -z "$version" ] || [ "$version" = dev ] || \
|
||||
[ "$version" = unknown ]; }; then \
|
||||
echo "no version could be derived although the build context carries .git" >&2; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
CGO_ENABLED=0 go build -trimpath -ldflags="-X main.Version=${version:-dev}" \
|
||||
-o /rtnetmon ./cmd/rtnetmon/
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
# below are thin shims that call them.
|
||||
.DEFAULT_GOAL := check
|
||||
|
||||
VERSION ?= $(shell git describe --tags --always)
|
||||
|
||||
bootstrap:
|
||||
@script/bootstrap
|
||||
|
||||
@@ -36,13 +38,14 @@ hooks:
|
||||
@script/install-precommit
|
||||
|
||||
build:
|
||||
CGO_ENABLED=0 go build -trimpath -o bin/rtnetmon ./cmd/rtnetmon
|
||||
CGO_ENABLED=0 go build -trimpath -ldflags "-X main.Version=$(VERSION)" \
|
||||
-o bin/rtnetmon ./cmd/rtnetmon
|
||||
|
||||
run: build
|
||||
./bin/rtnetmon
|
||||
|
||||
dev:
|
||||
go run ./cmd/rtnetmon
|
||||
go run -ldflags "-X main.Version=$(VERSION)" ./cmd/rtnetmon
|
||||
|
||||
deps:
|
||||
go mod download
|
||||
|
||||
@@ -8,8 +8,12 @@ import (
|
||||
"git.eeqj.de/sneak/rtnetmon/internal/cli"
|
||||
)
|
||||
|
||||
// Version is the git tag or short commit, set at link time with -X by the
|
||||
// Makefile and the Dockerfile. Builds that do not set it report dev.
|
||||
var Version = "dev" //nolint:gochecknoglobals // set at link time with -X
|
||||
|
||||
func main() {
|
||||
err := cli.Execute()
|
||||
err := cli.Execute(Version)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ package cli
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
// NewRootCmd exposes newRootCmd for external tests.
|
||||
func NewRootCmd() *cobra.Command { return newRootCmd() }
|
||||
func NewRootCmd() *cobra.Command { return newRootCmd("dev") }
|
||||
|
||||
@@ -51,8 +51,9 @@ func defaultTCPHosts() []string {
|
||||
}
|
||||
}
|
||||
|
||||
// newRootCmd builds the cobra root command with its flags bound.
|
||||
func newRootCmd() *cobra.Command {
|
||||
// newRootCmd builds the cobra root command with its flags bound. version is
|
||||
// logged at startup.
|
||||
func newRootCmd(version string) *cobra.Command {
|
||||
cfg := &config{}
|
||||
cmd := &cobra.Command{
|
||||
Use: "rtnetmon",
|
||||
@@ -60,7 +61,7 @@ func newRootCmd() *cobra.Command {
|
||||
Long: `rtnetmon is a dual-interface network monitoring dashboard that provides
|
||||
real-time visibility into network health, packet loss, and latency.`,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
return runMonitor(cmd, cfg)
|
||||
return runMonitor(cmd, cfg, version)
|
||||
},
|
||||
}
|
||||
registerFlags(cmd, cfg)
|
||||
@@ -88,8 +89,8 @@ func registerFlags(cmd *cobra.Command, cfg *config) {
|
||||
|
||||
// runMonitor detects the interfaces to monitor, then constructs and runs the
|
||||
// monitor from cfg.
|
||||
func runMonitor(cmd *cobra.Command, cfg *config) error {
|
||||
monitor.Logf(cfg.LogFile, "Starting rtnetmon")
|
||||
func runMonitor(cmd *cobra.Command, cfg *config, version string) error {
|
||||
monitor.Logf(cfg.LogFile, "Starting rtnetmon %s", version)
|
||||
|
||||
specs, err := detectInterfaces(cmd, cfg)
|
||||
if err != nil {
|
||||
@@ -169,7 +170,7 @@ func detectInterfaces(
|
||||
return specs, nil
|
||||
}
|
||||
|
||||
// Execute builds the root command and runs it.
|
||||
func Execute() error {
|
||||
return newRootCmd().Execute()
|
||||
// Execute builds the root command and runs it. version is logged at startup.
|
||||
func Execute(version string) error {
|
||||
return newRootCmd(version).Execute()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user