diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 86095a8..ce3765e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,9 @@ on: tags: ["v[0-9]+.[0-9]+.[0-9]+*"] permissions: - contents: read + # write rather than read: the job creates the GitHub Release the update notice + # reads. packages: write is for pushing the image. + contents: write packages: write jobs: @@ -50,3 +52,15 @@ jobs: VERSION=${{ github.ref_name }} cache-from: type=gha cache-to: type=gha,mode=max + + # A tag is not a release. The in-app update notice reads GitHub's + # releases/latest, which answers 404 for a repository that only has tags — + # so without this step the check can never find anything, however correctly + # it is switched on. + # + # Created after the image, so a release never announces a version that + # failed to build. + - uses: softprops/action-gh-release@v2 + with: + generate_release_notes: true + make_latest: true diff --git a/cmd/verdande/main.go b/cmd/verdande/main.go index c3cc72b..ebb587f 100644 --- a/cmd/verdande/main.go +++ b/cmd/verdande/main.go @@ -77,7 +77,11 @@ func run() error { errc := make(chan error, 1) go func() { - log.Info("listening", "addr", cfg.Addr) + // The version is repeated here rather than only on the "starting" line + // above: this is the line the Rune's done_regex matches, so it is the one + // sitting at the bottom of the panel console after a deploy — which is + // exactly when somebody wants to know what actually started. + log.Info("listening", "addr", cfg.Addr, "version", version) if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { errc <- err } diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 5b46c37..0bd9b8f 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1718,7 +1718,15 @@ paths: broken volume reports unhealthy instead of pretending to work. security: [] responses: - "200": { description: Healthy. } + "200": + description: Healthy. Carries the running version — the one thing you can ask without a session. + content: + application/json: + schema: + type: object + properties: + status: { type: string, const: ok } + version: { type: string, example: v0.3.1 } "503": { description: Unhealthy. } /ics/{token}: diff --git a/internal/httpapi/server.go b/internal/httpapi/server.go index e8c2951..0fbbd80 100644 --- a/internal/httpapi/server.go +++ b/internal/httpapi/server.go @@ -348,7 +348,11 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { }) return } - writeJSON(w, http.StatusOK, map[string]string{"status": "ok"}) + // The version travels with the health check because this is the one endpoint + // that answers without a session. "Which version is actually running?" is + // otherwise a question you cannot ask from outside — and after a deploy it is + // the first question there is. + writeJSON(w, http.StatusOK, map[string]string{"status": "ok", "version": Version}) } // serveWeb serves the PWA, falling back to index.html so that client-side routes diff --git a/rune/verdande.yaml b/rune/verdande.yaml index 4d09d15..699b192 100644 --- a/rune/verdande.yaml +++ b/rune/verdande.yaml @@ -11,7 +11,7 @@ gameskill: invites and reminders, then start it and open the URL to create the first admin account. author: "kristianwind" - version: 1 + version: 2 icon: "app" # The image is distroless — no shell — so keep_entrypoint runs the binary the @@ -70,6 +70,14 @@ gameskill: pattern: '^[0-9]+(ns|us|ms|s|m|h)$' hint: "must be a duration like 720h, 30m or 45s" + # Off by default because it is an outbound request nobody asked for. It sends + # no identifier and reads one public URL — GitHub's releases API — but that is + # a choice to make rather than a default to inherit. + - key: VERDANDE_UPDATE_CHECK + name: "Look for new releases (asks GitHub once a day; sends nothing about you)" + type: bool + default: false + install: # The image has no shell, so the install step borrows one. It only has to make # the directory layout exist; verdande creates and migrates its own database on