123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- #!/usr/bin/env bash
- set -o errexit #abort if any command fails
- me=$(basename "$0")
- help_message="\
- Usage: $me [-c FILE] [<options>]
- Deploy generated files to a git branch.
- Options:
- -h, --help Show this help information.
- -v, --verbose Increase verbosity. Useful for debugging.
- -e, --allow-empty Allow deployment of an empty directory.
- -m, --message MESSAGE Specify the message used when committing on the
- deploy branch.
- -n, --no-hash Don't append the source commit's hash to the deploy
- commit's message.
- --source-only Only build but not push
- --push-only Only push but not build
- "
- run_build() {
- bundle exec middleman build --clean
- }
- parse_args() {
- # Set args from a local environment file.
- if [ -e ".env" ]; then
- source .env
- fi
- # Parse arg flags
- # If something is exposed as an environment variable, set/overwrite it
- # here. Otherwise, set/overwrite the internal variable instead.
- while : ; do
- if [[ $1 = "-h" || $1 = "--help" ]]; then
- echo "$help_message"
- exit 0
- elif [[ $1 = "-v" || $1 = "--verbose" ]]; then
- verbose=true
- shift
- elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then
- allow_empty=true
- shift
- elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then
- commit_message=$2
- shift 2
- elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then
- GIT_DEPLOY_APPEND_HASH=false
- shift
- elif [[ $1 = "--source-only" ]]; then
- source_only=true
- shift
- elif [[ $1 = "--push-only" ]]; then
- push_only=true
- shift
- else
- break
- fi
- done
- if [ ${source_only} ] && [ ${push_only} ]; then
- >&2 echo "You can only specify one of --source-only or --push-only"
- exit 1
- fi
- # Set internal option vars from the environment and arg flags. All internal
- # vars should be declared here, with sane defaults if applicable.
- # Source directory & target branch.
- deploy_directory=build
- deploy_branch=gh-pages
- #if no user identity is already set in the current git environment, use this:
- default_username=${GIT_DEPLOY_USERNAME:-deploy.sh}
- default_email=${GIT_DEPLOY_EMAIL:-}
- #repository to deploy to. must be readable and writable.
- repo=origin
- #append commit hash to the end of message by default
- append_hash=${GIT_DEPLOY_APPEND_HASH:-true}
- }
- main() {
- enable_expanded_output
- if ! git diff --exit-code --quiet --cached; then
- echo Aborting due to uncommitted changes in the index >&2
- return 1
- fi
- commit_title=`git log -n 1 --format="%s" HEAD`
- commit_hash=` git log -n 1 --format="%H" HEAD`
- #default commit message uses last title if a custom one is not supplied
- if [[ -z $commit_message ]]; then
- commit_message="publish: $commit_title"
- fi
- #append hash to commit message unless no hash flag was found
- if [ $append_hash = true ]; then
- commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash"
- fi
- previous_branch=`git rev-parse --abbrev-ref HEAD`
- if [ ! -d "$deploy_directory" ]; then
- echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2
- return 1
- fi
- # must use short form of flag in ls for compatibility with macOS and BSD
- if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then
- echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the --allow-empty / -e flag." >&2
- return 1
- fi
- if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then
- # deploy_branch exists in $repo; make sure we have the latest version
- disable_expanded_output
- git fetch --force $repo $deploy_branch:$deploy_branch
- enable_expanded_output
- fi
- # check if deploy_branch exists locally
- if git show-ref --verify --quiet "refs/heads/$deploy_branch"
- then incremental_deploy
- else initial_deploy
- fi
- restore_head
- }
- initial_deploy() {
- git --work-tree "$deploy_directory" checkout --orphan $deploy_branch
- git --work-tree "$deploy_directory" add --all
- commit+push
- }
- incremental_deploy() {
- #make deploy_branch the current branch
- git symbolic-ref HEAD refs/heads/$deploy_branch
- #put the previously committed contents of deploy_branch into the index
- git --work-tree "$deploy_directory" reset --mixed --quiet
- git --work-tree "$deploy_directory" add --all
- set +o errexit
- diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$?
- set -o errexit
- case $diff in
- 0) echo No changes to files in $deploy_directory. Skipping commit.;;
- 1) commit+push;;
- *)
- echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to main, use: git symbolic-ref HEAD refs/heads/main && git reset --mixed >&2
- return $diff
- ;;
- esac
- }
- commit+push() {
- set_user_id
- git --work-tree "$deploy_directory" commit -m "$commit_message"
- disable_expanded_output
- #--quiet is important here to avoid outputting the repo URL, which may contain a secret token
- git push --quiet $repo $deploy_branch
- enable_expanded_output
- }
- #echo expanded commands as they are executed (for debugging)
- enable_expanded_output() {
- if [ $verbose ]; then
- set -o xtrace
- set +o verbose
- fi
- }
- #this is used to avoid outputting the repo URL, which may contain a secret token
- disable_expanded_output() {
- if [ $verbose ]; then
- set +o xtrace
- set -o verbose
- fi
- }
- set_user_id() {
- if [[ -z `git config user.name` ]]; then
- git config user.name "$default_username"
- fi
- if [[ -z `git config user.email` ]]; then
- git config user.email "$default_email"
- fi
- }
- restore_head() {
- if [[ $previous_branch = "HEAD" ]]; then
- #we weren't on any branch before, so just set HEAD back to the commit it was on
- git update-ref --no-deref HEAD $commit_hash $deploy_branch
- else
- git symbolic-ref HEAD refs/heads/$previous_branch
- fi
- git reset --mixed
- }
- filter() {
- sed -e "s|$repo|\$repo|g"
- }
- sanitize() {
- "$@" 2> >(filter 1>&2) | filter
- }
- parse_args "$@"
- if [[ ${source_only} ]]; then
- run_build
- elif [[ ${push_only} ]]; then
- main "$@"
- else
- run_build
- main "$@"
- fi
|