diff options
Diffstat (limited to 'msci')
| -rwxr-xr-x[l---------] | msci | 228 |
1 files changed, 227 insertions, 1 deletions
@@ -1 +1,227 @@ -makeshiftci
\ No newline at end of file +#!/usr/bin/env bash + +set -e +shopt -s nullglob +mkdir -p "$MSCI_HOME"/projects \ + "$MSCI_HOME"/stdout/public \ + "$MSCI_HOME"/stdout/private \ + "$MSCI_HOME"/tmp +[ ! -f "$MSCI_HOME"/cron ] && touch "$MSCI_HOME"/cron + +confirm_in() { + read -rp "$1 (y/N): " confirm + [[ $confirm == [yY]* ]] && return 0 || return 1 +} + +find_project() { + if list_projects | grep -xFq -- "$1"; then + return 0 + fi + return 1 +} + +list_projects() { + paths=("$MSCI_HOME"/projects/*) + names=("${paths[@]##*/}") + projects=("${names[@]%.json}") + printf '%s\n' "${projects[@]}" +} + +write_cron() { + cfile="MSCI_HOME=$MSCI_HOME\n" + for project in $(list_projects); do + ppath="$MSCI_HOME"/projects/"$project".json + schedule=$(jq -r '.cron' "$ppath") + [ "$schedule" = 'null' ] && continue + cfile="${cfile}$schedule $MSCI_HOME/makeshiftci run $project\n" + done + echo -e "$cfile" >"$MSCI_HOME"/tmp.cron + if crontab "$MSCI_HOME"/tmp.cron; then + mv -fv "$MSCI_HOME"/tmp.cron "$MSCI_HOME"/cron + else + rm -fv "$MSCI_HOME"/tmp.cron + fi +} + +run_project() { + ppath="$MSCI_HOME"/projects/"$1".json + repo_name=$(jq -r '.name' "$ppath") + repo_url=$(jq -r '.url' "$ppath") + repo_path="$MSCI_HOME"/tmp/"$repo_name" + echo "cloning repo: $repo_url" | tee -a "$2" + git clone --quiet "$repo_url" "$repo_path" + pushd "$repo_path" >/dev/null || return 1 + for job in "$repo_path"/.makeshiftci/*; do + pname=$(jq -r '.name' "$job") + echo "running job: $pname" | tee -a "$2" + pimage=$(jq -r '.image' "$job") + psecrets=$(jq -r '.secrets' "$job") + prun=$(jq -r '.run[]' "$job") + env_secrets=() + secret_mounts=() + if [ ! "$psecrets" = 'null' ]; then + for secret_key in $(echo "$psecrets" | jq -r '. | keys[]'); do + secret_value=$(echo "$psecrets" | jq -r ".$secret_key") + secret_name=$(openssl rand -hex 16) + secret_mounts+=("--mount=type=bind,source=$secret_value,target=/$secret_name,readonly") + env_secrets+=("$secret_key=/$secret_name") + done + fi + docker run --rm \ + "${env_secrets[@]/#/--env=}" \ + --mount type=bind,source="$repo_path",target=/"$repo_name" \ + "${secret_mounts[@]}" \ + --workdir="/$repo_name" \ + "$pimage" \ + sh -c "exec $prun" | tee -a "$2" + done + popd >/dev/null && rm -rf "$repo_path" + echo "finished" | tee -a "$2" +} + +create_project() { + name="$1" + if find_project "$name"; then + echo "project file already exists" + return 1 + fi + read -rp "project name: " pname + read -rp ".makeshiftci repo URL: " purl + phidden=$(confirm_in "hidden?" && echo true || echo false) + read -rp "cron (optional): " pcron + jq -n \ + --arg pname "$pname" \ + --arg purl "$purl" \ + --argjson phidden "$phidden" \ + --arg pcron "$pcron" \ + '{ + name: $pname, + url: $purl, + hidden: $phidden, + cron: (if $pcron == "" then null else $pcron end) + }' \ + >"$MSCI_HOME"/projects/"$name".json + [ -n "$pcron" ] && write_cron + ([ "$phidden" = "true" ] && + mkdir -p "$MSCI_HOME"/stdout/private/"$1") || + mkdir -p "$MSCI_HOME"/stdout/public/"$1" +} + +edit_project() { + name="$1" + if ! find_project "$name"; then + echo "project file doesn't exist" + return 1 + fi + ppath="$MSCI_HOME"/projects/"$name".json + echo "editing $ppath" + oldname=$(jq -r '.name' "$ppath") + oldurl=$(jq -r '.url' "$ppath") + washidden=$(jq '.hidden' "$ppath") + keephidden=$([ "$washidden" = 'true' ] && echo "keep" || echo "make") + oldcron=$(jq -r '.cron' "$ppath") + echo "project name: $oldname" + read -rp "new name (optional): " pname + [ -z "$pname" ] && pname=$oldname + echo ".makeshiftci repo URL: $oldurl" + read -rp "new URL (optional): " purl + [ -z "$purl" ] && purl=$oldurl + echo "hidden: $washidden" + phidden=$(confirm_in "$keephidden hidden?" && echo true || echo false) + echo "cron: $oldcron" + read -rp "new cron (optional): " pcron + [ -z "$pcron" ] && pcron=$oldcron + jq -n \ + --arg pname "$pname" \ + --arg purl "$purl" \ + --argjson phidden "$phidden" \ + --arg pcron "$pcron" \ + '{ + name: $pname, + url: $purl, + hidden: $phidden, + cron: (if $pcron == "null" then null else $pcron end) + }' \ + >"$ppath" + [ ! "$pcron" = "$oldcron" ] && write_cron + privout="$MSCI_HOME"/stdout/private/"$1" + pubout="$MSCI_HOME"/stdout/public/"$1" + ( + [ "$phidden" = "true" ] && + ([ ! -d "$privout" ] && mv "$pubout" "$privout") + ) || + ([ ! -d "$pubout" ] && mv "$privout" "$pubout") +} + +case $1 in +create) + if [ -z "$2" ]; then + echo "no project file name is supplied" + exit 1 + fi + create_project "$2" + ;; +edit) + if [ -z "$2" ]; then + echo "no project file name is supplied" + exit 1 + fi + edit_project "$2" + ;; +delete) + if [ -z "$2" ]; then + echo "no project file name is supplied" + exit 1 + fi + if ! find_project "$2"; then + echo "project file doesn't exist" + exit 1 + fi + ppath="$MSCI_HOME"/projects/"$2".json + cat "$ppath" + confirm_in "delete '$2' (details above)?" && + rm -vf "$MSCI_HOME"/projects/"$2".json || + exit 0 + rm -rf "$MSCI_HOME"/stdout/**/"$2" + write_cron + ;; +run) + if [ -z "$2" ]; then + echo "no project file name is supplied" + exit 1 + fi + if ! find_project "$2"; then + echo "project file doesn't exist" + exit 1 + fi + ppath="$MSCI_HOME"/projects/"$2".json + phidden=$(jq -r '.hidden' "$ppath") + stdout_type=$([ "$phidden" = 'false' ] && echo "public" || echo "private") + stdout_path="$MSCI_HOME"/stdout/"$stdout_type"/"$2" + last_run=$( + find "$stdout_path" \ + -maxdepth 1 \ + -mindepth 1 \ + -type f -printf '%f\n' | + grep -E '^[0-9]+$' | + sort -n | + tail -n 1 + ) + next_run=$( + [ -z "$last_run" ] && + echo "1" || + echo $((last_run + 1)) + ) + stdout_path="$stdout_path"/"$next_run" + run_project "$2" "$stdout_path" + ;; +list) + list_projects + ;; +*) + echo "unknown option '$1'" + exit 1 + ;; +esac + +# vim: set filetype=bash: |
