diff --git a/CI/create_version_badge.sh b/CI/create_version_badge.sh
new file mode 100644
index 0000000000000000000000000000000000000000..c01bf913073c80f7b838c1a8afe93aa0bcd77fed
--- /dev/null
+++ b/CI/create_version_badge.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+VERSION="$(git describe --tags $(git rev-list --tags --max-count=1))"
+COLOR="blue"
+BADGE_NAME="version"
+
+ls .
+./CI/update_badge.sh -b ${BADGE_NAME} -c ${COLOR} -s ${VERSION}
+
+exit 0
diff --git a/CI/run_pytest.sh b/CI/run_pytest.sh
new file mode 100644
index 0000000000000000000000000000000000000000..4ba24b11a0aa4de7a9f5aca5fe93a4101986d98d
--- /dev/null
+++ b/CI/run_pytest.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# run pytest for all modules
+python3 -m pytest test/ | tee test_results.out
+
+IS_FAILED=$?
+
+# exit 0 if no tests implemented
+RUN_NO_TESTS="$(grep -c 'no tests ran' test_results.out)"
+if [[ ${RUN_NO_TESTS} > 0 ]]; then
+    echo "no test available"
+    echo "incomplete" > status.txt
+    echo "no tests avail" > incomplete.txt
+    exit 0
+fi
+
+# extract if tests passed or not
+TEST_FAILED="$(grep -oP '(\d+\s{1}failed)' test_results.out)"
+TEST_FAILED="$(echo ${TEST_FAILED} | (grep -oP '\d*'))"
+TEST_PASSED="$(grep -oP '\d+\s{1}passed' test_results.out)"
+TEST_PASSED="$(echo ${TEST_PASSED} | (grep -oP '\d*'))"
+if [[ -z "$TEST_FAILED" ]]; then
+    TEST_FAILED=0
+fi
+let "TEST_PASSED=${TEST_PASSED}-${TEST_FAILED}"
+
+# calculate metrics
+let "SUM=${TEST_FAILED}+${TEST_PASSED}"
+let "TEST_PASSED_RATIO=${TEST_PASSED}*100/${SUM}"
+
+# report
+if [[ ${IS_FAILED} == 0 ]]; then
+    if [[ ${TEST_PASSED_RATIO} -lt 100 ]]; then
+        echo "only ${TEST_PASSED_RATIO}% passed"
+        echo "incomplete" > status.txt
+        echo "${TEST_PASSED_RATIO}%25 passed" > incomplete.txt
+        if [[ ${TEST_PASSED_RATIO} -lt ${FAILURE_THRESHOLD} ]]; then
+            echo -e "\033[1;31monly ${TEST_PASSED_RATIO}% passed!!\033[0m"
+            exit 1
+        fi
+    else
+        echo "passed"
+        echo "success" > status.txt
+    fi
+    exit 0
+else
+    echo "not passed"
+    exit 1
+fi
diff --git a/CI/run_pytest_coverage.sh b/CI/run_pytest_coverage.sh
new file mode 100644
index 0000000000000000000000000000000000000000..0f6d76494e7aefce9a415cdfd75cdc50ef6e49b4
--- /dev/null
+++ b/CI/run_pytest_coverage.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# run coverage twice, 1) for html deploy 2) for success evaluation
+python3 -m pytest --cov=${CODE_PATH} --cov-report html
+python3 -m pytest --cov=${CODE_PATH} --cov-report term | tee coverage_results.out
+
+IS_FAILED=$?
+
+# move html coverage report
+mkdir coverage/
+BRANCH_NAME=$( echo -e "${CI_COMMIT_REF_NAME////_}")
+mkdir coverage/${BRANCH_NAME}
+mkdir coverage/recent
+cp -r htmlcov/* coverage/${BRANCH_NAME}/.
+cp -r htmlcov/* coverage/recent/.
+if [[ "${CI_COMMIT_REF_NAME}" = "master" ]]; then
+    cp -r htmlcov/* coverage/.
+fi
+
+# extract coverage information
+COVERAGE_RATIO="$(grep -oP '\d+\%' coverage_results.out | tail -1)"
+COVERAGE_RATIO="$(echo ${COVERAGE_RATIO} | (grep -oP '\d*'))"
+
+# report
+if [[ ${IS_FAILED} == 0 ]]; then
+    if [[ ${COVERAGE_RATIO} -lt ${COVERAGE_PASS_THRESHOLD} ]]; then
+        echo "only ${COVERAGE_RATIO}% covered"
+        echo "incomplete" > status.txt
+        echo "${COVERAGE_RATIO}%25" > incomplete.txt
+        if [[ ${COVERAGE_RATIO} -lt ${FAILURE_THRESHOLD} ]]; then
+            echo -e "\033[1;31monly ${COVERAGE_RATIO}% covered!!\033[0m"
+            exit 1
+        fi
+    else
+        echo "passed"
+        echo "success" > status.txt
+        echo "${COVERAGE_RATIO}%25" > success.txt
+    fi
+    exit 0
+else
+    echo "not passed"
+    exit 1
+fi
diff --git a/CI/update_badge.sh b/CI/update_badge.sh
new file mode 100644
index 0000000000000000000000000000000000000000..c8b11015d27f509faeb4b26b5d88ec7df5a4e675
--- /dev/null
+++ b/CI/update_badge.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+# 'running', 'success' or 'failure' is in this file
+if [[ -e status.txt ]]; then
+  EXIT_STATUS=`cat status.txt`
+else
+  EXIT_STATUS="running"
+fi
+
+printf "%s\n" ${EXIT_STATUS}
+
+# fetch badge_status
+BADGE_STATUS="${CI_COMMIT_REF_NAME}:${CI_JOB_NAME}"
+# replace - with --
+BADGE_STATUS=$( echo -e "${BADGE_STATUS//\-/--}")
+
+
+# Set values for shields.io fields based on STATUS
+if [[ ${EXIT_STATUS} = "running" ]]; then
+	BADGE_SUBJECT="running"
+	BADGE_COLOR="lightgrey"
+elif [[ ${EXIT_STATUS} = "failure" ]]; then
+	BADGE_SUBJECT="failed"
+	BADGE_COLOR="red"
+elif [[ ${EXIT_STATUS} = "success" ]]; then
+	BADGE_SUBJECT="passed"
+	BADGE_COLOR="brightgreen"
+	if [[ -e success.txt ]]; then
+	    SUCCESS_MESSAGE=`cat success.txt`
+	    BADGE_SUBJECT="${SUCCESS_MESSAGE}"
+	fi
+elif [[ ${EXIT_STATUS} = "incomplete" ]]; then
+    EXIT_STATUS_MESSAGE=`cat incomplete.txt`
+    BADGE_SUBJECT="${EXIT_STATUS_MESSAGE}"
+    EXIT_STATUS_RATIO="$(echo ${EXIT_STATUS_MESSAGE} | (grep -oP '\d*') | head -1)"
+    printf "%s\n" ${EXIT_STATUS_RATIO}
+    if [[ "${EXIT_STATUS_RATIO}" -lt "${FAILURE_THRESHOLD}" ]]; then
+        BADGE_COLOR="red"
+    else
+        BADGE_COLOR="yellow"
+    fi
+else
+	exit 1
+fi
+
+# load additional options
+while getopts b:c:s: option
+do
+  case ${option} in
+    b) BADGE_STATUS=$( echo -e "${OPTARG//\-/--}");;
+    c) BADGE_COLOR=$( echo -e "${OPTARG//\-/--}");;
+    s) BADGE_SUBJECT=$( echo -e "${OPTARG//\-/--}");;
+  esac
+done
+
+
+# Set filename for the badge (i.e. 'ci-test-branch-job.svg')
+CI_COMMIT_REF_NAME_NO_SLASH="$( echo -e "${CI_COMMIT_REF_NAME}" | tr  '/' '_'  )"
+if [[ ${BADGE_STATUS} = "version" ]]; then
+    BADGE_FILENAME="badge_version.svg"
+else
+    BADGE_FILENAME="badge_${CI_COMMIT_REF_NAME_NO_SLASH}-${CI_JOB_NAME}.svg"
+fi
+RECENT_BADGE_FILENAME="badge_recent-${CI_JOB_NAME}.svg"
+
+# Get the badge from shields.io
+SHIELDS_IO_NAME=${BADGE_STATUS}-${BADGE_SUBJECT}-${BADGE_COLOR}.svg
+printf  "%s\n" "INFO: Fetching badge ${SHIELDS_IO_NAME} from shields.io to ${BADGE_FILENAME}."
+printf  "%s\n" "${SHIELDS_IO_NAME//\_/__}"
+printf  "%s\n" "${SHIELDS_IO_NAME//\#/%23}"
+
+SHIELDS_IO_NAME="$( echo -e "${SHIELDS_IO_NAME//\_/__}" )"
+SHIELDS_IO_NAME="$( echo -e "${SHIELDS_IO_NAME//\#/%23}")"
+curl "https://img.shields.io/badge/${SHIELDS_IO_NAME}" > ${BADGE_FILENAME}
+echo "https://img.shields.io/badge/${SHIELDS_IO_NAME}"
+SHIELDS_IO_NAME_RECENT="RECENT:${SHIELDS_IO_NAME}"
+curl "https://img.shields.io/badge/${SHIELDS_IO_NAME_RECENT}" > ${RECENT_BADGE_FILENAME}
+echo "${SHIELDS_IO_NAME_RECENT}" > testRecentName.txt
+
+#
+if [[ ! -d ./badges ]]; then
+  # Control will enter here if $DIRECTORY doesn't exist.
+  mkdir badges/
+fi
+mv ${BADGE_FILENAME} ./badges/.
+
+# replace outdated recent badge by new badge
+mv ${RECENT_BADGE_FILENAME} ./badges/${RECENT_BADGE_FILENAME}
+
+# set status to failed, this will be overwritten if job ended with exitcode 0
+echo "failed" > status.txt
+
+exit 0