PIPE-8085 | Convert acquia recommended pipeline yaml file to standard gitlab-ci yaml file#2017
PIPE-8085 | Convert acquia recommended pipeline yaml file to standard gitlab-ci yaml file#2017shubham-bansal96 wants to merge 19 commits into
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create tests/fixtures/acquia-pipelines-full.yml with all 5 pipeline events (build, fail-on-build, post-deploy, pr-merged, pr-closed) and full services and variables configuration. This fixture is used by subsequent pipeline migration tasks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add EVENT_STAGE_MAP constant mapping Acquia pipeline event names to GitLab CI stage names - Add migrateEvents() converting pipeline events to GitLab jobs with stage, script, before_script (composer), when (on_failure for fail-on-build), and rules (pr-merged/pr-closed MR conditions) - Update convert() to call migrateEvents() and merge stages + jobs into output - Expand test suite to 14 tests: full conversion, per-event assertions, empty script skip, source not deleted, overwrite behaviour Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update KernelTest column widths after adding pipelines:migrate:gitlab command (24-char name widens CLI list column from 25 to 26). Adds the pipelines section to the expected list output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Inject TODO comments before pr-merged and pr-closed job names in the generated .gitlab-ci.yml via post-processing after Yaml::dump() - Warn when a step name collision occurs across events in migrateEvents() - Add tests: testEmptyInputFileThrows, testInvalidYamlInputThrows, testPrMergedAndPrClosedJobsHaveYamlComments Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2017 +/- ##
============================================
+ Coverage 92.49% 92.60% +0.11%
- Complexity 1991 2049 +58
============================================
Files 123 124 +1
Lines 7232 7369 +137
============================================
+ Hits 6689 6824 +135
- Misses 543 545 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds a new standalone pipelines:migrate:gitlab Symfony Console command to convert Acquia acquia-pipelines.yml/.yaml into a generic .gitlab-ci.yml/.yaml, plus fixtures/tests and updates the CLI command-list snapshot.
Changes:
- Introduces
PipelinesMigrateGitlabCommandto detect, parse, convert, and write.gitlab-ci.*output (with warnings + injected TODO comments for MR-related stages). - Adds a full-fixture YAML and a PHPUnit test suite covering the conversion behavior and error cases.
- Updates
KernelTest’s expectedlistoutput to include the newpipelines:*command.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/Command/Pipelines/PipelinesMigrateGitlabCommand.php |
New command implementing file detection, YAML parsing, services/variables/events migration, and output generation. |
tests/phpunit/src/Commands/Pipelines/PipelinesMigrateGitlabCommandTest.php |
New test class validating conversion output structure, warnings, overwrite behavior, and error handling. |
tests/fixtures/acquia-pipelines-full.yml |
New “full” input fixture covering services/variables plus all targeted events. |
tests/phpunit/src/Application/KernelTest.php |
Updates expected list output to include the new pipelines:migrate:gitlab command. |
docs/superpowers/specs/2026-07-09-pipelines-migrate-gitlab-design.md |
Design/spec documentation for the new command. |
docs/superpowers/plans/2026-07-09-pipelines-migrate-gitlab.md |
Implementation plan documentation for the new command. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public function testMissingInputFileThrows(): void | ||
| { | ||
| $this->expectException(AcquiaCliException::class); | ||
| $this->expectExceptionMessage('No acquia-pipelines.yml or acquia-pipelines.yaml file found'); |
| public function testNonExistentPathOptionThrows(): void | ||
| { | ||
| $this->expectException(AcquiaCliException::class); | ||
| $this->expectExceptionMessage('does not exist'); |
| ); | ||
|
|
||
| $this->expectException(AcquiaCliException::class); | ||
| $this->expectExceptionMessage("does not contain an 'events' key"); |
| if (!array_key_exists('services', $contents)) { | ||
| return $output; | ||
| } | ||
|
|
||
| foreach ($contents['services'] as $service) { | ||
| if (is_string($service)) { | ||
| $name = $service; | ||
| $version = null; | ||
| } else { | ||
| $name = (string) array_key_first($service); | ||
| $version = $service[$name]['version'] ?? null; | ||
| } | ||
|
|
||
| match ($name) { | ||
| 'php' => $output['image'] = 'php:' . $version, | ||
| 'mysql' => $output['services'][] = $version ? "mysql:$version" : 'mysql', | ||
| 'composer' => $output['_composer'] = true, | ||
| default => $this->io->warning("Unknown service '$name'. Configure it manually in .gitlab-ci.yml."), | ||
| }; | ||
| } |
| foreach ($eventData['steps'] as $step) { | ||
| $stepName = (string) array_key_first($step); | ||
| $stepData = $step[$stepName]; | ||
|
|
||
| if (empty($stepData['script'])) { | ||
| $this->io->warning("Step '$stepName' in event '$eventName' has no script. Skipping."); | ||
| continue; | ||
| } |
|
Try the dev build for this PR: https://acquia-cli.s3.amazonaws.com/build/pr/2017/acli.phar |
- Switch expectExceptionMessage() to expectExceptionMessageMatches() for substring assertions (testMissingInputFileThrows, testNonExistentPathOptionThrows, testMissingEventsKeyThrows) - Add testYmlExtensionInputProducesYmlOutput to kill the two escaped mutants (ArrayItemRemoval and Foreach_ on the yml/yaml loop) - Guard malformed service entries (non-array value) in migrateServices() - Guard malformed step entries (non-array or non-array stepData) in migrateEvents() before accessing array_key_first() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| if (!is_array($parsed) || !array_key_exists('events', $parsed)) { | ||
| throw new AcquiaCliException("The file {$path} does not contain an 'events' key."); | ||
| } |
| match ($name) { | ||
| 'php' => $output['image'] = 'php:' . $version, | ||
| 'mysql' => $output['services'][] = $version ? "mysql:$version" : 'mysql', | ||
| 'composer' => $output['_composer'] = true, | ||
| default => $this->io->warning("Unknown service '$name'. Configure it manually in .gitlab-ci.yml."), | ||
| }; |
Infection excludes the serial group (testFrameworkOptions: --exclude-group=serial), so the two escaped mutants on the foreach(['yml','yaml']) loop weren't caught. Add testYmlExtensionIsDetected and testYamlExtensionIsDetected as non-serial tests using file_put_contents into the vfsStream projectDir so Infection can exercise and kill both the ArrayItemRemoval and Foreach_ mutants on that line. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add 20 new non-serial tests that assert conversion behavior using vfsStream, so Infection can cover and kill mutants on the command logic without needing serial tests excluded by --exclude-group=serial. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cover: overwrite warning, YAML parse error message format, missing events key, variables migration message, malformed services, multiple non-global variables, continue vs break in event loop, eventHasJob false initialization, malformed/missing steps, script property presence, duplicate step name warning, event migration message, preg_quote for step names with dots, and the YAML indentation/block-style assertions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mark the Yaml::dump numeric arguments and (string) array_key_first() casts as infection-ignore-all since the mutations produce equivalent behavior for valid YAML input. Also annotate the empty-array early return in migrateServices() for the same reason. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ConcatOperandRemoval: assert exception message length > prefix length - Continue_ (malformed service): assert subsequent service still migrated - MethodCallRemoval (malformed step): assert warning text appears - MethodCallRemoval (no-script step): assert warning text appears - IfNegation (duplicate step check): add negative test for no-duplicate case - PregQuote: use step name with '+' (regex special char); assert TODO comment appears directly before the job entry in raw YAML output Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- parseSourceFile: validate 'events' value is an array, not just that the key exists; throws AcquiaCliException for scalar/null events values - migrateServices: warn and skip image when PHP service has no version specified instead of producing invalid 'php:' image name - Add non-serial tests for both new code paths to preserve 100% covered MSI Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| if (!array_key_exists('services', $contents)) { | ||
| // @infection-ignore-all Returning empty array; ArrayOneItem mutant is equivalent here. | ||
| return $output; | ||
| } | ||
|
|
||
| foreach ($contents['services'] as $service) { |
| $vars = $contents['variables']; | ||
|
|
||
| if (array_key_exists('global', $vars) && is_array($vars['global'])) { | ||
| return $vars['global']; | ||
| } | ||
|
|
||
| return $vars; | ||
| } |
| $eventData = $contents['events'][$eventName]; | ||
| if (empty($eventData['steps'])) { | ||
| $this->io->warning("Event '$eventName' has no steps and was skipped."); | ||
| continue; | ||
| } |
There was a problem hiding this comment.
Instead of superpower can we use https://github.com/Fission-AI/OpenSpec/
|
@shubham-bansal96 Are we taking into consideration different version of acquia-pipeline.yaml. There are some format changes with older versions and customers are using those. |
Motivation
Fixes - PIPE-8085
Proposed changes
Added a new command
pipelines:migrate:gitlabto convert acquia recommendedacquia-pipelines.yamlORacquia-pipelines.ymlfile to standard.gitlab-ci.yamlOR.gitlab-ci.ymlfile.pipelines:migrate:gitlabthis command need a flag, that will be a path to acquia yaml file, if not provided then yaml file will be search in the current directory.Flag -
--pathTesting steps
Added a file acquia-pipelines.yml in test/fixtures directory, then ran a command and provided path to directory where acquia-pipelines.yaml file resides.
php bin/acli pipelines:migrate:gitlab --path=tests/fixturesOutput
Screenshot of output
.gitlab-ci.yml file was generated under the same directory.
acquia-pipelines.yml file content
.gitlab-ci.yml file content