1
0

deploy.sh 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #!/usr/bin/env bash
  2. set -o errexit #abort if any command fails
  3. me=$(basename "$0")
  4. help_message="\
  5. Usage: $me [-c FILE] [<options>]
  6. Deploy generated files to a git branch.
  7. Options:
  8. -h, --help Show this help information.
  9. -v, --verbose Increase verbosity. Useful for debugging.
  10. -e, --allow-empty Allow deployment of an empty directory.
  11. -m, --message MESSAGE Specify the message used when committing on the
  12. deploy branch.
  13. -n, --no-hash Don't append the source commit's hash to the deploy
  14. commit's message.
  15. --source-only Only build but not push
  16. --push-only Only push but not build
  17. "
  18. run_build() {
  19. bundle exec middleman build --clean
  20. }
  21. parse_args() {
  22. # Set args from a local environment file.
  23. if [ -e ".env" ]; then
  24. source .env
  25. fi
  26. # Parse arg flags
  27. # If something is exposed as an environment variable, set/overwrite it
  28. # here. Otherwise, set/overwrite the internal variable instead.
  29. while : ; do
  30. if [[ $1 = "-h" || $1 = "--help" ]]; then
  31. echo "$help_message"
  32. exit 0
  33. elif [[ $1 = "-v" || $1 = "--verbose" ]]; then
  34. verbose=true
  35. shift
  36. elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then
  37. allow_empty=true
  38. shift
  39. elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then
  40. commit_message=$2
  41. shift 2
  42. elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then
  43. GIT_DEPLOY_APPEND_HASH=false
  44. shift
  45. elif [[ $1 = "--source-only" ]]; then
  46. source_only=true
  47. shift
  48. elif [[ $1 = "--push-only" ]]; then
  49. push_only=true
  50. shift
  51. else
  52. break
  53. fi
  54. done
  55. if [ ${source_only} ] && [ ${push_only} ]; then
  56. >&2 echo "You can only specify one of --source-only or --push-only"
  57. exit 1
  58. fi
  59. # Set internal option vars from the environment and arg flags. All internal
  60. # vars should be declared here, with sane defaults if applicable.
  61. # Source directory & target branch.
  62. deploy_directory=build
  63. deploy_branch=gh-pages
  64. #if no user identity is already set in the current git environment, use this:
  65. default_username=${GIT_DEPLOY_USERNAME:-deploy.sh}
  66. default_email=${GIT_DEPLOY_EMAIL:-}
  67. #repository to deploy to. must be readable and writable.
  68. repo=origin
  69. #append commit hash to the end of message by default
  70. append_hash=${GIT_DEPLOY_APPEND_HASH:-true}
  71. }
  72. main() {
  73. enable_expanded_output
  74. if ! git diff --exit-code --quiet --cached; then
  75. echo Aborting due to uncommitted changes in the index >&2
  76. return 1
  77. fi
  78. commit_title=`git log -n 1 --format="%s" HEAD`
  79. commit_hash=` git log -n 1 --format="%H" HEAD`
  80. #default commit message uses last title if a custom one is not supplied
  81. if [[ -z $commit_message ]]; then
  82. commit_message="publish: $commit_title"
  83. fi
  84. #append hash to commit message unless no hash flag was found
  85. if [ $append_hash = true ]; then
  86. commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash"
  87. fi
  88. previous_branch=`git rev-parse --abbrev-ref HEAD`
  89. if [ ! -d "$deploy_directory" ]; then
  90. echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2
  91. return 1
  92. fi
  93. # must use short form of flag in ls for compatibility with macOS and BSD
  94. if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then
  95. 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
  96. return 1
  97. fi
  98. if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then
  99. # deploy_branch exists in $repo; make sure we have the latest version
  100. disable_expanded_output
  101. git fetch --force $repo $deploy_branch:$deploy_branch
  102. enable_expanded_output
  103. fi
  104. # check if deploy_branch exists locally
  105. if git show-ref --verify --quiet "refs/heads/$deploy_branch"
  106. then incremental_deploy
  107. else initial_deploy
  108. fi
  109. restore_head
  110. }
  111. initial_deploy() {
  112. git --work-tree "$deploy_directory" checkout --orphan $deploy_branch
  113. git --work-tree "$deploy_directory" add --all
  114. commit+push
  115. }
  116. incremental_deploy() {
  117. #make deploy_branch the current branch
  118. git symbolic-ref HEAD refs/heads/$deploy_branch
  119. #put the previously committed contents of deploy_branch into the index
  120. git --work-tree "$deploy_directory" reset --mixed --quiet
  121. git --work-tree "$deploy_directory" add --all
  122. set +o errexit
  123. diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$?
  124. set -o errexit
  125. case $diff in
  126. 0) echo No changes to files in $deploy_directory. Skipping commit.;;
  127. 1) commit+push;;
  128. *)
  129. 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
  130. return $diff
  131. ;;
  132. esac
  133. }
  134. commit+push() {
  135. set_user_id
  136. git --work-tree "$deploy_directory" commit -m "$commit_message"
  137. disable_expanded_output
  138. #--quiet is important here to avoid outputting the repo URL, which may contain a secret token
  139. git push --quiet $repo $deploy_branch
  140. enable_expanded_output
  141. }
  142. #echo expanded commands as they are executed (for debugging)
  143. enable_expanded_output() {
  144. if [ $verbose ]; then
  145. set -o xtrace
  146. set +o verbose
  147. fi
  148. }
  149. #this is used to avoid outputting the repo URL, which may contain a secret token
  150. disable_expanded_output() {
  151. if [ $verbose ]; then
  152. set +o xtrace
  153. set -o verbose
  154. fi
  155. }
  156. set_user_id() {
  157. if [[ -z `git config user.name` ]]; then
  158. git config user.name "$default_username"
  159. fi
  160. if [[ -z `git config user.email` ]]; then
  161. git config user.email "$default_email"
  162. fi
  163. }
  164. restore_head() {
  165. if [[ $previous_branch = "HEAD" ]]; then
  166. #we weren't on any branch before, so just set HEAD back to the commit it was on
  167. git update-ref --no-deref HEAD $commit_hash $deploy_branch
  168. else
  169. git symbolic-ref HEAD refs/heads/$previous_branch
  170. fi
  171. git reset --mixed
  172. }
  173. filter() {
  174. sed -e "s|$repo|\$repo|g"
  175. }
  176. sanitize() {
  177. "$@" 2> >(filter 1>&2) | filter
  178. }
  179. parse_args "$@"
  180. if [[ ${source_only} ]]; then
  181. run_build
  182. elif [[ ${push_only} ]]; then
  183. main "$@"
  184. else
  185. run_build
  186. main "$@"
  187. fi