Release: weekly deploy
This commit is contained in:
@@ -6,6 +6,7 @@ client/node_modules/
|
|||||||
.env.*.local
|
.env.*.local
|
||||||
infra/docker/.env.prod
|
infra/docker/.env.prod
|
||||||
infra/deploy/devtoprod.config.json
|
infra/deploy/devtoprod.config.json
|
||||||
|
infra/deploy/last-docker-release.json
|
||||||
|
|
||||||
# DB backups (may contain data)
|
# DB backups (may contain data)
|
||||||
db/DataBackup/
|
db/DataBackup/
|
||||||
|
|||||||
@@ -34,13 +34,11 @@ For a typical weekly release, use the orchestrator instead of running each step
|
|||||||
- `autoStartDevStack`: `true` starts `dev:server` (or `dev:web`) automatically when `validateBuild` finds API down
|
- `autoStartDevStack`: `true` starts `dev:server` (or `dev:web`) automatically when `validateBuild` finds API down
|
||||||
- `git.message`, `git.branch` — used when `gitCommitPush` is enabled
|
- `git.message`, `git.branch` — used when `gitCommitPush` is enabled
|
||||||
- `schemaChanged`: `true` enables prod schema migration on `full` profile
|
- `schemaChanged`: `true` enables prod schema migration on `full` profile
|
||||||
- `release.imageTag`: image/version tag shared between Gitea push and runtime (`latest`, `2026-07-09`, `v1.3.0`, etc.)
|
|
||||||
- `smb.user` / `smb.password` — optional; maps `\\host\share` before image sync
|
- `smb.user` / `smb.password` — optional; maps `\\host\share` before image sync
|
||||||
- `backupFile` — optional fixed path; otherwise uses the newest `gallery_dev_data_*.txt` after backup
|
- `backupFile` — optional fixed path; otherwise uses the newest `gallery_dev_data_*.txt` after backup
|
||||||
|
|
||||||
3. Prerequisites still apply: **`npm run dev:web` running** (Vite `:5173` + API `:3451`), Docker Desktop running, `docker login gitea.mysuperlab.netcraze.pro`, [`infra/docker/.env.prod`](../infra/docker/.env.prod) present.
|
3. Prerequisites still apply: **`npm run dev:web` running** (Vite `:5173` + API `:3451`), Docker Desktop running, `docker login gitea.mysuperlab.netcraze.pro`, [`infra/docker/.env.prod`](../infra/docker/.env.prod) present.
|
||||||
- Before migration/restore steps, verify prod DB target in `.env.prod`: `DB_NAME=gallery_prod`.
|
- Before migration/restore steps, verify prod DB target in `.env.prod`: `DB_NAME=gallery_prod`.
|
||||||
- Set `IMAGE_TAG=<release.imageTag>` in prod env (TrueNAS app vars or `.env.prod`) to control which pushed Gitea image tag is active.
|
|
||||||
|
|
||||||
### Run
|
### Run
|
||||||
|
|
||||||
@@ -68,7 +66,7 @@ npm run devtoprod:release -- -DryRun
|
|||||||
| `migrateProdSchema` | Step 4 — `dev:migrate` on `gallery_prod` |
|
| `migrateProdSchema` | Step 4 — `dev:migrate` on `gallery_prod` |
|
||||||
| `restoreProd` | Step 5 — `devtoprod:db:restore` |
|
| `restoreProd` | Step 5 — `devtoprod:db:restore` |
|
||||||
| `syncImages` | Step 6 — `devtoprod:images` |
|
| `syncImages` | Step 6 — `devtoprod:images` |
|
||||||
| `dockerPublish` | Step 7 — `prod:docker:publish -- -Tag <release.imageTag>` |
|
| `dockerPublish` | Step 7 — `prod:docker:publish` (auto tag: `YYYYMMDD-HHMMSS-<gitsha>` + push `latest`) |
|
||||||
| `truenasRestartPause` | Step 8 — **manual** pause; script waits for Enter after you restart **gallery-web** |
|
| `truenasRestartPause` | Step 8 — **manual** pause; script waits for Enter after you restart **gallery-web** |
|
||||||
| `verify` | Step 9 — curl LAN + public `/api/bounds` |
|
| `verify` | Step 9 — curl LAN + public `/api/bounds` |
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ Gallery uses **one PostgreSQL server** on TrueNAS (`192.168.10.122`) with **two
|
|||||||
| **Production** | `gallery_prod` | `https://gallery.mysuperlab.netcraze.pro` | TrueNAS container `192.168.10.122:5173` |
|
| **Production** | `gallery_prod` | `https://gallery.mysuperlab.netcraze.pro` | TrueNAS container `192.168.10.122:5173` |
|
||||||
|
|
||||||
Version tracking:
|
Version tracking:
|
||||||
- Runtime version endpoint: `/api/version` (reports `app_env`, `app_version`, `image_tag`, `git_sha`, `db_name`)
|
- Runtime version endpoint: `/api/version` (reports `app_env`, `app_version`, `image_tag`, `git_sha`, `built_at`, `db_name`)
|
||||||
- Prod image selection: set `IMAGE_TAG` in TrueNAS app env / `infra/docker/.env.prod`
|
- `npm run prod:docker:publish` auto-creates a release tag like `20260709-155412-f72ddcc` (build time + git commit), pushes it and `latest`
|
||||||
- Release push tag: set `release.imageTag` in `infra/deploy/devtoprod.config.json`
|
- Version metadata is baked into the Docker image; TrueNAS only needs `gallery-web:latest` with `pull_policy: always`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,6 @@
|
|||||||
"stageAll": true
|
"stageAll": true
|
||||||
},
|
},
|
||||||
"schemaChanged": false,
|
"schemaChanged": false,
|
||||||
"release": {
|
|
||||||
"imageTag": "latest"
|
|
||||||
},
|
|
||||||
"backupFile": "",
|
"backupFile": "",
|
||||||
"smb": {
|
"smb": {
|
||||||
"host": "192.168.10.122",
|
"host": "192.168.10.122",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ DB_NAME=gallery_prod
|
|||||||
PORT=5173
|
PORT=5173
|
||||||
HOST=0.0.0.0
|
HOST=0.0.0.0
|
||||||
APP_ENV=prod
|
APP_ENV=prod
|
||||||
IMAGE_TAG=latest
|
|
||||||
PUBLIC_URL=https://gallery.mysuperlab.netcraze.pro
|
PUBLIC_URL=https://gallery.mysuperlab.netcraze.pro
|
||||||
TRUST_PROXY=true
|
TRUST_PROXY=true
|
||||||
IMAGE_DIR=/app/data/images
|
IMAGE_DIR=/app/data/images
|
||||||
|
|||||||
@@ -23,10 +23,18 @@ COPY client ./client
|
|||||||
RUN npm run build --prefix client
|
RUN npm run build --prefix client
|
||||||
|
|
||||||
FROM node:20-alpine AS runner
|
FROM node:20-alpine AS runner
|
||||||
|
ARG APP_VERSION=0.0.0
|
||||||
|
ARG GIT_SHA=
|
||||||
|
ARG IMAGE_TAG=latest
|
||||||
|
ARG BUILD_TIME=
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV PORT=5173
|
ENV PORT=5173
|
||||||
ENV HOST=0.0.0.0
|
ENV HOST=0.0.0.0
|
||||||
ENV IMAGE_DIR=/app/data/images
|
ENV IMAGE_DIR=/app/data/images
|
||||||
|
ENV APP_VERSION=$APP_VERSION
|
||||||
|
ENV GIT_SHA=$GIT_SHA
|
||||||
|
ENV IMAGE_TAG=$IMAGE_TAG
|
||||||
|
ENV BUILD_TIME=$BUILD_TIME
|
||||||
|
|
||||||
RUN addgroup --system --gid 1001 nodejs \
|
RUN addgroup --system --gid 1001 nodejs \
|
||||||
&& adduser --system --uid 1001 --ingroup nodejs gallery
|
&& adduser --system --uid 1001 --ingroup nodejs gallery
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
# Build and push the production web image to Gitea over LAN (fast path).
|
# Build and push the production web image to Gitea over LAN (fast path).
|
||||||
param(
|
param(
|
||||||
[string]$Tag = "latest",
|
[string]$Tag = '',
|
||||||
[switch]$SkipHosts,
|
[switch]$SkipHosts,
|
||||||
[switch]$SkipBuild
|
[switch]$SkipBuild
|
||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
. (Join-Path $PSScriptRoot "..\scripts\lib\Deploy-CliResult.ps1")
|
. (Join-Path $PSScriptRoot "..\scripts\lib\Deploy-CliResult.ps1")
|
||||||
|
. (Join-Path $PSScriptRoot "..\scripts\lib\Build-ReleaseTag.ps1")
|
||||||
|
|
||||||
$Registry = "gitea.mysuperlab.netcraze.pro"
|
$Registry = "gitea.mysuperlab.netcraze.pro"
|
||||||
$Image = "$Registry/danilka/gallery-web"
|
$Image = "$Registry/danilka/gallery-web"
|
||||||
|
$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).Path
|
||||||
|
|
||||||
function Test-DockerRunning {
|
function Test-DockerRunning {
|
||||||
$prevEap = $ErrorActionPreference
|
$prevEap = $ErrorActionPreference
|
||||||
@@ -27,10 +29,24 @@ if (-not (Test-DockerRunning)) {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$meta = Get-BuildMetadata -RepoRoot $RepoRoot
|
||||||
|
$releaseTag = if ($Tag -and $Tag.Trim()) { $Tag.Trim() } else { $meta.ReleaseTag }
|
||||||
|
$meta.ReleaseTag = $releaseTag
|
||||||
|
|
||||||
|
Write-Host "Release tag: $releaseTag"
|
||||||
|
Write-Host "Build metadata: app_version=$($meta.AppVersion), git_sha=$($meta.GitSha), built_at=$($meta.BuildTimeUtc)"
|
||||||
|
|
||||||
if (-not $SkipBuild) {
|
if (-not $SkipBuild) {
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "Building ${Image}:${Tag} ..."
|
Write-Host "Building ${Image}:$releaseTag and ${Image}:latest ..."
|
||||||
docker build -f infra/docker/Dockerfile -t "${Image}:${Tag}" .
|
docker build -f infra/docker/Dockerfile `
|
||||||
|
--build-arg "APP_VERSION=$($meta.AppVersion)" `
|
||||||
|
--build-arg "GIT_SHA=$($meta.GitSha)" `
|
||||||
|
--build-arg "IMAGE_TAG=$releaseTag" `
|
||||||
|
--build-arg "BUILD_TIME=$($meta.BuildTimeUtc)" `
|
||||||
|
-t "${Image}:$releaseTag" `
|
||||||
|
-t "${Image}:latest" `
|
||||||
|
$RepoRoot
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
Write-DeployCliResult -Script 'build-push-lan' -Success $false -Summary "Docker build failed with exit code $LASTEXITCODE"
|
Write-DeployCliResult -Script 'build-push-lan' -Success $false -Summary "Docker build failed with exit code $LASTEXITCODE"
|
||||||
exit $LASTEXITCODE
|
exit $LASTEXITCODE
|
||||||
@@ -41,11 +57,28 @@ if (-not $SkipBuild) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
& "$PSScriptRoot/push-lan.ps1" -Tag $Tag -SkipHosts:$SkipHosts
|
if ($SkipBuild) {
|
||||||
|
$pushTags = @('latest')
|
||||||
|
if ($Tag -and $Tag.Trim()) {
|
||||||
|
$pushTags = @($Tag.Trim(), 'latest') | Select-Object -Unique
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$pushTags = @($releaseTag, 'latest') | Select-Object -Unique
|
||||||
|
}
|
||||||
|
& "$PSScriptRoot/push-lan.ps1" -Tags $pushTags -SkipHosts:$SkipHosts
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
Write-DeployCliResult -Script 'build-push-lan' -Success $false -Summary "Docker push failed with exit code $LASTEXITCODE"
|
Write-DeployCliResult -Script 'build-push-lan' -Success $false -Summary "Docker push failed with exit code $LASTEXITCODE"
|
||||||
exit $LASTEXITCODE
|
exit $LASTEXITCODE
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-DeployCliResult -Script 'build-push-lan' -Success $true -Summary 'Docker image built and pushed to Gitea.' -Details @("Image: ${Image}:${Tag}")
|
$manifestPath = Write-LastDockerRelease -RepoRoot $RepoRoot -Metadata $meta -Image "${Image}:$releaseTag"
|
||||||
|
|
||||||
|
Write-DeployCliResult -Script 'build-push-lan' -Success $true -Summary 'Docker image built and pushed to Gitea.' -Details @(
|
||||||
|
"Release tag: $releaseTag",
|
||||||
|
"Also pushed as: latest",
|
||||||
|
"Git commit: $($meta.GitSha)",
|
||||||
|
"Built at: $($meta.BuildTimeUtc)",
|
||||||
|
"Manifest: $manifestPath",
|
||||||
|
"TrueNAS: restart gallery-web (pull_policy: always uses latest)."
|
||||||
|
)
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ../..
|
context: ../..
|
||||||
dockerfile: infra/docker/Dockerfile
|
dockerfile: infra/docker/Dockerfile
|
||||||
image: gitea.mysuperlab.netcraze.pro/danilka/gallery-web:${IMAGE_TAG:-latest}
|
image: gitea.mysuperlab.netcraze.pro/danilka/gallery-web:latest
|
||||||
container_name: gallery-web
|
container_name: gallery-web
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
# See infra/docker/DEPLOY-truenas.md and Documentation/environments.md
|
# See infra/docker/DEPLOY-truenas.md and Documentation/environments.md
|
||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
image: gitea.mysuperlab.netcraze.pro/danilka/gallery-web:${IMAGE_TAG:-latest}
|
image: gitea.mysuperlab.netcraze.pro/danilka/gallery-web:latest
|
||||||
container_name: gallery-web
|
container_name: gallery-web
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
pull_policy: always
|
pull_policy: always
|
||||||
@@ -19,7 +19,6 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
APP_ENV: "prod"
|
APP_ENV: "prod"
|
||||||
IMAGE_TAG: "${IMAGE_TAG:-latest}"
|
|
||||||
PORT: "5173"
|
PORT: "5173"
|
||||||
HOST: "0.0.0.0"
|
HOST: "0.0.0.0"
|
||||||
DB_HOST: "192.168.10.122"
|
DB_HOST: "192.168.10.122"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Push Docker image to Gitea over LAN (avoids KeenDNS hairpin slow upload).
|
# Push Docker image to Gitea over LAN (avoids KeenDNS hairpin slow upload).
|
||||||
param(
|
param(
|
||||||
[string]$Tag = "latest",
|
[string[]]$Tags = @('latest'),
|
||||||
[switch]$SkipHosts
|
[switch]$SkipHosts
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -55,10 +55,12 @@ if (-not $SkipHosts) {
|
|||||||
$after = Get-GiteaDnsAddress
|
$after = Get-GiteaDnsAddress
|
||||||
Write-Host "After override, resolves to: $after"
|
Write-Host "After override, resolves to: $after"
|
||||||
|
|
||||||
Write-Host ""
|
foreach ($tag in ($Tags | Select-Object -Unique)) {
|
||||||
Write-Host "Pushing ${Image}:${Tag} ..."
|
Write-Host ""
|
||||||
docker push "${Image}:${Tag}"
|
Write-Host "Pushing ${Image}:$tag ..."
|
||||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
docker push "${Image}:$tag"
|
||||||
|
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "Done. Remove hosts entry ($HostsMarker) when finished if you no longer need LAN override." -ForegroundColor Cyan
|
Write-Host "Done. Remove hosts entry ($HostsMarker) when finished if you no longer need LAN override." -ForegroundColor Cyan
|
||||||
|
|||||||
@@ -564,9 +564,7 @@ if (Get-StepEnabled $steps 'syncImages') {
|
|||||||
|
|
||||||
if (Get-StepEnabled $steps 'dockerPublish') {
|
if (Get-StepEnabled $steps 'dockerPublish') {
|
||||||
$ok = Invoke-Step 'dockerPublish' {
|
$ok = Invoke-Step 'dockerPublish' {
|
||||||
$tag = if ($cfg.release.imageTag) { $cfg.release.imageTag } else { 'latest' }
|
$code = Invoke-Npm 'prod:docker:publish'
|
||||||
Write-Host "Docker release tag: $tag"
|
|
||||||
$code = Invoke-Npm 'prod:docker:publish' @('-Tag', $tag)
|
|
||||||
return $code
|
return $code
|
||||||
}
|
}
|
||||||
if (-not $ok) { Write-ReleaseBanner -Success $false -FailedAt $FailedStep; exit 1 }
|
if (-not $ok) { Write-ReleaseBanner -Success $false -FailedAt $FailedStep; exit 1 }
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
function Get-BuildMetadata {
|
||||||
|
param([string]$RepoRoot)
|
||||||
|
|
||||||
|
$gitSha = ''
|
||||||
|
$appVersion = '0.0.0'
|
||||||
|
try {
|
||||||
|
Push-Location $RepoRoot
|
||||||
|
$gitSha = (git rev-parse --short HEAD 2>$null).Trim()
|
||||||
|
$appVersion = (node -p "require('./package.json').version" 2>$null).Trim()
|
||||||
|
} finally {
|
||||||
|
Pop-Location
|
||||||
|
}
|
||||||
|
if (-not $gitSha) { $gitSha = 'unknown' }
|
||||||
|
if (-not $appVersion) { $appVersion = '0.0.0' }
|
||||||
|
|
||||||
|
$buildTime = Get-Date
|
||||||
|
$buildTimeUtc = $buildTime.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'")
|
||||||
|
|
||||||
|
return @{
|
||||||
|
GitSha = $gitSha
|
||||||
|
AppVersion = $appVersion
|
||||||
|
BuildTimeUtc = $buildTimeUtc
|
||||||
|
ReleaseTag = New-ReleaseImageTag -GitSha $gitSha -BuildTime $buildTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function New-ReleaseImageTag {
|
||||||
|
param(
|
||||||
|
[string]$GitSha,
|
||||||
|
[datetime]$BuildTime
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not $BuildTime) { $BuildTime = Get-Date }
|
||||||
|
if (-not $GitSha) { $GitSha = 'unknown' }
|
||||||
|
|
||||||
|
$stamp = $BuildTime.ToString('yyyyMMdd-HHmmss')
|
||||||
|
return "$stamp-$GitSha"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-LastDockerRelease {
|
||||||
|
param(
|
||||||
|
[string]$RepoRoot,
|
||||||
|
[hashtable]$Metadata,
|
||||||
|
[string]$Image
|
||||||
|
)
|
||||||
|
|
||||||
|
$manifestPath = Join-Path $RepoRoot 'infra\deploy\last-docker-release.json'
|
||||||
|
$manifest = @{
|
||||||
|
image = $Image
|
||||||
|
release_tag = $Metadata.ReleaseTag
|
||||||
|
git_sha = $Metadata.GitSha
|
||||||
|
app_version = $Metadata.AppVersion
|
||||||
|
built_at = $Metadata.BuildTimeUtc
|
||||||
|
pushed_at = (Get-Date).ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss'Z'")
|
||||||
|
}
|
||||||
|
$manifest | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $manifestPath -Encoding UTF8
|
||||||
|
return $manifestPath
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ const env = {
|
|||||||
PORT: apiPort,
|
PORT: apiPort,
|
||||||
APP_ENV: process.env.APP_ENV || 'dev',
|
APP_ENV: process.env.APP_ENV || 'dev',
|
||||||
IMAGE_TAG: process.env.IMAGE_TAG || 'dev-local',
|
IMAGE_TAG: process.env.IMAGE_TAG || 'dev-local',
|
||||||
|
APP_VERSION: process.env.APP_VERSION || require('../package.json').version,
|
||||||
};
|
};
|
||||||
|
|
||||||
function run(label, command, args, cwd) {
|
function run(label, command, args, cwd) {
|
||||||
|
|||||||
+2
-12
@@ -12,16 +12,13 @@ const { requireCurator } = require('./middleware/auth');
|
|||||||
const { logCuratorAction } = require('./audit-log');
|
const { logCuratorAction } = require('./audit-log');
|
||||||
const authRoutes = require('./routes/auth');
|
const authRoutes = require('./routes/auth');
|
||||||
const { ensurePaintingImages, preloadArtistImagesLocal, replacePaintingImageFromUrl, replaceArtistPortraitFromUrl, clearPaintingImage, deletePainting, clearArtistPortrait, replacePaintingImageFromBuffer, replaceArtistPortraitFromBuffer, IMAGE_DIR } = require('./image-service');
|
const { ensurePaintingImages, preloadArtistImagesLocal, replacePaintingImageFromUrl, replaceArtistPortraitFromUrl, clearPaintingImage, deletePainting, clearArtistPortrait, replacePaintingImageFromBuffer, replaceArtistPortraitFromBuffer, IMAGE_DIR } = require('./image-service');
|
||||||
|
const { getVersionInfo } = require('./version-info');
|
||||||
const { searchGoogleImagesFirst, searchArtistPortraitFirst, searchPaintingImagesMany, searchArtistPortraitMany, fetchImageBuffer, friendlyImageFetchError, pickExt } = require('../scripts/image-fetcher');
|
const { searchGoogleImagesFirst, searchArtistPortraitFirst, searchPaintingImagesMany, searchArtistPortraitMany, fetchImageBuffer, friendlyImageFetchError, pickExt } = require('../scripts/image-fetcher');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const HOST = process.env.HOST || '0.0.0.0';
|
const HOST = process.env.HOST || '0.0.0.0';
|
||||||
const PORT = Number(process.env.PORT) || 3001;
|
const PORT = Number(process.env.PORT) || 3001;
|
||||||
const PUBLIC_URL = process.env.PUBLIC_URL || '';
|
const PUBLIC_URL = process.env.PUBLIC_URL || '';
|
||||||
const APP_ENV = process.env.APP_ENV || (process.env.DB_NAME === 'gallery_prod' ? 'prod' : 'dev');
|
|
||||||
const IMAGE_TAG = process.env.IMAGE_TAG || 'local';
|
|
||||||
const GIT_SHA = process.env.GIT_SHA || '';
|
|
||||||
const APP_VERSION = process.env.npm_package_version || '0.0.0';
|
|
||||||
|
|
||||||
if (process.env.TRUST_PROXY === '1' || process.env.TRUST_PROXY === 'true') {
|
if (process.env.TRUST_PROXY === '1' || process.env.TRUST_PROXY === 'true') {
|
||||||
app.set('trust proxy', 1);
|
app.set('trust proxy', 1);
|
||||||
@@ -1044,14 +1041,7 @@ app.get('/api/bounds', async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/version', async (_req, res) => {
|
app.get('/api/version', async (_req, res) => {
|
||||||
res.json({
|
res.json(getVersionInfo());
|
||||||
app_env: APP_ENV,
|
|
||||||
app_version: APP_VERSION,
|
|
||||||
image_tag: IMAGE_TAG,
|
|
||||||
git_sha: GIT_SHA,
|
|
||||||
db_name: process.env.DB_NAME || '',
|
|
||||||
public_url: PUBLIC_URL || '',
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const CLIENT_DIST = path.join(__dirname, '..', 'client', 'dist');
|
const CLIENT_DIST = path.join(__dirname, '..', 'client', 'dist');
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
|
||||||
|
const rootDir = path.join(__dirname, '..');
|
||||||
|
|
||||||
|
function readPackageVersion() {
|
||||||
|
try {
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
|
||||||
|
return pkg.version || '0.0.0';
|
||||||
|
} catch {
|
||||||
|
return '0.0.0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readGitSha() {
|
||||||
|
if (process.env.GIT_SHA) {
|
||||||
|
return process.env.GIT_SHA;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return execSync('git rev-parse --short HEAD', {
|
||||||
|
cwd: rootDir,
|
||||||
|
encoding: 'utf8',
|
||||||
|
stdio: ['ignore', 'pipe', 'ignore'],
|
||||||
|
}).trim();
|
||||||
|
} catch {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVersionInfo() {
|
||||||
|
const dbName = process.env.DB_NAME || '';
|
||||||
|
const appEnv = process.env.APP_ENV || (dbName === 'gallery_prod' ? 'prod' : 'dev');
|
||||||
|
const imageTag = process.env.IMAGE_TAG || (appEnv === 'prod' ? 'unknown' : 'dev-local');
|
||||||
|
|
||||||
|
return {
|
||||||
|
app_env: appEnv,
|
||||||
|
app_version: process.env.APP_VERSION || readPackageVersion(),
|
||||||
|
image_tag: imageTag,
|
||||||
|
git_sha: readGitSha(),
|
||||||
|
built_at: process.env.BUILD_TIME || '',
|
||||||
|
db_name: dbName,
|
||||||
|
public_url: process.env.PUBLIC_URL || '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { getVersionInfo };
|
||||||
Reference in New Issue
Block a user