Last active
June 21, 2023 08:12
-
-
Save aryomuzakki/c5d19685b4ff1f7b287bcc9f20924262 to your computer and use it in GitHub Desktop.
Bash command in ubuntu to create a bare git repo and post commit hooks to start node js with pm2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# USAGE: | |
# command example.com [OPTIONS] | |
# | |
# args desc | |
# example.com the domain name | |
# | |
# options args desc | |
# --app-name short-app-name required if --pm2-start is yes | |
# --domain-name domain-name | |
# --npm-install yes|no include npm install script in post hooks or not | |
# --npm-build yes|no include npm run build in post hooks or not | |
# --pm2-start yes|no include pm2 start script in post hooks or not | |
# -p --port 3000 required if --pm2-start option is yes | |
# -? show this help | |
# -h --help show this help | |
# example: | |
# > command example.com --npm-install yes --pm2-start no | |
# | |
# or | |
# > command example.com --pm2-start=yes --app-name=something --port 3000 | |
# | |
# or | |
# > command --domain-name=example.com --npm-install no | |
# ## VARIABLES | |
domainName= | |
appName= | |
isUseNPM= | |
isUseNPMBuild= | |
isUsePM2= | |
port= | |
gitDir= | |
gitWorkTreeDir= | |
postHooksFile= | |
postHooksScript= | |
pm2ConfigFile= | |
pm2ConfigScript= | |
# exit and show error | |
function Die() { | |
echo "$1\n" >&2 | |
printf "$s\n" "$1" >&2 | |
exit 1 | |
} | |
# show usage | |
function ShowHelp() { | |
cat <<-EOF | |
Usage for $0: | |
command example.com [OPTIONS] | |
args desc | |
example.com the domain name | |
options args desc | |
--app-name short-app-name required if --pm2-start is yes | |
--domain-name domain-name | |
--npm-install yes|no include npm install script in post hooks or not | |
--npm-build yes|no include npm run build in post hooks or not | |
--pm2-start yes|no include pm2 start script in post hooks or not | |
-p --port 3000 required if --pm2-start option is yes | |
-? show this help | |
-h --help show this help | |
example: | |
> command example.com --npm-install yes --npm-build yes --pm2-start no | |
or | |
> command example.com --pm2-start=yes --app-name=something --port 3000 | |
or | |
> command --domain-name=example.com --npm-install no | |
EOF | |
} | |
# ## first argument | |
if [ "$1" ] && [[ "$1" != -* ]]; then # if first arg exist and not starts with -, assign domain name | |
domainName=$1 | |
shift | |
fi | |
# ## option argument | |
if [ $# -gt 0 ]; then | |
while [ "$1" ]; do | |
case $1 in | |
--app-name) | |
# set app name | |
# if argument exist, set app name, else ask user input | |
if [ "$2" ]; then | |
if [[ "$2" == -* ]]; then | |
Die "Error: argument cannot start with \"-\" for option \"$1\"" | |
else | |
appName=$2 | |
shift 2 | |
fi | |
else | |
Die "Error: argument required for \"$1\" option" | |
fi | |
;; | |
--app-name=?*) | |
# get argument after "=" sign | |
appName=${1#*=} | |
shift | |
;; | |
--app-name=) | |
# empty args | |
Die "Error: argument required for \"$1\" option" | |
;; | |
--domain-name) | |
# set domain name | |
# if domain name is not null | |
if [ "$domainName" ]; then | |
echo "Warning: redeclared domain name using \"$1\" option" | |
fi | |
if [ "$2" ]; then | |
if [[ "$2" == -* ]]; then | |
Die "Error: argument cannot start with \"-\" for option \"$1\"" | |
else | |
domainName=$2 | |
shift 2 | |
fi | |
else | |
Die "Error: argument required for \"$1\" option" | |
fi | |
;; | |
--domain-name=?*) | |
# get argument after "=" sign | |
domainName=${1#*=} | |
shift | |
;; | |
--domain-name=) | |
# empty args | |
Die "Error: argument required for \"$1\" option" | |
;; | |
--npm-install) | |
# include or exclude npm install | |
echo "npm install case" | |
[[ "$2" == -* ]] && echo "ok" | |
if [ "$2" ]; then | |
if [[ "$2" == -* ]]; then | |
Die "Error: argument cannot start with \"-\" for option \"$1\"" | |
else | |
if [ "$2" = "yes" ]; then | |
isUseNPM="include npm" | |
elif [ "$2" = "no" ]; then | |
isUseNPM="exclude npm" | |
fi | |
shift 2 | |
fi | |
else | |
Die "Error: argument required for \"$1\" option" | |
fi | |
;; | |
--npm-install=?*) | |
# get argument after "=" sign | |
if [ "${1#*=}" = "yes" ]; then | |
isUseNPM="include npm" | |
elif [ "${1#*=}" = "no" ]; then | |
isUseNPM="exclude npm" | |
fi | |
shift | |
;; | |
--npm-install=) | |
# empty args | |
Die "Error: argument required for \"$1\" option" | |
;; | |
--npm-build) | |
# include or exclude npm run build | |
echo "npm run build case" | |
[[ "$2" == -* ]] && echo "ok" | |
if [ "$2" ]; then | |
if [[ "$2" == -* ]]; then | |
Die "Error: argument cannot start with \"-\" for option \"$1\"" | |
else | |
if [ "$2" = "yes" ]; then | |
isUseNPMBuild="include npm run build" | |
elif [ "$2" = "no" ]; then | |
isUseNPMBuild="exclude npm run build" | |
fi | |
shift 2 | |
fi | |
else | |
Die "Error: argument required for \"$1\" option" | |
fi | |
;; | |
--npm-build=?*) | |
# get argument after "=" sign | |
if [ "${1#*=}" = "yes" ]; then | |
isUseNPMBuild="include npm run build" | |
elif [ "${1#*=}" = "no" ]; then | |
isUseNPMBuild="exclude npm run build" | |
fi | |
shift | |
;; | |
--npm-build=) | |
# empty args | |
Die "Error: argument required for \"$1\" option" | |
;; | |
--pm2-start) | |
# include or exclude pm2 start script | |
if [ "$2" ]; then | |
if [[ "$2" == -* ]]; then | |
Die "Error: argument cannot start with \"-\" for option \"$1\"" | |
else | |
if [ "$2" = "yes" ]; then | |
isUsePM2="include pm2" | |
elif [ "$2" = "no" ]; then | |
isUsePM2="exclude pm2" | |
fi | |
shift 2 | |
fi | |
else | |
Die "Error: argument required for \"$1\" option" | |
fi | |
;; | |
--pm2-start=?*) | |
# get argument after "=" sign | |
if [ "${1#*=}" = "yes" ]; then | |
isUsePM2="include pm2" | |
elif [ "${1#*=}" = "no" ]; then | |
isUsePM2="exclude pm2" | |
fi | |
shift | |
;; | |
--pm2-start=) | |
# empty args | |
Die "Error: argument required for \"$1\" option" | |
;; | |
--port) | |
# set port in pm2 config | |
if [ "$2" ]; then | |
if [[ "$2" == -* ]]; then | |
Die "Error: argument cannot start with \"-\" for option \"$1\"" | |
else | |
port=$2 | |
shift 2 | |
fi | |
else | |
Die "Error: argument required for \"$1\" option" | |
fi | |
;; | |
--port=?*) | |
# get argument after "=" sign | |
port=${1#*=} | |
shift | |
;; | |
--port=) | |
# empty args | |
Die "Error: argument required for \"$1\" option" | |
;; | |
-h | -\? | --help) | |
# display usage | |
ShowHelp | |
shift | |
exit | |
;; | |
*) | |
# unrecognized argument | |
Die "Error: \"$1\" is not recognized as an argument or option" | |
;; | |
esac | |
done | |
fi | |
# ## check required user input when argument not specified | |
# ## and set variables | |
while [ ! "$domainName" ]; do | |
read -p "*Provide domain name: (domain.com) " domainName | |
done | |
if [ "$domainName" ]; then | |
gitDir=${HOME}/repo/node/${domainName}.git | |
gitWorkTreeDir=${HOME}/source/node/${domainName} | |
postHooksFile=${gitDir}/hooks/post-receive | |
postHooksScript=$( | |
cat <<-EOF | |
#!/bin/sh | |
git --work-tree=$gitWorkTreeDir --git-dir=$gitDir checkout -f main | |
EOF | |
) | |
fi | |
while [ ! "$isUseNPM" ]; do | |
read -p "*Include npm install? (yes/no) " isUseNPM | |
if [ "$isUseNPM" = "yes" ]; then | |
isUseNPM="include npm" | |
elif [ "$isUseNPM" = "no" ]; then | |
isUseNPM="exclude npm" | |
else | |
isUseNPM= | |
fi | |
done | |
if [ "$isUseNPM" = "include npm" ]; then | |
# append npm script to post receive hook | |
postHooksScript+=$( | |
cat <<-EOF | |
echo "export nvs path" | |
export PATH=\$PATH:${HOME}/.nvs/default/bin | |
echo "changing directory" | |
cd ${gitWorkTreeDir} | |
echo "installing dependencies" | |
npm install | |
EOF | |
) | |
fi | |
while [ ! "$isUseNPMBuild" ]; do | |
read -p "*Include npm run build? (yes/no) " isUseNPMBuild | |
if [ "$isUseNPMBuild" = "yes" ]; then | |
isUseNPMBuild="include npm run build" | |
elif [ "$isUseNPMBuild" = "no" ]; then | |
isUseNPMBuild="exclude npm run build" | |
else | |
isUseNPMBuild= | |
fi | |
done | |
if [ "$isUseNPMBuild" = "include npm run build" ]; then | |
# append npm run build script to post receive hook | |
postHooksScript+=$( | |
cat <<-EOF | |
echo "building project" | |
npm run build | |
EOF | |
) | |
fi | |
while [ ! "$isUsePM2" ]; do | |
read -p "*Include pm2 start script? (yes/no) " isUsePM2 | |
if [ "$isUsePM2" = "yes" ]; then | |
isUsePM2="include pm2" | |
while [ ! "$appName" ]; do | |
read -p "*Provide app name: (app-name) " appName | |
done | |
while [ ! "$port" ]; do | |
read -p "*Provide port number: (5000-5999) " port | |
done | |
elif [ "$isUsePM2" = "no" ]; then | |
isUsePM2="exclude pm2" | |
else | |
isUsePM2= | |
fi | |
done | |
if [ "$isUsePM2" = "include pm2" ]; then | |
# add pm2 config | |
pm2ConfigFile=${HOME}/source/node/ecosystem.config.js | |
pm2ConfigScript=$( | |
cat <<-EOF | |
{\ | |
\n name: "${appName}",\ | |
\n script: "npm",\ | |
\n args: "run start",\ | |
\n cwd: "./${domainName}",\ | |
\n watch: true,\ | |
\n ignore_watch: ["node_modules"],\ | |
\n restart_delay: 1000,\ | |
\n env: {\ | |
\n PORT: $port,\ | |
\n },\ | |
\n }, | |
EOF | |
) | |
# check if file exist and is not empty | |
if [ -f "$pm2ConfigFile" ] && [ -s "$pm2ConfigFile" ]; then | |
# get line position | |
ln=$(($(cat $pm2ConfigFile | wc -l) - 1)) | |
else | |
ln=3 | |
cat <<-EOF >$pm2ConfigFile | |
module.exports = { | |
apps: [ | |
], | |
} | |
EOF | |
fi | |
# insert pm2ConfigScript object string into array string in pm2ConfigFile | |
# in the correct line position | |
pm2ConfigScript=$(sed "${ln}i\\$pm2ConfigScript" $pm2ConfigFile) | |
# append pm2 script to post receive hook | |
postHooksScript+=$( | |
cat <<-EOF | |
echo "set up and start from pm2 config file" | |
cd ${HOME}/source/node/ | |
pm2 stop ${appName} || : && pm2 delete ${appName} || : && pm2 start ecosystem.config.js --only ${appName} | |
pm2 save | |
echo "completed" | |
EOF | |
) | |
fi | |
# main script | |
# create dirs | |
mkdir -p $gitDir $gitWorkTreeDir | |
# init git bare repo | |
if cd $gitDir; then | |
git init --bare --quiet | |
else | |
echo "failed changing directory to: $gitDir" >&2 | |
echo "exit before running \"git init --bare\" and the rest of process" >&2 | |
exit 1 | |
fi | |
# create post-receive hooks and set executable | |
echo "$postHooksScript" >$postHooksFile | |
chmod +x $postHooksFile | |
# create copy of previous pm2 config | |
cp $pm2ConfigFile $pm2ConfigFile.former 2>/dev/null | |
# create pm2 config app if set | |
[ "$isUsePM2" = "include pm2" ] && echo "$pm2ConfigScript" >$pm2ConfigFile | |
# get public ip address | |
publicIP=$(curl https://ipinfo.io/ip) | |
# finish, ready to pushed to repo | |
# output repo link | |
echo "ssh://${USER}@$publicIP$gitDir" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment