11#! /usr/bin/env bash
22#
3- # According to the GitLab flow release branching model,
4- # cherry-pick the last commit on the main branch to the release branch,
5- # and then create a tag and gem package on the release branch (naming format: 'release/<X.Y>').
3+ # Release a new version to the GitLab flow production branch.
64#
5+ # For a new major/minor version, bump version on the main branch, and then merge into the production branch.
76#
8- # Usage:
7+ # For a patch version, bump the version number on the patch branch, then merge that branch into the main branch
8+ # and production branch.
99#
10- # It can be run on main branch, and it should be used after just finishing the last feature in the version plan,
11- # or just after merging the hotfix to the main branch.
1210#
13- # Requires: Git, Gulp
11+ # Usage: run on main branch or the patch branch
12+ #
13+ # Requires: Git, Node.js, NPX and RubyGems
1414
1515set -eu
1616
17+ opt_pre=false # preview mode option
18+
19+ working_branch=" $( git branch --show-current) "
20+
21+ STAGING_BRANCH=" $( git symbolic-ref refs/remotes/origin/HEAD | sed ' s@^refs/remotes/origin/@@' ) "
22+
23+ PROD_BRANCH=" production"
24+
1725GEM_SPEC=" jekyll-theme-chirpy.gemspec"
1826
19- opt_pre=false
27+ NODE_CONFIG=" package.json"
28+
29+ FILES=(
30+ " _sass/jekyll-theme-chirpy.scss"
31+ " _javascript/copyright"
32+ " $GEM_SPEC "
33+ " $NODE_CONFIG "
34+ )
35+
36+ TOOLS=(
37+ " git"
38+ " npm"
39+ " npx"
40+ " gem"
41+ )
2042
2143help () {
2244 echo " A tool to release new version Chirpy gem"
@@ -26,19 +48,85 @@ help() {
2648 echo " bash ./tools/release.sh [options]"
2749 echo
2850 echo " Options:"
29- echo " -p, --preview Enable preview mode, only pakcage , and will not modify the branches"
51+ echo " -p, --preview Enable preview mode, only package , and will not modify the branches"
3052 echo " -h, --help Print this information."
3153}
3254
33- check () {
55+ _check_git () {
56+ # ensure nothing is uncommitted
3457 if [[ -n $( git status . -s) ]]; then
35- echo " Error : Commit unstaged files first, and then run this tool againt ."
36- exit - 1
58+ echo " Abort : Commit the staged files first, and then run this tool again ."
59+ exit 1
3760 fi
3861
39- if [[ ! -f $GEM_SPEC ]]; then
40- echo -e " Error: Missing file \" $GEM_SPEC \" !\n"
41- exit -1
62+ # ensure the working branch is the main/patch branch
63+ if [[ $working_branch != " $STAGING_BRANCH " && $working_branch != hotfix/* ]]; then
64+ echo " Abort: Please run on the main branch or patch branches."
65+ exit 1
66+ fi
67+ }
68+
69+ _check_src () {
70+ if [[ ! -f $1 && ! -d $1 ]]; then
71+ echo -e " Error: Missing file \" $1 \" !\n"
72+ exit 1
73+ fi
74+ }
75+
76+ _check_command () {
77+ if ! command -v " $1 " & > /dev/null; then
78+ echo " Command '$1 ' not found"
79+ exit 1
80+ fi
81+ }
82+
83+ _check_node_packages () {
84+ if [[ ! -d node_modules || " $( du node_modules | awk ' {print $1}' ) " == " 0" ]]; then
85+ npm i
86+ fi
87+ }
88+
89+ check () {
90+ _check_git
91+
92+ for i in " ${! FILES[@]} " ; do
93+ _check_src " ${FILES[$i]} "
94+ done
95+
96+ for i in " ${! TOOLS[@]} " ; do
97+ _check_command " ${TOOLS[$i]} "
98+ done
99+
100+ _check_node_packages
101+ }
102+
103+ _bump_file () {
104+ for i in " ${! FILES[@]} " ; do
105+ sed -i " s/v[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+/v$1 /" " ${FILES[$i]} "
106+ done
107+
108+ npx gulp
109+ }
110+
111+ _bump_gemspec () {
112+ sed -i " s/[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+/$1 /" " $GEM_SPEC "
113+ }
114+
115+ # 1. Bump latest version number to the following files:
116+ #
117+ # - _sass/jekyll-theme-chirpy.scss
118+ # - _javascript/copyright
119+ # - assets/js/dist/*.js (will be built by gulp later)
120+ # - jekyll-theme-chirpy.gemspec
121+ #
122+ # 2. Create a commit to save the changes.
123+ bump () {
124+ _bump_file " $1 "
125+ _bump_gemspec " $1 "
126+
127+ if [[ $opt_pre = false && -n $( git status . -s) ]]; then
128+ git add .
129+ git commit -m " chore(release): $1 "
42130 fi
43131}
44132
@@ -52,39 +140,95 @@ resume_config() {
52140 mv _config.yml.bak _config.yml
53141}
54142
55- release () {
56- _default_branch=" $( git symbolic-ref refs/remotes/origin/HEAD | sed ' s@^refs/remotes/origin/@@' ) "
57- _version=" $( grep " spec.version" jekyll-theme-chirpy.gemspec | sed ' s/.*= "//;s/".*//' ) " # X.Y.Z
58- _release_branch=" release/${_version% .* } "
59-
60- if [[ $opt_pre = " false" ]]; then
61- # Modify the GitLab release branches
62- if [[ -z $( git branch -v | grep " $_release_branch " ) ]]; then
63- # create a new release branch
64- git checkout -b " $_release_branch "
65- else
66- # cherry-pick the latest commit from default branch to release branch
67- _last_commit=" $( git rev-parse " $_default_branch " ) "
68- git checkout " $_release_branch "
69- git cherry-pick " $_last_commit " -m 1
70- fi
71-
72- # Create a new tag
73- echo -e " Create tag v$_version \n"
74- git tag " v$_version "
143+ # auto-generate a new version number to the file 'package.json'
144+ standard_version () {
145+ if $opt_pre ; then
146+ npx standard-version --prerelease rc
147+ else
148+ npx standard-version
75149 fi
150+ }
151+
152+ # Prevent changelogs generated on master branch from having duplicate content
153+ # (the another bug of `standard-version`)
154+ standard_version_plus () {
155+ temp_branch=" prod-mirror"
156+ temp_dir=" $( mktemp -d) "
157+
158+ git checkout -b " $temp_branch " " $PROD_BRANCH "
159+ git merge --no-ff --no-edit " $STAGING_BRANCH "
76160
77- # build a gem package
78- echo -e " Build the gem pakcage for v$_version \n"
161+ standard_version
162+
163+ cp package.json CHANGELOG.md " $temp_dir "
164+
165+ git checkout " $STAGING_BRANCH "
166+ git reset --hard HEAD # undo the changes from $temp_branch
167+ mv " $temp_dir " /* . # rewrite the changelog
168+
169+ # clean up the temp stuff
170+ rm -rf " $temp_dir "
171+ git branch -D " $temp_branch "
172+ }
173+
174+ # build a gem package
175+ build_gem () {
176+ echo -e " Build the gem package for v$_version \n"
79177 cleanup_config
80178 rm -f ./* .gem
81179 gem build " $GEM_SPEC "
82180 resume_config
83181}
84182
183+ # Update the git branch graph, tag, and then build the gem package.
184+ release () {
185+ _version=" $1 " # X.Y.Z
186+
187+ if $opt_pre ; then
188+ $opt_pre
189+ exit 0
190+ fi
191+
192+ git checkout " $PROD_BRANCH "
193+ git merge --no-ff --no-edit " $working_branch "
194+
195+ # Create a new tag on production branch
196+ echo -e " Create tag v$_version \n"
197+ git tag " v$_version "
198+
199+ build_gem
200+
201+ # merge from patch branch to the staging branch
202+ # NOTE: This may break due to merge conflicts, so it may need to be resolved manually.
203+ if [[ $working_branch == hotfix/* ]]; then
204+ git checkout " $STAGING_BRANCH "
205+ git merge --no-ff --no-edit " $working_branch "
206+ git branch -D " $working_branch "
207+ fi
208+ }
209+
85210main () {
86211 check
87- release
212+
213+ if [[ " $working_branch " == " $STAGING_BRANCH " ]]; then
214+ standard_version_plus
215+ else
216+ standard_version
217+ fi
218+
219+ # Change heading of Patch version to level 2 (a bug from `standard-version`)
220+ sed -i " s/^### \[/## \[/g" CHANGELOG.md
221+
222+ _version=" $( grep ' "version":' package.json | sed ' s/.*: "//;s/".*//' ) "
223+
224+ echo -e " Bump version number to $_version \n"
225+ bump " $_version "
226+
227+ release " $_version "
228+
229+ # Undo all changes on Git
230+ $opt_pre && git reset --hard && git clean -fd
231+
88232}
89233
90234while (( $# )) ; do
0 commit comments