feat: make it possible to see which version is actually running
Release / Build and publish image (push) Failing after 9m56s
Release / Build and publish image (push) Failing after 9m56s
"I have updated and restarted, but I cannot tell whether it worked" is not a question the panel could answer. The version was on the startup line and in the settings page, and nowhere you can reach from outside. /healthz carries it now. That is the one endpoint answering without a session, which makes it the only way to ask the question from a terminal or from the panel itself. The "listening" line repeats it too, because that is the line the Rune's done_regex matches and therefore the one sitting at the bottom of the console after a deploy. The update notice could also never have worked. It reads GitHub's releases/latest, and this repository had only tags — a tag is not a release, and that endpoint answers 404 for a repository without any. The release workflow creates one now, after the image is pushed so a release never announces a version that failed to build. VERDANDE_UPDATE_CHECK is a Rune variable, so it can be switched on without editing the container. Still off by default: it is an outbound request, and that is a choice to make rather than a default to inherit. Rune version 1 -> 2, so the panel offers the update. Note that the check still cannot see anything while the repository is private — releases/latest is 404 anonymously, exactly as the GHCR package was. Making the repo public, or teaching the check to carry a token, is a separate decision. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Kristian Wind
co-authored by
Claude Opus 5
parent
78ec9b08a1
commit
0dbea0ea4b
@@ -6,7 +6,9 @@ on:
|
|||||||
tags: ["v[0-9]+.[0-9]+.[0-9]+*"]
|
tags: ["v[0-9]+.[0-9]+.[0-9]+*"]
|
||||||
|
|
||||||
permissions:
|
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
|
packages: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -50,3 +52,15 @@ jobs:
|
|||||||
VERSION=${{ github.ref_name }}
|
VERSION=${{ github.ref_name }}
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
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
|
||||||
|
|||||||
@@ -77,7 +77,11 @@ func run() error {
|
|||||||
|
|
||||||
errc := make(chan error, 1)
|
errc := make(chan error, 1)
|
||||||
go func() {
|
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) {
|
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
errc <- err
|
errc <- err
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -1718,7 +1718,15 @@ paths:
|
|||||||
broken volume reports unhealthy instead of pretending to work.
|
broken volume reports unhealthy instead of pretending to work.
|
||||||
security: []
|
security: []
|
||||||
responses:
|
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. }
|
"503": { description: Unhealthy. }
|
||||||
|
|
||||||
/ics/{token}:
|
/ics/{token}:
|
||||||
|
|||||||
@@ -348,7 +348,11 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
|
|||||||
})
|
})
|
||||||
return
|
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
|
// serveWeb serves the PWA, falling back to index.html so that client-side routes
|
||||||
|
|||||||
+9
-1
@@ -11,7 +11,7 @@ gameskill:
|
|||||||
invites and reminders, then start it and open the URL to create the first
|
invites and reminders, then start it and open the URL to create the first
|
||||||
admin account.
|
admin account.
|
||||||
author: "kristianwind"
|
author: "kristianwind"
|
||||||
version: 1
|
version: 2
|
||||||
icon: "app"
|
icon: "app"
|
||||||
|
|
||||||
# The image is distroless — no shell — so keep_entrypoint runs the binary the
|
# 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)$'
|
pattern: '^[0-9]+(ns|us|ms|s|m|h)$'
|
||||||
hint: "must be a duration like 720h, 30m or 45s"
|
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:
|
install:
|
||||||
# The image has no shell, so the install step borrows one. It only has to make
|
# 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
|
# the directory layout exist; verdande creates and migrates its own database on
|
||||||
|
|||||||
Reference in New Issue
Block a user