Skip to content

Commit

Permalink
feat: new docker-copy action for artifact based deployments
Browse files Browse the repository at this point in the history
  • Loading branch information
stmh committed Nov 7, 2023
1 parent 65aca2d commit a036353
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 16 deletions.
34 changes: 24 additions & 10 deletions docs/deploying-artifacts.md
Expand Up @@ -126,12 +126,12 @@ hosts:

the default actions for the git-artifact-method will copy all files to the target repo and remove the fabfile.

| property | default value | description |
|-----------------------|---------------|-------------------------------------------|
| `artifact.branch` | `false` | if set to false, the name of the source-branch is used, otherwise the value |
| property | default value | description |
|-----------------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------|
| `artifact.branch` | `false` | if set to false, the name of the source-branch is used, otherwise the value |
| `artifact.baseBranch` | `master` | If phabalicious needs to create a new branch, because it is missing from the target-repository, then start the branch from `masterBranch` |
| `artifact.repository` | | The url to the target-repository |
| `artifact.actions` | | Actions to perform |
| `artifact.repository` | | The url to the target-repository |
| `artifact.actions` | | Actions to perform |


Phab will use a shallow clone for the target repository to keep resources low. If you need to use a deep copy for the target repository, you can adapt the gitOptions like:
Expand All @@ -155,11 +155,24 @@ You can force the artifact based deployment by adding the `--force`-option, or b

You can customize the list of actions be run when deploying an artifact. Here's a list of available actions

### docker-copy

```yaml
- action: docker-copy
arguments:
image: "%settings.gitlab.imageBaseTag%/builder:%host.branch%"
imageRootPath: /app
from: "*"
to: .
```

This action will copy the listed files from `from` inside the docker image `image` to `to`. If `from` is '*' phabalicious will ge the contents of the directory. As the copy is initiated from the container, make sure that the `imageRootPath` points to a valid directory inside the container. The `image`-property supports replacement patterns, in the example case it will get the image name from the gitlab settings and the branch from the host-config. Phab will try to pull the latest image before running the action. The action supports the `excludeFiles.gitSync` settings to skip certain files and folders (it defaults to `.git`).

### copy

```yaml
- action: copy
argumnents:
arguments:
from:
- file1
- folder2
Expand All @@ -169,6 +182,7 @@ You can customize the list of actions be run when deploying an artifact. Here's

This will copy the three mentioned files and folders into the subfolder `targetsubfolder` of the target folder. Please be aware, that you might need to create subdirectories beforehand manually via the `script`-method. Also be aware that copy action deletes existing files and folders from target before doing the copy, if you want to combine files from multiple sources it is better to also use the `script`-method for that.

The action supports the `excludeFiles.gitSync` settings to skip certain files and folders (it defaults to `.git`).
### delete

```yaml
Expand Down Expand Up @@ -224,10 +238,10 @@ This action comes handy when degugging the build process, as it will stop the ex

The `script`-action will run the script from the arguments section line by line. You can use the usual replacement patterns as for other scripts. Most helpful are:

| Pattern | Description |
|---------|-------------|
| `%context.data.installDir%` | The installation dir, where the app got installed into |
| `%context.data.targetDir%` | The targetdir, where the app got copied to, which gets committed or synced |
| Pattern | Description |
|-----------------------------|----------------------------------------------------------------------------|
| `%context.data.installDir%` | The installation dir, where the app got installed into |
| `%context.data.targetDir%` | The targetdir, where the app got copied to, which gets committed or synced |

If `arguments` contains a name, then this named script will be executed. It should be available under the global `scripts`-section or on the hosts' scripts section.

Expand Down
32 changes: 26 additions & 6 deletions src/Artifact/Actions/Base/DockerCopyAction.php
Expand Up @@ -16,17 +16,20 @@ class DockerCopyAction extends ActionBase

protected function validateArgumentsConfig(array $action_arguments, ValidationService $validation)
{
$validation->hasKey('imageRootPath', 'action needs an image root path which is inside the images file system');
$validation->hasKey('image', 'action needs a docker image argument');
$validation->hasKey('to', 'action needs a to argument');
$validation->hasKey('from', 'action needs a from argument');
}

public function run(HostConfig $host_config, TaskContextInterface $context) {
public function run(HostConfig $host_config, TaskContextInterface $context)
{
$this->getDockerImage($host_config, $context);
parent::run($host_config, $context); // TODO: Change the autogenerated stub
}

protected function getDockerImage(HostConfig $host_config, TaskContextInterface $context) {
protected function getDockerImage(HostConfig $host_config, TaskContextInterface $context)
{
$variables = Utilities::buildVariablesFrom($host_config, $context);
$replacements = Utilities::expandVariables($variables);

Expand All @@ -36,11 +39,14 @@ protected function getDockerImage(HostConfig $host_config, TaskContextInterface
protected function getDirectoryContents(ShellProviderInterface $shell, string $path)
{
$result = $shell->run(sprintf(
'docker run --entrypoint %s --rm %s -- cd %s && ls -1a',
$this->getArgument('entryPoint', '/bin/sh'),
'docker run --entrypoint /bin/ls --rm %s -1a %s',
$this->dockerImageName,
$path
), true);

if ($result->failed()) {
$result->throwException('Could not get directory contents from docker image!');
}
return $result->getOutput();
}

Expand All @@ -53,10 +59,21 @@ protected function runImplementation(
) {
$shell->pushWorkingDir($install_dir);

if ($this->getArgument('imagePull', true)) {
$shell->run(sprintf('docker pull -q %s', $this->dockerImageName));
}

$image_root_path = $this->getArgument('imageRootPath', $install_dir);
$files_to_copy = $this->getArgument('from');

if (!is_array($files_to_copy)) {
if ($files_to_copy === '*') {
$files_to_copy = $this->getDirectoryContents($shell, $this->getArgument('imageRootPath', $install_dir));
$files_to_copy = array_filter(
$this->getDirectoryContents($shell, $image_root_path),
static function ($e) {
return !in_array($e, ['.', '..']);
}
);
} else {
$files_to_copy = [$files_to_copy];
}
Expand All @@ -71,12 +88,15 @@ protected function runImplementation(
// Make sure the target directory exists before copying.
$shell->run(sprintf('mkdir -p %s', $to));

$docker_container = Utilities::getTempNamePrefixFromString('phab-docker-copy');
$shell->run(sprintf('docker create --name %s %s', $docker_container, $this->dockerImageName), false, true);
foreach ($files_to_copy as $file) {
if (!in_array($file, $files_to_skip)) {
$shell->run(sprintf('rm -rf %s', $to . '/' . basename($file)));
$shell->run(sprintf('cp -a %s %s', $file, $to));
$shell->run(sprintf('docker cp -a %s:%s/%s %s', $docker_container, $image_root_path, $file, $to));
}
}
$shell->run(sprintf('docker rm %s', $docker_container), false, true);

$shell->popWorkingDir();
}
Expand Down

0 comments on commit a036353

Please sign in to comment.