diff options
-rw-r--r-- | .github/workflows/cron.yml | 40 | ||||
-rw-r--r-- | Makefile | 13 | ||||
-rw-r--r-- | commands/root.go | 79 | ||||
-rw-r--r-- | commands/version.go | 87 | ||||
-rw-r--r-- | doc/generate.go | 2 | ||||
-rw-r--r-- | doc/man/git-bug-version.1 | 37 | ||||
-rw-r--r-- | doc/md/git-bug.md | 2 | ||||
-rw-r--r-- | doc/md/git-bug_version.md | 38 | ||||
-rw-r--r-- | main.go | 8 | ||||
-rw-r--r-- | misc/completion/generate.go | 2 | ||||
-rw-r--r-- | version.go | 94 |
11 files changed, 259 insertions, 143 deletions
diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml new file mode 100644 index 000000000..e68c9db05 --- /dev/null +++ b/.github/workflows/cron.yml @@ -0,0 +1,40 @@ +--- +name: cron + +on: + schedule: + - cron: '0 10 31 5 *' # 05/31 at 10:00 + +permissions: + contents: read + +jobs: + rename-default-branch: + runs-on: ubuntu-latest + if: github.ref_name == "master" + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: configure git remote + run: | + git remote set-url origin git@github.com:git-bug/git-bug.git + + - name: "merge pull request: 1464" + env: + GH_TOKEN: ${{ secrets.RENAME_TOKEN_1404 }} + run: gh pr merge 1464 --admin --squash + + - name: "set default branch: refs/heads/trunk" + env: + GH_TOKEN: ${{ secrets.RENAME_TOKEN_1404 }} + run: gh repo edit --default-branch trunk + + - name: "set base for all PRs: refs/heads/trunk" + env: + GH_TOKEN: ${{ secrets.RENAME_TOKEN_1404 }} + run: |- + for pr in $(gh pr list -B master -s open --json number --jq '.[] | .number'); do + gh pr edit "$pr" -B trunk + done @@ -1,8 +1,3 @@ -all: build - -GIT_COMMIT:=$(shell git rev-list -1 HEAD) -GIT_LAST_TAG:=$(shell git describe --abbrev=0 --tags 2>/dev/null || true) -GIT_EXACT_TAG:=$(shell git name-rev --name-only --tags HEAD) UNAME_S := $(shell uname -s) XARGS:=xargs -r ifeq ($(UNAME_S),Darwin) @@ -11,10 +6,10 @@ endif SYSTEM=$(shell nix eval --impure --expr 'builtins.currentSystem' --raw 2>/dev/null || echo '') -COMMANDS_PATH:=github.com/git-bug/git-bug/commands -LDFLAGS:=-X ${COMMANDS_PATH}.GitCommit="${GIT_COMMIT}" \ - -X ${COMMANDS_PATH}.GitLastTag="${GIT_LAST_TAG}" \ - -X ${COMMANDS_PATH}.GitExactTag="${GIT_EXACT_TAG}" +TAG:=$(shell git name-rev --name-only --tags HEAD) +LDFLAGS:=-X main.version="${TAG}" + +all: build .PHONY: list-checks list-checks: diff --git a/commands/root.go b/commands/root.go index 1a4109a3c..1b64b5090 100644 --- a/commands/root.go +++ b/commands/root.go @@ -1,25 +1,17 @@ -// Package commands contains the CLI commands package commands import ( - "fmt" "os" - "runtime/debug" "github.com/spf13/cobra" - bridgecmd "github.com/git-bug/git-bug/commands/bridge" - bugcmd "github.com/git-bug/git-bug/commands/bug" + "github.com/git-bug/git-bug/commands/bridge" + "github.com/git-bug/git-bug/commands/bug" "github.com/git-bug/git-bug/commands/execenv" - usercmd "github.com/git-bug/git-bug/commands/user" + "github.com/git-bug/git-bug/commands/user" ) -// These variables are initialized externally during the build. See the Makefile. -var GitCommit string -var GitLastTag string -var GitExactTag string - -func NewRootCommand() *cobra.Command { +func NewRootCommand(version string) *cobra.Command { cmd := &cobra.Command{ Use: execenv.RootCommandName, Short: "A bug tracker embedded in Git", @@ -33,7 +25,7 @@ the same git remote you are already using to collaborate with other people. PersistentPreRun: func(cmd *cobra.Command, args []string) { root := cmd.Root() - root.Version = getVersion() + root.Version = version }, // For the root command, force the execution of the PreRun @@ -80,64 +72,3 @@ the same git remote you are already using to collaborate with other people. return cmd } - -func Execute() { - if err := NewRootCommand().Execute(); err != nil { - os.Exit(1) - } -} - -func getVersion() string { - if GitExactTag == "undefined" { - GitExactTag = "" - } - - if GitExactTag != "" { - // we are exactly on a tag --> release version - return GitLastTag - } - - if GitLastTag != "" { - // not exactly on a tag --> dev version - return fmt.Sprintf("%s-dev-%.10s", GitLastTag, GitCommit) - } - - // we don't have commit information, try golang build info - if commit, dirty, err := getCommitAndDirty(); err == nil { - if dirty { - return fmt.Sprintf("dev-%.10s-dirty", commit) - } - return fmt.Sprintf("dev-%.10s", commit) - } - - return "dev-unknown" -} - -func getCommitAndDirty() (commit string, dirty bool, err error) { - info, ok := debug.ReadBuildInfo() - if !ok { - return "", false, fmt.Errorf("unable to read build info") - } - - var commitFound bool - - // get the commit and modified status - // (that is the flag for repository dirty or not) - for _, kv := range info.Settings { - switch kv.Key { - case "vcs.revision": - commit = kv.Value - commitFound = true - case "vcs.modified": - if kv.Value == "true" { - dirty = true - } - } - } - - if !commitFound { - return "", false, fmt.Errorf("no commit found") - } - - return commit, dirty, nil -} diff --git a/commands/version.go b/commands/version.go index 189a2e350..ffa4a180a 100644 --- a/commands/version.go +++ b/commands/version.go @@ -1,63 +1,66 @@ package commands import ( - "runtime" + "log/slog" "github.com/spf13/cobra" "github.com/git-bug/git-bug/commands/execenv" ) -type versionOptions struct { - number bool - commit bool - all bool -} +// TODO: 0.12.0: remove deprecated build vars +var ( + GitCommit string + GitLastTag string + GitExactTag string +) func newVersionCommand(env *execenv.Env) *cobra.Command { - options := versionOptions{} + return &cobra.Command{ + Use: "version", + Short: "Print version information", + Example: "git bug version", + Long: ` +Print version information. - cmd := &cobra.Command{ - Use: "version", - Short: "Show git-bug version information", - Run: func(cmd *cobra.Command, args []string) { - runVersion(env, options, cmd.Root()) - }, - } +Format: + git-bug <version> [commit[/dirty]] <compiler version> <platform> <arch> - flags := cmd.Flags() - flags.SortFlags = false +Format Description: + <version> may be one of: + - A semantic version string, prefixed with a "v", e.g. v1.2.3 + - "undefined" (if not provided, or built with an invalid version string) - flags.BoolVarP(&options.number, "number", "n", false, - "Only show the version number", - ) - flags.BoolVarP(&options.commit, "commit", "c", false, - "Only show the commit hash", - ) - flags.BoolVarP(&options.all, "all", "a", false, - "Show all version information", - ) + [commit], if present, is the commit hash that was checked out during the + build. This may be suffixed with '/dirty' if there were local file + modifications. This is indicative of your build being patched, or modified in + some way from the commit. - return cmd -} + <compiler version> is the version of the go compiler used for the build. -func runVersion(env *execenv.Env, opts versionOptions, root *cobra.Command) { - if opts.all { - env.Out.Printf("%s version: %s\n", execenv.RootCommandName, root.Version) - env.Out.Printf("System version: %s/%s\n", runtime.GOARCH, runtime.GOOS) - env.Out.Printf("Golang version: %s\n", runtime.Version()) - return - } + <platform> is the target platform (GOOS). - if opts.number { - env.Out.Println(root.Version) - return + <arch> is the target architecture (GOARCH). +`, + Run: func(cmd *cobra.Command, args []string) { + defer warnDeprecated() + env.Out.Printf("%s %s", execenv.RootCommandName, cmd.Root().Version) + }, } +} - if opts.commit { - env.Out.Println(GitCommit) - return +// warnDeprecated warns about deprecated build variables +// TODO: 0.12.0: remove support for old build tags +func warnDeprecated() { + msg := "please contact your package maintainer" + reason := "deprecated build variable" + if GitLastTag != "" { + slog.Warn(msg, "reason", reason, "name", "GitLastTag", "value", GitLastTag) + } + if GitExactTag != "" { + slog.Warn(msg, "reason", reason, "name", "GitExactTag", "value", GitExactTag) + } + if GitCommit != "" { + slog.Warn(msg, "reason", reason, "name", "GitCommit", "value", GitCommit) } - - env.Out.Printf("%s version: %s\n", execenv.RootCommandName, root.Version) } diff --git a/doc/generate.go b/doc/generate.go index 0001f1a77..005d9df76 100644 --- a/doc/generate.go +++ b/doc/generate.go @@ -34,7 +34,7 @@ func main() { wg.Add(1) go func(name string, f func(*cobra.Command) error) { defer wg.Done() - root := commands.NewRootCommand() + root := commands.NewRootCommand("") err := f(root) if err != nil { fmt.Printf(" - %s: FATAL\n", name) diff --git a/doc/man/git-bug-version.1 b/doc/man/git-bug-version.1 index 7183b696e..988849e8a 100644 --- a/doc/man/git-bug-version.1 +++ b/doc/man/git-bug-version.1 @@ -2,7 +2,7 @@ .TH "GIT-BUG" "1" "Apr 2019" "Generated from git-bug's source code" "" .SH NAME -git-bug-version - Show git-bug version information +git-bug-version - Print version information .SH SYNOPSIS @@ -10,25 +10,44 @@ git-bug-version - Show git-bug version information .SH DESCRIPTION -Show git-bug version information +Print version information. +.PP +Format: + git-bug [commit[/dirty]] -.SH OPTIONS -\fB-n\fP, \fB--number\fP[=false] - Only show the version number +.PP +Format Description: + may be one of: + - A semantic version string, prefixed with a "v", e.g. v1.2.3 + - "undefined" (if not provided, or built with an invalid version string) + +.PP +[commit], if present, is the commit hash that was checked out during the + build. This may be suffixed with '/dirty' if there were local file + modifications. This is indicative of your build being patched, or modified in + some way from the commit. .PP -\fB-c\fP, \fB--commit\fP[=false] - Only show the commit hash + is the version of the go compiler used for the build. .PP -\fB-a\fP, \fB--all\fP[=false] - Show all version information + is the target platform (GOOS). .PP + is the target architecture (GOARCH). + + +.SH OPTIONS \fB-h\fP, \fB--help\fP[=false] help for version +.SH EXAMPLE +.EX +git bug version +.EE + + .SH SEE ALSO \fBgit-bug(1)\fP diff --git a/doc/md/git-bug.md b/doc/md/git-bug.md index 03bebb65e..2ef0b7725 100644 --- a/doc/md/git-bug.md +++ b/doc/md/git-bug.md @@ -31,7 +31,7 @@ git-bug [flags] * [git-bug push](git-bug_push.md) - Push updates to a git remote * [git-bug termui](git-bug_termui.md) - Launch the terminal UI * [git-bug user](git-bug_user.md) - List identities -* [git-bug version](git-bug_version.md) - Show git-bug version information +* [git-bug version](git-bug_version.md) - Print version information * [git-bug webui](git-bug_webui.md) - Launch the web UI * [git-bug wipe](git-bug_wipe.md) - Wipe git-bug from the git repository diff --git a/doc/md/git-bug_version.md b/doc/md/git-bug_version.md index ceba8790f..a2569aff1 100644 --- a/doc/md/git-bug_version.md +++ b/doc/md/git-bug_version.md @@ -1,18 +1,46 @@ ## git-bug version -Show git-bug version information +Print version information + +### Synopsis + + +Print version information. + +Format: + git-bug <version> [commit[/dirty]] <compiler version> <platform> <arch> + +Format Description: + <version> may be one of: + - A semantic version string, prefixed with a "v", e.g. v1.2.3 + - "undefined" (if not provided, or built with an invalid version string) + + [commit], if present, is the commit hash that was checked out during the + build. This may be suffixed with '/dirty' if there were local file + modifications. This is indicative of your build being patched, or modified in + some way from the commit. + + <compiler version> is the version of the go compiler used for the build. + + <platform> is the target platform (GOOS). + + <arch> is the target architecture (GOARCH). + ``` git-bug version [flags] ``` +### Examples + +``` +git bug version +``` + ### Options ``` - -n, --number Only show the version number - -c, --commit Only show the commit hash - -a, --all Show all version information - -h, --help help for version + -h, --help help for version ``` ### SEE ALSO @@ -4,9 +4,15 @@ package main import ( + "os" + "github.com/git-bug/git-bug/commands" ) func main() { - commands.Execute() + v, _ := getVersion() + root := commands.NewRootCommand(v) + if err := root.Execute(); err != nil { + os.Exit(1) + } } diff --git a/misc/completion/generate.go b/misc/completion/generate.go index b64c1034f..5c6468121 100644 --- a/misc/completion/generate.go +++ b/misc/completion/generate.go @@ -26,7 +26,7 @@ func main() { wg.Add(1) go func(name string, f func(*cobra.Command) error) { defer wg.Done() - root := commands.NewRootCommand() + root := commands.NewRootCommand("") err := f(root) if err != nil { fmt.Printf(" - %s: %v\n", name, err) diff --git a/version.go b/version.go new file mode 100644 index 000000000..de9bd8753 --- /dev/null +++ b/version.go @@ -0,0 +1,94 @@ +package main + +import ( + "errors" + "fmt" + "runtime/debug" + "strings" + + "github.com/git-bug/git-bug/commands" + "golang.org/x/mod/semver" +) + +var ( + version = "undefined" +) + +// getVersion returns a string representing the version information defined when +// the binary was built, or a sane default indicating a local build. a string is +// always returned. an error may be returned along with the string in the event +// that we detect a local build but are unable to get build metadata. +// +// TODO: support validation of the version (that it's a real version) +// TODO: support notifying the user if their version is out of date +func getVersion() (string, error) { + var arch string + var commit string + var modified bool + var platform string + + var v strings.Builder + + // this supports overriding the default version if the deprecated var used + // for setting the exact version for releases is supplied. we are doing this + // in order to give downstream package maintainers a longer window to + // migrate. + // + // TODO: 0.12.0: remove support for old build tags + if version == "undefined" && commands.GitExactTag != "" { + version = commands.GitExactTag + } + + // automatically add the v prefix if it's missing + if version != "undefined" && !strings.HasPrefix(version, "v") { + version = fmt.Sprintf("v%s", version) + } + + // reset the version string to undefined if it is invalid + if ok := semver.IsValid(version); !ok { + version = "undefined" + } + + v.WriteString(version) + + info, ok := debug.ReadBuildInfo() + if !ok { + v.WriteString(fmt.Sprintf(" (no build info)\n")) + return v.String(), errors.New("unable to read build metadata") + } + + for _, kv := range info.Settings { + switch kv.Key { + case "GOOS": + platform = kv.Value + case "GOARCH": + arch = kv.Value + case "vcs.modified": + if kv.Value == "true" { + modified = true + } + case "vcs.revision": + commit = kv.Value + } + } + + if commit != "" { + v.WriteString(fmt.Sprintf(" %.12s", commit)) + } + + if modified { + v.WriteString("/dirty") + } + + v.WriteString(fmt.Sprintf(" %s", info.GoVersion)) + + if platform != "" { + v.WriteString(fmt.Sprintf(" %s", platform)) + } + + if arch != "" { + v.WriteString(fmt.Sprintf(" %s", arch)) + } + + return fmt.Sprint(v.String(), "\n"), nil +} |