Skip to content

Commit

Permalink
Merge pull request #1 from rtCamp/feat/CICD
Browse files Browse the repository at this point in the history
Add CI/CD
  • Loading branch information
Xieyt authored Oct 2, 2023
2 parents fbc060b + 10154c8 commit 439cb6c
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 0 deletions.
102 changes: 102 additions & 0 deletions .github/deploy/addon.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/bin/bash

__dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
source "$__dir/helper.sh"

APP_DIR="$GITHUB_WORKSPACE"

[[ -d "${APP_DIR:-}" ]] || emergency "$APP_DIR path doesn't exits. Aborting.."

setup_basic() {
info "Init and Validations."
hosts_file="$GITHUB_WORKSPACE/.github/hosts.yml"
REMOTE_USER=$(shyaml get-value "${GITHUB_BRANCH}.user" < "$hosts_file" || true)
REMOTE_HOST=$(shyaml get-value "${GITHUB_BRANCH}.hostname" < "$hosts_file" || true) REMOTE_PATH=$(shyaml get-value "${GITHUB_BRANCH}.deploy_path" < "$hosts_file" || true)
RELEASES_LIMIT=$(shyaml get-value "${GITHUB_BRANCH}.prev_releases_limit" < "$hosts_file" || true)

[[ "${REMOTE_HOST:-}" ]] || emergency "The variable ${CYAN} hostname ${ENDCOLOR} is missing in hosts.yml"
[[ "${REMOTE_USER:-}" ]] || emergency "The vairable ${CYAN} user ${ENDCOLOR} is missing in hosts.yml"
[[ "${REMOTE_PATH:-}" ]] || emergency "The variable ${CYAN} deploy_path ${ENDCOLOR} is missing in hosts.yml"

# remove leading slash
REMOTE_PATH="${REMOTE_PATH%/}"

setup_ssh

ssh-keyscan -H "$REMOTE_HOST" >>/etc/ssh/ssh_known_hosts 2>/dev/null

APP_PATH="${REMOTE_PATH}/app"
RELEASE_FOLDER_NAME="releases/$(date +'%d-%b-%Y--%H-%M')"
APP_REMOTE_RELEASE_PATH="${REMOTE_PATH}/app/${RELEASE_FOLDER_NAME}"

info "Everything looks good !"
}

handle_releases(){
# create folder
info "Deploy code to server."
cd ~/
mkdir -p "$RELEASE_FOLDER_NAME"
echo "::group::local rsync log."
rsync -avzhP "${APP_DIR}/" "${RELEASE_FOLDER_NAME}/"
echo "::endgroup::"
remote_execute "$REMOTE_PATH" "mkdir -p ${REMOTE_PATH}/app/releases"
echo "::group::remote rsync log."
rsync -avzhP "${RELEASE_FOLDER_NAME}" "$REMOTE_USER"@"$REMOTE_HOST":"$REMOTE_PATH/app/releases/"
echo "::endgroup::"
info "Deploy code to server."
}

handle_build_server(){
# building the app
info "App Build: Started"
remote_execute "$REMOTE_PATH" "ln -sfn $APP_REMOTE_RELEASE_PATH $REMOTE_PATH/builder"
echo "::group::Remote Build log."
remote_execute "$REMOTE_PATH" "docker compose up builder --no-log-prefix"
echo "::endgroup::"
BUILD_STANDALONE_STATUS="$?"

remote_execute "$REMOTE_PATH" "unlink $REMOTE_PATH/builder"

# check if build was successful
if [[ "$BUILD_STANDALONE_STATUS" -gt 0 ]]; then
error "App Build: Failed"
remote_execute "$REMOTE_PATH" "rm -rf $APP_REMOTE_RELEASE_PATH"
exit 1
else
info "App Build: Successful"
fi
}

handle_after_build(){
info "Symlink latest deployment."
remote_execute "$APP_PATH" "ln -sfn $RELEASE_FOLDER_NAME current"
info "Restarting server"
remote_execute "$REMOTE_PATH" 'docker compose restart server'
}

retain_releases(){
echo "::group::Cleanup Releases."
if [[ "${RELEASES_LIMIT:-}" ]]; then
info "Removing redundant previous releases"
info "Retain only -> $RELEASES_LIMIT releases"
list_of_releases=$(remote_execute "${APP_PATH}/releases" "ls -1t")
RELEASES_LIMIT=$(( "$RELEASES_LIMIT" + 1 ))
to_remove_dirs=$( tail +$RELEASES_LIMIT <<< "$list_of_releases" )

for dir in $to_remove_dirs; do
info "Removing dir -> $dir"
remote_execute "${APP_PATH}/releases" "rm -rf $dir"
done
fi
echo "::endgroup::"
}

function main() {
setup_basic
handle_releases
handle_build_server
handle_after_build
retain_releases
}
main
122 changes: 122 additions & 0 deletions .github/deploy/helper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env bash
# Exit on error. Append "|| true" if you expect an error.
set +x
# Exit on error inside any functions or subshells.
#set -o errtrace
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
set -o nounset
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
set -o pipefail
# Turn on traces, useful while debugging but commented out by default
# set -o xtrace

# Define the environment variables (and their defaults) that this script depends on
LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency
NO_COLOR="${NO_COLOR:-}" # true = disable color. otherwise autodetected

RED="\033[31m"
GREEN="\033[32m"
CYAN="\033[36m"
BLUE="\033[34m"
ENDCOLOR="\033[0m"

### Functions
##############################################################################

function __log () {
local log_level="${1}"
shift

# shellcheck disable=SC2034
local color_debug="\\x1b[35m"
# shellcheck disable=SC2034
local color_info="\\x1b[32m"
# shellcheck disable=SC2034
local color_notice="\\x1b[34m"
# shellcheck disable=SC2034
local color_warning="\\x1b[33m"
# shellcheck disable=SC2034
local color_error="\\x1b[31m"
# shellcheck disable=SC2034
local color_critical="\\x1b[1;31m"
# shellcheck disable=SC2034
local color_alert="\\x1b[1;37;41m"
# shellcheck disable=SC2034
local color_emergency="\\x1b[1;4;5;37;41m"

local colorvar="color_${log_level}"

local color="${!colorvar:-${color_error}}"
local color_reset="\\x1b[0m"

if [[ "${NO_COLOR:-}" = "true" ]] || { [[ "${TERM:-}" != "xterm"* ]] && [[ "${TERM:-}" != "screen"* ]]; } || [[ ! -t 2 ]]; then
if [[ "${NO_COLOR:-}" != "false" ]]; then
# Don't use colors on pipes or non-recognized terminals
color=""; color_reset=""
fi
fi

# all remaining arguments are to be printed
local log_line=""

while IFS=$'\n' read -r log_line; do
width=9
padding=$(( ($width - ${#log_level}) / 2 ))
echo -e "$(date -u +"%Y-%m-%d %H:%M:%S UTC") ${color}$(printf "[%${padding}s%s%${padding}s]" "" "${log_level}" "" )${color_reset} ${log_line}" 1>&2
done <<< "${@:-}"
}

function emergency () { __log emergency "${@}"; exit 1; }
function alert () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && __log alert "${@}"; true; }
function critical () { [[ "${LOG_LEVEL:-0}" -ge 2 ]] && __log critical "${@}"; true; }
function error () { [[ "${LOG_LEVEL:-0}" -ge 3 ]] && __log error "${@}"; true; }
function warn () { [[ "${LOG_LEVEL:-0}" -ge 4 ]] && __log warning "${@}"; true; }
function notice () { [[ "${LOG_LEVEL:-0}" -ge 5 ]] && __log notice "${@}"; true; }
function info () { [[ "${LOG_LEVEL:-0}" -ge 6 ]] && __log info "${@}"; true; }
function debug () { [[ "${LOG_LEVEL:-0}" -ge 7 ]] && __log debug "${@}"; true; }


function check_command_status () {
if [ "$?" -gt "$1" ]; then
emergency "$2"
else
info "$3"
fi
}

remote_execute() {

[[ "${REMOTE_USER}" ]] || emergency "REMOTE_USER not found."
[[ "${REMOTE_HOST}" ]] || emergency "REMOTE_USER not found."

# shellcheck disable=SC2116
path=$(echo "$1")
# shellcheck disable=SC2116
cmd=$(echo "$2")
ssh "${REMOTE_USER}"@"${REMOTE_HOST}" "cd $path && $cmd"
}

setup_ssh() {

# used for saving private key
SSH_DIR="$HOME/.ssh"
mkdir -p "$SSH_DIR"
chmod 700 "$SSH_DIR"

[[ "${SSH_PRIVATE_KEY:-}" ]] || emergency "SSH_PRIVATE_KEY is not set."

if [[ -n "$SSH_PRIVATE_KEY" ]]; then
echo "$SSH_PRIVATE_KEY" | tr -d '\r' > "$SSH_DIR/id_rsa"
chmod 600 "$SSH_DIR/id_rsa"
eval "$(ssh-agent -s)"
ssh-add "$SSH_DIR/id_rsa" 2>&1 1>/dev/null

cat > /etc/ssh/ssh_config <<EOL
Host $REMOTE_HOST
HostName $REMOTE_HOST
IdentityFile ${SSH_DIR}/id_rsa
User $REMOTE_USER
EOL

fi
}
5 changes: 5 additions & 0 deletions .github/hosts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
main:
hostname: domain-aaa.com
user: rtcamp
deploy_path: /home/rtcamp/privacy-sandbox-demos
prev_releases_limit: 7
19 changes: 19 additions & 0 deletions .github/workflows/deploy_on_push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
on:
push:
branches:
- main

name: Deploy
jobs:
deploy:
name: Deploy
runs-on: self-hosted
# runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy
id: deploy
uses: rtCamp/action-deploy-frappe@main
#uses: docker://ghcr.io/rtcamp/action-deploy-frappe:dev
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}

0 comments on commit 439cb6c

Please sign in to comment.