diff options
-rwxr-xr-x | .github/workflows/check-shell.sh | 111 | ||||
-rw-r--r-- | .github/workflows/exception-list.txt | 4 | ||||
-rw-r--r-- | .github/workflows/functions.sh | 93 | ||||
-rw-r--r-- | .github/workflows/integration_test.yml | 23 | ||||
-rw-r--r-- | .github/workflows/script-list.txt | 38 | ||||
-rw-r--r-- | .github/workflows/shellcheck_test.yml | 54 |
6 files changed, 323 insertions, 0 deletions
diff --git a/.github/workflows/check-shell.sh b/.github/workflows/check-shell.sh new file mode 100755 index 00000000..76e95bb0 --- /dev/null +++ b/.github/workflows/check-shell.sh @@ -0,0 +1,111 @@ +#!/bin/bash + +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" + +. $SCRIPT_DIR/functions.sh + +git_base=$1 +git_head=$2 + +# ------------ # +# FILE PATHS # +# ------------ # + +# https://github.com/actions/runner/issues/342 +# get names of files from PR (excluding deleted files) +git diff --name-only --diff-filter=db "$git_base".."$git_head" > ../pr-changes.txt + +# Find modified shell scripts +list_of_changes=() +file_to_array "../pr-changes.txt" "list_of_changes" 0 +list_of_scripts=() +file_to_array "$SCRIPT_DIR/script-list.txt" "list_of_scripts" 1 + +# Create list of scripts for testing +list_of_changed_scripts=() +for file in "${list_of_changes[@]}"; do + is_it_script "$file" "${list_of_scripts[@]}" && list_of_changed_scripts+=("./${file}") && continue + check_extension "$file" && list_of_changed_scripts+=("./${file}") && continue + check_shebang "$file" && list_of_changed_scripts+=("./${file}") +done + +# Expose list_of_changed_scripts[*] for use inside GA workflow +echo "LIST_OF_SCRIPTS=${list_of_changed_scripts[*]}" >> "$GITHUB_ENV" + +# Get list of exceptions +list_of_exceptions=() +file_to_array "$SCRIPT_DIR/exception-list.txt" "list_of_exceptions" 1 +string_of_exceptions=$(join_by , "${list_of_exceptions[@]}") + +echo -e "\n" +echo ":::::::::::::::::::::" +echo -e "::: ${WHITE}Shellcheck CI${NOCOLOR} :::" +echo ":::::::::::::::::::::" +echo -e "\n" + +echo -e "${WHITE}Changed shell scripts:${NOCOLOR}" +echo "${list_of_changed_scripts[@]}" +echo -e "${WHITE}List of shellcheck exceptions:${NOCOLOR}" +echo "${string_of_exceptions}" +echo -e "\n" + +# ------------ # +# SHELLCHECK # +# ------------ # + +# sed part is to edit shellcheck output so csdiff/csgrep knows it is shellcheck output (--format=gcc) +shellcheck --format=gcc --exclude="${string_of_exceptions}" "${list_of_changed_scripts[@]}" 2> /dev/null | sed -e 's|$| <--[shellcheck]|' > ../pr-br-shellcheck.err + +# make destination branch +git checkout -q -b ci_br_dest "$git_base" + +shellcheck --format=gcc --exclude="${string_of_exceptions}" "${list_of_changed_scripts[@]}" 2> /dev/null | sed -e 's|$| <--[shellcheck]|' > ../dest-br-shellcheck.err + +# ------------ # +# VALIDATION # +# ------------ # + +exitstatus=0 +echo ":::::::::::::::::::::::::" +echo -e "::: ${WHITE}Validation Output${NOCOLOR} :::" +echo ":::::::::::::::::::::::::" +echo -e "\n" + + +# Check output for Fixes +csdiff --fixed "../dest-br-shellcheck.err" "../pr-br-shellcheck.err" > ../fixes.log + +# Expose number of solved issues for use inside GA workflow +no_fixes=$(grep -Eo "[0-9]*" < <(csgrep --mode=stat ../fixes.log)) +echo "NUMBER_OF_SOLVED_ISSUES=${no_fixes:-0}" >> "$GITHUB_ENV" + +if [ "$(cat ../fixes.log | wc -l)" -ne 0 ]; then + echo -e "${GREEN}Fixed bugs:${NOCOLOR}" + csgrep ../fixes.log + echo "---------------------" +else + echo -e "${YELLOW}No Fixes!${NOCOLOR}" + echo "---------------------" +fi +echo -e "\n" + + +# Check output for added bugs +csdiff --fixed "../pr-br-shellcheck.err" "../dest-br-shellcheck.err" > ../bugs.log + +# Expose number of added issues for use inside GA workflow +no_issues=$(grep -Eo "[0-9]*" < <(csgrep --mode=stat ../bugs.log)) +echo "NUMBER_OF_ADDED_ISSUES=${no_issues:-0}" >> "$GITHUB_ENV" + +if [ "$(cat ../bugs.log | wc -l)" -ne 0 ]; then + echo -e "${RED}Added bugs, NEED INSPECTION:${NOCOLOR}" + csgrep ../bugs.log + echo "---------------------" + exitstatus=1 +else + echo -e "${GREEN}No bugs added Yay!${NOCOLOR}" + echo "---------------------" + exitstatus=0 +fi + +exit $exitstatus diff --git a/.github/workflows/exception-list.txt b/.github/workflows/exception-list.txt new file mode 100644 index 00000000..5b093820 --- /dev/null +++ b/.github/workflows/exception-list.txt @@ -0,0 +1,4 @@ +# List of Shelcheck codes which should be excluded from ci output +# Avoid spaces in list since they are counted as comment +SC1090 # Ignore when shellcheck can't follow non-constant source e.g. ``. "${path}"`` +SC2148 # Ignore missing shebang diff --git a/.github/workflows/functions.sh b/.github/workflows/functions.sh new file mode 100644 index 00000000..d6128486 --- /dev/null +++ b/.github/workflows/functions.sh @@ -0,0 +1,93 @@ +# shellcheck shell=bash +# Function to check whether input param is on list of shell scripts +# $1 - <string> absolute path to file +# $@ - <array of strings> list of strings to compare with +# $? - return value - 0 when succes +is_it_script () { + [ $# -le 1 ] && return 1 + local file="$1" + shift + local scripts=("$@") + + [[ " ${scripts[*]} " =~ " ${file} " ]] && return 0 || return 2 +} + +# Function to check if given file has .sh extension +# https://stackoverflow.com/a/407229 +# $1 - <string> absolute path to file +# $? - return value - 0 when succes +check_extension () { + [ $# -le 0 ] && return 1 + local file="$1" + + [ "${file: -3}" == ".sh" ] && return 0 || return 2 +} + +# Function to check if given file contain shell shebang (bash or sh) +# https://unix.stackexchange.com/a/406939 +# $1 - <string> absolute path to file +# $? - return value - 0 when succes +check_shebang () { + [ $# -le 0 ] && return 1 + local file="$1" + + if IFS= read -r line < "./${file}" ; then + case $line in + "#!/bin/bash") return 0;; + "#!/bin/sh") return 0;; + *) return 1 + esac + fi +} + +# Function to prepare string from array of strings where first argument specify one character separator +# https://stackoverflow.com/a/17841619 +# $1 - <char> Character used to join elements of array +# $@ - <array of string> list of strings +# return value - string +join_by () { + local IFS="$1" + shift + echo "$*" +} + +# Function to get rid of comments represented by '#' +# $1 - file path +# $2 - name of variable where will be stored result array +# $3 - value 1|0 - does file content inline comments? +# $? - return value - 0 when succes +file_to_array () { + [ $# -le 2 ] && return 1 + local output=() + + [ "$3" -eq 0 ] && readarray output < <(grep -v "^#.*" "$1") # fetch array with lines from file while excluding '#' comments + [ "$3" -eq 1 ] && readarray output < <(cut -d ' ' -f 1 < <(grep -v "^#.*" "$1")) # fetch array with lines from file while excluding '#' comments + clean_array "$2" "${output[@]}" && return 0 +} + +# Function to get rid of spaces and new lines from array elements +# https://stackoverflow.com/a/9715377 +# https://stackoverflow.com/a/19347380 +# https://unix.stackexchange.com/a/225517 +# $1 - name of variable where will be stored result array +# $@ - source array +# $? - return value - 0 when succes +clean_array () { + [ $# -le 2 ] && return 1 + local output="$1" + shift + local input=("$@") + + for i in "${input[@]}"; do + eval $output+=\("${i//[$'\t\r\n ']}"\) + done +} + +# Color aliases use echo -e to use them +export NOCOLOR='\033[0m' +export RED='\033[0;31m' +export GREEN='\033[0;32m' +export ORANGE='\033[0;33m' +export BLUE='\033[0;34m' +export YELLOW='\033[1;33m' +export WHITE='\033[1;37m' diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml new file mode 100644 index 00000000..0975a35c --- /dev/null +++ b/.github/workflows/integration_test.yml @@ -0,0 +1,23 @@ +# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions +name: Integration test +on: + push: + branches: + - master + pull_request: + branches: + - master + - rhel*-branch + release: + types: [published, created] + +jobs: + buildCheck: + runs-on: ubuntu-20.04 + steps: + - name: Repository checkout + uses: actions/checkout@v2 + - name: Install dependencies + run: sudo apt update && sudo apt install -y libpopt-dev gettext + - name: Build & install + run: make all && make install DESTDIR=/tmp/initscripts diff --git a/.github/workflows/script-list.txt b/.github/workflows/script-list.txt new file mode 100644 index 00000000..053672df --- /dev/null +++ b/.github/workflows/script-list.txt @@ -0,0 +1,38 @@ +# Tracker of all shell scripts in this repository +# Every new script should be added in order to test it with ci +# Avoid spaces in list since they are counted as comment +etc/rc.d/init.d/functions +etc/rc.d/init.d/network +network-scripts/ifdown-bnep +network-scripts/ifdown-ippp +network-scripts/ifdown-post +network-scripts/ifdown-sit +network-scripts/ifup +network-scripts/ifup-bnep +network-scripts/ifup-eth +network-scripts/ifup-ipv6 +network-scripts/ifup-plusb +network-scripts/ifup-routes +network-scripts/ifup-tunnel +network-scripts/init.ipv6-global +network-scripts/network-functions-ipv6 +network-scripts/ifdown +network-scripts/ifdown-eth +network-scripts/ifdown-ipv6 +network-scripts/ifdown-routes +network-scripts/ifdown-tunnel +network-scripts/ifup-aliases +network-scripts/ifup-ctc +network-scripts/ifup-ippp +network-scripts/ifup-plip +network-scripts/ifup-post +network-scripts/ifup-sit +network-scripts/ifup-wireless +network-scripts/network-functions +usr/libexec/import-state +usr/libexec/loadmodules +usr/libexec/netconsole +usr/libexec/readonly-root +usr/sbin/service +.ci/check-shell.sh +.ci/functions.sh diff --git a/.github/workflows/shellcheck_test.yml b/.github/workflows/shellcheck_test.yml new file mode 100644 index 00000000..bc4a4fd6 --- /dev/null +++ b/.github/workflows/shellcheck_test.yml @@ -0,0 +1,54 @@ +# GA doc: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions +# github-script doc: https://github.com/marketplace/actions/github-script +name: Shellcheck test +on: + pull_request: + branches: + - master + - rhel*-branch + - new-feature-actions-PR-comments + +jobs: + shellCheck: + runs-on: ubuntu-20.04 + defaults: + run: + shell: bash + + steps: + - name: Install dependencies + run: sudo apt update && sudo apt-get install -y cmake help2man libboost-dev libboost-filesystem-dev libboost-program-options-dev libboost-python-dev libboost-regex-dev tree + + - name: Clone csdiff repository + run: cd ../ && git clone --depth=1 https://github.com/csutils/csdiff.git && cd - + + - name: Build and install csdiff + run: cd ../csdiff && sudo make && sudo make install && cd - + + - name: Repository checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + + - name: Run shell-check test + run: | + bash ./.github/workflows/check-shell.sh ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} + + # ! Disable Output, since there is a problem with permissions and GITHUB_TOKEN + # ! https://github.blog/changelog/2021-04-20-github-actions-control-permissions-for-github_token/ + # TODO: possible solution is to use probot framework to build github app/action + # TODO: Set labels based on env.NUMBER_OF_ADDED_ISSUES and env.NUMBER_OF_SOLVED_ISSUES + # - name: Output test results + # # Run this step even if previous failed + # if: always() + # uses: actions/github-script@v5 + # with: + # # Colored GH comments: https://stackoverflow.com/a/39413824 + # script: | + # github.rest.issues.createComment({ + # issue_number: context.issue.number, + # owner: context.repo.owner, + # repo: context.repo.repo, + # body: '```diff\n@@ Shellcheck test summary @@\n- added issues: ${{ env.NUMBER_OF_ADDED_ISSUES }}\n+ solved issues: ${{ env.NUMBER_OF_SOLVED_ISSUES }}\n\n# list of edited shell scripts:\n${{ env.LIST_OF_SCRIPTS }}\n```' + # }) |