Skip to content

Instantly share code, notes, and snippets.

@jeffryang24
Last active August 23, 2018 10:46
Show Gist options
  • Save jeffryang24/b27829e0a9a63216b51ea9fcf3abfbd9 to your computer and use it in GitHub Desktop.
Save jeffryang24/b27829e0a9a63216b51ea9fcf3abfbd9 to your computer and use it in GitHub Desktop.
GitHub Auto Deployment Script Installation for NodeJS with PM2.
#!/usr/bin/env bash
# GitHub (NodeJS) Auto Deployment Script
# for debug
#set -o xtrace
# Version
_GHPLOY_VERSION="0.1a1"
# Reserved variables
_gh_query=()
version() {
printf "%s\n" "GHPloy Version ${_GHPLOY_VERSION}"
}
usage() {
printf "%s\n" "Usage: ghploy -q [remote-host:project-folder-name[:clone-location]] [ssh-arguments]"
}
help() {
version
printf "\n"
usage
printf "\n"
printf "\t%s\n" "[remote-host] => SSH remote host, ie. username@hostname."
printf "\t%s\n" "[project-folder-name] => GitHub project's folder name."
printf "\t%s\n" "[clone-location] => Clone location path."
}
do_ssh() {
local _ssh_script
if ! command -v ssh >/dev/null 2>&1; then
printf "%s\n" "ERROR! Please install ssh on your rig to use this script."
exit 1
fi
# Check remote host
if [[ -z "${_gh_query[0]:-}" ]]; then
printf "%s\n" "ERROR! Please specify remote host."
exit 1
elif [[ ! ${_gh_query[0]:-} =~ ^[a-zA-Z0-9_\-]+\@.+$ ]]; then
# shellcheck disable=SC1001
printf "%s\n" "ERROR! Doesn't match pattern {username}@{hostname}."
exit 1
fi
# Check project folder name
if [[ -z "${_gh_query[1]:-}" ]]; then
printf "%s\n" "ERROR! Please specify project folder name."
exit 1
fi
# Check clone location
if [[ -z "${_gh_query[2]:-}" ]]; then
_gh_query[2]="\${HOME}/${_gh_query[1]}"
else
_gh_query[2]="${_gh_query[2]}/${_gh_query[1]}"
fi
_ssh_script="$(cat <<EOF
#!/usr/bin/env bash
# Check Git and SSH is installed or not
printf "%s\n" "[*] Checking SSH Command."
if ! command -v ssh >/dev/null 2>&1; then
printf "%s\n" "ERROR! Please install openssh on your remote rig."
exit 1
fi
printf "%s\n\n" "[OK]. Done"
printf "%s\n" "[*] Checking Git Command."
if ! command -v git >/dev/null 2>&1; then
printf "%s\n" "ERROR! Please install git on your remote rig."
exit 1
fi
printf "%s\n\n" "[OK]. Done"
# Add Github Fingerprint
if ! ssh-keygen -F github.com >/dev/null 2>&1; then
printf "%s\n" "[*] Add GitHub fingerprint."
mkdir -p \${HOME}/.ssh
[ -f "\${HOME}/.ssh/known_hosts" ] &&
cp "\${HOME}/.ssh/known_hosts" "\${HOME}/.ssh/known_hosts.bak.\$(date +'%Y%m%d')"
(ssh-keyscan -H github.com >> \${HOME}/.ssh/known_hosts &&
printf "%s\n\n" "[OK]. Done") ||
exit 1
fi
# Initialize git bare repository.
printf "%s\n" "[*] Initialize bare repository."
# Force remove existed directory.
[ -d "${_gh_query[2]}" ] && rm -rf "${_gh_query[2]}"
(git init --bare "${_gh_query[2]}/.git" &&
printf "%s\n\n" "[OK]. Done") ||
exit 1
# Add Hook Script
cat > "${_gh_query[2]}/.git/hooks/post-receive" <<HOOK
#!/bin/sh
# Export Path
export PATH="\${PATH}:/usr/bin:/usr/local/bin:/usr/sbin"
# For nvm
if [ -d "\$HOME/.nvm" ]; then
export NVM_DIR="\$HOME/.nvm"
. "\$HOME/.nvm/nvm.sh"
fi
# Make sure pm2 is installed.
if ! command -v pm2 >/dev/null 2>&1; then
printf "%s\n" "[*] Installing PM2" &&
npm install -g pm2 &&
printf "%s\n\n" "[OK]. Done"
fi
cd "${_gh_query[2]}"
# Checkout directory
printf "%s\n" "[*] Checking out HEAD." &&
git --git-dir="${_gh_query[2]}/.git"\
--work-tree="${_gh_query[2]}"\
checkout -f &&
printf "%s\n\n" "[OK]. Done"
# Checkout Submodule
printf "%s\n" "[*] Updating submodule." &&
git --git-dir="${_gh_query[2]}/.git"\
--work-tree="${_gh_query[2]}"\
submodule update --init --recursive &&
printf "%s\n\n" "[OK]. Done"
# Fix submodule ownership
chown -R \${USER}:\${USER} .
# NPM Install and Build
printf "%s\n" "[*] Installing package.json." &&
npm install &&
printf "%s\n\n" "[OK]. Done"
printf "%s\n" "[*] Building project." &&
npm run build &&
printf "%s\n\n" "[OK]. Done"
# Create ecosystem file
if [ ! -f "${_gh_query[2]}/ecosystem.config.js" ]; then
cat > "${_gh_query[2]}/ecosystem.config.js" <<'ECOS'
module.exports = {
apps : [{
name: '${_gh_query[1]}',
script: 'npm',
args: ['run', 'start'],
env: {
NODE_ENV: 'staging'
},
env_production : {
NODE_ENV: 'production'
}
}],
};
ECOS
fi
# Run pm2
printf "%s\n" "[*] Starting pm2." &&
(pm2 delete "${_gh_query[2]}/ecosystem.config.js" || true) &&
pm2 start "${_gh_query[2]}/ecosystem.config.js" &&
printf "%s\n\n" "[OK]. Done"
HOOK
chmod +x "${_gh_query[2]}/.git/hooks/post-receive"
EOF
)"
#echo "${_ssh_script}"
# shellcheck disable=SC2029
ssh -T "$@" "${_gh_query[0]}" "${_ssh_script}"
}
main(){
local -a _parameters=()
local _OLD_IFS="${IFS}"
[[ "$#" -eq "0" ]] && help && exit 0
while [[ "$#" -gt "0" ]]; do
local _key="$1"
case ${_key} in
-h|--help)
help
shift
exit $?
;;
-q)
if [[ -z "$2" ]]; then
printf "%s\n" "ERROR! Please specify the query."
exit 1
fi
IFS=":" read -r -a _gh_query <<< "$2"
IFS="${_OLD_IFS}"
shift 2
;;
*)
_parameters+=("${_key}")
shift
;;
esac
done
# Restore positional arguments
eval set -- "${_parameters[@]}"
# Make sure user is not root
if [[ "${_gh_query[0]%@*}" == "root" ]]; then
printf "%s\n" "ERROR! For security purpose, please leave root account!"
exit 1
fi
# Set ssh argument
do_ssh "$@"
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment