Skip to content

Commit dfd4132

Browse files
Merge branch 'main' into 243
2 parents 097de7a + 4be0fa9 commit dfd4132

48 files changed

Lines changed: 533 additions & 97 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@ Latest
44
## Changes
55
* [#197](https://github.com/cleverage/process-bundle/issues/197) Add missing tests: every Task and Transformer is now covered by unit tests. Remove the obsolete `tests.old` directory.
66
* [#143](https://github.com/cleverage/process-bundle/issues/143) Improve PHPStan configuration: remove all `ignoreErrors` and `@phpstan-ignore` comments (report unmatched ignored errors again), add missing iterable value types and generic types in PHPDoc, remove unreachable code in AbstractIterableOutputTask and InputAggregatorTask.
7+
* [#143](https://github.com/cleverage/process-bundle/issues/143) Improve PHPStan level from 6 to 7, and fix the level 8 errors that do not require a signature change (the remaining ones, due to nullable return types such as `AbstractConfigurableTask::getOptions(): ?array`, will be fixed in v6.0). Default to a `ContextualOptionResolver` in ProcessState and to a property accessor in ConditionTrait when none is set.
78

89
## Fixes
910
* [#143](https://github.com/cleverage/process-bundle/issues/143) Fix InputIteratorTask: an `\IteratorAggregate` input whose `getIterator()` does not return an `\Iterator` (e.g. another `\IteratorAggregate`) is iterated instead of failing with a `TypeError`. Update documentation, add tests.
11+
* [#143](https://github.com/cleverage/process-bundle/issues/143) Fix level 8 edge cases failing with a `TypeError` or an `Error`: `CsvResource` rejects a blank header line and checks `ftell()`, XpathEvaluatorTransformer throws an explicit `\UnexpectedValueException` on an invalid query (with the libxml messages), a namespace node to unwrap or a node without document, SlugifyTransformer on a value that cannot be transliterated, `ProcessState::getContext()` returns `[]` until the context is defined, GenericTransformer and TransformerTrait throw a `\LogicException` when not initialized, IterableBatchTask and JsonStreamReaderTask can be flushed / iterated before their first execution, RegistryCompilerPass checks its configuration, SubprocessInstance checks the PHP executable. Update documentation, add tests.
12+
* [#239](https://github.com/cleverage/process-bundle/issues/239) Fix PropertyGetterTask: catch any `\Throwable`, so that the `TypeError` of the property accessor on a scalar input is set on the state (with the `property` error context) and handled according to the task `error_strategy` instead of escaping it. Update documentation, add tests.
13+
* [#241](https://github.com/cleverage/process-bundle/issues/241) Fix CsvWriterTask: a non-array input throws the documented `\UnexpectedValueException` instead of a `TypeError` when `headers` is `null`, and the CSV tasks release their file on `finalize()` so that the task can be executed again. Update documentation, add tests.
14+
* [#240](https://github.com/cleverage/process-bundle/issues/240) Fix FileMoverTask: with `autoincrement`, the suffix was computed on the whole path (a dot in a directory name was taken as the extension, making the move fail for a file without extension) and an existing numeric suffix of the file name was replaced (`report-2024.csv` became `report-1.csv`). The suffix is now appended to the file name only (`report-2024-1.csv`, `file-1`, `.env-1`). Update documentation, add tests.
1015
* [#243](https://github.com/cleverage/process-bundle/issues/243) Fix RecursivePropertySetterTransformer: a `\stdClass` item without the property was replaced by a copy in the output, so the input object was not modified; the property is now added to the item itself. Update documentation, add tests.
1116

1217
v5.1

‎docs/reference/tasks/csv_reader_task.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ Notes
7070
-----
7171
7272
* Each line must contain exactly as many columns as there are headers, otherwise an `\UnexpectedValueException` is thrown.
73-
* A UTF-8 BOM is removed from the first header when headers are read from the file.
73+
* A UTF-8 BOM is removed from the first header when headers are read from the file. If the first line is blank, an
74+
`\UnexpectedValueException` is thrown.
7475
* `csv_file` and `csv_line` are added to the error context of the process.
7576
* The file is closed once fully read: if the task is executed again (e.g. for a new input), the file is read again
7677
from its beginning.

‎docs/reference/tasks/csv_writer_task.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,6 @@ Notes
7676
* `{date}` is replaced by `Ymd`, `{date_time}` by `Ymd_His`, `{timestamp}` by the Unix timestamp and `{unique_token}`
7777
by a `uniqid()` value.
7878
* The parent directory of the file is created if needed.
79+
* An input that is not an `array` throws an `\UnexpectedValueException`.
7980
* Each input must contain every header key (extra keys are not allowed: the number of columns must match the number of
8081
headers), otherwise an `\UnexpectedValueException` is thrown. Columns are written in the headers order.

‎docs/reference/tasks/file_mover_task.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Options
2626
|-----------------|----------|:--------:|---------|--------------------------------------------------------------------------------------------------------------------------|
2727
| `destination` | `string` | **X** | | Destination path. If it is an existing directory, the original file name is kept |
2828
| `overwrite` | `bool` | | `false` | Allow overwriting an existing file at destination (otherwise an exception is thrown) |
29-
| `autoincrement` | `bool` | | `false` | If the destination file exists, add or increment a numeric suffix before the extension (e.g. `file-1.csv`, `file-2.csv`) |
29+
| `autoincrement` | `bool` | | `false` | If the destination file exists, append the first free numeric suffix to the file name, before its extension (e.g. `file-1.csv`, `file-2.csv`) |
3030

3131
Examples
3232
--------
@@ -46,3 +46,6 @@ Notes
4646
-----
4747
4848
* Underlying method is Symfony `Filesystem::rename()`.
49+
* With `autoincrement`, only the file name is changed (never the directory part), and the suffix is always appended to
50+
the original name: `report-2024.csv` becomes `report-2024-1.csv`, `file` becomes `file-1`, `archive.tar.gz` becomes
51+
`archive.tar-1.gz` and a hidden file `.env` becomes `.env-1`.

‎docs/reference/tasks/property_getter_task.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ Possible outputs
2121

2222
`mixed`: the value read at the `property` path.
2323

24-
If the value cannot be read, the exception is set on the state (with the `property` added to the error context) and
25-
handled according to the task `error_strategy`.
24+
If the value cannot be read (including a `\TypeError` of the property accessor, e.g. on a scalar input), the exception
25+
is set on the state (with the `property` added to the error context) and handled according to the task `error_strategy`.
2626

2727
Options
2828
-------

‎docs/reference/transformers/slugify_transformer.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,5 @@ Notes
5858
An invalid `transliterator` identifier (rejected by `\Transliterator::create()`), or an option that is not a string,
5959
raises an `InvalidOptionsException` when the options are resolved, i.e. when the transformer is configured, not on the
6060
first transformed value.
61+
62+
A value that cannot be transliterated (e.g. invalid UTF-8) throws an `\UnexpectedValueException`.

‎docs/reference/transformers/xpath_evaluator_transformer.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ Transformer reference
1717
Accepted inputs
1818
---------------
1919

20-
`\DOMNode` (including `\DOMDocument`). Any other value throws an `\UnexpectedValueException`.
20+
`\DOMNode` (including `\DOMDocument`). Any other value, a node that does not belong to a document or an invalid xpath
21+
query throws an `\UnexpectedValueException`.
2122

2223
Possible outputs
2324
----------------

‎phpstan.neon‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
parameters:
2-
level: 6
2+
level: 7
33
paths:
44
- src
55
- tests

‎src/Command/ListProcessCommand.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,6 @@ protected function padMessage(string $message, int $length = 80): string
125125

126126
protected function filterOutTags(string $string): string
127127
{
128-
return preg_replace('/<[^<>]*>/', '', $string);
128+
return preg_replace('/<[^<>]*>/', '', $string) ?? $string;
129129
}
130130
}

‎src/Command/ProcessHelpCommand.php‎

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int
107107
$totalBranches = \count($taskList);
108108
for ($i = 0; $i < $totalBranches; ++$i) {
109109
// Find the best task to display
110-
$nextTaskCode = $this->findBestNextTask($branches, $remainingTasks, $process);
110+
// A numeric task code may be returned as an integer array key
111+
$nextTaskCode = (string) $this->findBestNextTask($branches, $remainingTasks, $process);
111112

112113
$this->resolveBranchOutput($branches, $nextTaskCode, $process, $output);
113114

114115
// Remove the task from the remaining list
115-
$remainingTasks = array_filter($remainingTasks, static fn ($task): bool => $task !== $nextTaskCode);
116+
$remainingTasks = array_values(array_filter($remainingTasks, static fn ($task): bool => $task !== $nextTaskCode));
116117
}
117118

118119
$branches = array_filter($branches);
@@ -127,8 +128,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
127128
/**
128129
* Try to find a best candidate for next display.
129130
*
130-
* @param array<string|null> $branches
131-
* @param list<string> $taskList
131+
* @param array<int, string|null> $branches
132+
* @param list<string> $taskList
132133
*/
133134
protected function findBestNextTask(
134135
array $branches,
@@ -227,7 +228,7 @@ protected function getTaskChildrenCount(TaskConfiguration $task): int
227228
/**
228229
* Merge needed branches, display a task node, split following needed branches.
229230
*
230-
* @param array<string|null> $branches
231+
* @param array<int, string|null> $branches
231232
*/
232233
protected function resolveBranchOutput(
233234
array &$branches,
@@ -293,7 +294,12 @@ protected function resolveBranchOutput(
293294

294295
$origin = array_shift($branchesToMerge);
295296
$final = $gapFrom;
296-
$branches[$origin] = $taskCode;
297+
if (null === $origin) {
298+
// No previous branch found (an error has been displayed): open a new branch
299+
$branches[] = $taskCode;
300+
} else {
301+
$branches[$origin] = $taskCode;
302+
}
297303
}
298304

299305
// Merge branches
@@ -377,6 +383,9 @@ static function ($taskCode, $i) use ($gapBranches, $origin, $final, $branches):
377383
$this->writeBranches($output, $branches);
378384
array_shift($nextTasks);
379385
$origin = array_search($taskCode, $branches, true);
386+
if (false === $origin) {
387+
throw new \UnexpectedValueException("Task '{$taskCode}' is not in any branch");
388+
}
380389
$expandBranches = [];
381390
foreach ($nextTasks as $nextTask) {
382391
$index = array_search(null, $branches, true);
@@ -448,7 +457,7 @@ static function ($branchTask, $i) use ($origin, $branches, $gapBranches, $final)
448457
}
449458

450459
/**
451-
* @param array<string|null> $branches
460+
* @param array<int, string|null> $branches
452461
* @param string|iterable<string> $comment
453462
*/
454463
protected function writeBranches(

0 commit comments

Comments
 (0)