diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index 4ae65c4..5f2506a 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -12,13 +12,15 @@ jobs:
strategy:
matrix:
- php:
- - "8.0"
- - "8.1"
- - "8.2"
include:
- - php-version: "8.0"
- phpunit: "9.5"
+ - php: "8.1"
+ phpunit: "10"
+ phpunit-config: "phpunit-10.xml.dist"
+ - php: "8.2"
+ phpunit: "11"
+ phpunit-config: "phpunit.xml.dist"
+ - php: "8.3"
+ phpunit: "11"
phpunit-config: "phpunit.xml.dist"
steps:
@@ -28,12 +30,12 @@ jobs:
php-version: "${{ matrix.php }}"
extensions: redis, apcu, ctype, dom, iconv, gd, mbstring, fileinfo, intl, json, mysql, bcmath, zip
coverage: none # disable xdebug, pcov
- ini-values: post_max_size=256M memory
+ #ini-values: post_max_size=256M memory
tools: cs2pr, pecl, php-cs-fixer, vimeo/psalm, phpstan, phpcs
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- - uses: "ramsey/composer-install@v2"
+ - uses: "ramsey/composer-install@v3"
with:
composer-options: "--no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist -q"
@@ -41,8 +43,10 @@ jobs:
uses: php-actions/phpunit@v3
with:
version: "${{ matrix.phpunit }}"
+ php_version: "${{matrix.php}}"
configuration: "${{ matrix.phpunit-config }}"
memory_limit: "256M"
+ test_suffix: .php
- name: Run phpstan
run: phpstan analyse --error-format=checkstyle -c "phpstan.neon" | cs2pr
diff --git a/Asm/Ansible/Command/AbstractAnsibleCommand.php b/Asm/Ansible/Command/AbstractAnsibleCommand.php
index d3e6829..41cbefa 100644
--- a/Asm/Ansible/Command/AbstractAnsibleCommand.php
+++ b/Asm/Ansible/Command/AbstractAnsibleCommand.php
@@ -34,6 +34,8 @@ abstract class AbstractAnsibleCommand
private array $baseOptions;
+ private bool $useStdoutForError;
+
/**
* @param ProcessBuilderInterface $processBuilder
* @param LoggerInterface|null $logger
@@ -44,6 +46,7 @@ public function __construct(ProcessBuilderInterface $processBuilder, LoggerInter
$this->options = [];
$this->parameters = [];
$this->baseOptions = [];
+ $this->useStdoutForError = false;
$this->setLogger($logger ?? new NullLogger());
}
@@ -183,7 +186,7 @@ protected function runProcess(?callable $callback): int|string
// if no callback is set, and the process is not successful, we return the output
if (false === $process->isSuccessful()) {
- return $process->getErrorOutput();
+ return $this->useStdoutForError ? $process->getOutput() : $process->getErrorOutput();
}
// if no callback is set, and the process is successful, we return the output
@@ -210,4 +213,14 @@ protected function getProcessCommandline(Process $process): string
return sprintf('%s %s', implode(' ', $vars), $commandline);
}
+
+ /**
+ * in case ansible explicitly is in json mode, this will be set to be able to get error outputs
+ *
+ * @return void
+ */
+ protected function useStdoutForError(): void
+ {
+ $this->useStdoutForError = true;
+ }
}
diff --git a/Asm/Ansible/Command/AnsiblePlaybook.php b/Asm/Ansible/Command/AnsiblePlaybook.php
index f68535d..a1c8c92 100644
--- a/Asm/Ansible/Command/AnsiblePlaybook.php
+++ b/Asm/Ansible/Command/AnsiblePlaybook.php
@@ -408,6 +408,7 @@ public function colors(bool $colors = true): AnsiblePlaybookInterface
public function json(): AnsiblePlaybookInterface
{
$this->processBuilder->setEnv('ANSIBLE_STDOUT_CALLBACK', 'json');
+ $this->useStdoutForError();
return $this;
}
@@ -728,12 +729,12 @@ public function hostKeyChecking(bool $enable = true): AnsiblePlaybookInterface
}
/**
- * Ansible SSH pipelining option
- * https://docs.ansible.com/ansible/latest/reference_appendices/config.html#ansible-pipelining
- *
- * @param bool $enable
- * @return AnsiblePlaybookInterface
- **/
+ * Ansible SSH pipelining option
+ * https://docs.ansible.com/ansible/latest/reference_appendices/config.html#ansible-pipelining
+ *
+ * @param bool $enable
+ * @return AnsiblePlaybookInterface
+ **/
public function sshPipelining(bool $enable = false): AnsiblePlaybookInterface
{
$enable ?
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..b6aff1b
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,24 @@
+FROM php:8.3-cli
+
+WORKDIR /app
+
+ENV ANSIBLE_VERSION 2.9.17
+
+# composer
+RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
+ && php -r "if (hash_file('sha384', 'composer-setup.php') === 'dac665fdc30fdd8ec78b38b9800061b4150413ff2e3b6f88543c636f7cd84f6db9189d43a81e5503cda447da73c7e5b6') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
+ && php composer-setup.php \
+ && php -r "unlink('composer-setup.php');" \
+ && mv composer.phar /usr/bin/composer \
+ && chmod +x /usr/bin/composer
+
+# python, pipx & ansible
+RUN apt-get update \
+ && apt-get install -y gcc python3 git zip 7zip unzip pipx \
+ && apt-get clean all; \
+ pipx install --upgrade pip; \
+ pipx install "ansible==${ANSIBLE_VERSION}"; \
+ pipx install ansible;
+
+# keep container running
+CMD [ "bash", "-c", "echo 'running'; tail -f /dev/null" ]
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ad88589
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,66 @@
+# Executables (local)
+DOCKER_COMP = docker compose
+
+# Docker containers
+PHP_CONT = $(DOCKER_COMP) exec php-ansible
+
+# Executables
+PHP = $(PHP_CONT) php
+COMPOSER = $(PHP_CONT) composer
+
+# Misc
+.DEFAULT_GOAL = help
+
+## —— php-ansible Makefile 🎵 ——————————————————————————————————
+help: ## Outputs this help screen
+ @grep -E '(^[a-zA-Z0-9\./_-]+:.*?##.*$$)|(^##)' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}{printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' | sed -e 's/\[32m##/[33m/'
+
+## —— Docker 🐳 ————————————————————————————————————————————————————————————————
+build: ## Builds the Docker images
+ @$(DOCKER_COMP) build --pull --no-cache
+
+up: ## Start the docker hub in detached mode (no logs)
+ @$(DOCKER_COMP) up --detach
+
+start: build up ## Build and start the containers
+
+down: ## Stop the docker hub
+ @$(DOCKER_COMP) down --remove-orphans
+
+logs: ## Show live logs
+ @$(DOCKER_COMP) logs --tail=0 --follow
+
+sh: ## Connect to the php-fpm container
+ @$(PHP_CONT) sh
+
+bash: ## Connect to the php-fpm container via bash so up and down arrows go to previous commands
+ @$(PHP_CONT) bash
+
+test: ## Start tests with phpunit, pass the parameter "c=" to add options to phpunit, example: make test c="--group e2e --stop-on-failure"
+ @$(eval c ?=)
+ @$(PHP_CONT) vendor/bin/phpunit -c phpunit.xml.dist $(c)
+
+analyze: ## Start analysis with phpstan, pass the parameter "c=" to add options to phpstan. Default config ist always used, example: make analyze c="--group e2e"
+ @$(eval c ?=)
+ @$(PHP_CONT) vendor/bin/phpstan --configuration=phpstan.neon $(c)
+
+codestyle: ## Start codestyle analysis with phpcs, pass the parameter "c=" to add options to phpcs. Default config ist always used. Example: make codestyle c="--parallel=2"
+ @$(eval c ?=)
+ @$(PHP_CONT) vendor/bin/phpcs --standard=phpcs.xml.dist $(c)
+
+codestyle-fix: ## Start codestyle analysis with phpcbf, pass the parameter "c=" to add options to phpcbf. Default config ist always used. Example: make codestyle c="--parallel=2"
+ @$(eval c ?=)
+ @$(PHP_CONT) vendor/bin/phpcbf --standard=phpcs.xml.dist $(c)
+
+psalm: ## Start code analysis with psalm, pass the parameter "c=" to add options to psalm. Default config ist always used. Example: make codestyle c="--level=2"
+ @$(eval c ?=)
+ @$(DOCKER_COMP) exec -e APP_ENV=dev php vendor/bin/psalm --config=psalm.xml $(c)
+
+## —— Composer 🧙 ——————————————————————————————————————————————————————————————
+composer: ## Run composer, pass the parameter "c=" to run a given command, example: make composer c='req phpstan/phpstan'
+ @$(eval c ?=)
+ @$(COMPOSER) $(c)
+
+vendor: ## Install vendors according to the current composer.lock file
+vendor: c=install --prefer-dist --no-dev --no-progress --no-scripts --no-interaction
+vendor: composer
\ No newline at end of file
diff --git a/README.md b/README.md
index 98db526..44d619d 100644
--- a/README.md
+++ b/README.md
@@ -162,7 +162,12 @@ $ansible
…
```
+## Development
+You can use the provided docker image with ```make build``` which uses a default php-cli docker image and ansible 2.x. See the ```Dockerfile``` for more info.
+Start the container with ```make up```.
+Composer install: ```make vendor```
+You can run code or the tests within the container: ```make test c="--testdox"```
## Thank you for your contributions!
@@ -178,7 +183,6 @@ The Next steps for implementation are:
- improve type handling and structure, due to overall complexity of the playbook at the moment
- scalar typehints all over the place
- provide docker support for development
-- move to php8.0 exclusively for the next major release
- wrapping the library into a bundle -> maybe
- provide commandline-capabilities -> maybe
diff --git a/Tests/Asm/Ansible/AnsibleTest.php b/Tests/Asm/Ansible/AnsibleTest.php
index 0ae6627..9d29772 100644
--- a/Tests/Asm/Ansible/AnsibleTest.php
+++ b/Tests/Asm/Ansible/AnsibleTest.php
@@ -1,26 +1,24 @@
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
+
+declare(strict_types=1);
namespace Asm\Ansible;
use Asm\Ansible\Exception\CommandException;
use Asm\Ansible\Testing\AnsibleTestCase;
use org\bovigo\vfs\vfsStream;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\CoversFunction;
+#[CoversClass(\Asm\Ansible\Ansible::class)]
+#[CoversFunction('playbook')]
+#[CoversFunction('createProcess')]
+#[CoversFunction('checkCommand')]
+#[CoversFunction('checkDir')]
+#[CoversFunction('__construct')]
class AnsibleTest extends AnsibleTestCase
{
- /**
- * @covers \Asm\Ansible\Ansible::checkCommand
- * @covers \Asm\Ansible\Ansible::checkDir
- * @covers \Asm\Ansible\Ansible::__construct
- */
+
public function testInstance()
{
$ansible = new Ansible(
@@ -31,11 +29,6 @@ public function testInstance()
$this->assertInstanceOf('\Asm\Ansible\Ansible', $ansible, 'Instantiation with given paths');
}
- /**
- * @covers \Asm\Ansible\Ansible::checkCommand
- * @covers \Asm\Ansible\Ansible::checkDir
- * @covers \Asm\Ansible\Ansible::__construct
- */
public function testAnsibleProjectPathNotFoundException()
{
$this->expectException(CommandException::class);
@@ -46,11 +39,6 @@ public function testAnsibleProjectPathNotFoundException()
);
}
- /**
- * @covers \Asm\Ansible\Ansible::checkCommand
- * @covers \Asm\Ansible\Ansible::checkDir
- * @covers \Asm\Ansible\Ansible::__construct
- */
public function testAnsibleCommandNotFoundException()
{
$this->expectException(CommandException::class);
@@ -61,11 +49,6 @@ public function testAnsibleCommandNotFoundException()
);
}
- /**
- * @covers \Asm\Ansible\Ansible::checkCommand
- * @covers \Asm\Ansible\Ansible::checkDir
- * @covers \Asm\Ansible\Ansible::__construct
- */
public function testAnsibleNoCommandGivenException()
{
// TODO: Not sure why the following command should give an error.
@@ -75,11 +58,6 @@ public function testAnsibleNoCommandGivenException()
// );
}
- /**
- * @covers \Asm\Ansible\Ansible::checkCommand
- * @covers \Asm\Ansible\Ansible::checkDir
- * @covers \Asm\Ansible\Ansible::__construct
- */
public function testAnsibleCommandNotExecutableException()
{
$this->expectException(CommandException::class);
@@ -94,13 +72,6 @@ public function testAnsibleCommandNotExecutableException()
);
}
- /**
- * @covers \Asm\Ansible\Ansible::playbook
- * @covers \Asm\Ansible\Ansible::createProcess
- * @covers \Asm\Ansible\Ansible::checkCommand
- * @covers \Asm\Ansible\Ansible::checkDir
- * @covers \Asm\Ansible\Ansible::__construct
- */
public function testPlaybookCommandInstance()
{
$ansible = new Ansible(
@@ -114,13 +85,6 @@ public function testPlaybookCommandInstance()
$this->assertInstanceOf('\Asm\Ansible\Command\AnsiblePlaybook', $playbook);
}
- /**
- * @covers \Asm\Ansible\Ansible::galaxy
- * @covers \Asm\Ansible\Ansible::createProcess
- * @covers \Asm\Ansible\Ansible::checkCommand
- * @covers \Asm\Ansible\Ansible::checkDir
- * @covers \Asm\Ansible\Ansible::__construct
- */
public function testGalaxyCommandInstance()
{
$ansible = new Ansible(
diff --git a/Tests/Asm/Ansible/Command/AnsibleGalaxyTest.php b/Tests/Asm/Ansible/Command/AnsibleGalaxyTest.php
index d8d1308..98d1821 100644
--- a/Tests/Asm/Ansible/Command/AnsibleGalaxyTest.php
+++ b/Tests/Asm/Ansible/Command/AnsibleGalaxyTest.php
@@ -23,11 +23,7 @@ public function testCreateInstance(): AnsibleGalaxyInterface
return $ansibleGalaxy;
}
- /**
- * @depends testCreateInstance
- * @param AnsibleGalaxyInterface $command
- */
- public function testExecute(AnsibleGalaxyInterface $command): void
+ public function testExecute(): void
{
// Skipped on Windows
if (Env::isWindows()) {
@@ -35,6 +31,7 @@ public function testExecute(AnsibleGalaxyInterface $command): void
return;
}
+ $command = $this->testCreateInstance();
$command->execute();
// if command executes without exception
diff --git a/Tests/Asm/Ansible/Command/AnsiblePlaybookTest.php b/Tests/Asm/Ansible/Command/AnsiblePlaybookTest.php
index 3c50ada..32cc499 100644
--- a/Tests/Asm/Ansible/Command/AnsiblePlaybookTest.php
+++ b/Tests/Asm/Ansible/Command/AnsiblePlaybookTest.php
@@ -30,13 +30,11 @@ public function testCreateInstance(): AnsiblePlaybookInterface
}
/**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
* @throws Exception
*/
- public function testDefaultDeployment(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+ public function testDefaultDeployment(): AnsiblePlaybookInterface
{
+ $command = $this->testCreateInstance();
$today = new DateTime();
$command
@@ -52,81 +50,56 @@ public function testDefaultDeployment(AnsiblePlaybookInterface $command): Ansibl
return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testAskPassArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+ public function testAskPassArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->askPass();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--ask-pass', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testAskSuPassArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+ public function testAskSuPassArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->askSuPass();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--ask-su-pass', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testAskBecomePassArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testAskBecomePassArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->askBecomePass();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--ask-become-pass', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testAskVaultPassArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testAskVaultPassArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->askVaultPass();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--ask-vault-pass', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testConnectionArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testConnectionArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->connection();
@@ -139,51 +112,36 @@ public function testConnectionArgumentPresent(AnsiblePlaybookInterface $command)
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--connection=test', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testDiffArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testDiffArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->diff();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--diff', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testForceHandlersArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testForceHandlersArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->forceHandlers();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--force-handlers', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testForksArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testForksArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->forks();
@@ -196,34 +154,24 @@ public function testForksArgumentPresent(AnsiblePlaybookInterface $command): Ans
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--forks=10', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testHelpArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testHelpArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->help();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--help', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testLimitArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testLimitArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->limit('test');
@@ -242,51 +190,36 @@ public function testLimitArgumentPresent(AnsiblePlaybookInterface $command): Ans
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--limit=test,more,some', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testlistHostsArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testlistHostsArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->listHosts();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--list-hosts', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testListTasksArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testListTasksArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->listTasks();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--list-tasks', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testModulePathArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testModulePathArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->modulePath();
@@ -299,34 +232,24 @@ public function testModulePathArgumentPresent(AnsiblePlaybookInterface $command)
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--module-path=/test,/narf', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testPrivateKeyArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testPrivateKeyArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->privateKey('/path/to/private/key');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--private-key=/path/to/private/key', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testSkipTagsArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testSkipTagsArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->skipTags('test');
@@ -345,68 +268,48 @@ public function testSkipTagsArgumentPresent(AnsiblePlaybookInterface $command):
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--skip-tags=test,another', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testStartAtTaskArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testStartAtTaskArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->startAtTask('test');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--start-at-task=test', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testStepArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testStepArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->step();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--step', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testSuArgumentPresent(AnsiblePlaybookInterface $command)
+
+ public function testSuArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->su();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--su', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testSuUserArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testSuUserArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->suUser();
@@ -419,34 +322,24 @@ public function testSuUserArgumentPresent(AnsiblePlaybookInterface $command): An
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--su-user=maschmann', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testBecomeArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testBecomeArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->become();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--become', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testBecomeUserArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testBecomeUserArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->becomeUser();
@@ -459,34 +352,24 @@ public function testBecomeUserArgumentPresent(AnsiblePlaybookInterface $command)
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--become-user=maschmann', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testSyntaxCheckArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testSyntaxCheckArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->syntaxCheck();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--syntax-check', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testTagsArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testTagsArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->tags('oneTag');
@@ -505,17 +388,12 @@ public function testTagsArgumentPresent(AnsiblePlaybookInterface $command): Ansi
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--tags=oneTag,anotherTag', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testTimeoutArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testTimeoutArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->timeout();
@@ -528,51 +406,36 @@ public function testTimeoutArgumentPresent(AnsiblePlaybookInterface $command): A
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--timeout=115', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testUserArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testUserArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->user('maschmann');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--user=maschmann', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testVaultPasswordFileArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testVaultPasswordFileArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->vaultPasswordFile('/path/to/vault');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--vault-password-file=/path/to/vault', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testVerboseArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testVerboseArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->verbose();
@@ -585,185 +448,129 @@ public function testVerboseArgumentPresent(AnsiblePlaybookInterface $command): A
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('-vvv', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testVersionArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testVersionArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->version();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--version', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testFlushCacheParameterPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testFlushCacheParameterPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->flushCache();
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--flush-cache', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testNewVaultIdArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testNewVaultIdArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->newVaultId('someId');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--new-vault-id=someId', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testNewVaultPasswordFileArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testNewVaultPasswordFileArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->newVaultPasswordFile('/path/to/vault');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--new-vault-password-file=/path/to/vault', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testScpExtraArgsArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testScpExtraArgsArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->scpExtraArgs('SomeExtraArgs');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--scp-extra-args=SomeExtraArgs', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testSftpExtraArgsArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testSftpExtraArgsArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->sftpExtraArgs('SftExtraArgs');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--sftp-extra-args=SftExtraArgs', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testSshCommonArgsArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testSshCommonArgsArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->sshCommonArgs('SshCommonArgs');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--ssh-common-args=SshCommonArgs', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testSshExtraArgsArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testSshExtraArgsArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->sshExtraArgs('SshExtraArgs');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--ssh-extra-args=SshExtraArgs', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testVaultIdArgumentPresent(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testVaultIdArgumentPresent()
{
+ $command = $this->testCreateInstance();
$command
->play($this->getPlayUri())
->vaultId('VaultId');
$arguments = array_flip($command->getCommandlineArguments());
$this->assertArrayHasKey('--vault-id=VaultId', $arguments);
-
- return $command;
}
- /**
- * @depends testCreateInstance
- * @param AnsiblePlaybookInterface $command
- * @return AnsiblePlaybookInterface
- */
- public function testGetCommandlineArguments(AnsiblePlaybookInterface $command): AnsiblePlaybookInterface
+
+ public function testGetCommandlineArguments()
{
+ $command = $this->testCreateInstance();
$arguments = $command
->play($this->getPlayUri())
->getCommandlineArguments();
$this->assertTrue(is_array($arguments));
$this->assertTrue(is_string($command->getCommandlineArguments(false)));
-
- return $command;
}
- /**
- * @depends testDefaultDeployment
- * @param AnsiblePlaybookInterface $command
- */
- public function testExecuteWithCallback(AnsiblePlaybookInterface $command): void
+ public function testExecuteWithCallback(): void
{
// Skipped on Windows
if (Env::isWindows()) {
@@ -771,6 +578,15 @@ public function testExecuteWithCallback(AnsiblePlaybookInterface $command): void
return;
}
+ $command = $this->testCreateInstance();
+
+ $command
+ ->play($this->getPlayUri())
+ ->user('maschmann')
+ ->extraVars(['project_release=' . (new DateTime())->getTimestamp()])
+ ->limit('test')
+ ->check();
+
$exitCode = $command
->execute(function (string $type, string $buffer) {
if (Process::ERR === $type) {
@@ -785,13 +601,15 @@ public function testExecuteWithCallback(AnsiblePlaybookInterface $command): void
$this->assertTrue(is_integer($exitCode));
}
- /**
- * @depends testDefaultDeployment
- * @param AnsiblePlaybookInterface $command
- */
- public function textExecuteWithTextOutput(AnsiblePlaybookInterface $command): void
+ public function textExecuteWithTextOutput(): void
{
+ $command = $this->testCreateInstance();
$result = $command
+ ->play($this->getPlayUri())
+ ->user('maschmann')
+ ->extraVars(['project_release=' . (new DateTime())->getTimestamp()])
+ ->limit('test')
+ ->check()
->execute(null);
$this->assertTrue(is_string($result));
@@ -1070,6 +888,38 @@ public function testReturnsErrorOutputIfProcessWasNotSuccessful(): void
self::assertEquals('error output', $playbook->execute());
}
+ public function testReturnsErrorOutputIfProcessWasNotSuccessfulInJsonMode(): void
+ {
+ $builder = $this->createMock(ProcessBuilderInterface::class);
+ $builder
+ ->expects(self::once())
+ ->method('setArguments')
+ ->willReturnSelf();
+ $builder
+ ->expects(self::once())
+ ->method('getProcess')
+ ->willReturn($process = $this->createMock(Process::class));
+ $process
+ ->expects(self::once())
+ ->method('run');
+ $process
+ ->expects(self::once())
+ ->method('isSuccessful')
+ ->willReturn(false);
+ $process
+ ->expects(self::once())
+ ->method('getOutput')
+ ->willReturn('{ "error": "error output" }');
+ $process
+ ->expects(self::never())
+ ->method('getErrorOutput');
+
+ $playbook = new AnsiblePlaybook($builder);
+ $playbook->json();
+
+ self::assertEquals('{ "error": "error output" }', $playbook->execute());
+ }
+
public function testReturnsNormalOutputIfProcessWasSuccessful(): void
{
$builder = $this->createMock(ProcessBuilderInterface::class);
@@ -1101,7 +951,7 @@ public function testReturnsNormalOutputIfProcessWasSuccessful(): void
self::assertEquals('success', $playbook->execute());
}
- public function testReturnsExitCodeIfCallbackwasPassed(): void
+ public function testReturnsExitCodeIfCallbackWasPassed(): void
{
$builder = $this->createMock(ProcessBuilderInterface::class);
$builder
diff --git a/Tests/Asm/Ansible/Process/ProcessBuilderTest.php b/Tests/Asm/Ansible/Process/ProcessBuilderTest.php
index ceb9388..b89de15 100644
--- a/Tests/Asm/Ansible/Process/ProcessBuilderTest.php
+++ b/Tests/Asm/Ansible/Process/ProcessBuilderTest.php
@@ -21,12 +21,10 @@ public function testCreateInstance(): ProcessBuilderInterface
return $processBuilder;
}
- /**
- * @param ProcessBuilderInterface $processBuilder
- * @depends testCreateInstance
- */
- public function testGetProcess(ProcessBuilderInterface $processBuilder): void
+ public function testGetProcess(): void
{
+ $processBuilder = $this->testCreateInstance();
+
$process = $processBuilder
->setArguments(['more_args'])
->setEnv('SOME', 'value')
diff --git a/Tests/Asm/Ansible/Testing/AnsibleTestCase.php b/Tests/Asm/Ansible/Testing/AnsibleTestCase.php
index 52c92a0..1e3e694 100644
--- a/Tests/Asm/Ansible/Testing/AnsibleTestCase.php
+++ b/Tests/Asm/Ansible/Testing/AnsibleTestCase.php
@@ -1,12 +1,6 @@
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
+
+declare(strict_types=1);
namespace Asm\Ansible\Testing;
@@ -57,7 +51,14 @@ protected function createProjectStructure(): vfsStreamDirectory
protected function getProjectUri(): string
{
- return $this->project->url() . '/ansible-project';
+ /**
+ * @todo using a virtual file system with an URI here, breaks proc_open for PHP 8.3.x due to change in
+ * the way it works underneath when not finding an executable. Providing an existing path here, does not
+ * break behavior of tests and has no real impact.
+ * @see https://github.com/php/php-src/issues/13743
+ */
+ //return $this->project->url() . '/ansible-project';
+ return $this->getAssetsBinPath();
}
protected function getPlayUri(): string
diff --git a/Tests/Asm/Ansible/Utils/StrTest.php b/Tests/Asm/Ansible/Utils/StrTest.php
index 2f311e0..a5bdf8e 100644
--- a/Tests/Asm/Ansible/Utils/StrTest.php
+++ b/Tests/Asm/Ansible/Utils/StrTest.php
@@ -5,10 +5,9 @@
namespace Asm\Ansible\Utils;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\Attributes\Group;
-/**
- * @group utils
- */
+#[Group('utils')]
class StrTest extends TestCase
{
/**
diff --git a/compose.yaml b/compose.yaml
new file mode 100644
index 0000000..2f0ea52
--- /dev/null
+++ b/compose.yaml
@@ -0,0 +1,6 @@
+services:
+ php-ansible:
+ build: .
+ container_name: php-ansible
+ volumes:
+ - ./:/app
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 2f6a2dd..af82267 100644
--- a/composer.json
+++ b/composer.json
@@ -15,13 +15,14 @@
}
],
"require": {
- "php": "^8.0.0|^8.1.0|^8.2.0",
- "psr/log": "^1.1|^2.0|^3.0",
- "symfony/process": "^5.3|^6.0"
+ "php": "^8.1.0|^8.2.0|^8.3.0",
+ "psr/log": "^2.0|^3.0",
+ "symfony/process": "^5.3|^6.0|^7.0"
},
"require-dev": {
- "phpunit/phpunit": "^9.5|^10.0 ",
- "mikey179/vfsstream": "^1.6"
+ "phpunit/phpunit": "^10.0|^11.0",
+ "mikey179/vfsstream": "^1.6",
+ "phpstan/phpstan": "^1.12"
},
"autoload": {
"psr-4": {
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index d25af5c..bc9cb59 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,6 +1,11 @@
-
-
+
+
+
+ ./Tests
+
+
+
-
-
- ./Tests
-
-
+
diff --git a/psalm.xml b/psalm.xml
index 8b0757c..b220368 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -2,7 +2,7 @@