Command: tusk version
Relevant source files
The following files were used as context for generating this wiki page:
The tusk version command provides a way to display the version information of the tusk-drift-cli binary. This is essential for debugging, reporting issues, and ensuring compatibility. The output includes the semantic version, the build timestamp, and the git commit hash from which the binary was built.
This information is not hardcoded but is injected into the binary at build time, a process tightly integrated with the project's release workflow.
Usage
The version information can be accessed in several ways:
- As a dedicated command:
tusk version - As a persistent flag on the root command:
tusk --versionortusk -v
All methods produce the same output, printing the version, build time, and git commit to standard output.
Example Output:
Version: v1.2.3
Build Time: 2023-10-27 10:00:00 UTC
Git Commit: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
Command Flags
The following flags trigger the version display. They are registered as persistent flags on the root command.
| Flag | Alias | Description | Source File |
|---|---|---|---|
--version | -v | Show version and exit. | cmd/root.go |
--ver | -V | Show version and exit (hidden alias). | cmd/root.go |
Sources: cmd/root.go:110-113
Architecture and Data Flow
The versioning feature is split across multiple packages to maintain a clean separation of concerns: command-line interface logic in cmd and version data management in internal/version.
The following diagram illustrates the execution flow when a user runs tusk --version.
This diagram shows the process from user command to the final output on the terminal.
Sources: cmd/root.go:40-47, internal/version/version.go:16-21
Command Registration (cmd/root.go)
The --version and -v flags are registered on the rootCmd in cmd/root.go. A PersistentPreRunE function is used to check if the showVersion flag was provided. If it was, the function calls version.PrintVersion() and exits the program, preventing any other command logic from running.
// cmd/root.go:40-47
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if showVersion {
version.PrintVersion()
os.Exit(0)
}
setupLogger()
...
Sources: cmd/root.go:40-47, cmd/root.go:110-113
Version Command (cmd/version.go)
In addition to the flags, a dedicated versionCmd is defined. This command's sole purpose is to call version.PrintVersion(). This provides a more explicit way for users to check the version.
// cmd/version.go:12-19
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number of Tusk",
Long: `All software has versions. This is Tusk's.`,
Run: func(cmd *cobra.Command, args []string) {
version.PrintVersion()
},
}
Sources: cmd/version.go:12-19
Version Data (internal/version/version.go)
The internal/version package is the single source of truth for version-related data and functions. It declares three key variables that are intended to be populated at build time.
| Variable | Description |
|---|---|
Version | The semantic version string (e.g., v1.2.3). |
BuildTime | The UTC timestamp of when the build occurred. |
GitCommit | The full git commit hash of the HEAD at build time. |
These variables are initialized with placeholder values.
// internal/version/version.go:8-12
var (
Version = "dev"
BuildTime = "n/a"
GitCommit = "n/a"
)
Sources: internal/version/version.go:8-12
The PrintVersion() function reads these variables and prints them in a formatted way.
// internal/version/version.go:16-21
func PrintVersion() {
fmt.Printf("Version: %s\n", Version)
fmt.Printf("Build Time: %s\n", BuildTime)
fmt.Printf("Git Commit: %s\n", GitCommit)
}
Sources: internal/version/version.go:16-21
Build-Time Version Injection
The Version, BuildTime, and GitCommit variables are populated during the go build process using linker flags (-ldflags). This mechanism allows metadata from the build environment (like git state and current time) to be embedded directly into the final binary.
The build command uses the -X flag to set the value of a string variable at a specific import path.
# CONTRIBUTING.md
VERSION=v1.2.3
BUILD_TIME=$(date -u '+%Y-%m-%d %H:%M:%S UTC')
GIT_COMMIT=$(git rev-parse HEAD)
go build \
-ldflags "-X github.com/Use-Tusk/tusk-drift-cli/internal/version.Version=${VERSION} \
-X github.com/Use-Tusk/tusk-drift-cli/internal/version.BuildTime=${BUILD_TIME} \
-X github.com/Use-Tusk/tusk-drift-cli/internal/version.GitCommit=${GIT_COMMIT}" \
-o tusk
Sources: CONTRIBUTING.md
This process is automated for releases via a GitHub Actions workflow that uses the same technique.
Release Process Integration
The versioning is tightly coupled with the release process, which is managed by the scripts/release.sh script. This script automates the version bumping and tagging process, which in turn triggers the release build on CI.
The release process flow is as follows:
This diagram outlines the automated release process from a developer's machine to a published GitHub Release.
Sources: scripts/release.sh
The script determines the next version number by parsing the latest git tag and incrementing either the patch or minor version number based on the developer's input.
# scripts/release.sh:81-96
# Parse current version (strip 'v' prefix)
VERSION="${LAST_TAG#v}"
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
# ...
# Increment based on bump type
case "$BUMP_TYPE" in
patch)
PATCH=$((PATCH + 1))
;;
minor)
MINOR=$((MINOR + 1))
PATCH=0
;;
esac
NEW_VERSION="v${MAJOR}.${MINOR}.${PATCH}"
Sources: scripts/release.sh:81-96
Once the new tag (e.g., v1.2.4) is pushed, a GitHub Actions workflow takes over to build the binaries for all supported platforms, embedding the correct version information using the -ldflags method described above.
Conclusion
The tusk version command and its underlying mechanism are critical components of the project's development and release lifecycle. By dynamically injecting version information at build time, the CLI provides accurate, verifiable metadata that is essential for user support, bug reporting, and maintaining a stable and predictable release process. The separation of concerns between command definition, data storage, and the build process ensures the system is robust and easy to maintain.