Skip to content

Commit 53be951

Browse files
CopilotMossaka
andcommitted
feat(cli): add --no-pull flag to use pre-downloaded images
Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
1 parent aaecf2b commit 53be951

5 files changed

Lines changed: 61 additions & 4 deletions

File tree

src/cli-workflow.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export interface WorkflowDependencies {
44
ensureFirewallNetwork: () => Promise<{ squidIp: string }>;
55
setupHostIptables: (squidIp: string, port: number, dnsServers: string[]) => Promise<void>;
66
writeConfigs: (config: WrapperConfig) => Promise<void>;
7-
startContainers: (workDir: string, allowedDomains: string[], proxyLogsDir?: string) => Promise<void>;
7+
startContainers: (workDir: string, allowedDomains: string[], proxyLogsDir?: string, skipPull?: boolean) => Promise<void>;
88
runAgentCommand: (
99
workDir: string,
1010
allowedDomains: string[],
@@ -51,7 +51,7 @@ export async function runMainWorkflow(
5151
await dependencies.writeConfigs(config);
5252

5353
// Step 2: Start containers
54-
await dependencies.startContainers(config.workDir, config.allowedDomains, config.proxyLogsDir);
54+
await dependencies.startContainers(config.workDir, config.allowedDomains, config.proxyLogsDir, config.skipPull);
5555
onContainersStarted?.();
5656

5757
// Step 3: Wait for agent to complete

src/cli.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,11 @@ program
401401
'Comma-separated list of allowed URL patterns for HTTPS (requires --ssl-bump).\n' +
402402
' Supports wildcards: https://github.com/githubnext/*'
403403
)
404+
.option(
405+
'--no-pull',
406+
'Skip pulling container images and use locally cached ones (from awf preload)',
407+
false
408+
)
404409
.argument('[args...]', 'Command and arguments to execute (use -- to separate from options)')
405410
.action(async (args: string[], options) => {
406411
// Require -- separator for passing command arguments
@@ -622,6 +627,7 @@ program
622627
enableHostAccess: options.enableHostAccess,
623628
sslBump: options.sslBump,
624629
allowedUrls,
630+
skipPull: options.noPull,
625631
};
626632

627633
// Warn if --env-all is used

src/docker-manager.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,32 @@ describe('docker-manager', () => {
727727

728728
await expect(startContainers(testDir, ['github.com'])).rejects.toThrow();
729729
});
730+
731+
it('should use --pull never when skipPull is true', async () => {
732+
mockExecaFn.mockResolvedValueOnce({ stdout: '', stderr: '', exitCode: 0 } as any);
733+
mockExecaFn.mockResolvedValueOnce({ stdout: '', stderr: '', exitCode: 0 } as any);
734+
735+
await startContainers(testDir, ['github.com'], undefined, true);
736+
737+
expect(mockExecaFn).toHaveBeenCalledWith(
738+
'docker',
739+
['compose', 'up', '-d', '--pull', 'never'],
740+
{ cwd: testDir, stdio: 'inherit' }
741+
);
742+
});
743+
744+
it('should not use --pull when skipPull is false', async () => {
745+
mockExecaFn.mockResolvedValueOnce({ stdout: '', stderr: '', exitCode: 0 } as any);
746+
mockExecaFn.mockResolvedValueOnce({ stdout: '', stderr: '', exitCode: 0 } as any);
747+
748+
await startContainers(testDir, ['github.com'], undefined, false);
749+
750+
expect(mockExecaFn).toHaveBeenCalledWith(
751+
'docker',
752+
['compose', 'up', '-d'],
753+
{ cwd: testDir, stdio: 'inherit' }
754+
);
755+
});
730756
});
731757

732758
describe('stopContainers', () => {

src/docker-manager.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -613,8 +613,12 @@ async function checkSquidLogs(workDir: string, proxyLogsDir?: string): Promise<{
613613

614614
/**
615615
* Starts Docker Compose services
616+
* @param workDir - Working directory containing configs
617+
* @param allowedDomains - List of allowed domains for error reporting
618+
* @param proxyLogsDir - Optional custom directory for proxy logs
619+
* @param skipPull - If true, use --pull never to skip pulling images
616620
*/
617-
export async function startContainers(workDir: string, allowedDomains: string[], proxyLogsDir?: string): Promise<void> {
621+
export async function startContainers(workDir: string, allowedDomains: string[], proxyLogsDir?: string, skipPull?: boolean): Promise<void> {
618622
logger.info('Starting containers...');
619623

620624
// Force remove any existing containers with these names to avoid conflicts
@@ -630,7 +634,14 @@ export async function startContainers(workDir: string, allowedDomains: string[],
630634
}
631635

632636
try {
633-
await execa('docker', ['compose', 'up', '-d'], {
637+
// Build docker compose command with optional --pull never
638+
const composeArgs = ['compose', 'up', '-d'];
639+
if (skipPull) {
640+
composeArgs.push('--pull', 'never');
641+
logger.info('Using locally cached images (--no-pull)');
642+
}
643+
644+
await execa('docker', composeArgs, {
634645
cwd: workDir,
635646
stdio: 'inherit',
636647
});

src/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,20 @@ export interface WrapperConfig {
283283
* @example ['https://github.com/githubnext/*', 'https://api.example.com/v1/*']
284284
*/
285285
allowedUrls?: string[];
286+
287+
/**
288+
* Whether to skip pulling container images and use locally cached ones
289+
*
290+
* When true, Docker Compose will use `--pull never` to avoid pulling
291+
* images from the registry. This is useful when images have been
292+
* pre-downloaded using `awf preload` or are available locally.
293+
*
294+
* When false (default), Docker Compose uses its default pull policy,
295+
* which pulls images if they don't exist locally.
296+
*
297+
* @default false
298+
*/
299+
skipPull?: boolean;
286300
}
287301

288302
/**

0 commit comments

Comments
 (0)