diff --git a/api/tangled/knotversion.go b/api/tangled/knotversion.go new file mode 100644 --- /dev/null +++ b/api/tangled/knotversion.go @@ -0,0 +1,30 @@ +// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. + +package tangled + +// schema: sh.tangled.knot.version + +import ( + "context" + + "github.com/bluesky-social/indigo/lex/util" +) + +const ( + KnotVersionNSID = "sh.tangled.knot.version" +) + +// KnotVersion_Output is the output of a sh.tangled.knot.version call. +type KnotVersion_Output struct { + Version string `json:"version" cborgen:"version"` +} + +// KnotVersion calls the XRPC method "sh.tangled.knot.version". +func KnotVersion(ctx context.Context, c util.LexClient) (*KnotVersion_Output, error) { + var out KnotVersion_Output + if err := c.LexDo(ctx, util.Query, "", "sh.tangled.knot.version", nil, nil, &out); err != nil { + return nil, err + } + + return &out, nil +} diff --git a/knotserver/router.go b/knotserver/router.go --- a/knotserver/router.go +++ b/knotserver/router.go @@ -5,7 +5,6 @@ "context" "fmt" "log/slog" "net/http" - "runtime/debug" "github.com/go-chi/chi/v5" "tangled.sh/tangled.sh/core/idresolver" @@ -82,10 +81,7 @@ }) }) // xrpc apis - r.Route("/xrpc", func(r chi.Router) { - r.Get("/_health", h.Version) - r.Mount("/", h.XrpcRouter()) - }) + r.Mount("/xrpc", h.XrpcRouter()) // Socket that streams git oplogs r.Get("/events", h.Events) @@ -109,54 +105,6 @@ Resolver: h.resolver, ServiceAuth: serviceAuth, } return xrpc.Router() -} - -// version is set during build time. -var version string - -func (h *Knot) Version(w http.ResponseWriter, r *http.Request) { - if version == "" { - info, ok := debug.ReadBuildInfo() - if !ok { - http.Error(w, "failed to read build info", http.StatusInternalServerError) - return - } - - var modVer string - var sha string - var modified bool - - for _, mod := range info.Deps { - if mod.Path == "tangled.sh/tangled.sh/knotserver" { - modVer = mod.Version - break - } - } - - for _, setting := range info.Settings { - switch setting.Key { - case "vcs.revision": - sha = setting.Value - case "vcs.modified": - modified = setting.Value == "true" - } - } - - if modVer == "" { - modVer = "unknown" - } - - if sha == "" { - version = modVer - } else if modified { - version = fmt.Sprintf("%s (%s with modifications)", modVer, sha) - } else { - version = fmt.Sprintf("%s (%s)", modVer, sha) - } - } - - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - fmt.Fprintf(w, "knotserver/%s", version) } func (h *Knot) configureOwner() error { diff --git a/knotserver/xrpc/version.go b/knotserver/xrpc/version.go new file mode 100644 --- /dev/null +++ b/knotserver/xrpc/version.go @@ -0,0 +1,70 @@ +package xrpc + +import ( + "encoding/json" + "fmt" + "net/http" + "runtime/debug" + + "tangled.sh/tangled.sh/core/api/tangled" + xrpcerr "tangled.sh/tangled.sh/core/xrpc/errors" +) + +// version is set during build time. +var version string + +func (x *Xrpc) Version(w http.ResponseWriter, r *http.Request) { + if version == "" { + info, ok := debug.ReadBuildInfo() + if !ok { + http.Error(w, "failed to read build info", http.StatusInternalServerError) + return + } + + var modVer string + var sha string + var modified bool + + for _, mod := range info.Deps { + if mod.Path == "tangled.sh/tangled.sh/knotserver/xrpc" { + modVer = mod.Version + break + } + } + + for _, setting := range info.Settings { + switch setting.Key { + case "vcs.revision": + sha = setting.Value + case "vcs.modified": + modified = setting.Value == "true" + } + } + + if modVer == "" { + modVer = "unknown" + } + + if sha == "" { + version = modVer + } else if modified { + version = fmt.Sprintf("%s (%s with modifications)", modVer, sha) + } else { + version = fmt.Sprintf("%s (%s)", modVer, sha) + } + } + + response := tangled.KnotVersion_Output{ + Version: version, + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(response); err != nil { + x.Logger.Error("failed to encode response", "error", err) + writeError(w, xrpcerr.NewXrpcError( + xrpcerr.WithTag("InternalServerError"), + xrpcerr.WithMessage("failed to encode response"), + ), http.StatusInternalServerError) + return + } +} diff --git a/knotserver/xrpc/xrpc.go b/knotserver/xrpc/xrpc.go --- a/knotserver/xrpc/xrpc.go +++ b/knotserver/xrpc/xrpc.go @@ -69,6 +69,7 @@ r.Get("/"+tangled.RepoLanguagesNSID, x.RepoLanguages) // knot query endpoints (no auth required) r.Get("/"+tangled.KnotListKeysNSID, x.ListKeys) + r.Get("/"+tangled.KnotVersionNSID, x.Version) // service query endpoints (no auth required) r.Get("/"+tangled.OwnerNSID, x.Owner) diff --git a/lexicons/knot/version.json b/lexicons/knot/version.json new file mode 100644 --- /dev/null +++ b/lexicons/knot/version.json @@ -0,0 +1,25 @@ +{ + "lexicon": 1, + "id": "sh.tangled.knot.version", + "defs": { + "main": { + "type": "query", + "description": "Get the version of a knot", + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": [ + "version" + ], + "properties": { + "version": { + "type": "string" + } + } + } + }, + "errors": [] + } + } +} diff --git a/nix/pkgs/knot-unwrapped.nix b/nix/pkgs/knot-unwrapped.nix --- a/nix/pkgs/knot-unwrapped.nix +++ b/nix/pkgs/knot-unwrapped.nix @@ -4,15 +4,22 @@ modules, sqlite-lib, src, }: +let + version = "1.8.1-alpha"; +in buildGoApplication { pname = "knot"; - version = "0.1.0"; + version = "1.8.1"; inherit src modules; doCheck = false; subPackages = ["cmd/knot"]; tags = ["libsqlite3"]; + + ldflags = [ + "-X tangled.sh/tangled.sh/core/knotserver/xrpc.version=${version}" + ]; env.CGO_CFLAGS = "-I ${sqlite-lib}/include "; env.CGO_LDFLAGS = "-L ${sqlite-lib}/lib";