dist: xenial
language: c

# Build only master and stable branches.  Other branches go through PRs.
branches:
  only:
    - master
    - 3.5

addons:
  apt:
    packages: &BASE_PACKAGES
      # Build dependencies.
      # See also `apt-cache showsrc awesome | grep -E '^(Version|Build-Depends)'`.
      - libnotify-bin
      - libcairo2-dev
      - gir1.2-gtk-3.0
      - libpango1.0-dev
      - libxcb-xtest0-dev
      - libxcb-icccm4-dev
      - libxcb-randr0-dev
      - libxcb-keysyms1-dev
      - libxcb-xinerama0-dev
      - libdbus-1-dev
      - libxdg-basedir-dev
      - libstartup-notification0-dev
      - imagemagick
      - libxcb1-dev
      - libxcb-shape0-dev
      - libxcb-util0-dev
      - libx11-xcb-dev
      - libxcb-cursor-dev
      - libxcb-xkb-dev
      - libxcb-xfixes0-dev
      - libxkbcommon-dev
      - libxkbcommon-x11-dev
      # Deps for tests.
      - dbus-x11
      - xterm
      - xdotool
      - wmctrl
      - xterm
      - xvfb
      - zsh
      - x11-apps
      # Need xorg-macros
      - xutils-dev
      # lgi.
      - gir1.2-pango-1.0
      - libgirepository1.0-dev

jobs:
  include:
    - env: LUA=5.2 LUANAME=lua5.2 DO_COVERAGE=coveralls MANUAL_SCREENS=1
      addons:
        apt:
          packages:
            - *BASE_PACKAGES
            - liblua5.2-dev
            - lua5.2
    - env: LUA=5.3 LUANAME=lua5.3 DO_COVERAGE=codecov MANUAL_SCREENS=1
      addons:
        apt:
          packages:
            - *BASE_PACKAGES
            - liblua5.3-dev
            - lua5.3
    - env: LUA=5.1 LUANAME=lua5.1 BUILD_IN_DIR=/tmp/awesome-build WITH_XCB_ERRORS=yes
      addons:
        apt:
          packages:
            - *BASE_PACKAGES
            - liblua5.1-dev
            - lua5.1
            # For xcb-errors
            - xcb-proto
    - env: LUA=5.1 LUANAME=luajit-2.0 LUALIBRARY=/usr/lib/x86_64-linux-gnu/libluajit-5.1.so LUAROCKS_ARGS=--lua-suffix=jit-2.0.4
      addons:
        apt:
          packages:
            - *BASE_PACKAGES
            - libluajit-5.1-dev
            - luajit
    # Lua 5.2 with older lgi and screen size not divisible by 2.
    # SOURCE_DATE_EPOCH: used for stable dates during build.
    - env: LUA=5.2 LUANAME=lua5.2 LGIVER=0.8.0 TESTS_SCREEN_SIZE=1921x1079 BUILD_APIDOC=true DO_CHECKQA=1 EMPTY_THEME_WHILE_LOADING=1 SOURCE_DATE_EPOCH=1893456000 TEST_PREV_COMMITS=1
      addons:
        apt:
          packages:
            - *BASE_PACKAGES
            - liblua5.2-dev
            - lua5.2
            - lua-discount

env:
  global:
    # Secure GH_APIDOC_TOKEN to push to awesomeWM/apidoc.
    - secure: "R/HYDclnws1I1+v9Yjt+RKa4CsFhbBT9tiwE3EfPhEj2KCYX4sFRMxuZvLf5sq0XWdrQaPhQ54fgAZGr3f054JKRXcTB0g9J6nhSHz9kIjPh446gafUhEeDQcZRwM/MeCWiwFIkiZm6smYoDFE9JTWu6quNV+lQ4kcVDOp2ibEc="

before_install:
  - if [ "$BUILD_APIDOC" = true ] && [ -n "$DO_COVERAGE" ]; then echo "BUILD_APIDOC and DO_COVERAGE are not meant to be used together." >&2; exit 1; fi
  - if [ -z $LUAINCLUDE ]; then LUAINCLUDE=/usr/include/${LUANAME}; fi
  - if [ -z $LUALIBRARY ]; then LUALIBRARY=/usr/lib/x86_64-linux-gnu/lib${LUANAME}.so; fi
  - cmake --version

install:
  - sudo gem install asciidoctor
  - |
    # Install xcb-util-xrm.
    set -e
    (git clone --depth 1 --recursive https://github.com/Airblader/xcb-util-xrm.git /tmp/xcb-util-xrm
     cd /tmp/xcb-util-xrm
     ./autogen.sh --prefix=/usr
     make && sudo make install)

  # Install xcb-errors if needed
  - |
    set -e
    if [[ "$WITH_XCB_ERRORS" == "yes" ]]; then
      git clone --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-errors.git /tmp/xcb-errors
      (cd /tmp/xcb-errors
       ./autogen.sh --prefix=/usr
       make && sudo make install)
    fi

  - |
    # Install Lua (per env).
    if [[ "$LUANAME" == "luajit-2.0" ]]; then
      # "Create" /usr/bin/lua if needed (Yup, this is a bad hack)
      if [ ! -e "/usr/bin/lua" ]; then sudo ln -s /usr/bin/luajit /usr/bin/lua; fi
    else
      # lua5.3 does not install /usr/bin/lua, but lua5.1/lua5.2 do.
      if [ ! -e "/usr/bin/lua" ]; then sudo ln -s /usr/bin/${LUANAME} /usr/bin/lua; fi
    fi
  - lua -v

  # Install luarocks (for the selected Lua version).
  - |
    travis_retry wget https://github.com/luarocks/luarocks/archive/v3.0.4.tar.gz
    tar xf v3.0.4.tar.gz -C /tmp
    (cd /tmp/luarocks-* \
      && ./configure --lua-version=$LUA --with-lua-include=${LUAINCLUDE} ${LUAROCKS_ARGS} \
      && make build \
      && sudo make install)

  - travis_retry sudo luarocks install lgi $LGIVER

  # Install busted for "make check-unit".
  - travis_retry sudo luarocks install busted
  # Install luacheck for "make check-qa".
  - if [ "$DO_CHECKQA" = 1 ]; then travis_retry sudo luarocks install luacheck; fi
  # Install depgraph for "make check-qa".
  - if [ "$DO_CHECKQA" = 1 ]; then travis_retry sudo luarocks install depgraph; fi

  # Install ldoc for building docs and check-ldoc-warnings.
  - |
    if [ "$BUILD_APIDOC" = "true" ] || [ "$DO_CHECKQA" = 1 ]; then
      travis_retry sudo luarocks install ldoc
    fi

  # Install dependencies for code coverage testing.
  - if [ -n "$DO_COVERAGE" ]; then sudo luarocks install cluacov; fi
  - if [ "$DO_COVERAGE" = "coveralls" ]; then sudo luarocks install luacov-coveralls; fi

  # Determine custom version.
  - export AWESOME_VERSION="${TRAVIS_BRANCH}-g$(git rev-parse --short HEAD)"
  - |
    if [ "$TRAVIS_PULL_REQUEST" != false ] && [ "$TEST_PREV_COMMITS" = 1 ]; then
      AWESOME_VERSION="${AWESOME_VERSION}-PR${TRAVIS_PULL_REQUEST}"
    elif [ "$TRAVIS_PULL_REQUEST" != false ]; then
      AWESOME_VERSION="v9999-PR${TRAVIS_PULL_REQUEST}";
    fi
  # function for codecov support
  - if [ "$DO_COVERAGE" = "codecov" ]; then travis_retry wget -O /tmp/codecov-bash https://codecov.io/bash; fi
  - |
    do_codecov() {
      echo "== do_codecov in $PWD: $*: build/luacov.stats.out: =="
      if [ "$DO_COVERAGE" = "codecov" ]; then
        test -f build/luacov.stats.out || { echo 'build/luacov.stats.out does not exist.'; return 1; }
        luacov || return 1
        travis_retry bash /tmp/codecov-bash -f build/luacov.report.out -X gcov -X coveragepy -F luacov -e LUANAME,LGIVER || return 1
        rm build/luacov.report.out build/luacov.stats.out
      fi
      return 0
    }
  - |
    do_codecov_gcov() {
      echo "== do_codecov_gcov in $PWD: $*: =="
      if [ "$DO_COVERAGE" = "codecov" ]; then
        # Report coverage for each .gcno file separately.
        # gcov will create .gcov files for the same source (e.g. for
        # globalconf.h from awesome.c.gcno and event.c.gcno).
        i=0
        set -x
        (
          cd build
          find -path "*/lgi-check.dir" -prune -o \( -name '*.gcno' -print \) | while read -r gcno; do
            gcov -pb "$gcno"

            mkdir gcov.$(( ++i ))
            mv *.gcov "gcov.$i"

            # Delete any files for /usr.
            # They are not relevant and might cause "Invalid path part" errors
            # with Code Climate.
            find "gcov.$i" -maxdepth 1 -type f -name '#usr#*.gcov' -delete
          done

          # Upload to Codecov.
          travis_retry bash /tmp/codecov-bash -X gcov -X coveragepy -F gcov -e LUANAME,LGIVER
        )
      fi
      return 0
    }

  # Functions for custom Travis folds.
  - |
    travis_fold_start() {
      travis_fold start "$1"
      travis_fold_current="$1"
    }
    travis_fold_end() {
      travis_fold end "$travis_fold_current"
    }
    travis_run_in_fold() {
      travis_fold_start "$1"
      shift
      "$@" || return 1
      travis_fold_end
      return 0
    }
script:
  - if [ "$MANUAL_SCREENS" != "1" ]; then export MANUAL_SCREENS=0; fi
  - export CMAKE_ARGS="-DLUA_LIBRARY=${LUALIBRARY} -D LUA_INCLUDE_DIR=${LUAINCLUDE} -D OVERRIDE_VERSION=$AWESOME_VERSION -D STRICT_TESTS=true -D DO_COVERAGE=$DO_COVERAGE -D TEST_MANUAL_SCREENS=$MANUAL_SCREENS -D CMAKE_C_FLAGS=-Werror"
  - |
    if [ "$EMPTY_THEME_WHILE_LOADING" = 1 ]; then
      # Break beautiful so that trying to access the theme before beautiful.init() causes an error
      sed -i -e 's/theme = {}/theme = setmetatable({}, { __index = function() error("May not access theme before beautiful.init()") end })/' lib/beautiful/init.lua \
        && grep -q 'May not access' lib/beautiful/init.lua
    fi
  - |
    set -e
    if [ -n "$BUILD_IN_DIR" ]; then
      # Explicitly remove the Makefile to not build from the src dir accidentally.
      rm Makefile
      SOURCE_DIRECTORY="$PWD"
      mkdir "$BUILD_IN_DIR"
      cd "$BUILD_IN_DIR"
      travis_run_in_fold "build_in_dir" cmake $CMAKE_ARGS "$SOURCE_DIRECTORY"
    fi
  - travis_run_in_fold "make" make
  - |
    if [ "$TRAVIS_TEST_RESULT" = 0 ]; then
      travis_run_in_fold "make.install" sudo env PATH=$PATH make install
      awesome --version
    fi
  # Run checks.
  - |
    if [ "$TRAVIS_TEST_RESULT" = 0 ]; then
      set -ex
      if [ -n "$DO_COVERAGE" ]; then
        travis_fold_start "DO_COVERAGE"

        # Run tests/examples explicitly.
        make check-examples || exit 1
        do_codecov samples

        make check-unit || exit 1
        do_codecov unittests
        make check-integration || exit 1
        do_codecov functionaltests
        make check-themes || exit 1
        do_codecov themes
        do_codecov_gcov c_code

        travis_fold_end
      else
        # TODO: does not run check-examples.  Should it?
        travis_run_in_fold "make.check-unit" make check-unit
        travis_run_in_fold "make.check-integration" make check-integration
        travis_run_in_fold "make.check-themes" make check-themes
      fi
      set +x
    fi
  # Run check-qa.
  - |
    if [ "$DO_CHECKQA" = 1 ]; then
      travis_run_in_fold "make.check-qa" make check-qa
    fi
  - |
    if [ "$TEST_PREV_COMMITS" = 1 ] && ! [ "$TRAVIS_PULL_REQUEST" = false ]; then
      set -e
      # Check each commit separately (to make git-bisect less annoying).
      # Fix Travis' commit range (https://github.com/travis-ci/travis-ci/issues/4596).
      commit_range="${TRAVIS_COMMIT_RANGE/.../..}"
      echo "Testing previous commits ($commit_range)"
      rev_list="$(git rev-list --bisect-all $commit_range)"
      echo "rev-list: $rev_list"
      commits="$(echo "$rev_list" | grep -v 'dist=0' | cut -d\  -f 1)"
      n="$(echo "$commits" | wc -l)"
      echo "Testing $n commits: $commits"
      i=0
      failed=
      for commit in $commits; do
        i=$((i+1))
        travis_fold_start "test_commit_${commit}_.$i.$n"
        echo "Testing commit $commit"
        git reset --hard # Some files are updated when compiling...
        git checkout "$commit"
        git --no-pager show --stat

        if ! make all check CMAKE_ARGS+="-D DO_COVERAGE=0"; then
          failed="$failed $commit"
        fi
        travis_fold_end
      done

      git checkout -qf FETCH_HEAD
      if [ -n "$failed" ]; then
        echo "Checks failed for these commits:"
        for c in $failed; do
          git log -1 --pretty="%h %s (%an, %ad)" "$c"
        done
        false
      fi
    fi

after_success:
  # Push updated API docs for relevant branches, e.g. non-PRs builds on master.
  - if [ "$BUILD_APIDOC" = "true" ]; then build-utils/travis-apidoc.sh; fi
  # Push code coverage information
  - |
    set -e
    if [ "$DO_COVERAGE" = "coveralls" ]; then
      test -f build/luacov.stats.out || { echo 'build/luacov.stats.out does not exist.'; return 1; }
      luacov-coveralls --verbose --merge
    fi