Skip to content

PIPE-8085 | Convert acquia recommended pipeline yaml file to standard gitlab-ci yaml file#2017

Open
shubham-bansal96 wants to merge 19 commits into
acquia:mainfrom
shubham-bansal96:PIPE-8085
Open

PIPE-8085 | Convert acquia recommended pipeline yaml file to standard gitlab-ci yaml file#2017
shubham-bansal96 wants to merge 19 commits into
acquia:mainfrom
shubham-bansal96:PIPE-8085

Conversation

@shubham-bansal96

@shubham-bansal96 shubham-bansal96 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Motivation

Fixes - PIPE-8085

Proposed changes
Added a new command pipelines:migrate:gitlab to convert acquia recommended acquia-pipelines.yaml OR acquia-pipelines.yml file to standard .gitlab-ci.yaml OR .gitlab-ci.yml file.

pipelines:migrate:gitlab this 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 - --path

Testing 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/fixtures

Output

shubham.bansal@MacBook-Pro-ShubhamBansal cli % php bin/acli pipelines:migrate:gitlab --path=tests/fixtures
                                                                                                     
 [OK] Migrated 'variables' section.                                                                        
                                                                                                        
 [OK] Migrated 'build' event.                                                                              
                                                               
 [OK] Migrated 'post-deploy' event.                                                                        
                                                                                                                                                                                                            
 [OK] Migration complete. Created tests/fixtures/.gitlab-ci.yml. Review the file before committing — some  
      manual adjustments may be needed.                                                                    

Screenshot of output

Screenshot 2026-07-10 at 10 16 41 AM

.gitlab-ci.yml file was generated under the same directory.

acquia-pipelines.yml file content

# This file is used by Acquia Pipelines continuous integration. Upon success, an
# artifact is deployed to the `orionacms` subscription on Acquia Cloud.
version: 1.3.0
services:
  - composer:
      version: 2
  - php:
      version: 7.4

variables:
  global:
    COMPOSER_BIN: $SOURCE_DIR/vendor/bin
    BLT_DIR: $SOURCE_DIR/vendor/acquia/blt

events:
  build:
    steps:
      - setup:
          type: script
          script:
            - composer validate --no-check-all --ansi --no-interaction
            - composer install
            - mkdir -p docroot/profiles/acquia_cms
            - composer archive --format zip --file acquia_cms
            - unzip acquia_cms.zip -d docroot/profiles/acquia_cmsort 
            - cp -R modules/acquia_cms_development docroot/profiles/acquia_cms/modules
            - cp config/optional/views.view.acquia_search.yml docroot/profiles/acquia_cms/config/optional
      - setup-env:
          type: script
          script:
            - composer validate --no-check-all --ansi
            - composer install --ansi
            - source ${BLT_DIR}/scripts/pipelines/setup_env
      - validate:
          type: script
          script:
            - source ${BLT_DIR}/scripts/pipelines/validate
      - front-end:
          type: script
          script:
            - cd themes/acquia_claro
            - npm install
            - npm run build
            - cd -
            - cp -R themes/acquia_claro/css docroot/profiles/acquia_cms/themes/acquia_claro
            - mkdir -p docroot/profiles/acquia_cms/modules/acquia_cms_tour/css
            - cp modules/acquia_cms_tour/css/acquia_cms_tour.css docroot/profiles/acquia_cms/modules/acquia_cms_tour/css
  post-deploy:
    steps:
      - launch_ode:
          script:
            - 'alias run="node $SOURCE_DIR/scripts/run.js"'
            - 'run launch_ode "pipelines-deploy"'
            - export PIPELINES_DEPLOYMENT_NAME=$(node -pe 'JSON.parse(process.argv[1]).environment.PIPELINES_DEPLOYMENT_NAME' "$(cat $PIPELINES_SCRIPT_DATA_FILE)")
            - export PIPELINES_DEPLOYMENT_LINK=$(node -pe 'JSON.parse(process.argv[1]).environment.PIPELINES_DEPLOYMENT_LINK' "$(cat $PIPELINES_SCRIPT_DATA_FILE)")
      - e2e_test:
          script:
            - 'run launch_ode "node $SOURCE_DIR/scripts/clear-cloud-varnish.js"'
            - export PIPELINES_URL=$PIPELINES_DEPLOYMENT_LINK/index.html#
            - '\[ $PIPELINE_DEPLOY_VCS_PATH == "pipelines-build-master" \] && export PIPELINES_URL=$PIPELINES_DEV_URL || echo Not master.'
            - '\[ $PIPELINE_DEPLOY_VCS_PATH == "pipelines-build-staging" \] && export PIPELINES_URL=$PIPELINES_STAGING_URL || echo Not staging.'
            - '\[ $PIPELINE_DEPLOY_VCS_PATH == "pipelines-build-production" \] && run e2e_test "npm run e2e:acceptance"'
            - 'run end'
      - release:
          script:
            - chmod +x ./scripts/post_deploy.sh
            - echo "switching the directory to $SOURCE_DIR"
            - 'cd $SOURCE_DIR'
            - ./scripts/post_deploy.sh $PIPELINE_DEPLOY_VCS_PATH

.gitlab-ci.yml file content

image: 'php:7.4'
variables:
  COMPOSER_BIN: $SOURCE_DIR/vendor/bin
  BLT_DIR: $SOURCE_DIR/vendor/acquia/blt
stages:
  - build
  - post-deploy
setup:
  script:
    - 'composer validate --no-check-all --ansi --no-interaction'
    - 'composer install'
    - 'mkdir -p docroot/profiles/acquia_cms'
    - 'composer archive --format zip --file acquia_cms'
    - 'unzip acquia_cms.zip -d docroot/profiles/acquia_cmsort'
    - 'cp -R modules/acquia_cms_development docroot/profiles/acquia_cms/modules'
    - 'cp config/optional/views.view.acquia_search.yml docroot/profiles/acquia_cms/config/optional'
  stage: build
  before_script:
    - 'composer install'
setup-env:
  script:
    - 'composer validate --no-check-all --ansi'
    - 'composer install --ansi'
    - 'source ${BLT_DIR}/scripts/pipelines/setup_env'
  stage: build
  before_script:
    - 'composer install'
validate:
  script:
    - 'source ${BLT_DIR}/scripts/pipelines/validate'
  stage: build
  before_script:
    - 'composer install'
front-end:
  script:
    - 'cd themes/acquia_claro'
    - 'npm install'
    - 'npm run build'
    - 'cd -'
    - 'cp -R themes/acquia_claro/css docroot/profiles/acquia_cms/themes/acquia_claro'
    - 'mkdir -p docroot/profiles/acquia_cms/modules/acquia_cms_tour/css'
    - 'cp modules/acquia_cms_tour/css/acquia_cms_tour.css docroot/profiles/acquia_cms/modules/acquia_cms_tour/css'
  stage: build
  before_script:
    - 'composer install'
launch_ode:
  script:
    - 'alias run="node $SOURCE_DIR/scripts/run.js"'
    - 'run launch_ode "pipelines-deploy"'
    - 'export PIPELINES_DEPLOYMENT_NAME=$(node -pe ''JSON.parse(process.argv[1]).environment.PIPELINES_DEPLOYMENT_NAME'' "$(cat $PIPELINES_SCRIPT_DATA_FILE)")'
    - 'export PIPELINES_DEPLOYMENT_LINK=$(node -pe ''JSON.parse(process.argv[1]).environment.PIPELINES_DEPLOYMENT_LINK'' "$(cat $PIPELINES_SCRIPT_DATA_FILE)")'
  stage: post-deploy
e2e_test:
  script:
    - 'run launch_ode "node $SOURCE_DIR/scripts/clear-cloud-varnish.js"'
    - 'export PIPELINES_URL=$PIPELINES_DEPLOYMENT_LINK/index.html#'
    - '\[ $PIPELINE_DEPLOY_VCS_PATH == "pipelines-build-master" \] && export PIPELINES_URL=$PIPELINES_DEV_URL || echo Not master.'
    - '\[ $PIPELINE_DEPLOY_VCS_PATH == "pipelines-build-staging" \] && export PIPELINES_URL=$PIPELINES_STAGING_URL || echo Not staging.'
    - '\[ $PIPELINE_DEPLOY_VCS_PATH == "pipelines-build-production" \] && run e2e_test "npm run e2e:acceptance"'
    - 'run end'
  stage: post-deploy
release:
  script:
    - 'chmod +x ./scripts/post_deploy.sh'
    - 'echo "switching the directory to $SOURCE_DIR"'
    - 'cd $SOURCE_DIR'
    - './scripts/post_deploy.sh $PIPELINE_DEPLOY_VCS_PATH'
  stage: post-deploy

shubham-bansal96 and others added 12 commits July 9, 2026 11:24
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>
Copilot AI review requested due to automatic review settings July 9, 2026 06:59
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.54015% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.60%. Comparing base (4f6ac74) to head (df8f7f0).

Files with missing lines Patch % Lines
...ommand/Pipelines/PipelinesMigrateGitlabCommand.php 98.54% 2 Missing ⚠️
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 PipelinesMigrateGitlabCommand to 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 expected list output to include the new pipelines:* 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");
Comment on lines +170 to +189
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."),
};
}
Comment on lines +235 to +242
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;
}
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Try the dev build for this PR: https://acquia-cli.s3.amazonaws.com/build/pr/2017/acli.phar

curl -OL https://acquia-cli.s3.amazonaws.com/build/pr/2017/acli.phar
chmod +x 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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment on lines +121 to +123
if (!is_array($parsed) || !array_key_exists('events', $parsed)) {
throw new AcquiaCliException("The file {$path} does not contain an 'events' key.");
}
Comment on lines +186 to +191
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."),
};
shubham-bansal96 and others added 6 commits July 9, 2026 15:25
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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Comment on lines +174 to +179
if (!array_key_exists('services', $contents)) {
// @infection-ignore-all Returning empty array; ArrayOneItem mutant is equivalent here.
return $output;
}

foreach ($contents['services'] as $service) {
Comment on lines +215 to +222
$vars = $contents['variables'];

if (array_key_exists('global', $vars) && is_array($vars['global'])) {
return $vars['global'];
}

return $vars;
}
Comment on lines +238 to +242
$eventData = $contents['events'][$eventName];
if (empty($eventData['steps'])) {
$this->io->warning("Event '$eventName' has no steps and was skipped.");
continue;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of superpower can we use https://github.com/Fission-AI/OpenSpec/

@PrakharJainS3

Copy link
Copy Markdown
Contributor

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants