# cspell:ignore codequality Micheh micheh

################
# Drupal GitLabCI template.
#
# Based off GitlabCI templates project: https://git.drupalcode.org/project/gitlab_templates
# Guide: https://www.drupal.org/docs/develop/git/using-gitlab-to-contribute-to-drupal/gitlab-ci
#
# With thanks to:
# - The GitLab Acceleration Initiative participants
# - DrupalSpoons
################

################
# Includes
#
# Additional configuration can be provided through includes.
# One advantage of include files is that if they are updated upstream, the
# changes affect all pipelines using that include.
#
# Includes can be overridden by re-declaring anything provided in an include,
# here in gitlab-ci.yml.
# https://docs.gitlab.com/ee/ci/yaml/includes.html#override-included-configuration-values
################

include:
  - project: $_GITLAB_TEMPLATES_REPO
    ref: $_GITLAB_TEMPLATES_REF
    file:
      - '/includes/include.drupalci.variables.yml'
      - '/includes/include.drupalci.workflows.yml'

################
# Variables
#
# Overriding variables
# - To override one or more of these variables, simply declare your own variables keyword.
# - Keywords declared directly in .gitlab-ci.yml take precedence over include files.
# - Documentation:  https://docs.gitlab.com/ee/ci/variables/
# - Predefined variables: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
#
################

variables:
  COMPOSER: composer.json
  # Let composer know what self.version means.
  COMPOSER_ROOT_VERSION: "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}${CI_COMMIT_BRANCH}-dev"
  CONCURRENCY: 24
  GIT_DEPTH: "50"
  PARENT_PIPELINE_ID: $CI_PIPELINE_ID
  _TARGET_PHP: "8.2"

#############
# Stages    #
#############
stages:
  - 🏗️ Build
  - 🪄 Lint
  - 🗜️ Test

#############
# Defaults  #
#############

default:
  interruptible: true
  retry:
    max: 2
    when:
      - unknown_failure
      - api_failure
      - stuck_or_timeout_failure
      - runner_system_failure
      - scheduler_failure
  image:
    name: $_CONFIG_DOCKERHUB_ROOT/php-$_TARGET_PHP-apache:production

#############
# Templates #
#############

.with-composer: &with-composer
  needs:
    - '📦️ Composer'

.with-yarn: &with-yarn
  needs:
    - '📦️ Yarn'

.default-job-settings-lint: &default-job-settings-lint
  rules:
    - if: $PERFORMANCE_TEST != "1"


################
# Stages
#
# Each job is assigned to a stage, defining the order in which the jobs are executed.
# Jobs in the same stage run in parallel.
#
# If all jobs in a stage succeed, the pipeline will proceed to the next stage.
# If any job in the stage fails, the pipeline will exit early.
################

.default-stage: &default-stage
  stage: 🗜️ Test
  trigger:
    # Rely on the status of the child pipeline.
    strategy: depend
    include:
      - local: .gitlab-ci/pipeline.yml

.run-on-commit: &run-on-commit
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ROOT_NAMESPACE == "project"
      allow_failure: true

.run-daily: &run-daily
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule" && $CI_PROJECT_ROOT_NAMESPACE == "project" && $DAILY_TEST == "1"
      allow_failure: true

.run-on-mr: &run-on-mr
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: manual
      allow_failure: true

# Default configuration.
'DEFAULT: PHP 8.2 MySQL 8':
  <<: *default-stage
  variables:
    _TARGET_PHP: "8.2"
    _TARGET_DB: "mysql-8"
    PERFORMANCE_TEST: $PERFORMANCE_TEST
    OTEL_COLLECTOR: $OTEL_COLLECTOR
  # Run on MR, schedule, push and performance test.
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ROOT_NAMESPACE == "project"
      allow_failure: true
    - if: $CI_PIPELINE_SOURCE == "schedule" && $CI_PROJECT_ROOT_NAMESPACE == "project" && $DAILY_TEST == "1"
      allow_failure: true
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $PERFORMANCE_TEST == "1"

# Special job for MRs for test-only checks.
'DEFAULT: Test-only (PHP 8.2 MySQL 8)':
  <<: [ *default-stage, *with-composer ]
  when: manual
  allow_failure: true
  variables:
    _TARGET_PHP: "8.2"
    _TARGET_DB: "mysql-8"
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  trigger:
    # Rely on the status of the child pipeline.
    strategy: depend
    include:
      - local: .gitlab-ci/pipeline-test-only.yml

# Main listing of jobs.
# All of these are available on Merge Requests and also work as base jobs for
# on-commit and daily jobs to extend from.
'PHP 8.1 MySQL 5.7':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.1"
    _TARGET_DB: "mysql-5.7"

'PHP 8.2 PostgreSQL 14.1':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.2"
    _TARGET_DB: "pgsql-14.1"

'PHP 8.2 PostgreSQL 15':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.2"
    _TARGET_DB: "pgsql-15"

'PHP 8.2 PostgreSQL 16':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.2"
    _TARGET_DB: "pgsql-16"

'PHP 8.2 SQLite 3':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.2"
    _TARGET_DB: "sqlite-3"

'PHP 8.3 MySQL 8':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.3"
    _TARGET_DB: "mysql-8"

'PHP 8.3 PostgreSQL 16':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.3"
    _TARGET_DB: "pgsql-16"

'PHP 8.3 SQLite 3':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.3"
    _TARGET_DB: "sqlite-3"

'PHP 8.1 MariaDB 10.3.22':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.1"
    _TARGET_DB: "mariadb-10.3.22"

'PHP 8.1 PostgreSQL 14.1':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.1"
    _TARGET_DB: "pgsql-14.1"

'PHP 8.1 SQLite 3':
  <<: [ *default-stage, *run-on-mr ]
  variables:
    _TARGET_PHP: "8.1"
    _TARGET_DB: "sqlite-3"

# Jobs running on commits.
# The value set in the "needs" property will determine the order in the sequence.
'[Commit] PHP 8.1 MySQL 5.7':
  extends: 'PHP 8.1 MySQL 5.7'
  needs: [ 'DEFAULT: PHP 8.2 MySQL 8' ]
  <<: [ *run-on-commit ]

'[Commit] PHP 8.2 PostgreSQL 16':
  extends: 'PHP 8.2 PostgreSQL 16'
  needs: [ '[Commit] PHP 8.1 MySQL 5.7' ]
  <<: [ *run-on-commit ]

'[Commit] PHP 8.2 SQLite 3':
  extends: 'PHP 8.2 SQLite 3'
  needs: [ '[Commit] PHP 8.2 PostgreSQL 16' ]
  <<: [ *run-on-commit ]

# Jobs running daily.
# The value set in the "needs" property will determine the order in the sequence.
'[Daily] PHP 8.2 PostgreSQL 14.1':
  extends: 'PHP 8.2 PostgreSQL 14.1'
  needs: [ 'DEFAULT: PHP 8.2 MySQL 8' ]
  <<: [ *run-daily ]

'[Daily] PHP 8.2 PostgreSQL 15':
  extends: 'PHP 8.2 PostgreSQL 15'
  needs: [ '[Daily] PHP 8.2 PostgreSQL 14.1' ]
  <<: [ *run-daily ]

'[Daily] PHP 8.3 MySQL 8':
  extends: 'PHP 8.3 MySQL 8'
  needs: [ '[Daily] PHP 8.2 PostgreSQL 15' ]
  <<: [ *run-daily ]

'[Daily] PHP 8.3 PostgreSQL 16':
  extends: 'PHP 8.3 PostgreSQL 16'
  needs: [ '[Daily] PHP 8.3 MySQL 8' ]
  <<: [ *run-daily ]

'[Daily] PHP 8.3 SQLite 3':
  extends: 'PHP 8.3 SQLite 3'
  needs: [ '[Daily] PHP 8.3 PostgreSQL 16' ]
  <<: [ *run-daily ]

'[Daily] PHP 8.1 MariaDB 10.3.22':
  extends: 'PHP 8.1 MariaDB 10.3.22'
  needs: [ '[Daily] PHP 8.3 SQLite 3' ]
  <<: [ *run-daily ]

'[Daily] PHP 8.1 PostgreSQL 14.1':
  extends: 'PHP 8.1 PostgreSQL 14.1'
  needs: [ '[Daily] PHP 8.1 MariaDB 10.3.22' ]
  <<: [ *run-daily ]

'[Daily] PHP 8.1 SQLite 3':
  extends: 'PHP 8.1 SQLite 3'
  needs: [ '[Daily] PHP 8.1 PostgreSQL 14.1' ]
  <<: [ *run-daily ]

################
# Build Jobs for linting
################

'📦️ Composer':
  variables:
    KUBERNETES_CPU_REQUEST: "1"
  stage: 🏗️ Build
  cache:
    key:
      files:
        - ./composer.json
        - ./composer.lock
    paths:
      - ./vendor
  artifacts:
    expire_in: 1 week
    expose_as: 'web-vendor'
    paths:
      - vendor/
  script:
      - composer validate
      - composer install

'📦️ Yarn':
  variables:
    KUBERNETES_CPU_REQUEST: "2"
  stage: 🏗️ Build
  cache:
    key:
      files:
        - ./core/package.json
        - ./core/yarn.lock
    paths:
      - ./core/node_modules
  artifacts:
    expire_in: 1 week
    expose_as: 'yarn-vendor'
    paths:
      - core/node_modules/
  script:
    - yarn --cwd ./core install

################
# Lint Jobs
################

'🧹 PHP Static Analysis (phpstan)':
  <<: [ *with-composer, *default-job-settings-lint ]
  stage: 🪄 Lint
  variables:
    KUBERNETES_CPU_REQUEST: "16"
  script:
    # Rely on PHPStan caching to execute analysis multiple times without performance drawback.
    # Output a copy in junit.
    - php vendor/bin/phpstan analyze --configuration=./core/phpstan.neon.dist --error-format=gitlab > phpstan-quality-report.json || EXIT_CODE=$?
    - php vendor/bin/phpstan analyze --configuration=./core/phpstan.neon.dist --no-progress --error-format=junit > phpstan-junit.xml || true
    - |
      if [ -n "$EXIT_CODE" ]; then
        # Output a copy in plain text for human logs.
        php vendor/bin/phpstan analyze --configuration=./core/phpstan.neon.dist --no-progress || true
        # Generate a new baseline.
        echo "Generating an PHPStan baseline file (available as job artifact)."
        php vendor/bin/phpstan analyze --configuration=./core/phpstan.neon.dist --no-progress --generate-baseline=./core/phpstan-baseline.neon || true
        exit $EXIT_CODE
      fi

  artifacts:
    reports:
      codequality: phpstan-quality-report.json
      junit: phpstan-junit.xml
    # Only store the baseline if the job fails.
    when: on_failure
    paths:
      - core/phpstan-baseline.neon

'🧹 PHP Coding standards (PHPCS)':
  <<: [ *with-composer, *default-job-settings-lint ]
  stage: 🪄 Lint
  variables:
    KUBERNETES_CPU_REQUEST: "16"
  script:
    - composer phpcs -- --report-full --report-summary --report-\\Micheh\\PhpCodeSniffer\\Report\\Gitlab=phpcs-quality-report.json
  artifacts:
    reports:
      codequality: phpcs-quality-report.json

'🧹 JavaScript linting (eslint)':
  <<: [ *with-yarn ]
  stage: 🪄 Lint
  variables:
    KUBERNETES_CPU_REQUEST: "2"
  # Run on push, or on MRs if CSS files have changed, or manually.
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ROOT_NAMESPACE == "project"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      changes:
        - core/package.json
        - core/yarn.lock
        - "**/*.js"
        - "**/*.yml"
    - when: manual
      allow_failure: true
  script:
    - yarn --cwd=./core run -s check:ckeditor5
    - yarn --cwd=./core run -s lint:core-js-passing --format gitlab
  artifacts:
    reports:
      codequality: eslint-quality-report.json

'🧹 CSS linting (stylelint)':
  <<: [ *with-yarn ]
  stage: 🪄 Lint
  variables:
    KUBERNETES_CPU_REQUEST: "2"
  # Run on push, or on MRs if CSS files have changed, or manually.
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ROOT_NAMESPACE == "project"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      changes:
        - core/package.json
        - core/yarn.lock
        - "**/*.css"
    - when: manual
      allow_failure: true
  script:
    - yarn run --cwd=./core build:css --check
    - yarn run --cwd=./core lint:css --color --custom-formatter=node_modules/stylelint-formatter-gitlab
  artifacts:
    reports:
      codequality: stylelint-quality-report.json

'📔 Spell-checking':
  <<: [ *with-yarn, *default-job-settings-lint ]
  stage: 🪄 Lint
  variables:
    KUBERNETES_CPU_REQUEST: "2"
  script:
    - if [ -n "$CI_MERGE_REQUEST_TARGET_BRANCH_SHA" ]; then
        echo "HEAD is $(git rev-parse HEAD). \$CI_MERGE_REQUEST_TARGET_BRANCH_SHA is ${CI_MERGE_REQUEST_TARGET_BRANCH_SHA}";
      else
        echo "HEAD is $(git rev-parse HEAD). \$CI_MERGE_REQUEST_DIFF_BASE_SHA is ${CI_MERGE_REQUEST_DIFF_BASE_SHA}";
      fi;
    - git diff ${CI_MERGE_REQUEST_TARGET_BRANCH_SHA:-$CI_MERGE_REQUEST_DIFF_BASE_SHA} --name-only | sed "s_^_../_" | yarn --cwd=./core run -s spellcheck:core --no-must-find-files --file-list stdin
