index-ext 0.0.1

Index slices with arbitrary ints and as arrays.
Documentation
#!/bin/bash
determine_new_version() {
	grep "version = " Cargo.toml | sed -Ee 's/version = "(.*)"/\1/' | head -1
}

determine_crate_name() {
	grep "name = " Cargo.toml | sed -Ee 's/name = "(.*)"/\1/' | head -1
}

check_published_version() {
	cirrus_agent="${CIRRUS_CI/?*/(Cirrus-CI)}"
	final_agent="Release-Script/1.0 ${cirrus_agent:-(local)} (for $crate) (author:HeroicKatora)"
	echo $final_agent
	# Does the api information start with: '{"errors":'
	[[ $(wget -U "$final_agent" --content-on-error "https://crates.io/api/v1/crates/$crate/$new_version" -qO -) == "{\"errors\":"* ]] || {
		published_commit=$(wget -U "$final_agent" "https://crates.io/api/v1/crates/$crate/$new_version/download" -qO - | tar xOzf - "$crate-$new_version/.cargo_vcs_info.json")
		published_commit=$(sed 's/\"sha1\": \"\(.*\)\"/\1/;T0;p;:0;d' <<< "$published_commit")
		echo "Already published at" "$published_commit"
	}
}

git_considered_clean() {
	[[ -z $(git status -s) ]]
}

count_wip_marker() {
	# WIP alone is not a marker
	[[ -z $(grep "\[WIP\]" Changes.md Readme.md) ]]
}

check_release_changes() {
	[[ -z $(grep "# v$new_version" Changes.md) ]]
}

make_git_tag() {
	tag_edit_msg="../.git/TAG_MSG_$(uuidgen)"
	touch "$tag_edit_msg"
	function cleanup() {
		rm "$tag_edit_msg"
	}
	trap cleanup EXIT
	# Extract the verion specific section from Changes.md
	#   Delete lines until $new_version header
	#   Delete lines starting from the next header
	#   Delete all empty lines at the start
	# Use as the initial message for a signed tag, but open edit anyways
	echo $(pwd)
	sed -e '0,/'"$new_version"'/d;/\#/,$d;/./,$!d' Changes.md >> "$tag_edit_msg"
	echo >> "$tag_edit_msg"
	# Sign the package content by including its hash in the tag
	sha256sum "../target/package/${crate}-${new_version}.crate" >> "$tag_edit_msg"
	git tag -s -F "$tag_edit_msg" -e "${crate}-v${new_version}" $published_commit
}

is_force=""
do_tag=""

for param in $@
do
	case "$param" in
		-f) is_force="-f";;
		--tag) do_tag="yes";;
		--help) ;&
		-h) { cat << EOF
usage: release [-f] [-h|--help] <version>

Automates checks and tagging of new releases. Encourages a workflow where
planned changes are integrated into readme and migration documentation early,
with WIP markers to help produce complete logs.

  -f		Force usage of version, even if such a tag already exists.
  -h, --help    Display this help
  <version>	A semantic version number matching [0-9a-zA-Z.-]*
  
EOF
exit 1; } ;;
	esac
done

new_version="$(determine_new_version)"
crate="$(determine_crate_name)"

# check it is a sane version number
[[ -z $(grep -vE '[0-9a-zA-Z.-]*' <<< "$new_version" ) ]] || { echo "Fail: Check version number: ${new_version}"; exit 1; }

# check we identified the crate
[[ -z "$crate" ]] && { echo "Couldn't determine crate name"; exit 1; }

# Check that the working dir is clean. May comment this out if it produces problems.
git_considered_clean || { echo "Fail: Working directory is not clean"; exit 1; }

# Check that for every author, we have at least name or mail recorded in Contributors.txt
# For each commit author, checks that either his/her name or respective mail
# address appears in the contributors file. Note that a .mailcap file could be
# introduced to canonicalize these names in the output of git-shortlog already.
# Since this needs GNU parallel, the check is optional.
if [[ -f Contributors.txt ]]; then
	if which parallel 2>/dev/null; then
		{ (git shortlog -se | parallel -C '\t|<' grep -Fq -e '{2}' -e '\<{3}' Contributors.txt) || { echo "Fail: contributor not listed"; exit 1; }; }
	else
		{ echo "Checking contributors needs GNU parallel, please make sure manually." 1>&2; }
	fi
fi

check_published_version || { echo "Version $new_version appears already published"; exit 1; }

# Check there are no more [WIP] markers in Migrate and Readme
count_wip_marker || { echo "Fail: Work in progress in documentation"; exit 1; }

# Find a matching header in the changelog
check_release_changes && { echo "Fail: No changelog regarding this release"; exit 1; }

# Packaging works. Note: does not publish the version.
cargo package || { echo "Fail: cargo could not package successfully"; exit 1; }

[[ -z $do_tag ]] || make_git_tag