Documentation
¶
Overview ¶
Package buildinfo exposes the forge binary's version metadata to packages that cannot depend on internal/cli (to avoid import cycles). The cmd/forge entrypoint and internal/cli are responsible for seeding this data at startup via Set; anything that wants to stamp the forge version into generated artifacts should read it from here.
Index ¶
- Constants
- Variables
- func CheckoutVersion(root string) string
- func ClearCI()
- func ClearDevBuild()
- func ClearDiscoveredForgeRoot()
- func ClearGitVersion()
- func Describe() string
- func DevWebRuntimeLinkForced() bool
- func DiscoverDevForgeRootFromSource() string
- func GitCommit() string
- func Identity() string
- func InstallableVersion() string
- func IsCI() bool
- func IsDevBuild() bool
- func IsDevVersion(v string) bool
- func IsModuleCachePath(path string) bool
- func LocalBuild() bool
- func PublishedFloor() string
- func Set(v, _, commit string)
- func SetBuildDate(d string)
- func SetCI(v bool)
- func SetDevBuild(v bool)
- func SetDiscoveredForgeRoot(v string)
- func SetGitVersion(v string)
- func SourceRoot() string
- func Version() string
- type Build
- type ForgeRoot
- type Source
Constants ¶
const ForgeRootEnv = "FORGE_ROOT"
ForgeRootEnv names the forge checkout for --link-forge, like --forge-root.
Variables ¶
var DevForgeRoot string
DevForgeRoot is the absolute path to the LOCAL forge source checkout that THIS forge binary was built from. It is injected ONLY on dev builds, via ldflags, from the builder's own checkout — never committed, never machine-specific in source:
go install -ldflags \ "-X github.com/reliant-labs/forge/internal/buildinfo.DevForgeRoot=$(git rev-parse --show-toplevel)" \ ./cmd/forge
(see the `dev` target in the Makefile / Taskfile and CONTRIBUTING.md). Released builds never pass this ldflag, so it stays "" for anything a user installs. The e2e corpus stamps the binary it tests (devForgeRootLDFlag in internal/cli/scaffold_e2e_test.go), which is never shipped.
Its only consumer is the project scaffolder (internal/cli/new.go): on a dev build it writes a gitignored go.work into the freshly-created project that `use`s this path, so the scaffold builds against the in-development forge/pkg instead of the last published tag — no manual `go mod edit -replace` dance. The path lands ONLY in that generated, gitignored, machine-local go.work; it is never written into committed forge source or any committed project file.
Functions ¶
func CheckoutVersion ¶ added in v1.0.0
CheckoutVersion is the Go pseudo-version of the forge checkout at root, the version a binary built from it reports, or "" when root is not a git checkout git can read. It carries the same "+dev" / "+dirty" build metadata as a derived Version(): it names a commit, not a published module.
func ClearCI ¶ added in v0.1.45
func ClearCI()
ClearCI removes any override set by SetCI, restoring the environment read.
func ClearDevBuild ¶ added in v0.1.45
func ClearDevBuild()
ClearDevBuild removes any override set by SetDevBuild, restoring the real build-info read.
func ClearDiscoveredForgeRoot ¶ added in v0.1.45
func ClearDiscoveredForgeRoot()
ClearDiscoveredForgeRoot removes any override set by SetDiscoveredForgeRoot, restoring the real runtime.Caller discovery.
func ClearGitVersion ¶ added in v0.1.45
func ClearGitVersion()
ClearGitVersion removes any override set by SetGitVersion.
func Describe ¶ added in v0.1.45
func Describe() string
Describe renders the multi-line identity block used when a failure needs to spell out which forge is running and what library it resolved.
func DevWebRuntimeLinkForced ¶ added in v0.1.45
func DevWebRuntimeLinkForced() bool
DevWebRuntimeLinkForced reports whether the operator has explicitly demanded the web-runtime dev link despite running under CI.
func DiscoverDevForgeRootFromSource ¶ added in v0.1.45
func DiscoverDevForgeRootFromSource() string
DiscoverDevForgeRootFromSource locates the LOCAL forge source checkout that THIS binary was COMPILED from, at runtime, with no build-time ldflag. It is the embedder-independent complement to DevForgeRoot: forge's CLI runs both standalone (cmd/forge) AND embedded in other binaries — reliant imports github.com/reliant-labs/forge/cli and runs `reliant forge project new` in-process. Only forge's own `make dev` stamps DevForgeRoot; an embedder's build almost never remembers to pass forge's internal ldflag, so on a dev forge running inside reliant DevForgeRoot is "" and the scaffolder would silently fall back to the last PUBLISHED forge/pkg tag — which cannot satisfy generated code that targets not-yet-published forge/pkg APIs. Rather than make every embedder stamp the flag, we recover the path the compiler baked into this source file.
How: runtime.Caller yields the absolute path of THIS file as it existed on the build machine. Contributor/dev builds are NOT built with -trimpath, so that path is a real, absolute checkout path; we walk upward to the module root (the go.mod declaring github.com/reliant-labs/forge) and confirm its pkg/ runtime-library directory exists on disk.
It returns "" — bridging nothing — for anything that is not a genuine, present-on-disk forge checkout, which is exactly the release/shipped case:
- release builds use -trimpath, so the baked path is a module-relative stub that does not exist as an absolute path;
- a dev binary copied to another machine no longer finds its source tree;
- any walk that fails to find the go.mod module marker and pkg/.
So it is safe to call unconditionally — it self-limits to the machine that built a from-source forge. Callers still gate on IsDevBuild first, so a clean release never even attempts discovery.
func GitCommit ¶
func GitCommit() string
GitCommit returns the git commit SHA recorded via Set. Falls back to the VCS revision from runtime build info when available.
func Identity ¶ added in v0.1.45
func Identity() string
Identity is the one-line build identity, the string `--version` prints and that failure runbooks quote to name which forge ran.
func InstallableVersion ¶
func InstallableVersion() string
InstallableVersion returns the forge binary's version ONLY when it is a ref that `go install ...@<ref>` can actually resolve from a module proxy — a release tag or a clean Go pseudo-version. For anything else (the "dev" sentinel, "(devel)", an empty value, or a `+dirty` pseudo-version from a dirty-tree build) it returns "" so callers fall back to pinning by git SHA instead.
This is the boundary that keeps `+dirty` out of generated CI: callers stamp this (not raw Version()) into the `go install` step, and the empty return routes the CI template's three-branch policy onto the SHA branch. See internal/templates/ci/github/ci.yml.tmpl.
func IsCI ¶ added in v0.1.45
func IsCI() bool
IsCI reports whether forge is running on an automated build agent.
Callers use it to suppress artifacts that only make sense in a human's dev loop. It is deliberately NOT folded into IsDevBuild: that function answers a question about the BINARY (built from source vs. released), and conflating the two would make a CI build of a dev binary claim to be a release, changing version reporting and the scaffolded go.work bridge as a side effect of an unrelated fix.
func IsDevBuild ¶ added in v0.1.45
func IsDevBuild() bool
IsDevBuild reports whether THIS forge binary is a development build rather than a released, tagged one. It is the guard the scaffolder pairs with DevForgeRoot before writing a local-forge go.work bridge: a released binary must NEVER write one, even if a DevForgeRoot value somehow leaked in.
A build is treated as a RELEASE (returns false) only when the binary's own module build info records a clean, tagged semver version (vX.Y.Z[-pre]) from an unmodified working tree — i.e. `go install github.com/reliant-labs/forge/cmd/forge@vX.Y.Z` or a tag-checkout release build. Everything else is a dev build (returns true):
- no build info at all,
- the "(devel)" marker (a plain `go build`/`go install` from the source tree — the ordinary contributor loop),
- a Go pseudo-version (an untagged commit, e.g. `...@main`),
- vcs.modified=true (a dirty working tree).
func IsDevVersion ¶ added in v0.1.45
IsDevVersion reports whether a forge version STRING denotes a development build rather than a published release tag.
IsDevBuild answers that question about the RUNNING binary by reading its own build info. IsDevVersion answers it about a version string recorded somewhere else — most importantly the `forge_version` a project pins in forge.yaml, which outlives the binary that wrote it. A project scaffolded by a local forge checkout records a Go pseudo-version (`v0.0.4-0.<ts>-<sha>`, optionally `+dirty`). That is honest IDENTITY — it names the exact commit — but it is not a release, and anything that REPORTS a version should say so rather than let a reader mistake it for a tag.
Development (true): the "dev" / "(devel)" sentinels, an empty value, any version carrying build metadata (`+dirty` — only a modified working tree produces one), any Go pseudo-version, and anything that is not valid semver. Release (false): a canonical tagged semver version.
It is deliberately a pure function of the string: ordering and identity are separate concerns, and callers that need ordering compare semver directly.
func IsModuleCachePath ¶ added in v0.1.45
IsModuleCachePath reports whether path is, or lies inside, a Go module-cache extraction of some module — any ancestor directory named `<element>@<version>`. See isModuleCacheDir.
func LocalBuild ¶ added in v1.0.7
func LocalBuild() bool
LocalBuild reports whether this forge was compiled from a local source tree — a checkout built where it stands, or a host that embeds forge through a go.work `use` or a directory replace — rather than from a published module version (`go install …/cmd/forge@<version>`, or a host whose go.mod requires forge at a version, as every released `reliant` does).
A pseudo-version alone cannot tell the two apart: a checkout build and a `go install …@<pseudo>` both report one. What tells them apart is where the bytes came from. Only a local build is "the forge someone is working on"; a module build is exactly the forge its version names, and nothing more.
func PublishedFloor ¶ added in v0.1.45
func PublishedFloor() string
PublishedFloor returns the newest forge RELEASE this binary's source is known to descend from — the embedded VERSION file (e.g. "v0.1.17") — or "" when that file is missing or malformed.
It exists for the one question InstallableVersion must answer "" to: what should a module REQUIRE when this build itself is on no proxy? Requiring nothing is not neutral. `go mod tidy` never reads go.work, so a module that imports github.com/reliant-labs/forge/pkg/* with no forge requirement makes tidy go looking for a module that provides that import path — and the longest match on the proxy is the RETIRED github.com/reliant-labs/forge/pkg module. tidy writes that in, and the next `forge generate` refuses the project. The floor is a version the proxy DOES serve and that genuinely provides every forge/pkg package, so tidy resolves the require it already has instead of inventing one; a go.work bridge (the dev case) still decides what the build actually compiles.
func Set ¶
func Set(v, _, commit string)
Set records the forge binary's version metadata. It is intended to be called exactly once, from the main entrypoint. The date argument is accepted for call-site compatibility but is not currently retained.
func SetBuildDate ¶ added in v0.1.45
func SetBuildDate(d string)
SetBuildDate records the ldflags-stamped build date, which has no runtime/debug equivalent. Safe to call with "" (the embedded path, where nothing stamps one) — the clause is then omitted rather than rendered empty.
func SetCI ¶ added in v0.1.45
func SetCI(v bool)
SetCI pins IsCI's answer. Test-only seam — pair with ClearCI in a t.Cleanup.
func SetDevBuild ¶ added in v0.1.45
func SetDevBuild(v bool)
SetDevBuild overrides what IsDevBuild reports, bypassing the ambient binary build info. Test-only seam: build info is baked at compile time and is always the "(devel)" test binary under `go test`, so tests pin it here to exercise both the dev and release paths deterministically. Pair with ClearDevBuild in a t.Cleanup.
func SetDiscoveredForgeRoot ¶ added in v0.1.45
func SetDiscoveredForgeRoot(v string)
SetDiscoveredForgeRoot overrides what DiscoverDevForgeRootFromSource returns, bypassing the runtime.Caller walk. Test-only seam (pairs with SetDevBuild): pass "" to exercise the not-discoverable/hint path, or a fixture root to exercise the bridge path deterministically. Pair with ClearDiscoveredForgeRoot in a t.Cleanup.
func SetGitVersion ¶ added in v0.1.45
func SetGitVersion(v string)
SetGitVersion overrides what gitVersion returns. Test-only; pair with ClearGitVersion in a t.Cleanup.
func SourceRoot ¶ added in v0.1.45
func SourceRoot() string
SourceRoot is the local forge checkout this binary was compiled from — the ldflags stamp when a contributor build supplied one, otherwise recovered from the binary's compiled file paths — or "" when it has none (a release built with -trimpath, or a binary copied off the machine that built it).
func Version ¶
func Version() string
Version returns the forge binary's version. When the binary was produced by `go install ...@<ref>`, Set will not have been called with a real value, so we fall back to reading the module version from runtime build info.
Returns "dev" if neither source is available.
Types ¶
type Build ¶ added in v0.1.45
type Build struct {
// Version identifies FORGE, never the host binary. On an embedded
// build this is the version of the forge module dependency — reading
// the main module there would report the EMBEDDER's version, which is
// the bug that stamped `forge_version: v1.5.1-...` (a reliant version)
// into a scaffolded project's forge.yaml.
Version string
// Commit is the VCS revision the binary was built from.
Commit string
// BuildDate is the ldflags-stamped build date, if any.
BuildDate string
// Embedded reports whether forge is compiled into a host binary
// rather than running as its own executable.
Embedded bool
// Embedder / EmbedderVersion / EmbedderCommit name the host binary on
// an embedded build ("github.com/reliant-labs/reliant", "v1.5.1-...").
// The host's commit matters because an embedded forge only changes
// when the HOST is rebuilt — it is what pins which forge source ran.
Embedder string
EmbedderVersion string
EmbedderCommit string
// ReplacedBy is the local `replace` target the forge module resolved
// through, when there is one ("../forge"). A local replace is exactly
// the skew that makes two builds differ while reporting one version.
ReplacedBy string
}
Build is the identity that makes the two distinguishable. It is derived from the binary's own runtime/debug build info, so it works for anything `go install`/`go build` produced and needs no build-system change; ldflags stamps, when present, take precedence.
func Current ¶ added in v0.1.45
func Current() Build
Current returns this binary's forge identity, derived from its own build info plus whatever the entrypoint stamped via Set/SetVersion.
func (Build) Origin ¶ added in v0.1.45
Origin names how forge is being invoked, for error messages that must tell a user WHICH forge ran.
func (Build) String ¶ added in v0.1.45
String renders the identity as one line, omitting clauses it has no value for rather than padding them with empty parentheses. It carries no "forge" prefix: cobra's version template already renders "<name> version <this>", and the `version` subcommand adds its own label.
type ForgeRoot ¶ added in v1.0.0
ForgeRoot is a local forge checkout and how it was found.
func ResolveForgeRoot ¶ added in v1.0.0
ResolveForgeRoot finds the local forge checkout `forge project new --link-forge` bridges a project to.
Discovery used to rest on one thing: a path the compiler baked into the binary (an ldflag, or runtime.Caller). Any -trimpath build erases both, and the Reliant workspace image makes -trimpath the toolchain default, so --link-forge failed for every binary built there, and for `go test`. Now, first match wins:
- explicit, the --forge-root flag, else $FORGE_ROOT: a stated path is never second-guessed, and one that is not a forge checkout is an error;
- the DevForgeRoot ldflag a contributor build stamps;
- the source path compiled into this binary (runtime.Caller);
- the `replace github.com/reliant-labs/forge => <path>` in the build info of a host binary that embeds forge (reliant), resolved against the directories the binary and this process live under, since build info records the path as written in go.mod;
- the checkout the executable sits inside (bin/forge, go-build's output under the checkout);
- the checkout the process started in.
A module-cache copy is never a checkout (nothing to edit, read-only). ok is false when none is found; err is set only for a bad explicit path.
type Source ¶ added in v0.1.45
type Source struct {
// Revision is the forge commit (full or 12-char) the build recorded, or
// "" when it recorded none.
Revision string
// Modified reports the binary was built from a dirty forge tree.
Modified bool
// Tag is a release tag the build names but whose commit is not in build
// info (`go install …/cmd/forge@v0.1.44`). A caller with a checkout can
// resolve it there.
Tag string
// Embedded reports forge is compiled into a host binary (`reliant forge`).
Embedded bool
}
Source is the forge SOURCE this binary was compiled from, as far as its build recorded it. The version-skew check compares it with the checkout a project bridges to: generated code comes from this binary, the library it compiles against comes from that checkout, and the two must be one commit.
func ForgeSource ¶ added in v0.1.45
func ForgeSource() Source
ForgeSource reports the forge source this binary was compiled from.