File yast-ci-ruby of Package ci-ruby-container

#! /bin/bash

# This is a CI build script, it is designed for the YaST packages written in Ruby.

# exit on error immediately
set -e

# all known steps in this script
ALL_STEPS="pot, rubocop, spelling, yardoc, build, tests, package, perl_syntax"

# when adding a new step
# 1) add it to $ALL_STEPS
# 2) handle it in disable_all(), set_defaults(), exclude(), run_only()
#    and dump_settings()
# 3) run it in the "main" part

function usage() {
  echo "Usage: $0 [OPTIONS]"
  echo
  echo "OPTIONS:"
  echo -e "\\t -x <step> \\t exclude the specified step"
  echo -e "\\t -o <step> \\t run only the specified step"
  echo -e "\\t -y        \\t run \"rake check:doc\" (more strict) in the \"yardoc\" step"
  echo -e "\\t -d        \\t enable debug mode"
  echo -e "\\t -h        \\t print this help"
  echo
  echo "The known steps are: $ALL_STEPS"
  echo
  echo "The script analyzes the configuration files and runs the checks accordingly."
  echo "You can manually override the autodection using the -x or -o option."
  echo
  echo "Options -x and -o are exclusive and cannot be used together,"
  echo "but they can be used repeatedly to specify several steps."
}

# disable all steps
function disable_all() {
  # run this only once
  if [ "$DISABLE_ALL" != "1" ]; then
    RUN_CHECK_POT=0
    RUN_RUBOCOP=0
    RUN_CHECK_SPELLING=0
    RUN_CHECK_YARDOC=0
    RUN_BUILD=0
    RUN_TESTS=0
    RUN_BUILD_PACKAGE=0
    RUN_CHECK_PERL=0

    DISABLE_ALL=1
  fi
}

# set defaults, run everything possible
function set_defaults() {
  RUN_CHECK_POT=1

  if [ -e .rubocop.yml ]; then
    RUN_RUBOCOP=1
  else
    RUN_RUBOCOP=0
  fi;

  if [ -e .spell.yml ]; then
    RUN_CHECK_SPELLING=1
  else
    RUN_CHECK_SPELLING=0
  fi

  # run yardoc when there is at least one Ruby file
  if [ -n "$(find . -name '*.rb' -print -quit)" ]; then
    RUN_CHECK_YARDOC=1
  else
    RUN_CHECK_YARDOC=0
  fi

  # run the perl syntax check by default when there is at least one Perl file
  if [ -n "$(find . -type f -name '*.p[ml]' -print -quit)" ]; then
    RUN_CHECK_PERL=1
  else
    RUN_CHECK_PERL=0
  fi

  # we need to build only the autotools based packages
  if [ -e Makefile.cvs ]; then
    RUN_BUILD=1
  else
    RUN_BUILD=0
  fi

  RUN_TESTS=1
  RUN_BUILD_PACKAGE=1
}

function exclude() {
  if [ "$RUN_ONLY_USED" == "1" ]; then
    echo "ERROR: Options -x -o are exclusive and cannot be used together!"
    exit 1
  fi

  case $1 in
    pot)
      RUN_CHECK_POT=0
      ;;
    rubocop)
      RUN_RUBOCOP=0
      ;;
    spelling)
      RUN_CHECK_SPELLING=0
      ;;
    yardoc)
      RUN_CHECK_YARDOC=0
      ;;
    build)
      RUN_BUILD=0
      ;;
    tests)
      RUN_TESTS=0
      ;;
    package)
      RUN_BUILD_PACKAGE=0
      ;;
    perl_syntax)
      RUN_CHECK_PERL=0
      ;;
    *)
      echo "ERROR: Unknown step: '$1'"
      echo "Known steps: $ALL_STEPS"
      exit 1
  esac
  EXCLUDE_USED=1
}

function run_only() {
  if [ "$EXCLUDE_USED" == "1" ]; then
    echo "ERROR: Options -x -o are exclusive and cannot be used together!"
    exit 1
  fi

  # disable the other steps
  disable_all

  case $1 in
    pot)
      RUN_CHECK_POT=1
      ;;
    rubocop)
      RUN_RUBOCOP=1
      ;;
    spelling)
      RUN_CHECK_SPELLING=1
      ;;
    yardoc)
      RUN_CHECK_YARDOC=1
      ;;
    build)
      RUN_BUILD=1
      ;;
    tests)
      RUN_TESTS=1
      ;;
    package)
      RUN_BUILD_PACKAGE=1
      ;;
    perl_syntax)
      RUN_CHECK_PERL=1
      ;;
    *)
      echo "ERROR: Unknown step: '$1'"
      echo "Known steps: $ALL_STEPS"
      exit 1
  esac
  RUN_ONLY_USED=1
}

function dump_settings() {
  echo "Script configuration:"
  echo "RUN_CHECK_POT: $RUN_CHECK_POT"
  echo "RUN_RUBOCOP: $RUN_RUBOCOP"
  echo "RUN_CHECK_SPELLING: $RUN_CHECK_SPELLING"
  echo "RUN_CHECK_YARDOC: $RUN_CHECK_YARDOC"
  echo "RUN_CHECK_PERL: $RUN_CHECK_PERL"
  echo "RUN_BUILD: $RUN_BUILD"
  echo "RUN_TESTS: $RUN_TESTS"
  echo "RUN_BUILD_PACKAGE: $RUN_BUILD_PACKAGE"
  echo
}

function set_rubocop_version() {
  # here we need to set path exactly as update-alternatives needs, so find proper path from its output
  RUBOCOP_PATH=$(update-alternatives --display rubocop | sed "/^[^[:space:]]\+$1"'/!d;s/^\([^[:space:]]\+\).*$/\1/')
  update-alternatives --set rubocop "$RUBOCOP_PATH"
}

# run parallel rubocop if it is available,
# otherwise fallback to standard rubocop call
function run_rubocop() {
  # set rubocop according to version that project use
  if grep 'rubocop-0.71.0' .rubocop.yml; then
    set_rubocop_version 0.71.0
  else
    set_rubocop_version 0.41.2
  fi
  if rake -T | grep -q "^rake check:rubocop"; then
    rake check:rubocop
  else
    rubocop
  fi
}

# check the syntax of the perl files
function check_perl() {
  # Perl allows checking the syntax only for one file at once, we need to use -n1
  # xargs option, to speed it up run the checks in parallel (-P option).
  # If you need to specify an additional search path use the PERL5LIB environment variable.
  find . -type f -name '*.p[ml]' -print0 \
    | xargs -0 -P"$(nproc)" -n1 perl -I src/modules -I /usr/share/YaST2/modules -w -c
}

# initializa the defaults and parse the command line options

set_defaults

while getopts ":x:o:dhy" arg; do
  case $arg in
    x)
      exclude "$OPTARG"
      ;;
    o)
      run_only "$OPTARG"
      ;;
    h)
      usage
      exit 0
      ;;
    d)
      DEBUG=1
      ;;
    y)
      USE_RAKE_CHECK_YARDOC=1
      ;;
    *)
      usage
      exit 1
      ;;
  esac
done

# start the main script

# enable debug
if [ "$DEBUG" == "1" ]; then
  dump_settings
  set -x
fi

[ "$RUN_CHECK_POT" == "1" ] && rake check:pot

# if rubocop is not used then rake package later runs a syntax check at least
[ "$RUN_RUBOCOP" == "1" ] && run_rubocop

# run syntax check for the perl files
[ "$RUN_CHECK_PERL" == "1" ] && check_perl

[ "$RUN_CHECK_SPELLING" == "1" ] && rake check:spelling

if [ "$RUN_CHECK_YARDOC" == "1" ]; then
  if [ "$USE_RAKE_CHECK_YARDOC" == "1" ]; then
    rake check:doc
  else
    yardoc
  fi
fi

# autotools based package
if [ -e Makefile.cvs ]; then
  if [ "$RUN_BUILD" == "1" ]; then
    make -f Makefile.cvs
    make -s
    make -s install
  fi

  [ "$RUN_TESTS" == "1" ] && make -s check VERBOSE=1 Y2DIR="$(pwd)"
fi

# enable coverage reports
[ "$RUN_TESTS" == "1" ] && COVERAGE=1 CI=1 rake test:unit

# the rest is a package build if it is disabled then just finish now
[ "$RUN_BUILD_PACKAGE" == "0" ] && exit 0

# ensure the files are owned by the current (root) user,
# git would fail if the owner is different like when running in GitHub Actions
# ("git clone" is called in a VM as a non-root user, but when running an action
# in a Docker container it runs as root which is the Docker default)
# https://github.blog/2022-04-18-highlights-from-git-2-36/
# https://github.blog/2022-04-12-git-security-vulnerability-announced/
if [ "$UID" == "0" ]; then
  chown -R -c 0 .
fi

# run package with all its checks, but be silent as possible. STDOUT is sent to dev null due to output of tar command
rake --silent package > /dev/null

if [ -d package ]; then
  # run the osc source validator to check the .spec and .changes locally
  (cd package && /usr/lib/obs/service/source_validator)
fi

# support RPM building for both root and non-root
if [ "$UID" == "0" ]; then
  PKG_DIR=/usr/src/packages
else
  PKG_DIR=~/rpmbuild
fi

mkdir -p $PKG_DIR/SOURCES/
cp package/* $PKG_DIR/SOURCES/

# Build the binary package, skip the %check section,
# the tests have been already executed outside RPM build.
# If it fails try to build the package with ignored deps, maybe it can work anyway...
# (e.g. yast2-packager requires yast2_theme which is not needed in simple rpmbuild)
rpmbuild -bb --nocheck package/*.spec || rpmbuild -bb --nocheck --nodeps package/*.spec

# test the %pre/%post scripts by installing/updating/removing the built packages
# ignore the dependencies to make the test easier, as a smoke test it's good enough
rpm -iv --force --nodeps $PKG_DIR/RPMS/*/*.rpm
rpm -Uv --force --nodeps $PKG_DIR/RPMS/*/*.rpm
# get the plain package names and remove all packages at once
mapfile -t packages < <(rpm -q --qf '%{NAME}\n' -p $PKG_DIR/RPMS/*/*.rpm)
rpm -ev --nodeps "${packages[@]}"
openSUSE Build Service is sponsored by