# -*- YAML -*-
# Copyright (C) 2011 Urabe, Shyouhei.  All rights reserved.
#
# This file is  a part of the programming language  Ruby.  Permission is hereby
# granted,  to either  redistribute  or  modify this  file,  provided that  the
# conditions  mentioned in  the file  COPYING are  met.  Consult  the  file for
# details.

# This is  a Travis-CI  build configuration file.   The list  of configurations
# available is located in
#
#     http://about.travis-ci.org/docs/user/build-configuration/
#
# and as Ruby itself is a project written in C language,
#
#     http://about.travis-ci.org/docs/user/languages/c/
#
# is also a good place to look at.

language: c

os: linux

dist: xenial

git:
  quiet: true

cache:
  ccache: true
  directories:
    - $HOME/config_2nd
    - $HOME/.downloaded-cache

env:
  global:
    # Reset timestamps early
    - _=$(touch NEWS && find . -type f -exec touch -r NEWS {} +)
    - CONFIGURE_TTY=no
    - CCACHE_COMPILERCHECK=none
    - CCACHE_NOCOMPRESS=1
    - CCACHE_MAXSIZE=512Mi
    - NPROC="`nproc`"
    # JOBS and SETARCH are overridden when necessary; see below.
    - JOBS=-j$((1+${NPROC}))
    - SETARCH=
    - RUBY_PREFIX=/tmp/ruby-prefix
    - GEMS_FOR_TEST='timezone tzinfo'
    - UPDATE_UNICODE="UNICODE_FILES=. UNICODE_PROPERTY_FILES=. UNICODE_AUXILIARY_FILES=. UNICODE_EMOJI_FILES=."
    # https://github.com/travis-ci/travis-build/blob/e411371dda21430a60f61b8f3f57943d2fe4d344/lib/travis/build/bash/travis_apt_get_options.bash#L7
    - travis_apt_get_options='--allow-downgrades --allow-remove-essential --allow-change-held-packages'
    - travis_apt_get_options="-yq --no-install-suggests --no-install-recommends $travis_apt_get_options"

.org.ruby-lang.ci.matrix-definitions:

  - &cron-only
    if: (type = cron) AND (branch = master) AND (fork = false)

  - &make-test-only
    script:
      - $SETARCH make -s test TESTOPTS="${TESTOPTS=$JOBS -q --tty=no}"

  - &gcc-8
    compiler: gcc-8
    # # Not using addon to control retries
    # addons:
    #   apt:
    #     sources:
    #       - ubuntu-toolchain-r-test
    before_install:
      - tool/travis_retry.sh sudo -E apt-add-repository -y "ppa:ubuntu-toolchain-r/test"
      - tool/travis_retry.sh sudo bash -c "rm -rf '${TRAVIS_ROOT}/var/lib/apt/lists/'* && exec apt-get update -yq"
      - |-
        ${BEFORE_INSTALL}
        tool/travis_retry.sh sudo -E apt-get $travis_apt_get_options install \
          ccache \
          gcc-8 \
          g++-8 \
          libffi-dev \
          libgdbm-dev \
          libgmp-dev \
          libjemalloc-dev \
          libncurses5-dev \
          libncursesw5-dev \
          libreadline6-dev \
          libssl-dev \
          libyaml-dev \
          openssl \
          valgrind \
          zlib1g-dev

  - &clang-8
    compiler: clang-8
    addons:
      apt:
        # Not doing this manually unlike other sources, because it has been stable.
        sources:
          - llvm-toolchain-xenial-8
        config:
          retries: true
    before_install:
      - tool/travis_retry.sh sudo bash -c "rm -rf '${TRAVIS_ROOT}/var/lib/apt/lists/'* && exec apt-get update -yq"
      - |-
        tool/travis_retry.sh sudo -E apt-get $travis_apt_get_options install \
          clang-8 \
          llvm-8-tools \
          libffi-dev \
          libgdbm-dev \
          libgmp-dev \
          libjemalloc-dev \
          libncurses5-dev \
          libncursesw5-dev \
          libreadline6-dev \
          libssl-dev \
          libyaml-dev \
          openssl \
          valgrind \
          zlib1g-dev

  # --------

  - &x86_64-linux
    name: x86_64-linux
    <<: *gcc-8

  - &arm64-linux
    name: arm64-linux
    arch: arm64
    <<: *gcc-8

  - &jemalloc
    name: --with-jemalloc
    <<: *gcc-8
    <<: *cron-only
    env:
      - CONFIG_FLAG='--with-gmp --with-jemalloc --with-valgrind'

  - &assertions
    name: RUBY_DEBUG=1
    <<: *gcc-8
    #<<: *cron-only
    <<: *make-test-only
    env:
      - GEMS_FOR_TEST=
      - cppflags='-DRUBY_DEBUG -DVM_CHECK_MODE=1 -DTRANSIENT_HEAP_CHECK_MODE -DRGENGC_CHECK_MODE -DENC_DEBUG'

  - &VM_CHECK_MODE
    name: VM_CHECK_MODE=3
    <<: *gcc-8
    <<: *cron-only
    <<: *make-test-only
    env:
      - GEMS_FOR_TEST=
      - cppflags=-DVM_CHECK_MODE=0x0003

  - &SUPPORT_JOKE
    name: SUPPORT_JOKE
    <<: *gcc-8
    <<: *cron-only
    <<: *make-test-only
    env:
      - BEFORE_INSTALL="sed vm_opts.h -e 's/OPT_SUPPORT_JOKE *0/OPT_SUPPORT_JOKE 1/' -i"

  - &CPDEBUG
    name: CPDEBUG
    <<: *gcc-8
    <<: *cron-only
    <<: *make-test-only
    env:
      - cppflags=-DCPDEBUG

  - &WITH_COROUTINE_UCONTEXT
    name: COROUTINE=ucontext
    <<: *gcc-8
    <<: *cron-only
    env:
      - CONFIG_FLAG='--with-coroutine=ucontext'

  - &WITH_COROUTINE_COPY
    name: COROUTINE=copy
    <<: *gcc-8
    <<: *cron-only
    env:
      - CONFIG_FLAG='--with-coroutine=copy'

  - &TOKEN_THREADED_CODE
    name: TOKEN_THREADED_CODE
    <<: *gcc-8
    <<: *cron-only
    <<: *make-test-only
    env:
      - GEMS_FOR_TEST=
      - cppflags=-DOPT_THREADED_CODE=1

  - &CALL_THREADED_CODE
    name: CALL_THREADED_CODE
    <<: *gcc-8
    <<: *cron-only
    <<: *make-test-only
    env:
      - GEMS_FOR_TEST=
      - cppflags=-DOPT_THREADED_CODE=2

  - &NO_THREADED_CODE
    name: NO_THREADED_CODE
    <<: *gcc-8
    <<: *cron-only
    <<: *make-test-only
    env:
      - GEMS_FOR_TEST=
      - cppflags=-DOPT_THREADED_CODE=3

  - &ASAN
    name: -fsanitize=address
    <<: *clang-8
    #<<: *cron-only
    <<: *make-test-only
    env:
      - GEMS_FOR_TEST=
      - ASAN_OPTIONS=detect_leaks=0
      - cflags='-U_FORTIFY_SOURCE -march=native -fsanitize=address -fno-omit-frame-pointer -fPIC'
      - debugflags=-ggdb3
      - optflags=-O1
      - LD=clang-8
      - LDFLAGS='-fsanitize=address -fPIC'
      - CONFIG_FLAG='--with-out-ext=openssl --without-gmp --without-jemalloc --without-valgrind'

  - &MSAN
    name: -fsanitize=memory
    <<: *clang-8
    #<<: *cron-only
    <<: *make-test-only
    env:
      - GEMS_FOR_TEST=
      - cflags='-U_FORTIFY_SOURCE -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -fPIC'
      - optflags=-O1
      - LD=clang-8
      - LDFLAGS='-fsanitize=memory -fPIC'
      - CONFIG_FLAG='--with-out-ext=openssl --without-gmp --without-jemalloc --without-valgrind'

  - &UBSAN
    name: -fsanitize=undefined
    <<: *clang-8
    #<<: *cron-only
    <<: *make-test-only
    env:
      - GEMS_FOR_TEST=
      - cflags='-U_FORTIFY_SOURCE -fsanitize=undefined,integer,nullability -fno-sanitize=implicit-integer-sign-change,unsigned-integer-overflow'
      - cppflags=-DUNALIGNED_WORD_ACCESS=0
      - debugflags=-ggdb3
      - optflags='-O1 -march=native'
      - LD=clang-8
      - LDFLAGS='-fsanitize=undefined,integer,nullability -fno-sanitize=implicit-integer-sign-change,unsigned-integer-overflow'

  - &i686-linux
    name: i686-linux
    compiler: gcc-8
    env:
      - GCC_FLAGS=-m32
      - CXX='g++-8 -m32'
      - debugflags=-g0
      - SETARCH='setarch i686 --verbose --3gb'
    # # Not using addon to control retries
    # addons:
    #   apt:
    #     sources:
    #       - ubuntu-toolchain-r-test
    before_install:
      - tool/travis_retry.sh sudo -E apt-add-repository -y "ppa:ubuntu-toolchain-r/test"
      - tool/travis_retry.sh sudo bash -c "rm -rf '${TRAVIS_ROOT}/var/lib/apt/lists/'* && exec apt-get update -yq"
      - |-
        tool/travis_retry.sh sudo -E apt-get $travis_apt_get_options install \
          gcc-8-multilib \
          g++-8 \
          g++-8-multilib \
          libstdc++-8-dev:i386 \
          libffi-dev:i386 \
          libffi6:i386 \
          libgdbm-dev:i386 \
          libgdbm3:i386 \
          libncurses5-dev:i386 \
          libncurses5:i386 \
          libncursesw5-dev:i386 \
          libreadline6-dev:i386 \
          libreadline6:i386 \
          libssl-dev:i386 \
          libssl1.0.0:i386 \
          linux-libc-dev:i386 \
          zlib1g-dev:i386 \
          zlib1g:i386

  - &pedanticism
    name: -std=c99 -pedantic
    compiler: clang
    <<: *make-test-only
    env:
      - GEMS_FOR_TEST=
      - GCC_FLAGS='-std=c99 -Werror=pedantic -pedantic-errors'
      - CONFIG_FLAG=
      - JOBS=
      - >-
        warnflags='
        -Wall
        -Wextra
        -Werror=deprecated-declarations
        -Werror=division-by-zero
        -Werror=extra-tokens
        -Werror=implicit-function-declaration
        -Werror=implicit-int
        -Werror=pointer-arith
        -Werror=shorten-64-to-32
        -Werror=write-strings
        -Wmissing-noreturn
        -Wno-constant-logical-operand
        -Wno-missing-field-initializers
        -Wno-overlength-strings
        -Wno-parentheses-equality
        -Wno-self-assign
        -Wno-tautological-compare
        -Wno-unused-local-typedef
        -Wno-unused-parameter
        -Wunused-variable'
      - LDFLAGS=-Wno-unused-command-line-argument

  - &rubyspec
    name: Check ruby/spec version guards on Ruby 2.4
    language: ruby
    rvm: 2.4.6
    before_install:
    install:
    before_script: chmod -R u+w spec/ruby
    # -j randomly hangs.
    script: ruby -C spec/ruby ../mspec/bin/mspec .
    after_failure:
      - echo "ruby/spec failed on Ruby 2.4. This is likely because of a missing ruby_version_is guard, please add it. See spec/README.md."

  - &baseruby
    name: "BASERUBY: Ruby 2.2"
    <<: *gcc-8
    <<: *make-test-only
    language: ruby
    rvm: 2.2

  - &dependency
    name: Check dependencies in makefiles
    language: ruby
    before_install:
    install:
    before_script:
      - |-
        ruby -e 'new = []
          Dir.glob("ext/**/extconf.rb") {|ex|
            unless File.exist?(dep = File.dirname(ex)+"/depend")
              puts "Adding "+dep
              File.copy_stream("template/depend.tmpl", dep)
              new << dep
            end
          }
          exec("git", "add", *new) unless new.empty?'
      - git diff --cached
      - "> config.status"
      - "> .rbconfig.time"
      - sed -f tool/prereq.status template/Makefile.in common.mk > Makefile
      - make touch-unicode-files
      - make -s $JOBS $UPDATE_UNICODE up
      - make -s $JOBS srcs
      - rm -f config.status Makefile rbconfig.rb .rbconfig.time
      - $SETARCH ./configure -C --disable-install-doc --prefix=$RUBY_PREFIX --disable-rubygems 'optflags=-O0' 'debugflags=-save-temps=obj -g'
      - ruby tool/update-deps --fix
    script:
      - git diff --no-ext-diff --ignore-submodules --exit-code
    after_failure:
      - echo "Dependencies need to update"
    env:
      - CONFIG_FLAG=

matrix:
  include:
    # Build every commit:
    - <<: *x86_64-linux
    - <<: *i686-linux
    - <<: *pedanticism
    - <<: *assertions
    - <<: *baseruby
    - <<: *rubyspec
    - <<: *dependency
    # Build every commit (Allowed Failures):
    - <<: *arm64-linux
    - <<: *ASAN
    - <<: *MSAN
    - <<: *UBSAN
    # Cron only:
    - <<: *jemalloc
    - <<: *VM_CHECK_MODE
    - <<: *SUPPORT_JOKE
    - <<: *CPDEBUG
    - <<: *WITH_COROUTINE_UCONTEXT
    - <<: *WITH_COROUTINE_COPY
    - <<: *TOKEN_THREADED_CODE
    - <<: *CALL_THREADED_CODE
    - <<: *NO_THREADED_CODE
  allow_failures:
    - name: arm64-linux
    - name: -fsanitize=address
    - name: -fsanitize=memory
    - name: -fsanitize=undefined
  fast_finish: true

before_script:
  - date # Debugging "Permission defined" failure on darwin like https://travis-ci.org/ruby/ruby/jobs/508683759
  - echo JOBS=${JOBS} SETARCH=${SETARCH}
  - $SETARCH uname -a
  - $SETARCH uname -r
  - rm -fr .ext autom4te.cache
  - echo $TERM
  - |-
    [ -d ~/.downloaded-cache ] ||
    mkdir ~/.downloaded-cache
  - ln -s ~/.downloaded-cache
  - "> config.status"
  - "> .rbconfig.time"
  - sed -f tool/prereq.status template/Makefile.in common.mk > Makefile
  - date; make touch-unicode-files
  - date; make -s $JOBS $UPDATE_UNICODE up
  - date; make -s $JOBS srcs
  - rm -f config.status Makefile rbconfig.rb .rbconfig.time
  - |-
    if [ -d ~/config_2nd ]; then
      cp -pr ~/config_2nd build
    else
      mkdir build
    fi
  - mkdir config_1st config_2nd
  - chmod -R a-w .
  - chmod -R u+w build config_1st config_2nd
  - cd build
  - ccache --show-stats
  - |-
    case "$CC" in
    gcc*)   CC="ccache $CC${GCC_FLAGS:+ }$GCC_FLAGS -fno-diagnostics-color";;
    clang*) CC="ccache $CC${GCC_FLAGS:+ }$GCC_FLAGS -fno-color-diagnostics";;
    esac
  - |-
    [ ! -f config.cache ] ||
    [ "$CC" = "`sed -n s/^ac_cv_prog_CC=//p config.cache`" ] ||
    (set -x; exec rm config.cache)
  - $SETARCH ../configure -C --disable-install-doc --prefix=$RUBY_PREFIX $CONFIG_FLAG
  - cp -pr config.cache config.status .ext/include ../config_1st
  - $SETARCH make reconfig
  - cp -pr config.cache config.status .ext/include ../config_2nd
  - (cd .. && exec diff -ru config_1st config_2nd)
  - chmod u+w ..
  - rm -rf ~/config_2nd
  - mv ../config_2nd ~
  - chmod u-w ..
  - $SETARCH make -s $JOBS
  - |-
    date; : # Debugging "Permission defined" failure on darwin like https://travis-ci.org/ruby/ruby/jobs/508683759
    if ! make install; then
      if [ "$(uname)" = Darwin ]; then
        # Debugging "Permission defined" failure on darwin like https://travis-ci.org/ruby/ruby/jobs/508683759
        set -x
        date
        ./miniruby -e 'ARGV.map{|path|[path,File.stat(path)]}.sort_by{|path,st|st.mtime}.each{|path,st|p mtime:st.mtime.to_f, ctime:st.ctime.to_f, path:path}' .ext/.timestamp/.RUBYCOMMONDIR*time .ext/common/bigdecimal/*.rb ../ext/bigdecimal/lib/bigdecimal/*.rb . .. .ext .ext/common .ext/common/bigdecimal ext/bigdecimal ../ext ../ext/bigdecimal ../ext/bigdecimal/lib ../ext/bigdecimal/lib/bigdecimal
        make COPY='cp -f' install
      else
        exit 1
      fi
    fi
  - ccache --show-stats
  - |-
    [ -z "${GEMS_FOR_TEST}" ] ||
    $RUBY_PREFIX/bin/gem install --no-document $GEMS_FOR_TEST
  - echo "raise 'do not load ~/.irbrc in test'" > ~/.irbrc

script:
  - $SETARCH make -s test -o showflags TESTOPTS="${TESTOPTS=$JOBS -q --tty=no}"
  - travis_wait 50 $SETARCH make -s test-all -o exts TESTOPTS="${TESTOPTS} ${TEST_ALL_OPTS}" RUBYOPT="-w"
  - $SETARCH make -s test-spec MSPECOPT=-ff # not using `-j` because sometimes `mspec -j` silently dies
  - $SETARCH make -s -o showflags leaked-globals

# Branch matrix.  Not all branches are Travis-ready so we limit branches here.
branches:
  only:
    - master
    - ruby_2_4
    - ruby_2_5
    - ruby_2_6

# We want to be notified when something happens.
notifications:
  irc:
    channels:
      - "chat.freenode.net#ruby-core"
    on_success: change # [always|never|change] # default: always
    on_failure: always # [always|never|change] # default: always
    template:
      - "%{message} by @%{author}: See %{build_url}"

  slack:
    rooms:
      - secure: ah7UEHBvncXT7bM5mvYIQAO+tIyV/wl7nXLb7wQD16dO2v8Gragy0mWjB79Q09hrrMGmp6H9bCDpdGS80boIA5EHaHoG4QaP0i9bsSt8U2AMWgZtfyIgQKJ4H2kXkGlrjO+AXTgnIkP7LNjdgAVUUTGQPb26T3QmoN2Splt+fIQ= # ruby:<token>#alerts
    on_pull_requests: false
    on_success: change
    on_failure: always

  email:
    - ko1c-failure@atdot.net