Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@ on:
branches:
- main
- develop
- feature/*
jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
include:
- php: "8.1"
phpunit: "10"
phpunit-config: "phpunit-10.xml.dist"
- php: "8.2"
phpunit: "11"
phpunit-config: "phpunit.xml.dist"
phpunit-config: "phpunit-11.xml.dist"
- php: "8.3"
phpunit: "11"
phpunit: "12"
phpunit-config: "phpunit-12.xml.dist"
- php: "8.4"
phpunit: "13"
phpunit-config: "phpunit.xml.dist"

steps:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ Tests/data/**
!Tests/data/temp/.empty
composer.lock
.phpunit.cache
GEMINI.md
AGENTS.md
22 changes: 20 additions & 2 deletions Asm/Ansible/Ansible.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use Asm\Ansible\Command\AnsibleGalaxy;
use Asm\Ansible\Command\AnsibleGalaxyInterface;
use Asm\Ansible\Command\AnsibleGalaxyCollection;
use Asm\Ansible\Command\AnsibleGalaxyCollectionInterface;
use Asm\Ansible\Command\AnsiblePlaybook;
use Asm\Ansible\Command\AnsiblePlaybookInterface;
use Asm\Ansible\Exception\CommandException;
Expand Down Expand Up @@ -44,8 +46,11 @@ final class Ansible implements LoggerAwareInterface
* @param string $playbookCommand path to playbook executable, default ansible-playbook
* @param string $galaxyCommand path to galaxy executable, default ansible-galaxy
*/
public function __construct(string $ansibleBaseDir, string $playbookCommand = '', string $galaxyCommand = '')
{
public function __construct(
string $ansibleBaseDir,
string $playbookCommand = '',
string $galaxyCommand = ''
) {
$this->ansibleBaseDir = $this->checkDir($ansibleBaseDir);
$this->playbookCommand = $this->checkCommand($playbookCommand, 'ansible-playbook');
$this->galaxyCommand = $this->checkCommand($galaxyCommand, 'ansible-galaxy');
Expand Down Expand Up @@ -80,6 +85,19 @@ public function galaxy(): AnsibleGalaxyInterface
);
}

/**
* AnsibleGalaxyCollection instance creator
*
* @return AnsibleGalaxyCollectionInterface
*/
public function galaxyCollection(): AnsibleGalaxyCollectionInterface
{
return new AnsibleGalaxyCollection(
$this->createProcess($this->galaxyCommand),
$this->logger
);
}

/**
* Set process timeout in seconds.
*
Expand Down
61 changes: 61 additions & 0 deletions Asm/Ansible/Collection/AnsibleCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace Asm\Ansible\Collection;

use Asm\Ansible\Process\ProcessRunner;
use Asm\Ansible\Process\ProcessResult;
use Asm\Ansible\Exception\CollectionException;

class AnsibleCollection
{
public function __construct(
private readonly ProcessRunner $processRunner
) {
}

public function install(string $collection, ?string $version = null): ProcessResult
{
$command = ['ansible-galaxy', 'collection', 'install'];
$command[] = $version ? "$collection:$version" : $collection;

$result = $this->processRunner->run($command);

if (!$result->isSuccessful()) {
throw new CollectionException(
"Failed to install collection: $collection",
$result->getExitCode(),
null,
implode(' ', $command),
$result->getOutput()
);
}

return $result;
}

public function list(): ProcessResult
{
return $this->processRunner->run(['ansible-galaxy', 'collection', 'list']);
}

public function uninstall(string $collection): ProcessResult
{
$command = ['ansible-galaxy', 'collection', 'remove', $collection];

$result = $this->processRunner->run($command);

if (!$result->isSuccessful()) {
throw new CollectionException(
"Failed to uninstall collection: $collection",
$result->getExitCode(),
null,
implode(' ', $command),
$result->getOutput()
);
}

return $result;
}
}
14 changes: 12 additions & 2 deletions Asm/Ansible/Command/AbstractAnsibleCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ abstract class AbstractAnsibleCommand
* @param ProcessBuilderInterface $processBuilder
* @param LoggerInterface|null $logger
*/
public function __construct(ProcessBuilderInterface $processBuilder, LoggerInterface $logger = null)
public function __construct(ProcessBuilderInterface $processBuilder, ?LoggerInterface $logger = null)
{
$this->processBuilder = $processBuilder;
$this->options = [];
Expand All @@ -59,7 +59,7 @@ public function __construct(ProcessBuilderInterface $processBuilder, LoggerInter
protected function prepareArguments(bool $asArray = true): string|array
{
$arguments = array_merge(
[$this->getBaseOptions()],
$this->getBaseOptionsAsArray(),
$this->getOptions(),
$this->getParameters()
);
Expand Down Expand Up @@ -142,6 +142,16 @@ protected function getBaseOptions(): string
return implode(' ', $this->baseOptions);
}

/**
* Get base options as array.
*
* @return array
*/
protected function getBaseOptionsAsArray(): array
{
return $this->baseOptions;
}

/**
* Check if param is array or string and implode with glue if necessary.
*
Expand Down
25 changes: 21 additions & 4 deletions Asm/Ansible/Command/AnsibleGalaxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public function execute(?callable $callback = null): int|string
public function init(string $roleName): AnsibleGalaxyInterface
{
$this
->addBaseOption('role')
->addBaseOption('init')
->addBaseOption($roleName);

Expand All @@ -51,6 +52,7 @@ public function info(string $role, string $version = ''): AnsibleGalaxyInterface
}

$this
->addBaseOption('role')
->addBaseOption('info')
->addBaseOption($role);

Expand All @@ -70,10 +72,16 @@ public function install(string|array $roles = ''): AnsibleGalaxyInterface
{
$roles = $this->checkParam($roles, ' ');

$this->addBaseOption('role');
$this->addBaseOption('install');

if ('' !== $roles) {
$this->addBaseOption($roles);
$rolesArray = explode(' ', $roles);
foreach ($rolesArray as $role) {
if ($role !== '') {
$this->addBaseOption($role);
}
}
}

return $this;
Expand All @@ -87,6 +95,7 @@ public function install(string|array $roles = ''): AnsibleGalaxyInterface
*/
public function modulelist(string $roleName = ''): AnsibleGalaxyInterface
{
$this->addBaseOption('role');
$this->addBaseOption('list');

if ('' !== $roleName) {
Expand All @@ -106,9 +115,17 @@ public function remove(string|array $roles = ''): AnsibleGalaxyInterface
{
$roles = $this->checkParam($roles, ' ');

$this
->addBaseOption('remove')
->addBaseOption($roles);
$this->addBaseOption('role');
$this->addBaseOption('remove');

if ('' !== $roles) {
$rolesArray = explode(' ', $roles);
foreach ($rolesArray as $role) {
if ($role !== '') {
$this->addBaseOption($role);
}
}
}

return $this;
}
Expand Down
149 changes: 149 additions & 0 deletions Asm/Ansible/Command/AnsibleGalaxyCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php

declare(strict_types=1);

namespace Asm\Ansible\Command;

/**
* Class AnsibleGalaxyCollection
*
* @package Asm\Ansible\Command
*/
final class AnsibleGalaxyCollection extends AbstractAnsibleCommand implements AnsibleGalaxyCollectionInterface
{
/**
* Executes a command process.
* Returns either exitcode or string output if no callback is given.
*
* @param callable|null $callback
* @return integer|string
*/
public function execute(?callable $callback = null): int|string
{
return $this->runProcess($callback);
}

/**
* Initialize a new collection with base structure.
*
* @param string $collectionName
* @return AnsibleGalaxyCollectionInterface
*/
public function init(string $collectionName): AnsibleGalaxyCollectionInterface
{
$this
->addBaseOption('collection')
->addBaseOption('init')
->addBaseOption($collectionName);

return $this;
}

/**
* Build an Ansible collection artifact that can be published to Ansible Galaxy.
*
* @param string $collectionPath
* @return AnsibleGalaxyCollectionInterface
*/
public function build(string $collectionPath = ''): AnsibleGalaxyCollectionInterface
{
$this->addBaseOption('collection');
$this->addBaseOption('build');

if ('' !== $collectionPath) {
$this->addBaseOption($collectionPath);
}

return $this;
}

/**
* Publish a collection artifact to Ansible Galaxy.
*
* @param string $artifactPath
* @return AnsibleGalaxyCollectionInterface
*/
public function publish(string $artifactPath): AnsibleGalaxyCollectionInterface
{
$this->addBaseOption('collection');
$this->addBaseOption('publish');
$this->addBaseOption($artifactPath);

return $this;
}

/**
* Install collection(s).
*
* @param string|array $collections collection_name(s) | path/to/collection.tar.gz
* @return AnsibleGalaxyCollectionInterface
*/
public function install(string|array $collections = ''): AnsibleGalaxyCollectionInterface
{
$collections = $this->checkParam($collections, ' ');

$this->addBaseOption('collection');
$this->addBaseOption('install');

if ('' !== $collections) {
$collectionsArray = explode(' ', $collections);
foreach ($collectionsArray as $collection) {
if ($collection !== '') {
$this->addBaseOption($collection);
}
}
}

return $this;
}

/**
* The path in which the skeleton collection will be created.
* The default is the current working directory.
*
* @param string $path
* @return AnsibleGalaxyCollectionInterface
*/
public function initPath(string $path = ''): AnsibleGalaxyCollectionInterface
{
$this->addOption('--init-path', $path);

return $this;
}

/**
* Force overwriting an existing collection.
*
* @return AnsibleGalaxyCollectionInterface
*/
public function force(): AnsibleGalaxyCollectionInterface
{
$this->addParameter('--force');

return $this;
}

/**
* The path to the directory containing your collections.
*
* @param string $collectionsPath
* @return AnsibleGalaxyCollectionInterface
*/
public function collectionsPath(string $collectionsPath): AnsibleGalaxyCollectionInterface
{
$this->addOption('--collections-path', $collectionsPath);

return $this;
}

/**
* Get parameter string which will be used to call ansible.
*
* @param bool $asArray
* @return string|array
*/
public function getCommandlineArguments(bool $asArray = true): string|array
{
return $this->prepareArguments($asArray);
}
}
Loading
Loading