dncurrency/util/changelog_generator
Russel Waters fbd02abe04
cmake format pass (#3053)
add cmake-format python module to static analyzers
various other script formatting and cleanup
2020-11-19 08:46:48 -08:00

236 lines
5.6 KiB
Bash
Executable file

#! /usr/bin/env bash
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <user/repo> <tag> [only]" >&2
exit 1
fi
repository="$1"
tag="$2"
shift 2
flags=("$@")
set -eo pipefail
function _curl() {
local curl_args
curl_args=(-s)
if [ -n "${API_KEY}" ]; then
curl_args+=(-H "Authorization: token ${API_KEY}")
fi
curl "${curl_args[@]}" "$@"
}
function milestones() {
local repository
repository="$1"
(
for state in closed open; do
_curl "https://api.github.com/repos/${repository}/milestones?state=${state}&per_page=100" | jq -r '.[] | [.title, .number] | @tsv' || return 1
done
) | sort -rV
}
function tag_to_tag_date() {
local tag
local tag_url
tag="$1"
tag_url="$(_curl "https://api.github.com/repos/${repository}/git/refs/tags/${tag}" | jq -r 'if (type == "object") then . else .[] end | select(.ref=="refs/tags/'"${tag}"'") | .object.url')" || return 1
_curl "${tag_url}" | jq -r '.tagger.date | fromdateiso8601 | strftime("%Y-%m-%d")' 2>/dev/null || \
_curl "${tag_url}" | jq -r '.committer.date | fromdateiso8601 | strftime("%Y-%m-%d")' || return 1
}
function parts_of_milestone() {
local repository milestone_id
local state
repository="$1"
milestone_id="$2"
for state in closed open; do
page='0'
while true; do
page=$((${page} + 1))
data="$(_curl "https://api.github.com/repos/${repository}/issues?milestone=${milestone_id}&state=${state}&page=${page}")"
item_count="$(echo "${data}" | jq -r '. | length')"
if [ "${item_count}" = '0' ]; then
break
fi
echo "${data}" | \
jq -r '.[] | [.html_url, .number, .title, (.labels[] | .name)] | @tsv' || return 1
done
done
}
function sanitize_markdown() {
sed -r 's@(\[|\]|_|#)@\\&@g'
}
function print_item() {
local item_id
local item_name item_url
item_id="$1"
item_name="${itemToName[${item_id}]}"
item_url="${itemToURL[${item_id}]}"
echo " - ${item_name} \[[\#${item_id}](${item_url})\]"
}
function changelog() {
local repository start_tag flags_list
local milestones_info previous_milestones previous_milestone
local milestone_name previous_milestone_name milestone_date tag_name
local itemToTags itemToName itemURL categoryIds categoryId
local majorIds item_url item_id item_name item_tags skip_item
local category is_major breaking
local start_output flags flag_only
echo "# Change Log"
repository="$1"
start_tag="$2"
flags_list="$3"
flag_only='false'
for flag in ${flags_list}; do
case "${flag}" in
only)
if [ -n "${start_tag}" ]; then
flag_only='true'
fi
;;
esac
done
# Get milestone information
milestones_info="$(milestones "${repository}")" || return 1
# Compute previous version information
unset previous_milestones
declare -A previous_milestones
milestone_name=''
while IFS=$'\t' read -r milestone_name milestone_id; do
previous_milestones["${milestone_name}"]="${previous_milestone}"
previous_milestone="${milestone_name}"
done < <(echo "${milestones_info}" | sort -V)
# Process all milestones
if [ -n "${start_tag}" ]; then
start_output='false'
else
start_output='true'
fi
start_tag_check="$(echo "${start_tag}" | sed 's@RC[0-9]*$@@')"
while IFS=$'\t' read -r milestone_name milestone_id; do
echo "Processing milestone: ${milestone_name} ..." >&2
tag_name="${milestone_name}"
if [ "${start_output}" = 'false' ]; then
if [ "${milestone_name}" = "${start_tag_check}" ]; then
start_output='true'
tag_name="${start_tag}"
fi
fi
if [ "${start_output}" = 'false' ]; then
continue
fi
milestone_date="$(tag_to_tag_date "${tag_name}")" || milestone_date=''
previous_milestone_name="${previous_milestones[${milestone_name}]}"
if [ -z "${milestone_date}" -o -z "${previous_milestone_name}" ]; then
continue
fi
echo "## Release [${tag_name}](https://github.com/nanocurrency/nano-node/tree/${tag_name}) (${milestone_date})"
echo ""
echo "[Full Changelog](https://github.com/nanocurrency/nano-node/compare/${previous_milestone_name}...${tag_name})"
echo ""
unset itemToTags itemToName itemURL categoryIds
declare -A itemToTags itemToName itemToURL
declare -A categoryIds
majorIds=()
while IFS=$'\t' read -r item_url item_id item_name item_tags; do
skip_item='false'
is_major='false'
category=''
for item_tag in ${item_tags}; do
case "${item_tag}" in
wontfix | duplicate | invalid)
skip_item='true'
;;
enhancement | quality)
category='Implemented enhancements'
;;
major | semantics)
is_major='true'
;;
bug)
category='Fixed bugs'
;;
esac
done
if [ -z "${category}" ]; then
category='Fixed bugs'
fi
if [ "${skip_item}" = 'true' ]; then
continue
fi
breaking='false'
item_name="$(echo "${item_name}" | sanitize_markdown)"
itemToTags[$item_id]="${item_tags}"
itemToName[$item_id]="${item_name}"
itemToURL[$item_id]="${item_url}"
categoryIds[${category}]+=" $item_id"
if [ "${is_major}" = 'true' ]; then
majorIds+=($item_id)
fi
done < <(parts_of_milestone "${repository}" "${milestone_id}")
if [ "${#majorIds[@]}" -gt 0 ]; then
echo "**Major Changes:**"
for item_id in "${majorIds[@]}"; do
print_item "${item_id}"
done
echo ""
fi
for categoryId in 'Implemented enhancements' 'Fixed bugs'; do
if [ -n "${categoryIds[${categoryId}]}" ]; then
echo "**${categoryId}:**"
for item_id in ${categoryIds[${categoryId}]}; do
print_item "${item_id}"
done
echo ""
fi
done
if [ "${flag_only}" = 'true' ]; then
break
fi
echo ""
echo ""
done <<<"${milestones_info}"
}
changelog="$(changelog "${repository}" "${tag}" "${flags[*]}")"
echo "${changelog}" >CHANGELOG.md