notes/scripts/bgit
2022-07-27 12:45:36 -07:00

431 lines
18 KiB
Bash
Executable file

#!/bin/bash
# checklist:
# [-] add -i flag for install script (default if not git repo is found)
# [-] add function where $1 checks for existing directory and creates it if it doesn't exist, cd's into it, and initializes git repo (also cd's into it if it DOES exist, and initizliaes repo), also checks for .git directory...
# Error handling
set -e
# For styling/colorizing output
txtbld=$(tput bold)
txtblue=${txtbld}$(tput setaf 4)
txtgreen=${txtbld}$(tput setaf 2)
txtred=${txtbld}$(tput setaf 1)
txtyellow=${txtbld}$(tput setaf 3)
txtwhite=${txtbld}$(tput setaf 7)
# Dependency check
if ! command -v git &> /dev/null
then
echo "${txtred}dependency not met: git"
echo "Please install needed depndencies${txtwhite}"
exit 1
fi
# Intro Prompt
echo "${txtblue}bgit: a handy shell script for automating simple git inits/commits"
# Reset output style
tput bold & tput setaf 7
# counts the number of repos
numrepos=$(git remote | wc -l)
# If there are no git repositories in this directory...
if [ $numrepos -eq 0 ] ; then
echo "${txtgreen}no git repository found, executing git init...${txtwhite}"
while true
do
#Prompts the user if they'd like to initialize repository
read -e -r -p "${txtwhite}initialize repository?(y/n): ${txtyellow}" init
if [[ $init == "n" || $init = "no" ]]; then
echo "${txtred}no git repository initialized...exiting${txtwhite}"
break
elif [[ $init == "y" || $init == "yes" ]] ; then
# Creates a default README.md
echo -e "## A Simple README\n\nSome Text" > README.md
# Creates a default .gitignore
echo -e "node_modules\n*.env\n*.out\n.pretterrc\n.gitignore" > .gitignore
# Initializes git repository cwd...
git init
# defaults to not requiring gpg key sign
git config commit.gpgsign false
while [ true ];
do
# prompts user to change default username/email and changes them if they'd like (no input defaults to global values)
read -e -r -p "${txtwhite}would you like to change username/password from global defaults?(y/n): ${txtyellow}" changedefaults
if [[ $changedefaults == "y" || $changedefaults == "yes" ]] ; then
read -e -r -p "${txtwhite}enter your username: ${txtyellow}" uname
if [[ -n $uname ]] ; then
git config user.name $uname
read -e -r -p "${txtwhite}enter your email: ${txtyellow}" uemail
if [[ -n $uemail ]] ; then
git config user.email $uemail
break
else
echo "${txtblue}no email entered, defaulting to global value${txtwhite}"
break
fi
else
echo "${txtblue}no username entered, defaulting to global value${txtwhite}"
break
fi
else
echo "${txtblue}defaulting to global username/password${txtwhite}"
break
fi
done
while true
do
# initializes standard html/css/javascript project (incomplete)
read -e -r -p "${txtwhite}would you like to make this an npm project?(y/n): ${txtyellow}" confirmnpm
if [[ $confirmnpm == "y" || $confirmnpm == "yes" ]] ; then
# Dependency check
dependencies=("node" "npm")
numdependencies=2
missingdependencies=0
for ((i = 0; i < numdependencies; i++)) ;
do
if ! command -v "${dependencies[$i]}" &> /dev/null
then
echo "${txtred}dependency not met: ${dependencies[$i]}${txtwhite}"
missingdependencies=$((missingdependencies+1))
fi
done
if [ $missingdependencies -gt 0 ] ;
then
echo "${txtred}Please install needed dependencies${txtwhite}"
exit 1
fi
npm init -y
npm install -D nodemon prettier jest
# creates default .prettierrc
echo -e 'trailingComma: "all"\ntabWidth: 4\nsemi: false\nsingleQuote: true\nbracketSpacing: true\narrowParens: "avoid"' > .prettierrc
# replace touch commands here with echo later on...
echo -e '<!DOCTYPE html>\n<html>\n <head>\n <meta charset="utf-8">\n <meta name="viewport" content="width=device-width">\n <title>My Website</title>\n <link rel="stylesheet" href="css/styles.css" />\n </head>\n <body>\n <h1>Header 1</h1>\n <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>\n <script src="scripts/index.js" defer></script>\n </body>\n</html>' > index.html
mkdir scripts
mkdir css
mkdir tests
touch tests/index.test.js
echo 'console.log("Hello World!");' > scripts/index.js
echo -e '* {\n font-family: monospace;\n text-align: center;\n background-color: #dedede;\n}' > css/styles.css
sed 's/1"/1",/' package.json > package2.json && sed -i '/no test/a\ \ \ \ "start":\ "nodemon\ scripts/index.js"' package2.json && mv package2.json package.json
break
else
break
fi
done
# Reset output style
tput bold & tput setaf 7
# sane default initial commit message
git add .
git commit -m ":tada: Initial commit"
while true
do
# allows user to change default branch name (no input defaults to "master")
read -e -r -p "${txtwhite}change branch name?(y/n): ${txtyellow}" chbranch
if [[ $chbranch == "y" || $chbranch == "yes" ]] ; then
read -e -r -p "${txtwhite}branch name?(i.e. 'main'): ${txtyellow}" branch
if [ -n "$branch" ] ; then
git branch -M $branch
break
else
echo "${txtred}branch name is empty, please enter branch name!${txtwhite}"
fi
else
echo "${txtblue}branch name will be left as ${txtyellow}'master'${txtwhite}"
branch="master"
break
fi
done
# main git init loop
while true
do
uname=$(git config user.name)
read -e -r -p "${txtwhite}Please enter remote to add(i.e. origin): ${txtyellow}" remote
# if the user doesn't enter anything for the remote prompt, it defaults to origin
if [[ -z $remote ]]; then
remote="origin"
fi
# infinitely prompts the user for a host site until something is entered
while [ -z $host ]
do
read -e -r -p "${txtwhite}Please enter host site (i.e. github.com): ${txtyellow}" host
done
# similarly infinitely prompts the user for a repository name
while [ -z $repo ]
do
read -e -r -p "${txtwhite}Please enter name of repository: ${txtyellow}" repo
done
# Reset output style
tput bold & tput setaf 7
# bgit uses github api if github.com is defined as host site
if [[ -n $host && $host == "github.com" ]] ; then
read -e -r -p "${txtwhite}Host site is github.com, would you like bgit to create the repository?(y/n): ${txtyellow}" crepo
# Reset output style
tput bold & tput setaf 7
# if $HOME/.gh_pat doesn't exist, then exits
if [[ ! -f $HOME/.gh_pat ]]; then
echo "${txtred}Github personal access token doesn't exist"
echo "See https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token${txtwhite}"
exit 1
fi
source $HOME/.gh_pat
if [[ $crepo == 'y' || $crepo == 'yes' ]] ; then
# Dependency check
dependencies=("xclip" "curl")
numdependencies=2
missingdependencies=0
for ((i = 0; i < numdependencies; i++)) ;
do
if ! command -v "${dependencies[$i]}" &> /dev/null
then
echo "${txtred}dependency not met: ${dependencies[$i]}${txtwhite}"
missingdependencies=$((missingdependencies+1))
fi
done
if [ $missingdependencies -gt 0 ] ;
then
echo "${txtred}Please install needed dependencies${txtwhite}"
exit 1
fi
echo "${txtgreen}Host Site is github.com, creating repository...${txtwhite}"
curl -u $uname:$GH_TOKEN https://api.github.com/user/repos -d '{"name": "'${repo}'"}'
fi
echo -e "${txtblue}Your \$GH_TOKEN is saved to your clipboard...\nsimply enter CTRL+SHIFT+V to paste your token...\nwhen prompted for your password${txtwhite}"
echo $GH_TOKEN | xclip -sel clip
fi
# finally adds the specified remote, host site, username, and repository, and pushes it
git remote add $remote "https://$host/$uname/$repo"
git push --set-upstream $remote $branch
# git push -u $remote $branch
if [[ $host == "github.com" ]] ; then
echo "${txtgreen}Git repository created and initiated!!${txtwhite}"
# clears $GH_TOKEN from clipboard
echo '' | xclip && xclip -selection clipboard /dev/null
else
echo "${txtgreen}Git repository initiated!!${txtwhite}"
fi
break
done
break
else
break
fi
done
# Otherwise, if there already is a .git directory...
else
# creates a list of repos and puts them in an array
remotearray=($(git remote))
# Grabs all new files
newfiles=$(git status --short | grep '??' | awk '{print $2}' | tr '\n' ' ')
# Grabs all modified files
modified=$(git status --short | grep M | awk '{print $2}' | tr '\n' ' ')
# Grabs all deleted files
deleted=$(git status --short | grep D | awk '{print $2}' | tr '\n' ' ')
# getopts loop for flag -r that reverts back changes in git repo
while getopts "r" opt; do
case $opt in
r)
echo "${txtgreen}-r flag initiated"
read -e -r -p "${txtwhite}Would you like to revert back to a previous commit?: ${txtyellow}" revert
# Reset output style
tput bold & tput setaf 7
if [[ $revert == "y" || $revert == "yes" ]] ; then
# commitarray contains all the sha256 sums of our git commits
commitarray=($(git log -6 | grep commit | sed 's/commit//g'));
# verbosecommits is a long format output of all our commit messages
verbosecommits=$(git shortlog -6 --reverse | sed 1d);
# displays the sha256 sums of our git commits, along with the git commit messages
numcommits=6
for ((i = 0; i < numcommits; i++)) do
# j is simply 1 count ahead of i, this is specifically to be used in nextcommit
j=$(echo ${i} + 1 | bc)
# nextcommit prints out each verbosecommit message one by one
nextcommit=$(echo "${verbosecommits}" | head -n $j | tail -n 1)
echo -e "${i}) ${commitarray[$i]}${nextcommit}"
done
# and asks the user to choose a commit to revert back to
read -e -r -p "${txtwhite}Choose commit to revert back to: ${txtyellow}" version
# notifies the user of which version they are rolling back to with the sha256 sum
echo "${txtblue}Reverting back to version: ${txtyellow}${commitarray[$version]}"
# Reset output style
tput bold & tput setaf 7
# and finally resets the local repository to that version
git reset --hard ${commitarray[$version]}
# and pushes it to remote repository
for ((i = 0; i < $numrepos; i++)) ; do
git push --force ${remotearray[i]} ;
done
echo "${txtblue}bgit script has completed! goodbye!${txtwhite}"
exit 0
else
echo "${txtblue}No revisions to git branch have been made.${txtwhite}"
fi ;;
*)
echo "${txtred}Flag not recognized...exiting bgit."
exit 1;;
esac
done
# Reports what is staged for commit
# If there is anything to commit...
if [[ ! -z $newfiles || ! -z $modified || ! -z $deleted ]] ; then
# Let the user know what is staged for commit
echo "${txtwhite}The following files are staged for commit:"
# Otherwise, if there isn't anything to commit...
else
# Let the user know that everything is up to date
echo "${txtred}everything up-to-date...exiting bgit${txtwhite}"
# and exit the program
exit 0
fi
# Let the user know what is staged for commit
if [[ $newfiles ]]; then
echo "${txtgreen}ADDED: ${txtgreen}$newfiles"
fi
if [[ $modified ]]; then
echo "${txtblue}MODIFIED: ${txtblue}$modified"
fi
if [[ $deleted ]]; then
echo "${txtred}DELETED: ${txtred}$deleted"
fi
while true
do
# Prompts user if they'd like to commit the changes
read -e -r -p "${txtwhite}commit changes?(y/n): ${txtyellow}" change
# If the user chooses to commit the changes...
if [[ $change == "y" || $change == "yes" ]] ; then
# prompt if user wants to specify gitmoji:
while [ true ]
do
read -e -r -p "${txtwhite}add a gitmoji?(y/n): ${txtyellow}" gmojiprompt
if [[ $gmojiprompt == "y" || $gmojiprompt == "yes" ]] ; then
read -e -r -p "${txtwhite}enter gitmoji: ${txtyellow}" gitmoji
gitmoji=":$gitmoji:"
break
else
echo "${txtblue}no gitmoji specified...${txtwhite}"
gitmoji=""
break
fi
done
# Grabs commit message
while [ true ]
do
# Prompts the user to input their commit message
# (does not allow for multiple message commits)
read -e -r -p "${txtwhite}commit message: ${txtyellow}" message
cmessage=("$message")
# capitalizes first character of commit message
cmessage="$(tr '[:lower:]' '[:upper:]' <<< ${cmessage:0:1})${cmessage:1}"
# if the user entered a commit message over 50 characters...
if [ "${#message}" -ge 51 ] ; then
echo "${txtred}commit message is too large!"
echo "${txtred}please limit to 50 or less characters${txtwhite}"
# if the user inputted a commit message..
elif [ -n "$message" ] ; then
# then break out of the while loop and continue with the commit...
break
# if the user did NOT input a commit message...
else
# tell the user to do so or to quit
echo "${txtred}commit message is empty, please write a commit message"
echo "${txtred}or type 'CTRL+C' to quit${txtwhite}"
fi
done
# Reset output style
tput bold & tput setaf 7
# adds the modified and new files
# (suppresses message anyways if only deleted files are to be committed)
if [[ $newfiles || $modified ]] ; then
# also remembers password for 1 hour after last use
# (comment out if more security needed, or just use ssh...)
echo "${txtgreen}bgit will remember your password for 1 hour!"
echo "(doesn't apply to gpg or ssh)${txtwhite}"
git config credential.helper 'cache --timeout=3600';
git config advice.addEmptyPathspec false;
git add $modified $newfiles;
fi
if [[ $deleted ]] ; then
git rm $deleted;
fi
# commits the user's message (multi-word supported)
git commit -m "$gitmoji $cmessage" ;
# pushes the commit to each repository
for ((i = 0; i < numrepos; i++)) ; do
git push ${remotearray[i]} ;
done
echo "${txtblue}bgit script has completed! goodbye!${txtwhite}"
exit 0
# If the user chooses to not the commit the changes ...
elif [[ $change == "n" || $change == "no" ]] ; then
# Reset output style
tput bold & tput setaf 7
# Report the git status
git status --short
# And let the user know no changes were committed
echo "${txtred}no changes committed"
exit 0
# If the user chooses to quit...
elif [[ $change == "q" || $change == "quit" ]] ; then
exit 0
# If the user continues to just press enter...
else
echo "${txtred}please enter y or n or type 'q' or 'quit' or 'CTRL+C' to quit${txtwhite}"
fi
done
fi