From 2b100e6eab7ee7a8643d548e8f3cacb5ce6b0cdc Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 5 Apr 2022 23:20:37 +0000 Subject: [PATCH 01/21] Add endpoint for getting build info For now it just returns the version. --- coderd/buildinfo.go | 16 ++++++++++++++++ coderd/buildinfo_test.go | 23 +++++++++++++++++++++++ coderd/coderd.go | 3 +++ codersdk/buildinfo.go | 28 ++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 coderd/buildinfo.go create mode 100644 coderd/buildinfo_test.go create mode 100644 codersdk/buildinfo.go diff --git a/coderd/buildinfo.go b/coderd/buildinfo.go new file mode 100644 index 0000000000000..384ab64d650cd --- /dev/null +++ b/coderd/buildinfo.go @@ -0,0 +1,16 @@ +package coderd + +import ( + "net/http" + + "github.com/go-chi/render" + + "github.com/coder/coder/cli/buildinfo" + "github.com/coder/coder/codersdk" +) + +func (*api) buildInfo(rw http.ResponseWriter, r *http.Request) { + render.JSON(rw, r, codersdk.BuildInfoResponse{ + Version: buildinfo.Version(), + }) +} diff --git a/coderd/buildinfo_test.go b/coderd/buildinfo_test.go new file mode 100644 index 0000000000000..35c16a4e85c72 --- /dev/null +++ b/coderd/buildinfo_test.go @@ -0,0 +1,23 @@ +package coderd_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/coder/coder/cli/buildinfo" + "github.com/coder/coder/coderd/coderdtest" +) + +func TestBuildInfo(t *testing.T) { + t.Parallel() + + t.Run("OK", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, nil) + buildInfo, err := client.BuildInfo(context.Background()) + require.NoError(t, err) + require.Equal(t, buildinfo.Version(), buildInfo.Version, "version") + }) +} diff --git a/coderd/coderd.go b/coderd/coderd.go index d60e975a726dd..13ca2d3b97c43 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -191,6 +191,9 @@ func New(options *Options) (http.Handler, func()) { r.Get("/logs", api.workspaceBuildLogs) r.Get("/resources", api.workspaceBuildResources) }) + r.Route("/buildinfo", func(r chi.Router) { + r.Get("/", api.buildInfo) + }) }) r.NotFound(site.DefaultHandler().ServeHTTP) return r, func() { diff --git a/codersdk/buildinfo.go b/codersdk/buildinfo.go new file mode 100644 index 0000000000000..3ef423e2aaaf5 --- /dev/null +++ b/codersdk/buildinfo.go @@ -0,0 +1,28 @@ +package codersdk + +import ( + "context" + "encoding/json" + "net/http" +) + +// BuildInfoResponse contains build information for this instance of Coder. +type BuildInfoResponse struct { + Version string `json:"version"` +} + +// BuildInfo returns build information for this instance of Coder. +func (c *Client) BuildInfo(ctx context.Context) (BuildInfoResponse, error) { + res, err := c.request(ctx, http.MethodGet, "/api/v2/buildinfo", nil) + if err != nil { + return BuildInfoResponse{}, err + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return BuildInfoResponse{}, readBodyAsError(res) + } + + var buildInfo BuildInfoResponse + return buildInfo, json.NewDecoder(res.Body).Decode(&buildInfo) +} From 6fef81ffe0731f893144ffae0e883e7cc83a9541 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 5 Apr 2022 22:13:42 +0000 Subject: [PATCH 02/21] Add build info XService --- site/src/api/index.ts | 5 ++ site/src/api/types.ts | 7 +++ site/src/xServices/StateContext.tsx | 15 ++++- .../xServices/buildInfo/buildInfoXService.ts | 62 +++++++++++++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 site/src/xServices/buildInfo/buildInfoXService.ts diff --git a/site/src/api/index.ts b/site/src/api/index.ts index 0d4ff993fb0ad..ce2847d3ce10f 100644 --- a/site/src/api/index.ts +++ b/site/src/api/index.ts @@ -68,3 +68,8 @@ export const getApiKey = async (): Promise => { const response = await axios.post("/api/v2/users/me/keys") return response.data } + +export const getBuildInfo = async (): Promise => { + const response = await axios.get("/api/v2/buildinfo") + return response.data +} diff --git a/site/src/api/types.ts b/site/src/api/types.ts index 0b700f0c459de..c5ca7ca578c79 100644 --- a/site/src/api/types.ts +++ b/site/src/api/types.ts @@ -66,3 +66,10 @@ export interface UserAgent { readonly ip_address: string readonly os: string } + +/** + * `BuildInfoResponse` must be kept in sync with the go struct in buildinfo.go. + */ +export interface BuildInfoResponse { + version: string +} diff --git a/site/src/xServices/StateContext.tsx b/site/src/xServices/StateContext.tsx index 26ba57465504a..d043f463c27fb 100644 --- a/site/src/xServices/StateContext.tsx +++ b/site/src/xServices/StateContext.tsx @@ -1,9 +1,11 @@ import { useInterpret } from "@xstate/react" import React, { createContext } from "react" import { ActorRefFrom } from "xstate" +import { buildInfoMachine } from "./buildInfo/buildInfoXService" import { userMachine } from "./user/userXService" interface XServiceContextType { + buildInfoXService: ActorRefFrom userXService: ActorRefFrom } @@ -18,7 +20,14 @@ interface XServiceContextType { export const XServiceContext = createContext({} as XServiceContextType) export const XServiceProvider: React.FC = ({ children }) => { - const userXService = useInterpret(userMachine) - - return {children} + return ( + + {children} + + ) } diff --git a/site/src/xServices/buildInfo/buildInfoXService.ts b/site/src/xServices/buildInfo/buildInfoXService.ts new file mode 100644 index 0000000000000..035bb04287589 --- /dev/null +++ b/site/src/xServices/buildInfo/buildInfoXService.ts @@ -0,0 +1,62 @@ +import { assign, createMachine } from "xstate" +import * as API from "../../api" +import * as Types from "../../api/types" + +export interface BuildInfoContext { + getBuildInfoError?: Error | unknown + buildInfo?: Types.BuildInfoResponse +} + +export const buildInfoMachine = createMachine( + { + tsTypes: {} as import("./buildInfoXService.typegen").Typegen0, + schema: { + context: {} as BuildInfoContext, + services: {} as { + getBuildInfo: { + data: Types.BuildInfoResponse + } + }, + }, + context: { + buildInfo: undefined, + }, + id: "buildInfoState", + initial: "gettingBuildInfo", + states: { + gettingBuildInfo: { + invoke: { + src: "getBuildInfo", + id: "getBuildInfo", + onDone: [ + { + actions: ["assignBuildInfo", "clearGetBuildInfoError"], + }, + ], + onError: [ + { + actions: "assignGetBuildInfoError", + }, + ], + }, + }, + }, + }, + { + services: { + getBuildInfo: API.getBuildInfo, + }, + actions: { + assignBuildInfo: assign({ + buildInfo: (_, event) => event.data, + }), + assignGetBuildInfoError: assign({ + getBuildInfoError: (_, event) => event.data, + }), + clearGetBuildInfoError: assign((context: BuildInfoContext) => ({ + ...context, + getBuildInfoError: undefined, + })), + }, + }, +) From c79bdd2c292850e4a8ae78b04f79e926d7077259 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 5 Apr 2022 23:27:27 +0000 Subject: [PATCH 03/21] Add version to page footer Partially addresses #376. --- site/src/components/Page/Footer.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/site/src/components/Page/Footer.tsx b/site/src/components/Page/Footer.tsx index b0f1e4b225439..e7d3b0c0ba403 100644 --- a/site/src/components/Page/Footer.tsx +++ b/site/src/components/Page/Footer.tsx @@ -1,9 +1,13 @@ import { makeStyles } from "@material-ui/core/styles" import Typography from "@material-ui/core/Typography" -import React from "react" +import { useActor } from "@xstate/react" +import React, { useContext } from "react" +import { XServiceContext } from "../../xServices/StateContext" export const Footer: React.FC = ({ children }) => { const styles = useFooterStyles() + const xServices = useContext(XServiceContext) + const [buildInfoState] = useActor(xServices.buildInfoXService) return (
@@ -15,7 +19,7 @@ export const Footer: React.FC = ({ children }) => {
- v2 0.0.0-prototype + Coder {buildInfoState.context.buildInfo?.version}
From 201c26497e71485518d3b107b5054b734f680038 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 5 Apr 2022 23:51:28 +0000 Subject: [PATCH 04/21] Sort buildinfo route alphabetically --- coderd/coderd.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coderd/coderd.go b/coderd/coderd.go index 13ca2d3b97c43..035e634de478e 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -57,6 +57,9 @@ func New(options *Options) (http.Handler, func()) { Message: "👋", }) }) + r.Route("/buildinfo", func(r chi.Router) { + r.Get("/", api.buildInfo) + }) r.Route("/files", func(r chi.Router) { r.Use( httpmw.ExtractAPIKey(options.Database, nil), @@ -191,9 +194,6 @@ func New(options *Options) (http.Handler, func()) { r.Get("/logs", api.workspaceBuildLogs) r.Get("/resources", api.workspaceBuildResources) }) - r.Route("/buildinfo", func(r chi.Router) { - r.Get("/", api.buildInfo) - }) }) r.NotFound(site.DefaultHandler().ServeHTTP) return r, func() { From 63dfcf1558ee642c3c0dadfae5d4e88971ef3057 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 5 Apr 2022 23:56:00 +0000 Subject: [PATCH 05/21] Unnest buildinfo route test --- coderd/buildinfo_test.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/coderd/buildinfo_test.go b/coderd/buildinfo_test.go index 35c16a4e85c72..077f5f4ae1b1d 100644 --- a/coderd/buildinfo_test.go +++ b/coderd/buildinfo_test.go @@ -12,12 +12,8 @@ import ( func TestBuildInfo(t *testing.T) { t.Parallel() - - t.Run("OK", func(t *testing.T) { - t.Parallel() - client := coderdtest.New(t, nil) - buildInfo, err := client.BuildInfo(context.Background()) - require.NoError(t, err) - require.Equal(t, buildinfo.Version(), buildInfo.Version, "version") - }) + client := coderdtest.New(t, nil) + buildInfo, err := client.BuildInfo(context.Background()) + require.NoError(t, err) + require.Equal(t, buildinfo.Version(), buildInfo.Version, "version") } From 7fc15704f4a4c7231005612a61a5d44693c76b12 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 5 Apr 2022 23:59:11 +0000 Subject: [PATCH 06/21] Move buildinfo route into coderd.go --- coderd/buildinfo.go | 16 ---------------- coderd/buildinfo_test.go | 19 ------------------- coderd/coderd.go | 9 +++++++++ coderd/coderd_test.go | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 35 deletions(-) delete mode 100644 coderd/buildinfo.go delete mode 100644 coderd/buildinfo_test.go diff --git a/coderd/buildinfo.go b/coderd/buildinfo.go deleted file mode 100644 index 384ab64d650cd..0000000000000 --- a/coderd/buildinfo.go +++ /dev/null @@ -1,16 +0,0 @@ -package coderd - -import ( - "net/http" - - "github.com/go-chi/render" - - "github.com/coder/coder/cli/buildinfo" - "github.com/coder/coder/codersdk" -) - -func (*api) buildInfo(rw http.ResponseWriter, r *http.Request) { - render.JSON(rw, r, codersdk.BuildInfoResponse{ - Version: buildinfo.Version(), - }) -} diff --git a/coderd/buildinfo_test.go b/coderd/buildinfo_test.go deleted file mode 100644 index 077f5f4ae1b1d..0000000000000 --- a/coderd/buildinfo_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package coderd_test - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/coder/coder/cli/buildinfo" - "github.com/coder/coder/coderd/coderdtest" -) - -func TestBuildInfo(t *testing.T) { - t.Parallel() - client := coderdtest.New(t, nil) - buildInfo, err := client.BuildInfo(context.Background()) - require.NoError(t, err) - require.Equal(t, buildinfo.Version(), buildInfo.Version, "version") -} diff --git a/coderd/coderd.go b/coderd/coderd.go index 035e634de478e..480c2e6d47249 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -7,15 +7,18 @@ import ( "time" "github.com/go-chi/chi/v5" + "github.com/go-chi/render" "google.golang.org/api/idtoken" chitrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi.v5" "cdr.dev/slog" + "github.com/coder/coder/cli/buildinfo" "github.com/coder/coder/coderd/awsidentity" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/httpapi" "github.com/coder/coder/coderd/httpmw" + "github.com/coder/coder/codersdk" "github.com/coder/coder/site" ) @@ -211,3 +214,9 @@ type api struct { websocketWaitMutex sync.Mutex websocketWaitGroup sync.WaitGroup } + +func (*api) buildInfo(rw http.ResponseWriter, r *http.Request) { + render.JSON(rw, r, codersdk.BuildInfoResponse{ + Version: buildinfo.Version(), + }) +} diff --git a/coderd/coderd_test.go b/coderd/coderd_test.go index ef360326b1d8e..bd042080859a8 100644 --- a/coderd/coderd_test.go +++ b/coderd/coderd_test.go @@ -1,11 +1,25 @@ package coderd_test import ( + "context" "testing" "go.uber.org/goleak" + + "github.com/stretchr/testify/require" + + "github.com/coder/coder/cli/buildinfo" + "github.com/coder/coder/coderd/coderdtest" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } + +func TestBuildInfo(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, nil) + buildInfo, err := client.BuildInfo(context.Background()) + require.NoError(t, err) + require.Equal(t, buildinfo.Version(), buildInfo.Version, "version") +} From 0eac73623df85e455373b46cc09e515175ca2712 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 00:00:18 +0000 Subject: [PATCH 07/21] Ensure 200 on buildinfo route --- coderd/coderd.go | 1 + 1 file changed, 1 insertion(+) diff --git a/coderd/coderd.go b/coderd/coderd.go index 480c2e6d47249..dbb328ccfd147 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -216,6 +216,7 @@ type api struct { } func (*api) buildInfo(rw http.ResponseWriter, r *http.Request) { + render.Status(r, http.StatusOK) render.JSON(rw, r, codersdk.BuildInfoResponse{ Version: buildinfo.Version(), }) From 0479d341d800f6f5fccc7f5175383179a806a6aa Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 00:27:12 +0000 Subject: [PATCH 08/21] Add frontend mock for buildinfo route --- site/src/components/Page/Footer.test.tsx | 3 ++- site/src/test_helpers/entities.ts | 6 +++++- site/src/test_helpers/handlers.ts | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/site/src/components/Page/Footer.test.tsx b/site/src/components/Page/Footer.test.tsx index e61694b93606a..e2420166b7890 100644 --- a/site/src/components/Page/Footer.test.tsx +++ b/site/src/components/Page/Footer.test.tsx @@ -1,6 +1,6 @@ import { screen } from "@testing-library/react" import React from "react" -import { render } from "../../test_helpers" +import { MockBuildInfo, render } from "../../test_helpers" import { Footer } from "./Footer" describe("Footer", () => { @@ -10,5 +10,6 @@ describe("Footer", () => { // Then await screen.findByText("Copyright", { exact: false }) + await screen.findByText(MockBuildInfo.version, { exact: false }) }) }) diff --git a/site/src/test_helpers/entities.ts b/site/src/test_helpers/entities.ts index 90743b7b0afc1..860746858fbef 100644 --- a/site/src/test_helpers/entities.ts +++ b/site/src/test_helpers/entities.ts @@ -1,9 +1,13 @@ -import { Organization, Project, Provisioner, UserAgent, UserResponse, Workspace } from "../api/types" +import { BuildInfoResponse, Organization, Project, Provisioner, UserAgent, UserResponse, Workspace } from "../api/types" export const MockSessionToken = { session_token: "my-session-token" } export const MockAPIKey = { key: "my-api-key" } +export const MockBuildInfo: BuildInfoResponse = { + version: "v99.999.9999+c9cdf14", +} + export const MockUser: UserResponse = { id: "test-user", username: "TestUser", diff --git a/site/src/test_helpers/handlers.ts b/site/src/test_helpers/handlers.ts index 5e558a4818e34..8d8d52ea38458 100644 --- a/site/src/test_helpers/handlers.ts +++ b/site/src/test_helpers/handlers.ts @@ -2,6 +2,11 @@ import { rest } from "msw" import * as M from "./entities" export const handlers = [ + // build info + rest.get("/api/v2/buildinfo", async (req, res, ctx) => { + return res(ctx.status(200), ctx.json(M.MockBuildInfo)) + }), + // organizations rest.get("/api/v2/organizations/:organizationId", async (req, res, ctx) => { return res(ctx.status(200), ctx.json(M.MockOrganization)) From 123d523cad067f68428d64faa130ee9ea6e7c787 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 00:27:35 +0000 Subject: [PATCH 09/21] Sort BuildInfoResponse alphabetically The rest of the file is not alphabetic but might as well. --- site/src/api/types.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/site/src/api/types.ts b/site/src/api/types.ts index c5ca7ca578c79..adbac30914fcf 100644 --- a/site/src/api/types.ts +++ b/site/src/api/types.ts @@ -1,3 +1,10 @@ +/** + * `BuildInfoResponse` must be kept in sync with the go struct in buildinfo.go. + */ +export interface BuildInfoResponse { + version: string +} + export interface LoginResponse { session_token: string } @@ -66,10 +73,3 @@ export interface UserAgent { readonly ip_address: string readonly os: string } - -/** - * `BuildInfoResponse` must be kept in sync with the go struct in buildinfo.go. - */ -export interface BuildInfoResponse { - version: string -} From cfc4bb88bfee853f59170ef9c06eae3d220781be Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 00:40:28 +0000 Subject: [PATCH 10/21] Inline buildinfo route handler --- coderd/coderd.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/coderd/coderd.go b/coderd/coderd.go index dbb328ccfd147..83ee3be71f0f8 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -61,7 +61,12 @@ func New(options *Options) (http.Handler, func()) { }) }) r.Route("/buildinfo", func(r chi.Router) { - r.Get("/", api.buildInfo) + r.Get("/", func(rw http.ResponseWriter, r *http.Request) { + render.Status(r, http.StatusOK) + render.JSON(rw, r, codersdk.BuildInfoResponse{ + Version: buildinfo.Version(), + }) + }) }) r.Route("/files", func(r chi.Router) { r.Use( @@ -214,10 +219,3 @@ type api struct { websocketWaitMutex sync.Mutex websocketWaitGroup sync.WaitGroup } - -func (*api) buildInfo(rw http.ResponseWriter, r *http.Request) { - render.Status(r, http.StatusOK) - render.JSON(rw, r, codersdk.BuildInfoResponse{ - Version: buildinfo.Version(), - }) -} From fc65c10afe15f121f8ee5e319ab94a7c9404249c Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 16:19:48 +0000 Subject: [PATCH 11/21] Skip version line when there is no build info --- site/src/components/Page/Footer.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/site/src/components/Page/Footer.tsx b/site/src/components/Page/Footer.tsx index e7d3b0c0ba403..056de6a128508 100644 --- a/site/src/components/Page/Footer.tsx +++ b/site/src/components/Page/Footer.tsx @@ -17,11 +17,13 @@ export const Footer: React.FC = ({ children }) => { {`Copyright \u00a9 ${new Date().getFullYear()} Coder Technologies, Inc. All rights reserved.`} -
- - Coder {buildInfoState.context.buildInfo?.version} - -
+ {buildInfoState.context.buildInfo && ( +
+ + Coder {buildInfoState.context.buildInfo.version} + +
+ )} ) } From aa96e283023af624eff26c94939cee04591505f5 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 16:24:11 +0000 Subject: [PATCH 12/21] Add language object to footer --- site/src/components/Page/Footer.test.tsx | 6 +++--- site/src/components/Page/Footer.tsx | 9 ++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/site/src/components/Page/Footer.test.tsx b/site/src/components/Page/Footer.test.tsx index e2420166b7890..ce891492eab81 100644 --- a/site/src/components/Page/Footer.test.tsx +++ b/site/src/components/Page/Footer.test.tsx @@ -1,7 +1,7 @@ import { screen } from "@testing-library/react" import React from "react" -import { MockBuildInfo, render } from "../../test_helpers" -import { Footer } from "./Footer" +import { render, MockBuildInfo } from "../../test_helpers" +import { Footer, Language } from "./Footer" describe("Footer", () => { it("renders content", async () => { @@ -10,6 +10,6 @@ describe("Footer", () => { // Then await screen.findByText("Copyright", { exact: false }) - await screen.findByText(MockBuildInfo.version, { exact: false }) + await screen.findByText(Language.buildInfoText(MockBuildInfo)) }) }) diff --git a/site/src/components/Page/Footer.tsx b/site/src/components/Page/Footer.tsx index 056de6a128508..0fefce13ddab8 100644 --- a/site/src/components/Page/Footer.tsx +++ b/site/src/components/Page/Footer.tsx @@ -2,8 +2,15 @@ import { makeStyles } from "@material-ui/core/styles" import Typography from "@material-ui/core/Typography" import { useActor } from "@xstate/react" import React, { useContext } from "react" +import { BuildInfoResponse } from "../../api/types" import { XServiceContext } from "../../xServices/StateContext" +export const Language = { + buildInfoText: (buildInfo: BuildInfoResponse) => { + return `Coder ${buildInfo.version}` + } +} + export const Footer: React.FC = ({ children }) => { const styles = useFooterStyles() const xServices = useContext(XServiceContext) @@ -20,7 +27,7 @@ export const Footer: React.FC = ({ children }) => { {buildInfoState.context.buildInfo && (
- Coder {buildInfoState.context.buildInfo.version} + {Language.buildInfoText(buildInfoState.context.buildInfo)}
)} From 409ff778b526f5ceb4c0e3325312a6618192d1f4 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 16:30:19 +0000 Subject: [PATCH 13/21] Lift buildinfo --- {cli/buildinfo => buildinfo}/buildinfo.go | 0 {cli/buildinfo => buildinfo}/buildinfo_test.go | 2 +- cli/root.go | 2 +- coderd/coderd.go | 2 +- coderd/coderd_test.go | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename {cli/buildinfo => buildinfo}/buildinfo.go (100%) rename {cli/buildinfo => buildinfo}/buildinfo_test.go (94%) diff --git a/cli/buildinfo/buildinfo.go b/buildinfo/buildinfo.go similarity index 100% rename from cli/buildinfo/buildinfo.go rename to buildinfo/buildinfo.go diff --git a/cli/buildinfo/buildinfo_test.go b/buildinfo/buildinfo_test.go similarity index 94% rename from cli/buildinfo/buildinfo_test.go rename to buildinfo/buildinfo_test.go index 15733afe2c2e0..9a92927a5b420 100644 --- a/cli/buildinfo/buildinfo_test.go +++ b/buildinfo/buildinfo_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/mod/semver" - "github.com/coder/coder/cli/buildinfo" + "github.com/coder/coder/buildinfo" ) func TestBuildInfo(t *testing.T) { diff --git a/cli/root.go b/cli/root.go index 65003b56fb07b..21cc197c88c2b 100644 --- a/cli/root.go +++ b/cli/root.go @@ -11,7 +11,7 @@ import ( "github.com/mattn/go-isatty" "github.com/spf13/cobra" - "github.com/coder/coder/cli/buildinfo" + "github.com/coder/coder/buildinfo" "github.com/coder/coder/cli/cliui" "github.com/coder/coder/cli/config" "github.com/coder/coder/codersdk" diff --git a/coderd/coderd.go b/coderd/coderd.go index 83ee3be71f0f8..ed1add162b5da 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -13,7 +13,7 @@ import ( chitrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi.v5" "cdr.dev/slog" - "github.com/coder/coder/cli/buildinfo" + "github.com/coder/coder/buildinfo" "github.com/coder/coder/coderd/awsidentity" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/httpapi" diff --git a/coderd/coderd_test.go b/coderd/coderd_test.go index bd042080859a8..543c8a7246a01 100644 --- a/coderd/coderd_test.go +++ b/coderd/coderd_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/coder/coder/cli/buildinfo" + "github.com/coder/coder/buildinfo" "github.com/coder/coder/coderd/coderdtest" ) From 57f6787a59f8c53bdc9ceb2bb8992a4367f37d6a Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 16:35:59 +0000 Subject: [PATCH 14/21] Add external url to build info response --- coderd/coderd.go | 3 ++- coderd/coderd_test.go | 1 + codersdk/buildinfo.go | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/coderd/coderd.go b/coderd/coderd.go index ed1add162b5da..5337f5af675cb 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -64,7 +64,8 @@ func New(options *Options) (http.Handler, func()) { r.Get("/", func(rw http.ResponseWriter, r *http.Request) { render.Status(r, http.StatusOK) render.JSON(rw, r, codersdk.BuildInfoResponse{ - Version: buildinfo.Version(), + ExternalURL: buildinfo.ExternalURL(), + Version: buildinfo.Version(), }) }) }) diff --git a/coderd/coderd_test.go b/coderd/coderd_test.go index 543c8a7246a01..73d3c3d308def 100644 --- a/coderd/coderd_test.go +++ b/coderd/coderd_test.go @@ -21,5 +21,6 @@ func TestBuildInfo(t *testing.T) { client := coderdtest.New(t, nil) buildInfo, err := client.BuildInfo(context.Background()) require.NoError(t, err) + require.Equal(t, buildinfo.ExternalURL(), buildInfo.ExternalURL, "external URL") require.Equal(t, buildinfo.Version(), buildInfo.Version, "version") } diff --git a/codersdk/buildinfo.go b/codersdk/buildinfo.go index 3ef423e2aaaf5..a3aecc1ffdfed 100644 --- a/codersdk/buildinfo.go +++ b/codersdk/buildinfo.go @@ -8,6 +8,11 @@ import ( // BuildInfoResponse contains build information for this instance of Coder. type BuildInfoResponse struct { + // ExternalURL is a URL referencing the current Coder version. For production + // builds, this will link directly to a release. For development builds, this + // will link to a commit. + ExternalURL string `json:"external_url"` + // Version returns the semantic version of the build. Version string `json:"version"` } From 987b89de5382bd97dbe1dc25a1b88ac0caed7078 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 16:53:23 +0000 Subject: [PATCH 15/21] Link footer build info to external url --- site/src/api/types.ts | 1 + site/src/components/Page/Footer.test.tsx | 2 +- site/src/components/Page/Footer.tsx | 13 ++++++------- site/src/test_helpers/entities.ts | 1 + 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/site/src/api/types.ts b/site/src/api/types.ts index adbac30914fcf..dd0e9ed19d9c9 100644 --- a/site/src/api/types.ts +++ b/site/src/api/types.ts @@ -2,6 +2,7 @@ * `BuildInfoResponse` must be kept in sync with the go struct in buildinfo.go. */ export interface BuildInfoResponse { + external_url: string version: string } diff --git a/site/src/components/Page/Footer.test.tsx b/site/src/components/Page/Footer.test.tsx index ce891492eab81..9b8e4898183ff 100644 --- a/site/src/components/Page/Footer.test.tsx +++ b/site/src/components/Page/Footer.test.tsx @@ -1,6 +1,6 @@ import { screen } from "@testing-library/react" import React from "react" -import { render, MockBuildInfo } from "../../test_helpers" +import { MockBuildInfo, render } from "../../test_helpers" import { Footer, Language } from "./Footer" describe("Footer", () => { diff --git a/site/src/components/Page/Footer.tsx b/site/src/components/Page/Footer.tsx index 0fefce13ddab8..729546c78b14b 100644 --- a/site/src/components/Page/Footer.tsx +++ b/site/src/components/Page/Footer.tsx @@ -1,3 +1,4 @@ +import Link from "@material-ui/core/Link" import { makeStyles } from "@material-ui/core/styles" import Typography from "@material-ui/core/Typography" import { useActor } from "@xstate/react" @@ -8,7 +9,7 @@ import { XServiceContext } from "../../xServices/StateContext" export const Language = { buildInfoText: (buildInfo: BuildInfoResponse) => { return `Coder ${buildInfo.version}` - } + }, } export const Footer: React.FC = ({ children }) => { @@ -25,10 +26,10 @@ export const Footer: React.FC = ({ children }) => { {buildInfoState.context.buildInfo && ( -
- +
+ {Language.buildInfoText(buildInfoState.context.buildInfo)} - +
)}
@@ -42,11 +43,9 @@ const useFooterStyles = makeStyles((theme) => ({ flex: "0", }, copyRight: { - backgroundColor: theme.palette.background.default, margin: theme.spacing(0.25), }, - version: { - backgroundColor: theme.palette.background.default, + buildInfo: { margin: theme.spacing(0.25), }, })) diff --git a/site/src/test_helpers/entities.ts b/site/src/test_helpers/entities.ts index 860746858fbef..19ed4625b6671 100644 --- a/site/src/test_helpers/entities.ts +++ b/site/src/test_helpers/entities.ts @@ -5,6 +5,7 @@ export const MockSessionToken = { session_token: "my-session-token" } export const MockAPIKey = { key: "my-api-key" } export const MockBuildInfo: BuildInfoResponse = { + external_url: "file:///mock-url", version: "v99.999.9999+c9cdf14", } From 4c310582f181f1d69549c9718a6dd3c29b2c92d9 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 16:55:27 +0000 Subject: [PATCH 16/21] Add TODO for adding retry to frontend API calls --- site/src/xServices/buildInfo/buildInfoXService.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/site/src/xServices/buildInfo/buildInfoXService.ts b/site/src/xServices/buildInfo/buildInfoXService.ts index 035bb04287589..a0f1304fb5343 100644 --- a/site/src/xServices/buildInfo/buildInfoXService.ts +++ b/site/src/xServices/buildInfo/buildInfoXService.ts @@ -7,6 +7,8 @@ export interface BuildInfoContext { buildInfo?: Types.BuildInfoResponse } +// TODO@asher: Add retry. Maybe make it general for any API call (depending on +// the type of error)? export const buildInfoMachine = createMachine( { tsTypes: {} as import("./buildInfoXService.typegen").Typegen0, From 86d4a016c7bffa58b78261fe464f9b5a30d0ae9b Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 16:59:53 +0000 Subject: [PATCH 17/21] Add missing return type --- site/src/components/Page/Footer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/components/Page/Footer.tsx b/site/src/components/Page/Footer.tsx index 729546c78b14b..0ac758f470591 100644 --- a/site/src/components/Page/Footer.tsx +++ b/site/src/components/Page/Footer.tsx @@ -7,7 +7,7 @@ import { BuildInfoResponse } from "../../api/types" import { XServiceContext } from "../../xServices/StateContext" export const Language = { - buildInfoText: (buildInfo: BuildInfoResponse) => { + buildInfoText: (buildInfo: BuildInfoResponse): string => { return `Coder ${buildInfo.version}` }, } From 228ab5e76e833e5d60a6623b5ac96467f647a34b Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 6 Apr 2022 20:59:14 +0000 Subject: [PATCH 18/21] Run make fmt Looks like one line got one character too long after the merge. --- site/src/test_helpers/entities.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/site/src/test_helpers/entities.ts b/site/src/test_helpers/entities.ts index 35edb838db649..b3f6614e63ba3 100644 --- a/site/src/test_helpers/entities.ts +++ b/site/src/test_helpers/entities.ts @@ -1,4 +1,12 @@ -import { BuildInfoResponse, Organization, Provisioner, Template, UserAgent, UserResponse, Workspace } from "../api/types" +import { + BuildInfoResponse, + Organization, + Provisioner, + Template, + UserAgent, + UserResponse, + Workspace, +} from "../api/types" export const MockSessionToken = { session_token: "my-session-token" } From 49adf163c2c39401a0752dee913c00e8c5408580 Mon Sep 17 00:00:00 2001 From: Asher Date: Thu, 7 Apr 2022 15:36:44 +0000 Subject: [PATCH 19/21] Remove todo in favor of GitHub issue --- site/src/xServices/buildInfo/buildInfoXService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/site/src/xServices/buildInfo/buildInfoXService.ts b/site/src/xServices/buildInfo/buildInfoXService.ts index a0f1304fb5343..035bb04287589 100644 --- a/site/src/xServices/buildInfo/buildInfoXService.ts +++ b/site/src/xServices/buildInfo/buildInfoXService.ts @@ -7,8 +7,6 @@ export interface BuildInfoContext { buildInfo?: Types.BuildInfoResponse } -// TODO@asher: Add retry. Maybe make it general for any API call (depending on -// the type of error)? export const buildInfoMachine = createMachine( { tsTypes: {} as import("./buildInfoXService.typegen").Typegen0, From 55833fb9a5797344d240d4f7494f6b22ce8e34cd Mon Sep 17 00:00:00 2001 From: Asher Date: Thu, 7 Apr 2022 16:02:32 +0000 Subject: [PATCH 20/21] Clear build info on error --- site/src/xServices/buildInfo/buildInfoXService.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/site/src/xServices/buildInfo/buildInfoXService.ts b/site/src/xServices/buildInfo/buildInfoXService.ts index 035bb04287589..8583fb6c8ef18 100644 --- a/site/src/xServices/buildInfo/buildInfoXService.ts +++ b/site/src/xServices/buildInfo/buildInfoXService.ts @@ -35,7 +35,7 @@ export const buildInfoMachine = createMachine( ], onError: [ { - actions: "assignGetBuildInfoError", + actions: ["assignGetBuildInfoError", "clearBuildInfo"], }, ], }, @@ -50,6 +50,10 @@ export const buildInfoMachine = createMachine( assignBuildInfo: assign({ buildInfo: (_, event) => event.data, }), + clearBuildInfo: assign((context: BuildInfoContext) => ({ + ...context, + buildInfo: undefined, + })), assignGetBuildInfoError: assign({ getBuildInfoError: (_, event) => event.data, }), From 20c7be35d3628f2bf0a3afe53280b61ceb5b04cb Mon Sep 17 00:00:00 2001 From: Asher Date: Thu, 7 Apr 2022 16:56:34 +0000 Subject: [PATCH 21/21] Add success and failure states to buildInfo machine --- site/src/xServices/buildInfo/buildInfoXService.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/site/src/xServices/buildInfo/buildInfoXService.ts b/site/src/xServices/buildInfo/buildInfoXService.ts index 8583fb6c8ef18..2c428b2ec2460 100644 --- a/site/src/xServices/buildInfo/buildInfoXService.ts +++ b/site/src/xServices/buildInfo/buildInfoXService.ts @@ -31,15 +31,23 @@ export const buildInfoMachine = createMachine( onDone: [ { actions: ["assignBuildInfo", "clearGetBuildInfoError"], + target: "#buildInfoState.success", }, ], onError: [ { actions: ["assignGetBuildInfoError", "clearBuildInfo"], + target: "#buildInfoState.failure", }, ], }, }, + success: { + type: "final", + }, + failure: { + type: "final", + }, }, }, {