The repository had no .gitattributes. With core.autocrlf=true a Windows checkout handed deploy/bootstrap.sh 2374 CRs, and bootstrap_asset.go embeds that file from the working tree verbatim, so a dev-built felis piped a CRLF script into `bash -s` on the target host. CI builds on Linux, which is why released binaries were clean and only local builds carried it. eol=lf is global rather than scoped to *.sh because go:embed reaches further than the installer: deploy/*/Dockerfile, deploy/*/entrypoint.sh, plugins/*/src, the migrations and internal/panel/static are all compiled in and read on Linux. *.bat is the one exception, for the gradle wrappers' Windows launchers. Renormalizing the index touched exactly one tracked file, cmd/felis/version.go, and only its line endings: `git diff --cached --ignore-cr-at-eol` reports nothing outside .gitattributes itself. TestBootstrapPinsViaBlockConnectionsOff used to strip \r\n before asserting, with a comment stating that the repository pinned no eol attribute. That is no longer true, and the stripping hid the regression this commit prevents. It now asserts the absence of CRs, so losing the attribute reports itself as line endings rather than as a missing serverside-blockconnections pin. Closes #5
67 lines
2.4 KiB
Go
67 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"runtime"
|
|
"runtime/debug"
|
|
)
|
|
|
|
// version is the build stamp injected at link time via
|
|
//
|
|
// -ldflags "-X main.version=v1.2.3" (release channel: the tag verbatim)
|
|
// -ldflags "-X main.version=v1.2.3+g1a2b3c4" (dev channel: tag + build metadata)
|
|
//
|
|
// deploy/bootstrap.sh computes it per install channel (FELIS_VERSION_BOOTSTRAP):
|
|
// the release channel stamps the resolved tag verbatim (v1.2.3), the dev channel
|
|
// stamps "<latest-tag>+g<short-sha>". It stays "dev" for an un-stamped local
|
|
// `go build`, where ReadBuildInfo below still surfaces the vcs revision.
|
|
//
|
|
// NOT `git describe`, for two reasons that both bite. Its "<tag>-<n>-g<sha>" form
|
|
// puts the distance in the PRERELEASE field, which sorts BELOW the bare tag, so a
|
|
// dev build ahead of v1.2.3 would compare as older than v1.2.3 and `felis update`
|
|
// would propose "upgrading" onto the release it already contains — hence "+", which
|
|
// is build metadata and ignored for ordering. And bootstrap's primary clone is
|
|
// --depth 1, which carries no tags, so describe would fall back to a bare SHA that
|
|
// updates.Parse rejects outright.
|
|
var version = "dev"
|
|
|
|
// cmdVersion prints the build stamp. It takes no flags and never touches the
|
|
// cluster, so it is safe to run as any user (unlike setup/breakGlass).
|
|
func cmdVersion(args []string, stdout, stderr io.Writer) int {
|
|
fmt.Fprintf(stdout, "felis %s\n", resolvedVersion())
|
|
fmt.Fprintf(stdout, " go: %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
|
if rev, ok := vcsRevision(); ok {
|
|
fmt.Fprintf(stdout, " revision: %s\n", rev)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// resolvedVersion prefers the ldflag stamp, then the module version recorded by
|
|
// `go install`, and only reports "unknown" when neither is present.
|
|
func resolvedVersion() string {
|
|
if version != "" {
|
|
return version
|
|
}
|
|
if bi, ok := debug.ReadBuildInfo(); ok && bi.Main.Version != "" {
|
|
return bi.Main.Version
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
// vcsRevision returns the git commit the binary was built from when the build
|
|
// carried VCS stamping (local `go build` in a checkout; the docker build strips
|
|
// .git, so there the ldflag version carries the identity instead).
|
|
func vcsRevision() (string, bool) {
|
|
bi, ok := debug.ReadBuildInfo()
|
|
if !ok {
|
|
return "", false
|
|
}
|
|
for _, s := range bi.Settings {
|
|
if s.Key == "vcs.revision" && s.Value != "" {
|
|
return s.Value, true
|
|
}
|
|
}
|
|
return "", false
|
|
}
|