Skip to content

Commit

Permalink
feat: Add version command
Browse files Browse the repository at this point in the history
When building with Go 1.18+ (we're on 1.22 now), we get version control
info in the binary! Since we don't set version numbers, the commit hash
(revision) is all we have to identify the version of the code that's
running.

This adds a `version` chat command that returns a formatted "current
build" string. It looks something like this:

    github.com/recursecenter/pairing-bot (1234567890abcdef1234567890abcdef12345678, built with go1.23.0)

And since it might be useful to us for debugging, this also prints the
whole buildinfo string at startup.
  • Loading branch information
jdkaplan committed Sep 4, 2024
1 parent 2b1dbba commit ccd2502
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 2 deletions.
2 changes: 2 additions & 0 deletions dispatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ func dispatch(ctx context.Context, pl *PairingLogic, cmd string, cmdArgs []strin
response = getCookieClubMessage()
case "help":
response = helpMessage
case "version":
response = pl.version
default:
// this won't execute because all input has been sanitized
// by parseCmd() and all cases are handled explicitly above
Expand Down
30 changes: 30 additions & 0 deletions dispatch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"context"
"testing"
)

func Test_dispatch(t *testing.T) {
ctx := context.Background()
projectID := fakeProjectID(t)

client := testFirestoreClient(t, ctx, projectID)

pl := &PairingLogic{
rdb: &FirestoreRecurserDB{client},
version: "test string",
}

t.Run("version", func(t *testing.T) {
resp, err := dispatch(ctx, pl, "version", nil, 0, "[email protected]", "Your Name")
if err != nil {
t.Fatal(err)
}

expected := "test string"
if resp != expected {
t.Errorf("expected %q, got %q", expected, resp)
}
})
}
35 changes: 34 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"log"
"net/http"
"os"
"runtime/debug"

"cloud.google.com/go/firestore"
"github.com/recursecenter/pairing-bot/zulip"
Expand All @@ -19,6 +20,16 @@ func main() {
// and the file:line (without the full path- we don't have directories.)
log.SetFlags(log.Ldate | log.Ltime | log.LUTC | log.Lshortfile)

// Pre-format the version string from built-in debug info.
var version string
if bi, ok := debug.ReadBuildInfo(); ok {
log.Print(bi)
version = formatVersion(bi)
} else {
log.Print("Warning: no build info in binary")
version = "(unknown)"
}

ctx := context.Background()

appEnv := os.Getenv("APP_ENV")
Expand Down Expand Up @@ -98,7 +109,8 @@ func main() {
rcapi: rcapi,
revdb: revdb,

zulip: zulipClient,
zulip: zulipClient,
version: version,
}

http.HandleFunc("/", http.NotFound) // will this handle anything that's not defined?
Expand All @@ -123,3 +135,24 @@ func main() {
log.Printf("Listening on port %s", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}

func formatVersion(bi *debug.BuildInfo) string {
goModule := bi.Path
goVersion := bi.GoVersion

var revision string
var modified string

for _, setting := range bi.Settings {
switch setting.Key {
case "vcs.revision":
revision = setting.Value
case "vcs.modified":
if setting.Value == "true" {
modified = "+"
}
}
}

return fmt.Sprintf("%s (%s%s, built with %s)", goModule, revision, modified, goVersion)
}
3 changes: 2 additions & 1 deletion pairing_bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ type PairingLogic struct {
revdb ReviewDB
rcapi RecurseAPI

zulip *zulip.Client
zulip *zulip.Client
version string
}

func (pl *PairingLogic) handle(w http.ResponseWriter, r *http.Request) {
Expand Down
3 changes: 3 additions & 0 deletions parse_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func parseCmd(cmdStr string) (string, []string, error) {
"add-review",
"get-reviews",
"cookie",
"version",
}

//This contains the days of the week and common abbreviations
Expand Down Expand Up @@ -116,6 +117,8 @@ func parseCmd(cmdStr string) (string, []string, error) {
}

return "schedule", userSchedule, err
case cmd[0] == "version":
return "version", nil, nil
default:
return cmd[0], cmd[1:], err
}
Expand Down
4 changes: 4 additions & 0 deletions parse_cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var tableNoArgs = []struct {
{"help_wrong_usage", "help me", "help", nil, true},
{"status_correct_usage", "status", "status", nil, false},
{"status_wrong_usage", "status me", "help", nil, true},
{"version", "version", "version", nil, false},
}

func TestParseCmdNoArgs(t *testing.T) {
Expand Down Expand Up @@ -73,6 +74,7 @@ var tableWithArgs = []struct {
{"unskip_wrong_usage", "unskip today", "help", nil, true},
{"unskip_wrong_usage", "unskip friday", "help", nil, true},
{"unskip_wrong_usage", "unskip", "help", nil, true},
{"version_extra_args_ok", "version info", "version", nil, false},
}

func TestParseCmdWithArgs(t *testing.T) {
Expand All @@ -98,6 +100,8 @@ func TestParseCmdWithArgs(t *testing.T) {
if gotArgs[0] != "tomorrow" {
t.Errorf("Wrong argument %v for command %v\n", gotArgs[0], gotCmd)
}
case "version":
// Always fine as long as the wantedCmd check passes.
default:
if gotCmd != "help" {
t.Errorf("unknown command %v\n", gotCmd)
Expand Down

0 comments on commit ccd2502

Please sign in to comment.