#!/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... # [-] add optional input for add gitmoji(enter l/list for list): where l/list shows list of gitmojis and infinitely returns user to prompt until gitmoji is chosen, if gitmoji doesn't exist within gitmoji array, or "none" is chosen, then default to no gitmoji # 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 dependencies=("xclip" "git") 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 # 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 if [ ! -f "README.md" ] ; then echo -e "## A Simple README\n\nSome Text\n\n__Some Checklist__\n\n- [x] Completed task\n- [ ] Incomplete task" > README.md fi # 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) # perhaps put in separate script that may/can be called from bgit...what if they just want nginx or apache or php? 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 '\n\n \n \n \n My Website\n \n \n \n

Header 1

\n

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

\n \n \n' > 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 if ! command -v curl &> /dev/null then echo "${txtred}dependency not met: curl" echo "Please install needed depndencies${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 | grep modified | awk '{print $2}' | tr '\n' ' ') # Grabs all deleted files deleted=$(git status | grep deleted | 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}) ${txtyellow}${commitarray[$i]}${txtblue}${nextcommit}${txtwhite}" 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 # git remote | xargs -L1 git push --all 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 # 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 --force ${remotearray[i]} ; done # git remote | xargs -L1 git push --all 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