mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-09-10 01:27:11 +00:00
chore: update Go server version handling and enhance Docker build process
This commit is contained in:
@@ -117,6 +117,7 @@ jobs:
|
||||
build-args: |
|
||||
BETTERDESK_COMMIT_SHA=${{ github.sha }}
|
||||
BETTERDESK_IMAGE_VERSION=${{ needs.read-version.outputs.version }}
|
||||
BETTERDESK_PRODUCT_VERSION=${{ needs.read-version.outputs.version }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
platforms: linux/amd64,linux/arm64
|
||||
@@ -222,6 +223,7 @@ jobs:
|
||||
build-args: |
|
||||
BETTERDESK_COMMIT_SHA=${{ github.sha }}
|
||||
BETTERDESK_IMAGE_VERSION=${{ needs.read-version.outputs.version }}
|
||||
BETTERDESK_PRODUCT_VERSION=${{ needs.read-version.outputs.version }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
@@ -41,9 +41,7 @@ jobs:
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add VERSION web-nodejs/package.json betterdesk.sh betterdesk.ps1 betterdesk-docker.sh \
|
||||
CHANGELOG.md README.md Dockerfile Dockerfile.server Dockerfile.console \
|
||||
docker-compose.quick.yml docker/entrypoint.sh docker-entrypoint.sh
|
||||
git add $(node scripts/bump-version.js --list-paths)
|
||||
if git diff --cached --quiet; then
|
||||
echo "No version files changed — skipping commit"
|
||||
exit 0
|
||||
|
||||
@@ -46,9 +46,7 @@ jobs:
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add VERSION web-nodejs/package.json betterdesk.sh betterdesk.ps1 betterdesk-docker.sh \
|
||||
CHANGELOG.md README.md Dockerfile Dockerfile.server Dockerfile.console \
|
||||
docker-compose.quick.yml docker/entrypoint.sh docker-entrypoint.sh
|
||||
git add $(node scripts/bump-version.js --list-paths)
|
||||
BRANCH="release/v${NEW_VERSION}"
|
||||
git checkout -b "$BRANCH"
|
||||
git commit -m "chore: release version ${NEW_VERSION} [version-bump]"
|
||||
|
||||
@@ -5,6 +5,8 @@ on:
|
||||
branches: [main, dev]
|
||||
paths:
|
||||
- 'VERSION'
|
||||
- 'betterdesk-server/VERSION'
|
||||
- 'betterdesk-server/internal/productversion/VERSION'
|
||||
- 'web-nodejs/package.json'
|
||||
- 'betterdesk.sh'
|
||||
- 'betterdesk.ps1'
|
||||
@@ -21,6 +23,8 @@ on:
|
||||
branches: [main, dev]
|
||||
paths:
|
||||
- 'VERSION'
|
||||
- 'betterdesk-server/VERSION'
|
||||
- 'betterdesk-server/internal/productversion/VERSION'
|
||||
- 'web-nodejs/package.json'
|
||||
- 'betterdesk.sh'
|
||||
- 'betterdesk.ps1'
|
||||
|
||||
+4
-1
@@ -27,8 +27,11 @@ COPY betterdesk-server/go.mod betterdesk-server/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY betterdesk-server/ .
|
||||
|
||||
ARG BETTERDESK_PRODUCT_VERSION=dev
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||
-ldflags="-s -w" \
|
||||
-ldflags="-s -w -X main.Version=${BETTERDESK_PRODUCT_VERSION}" \
|
||||
-tags "netgo osusergo" \
|
||||
-o /betterdesk-server .
|
||||
|
||||
|
||||
+3
-1
@@ -21,9 +21,11 @@ RUN go mod download
|
||||
# Copy full source
|
||||
COPY betterdesk-server/ .
|
||||
|
||||
ARG BETTERDESK_PRODUCT_VERSION=dev
|
||||
|
||||
# Build static binary (modernc.org/sqlite is pure Go — no CGO needed)
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||
-ldflags="-s -w" \
|
||||
-ldflags="-s -w -X main.Version=${BETTERDESK_PRODUCT_VERSION}" \
|
||||
-tags "netgo osusergo" \
|
||||
-o /betterdesk-server .
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
3.2.15
|
||||
@@ -0,0 +1 @@
|
||||
3.2.15
|
||||
@@ -0,0 +1,19 @@
|
||||
// Package productversion exposes the embedded BetterDesk product semver.
|
||||
package productversion
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:embed VERSION
|
||||
var embedded []byte
|
||||
|
||||
// Product returns the embedded product version (X.Y.Z) or "dev" when unset.
|
||||
func Product() string {
|
||||
v := strings.TrimSpace(string(embedded))
|
||||
if v == "" {
|
||||
return "dev"
|
||||
}
|
||||
return v
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package productversion
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestProduct_notEmpty(t *testing.T) {
|
||||
v := Product()
|
||||
if v == "" {
|
||||
t.Fatal("Product() returned empty string")
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/unitronix/betterdesk-server/config"
|
||||
"github.com/unitronix/betterdesk-server/crypto"
|
||||
"github.com/unitronix/betterdesk-server/db"
|
||||
"github.com/unitronix/betterdesk-server/internal/productversion"
|
||||
"github.com/unitronix/betterdesk-server/logging"
|
||||
"github.com/unitronix/betterdesk-server/metrics"
|
||||
"github.com/unitronix/betterdesk-server/ratelimit"
|
||||
@@ -41,6 +42,14 @@ var (
|
||||
BuildDate = "unknown"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if Version == "dev" {
|
||||
if v := productversion.Product(); v != "" && v != "dev" {
|
||||
Version = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := parseFlags()
|
||||
|
||||
|
||||
+1
-1
@@ -1419,7 +1419,7 @@ compile_go_server() {
|
||||
go mod download
|
||||
|
||||
# Build with optimizations
|
||||
CGO_ENABLED=0 go build -ldflags="-s -w" -o "$output_name" .
|
||||
CGO_ENABLED=0 go build -ldflags="-s -w -X main.Version=${VERSION}" -o "$output_name" .
|
||||
|
||||
if [ -f "$output_name" ]; then
|
||||
chmod +x "$output_name"
|
||||
|
||||
@@ -28,13 +28,13 @@
|
||||
# (issue #186): use service_started (not service_healthy), pin image tags, and
|
||||
# set DB_PATH=/app/data/db_v2.sqlite3 plus AUTH_DB_PATH on the server.
|
||||
#
|
||||
# Image tag (aligned with CHANGELOG / git tag v3.2.14):
|
||||
# Default: 3.2.14 | Rolling: BETTERDESK_IMAGE_TAG=latest
|
||||
# Image tag (aligned with CHANGELOG / git tag v3.2.15):
|
||||
# Default: 3.2.15 | Rolling: BETTERDESK_IMAGE_TAG=latest
|
||||
# =============================================================================
|
||||
|
||||
services:
|
||||
server:
|
||||
image: ghcr.io/unitronix/betterdesk-server:${BETTERDESK_IMAGE_TAG:-3.2.14}
|
||||
image: ghcr.io/unitronix/betterdesk-server:${BETTERDESK_IMAGE_TAG:-3.2.15}
|
||||
container_name: betterdesk-server
|
||||
hostname: betterdesk-server
|
||||
command: ["/usr/local/bin/betterdesk-server", "-mode", "all", "-api-port", "21114", "-key-file", "/opt/rustdesk/id_ed25519"]
|
||||
@@ -70,7 +70,7 @@ services:
|
||||
start_period: 60s
|
||||
|
||||
console:
|
||||
image: ghcr.io/unitronix/betterdesk-console:${BETTERDESK_IMAGE_TAG:-3.2.14}
|
||||
image: ghcr.io/unitronix/betterdesk-console:${BETTERDESK_IMAGE_TAG:-3.2.15}
|
||||
container_name: betterdesk-console
|
||||
# Shares server network stack — panel and RustDesk ports use MACVLAN_IPV4.
|
||||
network_mode: service:server
|
||||
@@ -97,7 +97,7 @@ services:
|
||||
- WS_HBBR_PORT=21117
|
||||
- DOCKER=true
|
||||
- BETTERDESK_UPDATE_MODE=image
|
||||
- BETTERDESK_IMAGE_TAG=${BETTERDESK_IMAGE_TAG:-3.2.14}
|
||||
- BETTERDESK_IMAGE_TAG=${BETTERDESK_IMAGE_TAG:-3.2.15}
|
||||
- TZ=${TZ:-UTC}
|
||||
depends_on:
|
||||
# service_started (not healthy): avoids deadlock with auth.db on first boot (#138, #186).
|
||||
|
||||
@@ -39,7 +39,8 @@ Every automated bump updates these together:
|
||||
**Tier 1**
|
||||
|
||||
- `VERSION`
|
||||
- `web-nodejs/package.json`
|
||||
- `web-nodejs/package.json` (npm mirror; panel reads root `VERSION` via `web-nodejs/lib/productVersion.js`)
|
||||
- `betterdesk-server/VERSION` and `betterdesk-server/internal/productversion/VERSION` (Go `go:embed` + builds)
|
||||
- `betterdesk.sh`, `betterdesk.ps1`, `betterdesk-docker.sh`
|
||||
- `CHANGELOG.md` (moves `[Unreleased]` → new section)
|
||||
- `README.md` (version badge)
|
||||
@@ -47,9 +48,11 @@ Every automated bump updates these together:
|
||||
**Tier 2 (Docker)**
|
||||
|
||||
- `Dockerfile`, `Dockerfile.server`, `Dockerfile.console`
|
||||
- `docker-compose.quick.yml`
|
||||
- `docker-compose.quick.yml`, `docker-compose.quick.macvlan.yml`
|
||||
- `docker/entrypoint.sh`, `docker-entrypoint.sh`
|
||||
|
||||
The web console and Go server should report the **same product semver** after a normal install, panel update, or release build. Settings → Server Information shows both the product version and the live Go server version from `/api/health`.
|
||||
|
||||
Sub-project versions (`betterdesk-mgmt`, `betterdesk-agent-client`, SDKs) are **not** bumped with the main product unless explicitly requested.
|
||||
|
||||
### Maintainer commands
|
||||
@@ -58,6 +61,9 @@ Sub-project versions (`betterdesk-mgmt`, `betterdesk-agent-client`, SDKs) are **
|
||||
# Verify all Tier 1/2 files match VERSION (CI runs this too)
|
||||
node scripts/bump-version.js --verify
|
||||
|
||||
# List every path touched by automated bumps (used by CI git add)
|
||||
node scripts/bump-version.js --list-paths
|
||||
|
||||
# Manual bump (normally CI handles this)
|
||||
node scripts/bump-version.js --patch # +0.0.1
|
||||
node scripts/bump-version.js --minor # +0.1.0
|
||||
|
||||
+33
-1
@@ -152,8 +152,30 @@ const FILE_RULES = [
|
||||
`\${BETTERDESK_IMAGE_VERSION:-${version}}`
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'betterdesk-server-version',
|
||||
path: 'betterdesk-server/VERSION',
|
||||
extract: (content) => content.trim(),
|
||||
apply: (_content, version) => `${version}\n`,
|
||||
},
|
||||
{
|
||||
id: 'betterdesk-server-productversion-embed',
|
||||
path: 'betterdesk-server/internal/productversion/VERSION',
|
||||
extract: (content) => content.trim(),
|
||||
apply: (_content, version) => `${version}\n`,
|
||||
},
|
||||
];
|
||||
|
||||
const CHANGELOG_PATH = 'CHANGELOG.md';
|
||||
|
||||
function getManagedPaths() {
|
||||
const paths = FILE_RULES.map((rule) => rule.path);
|
||||
if (!paths.includes(CHANGELOG_PATH)) {
|
||||
paths.push(CHANGELOG_PATH);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
function escapeRegExp(value) {
|
||||
return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
@@ -308,12 +330,13 @@ function verifyVersions() {
|
||||
}
|
||||
|
||||
function printUsage() {
|
||||
console.log(`Usage: node scripts/bump-version.js [--patch | --minor | --set X.Y.Z] [--dry-run] [--verify]
|
||||
console.log(`Usage: node scripts/bump-version.js [--patch | --minor | --set X.Y.Z] [--dry-run] [--verify] [--list-paths]
|
||||
|
||||
--patch Bump patch (+0.0.1)
|
||||
--minor Bump minor (+0.1.0, reset patch)
|
||||
--set X.Y.Z Set explicit version
|
||||
--verify Exit 1 if Tier 1/2 files disagree with VERSION
|
||||
--list-paths Print managed file paths (one per line) for CI git add
|
||||
--dry-run Print planned version without writing files`);
|
||||
}
|
||||
|
||||
@@ -321,6 +344,14 @@ function main() {
|
||||
const args = process.argv.slice(2);
|
||||
const dryRun = args.includes('--dry-run');
|
||||
const verify = args.includes('--verify');
|
||||
const listPaths = args.includes('--list-paths');
|
||||
|
||||
if (listPaths) {
|
||||
for (const filePath of getManagedPaths()) {
|
||||
console.log(filePath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (verify) {
|
||||
verifyVersions();
|
||||
@@ -365,6 +396,7 @@ if (require.main === module) {
|
||||
|
||||
module.exports = {
|
||||
FILE_RULES,
|
||||
getManagedPaths,
|
||||
readCanonicalVersion,
|
||||
bumpPatch,
|
||||
bumpMinor,
|
||||
|
||||
@@ -30,12 +30,8 @@ if (fs.existsSync(_envFile)) {
|
||||
} catch (_e) { /* .env read failed — continue with existing env vars */ }
|
||||
}
|
||||
|
||||
// Read version from package.json
|
||||
let pkgVersion = '2.0.0';
|
||||
try {
|
||||
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
||||
pkgVersion = pkg.version || pkgVersion;
|
||||
} catch (e) { /* use default */ }
|
||||
const { readProductVersion } = require('../lib/productVersion');
|
||||
const pkgVersion = readProductVersion({ consoleDir: path.join(__dirname, '..') });
|
||||
|
||||
// Environment / platform detection
|
||||
const NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
||||
@@ -582,7 +582,9 @@
|
||||
"enrollment_tag_picker": "اختر علامات من علامات الأجهزة الموجودة",
|
||||
"enrollment_tag_picker_hint": "يتيح للمشغلين اختيار علامات من القائمة المستخدمة في صفحة الأجهزة بدلًا من الكتابة فقط.",
|
||||
"enrollment_open_requests": "فتح طلبات التسجيل",
|
||||
"enrollment_pending_count": "{count} طلب تسجيل معلق"
|
||||
"enrollment_pending_count": "{count} طلب تسجيل معلق",
|
||||
"go_server_version": "خادم Go",
|
||||
"go_server_version_dev_hint": "الثنائي Go يبلغ عن بناء تطويري — أعد البناء أو حدّث الخادم ليطابق إصدار المنتج"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "Wybor tagow z listy istniejacych",
|
||||
"enrollment_tag_picker_hint": "Umozliwia wybor tagow z listy uzywanej na stronie Urzadzenia zamiast samego wpisywania.",
|
||||
"enrollment_open_requests": "Otworz zadania rejestracji",
|
||||
"enrollment_pending_count": "{count} oczekujacych zadan rejestracji"
|
||||
"enrollment_pending_count": "{count} oczekujacych zadan rejestracji",
|
||||
"go_server_version": "Go server",
|
||||
"go_server_version_dev_hint": "Binární Go server hlásí vývojovou sestavu — přestavte nebo aktualizujte server, aby odpovídal verzi produktu"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Čas",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"advanced_file_build-env": "Agent-Build-Umgebung (/etc/betterdesk/build.env)",
|
||||
"advanced_file_docker-supervisord": "Docker: supervisord.conf (supervisor-konfiguration)",
|
||||
"advanced_file_docker-compose": "Docker: docker-compose.yml (orkestrering)",
|
||||
"advanced_restart_none": "Für diese Fil ist kein Tjenesteneustart erforderlich."
|
||||
"advanced_restart_none": "Für diese Fil ist kein Tjenesteneustart erforderlich.",
|
||||
"go_server_version": "Go-server",
|
||||
"go_server_version_dev_hint": "Go-binær rapporterer udviklingsbuild — genopbyg eller opdater serveren for at matche produktversionen"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "Tags aus vorhandenen Geräte-Tags auswählen",
|
||||
"enrollment_tag_picker_hint": "Ermöglicht Operatoren, Tags aus der auf der Geräteseite verwendeten Liste auszuwählen, anstatt nur zu tippen.",
|
||||
"enrollment_open_requests": "Offene Registrierungsanfragen",
|
||||
"enrollment_pending_count": "{count} ausstehende Registrierungsanfrage(n)"
|
||||
"enrollment_pending_count": "{count} ausstehende Registrierungsanfrage(n)",
|
||||
"go_server_version": "Go-Server",
|
||||
"go_server_version_dev_hint": "Go-Binary meldet Entwicklungsbuild — Server neu bauen oder aktualisieren, um die Produktversion anzugleichen"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Zeit",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"totp_recovery_warning": "Save these recovery codes in a safe place. Each code can only be used once. If you lose access to your authenticator app, you can use these codes to log in.",
|
||||
"totp_done": "Done",
|
||||
"totp_disable_warning": "Disabling two-factor authentication will make your account less secure. Enter your password to confirm.",
|
||||
"totp_disabled_success": "Two-factor authentication has been disabled."
|
||||
"totp_disabled_success": "Two-factor authentication has been disabled.",
|
||||
"go_server_version": "Go server",
|
||||
"go_server_version_dev_hint": "Go binary reports development build — rebuild or update the server to match the product version"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "Elegir etiquetas de las etiquetas de dispositivos existentes",
|
||||
"enrollment_tag_picker_hint": "Permite a los operadores seleccionar etiquetas de la lista usada en la página de Dispositivos en lugar de solo escribirlas.",
|
||||
"enrollment_open_requests": "Solicitudes de inscripción abiertas",
|
||||
"enrollment_pending_count": "{count} solicitud(es) de inscripción pendiente(s)"
|
||||
"enrollment_pending_count": "{count} solicitud(es) de inscripción pendiente(s)",
|
||||
"go_server_version": "Servidor Go",
|
||||
"go_server_version_dev_hint": "El binario Go informa compilación de desarrollo — recompile o actualice el servidor para igualar la versión del producto"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Hora",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"advanced_file_build-env": "Agent-Build-Umgebung (/etc/betterdesk/build.env)",
|
||||
"advanced_file_docker-supervisord": "Docker: supervisord.conf (supervisor-asetukset)",
|
||||
"advanced_file_docker-compose": "Docker: docker-compose.yml (orkestrointi)",
|
||||
"advanced_restart_none": "Für diese Tiedosto ist kein Palveluneustart erforderlich."
|
||||
"advanced_restart_none": "Für diese Tiedosto ist kein Palveluneustart erforderlich.",
|
||||
"go_server_version": "Go-palvelin",
|
||||
"go_server_version_dev_hint": "Go-binääri raportoi kehitysversion — rakenna palvelin uudelleen tai päivitä se vastaamaan tuoteversiota"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "Sélectionner des tags parmi les tags d'appareils existants",
|
||||
"enrollment_tag_picker_hint": "Permet aux opérateurs de sélectionner des tags dans la liste utilisée sur la page Appareils plutôt que de les saisir uniquement.",
|
||||
"enrollment_open_requests": "Demandes d'inscription ouvertes",
|
||||
"enrollment_pending_count": "{count} demande(s) d'inscription en attente"
|
||||
"enrollment_pending_count": "{count} demande(s) d'inscription en attente",
|
||||
"go_server_version": "Serveur Go",
|
||||
"go_server_version_dev_hint": "Le binaire Go signale une build de développement — reconstruisez ou mettez à jour le serveur pour correspondre à la version produit"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Heure",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"enrollment_tag_picker": "मौजूदा डिवाइस टैग से टैग चुनें",
|
||||
"enrollment_tag_picker_hint": "ऑपरेटरों को केवल टाइप करने की बजाय डिवाइस पेज पर उपयोग की गई टैग सूची से चुनने देता है।",
|
||||
"enrollment_open_requests": "नामांकन अनुरोध खोलें",
|
||||
"enrollment_pending_count": "{count} लंबित नामांकन अनुरोध"
|
||||
"enrollment_pending_count": "{count} लंबित नामांकन अनुरोध",
|
||||
"go_server_version": "Go सर्वर",
|
||||
"go_server_version_dev_hint": "Go बाइनरी विकास बिल्ड की सूचना देता है — उत्पाद संस्करण से मेल खाने के लिए सर्वर को पुनर्निर्माण या अपडेट करें"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"advanced_file_build-env": "Agent-Build-Umgebung (/etc/betterdesk/build.env)",
|
||||
"advanced_file_docker-supervisord": "Docker: supervisord.conf (supervisor konfiguráció)",
|
||||
"advanced_file_docker-compose": "Docker: docker-compose.yml (orchestráció)",
|
||||
"advanced_restart_none": "Für diese Fájl ist kein Szolgáltatásneustart erforderlich."
|
||||
"advanced_restart_none": "Für diese Fájl ist kein Szolgáltatásneustart erforderlich.",
|
||||
"go_server_version": "Go szerver",
|
||||
"go_server_version_dev_hint": "A Go bináris fejlesztői buildet jelez — építse újra vagy frissítse a szervert a termékverzióhoz"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"enrollment_tag_picker": "Pilih tag dari tag perangkat yang ada",
|
||||
"enrollment_tag_picker_hint": "Memungkinkan operator memilih tag dari daftar di halaman Perangkat alih-alih hanya mengetik.",
|
||||
"enrollment_open_requests": "Buka permintaan pendaftaran",
|
||||
"enrollment_pending_count": "{count} permintaan pendaftaran tertunda"
|
||||
"enrollment_pending_count": "{count} permintaan pendaftaran tertunda",
|
||||
"go_server_version": "Server Go",
|
||||
"go_server_version_dev_hint": "Biner Go melaporkan build pengembangan — bangun ulang atau perbarui server agar sesuai versi produk"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "Sèlectionner des tags parmi les tags d'dispositivi existants",
|
||||
"enrollment_tag_picker_hint": "Permet aux opèrateurs de sèlectionner des tags dall'elenco utilisèe sur la page Dispositivi plutôt que de les saisir uniquement.",
|
||||
"enrollment_open_requests": "Demandes d'inscription ouvertes",
|
||||
"enrollment_pending_count": "{count} demande(s) d'inscription en attesa"
|
||||
"enrollment_pending_count": "{count} demande(s) d'inscription en attesa",
|
||||
"go_server_version": "Server Go",
|
||||
"go_server_version_dev_hint": "Il binario Go segnala build di sviluppo — ricompilare o aggiornare il server per allineare la versione prodotto"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Ora",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "既存のデバイスタグからタグを選択",
|
||||
"enrollment_tag_picker_hint": "オペレーターがデバイスページで使用されるタグリストから選択できます(手動入力のみに限定されません)。",
|
||||
"enrollment_open_requests": "登録リクエストを開く",
|
||||
"enrollment_pending_count": "{count} 件の保留中の登録リクエスト"
|
||||
"enrollment_pending_count": "{count} 件の保留中の登録リクエスト",
|
||||
"go_server_version": "Goサーバー",
|
||||
"go_server_version_dev_hint": "Goバイナリが開発ビルドを報告しています — 製品バージョンに合わせてサーバーを再ビルドまたは更新してください"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "기존 기기 태그에서 태그 선택",
|
||||
"enrollment_tag_picker_hint": "운영자가 기기 페이지에서 사용되는 태그 목록에서 선택할 수 있습니다(입력만으로 제한되지 않음).",
|
||||
"enrollment_open_requests": "등록 요청 열기",
|
||||
"enrollment_pending_count": "대기 중인 등록 요청 {count}건"
|
||||
"enrollment_pending_count": "대기 중인 등록 요청 {count}건",
|
||||
"go_server_version": "Go 서버",
|
||||
"go_server_version_dev_hint": "Go 바이너리가 개발 빌드를 보고합니다 — 제품 버전과 일치하도록 서버를 다시 빌드하거나 업데이트하세요"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"advanced_file_build-env": "Agent-Build-Umgebung (/etc/betterdesk/build.env)",
|
||||
"advanced_file_docker-supervisord": "Docker: supervisord.conf (supervisor-konfigurasjon)",
|
||||
"advanced_file_docker-compose": "Docker: docker-compose.yml (orkestrering)",
|
||||
"advanced_restart_none": "Für diese Fil ist kein Tjenesteneustart erforderlich."
|
||||
"advanced_restart_none": "Für diese Fil ist kein Tjenesteneustart erforderlich.",
|
||||
"go_server_version": "Go-server",
|
||||
"go_server_version_dev_hint": "Go-binæren rapporterer utviklingsbuild — bygg på nytt eller oppdater serveren for å matche produktversjonen"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "Tags aus vorhandenen Gerate-Tags auswahlen",
|
||||
"enrollment_tag_picker_hint": "Ermoglicht Operatoren, Tags aus der auf der Gerateseite verwendeten Liste auszuwahlen, anstatt nur zu tippen.",
|
||||
"enrollment_open_requests": "Offene Registrierungsanfragen",
|
||||
"enrollment_pending_count": "{count} ausstehende Registrierungsanfrage(n)"
|
||||
"enrollment_pending_count": "{count} ausstehende Registrierungsanfrage(n)",
|
||||
"go_server_version": "Go-server",
|
||||
"go_server_version_dev_hint": "Go-binary meldt ontwikkelbuild — herbouw of werk de server bij om de productversie te matchen"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Tijd",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"totp_recovery_warning": "Zapisz te kody odzyskiwania w bezpiecznym miejscu. Każdy kod może być użyty tylko raz. Jeśli stracisz dostęp do aplikacji uwierzytelniającej, możesz użyć tych kodów do zalogowania.",
|
||||
"totp_done": "Gotowe",
|
||||
"totp_disable_warning": "Wyłączenie uwierzytelniania dwuskładnikowego zmniejszy bezpieczeństwo konta. Wprowadź hasło, aby potwierdzić.",
|
||||
"totp_disabled_success": "Uwierzytelnianie dwuskładnikowe zostało wyłączone."
|
||||
"totp_disabled_success": "Uwierzytelnianie dwuskładnikowe zostało wyłączone.",
|
||||
"go_server_version": "Serwer Go",
|
||||
"go_server_version_dev_hint": "Binarny serwer Go zgłasza build deweloperski — przebuduj lub zaktualizuj serwer, aby dopasować wersję produktu"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Czas",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "Escolher etiquetas de las etiquetas de dispositivos existentes",
|
||||
"enrollment_tag_picker_hint": "Permite aos operadores selecionar etiquetas de la lista usada en la página de Dispositivos em vez de solo escribirlas.",
|
||||
"enrollment_open_requests": "Pedidos de registo abiertas",
|
||||
"enrollment_pending_count": "{count} solicitud(es) de registo pendente(s)"
|
||||
"enrollment_pending_count": "{count} solicitud(es) de registo pendente(s)",
|
||||
"go_server_version": "Servidor Go",
|
||||
"go_server_version_dev_hint": "O binário Go reporta build de desenvolvimento — recompile ou atualize o servidor para corresponder à versão do produto"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Hora",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"advanced_file_build-env": "Agent-Build-Umgebung (/etc/betterdesk/build.env)",
|
||||
"advanced_file_docker-supervisord": "Docker: supervisord.conf (configurare supervisord)",
|
||||
"advanced_file_docker-compose": "Docker: docker-compose.yml (orchestrare)",
|
||||
"advanced_restart_none": "Für diese Fișier ist kein Serviciuneustart erforderlich."
|
||||
"advanced_restart_none": "Für diese Fișier ist kein Serviciuneustart erforderlich.",
|
||||
"go_server_version": "Server Go",
|
||||
"go_server_version_dev_hint": "Binarul Go raportează build de dezvoltare — reconstruiți sau actualizați serverul pentru a corespunde versiunii produsului"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"advanced_file_build-env": "Agent-Build-Umgebung (/etc/betterdesk/build.env)",
|
||||
"advanced_file_docker-supervisord": "Docker: supervisord.conf (supervisor-konfiguration)",
|
||||
"advanced_file_docker-compose": "Docker: docker-compose.yml (orkestrering)",
|
||||
"advanced_restart_none": "Für diese Fil ist kein Tjänstneustart erforderlich."
|
||||
"advanced_restart_none": "Für diese Fil ist kein Tjänstneustart erforderlich.",
|
||||
"go_server_version": "Go-server",
|
||||
"go_server_version_dev_hint": "Go-binären rapporterar utvecklingsbuild — bygg om eller uppdatera servern för att matcha produktversionen"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"enrollment_tag_picker": "เลือกแท็กจากแท็กอุปกรณ์ที่มีอยู่",
|
||||
"enrollment_tag_picker_hint": "ให้ผู้ดำเนินการเลือกแท็กจากรายการในหน้าอุปกรณ์แทนการพิมพ์เท่านั้น",
|
||||
"enrollment_open_requests": "เปิดคำขอลงทะเบียน",
|
||||
"enrollment_pending_count": "คำขอลงทะเบียนที่รอดำเนินการ {count} รายการ"
|
||||
"enrollment_pending_count": "คำขอลงทะเบียนที่รอดำเนินการ {count} รายการ",
|
||||
"go_server_version": "เซิร์ฟเวอร์ Go",
|
||||
"go_server_version_dev_hint": "ไบนารี Go รายงานว่าเป็น build พัฒนา — สร้างใหม่หรืออัปเดตเซิร์ฟเวอร์ให้ตรงกับเวอร์ชันผลิตภัณฑ์"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"enrollment_tag_picker": "Mevcut cihaz etiketlerinden etiket seç",
|
||||
"enrollment_tag_picker_hint": "Operatörlerin yalnızca yazmak yerine Cihazlar sayfasındaki etiket listesinden seçmesine olanak tanır.",
|
||||
"enrollment_open_requests": "Kayıt isteklerini aç",
|
||||
"enrollment_pending_count": "{count} bekleyen kayıt isteği"
|
||||
"enrollment_pending_count": "{count} bekleyen kayıt isteği",
|
||||
"go_server_version": "Go sunucusu",
|
||||
"go_server_version_dev_hint": "Go ikilisi geliştirme derlemesi bildiriyor — ürün sürümüyle eşleşmesi için sunucuyu yeniden derleyin veya güncelleyin"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"advanced_file_build-env": "Agent-Build-Umgebung (/etc/betterdesk/build.env)",
|
||||
"advanced_file_docker-supervisord": "Docker: supervisord.conf (конфігурація supervisord)",
|
||||
"advanced_file_docker-compose": "Docker: docker-compose.yml (оркестрація)",
|
||||
"advanced_restart_none": "Für diese Файл ist kein Службаneustart erforderlich."
|
||||
"advanced_restart_none": "Für diese Файл ist kein Службаneustart erforderlich.",
|
||||
"go_server_version": "Go-сервер",
|
||||
"go_server_version_dev_hint": "Go-бінарник повідомляє про dev-збірку — перезберіть або оновіть сервер, щоб відповідати версії продукту"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -581,7 +581,9 @@
|
||||
"enrollment_tag_picker": "Chọn thẻ từ thẻ thiết bị hiện có",
|
||||
"enrollment_tag_picker_hint": "Cho phép người vận hành chọn thẻ từ danh sách trên trang Thiết bị thay vì chỉ gõ tay.",
|
||||
"enrollment_open_requests": "Mở yêu cầu đăng ký",
|
||||
"enrollment_pending_count": "{count} yêu cầu đăng ký đang chờ"
|
||||
"enrollment_pending_count": "{count} yêu cầu đăng ký đang chờ",
|
||||
"go_server_version": "Máy chủ Go",
|
||||
"go_server_version_dev_hint": "Nhị phân Go báo bản dựng phát triển — build lại hoặc cập nhật máy chủ để khớp phiên bản sản phẩm"
|
||||
},
|
||||
"audit": {
|
||||
"time": "Time",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "從現有裝置標籤中選擇標籤",
|
||||
"enrollment_tag_picker_hint": "允許操作員從裝置頁面的標籤清單中選擇,而不僅限於手動輸入。",
|
||||
"enrollment_open_requests": "開啟註冊請求",
|
||||
"enrollment_pending_count": "{count} 個待處理的註冊請求"
|
||||
"enrollment_pending_count": "{count} 個待處理的註冊請求",
|
||||
"go_server_version": "Go 伺服器",
|
||||
"go_server_version_dev_hint": "Go 二進位報告為開發建置 — 請重新建置或更新伺服器以符合產品版本"
|
||||
},
|
||||
"audit": {
|
||||
"time": "時間",
|
||||
|
||||
@@ -575,7 +575,9 @@
|
||||
"enrollment_tag_picker": "从现有设备标签中选择标签",
|
||||
"enrollment_tag_picker_hint": "允许操作员从设备页面标签列表中选择,而不仅限于手动输入。",
|
||||
"enrollment_open_requests": "打开注册请求",
|
||||
"enrollment_pending_count": "{count} 个待处理注册请求"
|
||||
"enrollment_pending_count": "{count} 个待处理注册请求",
|
||||
"go_server_version": "Go 服务器",
|
||||
"go_server_version_dev_hint": "Go 二进制报告为开发构建 — 请重新构建或更新服务器以匹配产品版本"
|
||||
},
|
||||
"audit": {
|
||||
"time": "时间",
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/;
|
||||
|
||||
function getProjectRoot() {
|
||||
return path.join(__dirname, '..', '..');
|
||||
}
|
||||
|
||||
function readPackageJsonVersion(consoleDir) {
|
||||
try {
|
||||
const pkgPath = path.join(consoleDir || path.join(__dirname, '..'), 'package.json');
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
||||
const v = (pkg.version || '').trim();
|
||||
return SEMVER_RE.test(v) ? v : null;
|
||||
} catch (_e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read canonical BetterDesk product version.
|
||||
* Prefers repo-root VERSION, then web-nodejs/package.json, then fallback.
|
||||
*/
|
||||
function readProductVersion({ rootDir, consoleDir, fallback = '0.0.0' } = {}) {
|
||||
const projectRoot = rootDir || getProjectRoot();
|
||||
const versionFile = path.join(projectRoot, 'VERSION');
|
||||
|
||||
try {
|
||||
if (fs.existsSync(versionFile)) {
|
||||
const v = fs.readFileSync(versionFile, 'utf8').trim();
|
||||
if (SEMVER_RE.test(v)) return v;
|
||||
}
|
||||
} catch (_e) { /* fall through */ }
|
||||
|
||||
const fromPkg = readPackageJsonVersion(consoleDir || path.join(projectRoot, 'web-nodejs'));
|
||||
if (fromPkg) return fromPkg;
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
SEMVER_RE,
|
||||
getProjectRoot,
|
||||
readProductVersion,
|
||||
readPackageJsonVersion,
|
||||
};
|
||||
@@ -193,6 +193,17 @@
|
||||
|
||||
document.getElementById('db-path').textContent = data.paths?.database || '-';
|
||||
document.getElementById('uptime').textContent = formatUptime(data.server?.uptime);
|
||||
|
||||
const goVerEl = document.getElementById('go-server-version');
|
||||
if (goVerEl) {
|
||||
const goVer = data.goServer?.version;
|
||||
goVerEl.textContent = goVer ? `v${goVer}` : '-';
|
||||
if (goVer && goVer === 'dev' && data.app?.version && data.app.version !== 'dev') {
|
||||
goVerEl.title = typeof _ === 'function' ? _('settings.go_server_version_dev_hint') : '';
|
||||
} else {
|
||||
goVerEl.title = '';
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to load server info:', error);
|
||||
|
||||
@@ -26,6 +26,7 @@ const path = require('path');
|
||||
const https = require('https');
|
||||
const { execSync, execFileSync } = require('child_process');
|
||||
const config = require('../config/config');
|
||||
const { readProductVersion } = require('../lib/productVersion');
|
||||
const { createConsoleDeployGraph } = require('../lib/consoleDeployGraph');
|
||||
const { resolveChildPath, resolvePathUnderRoot, existsConfinedChild, removeConfinedChild } = require('../lib/safePath');
|
||||
const { runConsoleNpmInstall } = require('../lib/consoleNpmInstall');
|
||||
@@ -483,12 +484,7 @@ async function getRemoteHeadSHA() {
|
||||
}
|
||||
|
||||
function getLocalVersion() {
|
||||
const versionFile = path.join(PROJECT_ROOT, 'VERSION');
|
||||
if (fs.existsSync(versionFile)) {
|
||||
const v = fs.readFileSync(versionFile, 'utf8').trim();
|
||||
if (v) return v;
|
||||
}
|
||||
return config.appVersion;
|
||||
return readProductVersion({ rootDir: PROJECT_ROOT }) || config.appVersion;
|
||||
}
|
||||
|
||||
// ======================== Classify ======================================
|
||||
@@ -1155,9 +1151,11 @@ async function buildGoServer(preferredGoBinPath = null) {
|
||||
env: buildEnv
|
||||
});
|
||||
|
||||
const productVersion = readProductVersion({ rootDir: PROJECT_ROOT });
|
||||
const ldflags = `-s -w -X main.Version=${productVersion}`;
|
||||
await spawnPromise(
|
||||
goBin,
|
||||
['build', '-trimpath', '-ldflags=-s -w', '-o', binaryName, '.'],
|
||||
['build', '-trimpath', `-ldflags=${ldflags}`, '-o', binaryName, '.'],
|
||||
{ cwd: serverDir, timeout: 600000, env: buildEnv }
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const { readProductVersion } = require('../lib/productVersion');
|
||||
|
||||
describe('productVersion', () => {
|
||||
let tmpRoot;
|
||||
|
||||
beforeEach(() => {
|
||||
tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'bd-version-'));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(tmpRoot, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
test('reads semver from repo-root VERSION', () => {
|
||||
fs.writeFileSync(path.join(tmpRoot, 'VERSION'), '4.1.2\n');
|
||||
expect(readProductVersion({ rootDir: tmpRoot })).toBe('4.1.2');
|
||||
});
|
||||
|
||||
test('falls back to package.json when VERSION is missing', () => {
|
||||
const consoleDir = path.join(tmpRoot, 'web-nodejs');
|
||||
fs.mkdirSync(consoleDir, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(consoleDir, 'package.json'),
|
||||
JSON.stringify({ version: '3.9.8' })
|
||||
);
|
||||
expect(readProductVersion({ rootDir: tmpRoot, consoleDir })).toBe('3.9.8');
|
||||
});
|
||||
|
||||
test('prefers VERSION over package.json', () => {
|
||||
const consoleDir = path.join(tmpRoot, 'web-nodejs');
|
||||
fs.mkdirSync(consoleDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(tmpRoot, 'VERSION'), '2.0.1\n');
|
||||
fs.writeFileSync(
|
||||
path.join(consoleDir, 'package.json'),
|
||||
JSON.stringify({ version: '9.9.9' })
|
||||
);
|
||||
expect(readProductVersion({ rootDir: tmpRoot, consoleDir })).toBe('2.0.1');
|
||||
});
|
||||
|
||||
test('returns fallback when no sources available', () => {
|
||||
expect(readProductVersion({ rootDir: tmpRoot, fallback: '0.0.0' })).toBe('0.0.0');
|
||||
});
|
||||
});
|
||||
@@ -100,6 +100,13 @@
|
||||
</span>
|
||||
<span class="server-info-value">v${appVersion}</span>
|
||||
</div>
|
||||
<div class="server-info-item">
|
||||
<span class="server-info-label">
|
||||
<span class="material-icons">dns</span>
|
||||
${_('settings.go_server_version')}
|
||||
</span>
|
||||
<span class="server-info-value" id="go-server-version">-</span>
|
||||
</div>
|
||||
<div class="server-info-item">
|
||||
<span class="server-info-label">
|
||||
<span class="material-icons">storage</span>
|
||||
|
||||
Reference in New Issue
Block a user