Merge pull request #824 from PicPeak/fix/update-instructions-production-compose
fix(update): target docker-compose.production.yml in dashboard update steps + gate mailhog
This commit is contained in:
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Regression tests for the Docker update instructions (environmentService).
|
||||||
|
*
|
||||||
|
* A production install (docker-compose.production.yml) must get `-f
|
||||||
|
* docker-compose.production.yml` in every update command — bare `docker compose`
|
||||||
|
* targets docker-compose.yml, a different build-based stack that also starts the
|
||||||
|
* dev-only mailhog, which left production users stranded on the old version
|
||||||
|
* (reported against 3.44.0 → 3.45.2).
|
||||||
|
*/
|
||||||
|
const { detectEnvironment, generateUpdateInstructions } = require('../../src/services/environmentService');
|
||||||
|
|
||||||
|
describe('detectEnvironment — production compose detection', () => {
|
||||||
|
const orig = process.env.PICPEAK_RELEASE_CHANNEL;
|
||||||
|
afterEach(() => {
|
||||||
|
if (orig === undefined) delete process.env.PICPEAK_RELEASE_CHANNEL;
|
||||||
|
else process.env.PICPEAK_RELEASE_CHANNEL = orig;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('flags isProductionCompose when PICPEAK_RELEASE_CHANNEL is set', async () => {
|
||||||
|
process.env.PICPEAK_RELEASE_CHANNEL = 'stable';
|
||||||
|
const env = await detectEnvironment();
|
||||||
|
expect(env.isProductionCompose).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not flag it when the var is absent (default docker-compose.yml)', async () => {
|
||||||
|
delete process.env.PICPEAK_RELEASE_CHANNEL;
|
||||||
|
const env = await detectEnvironment();
|
||||||
|
expect(env.isProductionCompose).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('generateUpdateInstructions — Docker commands', () => {
|
||||||
|
const cmds = (env) => generateUpdateInstructions(env, '3.45.2').steps.map((s) => s.command);
|
||||||
|
|
||||||
|
it('targets docker-compose.production.yml for a production install', () => {
|
||||||
|
const commands = cmds({ isDocker: true, isProductionCompose: true });
|
||||||
|
expect(commands).toEqual([
|
||||||
|
'docker compose -f docker-compose.production.yml pull',
|
||||||
|
'docker compose -f docker-compose.production.yml up -d',
|
||||||
|
'docker compose -f docker-compose.production.yml logs -f backend',
|
||||||
|
]);
|
||||||
|
// And the warning tells them where to run it.
|
||||||
|
const { warnings } = generateUpdateInstructions({ isDocker: true, isProductionCompose: true }, '3.45.2');
|
||||||
|
expect(warnings.join(' ')).toMatch(/docker-compose\.production\.yml/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses bare commands + a hint when not a production compose', () => {
|
||||||
|
const commands = cmds({ isDocker: true, isProductionCompose: false });
|
||||||
|
expect(commands).toEqual([
|
||||||
|
'docker compose pull',
|
||||||
|
'docker compose up -d',
|
||||||
|
'docker compose logs -f backend',
|
||||||
|
]);
|
||||||
|
const { warnings } = generateUpdateInstructions({ isDocker: true, isProductionCompose: false }, '3.45.2');
|
||||||
|
// Still nudges production users to add -f in case detection missed.
|
||||||
|
expect(warnings.join(' ')).toMatch(/-f docker-compose\.production\.yml/);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -47,11 +47,23 @@ async function detectEnvironment() {
|
|||||||
type = 'standalone';
|
type = 'standalone';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect a production compose install. The backend runs INSIDE a container and
|
||||||
|
// cannot see the host's compose files (the image only carries backend/), so we
|
||||||
|
// can't stat docker-compose.production.yml. Instead we key off an env var the
|
||||||
|
// production compose sets in the backend environment (PICPEAK_RELEASE_CHANNEL)
|
||||||
|
// and the default docker-compose.yml does not. When present, the update
|
||||||
|
// instructions must target that file explicitly — bare `docker compose`
|
||||||
|
// operates on docker-compose.yml, a different (build-based) stack that also
|
||||||
|
// starts the dev-only mailhog and leaves the real production containers on the
|
||||||
|
// old version.
|
||||||
|
const isProductionCompose = Boolean(process.env.PICPEAK_RELEASE_CHANNEL);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type,
|
type,
|
||||||
isDocker,
|
isDocker,
|
||||||
isGit,
|
isGit,
|
||||||
hasDockerCompose,
|
hasDockerCompose,
|
||||||
|
isProductionCompose,
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
nodeVersion: process.version,
|
nodeVersion: process.version,
|
||||||
appVersion
|
appVersion
|
||||||
@@ -94,25 +106,36 @@ function generateUpdateInstructions(env, targetVersion) {
|
|||||||
|
|
||||||
if (env.isDocker) {
|
if (env.isDocker) {
|
||||||
instructions.environmentName = 'Docker';
|
instructions.environmentName = 'Docker';
|
||||||
|
// Production installs use docker-compose.production.yml (the file the README
|
||||||
|
// documents and the only one with pinned GHCR images + no dev-only mailhog).
|
||||||
|
// Bare `docker compose` targets docker-compose.yml instead, so a production
|
||||||
|
// user who runs it stays on the old version and gets a stray mailhog. When we
|
||||||
|
// detect a production compose (PICPEAK_RELEASE_CHANNEL set), point every
|
||||||
|
// command at that file with `-f`.
|
||||||
|
const composeFile = env.isProductionCompose ? '-f docker-compose.production.yml ' : '';
|
||||||
instructions.steps = [
|
instructions.steps = [
|
||||||
{
|
{
|
||||||
description: 'Pull latest images',
|
description: 'Pull latest images',
|
||||||
command: 'docker compose pull',
|
command: `docker compose ${composeFile}pull`,
|
||||||
note: 'Downloads the new version images'
|
note: 'Downloads the new version images'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Recreate containers with new images',
|
description: 'Recreate containers with new images',
|
||||||
command: 'docker compose up -d',
|
command: `docker compose ${composeFile}up -d`,
|
||||||
note: 'Restarts containers with new version'
|
note: 'Restarts containers with new version'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Watch logs for startup (optional)',
|
description: 'Watch logs for startup (optional)',
|
||||||
command: 'docker compose logs -f backend',
|
command: `docker compose ${composeFile}logs -f backend`,
|
||||||
note: 'Press Ctrl+C to exit logs',
|
note: 'Press Ctrl+C to exit logs',
|
||||||
optional: true
|
optional: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
instructions.warnings.push('Make sure you are in the directory containing your docker-compose.yml file');
|
if (env.isProductionCompose) {
|
||||||
|
instructions.warnings.push('Run these from the directory containing your docker-compose.production.yml file.');
|
||||||
|
} else {
|
||||||
|
instructions.warnings.push('Make sure you are in the directory containing your compose file. If you installed with docker-compose.production.yml, add `-f docker-compose.production.yml` to each command.');
|
||||||
|
}
|
||||||
} else if (env.isGit) {
|
} else if (env.isGit) {
|
||||||
instructions.environmentName = 'Git (Development)';
|
instructions.environmentName = 'Git (Development)';
|
||||||
instructions.steps = [
|
instructions.steps = [
|
||||||
|
|||||||
@@ -144,10 +144,16 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- picpeak-network
|
- picpeak-network
|
||||||
|
|
||||||
|
# Local mail catcher for development/testing only — never wanted in a real
|
||||||
|
# deployment. Gated behind the `dev` profile so a plain `docker compose up -d`
|
||||||
|
# does NOT start it; opt in with `docker compose --profile dev up -d`. Nothing
|
||||||
|
# depends on it (SMTP_HOST comes from .env), so gating is safe.
|
||||||
mailhog:
|
mailhog:
|
||||||
image: mailhog/mailhog:latest
|
image: mailhog/mailhog:latest
|
||||||
container_name: picpeak-mailhog
|
container_name: picpeak-mailhog
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
profiles:
|
||||||
|
- dev
|
||||||
ports:
|
ports:
|
||||||
- "${MAILHOG_SMTP_PORT:-1025}:1025"
|
- "${MAILHOG_SMTP_PORT:-1025}:1025"
|
||||||
- "${MAILHOG_UI_PORT:-8025}:8025"
|
- "${MAILHOG_UI_PORT:-8025}:8025"
|
||||||
|
|||||||
Reference in New Issue
Block a user