Gitlab ci
Claude Code plugin marketplace: Drupal development, DDEV, Docker, CI/CD, git workflows, and OWASP ASVS security
npx -y skills add siva01c/claude-plugins --skill gitlab-ciAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 17 stars17 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use this skill when authoring or debugging GitLab CI/CD pipelines (.gitlab-ci.yml) — e.g. "add a CI pipeline for this Drupal project", "run phpcs/phpstan/phpunit in GitLab CI", "deploy with drush from a pipeline", "why is my job not running", "cache composer dependencies", or anything involving stages, rules, artifacts, environments, or GitLab runners.
SKILL.md
4.9 KB, as published. Nobody here has run it
GitLab CI/CD Skill
GitLab CI runs pipelines defined in .gitlab-ci.yml at the repository root.
This skill covers pipeline authoring with a Drupal project as the working
example: validate → test → build → deploy, with composer caching and
drush-based deployment.
Pipeline anatomy
stages:
- validate
- test
- deploy
default:
image: php:8.3-cli
before_script:
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
variables:
COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.composer-cache"
cache:
key:
files:
- composer.lock # cache invalidates when the lock file changes
paths:
- .composer-cache/
- vendor/
stagesrun sequentially; jobs within a stage run in parallel.defaultholds settings shared by all jobs.- Cache vs artifacts: cache is best-effort storage between pipelines (composer/npm caches); artifacts pass build results between jobs of the same pipeline and can be downloaded from the UI.
Controlling when jobs run — rules:
rules: replaces the deprecated only/except:
phpcs:
stage: validate
script:
- composer install --no-progress
- vendor/bin/phpcs --standard=Drupal,DrupalPractice web/modules/custom
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
First matching rule wins. Common conditions:
| Goal | Rule |
|---|---|
| MR pipelines only | if: $CI_PIPELINE_SOURCE == "merge_request_event" |
| Default branch only | if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH |
| Tags only | if: $CI_COMMIT_TAG |
| Skip on draft MRs | if: $CI_MERGE_REQUEST_TITLE =~ /^Draft:/ + when: never |
| Manual gate | when: manual (e.g. production deploy) |
Drupal test jobs
phpstan:
stage: test
script:
- composer install --no-progress
- vendor/bin/phpstan analyse web/modules/custom
phpunit:
stage: test
services:
- name: mariadb:11.4
alias: db
variables:
MARIADB_DATABASE: drupal_test
MARIADB_ROOT_PASSWORD: root
SIMPLETEST_DB: mysql://root:root@db/drupal_test
SIMPLETEST_BASE_URL: http://localhost
script:
- composer install --no-progress
- vendor/bin/phpunit -c web/core/phpunit.xml.dist web/modules/custom
artifacts:
when: always
reports:
junit: junit.xml # test results shown in MR widget
services: starts sidecar containers (database, redis) reachable by alias.
Deploying with drush
deploy_prod:
stage: deploy
environment:
name: production
url: https://www.example.com
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: manual # require a human click for prod
script:
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- ssh [email protected] "cd /var/www/site && git pull --ff-only
&& composer install --no-dev --optimize-autoloader
&& vendor/bin/drush deploy -y"
drush deploy runs updb → config:import → cache:rebuild in the right
order. Store SSH_PRIVATE_KEY as a masked, protected CI/CD variable
(Settings → CI/CD → Variables) — never in the repository.
environment: makes deployments visible under Operations → Environments and
enables rollback tracking.
Reuse — include and needs
include:
- local: .gitlab/ci/common.yml # split big configs
- component: gitlab.com/components/sast/sast@main # CI/CD component
phpunit:
needs: ["phpcs"] # DAG: start as soon as phpcs passes, skip stage wait
needs: builds a directed acyclic graph so independent jobs don't wait for
their whole previous stage.
Troubleshooting
| Symptom | Fix |
|---|---|
| Job never appears in pipeline | A rules: entry filtered it out — check $CI_PIPELINE_SOURCE for the trigger type |
| "This job is stuck" | No runner with matching tags:; check runner availability |
| Composer re-downloads everything each run | Cache key/path mismatch — cache vendor/ and $COMPOSER_CACHE_DIR, key on composer.lock |
| PHPUnit cannot connect to DB | Service alias must match host in SIMPLETEST_DB; wait for DB startup or use healthcheck-aware images |
Masked variable prints as [MASKED] but auth fails | Variable contains newline/CR — for SSH keys use tr -d '\r' and file-type variables |
| Pipeline runs twice per MR push | Branch + MR pipelines both enabled — use workflow: rules: to keep one |