Skip to content

Commit a71d661

Browse files
authored
cumulative update (#99)
* drop PHP versions below 8.1 * update dependencies * merge fix for When using json() failing command has output on stdout and not stderr #90 * add symfony process 7 Adding support of symfony/process ^7.0 #94 * add docker env for develeopment * update phpunit, fix tests to work with v11
1 parent 30df141 commit a71d661

16 files changed

Lines changed: 339 additions & 411 deletions

.github/workflows/static-analysis.yml

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ jobs:
1212

1313
strategy:
1414
matrix:
15-
php:
16-
- "8.0"
17-
- "8.1"
18-
- "8.2"
1915
include:
20-
- php-version: "8.0"
21-
phpunit: "9.5"
16+
- php: "8.1"
17+
phpunit: "10"
18+
phpunit-config: "phpunit-10.xml.dist"
19+
- php: "8.2"
20+
phpunit: "11"
21+
phpunit-config: "phpunit.xml.dist"
22+
- php: "8.3"
23+
phpunit: "11"
2224
phpunit-config: "phpunit.xml.dist"
2325

2426
steps:
@@ -28,21 +30,23 @@ jobs:
2830
php-version: "${{ matrix.php }}"
2931
extensions: redis, apcu, ctype, dom, iconv, gd, mbstring, fileinfo, intl, json, mysql, bcmath, zip
3032
coverage: none # disable xdebug, pcov
31-
ini-values: post_max_size=256M memory
33+
#ini-values: post_max_size=256M memory
3234
tools: cs2pr, pecl, php-cs-fixer, vimeo/psalm, phpstan, phpcs
3335

34-
- uses: actions/checkout@v3
36+
- uses: actions/checkout@v4
3537

36-
- uses: "ramsey/composer-install@v2"
38+
- uses: "ramsey/composer-install@v3"
3739
with:
3840
composer-options: "--no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist -q"
3941

4042
- name: PHPUnit tests
4143
uses: php-actions/phpunit@v3
4244
with:
4345
version: "${{ matrix.phpunit }}"
46+
php_version: "${{matrix.php}}"
4447
configuration: "${{ matrix.phpunit-config }}"
4548
memory_limit: "256M"
49+
test_suffix: .php
4650

4751
- name: Run phpstan
4852
run: phpstan analyse --error-format=checkstyle -c "phpstan.neon" | cs2pr

Asm/Ansible/Command/AbstractAnsibleCommand.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ abstract class AbstractAnsibleCommand
3434

3535
private array $baseOptions;
3636

37+
private bool $useStdoutForError;
38+
3739
/**
3840
* @param ProcessBuilderInterface $processBuilder
3941
* @param LoggerInterface|null $logger
@@ -44,6 +46,7 @@ public function __construct(ProcessBuilderInterface $processBuilder, LoggerInter
4446
$this->options = [];
4547
$this->parameters = [];
4648
$this->baseOptions = [];
49+
$this->useStdoutForError = false;
4750
$this->setLogger($logger ?? new NullLogger());
4851
}
4952

@@ -183,7 +186,7 @@ protected function runProcess(?callable $callback): int|string
183186

184187
// if no callback is set, and the process is not successful, we return the output
185188
if (false === $process->isSuccessful()) {
186-
return $process->getErrorOutput();
189+
return $this->useStdoutForError ? $process->getOutput() : $process->getErrorOutput();
187190
}
188191

189192
// if no callback is set, and the process is successful, we return the output
@@ -210,4 +213,14 @@ protected function getProcessCommandline(Process $process): string
210213

211214
return sprintf('%s %s', implode(' ', $vars), $commandline);
212215
}
216+
217+
/**
218+
* in case ansible explicitly is in json mode, this will be set to be able to get error outputs
219+
*
220+
* @return void
221+
*/
222+
protected function useStdoutForError(): void
223+
{
224+
$this->useStdoutForError = true;
225+
}
213226
}

Asm/Ansible/Command/AnsiblePlaybook.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ public function colors(bool $colors = true): AnsiblePlaybookInterface
408408
public function json(): AnsiblePlaybookInterface
409409
{
410410
$this->processBuilder->setEnv('ANSIBLE_STDOUT_CALLBACK', 'json');
411+
$this->useStdoutForError();
411412

412413
return $this;
413414
}
@@ -728,12 +729,12 @@ public function hostKeyChecking(bool $enable = true): AnsiblePlaybookInterface
728729
}
729730

730731
/**
731-
* Ansible SSH pipelining option
732-
* https://docs.ansible.com/ansible/latest/reference_appendices/config.html#ansible-pipelining
733-
*
734-
* @param bool $enable
735-
* @return AnsiblePlaybookInterface
736-
**/
732+
* Ansible SSH pipelining option
733+
* https://docs.ansible.com/ansible/latest/reference_appendices/config.html#ansible-pipelining
734+
*
735+
* @param bool $enable
736+
* @return AnsiblePlaybookInterface
737+
**/
737738
public function sshPipelining(bool $enable = false): AnsiblePlaybookInterface
738739
{
739740
$enable ?

Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
FROM php:8.3-cli
2+
3+
WORKDIR /app
4+
5+
ENV ANSIBLE_VERSION 2.9.17
6+
7+
# composer
8+
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
9+
&& php -r "if (hash_file('sha384', 'composer-setup.php') === 'dac665fdc30fdd8ec78b38b9800061b4150413ff2e3b6f88543c636f7cd84f6db9189d43a81e5503cda447da73c7e5b6') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
10+
&& php composer-setup.php \
11+
&& php -r "unlink('composer-setup.php');" \
12+
&& mv composer.phar /usr/bin/composer \
13+
&& chmod +x /usr/bin/composer
14+
15+
# python, pipx & ansible
16+
RUN apt-get update \
17+
&& apt-get install -y gcc python3 git zip 7zip unzip pipx \
18+
&& apt-get clean all; \
19+
pipx install --upgrade pip; \
20+
pipx install "ansible==${ANSIBLE_VERSION}"; \
21+
pipx install ansible;
22+
23+
# keep container running
24+
CMD [ "bash", "-c", "echo 'running'; tail -f /dev/null" ]

Makefile

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Executables (local)
2+
DOCKER_COMP = docker compose
3+
4+
# Docker containers
5+
PHP_CONT = $(DOCKER_COMP) exec php-ansible
6+
7+
# Executables
8+
PHP = $(PHP_CONT) php
9+
COMPOSER = $(PHP_CONT) composer
10+
11+
# Misc
12+
.DEFAULT_GOAL = help
13+
14+
## —— php-ansible Makefile 🎵 ——————————————————————————————————
15+
help: ## Outputs this help screen
16+
@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/'
17+
18+
## —— Docker 🐳 ————————————————————————————————————————————————————————————————
19+
build: ## Builds the Docker images
20+
@$(DOCKER_COMP) build --pull --no-cache
21+
22+
up: ## Start the docker hub in detached mode (no logs)
23+
@$(DOCKER_COMP) up --detach
24+
25+
start: build up ## Build and start the containers
26+
27+
down: ## Stop the docker hub
28+
@$(DOCKER_COMP) down --remove-orphans
29+
30+
logs: ## Show live logs
31+
@$(DOCKER_COMP) logs --tail=0 --follow
32+
33+
sh: ## Connect to the php-fpm container
34+
@$(PHP_CONT) sh
35+
36+
bash: ## Connect to the php-fpm container via bash so up and down arrows go to previous commands
37+
@$(PHP_CONT) bash
38+
39+
test: ## Start tests with phpunit, pass the parameter "c=" to add options to phpunit, example: make test c="--group e2e --stop-on-failure"
40+
@$(eval c ?=)
41+
@$(PHP_CONT) vendor/bin/phpunit -c phpunit.xml.dist $(c)
42+
43+
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"
44+
@$(eval c ?=)
45+
@$(PHP_CONT) vendor/bin/phpstan --configuration=phpstan.neon $(c)
46+
47+
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"
48+
@$(eval c ?=)
49+
@$(PHP_CONT) vendor/bin/phpcs --standard=phpcs.xml.dist $(c)
50+
51+
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"
52+
@$(eval c ?=)
53+
@$(PHP_CONT) vendor/bin/phpcbf --standard=phpcs.xml.dist $(c)
54+
55+
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"
56+
@$(eval c ?=)
57+
@$(DOCKER_COMP) exec -e APP_ENV=dev php vendor/bin/psalm --config=psalm.xml $(c)
58+
59+
## —— Composer 🧙 ——————————————————————————————————————————————————————————————
60+
composer: ## Run composer, pass the parameter "c=" to run a given command, example: make composer c='req phpstan/phpstan'
61+
@$(eval c ?=)
62+
@$(COMPOSER) $(c)
63+
64+
vendor: ## Install vendors according to the current composer.lock file
65+
vendor: c=install --prefer-dist --no-dev --no-progress --no-scripts --no-interaction
66+
vendor: composer

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,12 @@ $ansible
162162
163163
```
164164

165+
## Development
165166

167+
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.
168+
Start the container with ```make up```.
169+
Composer install: ```make vendor```
170+
You can run code or the tests within the container: ```make test c="--testdox"```
166171

167172
## Thank you for your contributions!
168173

@@ -178,7 +183,6 @@ The Next steps for implementation are:
178183
- improve type handling and structure, due to overall complexity of the playbook at the moment
179184
- scalar typehints all over the place
180185
- provide docker support for development
181-
- move to php8.0 exclusively for the next major release
182186
- wrapping the library into a bundle -> maybe
183187
- provide commandline-capabilities -> maybe
184188

Tests/Asm/Ansible/AnsibleTest.php

Lines changed: 11 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
<?php
2-
/*
3-
* This file is part of the php-ansible package.
4-
*
5-
* (c) Marc Aschmann <maschmann@gmail.com>
6-
*
7-
* For the full copyright and license information, please view the LICENSE
8-
* file that was distributed with this source code.
9-
*/
2+
3+
declare(strict_types=1);
104

115
namespace Asm\Ansible;
126

137
use Asm\Ansible\Exception\CommandException;
148
use Asm\Ansible\Testing\AnsibleTestCase;
159
use org\bovigo\vfs\vfsStream;
10+
use PHPUnit\Framework\Attributes\CoversClass;
11+
use PHPUnit\Framework\Attributes\CoversFunction;
1612

13+
#[CoversClass(\Asm\Ansible\Ansible::class)]
14+
#[CoversFunction('playbook')]
15+
#[CoversFunction('createProcess')]
16+
#[CoversFunction('checkCommand')]
17+
#[CoversFunction('checkDir')]
18+
#[CoversFunction('__construct')]
1719
class AnsibleTest extends AnsibleTestCase
1820
{
19-
/**
20-
* @covers \Asm\Ansible\Ansible::checkCommand
21-
* @covers \Asm\Ansible\Ansible::checkDir
22-
* @covers \Asm\Ansible\Ansible::__construct
23-
*/
21+
2422
public function testInstance()
2523
{
2624
$ansible = new Ansible(
@@ -31,11 +29,6 @@ public function testInstance()
3129
$this->assertInstanceOf('\Asm\Ansible\Ansible', $ansible, 'Instantiation with given paths');
3230
}
3331

34-
/**
35-
* @covers \Asm\Ansible\Ansible::checkCommand
36-
* @covers \Asm\Ansible\Ansible::checkDir
37-
* @covers \Asm\Ansible\Ansible::__construct
38-
*/
3932
public function testAnsibleProjectPathNotFoundException()
4033
{
4134
$this->expectException(CommandException::class);
@@ -46,11 +39,6 @@ public function testAnsibleProjectPathNotFoundException()
4639
);
4740
}
4841

49-
/**
50-
* @covers \Asm\Ansible\Ansible::checkCommand
51-
* @covers \Asm\Ansible\Ansible::checkDir
52-
* @covers \Asm\Ansible\Ansible::__construct
53-
*/
5442
public function testAnsibleCommandNotFoundException()
5543
{
5644
$this->expectException(CommandException::class);
@@ -61,11 +49,6 @@ public function testAnsibleCommandNotFoundException()
6149
);
6250
}
6351

64-
/**
65-
* @covers \Asm\Ansible\Ansible::checkCommand
66-
* @covers \Asm\Ansible\Ansible::checkDir
67-
* @covers \Asm\Ansible\Ansible::__construct
68-
*/
6952
public function testAnsibleNoCommandGivenException()
7053
{
7154
// TODO: Not sure why the following command should give an error.
@@ -75,11 +58,6 @@ public function testAnsibleNoCommandGivenException()
7558
// );
7659
}
7760

78-
/**
79-
* @covers \Asm\Ansible\Ansible::checkCommand
80-
* @covers \Asm\Ansible\Ansible::checkDir
81-
* @covers \Asm\Ansible\Ansible::__construct
82-
*/
8361
public function testAnsibleCommandNotExecutableException()
8462
{
8563
$this->expectException(CommandException::class);
@@ -94,13 +72,6 @@ public function testAnsibleCommandNotExecutableException()
9472
);
9573
}
9674

97-
/**
98-
* @covers \Asm\Ansible\Ansible::playbook
99-
* @covers \Asm\Ansible\Ansible::createProcess
100-
* @covers \Asm\Ansible\Ansible::checkCommand
101-
* @covers \Asm\Ansible\Ansible::checkDir
102-
* @covers \Asm\Ansible\Ansible::__construct
103-
*/
10475
public function testPlaybookCommandInstance()
10576
{
10677
$ansible = new Ansible(
@@ -114,13 +85,6 @@ public function testPlaybookCommandInstance()
11485
$this->assertInstanceOf('\Asm\Ansible\Command\AnsiblePlaybook', $playbook);
11586
}
11687

117-
/**
118-
* @covers \Asm\Ansible\Ansible::galaxy
119-
* @covers \Asm\Ansible\Ansible::createProcess
120-
* @covers \Asm\Ansible\Ansible::checkCommand
121-
* @covers \Asm\Ansible\Ansible::checkDir
122-
* @covers \Asm\Ansible\Ansible::__construct
123-
*/
12488
public function testGalaxyCommandInstance()
12589
{
12690
$ansible = new Ansible(

Tests/Asm/Ansible/Command/AnsibleGalaxyTest.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,15 @@ public function testCreateInstance(): AnsibleGalaxyInterface
2323
return $ansibleGalaxy;
2424
}
2525

26-
/**
27-
* @depends testCreateInstance
28-
* @param AnsibleGalaxyInterface $command
29-
*/
30-
public function testExecute(AnsibleGalaxyInterface $command): void
26+
public function testExecute(): void
3127
{
3228
// Skipped on Windows
3329
if (Env::isWindows()) {
3430
$this->assertTrue(true);
3531
return;
3632
}
3733

34+
$command = $this->testCreateInstance();
3835
$command->execute();
3936

4037
// if command executes without exception

0 commit comments

Comments
 (0)