123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #!/bin/bash
  2. . "$MKIT_DIR/include/ini.sh" || die "cannot import ini.sh"
  3. . "$MKIT_DIR/include/facts.sh" || die "cannot import facts.sh"
  4. _bump_version() {
  5. #
  6. # Bump version on stdin by level $1 (x, y or z)
  7. #
  8. local rlevel=$1 # release level
  9. local old # old version
  10. local oldx # ... X
  11. local oldz # ... Z
  12. local oldy # ... Y
  13. local tmpy # Y parsing cache
  14. local new # bumped version
  15. read -r old
  16. oldx=${old%.*.*}
  17. oldz=${old#*.*.}
  18. tmpy=${old%.*}
  19. oldy=${tmpy#*.}
  20. case $rlevel in
  21. x) new="$((oldx+MKIT_BUMPSIZE)).0.0" ;;
  22. y) new="$oldx.$((oldy+MKIT_BUMPSIZE)).0" ;;
  23. z) new="$oldx.$oldy.$((oldz+MKIT_BUMPSIZE))" ;;
  24. *) die "invalid release level: $1" ;;
  25. esac
  26. echo "$new"
  27. }
  28. _relck() {
  29. #
  30. # Die if blocking condition $1 is detected
  31. #
  32. local condition=$1 # condition name
  33. local oracle # expected value
  34. case "$condition" in
  35. git_present)
  36. git rev-parse HEAD >&/dev/null\
  37. || die "cannot do this outside git repo"
  38. ;;
  39. at_relsrc)
  40. oracle=$(ini 1value project:relsrc)
  41. git_fact current_branch \
  42. | grep -qFx "$oracle" \
  43. || die "you are not on release source branch: $oracle"
  44. ;;
  45. not_dirty)
  46. git diff --shortstat 2>/dev/null \
  47. | grep -q . \
  48. && die "tree is dirty!"
  49. ;;
  50. tags_ok)
  51. git_fact latest_tag \
  52. | grep -q . \
  53. || die "cannot find latest tag"
  54. ;;
  55. vbump_hot)
  56. git diff-tree --no-commit-id --name-only -r HEAD \
  57. | grep -qFx mkit.ini \
  58. || die "last change must be version bump in mkit.ini"
  59. ;;
  60. no_wip)
  61. git_fact reldiff \
  62. | grep '^....... WIP ' \
  63. && die "WIP commit since $(git_fact latest_tag)"
  64. ;;
  65. ini_version)
  66. oracle=$(git_fact latest_version | _bump_version "$rlevel")
  67. ini 1value project:version \
  68. | grep -qFx "$oracle" \
  69. || die "new version not in mkit.ini: $oracle"
  70. ;;
  71. *)
  72. die "unknown release check: $condition"
  73. ;;
  74. esac
  75. }
  76. _release() {
  77. #
  78. # Prepare release
  79. #
  80. # Span release routines: make a signed tag, check branch
  81. # and update release branch
  82. #
  83. # FIXME: Using project:prerl as build.sh:semver() does may not be
  84. # compatible with this release strategy
  85. #
  86. local rlevel=$1 # release level (x, y or z)
  87. local newtag # new tag
  88. local reldst # release destination branch (if any)
  89. _relck git_present
  90. _relck at_relsrc
  91. _relck not_dirty
  92. _relck tags_ok
  93. _relck vbump_hot
  94. _relck no_wip
  95. _relck ini_version
  96. newtag=$(git_fact latest_version | _bump_version "$rlevel" | git_ver2tag )
  97. set -e
  98. debug_var newtag
  99. $MKIT_DRY && return
  100. git tag -m "$(_release_msg)" "$newtag"
  101. reldst=$(ini 1value project:reldst)
  102. debug_var reldst
  103. if test -n "$reldst"; then
  104. git branch -f "$reldst" "$newtag"
  105. fi
  106. }
  107. _release_msg() {
  108. #
  109. # Generate message for annotated tag
  110. #
  111. # The last commit before issuing a release must be "Bump version" commit
  112. # suggested by _vbump_gitmsg() and manually edited by user. Since the
  113. # commit contains changelog, this function just uses the message body.
  114. #
  115. # The sort message (first line) is replaced with a nicer one (with project
  116. # name, codename and version).
  117. #
  118. echo "$(ini 1value project:name) $newtag - $(ini 1value project:codename)"
  119. echo
  120. git show -s --format=%B \
  121. | tail -n +3
  122. }
  123. _vbump() {
  124. #
  125. # Do version bump at level $1
  126. #
  127. # Perform checks, compute new version, update mkit.ini and initiate
  128. # 'Bump version' commit with changelog template.
  129. #
  130. local rlevel=$1 # bump level (x, y or z)
  131. local nextver # version after the bump
  132. _relck git_present
  133. _relck at_relsrc
  134. _relck not_dirty
  135. nextver=$(ini 1value project:version | _bump_version "$rlevel")
  136. debug_var nextver
  137. $MKIT_DRY && return
  138. update_version "$nextver" mkit.ini \
  139. || die "failed to update version in mkit.ini"
  140. git add mkit.ini \
  141. || die "failed to add mkit.ini to the index"
  142. git commit -e -m "$(_vbump_gitmsg)"
  143. }
  144. _vbump_gitmsg() {
  145. #
  146. # Compose git message template for 'Bump version' commit
  147. #
  148. echo "Bump version"
  149. echo ""
  150. echo "Overview of changes:"
  151. echo ""
  152. git_fact reldiff \
  153. | sed '
  154. s/^[a-f0-9]\{7\} / * &/; t PATHS
  155. s/^/ /
  156. :PATHS
  157. '
  158. }
  159. release_x() {
  160. #
  161. # Perform release on X level
  162. #
  163. _release x
  164. }
  165. release_y() {
  166. #
  167. # Perform release on Y level
  168. #
  169. _release y
  170. }
  171. release_z() {
  172. #
  173. # Perform release on Z level
  174. #
  175. _release z
  176. }
  177. vbump_x() {
  178. #
  179. # Perform version bump on X level
  180. #
  181. _vbump x
  182. }
  183. vbump_y() {
  184. #
  185. # Perform version bump on Y level
  186. #
  187. _vbump y
  188. }
  189. vbump_z() {
  190. #
  191. # Perform version bump on Z level
  192. #
  193. _vbump z
  194. }