diff --git a/.changelog/2458.trivial.md b/.changelog/2458.trivial.md new file mode 100644 index 00000000000..4a090794a43 --- /dev/null +++ b/.changelog/2458.trivial.md @@ -0,0 +1 @@ +Makefile: Add tag-next-release target diff --git a/.changelog/2537.trivial.md b/.changelog/2537.trivial.md deleted file mode 100644 index 2f23fdb890f..00000000000 --- a/.changelog/2537.trivial.md +++ /dev/null @@ -1 +0,0 @@ -runtime: Extract common sealing code. diff --git a/Makefile b/Makefile index 58b6b2acee5..3923475bb50 100644 --- a/Makefile +++ b/Makefile @@ -97,14 +97,23 @@ clean: $(clean-targets) # Assemble Change log. changelog: - @if [[ -z "$(NEXT_VERSION)" ]]; then \ - echo "Error: Could not compute project's new version."; \ - exit 1; \ - else \ - echo "Generating changelog for version $(NEXT_VERSION)..."; \ - towncrier build --version $(NEXT_VERSION); \ - echo "Next, review the staged changes, commit them and make a pull request."; \ - fi + @$(ENSURE_NEXT_VERSION) + @$(ECHO_STDERR) "Generating Change Log for version $(NEXT_VERSION)..." + towncrier build --version $(NEXT_VERSION) + @$(ECHO_STDERR) "Next, review the staged changes, commit them and make a pull request." + +# Tag the next release. +tag-next-release: + @$(ENSURE_NEXT_VERSION) + @$(ECHO_STDERR) "Checking if we can tag version $(NEXT_VERSION) as the next release..." + @$(ENSURE_NO_CHANGELOG_FRAGMENTS) + @$(ENSURE_NEXT_VERSION_IN_CHANGELOG) + @$(ECHO_STDERR) "All checks have passed. Proceeding with tagging the $(OASIS_CORE_GIT_ORIGIN_REMOTE)/master HEAD with tag 'v$(NEXT_VERSION)'." + @$(CONFIRM_ACTION) + @$(ECHO_STDERR) "If this appears to be stuck, you might need to touch your security key for GPG sign operation." + @git tag --sign --message="Version $(NEXT_VERSION)" v$(NEXT_VERSION) $(OASIS_CORE_GIT_ORIGIN_REMOTE)/master + @git push $(OASIS_CORE_GIT_ORIGIN_REMOTE) v$(NEXT_VERSION) + @$(ECHO_STDERR) "$(CYAN)Tag 'v$(NEXT_VERSION)' has been successfully pushed to $(OASIS_CORE_GIT_ORIGIN_REMOTE) remote.$(OFF)" # Prepare release. release: @@ -128,5 +137,5 @@ docker-shell: $(fmt-targets) fmt \ $(test-unit-targets) $(test-targets) test \ $(clean-targets) clean \ - changelog release docker-shell \ + changelog tag-next-release release docker-shell \ all diff --git a/common.mk b/common.mk index 9e0790e6cb0..88a30d9bb1f 100644 --- a/common.mk +++ b/common.mk @@ -7,6 +7,7 @@ ifdef ISATTY # Running in interactive terminal, OK to use colors! MAGENTA := \e[35;1m CYAN := \e[36;1m + RED := \e[0;31m OFF := \e[0m # Built-in echo doesn't support '-e'. @@ -15,12 +16,25 @@ else # Don't use colors if not running interactively. MAGENTA := "" CYAN := "" + RED := "" OFF := "" # OK to use built-in echo. ECHO := echo endif +# A version of echo that outputs to stderr instead of stdout. +ECHO_STDERR := $(ECHO) 1>&2 + +# Helper that asks the user to confirm the action. +define CONFIRM_ACTION = + $(ECHO_STDERR) -n "Are you sure? [y/N] " && read ans && [ $${ans:-N} = y ] +endef + +# Name of git remote pointing to the canonical upstream git repository, i.e. +# git@github.com:oasislabs/oasis-core.git. +OASIS_CORE_GIT_ORIGIN_REMOTE ?= origin + # Try to determine Oasis Core's version from git. LATEST_TAG := $(shell git describe --tags --match 'v*' --abbrev=0 2>/dev/null) VERSION := $(subst v,,$(LATEST_TAG)) @@ -51,9 +65,9 @@ _PUNCH_VERSION_FILE := $(shell mktemp /tmp/oasis-core.XXXXX.py) # http://make.mad-scientist.net/deferred-simple-variable-expansion/. NEXT_VERSION ?= $(eval NEXT_VERSION := $$(shell \ set -e; \ - echo "Fetching all tags from the origin remote..." 1>&2; \ - git fetch origin --tags; \ - LATEST_TAG_ORIGIN=`git describe --tags --match 'v*' --abbrev=0 origin/master` \ + echo "Fetching all tags from the $(OASIS_CORE_GIT_ORIGIN_REMOTE) remote..." 1>&2; \ + git fetch $(OASIS_CORE_GIT_ORIGIN_REMOTE) --tags; \ + LATEST_TAG_ORIGIN=`git describe --tags --match 'v*' --abbrev=0 $(OASIS_CORE_GIT_ORIGIN_REMOTE)/master` \ python3 -c "import os; year, minor = os.environ['LATEST_TAG_ORIGIN'].lstrip('v').split('.'); \ print(f'year=\"{year}\"\nminor={minor}')" > $(_PUNCH_VERSION_FILE); \ punch --config-file .punch_config.py --version-file $(_PUNCH_VERSION_FILE) --action custom_bump --quiet; \ @@ -113,3 +127,31 @@ _ := $(shell printf "$(subst ",\",$(subst $(newline),\n,$(RELEASE_TEXT)))" > $(_ GORELEASER_ARGS = release --release-notes $(_RELEASE_NOTES_FILE) endif + +# Helper that ensures $(NEXT_VERSION) variable is not empty. +define ENSURE_NEXT_VERSION = + if [[ -z "$(NEXT_VERSION)" ]]; then \ + $(ECHO_STDERR) "$(RED)Error: Could not compute project's next version.$(OFF)"; \ + exit 1; \ + fi +endef + +# Helper that ensures the origin/master's HEAD doesn't contain any Change Log fragments. +define ENSURE_NO_CHANGELOG_FRAGMENTS = + CHANGELOG_FRAGMENTS=`git ls-tree -r --name-only $(OASIS_CORE_GIT_ORIGIN_REMOTE)/master .changelog | \ + grep --invert-match --extended-regexp '(README.md|template.md.j2)'`; \ + if [[ -n $${CHANGELOG_FRAGMENTS} ]]; then \ + $(ECHO_STDERR) "$(RED)Error: Found the following Change Log fragments on $(OASIS_CORE_GIT_ORIGIN_REMOTE)/master branch:"; \ + $(ECHO_STDERR) "$${CHANGELOG_FRAGMENTS}$(OFF)"; \ + exit 1; \ + fi +endef + +# Helper that ensures the origin/master's HEAD contains a Change Log section for the next release. +define ENSURE_NEXT_VERSION_IN_CHANGELOG = + if ! ( git show $(OASIS_CORE_GIT_ORIGIN_REMOTE)/master:CHANGELOG.md | \ + grep --quiet '^## $(NEXT_VERSION) (.*)' ); then \ + $(ECHO_STDERR) "$(RED)Error: Could not locate Change Log section for release $(NEXT_VERSION).$(OFF)"; \ + exit 1; \ + fi +endef