1*437bfbebSnyanmisaka#!/bin/bash 2*437bfbebSnyanmisaka## Author LinkinStar / HermanChen 3*437bfbebSnyanmisaka 4*437bfbebSnyanmisaka# solve the space by IFS 5*437bfbebSnyanmisakaOLDIFS=$IFS 6*437bfbebSnyanmisakaIFS=`echo -en "\n\b"` 7*437bfbebSnyanmisakaecho -en $IFS 8*437bfbebSnyanmisaka 9*437bfbebSnyanmisakadeclare -g changelog_file="CHANGELOG.md" 10*437bfbebSnyanmisakadeclare -g git_repo_rootdir 11*437bfbebSnyanmisakadeclare -g current_tag 12*437bfbebSnyanmisakadeclare -g previous_tag 13*437bfbebSnyanmisakadeclare -g prev_changelog 14*437bfbebSnyanmisakadeclare -g prev_changelog_version 15*437bfbebSnyanmisakadeclare -g prev_tag 16*437bfbebSnyanmisakadeclare -g curr_tag 17*437bfbebSnyanmisaka 18*437bfbebSnyanmisaka# changelog version define 19*437bfbebSnyanmisakadeclare -g version_tag 20*437bfbebSnyanmisaka 21*437bfbebSnyanmisakafunction log_filter_and_print() { 22*437bfbebSnyanmisaka local title=$1 23*437bfbebSnyanmisaka local prefix=$2 24*437bfbebSnyanmisaka local -a msgs=() 25*437bfbebSnyanmisaka local msg_cnt=0 26*437bfbebSnyanmisaka local prefix_len=${#prefix} 27*437bfbebSnyanmisaka 28*437bfbebSnyanmisaka # filter log and find the matched prefix number 29*437bfbebSnyanmisaka for msg in ${orig_logs[@]} 30*437bfbebSnyanmisaka do 31*437bfbebSnyanmisaka if [[ $msg == "$prefix"* ]]; then 32*437bfbebSnyanmisaka msgs[msg_cnt]=$msg 33*437bfbebSnyanmisaka let msg_cnt++ 34*437bfbebSnyanmisaka 35*437bfbebSnyanmisaka echo "$prefix commit $msg_cnt - ${msg}" 36*437bfbebSnyanmisaka fi 37*437bfbebSnyanmisaka done 38*437bfbebSnyanmisaka 39*437bfbebSnyanmisaka if [ $msg_cnt -gt 0 ]; then 40*437bfbebSnyanmisaka echo -e "### $title" >> ${changelog_file} 41*437bfbebSnyanmisaka 42*437bfbebSnyanmisaka for msg in ${msgs[@]} 43*437bfbebSnyanmisaka do 44*437bfbebSnyanmisaka # check log mode 45*437bfbebSnyanmisaka local pos=$prefix_len 46*437bfbebSnyanmisaka local log 47*437bfbebSnyanmisaka 48*437bfbebSnyanmisaka # message mode: prefix: xxxx 49*437bfbebSnyanmisaka log=$(echo $msg | grep -i "^$prefix:") 50*437bfbebSnyanmisaka #echo "pos $pos log $log" 51*437bfbebSnyanmisaka if [ "$log" != "" ]; then 52*437bfbebSnyanmisaka let pos++ 53*437bfbebSnyanmisaka fi 54*437bfbebSnyanmisaka 55*437bfbebSnyanmisaka # remove extra space 56*437bfbebSnyanmisaka log=$(echo ${msg:$pos} | sed -e 's/^[ ]*//g' | sed -e 's/[ ]*$//g') 57*437bfbebSnyanmisaka echo -e "- $log" >> ${changelog_file} 58*437bfbebSnyanmisaka done 59*437bfbebSnyanmisaka 60*437bfbebSnyanmisaka echo -e "" >> ${changelog_file} 61*437bfbebSnyanmisaka fi 62*437bfbebSnyanmisaka} 63*437bfbebSnyanmisaka 64*437bfbebSnyanmisakausage="changelog helper script 65*437bfbebSnyanmisaka use -t / --version to create a new tag commit and update CHANGELOG.md 66*437bfbebSnyanmisaka by insert new version on top, 67*437bfbebSnyanmisaka 68*437bfbebSnyanmisaka the basic commit message should be structured as follows: 69*437bfbebSnyanmisaka <type>[optional scope]: <description> 70*437bfbebSnyanmisaka [optional body] 71*437bfbebSnyanmisaka [optional footer(s)] 72*437bfbebSnyanmisaka 73*437bfbebSnyanmisaka Type 74*437bfbebSnyanmisaka Must be one of the following: 75*437bfbebSnyanmisaka feat: A new feature 76*437bfbebSnyanmisaka fix: A bug fix 77*437bfbebSnyanmisaka docs: Documentation only changes 78*437bfbebSnyanmisaka style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) 79*437bfbebSnyanmisaka refactor: A code change that neither fixes a bug nor adds a feature 80*437bfbebSnyanmisaka perf: A code change that improves performance 81*437bfbebSnyanmisaka test: Adding missing or correcting existing tests 82*437bfbebSnyanmisaka chore: Changes to the build process or auxiliary tools and libraries such as documentation generation 83*437bfbebSnyanmisaka 84*437bfbebSnyanmisaka https://www.conventionalcommits.org/zh-hans/v1.0.0/ 85*437bfbebSnyanmisaka 86*437bfbebSnyanmisaka .option('-t, --version', 'create a version tag with changelog update') 87*437bfbebSnyanmisaka .option('-f, --file [file]', 'file to write to, defaults to ./CHANGELOG.md, use - for stdout', './CHANGELOG.md') 88*437bfbebSnyanmisaka .option('-u, --repo-url [url]', 'specify the repo URL for commit links') 89*437bfbebSnyanmisaka" 90*437bfbebSnyanmisaka 91*437bfbebSnyanmisakawhile [ $# -gt 0 ]; do 92*437bfbebSnyanmisaka case $1 in 93*437bfbebSnyanmisaka --help | -h) 94*437bfbebSnyanmisaka echo "$usage" 95*437bfbebSnyanmisaka exit 1 96*437bfbebSnyanmisaka ;; 97*437bfbebSnyanmisaka --version | -t) 98*437bfbebSnyanmisaka version_tag=$2 99*437bfbebSnyanmisaka shift 100*437bfbebSnyanmisaka ;; 101*437bfbebSnyanmisaka --file | -f) 102*437bfbebSnyanmisaka changelog_file=$2 103*437bfbebSnyanmisaka echo "save changelog to file ${changelog_file}" 104*437bfbebSnyanmisaka shift 105*437bfbebSnyanmisaka ;; 106*437bfbebSnyanmisaka --repo-url | -u) 107*437bfbebSnyanmisaka git_repo_rootdir=$2 108*437bfbebSnyanmisaka echo "set repo rootdir to ${git_repo_rootdir}" 109*437bfbebSnyanmisaka shift 110*437bfbebSnyanmisaka ;; 111*437bfbebSnyanmisaka *) 112*437bfbebSnyanmisaka # skip invalid option 113*437bfbebSnyanmisaka shift 114*437bfbebSnyanmisaka ;; 115*437bfbebSnyanmisaka esac 116*437bfbebSnyanmisaka shift 117*437bfbebSnyanmisakadone 118*437bfbebSnyanmisaka 119*437bfbebSnyanmisaka# check git command 120*437bfbebSnyanmisakaif ! command -v git >/dev/null; then 121*437bfbebSnyanmisaka >&2 echo "ERROR: git command is not available" 122*437bfbebSnyanmisaka echo "$usage" 123*437bfbebSnyanmisaka exit 1 124*437bfbebSnyanmisakafi 125*437bfbebSnyanmisaka 126*437bfbebSnyanmisaka# if repo root is not set set sefault repo root 127*437bfbebSnyanmisakaif [ -z $git_repo_rootdir ]; then 128*437bfbebSnyanmisaka git_repo_rootdir=$(git rev-parse --show-toplevel 2>/dev/null) 129*437bfbebSnyanmisakafi 130*437bfbebSnyanmisaka 131*437bfbebSnyanmisaka# check repo root valid or not 132*437bfbebSnyanmisakaif [ -z ${git_repo_rootdir} ] || [ ! -d ${git_repo_rootdir} ]; then 133*437bfbebSnyanmisaka echo "ERROR: can not found repo root" 134*437bfbebSnyanmisaka echo "$usage" 135*437bfbebSnyanmisaka exit 1 136*437bfbebSnyanmisakafi 137*437bfbebSnyanmisaka 138*437bfbebSnyanmisaka# cd to rootdir 139*437bfbebSnyanmisakacd $git_repo_rootdir 140*437bfbebSnyanmisaka 141*437bfbebSnyanmisaka# check version tag exist or not 142*437bfbebSnyanmisakaif [ -z ${version_tag} ]; then 143*437bfbebSnyanmisaka echo "ERROR: can not run without a new version tag" 144*437bfbebSnyanmisaka echo "$usage" 145*437bfbebSnyanmisaka exit 1 146*437bfbebSnyanmisakafi 147*437bfbebSnyanmisaka 148*437bfbebSnyanmisakatag_log=$(git tag -v ${version_tag} | grep object) 149*437bfbebSnyanmisakaif [ ! -z ${tag_log} ]; then 150*437bfbebSnyanmisaka echo "ERROR: can not run with an existing tag ${version_tag}" 151*437bfbebSnyanmisaka echo "$usage" 152*437bfbebSnyanmisaka exit 1 153*437bfbebSnyanmisakafi 154*437bfbebSnyanmisaka 155*437bfbebSnyanmisaka# create new tag with empty commit 156*437bfbebSnyanmisakagit commit --allow-empty -s -m "docs: Update ${version_tag} CHANGELOG.md" 157*437bfbebSnyanmisakatag_date=`date '+%Y-%m-%d'` 158*437bfbebSnyanmisakagit tag ${version_tag} -m "${version_tag} version at ${tag_date}" 159*437bfbebSnyanmisaka 160*437bfbebSnyanmisaka# if changelog file is not exist then create it 161*437bfbebSnyanmisakaif [[ ! -f ${changelog_file} ]]; then 162*437bfbebSnyanmisaka touch ${changelog_file} 163*437bfbebSnyanmisakaelse 164*437bfbebSnyanmisaka # get old changelog 165*437bfbebSnyanmisaka prev_changelog=$(cat $changelog_file) 166*437bfbebSnyanmisaka prev_changelog_version=$(echo $prev_changelog | grep -E "## *.*.* *" | head -1 | awk '{ print $2 }') 167*437bfbebSnyanmisaka 168*437bfbebSnyanmisaka rm -rf ${changelog_file} 169*437bfbebSnyanmisaka touch ${changelog_file} 170*437bfbebSnyanmisakafi 171*437bfbebSnyanmisaka 172*437bfbebSnyanmisaka# get current version info 173*437bfbebSnyanmisakacurr_ver=$(git describe --tags --long) 174*437bfbebSnyanmisakacurr_tag=$(git describe --tags --abbrev=0) 175*437bfbebSnyanmisakaprev_tag=$(git describe --tags --abbrev=0 "$curr_tag"^) 176*437bfbebSnyanmisakadate="$(date '+%Y-%m-%d')" 177*437bfbebSnyanmisaka 178*437bfbebSnyanmisakaecho "curr ver: ${curr_ver}" 179*437bfbebSnyanmisakaecho "curr tag: ${curr_tag}" 180*437bfbebSnyanmisakaecho "prev tag: ${prev_tag}" 181*437bfbebSnyanmisaka 182*437bfbebSnyanmisaka# dump log between two tags 183*437bfbebSnyanmisakaorig_logs=$(git log --pretty="%s" --no-merges $curr_tag...$prev_tag) 184*437bfbebSnyanmisakaecho "commits: from ${prev_tag} to ${curr_tag}" 185*437bfbebSnyanmisakaecho "${orig_logs}" 186*437bfbebSnyanmisaka 187*437bfbebSnyanmisaka# check unreleased version number 188*437bfbebSnyanmisakaunreleased_count=$(echo ${curr_ver} | grep -E "## *.*.* *" | head -1 | awk -F "-" '{ printf $2 }') 189*437bfbebSnyanmisakaecho "unreleased version count: ${unreleased_count}" 190*437bfbebSnyanmisaka 191*437bfbebSnyanmisaka# write unreleased information 192*437bfbebSnyanmisakaif [ "$unreleased_count" ] && [ $unreleased_count -gt 0 ]; then 193*437bfbebSnyanmisaka echo -e "## Unreleased (${date})\n" >> ${changelog_file} 194*437bfbebSnyanmisaka 195*437bfbebSnyanmisaka unreleased_logs=$(git log --pretty="%s" --no-merges HEAD...$curr_tag) 196*437bfbebSnyanmisaka for msg in ${unreleased_logs[@]} 197*437bfbebSnyanmisaka do 198*437bfbebSnyanmisaka echo -e "- ${msg}" >> ${changelog_file} 199*437bfbebSnyanmisaka done 200*437bfbebSnyanmisaka 201*437bfbebSnyanmisaka echo -e "" >> ${changelog_file} 202*437bfbebSnyanmisakaelse 203*437bfbebSnyanmisaka echo -e "## $curr_tag ($date)" >> ${changelog_file} 204*437bfbebSnyanmisakafi 205*437bfbebSnyanmisaka 206*437bfbebSnyanmisaka# write taged information 207*437bfbebSnyanmisakalog_filter_and_print "Feature" "feat" 208*437bfbebSnyanmisakalog_filter_and_print "Fix" "fix" 209*437bfbebSnyanmisakalog_filter_and_print "Docs" "docs" 210*437bfbebSnyanmisakalog_filter_and_print "Style" "Style" 211*437bfbebSnyanmisakalog_filter_and_print "Refactor" "refactor" 212*437bfbebSnyanmisakalog_filter_and_print "Perf" "perf" 213*437bfbebSnyanmisakalog_filter_and_print "Test" "test" 214*437bfbebSnyanmisakalog_filter_and_print "Chore" "chore" 215*437bfbebSnyanmisaka 216*437bfbebSnyanmisakaecho -e "${prev_changelog}" >> ${changelog_file} 217*437bfbebSnyanmisaka 218*437bfbebSnyanmisaka# add CHANGELOG.md 219*437bfbebSnyanmisakagit add ${changelog_file} 220*437bfbebSnyanmisakagit commit --amend -C ${curr_ver} 221*437bfbebSnyanmisaka# update tag message 222*437bfbebSnyanmisakagit tag -f ${version_tag} -m "${version_tag} version at ${tag_date}" 223*437bfbebSnyanmisaka 224*437bfbebSnyanmisakaIFS=$OLDIFS 225