From 42fe8f5d2129d1e1b43e95a1f4bdbbfeccfc561c Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Tue, 1 Mar 2022 23:24:51 +0800 Subject: [PATCH] build(shell): update release tool to work with `standard-version` --- tools/bump.sh | 106 ---------------------- tools/release.sh | 222 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 183 insertions(+), 145 deletions(-) delete mode 100755 tools/bump.sh diff --git a/tools/bump.sh b/tools/bump.sh deleted file mode 100755 index 0824bc8..0000000 --- a/tools/bump.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env bash -# -# -# 1. Bump latest version number to the following files: -# -# - _sass/jekyll-theme-chirpy.scss -# - _javascript/copyright -# - assets/js/dist/*.js (will be built by gulp later) -# - jekyll-theme-chirpy.gemspec -# - package.json -# -# 2. Then create a commit to automatically save the changes. -# -# Usage: -# -# Run on the default branch or hotfix branch -# -# Requires: Git, Gulp - -set -eu - -ASSETS=( - "_sass/jekyll-theme-chirpy.scss" - "_javascript/copyright" -) - -GEM_SPEC="jekyll-theme-chirpy.gemspec" - -NODE_META="package.json" - -_check_src() { - if [[ ! -f $1 && ! -d $1 ]]; then - echo -e "Error: Missing file \"$1\"!\n" - exit -1 - fi -} - -check() { - if [[ -n $(git status . -s) ]]; then - echo "Error: Commit unstaged files first, and then run this tool againt." - exit -1 - fi - - for i in "${!ASSETS[@]}"; do - _check_src "${ASSETS[$i]}" - done - - _check_src "$NODE_META" - _check_src "$GEM_SPEC" -} - -_bump_assets() { - for i in "${!ASSETS[@]}"; do - sed -i "s/v[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+/v$1/" "${ASSETS[$i]}" - done - - gulp -} - -_bump_gemspec() { - sed -i "s/[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+/$1/" "$GEM_SPEC" -} - -_bump_node() { - sed -i \ - "s,[\"]version[\"]: [\"][[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+[\"],\"version\": \"$1\"," \ - $NODE_META -} - -bump() { - _bump_assets "$1" - _bump_gemspec "$1" - _bump_node "$1" - - if [[ -n $(git status . -s) ]]; then - git add . - git commit -m "Bump version to $1" - fi -} - -main() { - check - - _latest_tag="$(git describe --tags $(git rev-list --tags --max-count=1))" - - echo "Input a version number (hint: latest version is ${_latest_tag:1})" - - read -p "> " _version - - [[ $_version =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]$ ]] || - ( - echo "Error: Illegal version number: '$_version'" - exit 1 - ) - - if git tag --list | egrep -q "^v$_version$"; then - echo "Error: version '$_version' already exists" - exit 1 - fi - - echo -e "Bump version to $_version\n" - bump "$_version" - -} - -main diff --git a/tools/release.sh b/tools/release.sh index a067141..99e462e 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -1,22 +1,44 @@ #!/usr/bin/env bash # -# According to the GitLab flow release branching model, -# cherry-pick the last commit on the main branch to the release branch, -# and then create a tag and gem package on the release branch (naming format: 'release/'). +# Release a new version to the GitLab flow production branch. +# +# For a new major/minor version, bump version on the main branch, and then merge into the production branch. +# +# For a patch version, bump the version number on the patch branch, then merge that branch into the main branch +# and production branch. # # -# Usage: +# Usage: run on main branch or the patch branch # -# It can be run on main branch, and it should be used after just finishing the last feature in the version plan, -# or just after merging the hotfix to the main branch. -# -# Requires: Git, Gulp +# Requires: Git, Node.js, NPX and RubyGems set -eu +opt_pre=false # preview mode option + +working_branch="$(git branch --show-current)" + +STAGING_BRANCH="$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@')" + +PROD_BRANCH="production" + GEM_SPEC="jekyll-theme-chirpy.gemspec" -opt_pre=false +NODE_CONFIG="package.json" + +FILES=( + "_sass/jekyll-theme-chirpy.scss" + "_javascript/copyright" + "$GEM_SPEC" + "$NODE_CONFIG" +) + +TOOLS=( + "git" + "npm" + "npx" + "gem" +) help() { echo "A tool to release new version Chirpy gem" @@ -26,19 +48,85 @@ help() { echo " bash ./tools/release.sh [options]" echo echo "Options:" - echo " -p, --preview Enable preview mode, only pakcage, and will not modify the branches" + echo " -p, --preview Enable preview mode, only package, and will not modify the branches" echo " -h, --help Print this information." } -check() { +_check_git() { + # ensure nothing is uncommitted if [[ -n $(git status . -s) ]]; then - echo "Error: Commit unstaged files first, and then run this tool againt." - exit -1 + echo "Abort: Commit the staged files first, and then run this tool again." + exit 1 fi - if [[ ! -f $GEM_SPEC ]]; then - echo -e "Error: Missing file \"$GEM_SPEC\"!\n" - exit -1 + # ensure the working branch is the main/patch branch + if [[ $working_branch != "$STAGING_BRANCH" && $working_branch != hotfix/* ]]; then + echo "Abort: Please run on the main branch or patch branches." + exit 1 + fi +} + +_check_src() { + if [[ ! -f $1 && ! -d $1 ]]; then + echo -e "Error: Missing file \"$1\"!\n" + exit 1 + fi +} + +_check_command() { + if ! command -v "$1" &>/dev/null; then + echo "Command '$1' not found" + exit 1 + fi +} + +_check_node_packages() { + if [[ ! -d node_modules || "$(du node_modules | awk '{print $1}')" == "0" ]]; then + npm i + fi +} + +check() { + _check_git + + for i in "${!FILES[@]}"; do + _check_src "${FILES[$i]}" + done + + for i in "${!TOOLS[@]}"; do + _check_command "${TOOLS[$i]}" + done + + _check_node_packages +} + +_bump_file() { + for i in "${!FILES[@]}"; do + sed -i "s/v[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+/v$1/" "${FILES[$i]}" + done + + npx gulp +} + +_bump_gemspec() { + sed -i "s/[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+/$1/" "$GEM_SPEC" +} + +# 1. Bump latest version number to the following files: +# +# - _sass/jekyll-theme-chirpy.scss +# - _javascript/copyright +# - assets/js/dist/*.js (will be built by gulp later) +# - jekyll-theme-chirpy.gemspec +# +# 2. Create a commit to save the changes. +bump() { + _bump_file "$1" + _bump_gemspec "$1" + + if [[ $opt_pre = false && -n $(git status . -s) ]]; then + git add . + git commit -m "chore(release): $1" fi } @@ -52,39 +140,95 @@ resume_config() { mv _config.yml.bak _config.yml } -release() { - _default_branch="$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@')" - _version="$(grep "spec.version" jekyll-theme-chirpy.gemspec | sed 's/.*= "//;s/".*//')" # X.Y.Z - _release_branch="release/${_version%.*}" - - if [[ $opt_pre = "false" ]]; then - # Modify the GitLab release branches - if [[ -z $(git branch -v | grep "$_release_branch") ]]; then - # create a new release branch - git checkout -b "$_release_branch" - else - # cherry-pick the latest commit from default branch to release branch - _last_commit="$(git rev-parse "$_default_branch")" - git checkout "$_release_branch" - git cherry-pick "$_last_commit" -m 1 - fi - - # Create a new tag - echo -e "Create tag v$_version\n" - git tag "v$_version" +# auto-generate a new version number to the file 'package.json' +standard_version() { + if $opt_pre; then + npx standard-version --prerelease rc + else + npx standard-version fi +} - # build a gem package - echo -e "Build the gem pakcage for v$_version\n" +# Prevent changelogs generated on master branch from having duplicate content +# (the another bug of `standard-version`) +standard_version_plus() { + temp_branch="prod-mirror" + temp_dir="$(mktemp -d)" + + git checkout -b "$temp_branch" "$PROD_BRANCH" + git merge --no-ff --no-edit "$STAGING_BRANCH" + + standard_version + + cp package.json CHANGELOG.md "$temp_dir" + + git checkout "$STAGING_BRANCH" + git reset --hard HEAD # undo the changes from $temp_branch + mv "$temp_dir"/* . # rewrite the changelog + + # clean up the temp stuff + rm -rf "$temp_dir" + git branch -D "$temp_branch" +} + +# build a gem package +build_gem() { + echo -e "Build the gem package for v$_version\n" cleanup_config rm -f ./*.gem gem build "$GEM_SPEC" resume_config } +# Update the git branch graph, tag, and then build the gem package. +release() { + _version="$1" # X.Y.Z + + if $opt_pre; then + $opt_pre + exit 0 + fi + + git checkout "$PROD_BRANCH" + git merge --no-ff --no-edit "$working_branch" + + # Create a new tag on production branch + echo -e "Create tag v$_version\n" + git tag "v$_version" + + build_gem + + # merge from patch branch to the staging branch + # NOTE: This may break due to merge conflicts, so it may need to be resolved manually. + if [[ $working_branch == hotfix/* ]]; then + git checkout "$STAGING_BRANCH" + git merge --no-ff --no-edit "$working_branch" + git branch -D "$working_branch" + fi +} + main() { check - release + + if [[ "$working_branch" == "$STAGING_BRANCH" ]]; then + standard_version_plus + else + standard_version + fi + + # Change heading of Patch version to level 2 (a bug from `standard-version`) + sed -i "s/^### \[/## \[/g" CHANGELOG.md + + _version="$(grep '"version":' package.json | sed 's/.*: "//;s/".*//')" + + echo -e "Bump version number to $_version\n" + bump "$_version" + + release "$_version" + + # Undo all changes on Git + $opt_pre && git reset --hard && git clean -fd + } while (($#)); do