#!/usr/bin/env bash ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ci.sh ## ## ## ## A poor man's continuous ## ## integration system ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## Information ## (don't touch unless you are me) ## NAME="ci.sh" DESCRIPTION="A poor man's continuous integration system" VERSION="0.1.1" AUTHOR="david@socialnerds.org" LICENSE="MIT" WEBSITE="https://git.socialnerds.org/david/scripts" CHANGELOG=("[2023-12-21][v0.1.1] More error handling" "[2023-12-20][v0.1.0] Initial version") ## ## Configuration ## EXECUTABLE="$(basename $0)" LIBRARIES="lib.sh" DEPENDENCIES="whoami tr head basename dirname readlink curl git cut nohup ps cat getent" REQUIRE_ROOT=0 [[ ! $HOME ]] && HOME=$(getent passwd "$USER" | cut -d: -f6) SCRIPTS_DIR="$HOME/ci-scripts" TEMP_DIR="/tmp/ci-repos" ## ## Functions ## # Print help information function print_help() { local i=20 printf "%s\n\n%s\n%b\n\n%s\n" \ "$DESCRIPTION" "Usage:" "$LIB_BOLD$EXECUTABLE $LIB_CLEAR" "Options:" printf " %-${i}s %b\n" \ "-s, --scripts " "Specify the scripts directory (default: $SCRIPTS_DIR)" \ "-c, --checks " "Enable ${LIB_UNDERLINE}healthchecks.io${LIB_CLEAR} integration" \ "-n, --ntfy " "Enable ${LIB_UNDERLINE}ntfy.sh${LIB_CLEAR} integration" \ "-h, --help" "Print help screen and exit" \ "-i, --info" "Print script information and exit" \ "-v, --verbose" "More verbose output" \ "-q, --quiet" "No output except errors (overrides -v)" } ## ## Preflight ## # Load BASH libraries SCRIPT_PATH=$(readlink -f "$0") SCRIPT_DIR=$(dirname "$SCRIPT_PATH") for LIBRARY in $LIBRARIES; do if [[ -r "$SCRIPT_DIR/$LIBRARY" ]]; then #echo "Loading library file [$SCRIPT_DIR/$LIBRARY]" source "$SCRIPT_DIR/$LIBRARY" else echo "Error: Cannot load library file [$SCRIPT_DIR/$LIBRARY]" exit 1 fi done # Check for root privileges if ! lib_amiroot && [[ $REQUIRE_ROOT -eq 1 ]]; then lib_print "!You need to have root privileges" exit 1 fi # Check for dependencies MISSING_COMMANDS=$(lib_missing_commands $DEPENDENCIES) if [[ -n "$MISSING_COMMANDS" ]]; then lib_print "!One or more commands missing [$MISSING_COMMANDS]" lib_print "Try installing them with your package manager" exit 1 fi ## ## Liftoff ## while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case "$1" in -n|--ntfy) CURRENT_OPTION="$1" shift if lib_is_url "$1"; then NTFY_URL="$1" else lib_print "!$CURRENT_OPTION expects a valid ntfy.sh URL [$1]" exit 1 fi ;; -c|--checks) CURRENT_OPTION="$1" shift if lib_is_url "$1"; then CHECKS_URL="$1" else lib_print "!$CURRENT_OPTION expects a valid healthchecks.io URL [$1]" exit 1 fi ;; -s|--scripts) shift if lib_is_absolute "$1"; then SCRIPTS_DIR="$1" else SCRIPTS_DIR="$(PWD)/$1" fi ;; -h|--help) H=1 ;; -i|--info) I=1 ;; -v|--verbose) V=1 ;; -q|--quiet) Q=1 ;; *) lib_print "!Unknown option [$1]" lib_print "Try --help or -h for available options" exit 1 ;; esac shift done if [[ "$1" == '--' ]]; then shift fi if [[ $I -eq 1 ]]; then lib_print_info exit 0 elif [[ $H -eq 1 ]]; then print_help exit 0 fi if [[ -z "$1" ]]; then print_help exit 0 else # Check if a valid Git URL is provided and extract parts if [[ "$1" =~ ^(git@|https:\/\/)([^\/:]+)[:\/]([^\/]+)\/([^\/]+)(\.git)$ ]]; then GIT_URL="$1" GIT_HOST="${BASH_REMATCH[2]}" GIT_USER="${BASH_REMATCH[3]}" GIT_REPO="${BASH_REMATCH[4]}" shift else lib_print "!Input does not seem to be a valid Git URL [$1]" exit 1 fi # Chech if the script file exists and is executable if [[ ! -x "$SCRIPTS_DIR/$GIT_HOST/$GIT_USER/$GIT_REPO.sh" ]]; then lib_print "!No CI script for this repository found [$GIT_HOST/$GIT_USER/$GIT_REPO]" exit 1 fi # Create parent directories if missing if [[ ! -d "$TEMP_DIR/$GIT_HOST/$GIT_USER" ]]; then mkdir -p "$TEMP_DIR/$GIT_HOST/$GIT_USER" fi # Check if repo already exists and if the previous job is still running if [[ -d "$TEMP_DIR/$GIT_HOST/$GIT_USER/$GIT_REPO" ]]; then if lib_is_running $(cat "$TEMP_DIR/$GIT_HOST/$GIT_USER/$GIT_REPO.pid" 2> /dev/null); then lib_print "!CI job is still running [$GIT_HOST/$GIT_USER/$GIT_REPO]" exit 1 else rm -rf "$TEMP_DIR/$GIT_HOST/$GIT_USER/$GIT_REPO" fi fi # Clone the repo and execute the CI script git clone --quiet "$GIT_URL" "$TEMP_DIR/$GIT_HOST/$GIT_USER/$GIT_REPO" cd "$TEMP_DIR/$GIT_HOST/$GIT_USER/$GIT_REPO" nohup "$SCRIPTS_DIR/$GIT_HOST/$GIT_USER/$GIT_REPO.sh" "$@" > "$TEMP_DIR/$GIT_HOST/$GIT_USER/$GIT_REPO.log" 2>&1 & echo $! > "$TEMP_DIR/$GIT_HOST/$GIT_USER/$GIT_REPO.pid" # Inform user of a successful job execution lib_print "CI job has been triggered [$GIT_HOST/$GIT_USER/$GIT_REPO]" lib_ntfy "$NTFY_URL" "CI job has been triggered [$GIT_HOST/$GIT_USER/$GIT_REPO]" lib_checks "$CHECKS_URL" "CI job has been triggered [$GIT_HOST/$GIT_USER/$GIT_REPO]" fi ## ## Here be dragons ## exit 0