-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: embed version info into binary (#298)
(cherry picked from commit 6d5f489)
- Loading branch information
Showing
6 changed files
with
198 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package buildinfo | ||
|
||
import ( | ||
"fmt" | ||
"runtime/debug" | ||
"sync" | ||
|
||
"golang.org/x/mod/semver" | ||
) | ||
|
||
const ( | ||
noVersion = "v0.0.0" | ||
develPreRelease = "devel" | ||
) | ||
|
||
var ( | ||
buildInfo *debug.BuildInfo | ||
buildInfoValid bool | ||
readBuildInfo sync.Once | ||
|
||
version string | ||
readVersion sync.Once | ||
|
||
// Injected with ldflags at build time | ||
tag string | ||
) | ||
|
||
func revision() (string, bool) { | ||
return find("vcs.revision") | ||
} | ||
|
||
func find(key string) (string, bool) { | ||
readBuildInfo.Do(func() { | ||
buildInfo, buildInfoValid = debug.ReadBuildInfo() | ||
}) | ||
if !buildInfoValid { | ||
panic("could not read build info") | ||
} | ||
for _, setting := range buildInfo.Settings { | ||
if setting.Key != key { | ||
continue | ||
} | ||
return setting.Value, true | ||
} | ||
return "", false | ||
} | ||
|
||
// Version returns the semantic version of the build. | ||
// Use golang.org/x/mod/semver to compare versions. | ||
func Version() string { | ||
readVersion.Do(func() { | ||
revision, valid := revision() | ||
if valid { | ||
revision = "+" + revision[:7] | ||
} | ||
if tag == "" { | ||
// This occurs when the tag hasn't been injected, | ||
// like when using "go run". | ||
// <version>-<pre-release>+<revision> | ||
version = fmt.Sprintf("%s-%s%s", noVersion, develPreRelease, revision) | ||
return | ||
} | ||
version = "v" + tag | ||
// The tag must be prefixed with "v" otherwise the | ||
// semver library will return an empty string. | ||
if semver.Build(version) == "" { | ||
version += revision | ||
} | ||
}) | ||
return version | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#!/usr/bin/env bash | ||
|
||
# This script is meant to be sourced by other scripts. To source this script: | ||
# # shellcheck source=scripts/lib.sh | ||
# source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" | ||
|
||
set -euo pipefail | ||
|
||
# Avoid sourcing this script multiple times to guard against when lib.sh | ||
# is used by another sourced script, it can lead to confusing results. | ||
if [[ ${SCRIPTS_LIB_IS_SOURCED:-0} == 1 ]]; then | ||
return | ||
fi | ||
# Do not export to avoid this value being inherited by non-sourced | ||
# scripts. | ||
SCRIPTS_LIB_IS_SOURCED=1 | ||
|
||
# We have to define realpath before these otherwise it fails on Mac's bash. | ||
SCRIPT="${BASH_SOURCE[1]:-${BASH_SOURCE[0]}}" | ||
SCRIPT_DIR="$(realpath "$(dirname "$SCRIPT")")" | ||
|
||
function project_root { | ||
# Nix sets $src in derivations! | ||
[[ -n "${src:-}" ]] && echo "$src" && return | ||
|
||
# Try to use `git rev-parse --show-toplevel` to find the project root. | ||
# If this directory is not a git repository, this command will fail. | ||
git rev-parse --show-toplevel 2>/dev/null && return | ||
} | ||
|
||
PROJECT_ROOT="$(cd "$SCRIPT_DIR" && realpath "$(project_root)")" | ||
|
||
# cdroot changes directory to the root of the repository. | ||
cdroot() { | ||
cd "$PROJECT_ROOT" || error "Could not change directory to '$PROJECT_ROOT'" | ||
} | ||
|
||
# log prints a message to stderr | ||
log() { | ||
echo "$*" 1>&2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,78 @@ | ||
#!/usr/bin/env bash | ||
|
||
# This script generates the version string used by Envbuilder, including for dev | ||
# versions. Note: the version returned by this script will NOT include the "v" | ||
# prefix that is included in the Git tag. | ||
# | ||
# If $ENVBUILDER_RELEASE is set to "true", the returned version will equal the | ||
# current git tag. If the current commit is not tagged, this will fail. | ||
# | ||
# If $ENVBUILDER_RELEASE is not set, the returned version will always be a dev | ||
# version. | ||
|
||
set -euo pipefail | ||
cd "$(dirname "${BASH_SOURCE[0]}")" | ||
# shellcheck source=scripts/lib.sh | ||
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" | ||
cdroot | ||
|
||
if [[ -n "${ENVBUILDER_FORCE_VERSION:-}" ]]; then | ||
echo "${ENVBUILDER_FORCE_VERSION}" | ||
exit 0 | ||
fi | ||
|
||
# To make contributing easier, if there are no tags, we'll use a default | ||
# version. | ||
tag_list=$(git tag) | ||
if [[ -z ${tag_list} ]]; then | ||
log | ||
log "INFO(version.sh): It appears you've checked out a fork or shallow clone of Envbuilder." | ||
log "INFO(version.sh): By default GitHub does not include tags when forking." | ||
log "INFO(version.sh): We will use the default version 0.0.1 for this build." | ||
log "INFO(version.sh): To pull tags from upstream, use the following commands:" | ||
log "INFO(version.sh): - git remote add upstream https://github.com/coder/envbuilder.git" | ||
log "INFO(version.sh): - git fetch upstream" | ||
log | ||
last_tag="v0.0.1" | ||
else | ||
current_commit=$(git rev-parse HEAD) | ||
# Try to find the last tag that contains the current commit | ||
last_tag=$(git tag --contains "$current_commit" --sort=version:refname | head -n 1) | ||
# If there is no tag that contains the current commit, | ||
# get the latest tag sorted by semver. | ||
if [[ -z "${last_tag}" ]]; then | ||
last_tag=$(git tag --sort=version:refname | tail -n 1) | ||
fi | ||
fi | ||
|
||
version="${last_tag}" | ||
|
||
# If the HEAD has extra commits since the last tag then we are in a dev version. | ||
# | ||
# Dev versions are denoted by the "-dev+" suffix with a trailing commit short | ||
# SHA. | ||
if [[ "${ENVBUILDER_RELEASE:-}" == *t* ]]; then | ||
# $last_tag will equal `git describe --always` if we currently have the tag | ||
# checked out. | ||
if [[ "${last_tag}" != "$(git describe --always)" ]]; then | ||
# make won't exit on $(shell cmd) failures, so we have to kill it :( | ||
if [[ "$(ps -o comm= "${PPID}" || true)" == *make* ]]; then | ||
log "ERROR: version.sh: the current commit is not tagged with an annotated tag" | ||
kill "${PPID}" || true | ||
exit 1 | ||
fi | ||
|
||
error "version.sh: the current commit is not tagged with an annotated tag" | ||
fi | ||
else | ||
rev=$(git rev-parse --short HEAD) | ||
version="0.0.0+dev-${rev}" | ||
# If the git repo has uncommitted changes, mark the version string as 'dirty'. | ||
dirty_files=$(git ls-files --other --modified --exclude-standard) | ||
if [[ -n "${dirty_files}" ]]; then | ||
version+="-dirty" | ||
fi | ||
fi | ||
|
||
last_tag="$(git describe --tags --abbrev=0)" | ||
version="$last_tag" | ||
|
||
# Remove the "v" prefix. | ||
echo "${version#v}" |