# Copyright (C) 2017-2021 Free Software Foundation, Inc.
#
#  This file is part of GNU Emacs.
#
#  GNU Emacs is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  GNU Emacs is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.

# GNU Emacs support for the GitLab protocol for CI

# The presence of this file does not imply any FSF/GNU endorsement of
# any particular service that uses that protocol.  Also, it is intended for
# evaluation purposes, thus possibly temporary.

# Maintainer: Ted Zlatanov <tzz@lifelogs.com>
# URL: https://emba.gnu.org/emacs/emacs

# Never run merge request pipelines, they usually duplicate push pipelines
# see https://docs.gitlab.com/ee/ci/yaml/README.html#common-if-clauses-for-rules

# Rules: always run tags and branches named master*, emacs*, feature*, fix*
# Test that it triggers by pushing a tag: `git tag mytag; git push origin mytag`
# Test that it triggers by pushing to: feature/emba, feature1, master, master-2, fix/emba, emacs-299, fix-2
# Test that it doesn't trigger by pushing to: scratch-2, scratch/emba, oldbranch, dev
workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: never
    - if: '$CI_COMMIT_TAG'
      when: always
    - if: '$CI_COMMIT_BRANCH !~ /^(master|emacs|feature|fix)/'
      when: never
    - when: always

variables:
  GIT_STRATEGY: fetch
  EMACS_EMBA_CI: 1
  # Three hours, see below.
  EMACS_TEST_TIMEOUT: 10800
  EMACS_TEST_VERBOSE: 1
  # # Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
  # DOCKER_HOST: tcp://docker:2376
  # DOCKER_TLS_CERTDIR: "/certs"
  # Put the configuration for each run in a separate directory to
  # avoid conflicts.
  DOCKER_CONFIG: "/.docker-config-${CI_COMMIT_SHA}"
  DOCKER_BUILDKIT: 1
  # We don't use ${CI_COMMIT_SHA} to be able to do one bootstrap
  # across multiple builds.
  BUILD_TAG: ${CI_COMMIT_REF_SLUG}

default:
  image: docker:19.03.12
  timeout: 3 hours
  before_script:
    - docker info
    - echo "docker registry is ${CI_REGISTRY}"
    - docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}

.job-template:
  variables:
    test_name: ${CI_JOB_NAME}-${CI_COMMIT_SHORT_SHA}
  rules:
    - changes:
        - "**Makefile.in"
        - .gitlab-ci.yml
        - aclocal.m4
        - autogen.sh
        - configure.ac
        - lib/*.{h,c}
        - lisp/**.el
        - src/*.{h,c}
        - test/infra/*
        - test/lib-src/*.el
        - test/lisp/**.el
        - test/misc/*.el
        - test/src/*.el
    - changes:
        # gfilemonitor, kqueue
        - src/gfilenotify.c
        - src/kqueue.c
        # MS Windows
        - "**w32*"
        # GNUstep
        - lisp/term/ns-win.el
        - src/ns*.{h,m}
        - src/macfont.{h,m}
      when: never
  # These will be cached across builds.
  cache:
    key: ${CI_COMMIT_SHA}
    paths: []
    policy: pull-push
  # These will be saved for followup builds.
  artifacts:
    expire_in: 24 hrs
    paths: []
  # Using the variables for each job.
  script:
    - docker pull ${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG}
    # TODO: with make -j4 several of the tests were failing, for
    # example shadowfile-tests, but passed without it.
    - 'export PWD=$(pwd)'
    - 'docker run -i -e EMACS_EMBA_CI=${EMACS_EMBA_CI} -e EMACS_TEST_TIMEOUT=${EMACS_TEST_TIMEOUT} -e EMACS_TEST_VERBOSE=${EMACS_TEST_VERBOSE} --volumes-from $(docker ps -q -f "label=com.gitlab.gitlab-runner.job.id=${CI_JOB_ID}"):ro --name ${test_name} ${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG} /bin/bash -c "git fetch ${PWD} HEAD && echo checking out these updated files && git diff --name-only FETCH_HEAD && ( git diff --name-only FETCH_HEAD | xargs git checkout -f FETCH_HEAD ) && make -j4 && make ${make_params}"'
  after_script:
    # - docker ps -a
    # - printenv
    # - test -n "$(docker ps -aq -f name=${test_name})" && ( docker export ${test_name} | tar -tvf - )
    - test -n "$(docker ps -aq -f name=${test_name})" && docker cp ${test_name}:checkout/test ${test_name}
    - test -n "$(docker ps -aq -f name=${test_name})" && docker rm ${test_name}
    # - ls -alR ${test_name}

.build-template:
  needs: []
  rules:
    - if: '$CI_PIPELINE_SOURCE == "web"'
      when: always
    - changes:
        - "**Makefile.in"
        - .gitlab-ci.yml
        - aclocal.m4
        - autogen.sh
        - configure.ac
        - lib/*.{h,c}
        - lisp/emacs-lisp/*.el
        - src/*.{h,c}
        - test/infra/*
    - changes:
        # gfilemonitor, kqueue
        - src/gfilenotify.c
        - src/kqueue.c
        # MS Windows
        - "**w32*"
        # GNUstep
        - lisp/term/ns-win.el
        - src/ns*.{h,m}
        - src/macfont.{h,m}
      when: never
  script:
    - docker build --pull --target ${target} -t ${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG} -f test/infra/Dockerfile.emba .
    - docker push ${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG}

.test-template:
  # Do not run fast and normal test jobs when scheduled.
  rules:
    - if: '$CI_JOB_STAGE =~ "fast|normal" && $CI_PIPELINE_SOURCE == "schedule"'
      when: never
    - when: always
  artifacts:
    name: ${test_name}
    public: true
    expire_in: 1 week
    paths:
      - ${test_name}/**/*.log
      - ${test_name}/**/core
      - ${test_name}/core
    when: always

.gnustep-template:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "web"'
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
      changes:
        - "**Makefile.in"
        - .gitlab-ci.yml
        - configure.ac
        - src/ns*.{h,m}
        - src/macfont.{h,m}
        - lisp/term/ns-win.el
        - nextstep/**
        - test/infra/*

.filenotify-gio-template:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "web"'
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
      changes:
        - "**Makefile.in"
        - .gitlab-ci.yml
        - lisp/autorevert.el
        - lisp/filenotify.el
        - lisp/net/tramp-sh.el
        - src/gfilenotify.c
        - test/infra/*
        - test/lisp/autorevert-tests.el
        - test/lisp/filenotify-tests.el

.native-comp-template:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "web"'
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
      changes:
        - "**Makefile.in"
        - .gitlab-ci.yml
        - lisp/emacs-lisp/comp.el
        - lisp/emacs-lisp/comp-cstr.el
        - src/comp.{h,m}
        - test/infra/*
        - test/src/comp-resources/*.el
        - test/src/comp-tests.el
  timeout: 8 hours

stages:
  - build-images
#  - fast
  - normal
  - platform-images
  - platforms
  - native-comp-images
  - native-comp
  - slow

build-image-inotify:
  stage: build-images
  extends: [.job-template, .build-template]
  variables:
    target: emacs-inotify
# Temporarily.
  timeout: 8 hours

# test-fast-inotify:
#   stage: fast
#   extends: [.job-template, .test-template]
#   variables:
#     target: emacs-inotify
#     make_params: "-C test check"

test-lisp-inotify:
  stage: normal
  extends: [.job-template, .test-template]
  variables:
    target: emacs-inotify
    make_params: "-C test check-lisp"

test-lisp-net-inotify:
  stage: normal
  extends: [.job-template, .test-template]
  variables:
    target: emacs-inotify
    make_params: "-C test check-lisp-net"

test-lisp-mh-e-inotify:
  stage: normal
  extends: [.job-template, .test-template]
  variables:
    target: emacs-inotify
    make_params: "-C test check-lisp-mh-e"

build-image-filenotify-gio:
  stage: platform-images
  extends: [.job-template, .build-template, .filenotify-gio-template]
  variables:
    target: emacs-filenotify-gio

build-image-gnustep:
  stage: platform-images
  extends: [.job-template, .build-template, .gnustep-template]
  variables:
    target: emacs-gnustep

test-filenotify-gio:
  # This tests file monitor libraries gfilemonitor and gio.
  stage: platforms
  needs: [build-image-filenotify-gio]
  extends: [.job-template, .test-template, .filenotify-gio-template]
  variables:
    target: emacs-filenotify-gio
    make_params: "-k -C test autorevert-tests.log filenotify-tests.log"

test-gnustep:
  # This tests the GNUstep build process.
  stage: platforms
  needs: [build-image-gnustep]
  extends: [.job-template, .gnustep-template]
  variables:
    target: emacs-gnustep
    make_params: install

build-native-comp-speed0:
  stage: native-comp-images
  extends: [.job-template, .build-template, .native-comp-template]
  variables:
    target: emacs-native-comp-speed0

build-native-comp-speed1:
  stage: native-comp-images
  extends: [.job-template, .build-template, .native-comp-template]
  variables:
    target: emacs-native-comp-speed1

build-native-comp-speed2:
  stage: native-comp-images
  extends: [.job-template, .build-template, .native-comp-template]
  variables:
    target: emacs-native-comp-speed2

test-native-comp-speed0:
  stage: native-comp
  needs: [build-native-comp-speed0]
  extends: [.job-template, .test-template, .native-comp-template]
  variables:
    target: emacs-native-comp-speed0
    make_params: >-
      -C test check EXCLUDE_TESTS=%emacs-module-tests.el
         SELECTOR='(not (tag :unstable))'

test-all-inotify:
  # This tests also file monitor libraries inotify and inotifywatch.
  stage: slow
  needs: [build-image-inotify]
  extends: [.job-template, .test-template]
  rules:
    # Note there's no "changes" section, so this always runs on a schedule.
    - if: '$CI_PIPELINE_SOURCE == "web"'
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
  variables:
    target: emacs-inotify
    make_params: check-expensive EXCLUDE_TESTS=%emacs-module-tests.el
    # Two hours.
    EMACS_TEST_TIMEOUT: 7200

# Local Variables:
# add-log-current-defun-header-regexp: "^\\([-_.[:alnum:]]+\\)[ \t]*:"
# End: