Skip to content

Commit 84d0bb4

Browse files
chrisnealjoedixon
andauthored
Add ability to specify args that will be passed to docker during the build (#232)
* feat: Add ability to specify args that will be passed to docker during the build * fix: docblock * chore: handle docker args flags as well as long flags * fix: formatting * fix: spacing * raname args to options * fix output formatting * pass options * rename to buildOptions * revert * chore: output docker build command * chore: move args in front of options in function signatures * chore: move docker build args in front of build options in signature --------- Co-authored-by: Joe Dixon <[email protected]>
1 parent 3f3317a commit 84d0bb4

File tree

7 files changed

+142
-26
lines changed

7 files changed

+142
-26
lines changed

src/BuildProcess/BuildContainerImage.php

+14-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ class BuildContainerImage
4444
*/
4545
protected $cliBuildArgs;
4646

47+
/**
48+
* The Docker CLI options.
49+
*
50+
* @var array
51+
*/
52+
protected $cliBuildOptions;
53+
4754
/**
4855
* The Docker manifest build arguments.
4956
*
@@ -55,14 +62,17 @@ class BuildContainerImage
5562
* Create a new project builder.
5663
*
5764
* @param string|null $environment
58-
* @param array $buildArgs
65+
* @param array $cliBuildArgs
66+
* @param array $cliBuildOptions
67+
* @param array $manifestBuildArgs
5968
* @return void
6069
*/
61-
public function __construct($environment = null, $cliBuildArgs = [], $manifestBuildArgs = [])
70+
public function __construct($environment = null, $cliBuildArgs = [], $cliBuildOptions = [], $manifestBuildArgs = [])
6271
{
6372
$this->baseConstructor($environment);
6473

6574
$this->cliBuildArgs = $cliBuildArgs;
75+
$this->cliBuildOptions = $cliBuildOptions;
6676
$this->manifestBuildArgs = $manifestBuildArgs;
6777
}
6878

@@ -96,7 +106,8 @@ public function __invoke()
96106
$this->appPath,
97107
Manifest::name(),
98108
$this->environment,
99-
$this->formatBuildArguments()
109+
$this->formatBuildArguments(),
110+
$this->cliBuildOptions
100111
);
101112
}
102113

src/Commands/BuildCommand.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ protected function configure()
4545
->addArgument('environment', InputArgument::OPTIONAL, 'The environment name')
4646
->addOption('asset-url', null, InputOption::VALUE_OPTIONAL, 'The asset base URL')
4747
->addOption('build-arg', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Docker build argument')
48+
->addOption('build-option', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Docker build option')
4849
->setDescription('Build the project archive');
4950
}
5051

@@ -88,7 +89,12 @@ public function handle()
8889
new ExtractVendorToSeparateDirectory($this->argument('environment')),
8990
new CompressApplication($this->argument('environment')),
9091
new CompressVendor($this->argument('environment')),
91-
new BuildContainerImage($this->argument('environment'), $this->option('build-arg'), Manifest::dockerBuildArgs($this->argument('environment'))),
92+
new BuildContainerImage(
93+
$this->argument('environment'),
94+
$this->option('build-arg'),
95+
$this->option('build-option'),
96+
Manifest::dockerBuildArgs($this->argument('environment'))
97+
),
9298
])->each->__invoke();
9399

94100
$time = (new DateTime())->diff($startedAt)->format('%im%Ss');

src/Commands/DeployCommand.php

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ protected function configure()
3434
->addOption('without-waiting', null, InputOption::VALUE_NONE, 'Deploy without waiting for progress')
3535
->addOption('fresh-assets', null, InputOption::VALUE_NONE, 'Upload a fresh copy of all assets')
3636
->addOption('build-arg', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Docker build argument')
37+
->addOption('build-option', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Docker build option')
3738
->addOption('debug', null, InputOption::VALUE_OPTIONAL, 'Deploy with debug mode enabled', 'unset')
3839
->setDescription('Deploy an environment');
3940
}
@@ -123,6 +124,7 @@ protected function buildProject(array $project)
123124
'--asset-url' => $this->assetDomain($project).'/'.$uuid,
124125
'--manifest' => Path::manifest(),
125126
'--build-arg' => $this->option('build-arg'),
127+
'--build-option' => $this->option('build-option'),
126128
]);
127129

128130
return $this->uploadArtifact(

src/Docker.php

+63-15
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,24 @@ class Docker
1515
* @param string $project
1616
* @param string $environment
1717
* @param array $cliBuildArgs
18+
* @param array $cliBuildOptions
1819
* @return void
1920
*/
20-
public static function build($path, $project, $environment, $cliBuildArgs)
21+
public static function build($path, $project, $environment, $cliBuildArgs, $cliBuildOptions)
2122
{
23+
$buildCommand = static::buildCommand(
24+
$project,
25+
$environment,
26+
$cliBuildArgs,
27+
Manifest::dockerBuildArgs($environment),
28+
$cliBuildOptions,
29+
Manifest::dockerBuildOptions($environment)
30+
);
31+
32+
Helpers::line(sprintf('Build command: %s', $buildCommand));
33+
2234
Process::fromShellCommandline(
23-
static::buildCommand($project, $environment, $cliBuildArgs, Manifest::dockerBuildArgs($environment)),
35+
$buildCommand,
2436
$path
2537
)->setTimeout(null)->mustRun(function ($type, $line) {
2638
Helpers::write($line);
@@ -34,24 +46,60 @@ public static function build($path, $project, $environment, $cliBuildArgs)
3446
* @param string $environment
3547
* @param array $cliBuildArgs
3648
* @param array $manifestBuildArgs
49+
* @param array $cliBuildOptions
50+
* @param array $manifestBuildOptions
3751
* @return string
3852
*/
39-
public static function buildCommand($project, $environment, $cliBuildArgs, $manifestBuildArgs)
53+
public static function buildCommand($project, $environment, $cliBuildArgs, $manifestBuildArgs, $cliBuildOptions, $manifestBuildOptions)
4054
{
41-
return sprintf('docker build --pull --file=%s --tag=%s %s.',
55+
$command = sprintf(
56+
'docker build --pull --file=%s --tag=%s ',
4257
Manifest::dockerfile($environment),
43-
Str::slug($project).':'.$environment,
44-
Collection::make($manifestBuildArgs)
45-
->merge(Collection::make($cliBuildArgs)
46-
->mapWithKeys(function ($value) {
47-
[$key, $value] = explode('=', $value, 2);
48-
49-
return [$key => $value];
50-
})
51-
)->map(function ($value, $key) {
52-
return '--build-arg='.escapeshellarg("{$key}={$value}").' ';
53-
})->implode('')
58+
Str::slug($project).':'.$environment
5459
);
60+
61+
$buildArgs = Collection::make($manifestBuildArgs)
62+
->merge(Collection::make($cliBuildArgs)
63+
->mapWithKeys(function ($value) {
64+
[$key, $value] = explode('=', $value, 2);
65+
66+
return [$key => $value];
67+
})
68+
)->map(function ($value, $key) {
69+
return '--build-arg='.escapeshellarg("{$key}={$value}");
70+
})->implode(' ');
71+
72+
$buildOptions = Collection::make($manifestBuildOptions)
73+
->mapWithKeys(function ($value) {
74+
if (is_array($value)) {
75+
return $value;
76+
}
77+
78+
return [$value => null];
79+
})
80+
->merge(Collection::make($cliBuildOptions)
81+
->mapWithKeys(function ($value) {
82+
if (! str_contains($value, '=')) {
83+
return [$value => null];
84+
}
85+
86+
[$key, $value] = explode('=', $value, 2);
87+
88+
return [$key => $value];
89+
})
90+
)->map(function ($value, $key) {
91+
if ($value === null) {
92+
return "--{$key}";
93+
}
94+
95+
return "--{$key}=".escapeshellarg($value);
96+
})->implode(' ');
97+
98+
$command = $buildArgs ? $command.$buildArgs.' ' : $command;
99+
$command = $buildOptions ? $command.$buildOptions.' ' : $command;
100+
$command .= '.';
101+
102+
return $command;
55103
}
56104

57105
/**

src/Manifest.php

+11
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ public static function dockerBuildArgs($environment)
9595
return static::current()['environments'][$environment]['docker-build-args'] ?? [];
9696
}
9797

98+
/**
99+
* Get the Docker options.
100+
*
101+
* @param string $environment
102+
* @return array
103+
*/
104+
public static function dockerBuildOptions($environment)
105+
{
106+
return static::current()['environments'][$environment]['docker-build-options'] ?? [];
107+
}
108+
98109
/**
99110
* Determine if the environment uses a database proxy.
100111
*

tests/BuildContainerImageTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function test_docker_build_arguments_can_be_formatted_correctly()
5555
],
5656
]));
5757

58-
$buildArgs = (new BuildContainerImage('production', ['FOO=BAR', 'BAR=BAZ']))->formatBuildArguments();
58+
$buildArgs = (new BuildContainerImage('production', ['FOO=BAR', 'BAR=BAZ'], []))->formatBuildArguments();
5959

6060
$this->assertSame(['__VAPOR_RUNTIME=docker', 'FOO=BAR', 'BAR=BAZ'], $buildArgs);
6161
}
@@ -72,7 +72,7 @@ public function test_runtime_variable_cannot_be_overridden()
7272
],
7373
]));
7474

75-
$buildArgs = (new BuildContainerImage('production', ['__VAPOR_RUNTIME=foo']))->formatBuildArguments();
75+
$buildArgs = (new BuildContainerImage('production', [], ['__VAPOR_RUNTIME=foo']))->formatBuildArguments();
7676

7777
$this->assertSame(['__VAPOR_RUNTIME=docker'], $buildArgs);
7878
}

tests/DockerTest.php

+43-5
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ protected function tearDown(): void
2424

2525
public function test_build_command_no_build_args()
2626
{
27-
$command = Docker::buildCommand('my-project', 'production', [], []);
27+
$command = Docker::buildCommand('my-project', 'production', [], [], [], []);
2828
$expectedCommand = 'docker build --pull --file=production.Dockerfile --tag=my-project:production .';
2929
$this->assertEquals($expectedCommand, $command);
3030
}
3131

3232
public function test_build_command_cli_build_args()
3333
{
3434
$cliBuildArgs = ['FOO=BAR', 'FIZZ=BUZZ'];
35-
$command = Docker::buildCommand('my-project', 'production', $cliBuildArgs, []);
35+
$command = Docker::buildCommand('my-project', 'production', $cliBuildArgs, [], [], []);
3636
$expectedCommand = 'docker build --pull --file=production.Dockerfile --tag=my-project:production '.
3737
"--build-arg='FOO=BAR' --build-arg='FIZZ=BUZZ' .";
3838
$this->assertEquals($expectedCommand, $command);
@@ -41,7 +41,7 @@ public function test_build_command_cli_build_args()
4141
public function test_build_command_manifest_build_args()
4242
{
4343
$manifestBuildArgs = ['FOO' => 'BAR', 'FIZZ' => 'BUZZ'];
44-
$command = Docker::buildCommand('my-project', 'production', [], $manifestBuildArgs);
44+
$command = Docker::buildCommand('my-project', 'production', [], $manifestBuildArgs, [], []);
4545
$expectedCommand = 'docker build --pull --file=production.Dockerfile --tag=my-project:production '.
4646
"--build-arg='FOO=BAR' --build-arg='FIZZ=BUZZ' .";
4747
$this->assertEquals($expectedCommand, $command);
@@ -51,12 +51,50 @@ public function test_build_command_cli_and_manifest_build_args()
5151
{
5252
$cliBuildArgs = ['BAR=FOO', 'FIZZ=BAZZ'];
5353
$manifestBuildArgs = ['FOO' => 'BAR', 'FIZZ' => 'BUZZ'];
54-
$command = Docker::buildCommand('my-project', 'production', $cliBuildArgs, $manifestBuildArgs);
54+
$command = Docker::buildCommand('my-project', 'production', $cliBuildArgs, $manifestBuildArgs, [], []);
5555
$expectedCommand = 'docker build --pull --file=production.Dockerfile --tag=my-project:production '.
5656
"--build-arg='FOO=BAR' --build-arg='FIZZ=BAZZ' --build-arg='BAR=FOO' .";
5757
$this->assertEquals($expectedCommand, $command);
5858
}
5959

60+
public function test_build_command_cli_docker_options()
61+
{
62+
$cliBuildOptions = ['BAR=FOO', 'FIZZ=BAZZ', 'FIZZLE', 'BUZZLE'];
63+
$command = Docker::buildCommand('my-project', 'production', [], [], $cliBuildOptions, []);
64+
$expectedCommand = 'docker build --pull --file=production.Dockerfile --tag=my-project:production '.
65+
"--BAR='FOO' --FIZZ='BAZZ' --FIZZLE --BUZZLE .";
66+
$this->assertEquals($expectedCommand, $command);
67+
}
68+
69+
public function test_build_command_manifest_docker_options()
70+
{
71+
$manifestBuildOptions = [['FOO' => 'BAR'], ['FIZZ' => 'BUZZ'], 'FIZZLE', 'BUZZLE'];
72+
$command = Docker::buildCommand('my-project', 'production', [], [], [], $manifestBuildOptions);
73+
$expectedCommand = 'docker build --pull --file=production.Dockerfile --tag=my-project:production '.
74+
"--FOO='BAR' --FIZZ='BUZZ' --FIZZLE --BUZZLE .";
75+
$this->assertEquals($expectedCommand, $command);
76+
}
77+
78+
public function test_build_command_cli_and_manifest_docker_args()
79+
{
80+
$cliBuildOptions = ['BAR=FOO', 'FIZZ=BAZZ', 'FIZZLE', 'BUZZLE'];
81+
$manifestBuildOptions = [['FOO' => 'BAR'], ['FIZZ' => 'BUZZ'], 'FIZZLY', 'BUZZLY'];
82+
$command = Docker::buildCommand('my-project', 'production', [], [], $cliBuildOptions, $manifestBuildOptions);
83+
$expectedCommand = 'docker build --pull --file=production.Dockerfile --tag=my-project:production '.
84+
"--FOO='BAR' --FIZZ='BAZZ' --FIZZLY --BUZZLY --BAR='FOO' --FIZZLE --BUZZLE .";
85+
$this->assertEquals($expectedCommand, $command);
86+
}
87+
88+
public function test_build_command_cli_docker_options_and_cli_build_args()
89+
{
90+
$cliBuildOptions = ['BAR=FOO', 'FIZZ=BAZZ'];
91+
$cliBuildArgs = ['BAR=FOO', 'FIZZ=BAZZ'];
92+
$command = Docker::buildCommand('my-project', 'production', $cliBuildArgs, [], $cliBuildOptions, []);
93+
$expectedCommand = 'docker build --pull --file=production.Dockerfile --tag=my-project:production '.
94+
"--build-arg='BAR=FOO' --build-arg='FIZZ=BAZZ' --BAR='FOO' --FIZZ='BAZZ' .";
95+
$this->assertEquals($expectedCommand, $command);
96+
}
97+
6098
public function test_dockerfile_from_manifest()
6199
{
62100
file_put_contents(Container::getInstance()->offsetGet('manifest'), Yaml::dump([
@@ -69,7 +107,7 @@ public function test_dockerfile_from_manifest()
69107
],
70108
],
71109
]));
72-
$command = Docker::buildCommand('my-project', 'production', [], []);
110+
$command = Docker::buildCommand('my-project', 'production', [], [], [], []);
73111
$expectedCommand = 'docker build --pull --file=docker/shared.Dockerfile --tag=my-project:production .';
74112
$this->assertEquals($expectedCommand, $command);
75113
}

0 commit comments

Comments
 (0)