-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revamp Makefile based on what I'm using elsewhere
- Loading branch information
Showing
1 changed file
with
161 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,113 +1,210 @@ | ||
# ============================================================================= | ||
# @file Makefile | ||
# @brief Makefile for some steps in creating new releases on GitHub | ||
# @author Michael Hucka | ||
# @date 2020-08-11 | ||
# @date 2021-10-16 | ||
# @license Please see the file named LICENSE in the project directory | ||
# @website https://github.com/caltechlibrary/eprints2bags | ||
# @website https://github.com/caltechlibrary/commonpy | ||
# ============================================================================= | ||
|
||
.ONESHELL: # Run all commands in the same shell. | ||
.SHELLFLAGS += -e # Exit at the first error. | ||
|
||
# Before we go any further, test if certain programs are available. | ||
# The following is based on the approach posted by Jonathan Ben-Avraham to | ||
# Stack Overflow in 2014 at https://stackoverflow.com/a/25668869 | ||
|
||
PROGRAMS_NEEDED = curl gh git jq sed | ||
PROGRAMS_NEEDED = curl gh git jq sed pyinstaller | ||
TEST := $(foreach p,$(PROGRAMS_NEEDED),\ | ||
$(if $(shell which $(p)),_,$(error Cannot find program "$(p)"))) | ||
|
||
# Gather values that we need further below. | ||
|
||
$(info Gathering data -- this takes a few moments ...) | ||
# Set some basic variables. These are quick to set; we set additional | ||
# variables using "set-vars" but only when the others are needed. | ||
|
||
name := $(strip $(shell grep -m 1 'name\s*=' setup.cfg | cut -f2 -d'=')) | ||
version := $(strip $(shell grep -m 1 'version\s*=' setup.cfg | cut -f2 -d'=')) | ||
url := $(strip $(shell grep -m 1 'url\s*=' setup.cfg | cut -f2 -d'=')) | ||
desc := $(strip $(shell grep -m 1 'description\s*=' setup.cfg | cut -f2 -d'=')) | ||
author := $(strip $(shell grep -m 1 'author\s*=' setup.cfg | cut -f2 -d'=')) | ||
email := $(strip $(shell grep -m 1 'author_email\s*=' setup.cfg | cut -f2 -d'=')) | ||
license := $(strip $(shell grep -m 1 'license\s*=' setup.cfg | cut -f2 -d'=')) | ||
|
||
branch := $(shell git rev-parse --abbrev-ref HEAD) | ||
repo := $(strip $(shell gh repo view | head -1 | cut -f2 -d':')) | ||
id := $(shell curl -s https://api.github.com/repos/$(repo) | jq '.id') | ||
id_url := https://data.caltech.edu/badge/latestdoi/$(id) | ||
doi_url := $(shell curl -sILk $(id_url) | grep Locat | cut -f2 -d' ') | ||
doi := $(subst https://doi.org/,,$(doi_url)) | ||
doi_tail := $(lastword $(subst ., ,$(doi))) | ||
name := $(strip $(shell awk -F "=" '/^name/ {print $$2}' setup.cfg)) | ||
version := $(strip $(shell awk -F "=" '/^version/ {print $$2}' setup.cfg)) | ||
url := $(strip $(shell awk -F "=" '/^url/ {print $$2}' setup.cfg)) | ||
desc := $(strip $(shell awk -F "=" '/^description / {print $$2}' setup.cfg)) | ||
author := $(strip $(shell awk -F "=" '/^author / {print $$2}' setup.cfg)) | ||
email := $(strip $(shell awk -F "=" '/^author_email/ {print $$2}' setup.cfg)) | ||
license := $(strip $(shell awk -F "=" '/^license / {print $$2}' setup.cfg)) | ||
init_file := $(name)/__init__.py | ||
tmp_file := $(shell mktemp /tmp/release-notes-$(name).XXXXXX) | ||
branch := $(shell git rev-parse --abbrev-ref HEAD) | ||
|
||
$(info Gathering data ... Done.) | ||
|
||
# The main action is "make release". | ||
# Print help if no command is given ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
help: | ||
@echo 'Available commands:' | ||
@echo '' | ||
@echo 'make' | ||
@echo 'make help' | ||
@echo ' Print this summary of available commands.' | ||
@echo '' | ||
@echo 'make report' | ||
@echo ' Print variables set in this Makefile from various sources.' | ||
@echo ' This is useful to verify the values that have been parsed.' | ||
@echo '' | ||
@echo 'make release' | ||
@echo ' Do a release on GitHub. This will push changes to GitHub,' | ||
@echo ' open an editor to let you edit release notes, and run' | ||
@echo ' "gh release create" followed by "gh release upload".' | ||
@echo ' Note: this will NOT upload to PyPI, nor create binaries.' | ||
@echo '' | ||
@echo 'make update-doi' | ||
@echo ' Update the DOI inside the README.md file.' | ||
@echo ' This is only to be done after doing a "make release".' | ||
@echo '' | ||
@echo 'make packages' | ||
@echo ' Create the distribution files for PyPI.' | ||
@echo ' Do this manually to check that everything looks okay before.' | ||
@echo ' After doing this, do a "make test-pypi".' | ||
@echo '' | ||
@echo 'make test-pypi' | ||
@echo ' Upload distribution to test.pypi.org.' | ||
@echo ' Do this before doing "make pypi" for real.' | ||
@echo '' | ||
@echo 'make pypi' | ||
@echo ' Upload distribution to pypi.org.' | ||
@echo '' | ||
@echo 'make clean' | ||
@echo ' Clean up various files generated by this Makefile.' | ||
|
||
|
||
# Gather values that we need ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
.SILENT: vars | ||
vars: | ||
$(info Gathering data -- this takes a few moments ...) | ||
$(eval repo := $(strip $(shell gh repo view | head -1 | cut -f2 -d':'))) | ||
$(eval api_url := https://api.github.com) | ||
$(eval id := $(shell curl -s $(api_url)/repos/$(repo) | jq '.id')) | ||
$(eval id_url := https://data.caltech.edu/badge/latestdoi/$(id)) | ||
$(eval doi_url := $(shell curl -sILk $(id_url) | grep Locat | cut -f2 -d' ')) | ||
$(eval doi := $(subst https://doi.org/,,$(doi_url))) | ||
$(eval doi_tail := $(lastword $(subst ., ,$(doi)))) | ||
$(info Gathering data -- this takes a few moments ... Done.) | ||
|
||
report: vars | ||
@echo name = $(name) | ||
@echo version = $(version) | ||
@echo url = $(url) | ||
@echo desc = $(desc) | ||
@echo author = $(author) | ||
@echo email = $(email) | ||
@echo license = $(license) | ||
@echo branch = $(branch) | ||
@echo repo = $(repo) | ||
@echo id = $(id) | ||
@echo id_url = $(id_url) | ||
@echo doi_url = $(doi_url) | ||
@echo doi = $(doi) | ||
@echo doi_tail = $(doi_tail) | ||
@echo init_file = $(init_file) | ||
|
||
|
||
# make release ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
release: | test-branch release-on-github print-instructions | ||
|
||
test-branch: | ||
test-branch: vars | ||
ifneq ($(branch),main) | ||
$(error Current git branch != main. Merge changes into main first) | ||
$(error Current git branch != main. Merge changes into main first!) | ||
endif | ||
|
||
update-init-file:; | ||
update-init: vars | ||
@sed -i .bak -e "s|^\(__version__ *=\).*|\1 '$(version)'|" $(init_file) | ||
@sed -i .bak -e "s|^\(__description__ *=\).*|\1 '$(desc)'|" $(init_file) | ||
@sed -i .bak -e "s|^\(__url__ *=\).*|\1 '$(url)'|" $(init_file) | ||
@sed -i .bak -e "s|^\(__author__ *=\).*|\1 '$(author)'|" $(init_file) | ||
@sed -i .bak -e "s|^\(__email__ *=\).*|\1 '$(email)'|" $(init_file) | ||
@sed -i .bak -e "s|^\(__license__ *=\).*|\1 '$(license)'|" $(init_file) | ||
|
||
update-codemeta-file:; | ||
update-meta: vars | ||
@sed -i .bak -e "/version/ s/[0-9].[0-9][0-9]*.[0-9][0-9]*/$(version)/" codemeta.json | ||
|
||
edited := codemeta.json $(init_file) | ||
update-citation: vars | ||
$(eval date := $(shell date "+%F")) | ||
@sed -i .bak -e "/^date-released/ s/[0-9][0-9-]*/$(date)/" CITATION.cff | ||
@sed -i .bak -e "/^version/ s/[0-9].[0-9][0-9]*.[0-9][0-9]*/$(version)/" CITATION.cff | ||
|
||
edited := codemeta.json $(init_file) CITATION.cff | ||
|
||
check-in-updated-files:; | ||
commit-updates: vars | ||
git add $(edited) | ||
git diff-index --quiet HEAD $(edited) || git commit -m"Update version" $(edited) | ||
git diff-index --quiet HEAD $(edited) || \ | ||
git commit -m"Update stored version number" $(edited) | ||
|
||
release-on-github: | update-init-file update-codemeta-file check-in-updated-files | ||
release-on-github: | vars update-init update-meta update-citation commit-updates | ||
$(eval tmp_file := $(shell mktemp /tmp/release-notes-$(name).XXXX)) | ||
git push -v --all | ||
git push -v --tags | ||
$(info ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓) | ||
$(info ┃ Write release notes in the file that will be opened in your editor ┃) | ||
$(info ┃ then save and close the file to complete this release process. ┃) | ||
$(info ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛) | ||
$(info ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓) | ||
$(info ┃ Write release notes in the file that gets opened in your ┃) | ||
$(info ┃ editor. Close the editor to complete the release process. ┃) | ||
$(info ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛) | ||
sleep 2 | ||
$(EDITOR) $(tmp_file) | ||
gh release create v$(version) -t "Release $(version)" -F $(tmp_file) | ||
|
||
print-instructions:; | ||
$(info ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓) | ||
$(info ┃ Next steps: ┃) | ||
print-instructions: vars | ||
$(info ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓) | ||
$(info ┃ Next steps: ┃) | ||
$(info ┃ 1. Visit https://github.com/$(repo)/releases ) | ||
$(info ┃ 2. Double-check the draft release, and click "Publish" if ready ┃) | ||
$(info ┃ 3. Wait a few seconds to let web services do their work ┃) | ||
$(info ┃ 4. Run "make update-doi" to update the DOI in README.md ┃) | ||
$(info ┃ 5. Run "make create-dist" and check the distribution for problems ┃) | ||
$(info ┃ 6. Run "make test-pypi" to push to test.pypi.org ┃) | ||
$(info ┃ 7. Double-check https://test.pypi.org/$(repo) ) | ||
$(info ┃ 8. Run "make pypi" to push to pypi for real ┃) | ||
$(info ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛) | ||
$(info ┃ 2. Check the release ┃) | ||
$(info ┃ 3. Wait a few seconds to let web services do their work ┃) | ||
$(info ┃ 4. Run "make update-doi" to update the DOI in README.md ┃) | ||
$(info ┃ 5. Run "make packages" and check the results ┃) | ||
$(info ┃ 6. Run "make test-pypi" to push to test.pypi.org ┃) | ||
$(info ┃ 7. Check https://test.pypi.org/$(repo) ) | ||
$(info ┃ 8. Run "make pypi" to push to pypi for real ┃) | ||
$(info ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛) | ||
@echo "" | ||
|
||
update-doi: | ||
sed -i .bak -e 's|DOI-.*-blue|DOI-$(doi)-blue|' README.md | ||
sed -i .bak -e 's|caltech.edu/records/[0-9]\{1,\}|caltech.edu/records/$(doi_tail)|' README.md | ||
git add README.md | ||
git diff-index --quiet HEAD README.md || git commit -m"Update DOI" README.md && git push -v --all | ||
|
||
create-dist: clean | ||
update-doi: vars | ||
sed -i .bak -e 's|/api/record/[0-9]\{1,\}|/api/record/$(doi_tail)|' README.md | ||
sed -i .bak -e 's|edu/records/[0-9]\{1,\}|edu/records/$(doi_tail)|' README.md | ||
sed -i .bak -e '/doi:/ s|10.22002/[0-9]\{1,\}|10.22002/$(doi_tail)|' CITATION.cff | ||
git add README.md CITATION.cff | ||
git diff-index --quiet HEAD README.md || \ | ||
(git commit -m"Update DOI" README.md && git push -v --all) | ||
git diff-index --quiet HEAD CITATION.cff || \ | ||
(git commit -m"Update DOI" CITATION.cff && git push -v --all) | ||
|
||
packages: | vars clean | ||
python3 setup.py sdist bdist_wheel | ||
python3 -m twine check dist/* | ||
python3 -m twine check dist/$(name)-$(version).tar.gz | ||
python3 -m twine check dist/$(name)-$(version)-py3-none-any.whl | ||
|
||
test-pypi: packages | ||
python3 -m twine upload --repository testpypi dist/$(name)-$(version)*.{whl,gz} | ||
|
||
pypi: packages | ||
python3 -m twine upload dist/$(name)-$(version)*.{gz,whl} | ||
|
||
|
||
# Cleanup and miscellaneous directives ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
clean: clean-dist clean-build clean-release clean-other | ||
|
||
really-clean: clean really-clean-dist | ||
|
||
clean-dist: vars | ||
-rm -fr dist/$(name) dist/$(name).zip dist/*.tar.gz dist/*.whl \ | ||
dist/$(name)-${version}-macos-python3.*{,.zip} | ||
|
||
really-clean-dist:; | ||
-rm -fr dist | ||
|
||
test-pypi: create-dist | ||
python3 -m twine upload --verbose --repository-url https://test.pypi.org/legacy/ dist/* | ||
clean-build:; | ||
-rm -rf build | ||
|
||
pypi: create-dist | ||
python3 -m twine upload --verbose dist/* | ||
clean-release: vars | ||
-rm -rf $(name).egg-info codemeta.json.bak $(init_file).bak README.md.bak | ||
|
||
clean:; | ||
-rm -rf dist build $(name).egg-info | ||
clean-other: vars | ||
-rm -fr __pycache__ $(name)/__pycache__ .eggs | ||
-rm -rf .cache | ||
|
||
.PHONY: release release-on-github update-init-file update-codemeta-file \ | ||
print-instructions create-dist clean test-pypi pypi | ||
.PHONY: release release-on-github update-init update-meta \ | ||
vars print-instructions update-doi packages test-pypi pypi clean \ | ||
clean-dist really-clean-dist clean-build clean-release clean-other |