Skip to content
Back to skills

Gitlab Ci

ASecurity

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.

  • 16 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added August 31, 2026
ai-agentsgophpsqldebugginggitdatabaseci/cd

Works with

  • cli

Security analysis

A96/100
  • mediumUses curl or wget to download content

Pro shows the line behind each finding and how to fix it

Scanned August 31, 2026

npx -y skills add siva01c/claude-plugins --skill gitlab-ci --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gitlab Ci?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gitlab Ci
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/siva01c-gitlab-ci/badge)](https://www.skillsdirectory.com/skills/siva01c-gitlab-ci)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gitlab-ci
description: >
  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.
---

# 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

```yaml
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/
```

- **`stages`** run sequentially; jobs within a stage run in parallel.
- **`default`** holds 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`:

```yaml
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

```yaml
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

```yaml
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 deploy@prod.example.com "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

```yaml
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 |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.