github.com/vpayno/adventofcode-2022-golang-workspace@v0.0.0-20230605190011-dbafed5593de/scripts/git-release-notes (about)

     1  #!/bin/bash
     2  
     3  declare mode="${1:-latest}"
     4  declare release_message="${2:-}"
     5  
     6  git_get_tags() {
     7  	local tag="${1:-}"
     8  
     9  	if [[ -z ${tag} ]]; then
    10  		git tag | sort -Vr | grep -E '^v[[:digit:]]+[.][[:digit:]]+[.][[:digit:]]+$'
    11  	else
    12  		git tag | sort -Vr | grep -E '^v[[:digit:]]+[.][[:digit:]]+[.][[:digit:]]+$' | grep -A 1 "${tag}"
    13  	fi
    14  } # git_get_tags()
    15  
    16  git_get_tag_previous() {
    17  	local tag="${1:-}"
    18  
    19  	git_get_tags "${tag}" | head -n 2 | tail -n 1
    20  } # git_get_tag_previous()
    21  
    22  git_get_tag_latest() {
    23  	local tag="${1:-}"
    24  
    25  	git_get_tags "${tag}" | head -n 1
    26  } # git_get_tag_latest()
    27  
    28  git_cl() {
    29  	local tag="${1:-}"
    30  
    31  	local tag_previous
    32  	local tag_latest
    33  	local git_ref
    34  
    35  	if [[ ${tag} =~ ^v0.0.0\^$ ]]; then
    36  		git_ref="${tag}"
    37  	elif [[ ${tag} =~ ^release-(short|full:.*)$ ]]; then
    38  		git_ref="$(git_get_tags | head -n 1)..HEAD"
    39  	else
    40  		tag_previous="$(git_get_tag_previous "${tag}")"
    41  		tag_latest="$(git_get_tag_latest "${tag}")"
    42  
    43  		git_ref="${tag_previous}..${tag_latest}"
    44  	fi
    45  
    46  	git log --pretty=format:'    - %s' --abbrev-commit --decorate "${git_ref}"
    47  } # git_cl()
    48  
    49  get_release_heading() {
    50  	local tag="${1:-}"
    51  	local mode="${2:-}"
    52  
    53  	local heading_start="##"
    54  	local heading_end=""
    55  
    56  	if [[ ${mode%%:*} =~ ^all|release-full$ ]]; then
    57  		heading_start="<h2>"
    58  		heading_end="</h2>"
    59  	fi
    60  
    61  	if [[ ${tag%%:*} =~ ^release-short$ ]]; then
    62  		printf "release: %s\n" "${release_message}"
    63  		return
    64  	elif [[ ${tag%%:*} =~ ^release-full$ ]]; then
    65  		git log --pretty=format:"${heading_start} [%as] " --abbrev-commit --decorate -n 1 "${tag//release-*/HEAD}"
    66  		printf "Release %s: %s\n%s\n" "${tag##*:}" "${release_message}" "${heading_end}"
    67  		return
    68  	fi
    69  
    70  	git log --pretty=format:"${heading_start} [%as] " --abbrev-commit --decorate -n 1 "${tag//release-*/HEAD}"
    71  
    72  	if [[ ${tag} == v0.0.0^ ]]; then
    73  		printf "Release v0.0.0: initial release\n"
    74  	else
    75  		git_cl "${tag%%:*}" | head -n 1 | sed -r -e 's/^    - release: (v[[:digit:]]+[.][[:digit:]]+[.][[:digit:]]+) (- )?/Release \1: /g'
    76  	fi
    77  
    78  	printf "%s\n" "${heading_end}"
    79  }
    80  
    81  filter_commits() {
    82  	grep -v -e 'Initial commit' -e 'Merge pull request'
    83  } # filter_commits()
    84  
    85  get_release_body() {
    86  	local tag="${1:-}"
    87  
    88  	local -a sections
    89  
    90  	mapfile -t sections < <(git_cl "${tag}" | grep -v -E "^    - release: " | filter_commits | awk '{ print $2 }' | tr -d ":" | sort -Vu)
    91  
    92  	for section in "${sections[@]}"; do
    93  		printf "\n"
    94  		printf -- "### %s\n" "${section,,}"
    95  		printf "\n"
    96  		git_cl "${tag}" | grep -v -E "^    - release: " | filter_commits | sort -k 2,2 -V | grep -- "- ${section}: " | sed -r -e 's/^    - [[:alpha:]].*: /- /g' | sort -V
    97  	done
    98  }
    99  
   100  create_release_notes() {
   101  	local mode="${1}"
   102  
   103  	local first="true"
   104  	local -a tags
   105  	local open_fold_flag=" open"
   106  
   107  	if [[ ${mode} == latest ]]; then
   108  		mapfile -t tags < <(git_get_tag_latest)
   109  	elif [[ ${mode} == release-short ]]; then
   110  		mapfile -t tags < <(printf "%s\n" "${mode}")
   111  	elif [[ ${mode%%:*} == release-full ]]; then
   112  		printf "# %s Release Notes\n" '"Powerful Cli Applications in Go" Workspace'
   113  		printf "\n"
   114  
   115  		mapfile -t tags < <(printf "%s\n" "${mode}"; git_get_tags | sort -Vr)
   116  	elif [[ ${mode} =~ ^v[0-9]+[.][0-9]+[.][0-9]+$ ]]; then
   117  		if ! git tag | grep -q -E "^${mode##*:}$"; then
   118  			printf "ERROR: tag [%s] doesn't exist!\n" "${mode}"
   119  			exit 1
   120  		fi
   121  
   122  		mapfile -t tags < <(printf "%s\n" "${mode}")
   123  	else
   124  		printf "# %s Release Notes\n" '"Powerful Cli Applications in Go" Workspace'
   125  		printf "\n"
   126  
   127  		mapfile -t tags < <(git_get_tags | sort -Vr)
   128  	fi
   129  
   130  	for tag in "${tags[@]}"; do
   131  		if [[ ${tag} == v0.0.0 ]]; then
   132  			tag="${tag}^"
   133  		fi
   134  
   135  		if "${first}"; then
   136  			first="false"
   137  		else
   138  			printf "\n"
   139  		fi
   140  
   141  		[[ ${mode} =~ ^all|release-full:v.*$ ]] && printf "<details%s>\n    <summary>\n" "${open_fold_flag}"
   142  		get_release_heading "${tag}" "${mode}"
   143  		[[ ${mode} =~ ^all|release-full:v.*$ ]] &&	printf "    </summary>\n"
   144  		get_release_body "${tag}" "${mode}"
   145  		[[ ${mode} =~ ^all|release-full:v.*$ ]] && printf "\n</details>\n"
   146  
   147  		open_fold_flag=""
   148  	done
   149  
   150  	{
   151  		printf "Running misspell -w CHANGELOG.md...\n"
   152  		misspell -w CHANGELOG*.md
   153  		printf "done\n"
   154  	} 1>&2
   155  } # create_release_notes()
   156  
   157  if [[ ${mode} =~ ^(|latest|release-(short|full:v[0-9]+[.][0-9]+[.][0-9]+)|all|v[0-9]+[.][0-9]+[.][0-9]+)$ ]]; then
   158  	create_release_notes "${mode}"
   159  else
   160  	printf "Usage: %s ^(|latest|release-(short|full:[0-9]+[.][0-9]+[.][0-9]+)|all|v[0-9]+[.][0-9]+[.][0-9]+)$\n" "$0"
   161  	exit 1
   162  fi