disable build cache no longer errors on deploy
This commit is contained in:
2 files changed
+146
No files matched your search
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Operation-specific `docker compose` CLI args, split out of executeLocalCompose so the
|
||||
* arg construction is unit-testable without a daemon.
|
||||
*
|
||||
* `--no-cache` is a `docker compose build` flag, NOT an `up` flag: pushing it onto `up`
|
||||
* makes the CLI reject the whole command with "unknown flag: --no-cache" (#1479). When a
|
||||
* no-cache rebuild is requested, the caller runs a separate `build` operation first (see
|
||||
* shouldRunSeparateBuildStep) and then a plain `up` - so `up` omits `--build` in that case
|
||||
* (the fresh image already exists).
|
||||
*/
|
||||
export interface ComposeOperationArgOptions {
|
||||
forceRecreate?: boolean;
|
||||
removeVolumes?: boolean;
|
||||
build?: boolean;
|
||||
noBuildCache?: boolean;
|
||||
pullPolicy?: string;
|
||||
serviceName?: string;
|
||||
}
|
||||
|
||||
export function buildComposeOperationArgs(
|
||||
operation: 'up' | 'down' | 'stop' | 'start' | 'restart' | 'pull' | 'build',
|
||||
options: ComposeOperationArgOptions = {}
|
||||
): string[] {
|
||||
const { forceRecreate, removeVolumes, build, noBuildCache, pullPolicy, serviceName } = options;
|
||||
const args: string[] = [];
|
||||
|
||||
switch (operation) {
|
||||
case 'up':
|
||||
args.push('up', '-d', '--remove-orphans');
|
||||
if (forceRecreate) args.push('--force-recreate');
|
||||
// A no-cache rebuild is handled by a separate `build` step, so `up` must not
|
||||
// also carry --build (and never --no-cache, which up doesn't accept).
|
||||
if (build && !noBuildCache) args.push('--build');
|
||||
if (pullPolicy) args.push('--pull', pullPolicy);
|
||||
if (serviceName) args.push(serviceName);
|
||||
break;
|
||||
case 'down':
|
||||
args.push('down', '--remove-orphans');
|
||||
if (removeVolumes) args.push('--volumes');
|
||||
break;
|
||||
case 'stop':
|
||||
args.push('stop');
|
||||
break;
|
||||
case 'start':
|
||||
args.push('start');
|
||||
break;
|
||||
case 'restart':
|
||||
args.push('restart');
|
||||
break;
|
||||
case 'pull':
|
||||
args.push('pull');
|
||||
if (serviceName) args.push(serviceName);
|
||||
break;
|
||||
case 'build':
|
||||
args.push('build');
|
||||
if (noBuildCache) args.push('--no-cache');
|
||||
if (serviceName) args.push(serviceName);
|
||||
break;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* A no-cache rebuild needs a separate `docker compose build --no-cache` before `up`.
|
||||
* Hawser's remote agent has no `build` operation (#880/#1020), so the separate step only
|
||||
* runs for local/direct deployments; on Hawser a no-cache request is silently a no-op
|
||||
* rather than a hard error.
|
||||
*/
|
||||
export function shouldRunSeparateBuildStep(
|
||||
build: boolean | undefined,
|
||||
noBuildCache: boolean | undefined,
|
||||
connectionType: string | null | undefined
|
||||
): boolean {
|
||||
const isHawser = connectionType === 'hawser-standard' || connectionType === 'hawser-edge';
|
||||
return !!build && !!noBuildCache && !isHawser;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { describe, it, expect } from 'bun:test';
|
||||
import { buildComposeOperationArgs, shouldRunSeparateBuildStep } from '../src/lib/server/compose-args';
|
||||
|
||||
describe('buildComposeOperationArgs', () => {
|
||||
it('plain up: no --build, no --no-cache (back-compat, the common case)', () => {
|
||||
const a = buildComposeOperationArgs('up', {});
|
||||
expect(a).toEqual(['up', '-d', '--remove-orphans']);
|
||||
});
|
||||
|
||||
it('up with build (no no-cache): keeps --build exactly as before', () => {
|
||||
const a = buildComposeOperationArgs('up', { build: true });
|
||||
expect(a).toContain('--build');
|
||||
expect(a).not.toContain('--no-cache');
|
||||
});
|
||||
|
||||
it('up never carries --no-cache, even when noBuildCache is requested (#1479)', () => {
|
||||
const a = buildComposeOperationArgs('up', { build: true, noBuildCache: true });
|
||||
expect(a).not.toContain('--no-cache');
|
||||
});
|
||||
|
||||
it('up omits --build when a no-cache rebuild is requested (the separate build step handles it)', () => {
|
||||
const a = buildComposeOperationArgs('up', { build: true, noBuildCache: true });
|
||||
expect(a).not.toContain('--build');
|
||||
});
|
||||
|
||||
it('up passes forceRecreate, pull policy, and a target service', () => {
|
||||
const a = buildComposeOperationArgs('up', { forceRecreate: true, pullPolicy: 'always', serviceName: 'web' });
|
||||
expect(a).toEqual(['up', '-d', '--remove-orphans', '--force-recreate', '--pull', 'always', 'web']);
|
||||
});
|
||||
|
||||
it('build operation carries --no-cache only when requested', () => {
|
||||
expect(buildComposeOperationArgs('build', { noBuildCache: true })).toEqual(['build', '--no-cache']);
|
||||
expect(buildComposeOperationArgs('build', { noBuildCache: false })).toEqual(['build']);
|
||||
});
|
||||
|
||||
it('build operation scopes to a single service when given', () => {
|
||||
expect(buildComposeOperationArgs('build', { noBuildCache: true, serviceName: 'web' })).toEqual(['build', '--no-cache', 'web']);
|
||||
});
|
||||
|
||||
it('down / stop / start / restart / pull unchanged (back-compat)', () => {
|
||||
expect(buildComposeOperationArgs('down', {})).toEqual(['down', '--remove-orphans']);
|
||||
expect(buildComposeOperationArgs('down', { removeVolumes: true })).toEqual(['down', '--remove-orphans', '--volumes']);
|
||||
expect(buildComposeOperationArgs('stop', {})).toEqual(['stop']);
|
||||
expect(buildComposeOperationArgs('start', {})).toEqual(['start']);
|
||||
expect(buildComposeOperationArgs('restart', {})).toEqual(['restart']);
|
||||
expect(buildComposeOperationArgs('pull', {})).toEqual(['pull']);
|
||||
expect(buildComposeOperationArgs('pull', { serviceName: 'web' })).toEqual(['pull', 'web']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldRunSeparateBuildStep', () => {
|
||||
it('runs for local socket (no env) and direct when a no-cache rebuild is requested', () => {
|
||||
expect(shouldRunSeparateBuildStep(true, true, undefined)).toBe(true);
|
||||
expect(shouldRunSeparateBuildStep(true, true, 'socket')).toBe(true);
|
||||
expect(shouldRunSeparateBuildStep(true, true, 'direct')).toBe(true);
|
||||
});
|
||||
|
||||
it('never runs for Hawser (its agent has no build op) - a no-cache request is a no-op there', () => {
|
||||
expect(shouldRunSeparateBuildStep(true, true, 'hawser-standard')).toBe(false);
|
||||
expect(shouldRunSeparateBuildStep(true, true, 'hawser-edge')).toBe(false);
|
||||
});
|
||||
|
||||
it('does not run without both build and noBuildCache (back-compat: normal deploys unaffected)', () => {
|
||||
expect(shouldRunSeparateBuildStep(false, true, 'socket')).toBe(false);
|
||||
expect(shouldRunSeparateBuildStep(true, false, 'socket')).toBe(false);
|
||||
expect(shouldRunSeparateBuildStep(false, false, 'socket')).toBe(false);
|
||||
expect(shouldRunSeparateBuildStep(undefined, undefined, 'socket')).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user