image: studip/studip:tests-php8.1

variables:
  FF_NETWORK_PER_BUILD: 1
  GIT_DEPTH: 1
  MYSQL_RANDOM_ROOT_PASSWORD: "true"
  MYSQL_DATABASE: studip_db
  MYSQL_USER: studip_user
  MYSQL_PASSWORD: studip_password
  MYSQL_HOST: mariadb
  DEMO_DATA: "true"
  MAIL_TRANSPORT: debug
  PHPSTAN_LEVEL: 0
  # Optimize caching
  FF_USE_FASTZIP: "true"
  CACHE_COMPRESSION_LEVEL: "fast"
  # Use faster docker driver
  DOCKER_DRIVER: overlay2
  # Images
  NODE_IMAGE: node:18-slim
  # Directories
  CACHE_DIR: .caches
  REPORT_DIR: .reports
  # Set npm cache directory
  npm_config_cache: $CI_PROJECT_DIR/.npm

stages:
  - build
  - checks
  - analyse
  - test
  - packaging
  - release

.scripts:
  mkdir-caches: &mkdir-caches
    - mkdir -p $CACHE_DIR
  mkdir-reports: &mkdir-reports
    - mkdir -p $REPORT_DIR
  install-composer: &install-composer
    - make composer-dev
  configure-studip: &configure-studip
    - *install-composer
    - cp docker/studip/config_local.php config/config_local.inc.php
    - cp config/config.inc.php.dist config/config.inc.php
  initialize-studip-database: &initialize-studip-database
    - *configure-studip
    - chmod +x .gitlab/scripts/install_db.sh
    - .gitlab/scripts/install_db.sh
    - cli/studip migrate

.caches:
  composer: &composer-cache
    key:
      files:
        - composer.lock
    paths:
      - composer/
    policy: pull
  npm: &npm-cache
    key:
      files:
        - package-lock.json
    paths:
      - .npm

.definitions:
  mariadb-service: &mariadb-service
   - name: mariadb
     command: [ "--sql_mode=","--character-set-client=utf8","--character-set-server=utf8","--collation-server=utf8_unicode_ci"]

build-composer:
  stage: build
  needs: []
  interruptible: true
  variables:
    COMPOSER_CACHE: $CACHE_DIR/composer-cache
  before_script:
    - mkdir -p $COMPOSER_CACHE
  script:
    - composer install
  cache:
    - *composer-cache
    - key: composer-package-cache
      paths:
        - $COMPOSER_CACHE
      policy: pull-push

lint-php:
  stage: checks
  needs: [build-composer]
  variables:
    CACHE_LOCATION: $CACHE_DIR/phplint-cache
    PHPLINT_JSON_REPORT: $REPORT_DIR/phplint-report.json
    PHPLINT_CODE_QUALITY_REPORT: $REPORT_DIR/phplint-codequality.json
  interruptible: true
  cache:
    - *composer-cache
    - key: "$CI_JOB_NAME_SLUG:$CI_COMMIT_REF_SLUG"
      paths:
        - $CACHE_LOCATION
  before_script:
    - *mkdir-caches
    - *mkdir-reports
    - *install-composer
  script:
    - COMPOSER_MEMORY_LIMIT=-1
      composer exec phplint
      --
      --log-json=$PHPLINT_JSON_REPORT
      --cache=$CACHE_LOCATION
  after_script:
    - ./.gitlab/scripts/convert-phplint-report $PHPLINT_JSON_REPORT > $PHPLINT_CODE_QUALITY_REPORT
  artifacts:
    reports:
      codequality: $PHPLINT_CODE_QUALITY_REPORT

lint-php-8.3:
  image: studip/studip:tests-php8.3
  stage: checks
  needs: [build-composer]
  variables:
    CACHE_LOCATION: $CACHE_DIR/phplint-cache
    PHPLINT_JSON_REPORT: $REPORT_DIR/phplint-report-8.3.json
    PHPLINT_CODE_QUALITY_REPORT: $REPORT_DIR/phplint-codequality-8.3.json
  interruptible: true
  cache:
    - *composer-cache
    - key: "$CI_JOB_NAME_SLUG:$CI_COMMIT_REF_SLUG"
      paths:
        - $CACHE_LOCATION
  before_script:
    - *mkdir-caches
    - *mkdir-reports
    - *install-composer
  script:
    - COMPOSER_MEMORY_LIMIT=-1
      composer exec phplint
      --
      --log-json=$PHPLINT_JSON_REPORT
      --cache=$CACHE_LOCATION
  after_script:
    - ./.gitlab/scripts/convert-phplint-report $PHPLINT_JSON_REPORT > $PHPLINT_CODE_QUALITY_REPORT
  artifacts:
    reports:
      codequality: $PHPLINT_CODE_QUALITY_REPORT

lint-js:
  stage: checks
  needs: []
  image: $NODE_IMAGE
  variables:
    CACHE_LOCATION: $CACHE_DIR/eslint-cache
    ESLINT_CODE_QUALITY_REPORT: $REPORT_DIR/eslint-codequality.json
  cache:
    - key: "$CI_JOB_NAME_SLUG:$CI_COMMIT_REF_SLUG"
      paths:
        - $CACHE_LOCATION
  interruptible: true
  before_script:
    - *mkdir-reports
    - npm install -g npm@7
    - npm install
      --no-save --no-audit --no-fund
      --loglevel=error
      eslint eslint-formatter-gitlab
  script:
    - npx eslint
      --ext .js,.vue
      --cache --cache-location $CACHE_LOCATION
      --format gitlab
      resources/assets/javascripts resources/vue
  artifacts:
    reports:
      codequality: $ESLINT_CODE_QUALITY_REPORT

lint-css:
  stage: checks
  needs: []
  image: $NODE_IMAGE
  variables:
    CACHE_LOCATION: $CACHE_DIR/stylelint-cache
    STYLELINT_CODE_QUALITY_REPORT: $REPORT_DIR/stylelint-codequality.json
  interruptible: true
  cache:
    - key: "$CI_JOB_NAME_SLUG:CI_COMMIT_REF_SLUG"
      paths:
        - $CACHE_LOCATION
  before_script:
    - *mkdir-reports
    - npm install
      --no-save --no-audit --no-fund
      --loglevel=error 
      stylelint@^14.9.1
      stylelint-config-standard@^26.0.0
      stylelint-formatter-gitlab
  script:
    - npx
      stylelint
      --cache --cache-location $CACHE_LOCATION
      --custom-formatter=node_modules/stylelint-formatter-gitlab 
      --output-file $STYLELINT_CODE_QUALITY_REPORT
      resources/assets/stylesheets
  artifacts:
    reports:
      codequality: $STYLELINT_CODE_QUALITY_REPORT

phpstan:
  stage: analyse
  needs: [build-composer]
  variables:
    CACHE_LOCATION: $CACHE_DIR/phpstan
    PHPSTAN_CODE_QUALITY_REPORT: $REPORT_DIR/phpstan-codequality.json
  allow_failure: true
  interruptible: true
  when: manual
  cache:
   - *composer-cache
   - key: "$CO_JOB_NAME_SLUG:$CI_COMMIT_REF_SLUG"
     paths:
       - $CACHE_LOCATION
  before_script:
    - *mkdir-caches
    - *mkdir-reports
    - *install-composer
    - 'echo "includes:\n    - phpstan.neon.dist\n\nparameters:\n   tmpDir: $PHPSTAN_CACHE_PATH" > phpstan.neon'
  script:
    - php
      composer/bin/phpstan analyse 
      --memory-limit=1G 
      --no-progress 
      --level=$PHPSTAN_LEVEL
      --error-format=gitlab > $PHPSTAN_CODE_QUALITY_REPORT
  after_script:
    - rm phpstan.neon
  artifacts:
    reports:
      codequality: $PHPSTAN_CODE_QUALITY_REPORT

test-unit:
  stage: test
  needs: [lint-php]
  variables:
    PHPUNIT_XML_REPORT: $REPORT_DIR/phpunit-report.xml
  cache:
    <<: *composer-cache
    policy: pull
  allow_failure: false
  interruptible: true
  before_script:
    - *mkdir-reports
    - *configure-studip
  script:
    - 'composer/bin/codecept
      run unit
      --xml=$PHPUNIT_XML_REPORT
      -o "paths: output: ."'
  after_script:
    - sed -i "s%$PWD/%%" $PHPUNIT_XML_REPORT
  artifacts:
    reports:
      junit: $PHPUNIT_XML_REPORT

test-jest:
  stage: test
  needs: [lint-js]
  image: $NODE_IMAGE
  variables:
    JS_TEST_REPORT: $REPORT_DIR/jest.xml
  cache: *npm-cache
  interruptible: true
  before_script:
    - *mkdir-reports
    - npm install
  script:
    - JEST_JUNIT_OUTPUT_FILE="$JS_TEST_REPORT" npx jest tests/jest/ --ci --reporters=default --reporters=jest-junit
  artifacts:
    reports:
      junit: $JS_TEST_REPORT

test-functional:
  stage: test
  needs: [lint-php]
  variables:
    FUNCTIONAL_XML_REPORT: $REPORT_DIR/functional-report.xml
    FUNCTIONAL_CODE_QUALITY_REPORT: $REPORT_DIR/functional-codequality.json
  cache:
    <<: *composer-cache
    policy: pull
  services:
    - *mariadb-service
  allow_failure: false
  interruptible: true
  before_script:
    - *mkdir-reports
    - *initialize-studip-database
  script:
    - 'composer/bin/codecept
      run functional
      --xml=$FUNCTIONAL_XML_REPORT
      -o "paths: output: ."'
  after_script:
    - sed -i "s%$PWD/%%" $FUNCTIONAL_XML_REPORT
  artifacts:
    reports:
      junit: $FUNCTIONAL_XML_REPORT

test-jsonapi:
  stage: test
  needs: [lint-php]
  cache:
    <<: *composer-cache
    policy: pull
  services:
    - *mariadb-service
  variables:
    JSONAPI_XML_REPORT: $REPORT_DIR/jsonapi-report.xml
  interruptible: true
  before_script:
    - *mkdir-reports
    - *initialize-studip-database
  script:
    - 'composer/bin/codecept
      run jsonapi
      --xml=$JSONAPI_XML_REPORT
      -o "paths: output: ."'
  after_script:
    - sed -i "s%$PWD/%%" $JSONAPI_XML_REPORT
  artifacts:
    reports:
      junit: $JSONAPI_XML_REPORT

test-assets:
  stage: test
  needs: []
  image: $NODE_IMAGE
  cache: *npm-cache
  interruptible: true
  before_script:
    - npm install
  script:
    - npm run webpack-dev

test-e2e:
  stage: test
  #  needs: [lint-css, lint-js, lint-php]
  image: mcr.microsoft.com/playwright:v1.33.0-jammy
  services:
    - name: mariadb
      command: ["--sql_mode="]
  variables:
    PHP_WEBSERVER_URL: localhost:65432
    E2E_REPORT: $REPORT_DIR/e2e.xml
  interruptible: true
  when: manual
  cache:
    - *composer-cache
    - *npm-cache
  before_script:
    - mkdir ./bin
    - apt-get update
    - apt -y install software-properties-common
    - add-apt-repository ppa:ondrej/php
    - apt-get update
    - DEBIAN_FRONTEND=noninteractive
      apt-get -yq install
      make zip unzip mariadb-client
      php7.4 libapache2-mod-php7.4 php7.4-common php7.4-curl php7.4-mbstring
      php7.4-xmlrpc php7.4-mysql php7.4-gd php7.4-xml php7.4-intl php7.4-ldap
      php7.4-imagick php7.4-json php7.4-cli
    - echo "short_open_tag=On" >> /etc/php/7.4/php.ini
    - echo "short_open_tag=On" >> /etc/php/7.4/cli/php.ini
    - php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
    - php composer-setup.php  --install-dir=./bin --filename=composer
    - export PATH="./bin:$PATH"
    - php -r "unlink('composer-setup.php');"
    - *mkdir-reports
    - *initialize-studip-database
    - ./cli/studip config:set SHOW_TERMS_ON_FIRST_LOGIN 0
    - npm install playwright
    - npm ci
    - npx playwright install --with-deps
  script:
    - php -S $PHP_WEBSERVER_URL -t public -q &
    - PHP_SERVER_PID=$!
    - PLAYWRIGHT_JUNIT_OUTPUT_NAME="$E2E_REPORT"
      PLAYWRIGHT_BASE_URL="http://$PHP_WEBSERVER_URL"
      npx playwright test --reporter=junit --grep-invert a11y
    - kill -3 $PHP_SERVER_PID
  artifacts:
    reports:
      junit: $E2E_REPORT

packaging:
  stage: packaging
  cache: []
  rules:
    - if: $CI_COMMIT_TAG
  before_script:
    - echo GE_JOB_ID=$CI_JOB_ID >> .packaging.env
    - mkdir .pkg
  script:
    - echo 'Running packaging job'
    - make build clean-npm
    - zip -r9 .pkg/studip-$CI_COMMIT_TAG.zip *
    - tar -czf .pkg/studip-$CI_COMMIT_TAG.tar.gz *
  artifacts:
    name: 'Stud.IP-Release-$CI_COMMIT_TAG'
    paths:
      - .pkg/studip-$CI_COMMIT_TAG.zip
      - .pkg/studip-$CI_COMMIT_TAG.tar.gz
    reports:
      dotenv: .packaging.env
    expire_in: never

build_image:
  image: 
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  stage: build
  when: manual
  interruptible: true
  variables:
    IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
  script:
    - /kaniko/executor --context=dir://${CI_PROJECT_DIR} --dockerfile ${CI_PROJECT_DIR}/docker/studip/Dockerfile --destination ${IMAGE_TAG} --cache=true

release:
  stage: release
  image: studip/release-cli
  cache: []
  rules:
    - if: $CI_COMMIT_TAG
  script:
    - echo 'Running release job'
  needs:
    - job: packaging
      artifacts: true
  release:
    name: "$CI_COMMIT_TAG"
    description: "https://gitlab.studip.de/studip/studip/-/blob/${CI_COMMIT_TAG}/ChangeLog"
    tag_name: "$CI_COMMIT_TAG"
    assets:
      links:
        - name: "studip-$CI_COMMIT_TAG.zip"
          url: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/jobs/${GE_JOB_ID}/artifacts/.pkg/studip-$CI_COMMIT_TAG.zip"
          link_type: package
        - name: "studip-$CI_COMMIT_TAG.tar.gz"
          url: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/jobs/${GE_JOB_ID}/artifacts/.pkg/studip-$CI_COMMIT_TAG.tar.gz"
          link_type: package