From e03f1deb5c2a1db4dd8bac23afd0252ff87de25d Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sat, 2 Nov 2019 17:06:15 -0400 Subject: [PATCH 1/6] Add working build and release tox environments. The build environment was originally broken, and no release environment existed. This allows for the Python dependencies for `release.py` to be satisfied automatically as part of invoking the tox command. --- tox.ini | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 0c614132b..3b126f744 100644 --- a/tox.ini +++ b/tox.ini @@ -79,10 +79,22 @@ commands = sphinx-build -d "{toxworkdir}/docs_doctree" docs "{toxworkdir}/docs_o python setup.py check -r -s [testenv:build] -description = do a build +description = Build an sdist and bdist basepython = python3.7 skip_install = true passenv = * deps = click >= 7.0 pep517 >= 0.5.0 -commands = python release.py +commands = + python release.py build + +[testenv:release] +description = Sign and upload the built distributions to PyPI +basepython = python3.7 +skip_install = true +passenv = * +deps = click >= 7.0 + twine >= 2.0.0 +commands = + python release.py sign + python release.py upload {posargs} From 55301cd0ed2f768e3b9a1265fabf61f66ba3fac5 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sat, 2 Nov 2019 15:54:01 -0400 Subject: [PATCH 2/6] Fix Travis test for build command. The orignal test was using `[ ! -e "dist/*.whl" ]` to try and detect that a wheel was created (and an analogous command for the tarball), but it turns out that this would succeed even if the build command completely fails! The reason is that the shellw as expanding "dist/*.whl" to an empty list, which the conditional took to mean that it didn't need to check for the existence of *any* files. This was replaced by a more robust command that checks that exactly one of each file was created by the build. --- .travis.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9f77348e7..ec3bb48d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,7 +42,22 @@ install: script: - tox - - if [[ $TOXENV == "build" ]]; then [ ! -e "dist/*.whl" ] && [ ! -e "dist/*.tar.gz" ]; fi + - | + if [[ $TOXENV == "build" ]]; then + exactly_one() { + value=$(find dist -iname $1 | wc -l) + if [ $value -ne 1 ]; then + echo "Found $value instances of $1, not 1" + return 1 + else + echo "Found exactly 1 instance of $value" + fi + } + + # Check that exactly one tarball and one wheel are created + exactly_one '*.tar.gz' + exactly_one '*.whl' + fi after_success: - if [[ $TOXENV == "py" ]]; then tox -e coverage,codecov; fi From 58a4e46021dd2e441d443e65d260b97c19d49bd5 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sat, 2 Nov 2019 12:44:30 -0400 Subject: [PATCH 3/6] Add "news" environment to tox Moving to a model where dependencies are provided by `tox` as needed where possible. --- tox.ini | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tox.ini b/tox.ini index 3b126f744..b1b7a1b78 100644 --- a/tox.ini +++ b/tox.ini @@ -78,6 +78,15 @@ commands = sphinx-build -d "{toxworkdir}/docs_doctree" docs "{toxworkdir}/docs_o sphinx-build -d "{toxworkdir}/docs_doctree" docs "{toxworkdir}/docs_out" {posargs:-W --color -blinkcheck} python setup.py check -r -s + +[testenv:news] +description = Invoke towncrier to update the NEWS file +basepython = python3.7 +passenv = * +deps = towncrier +commands = + towncrier {posargs} + [testenv:build] description = Build an sdist and bdist basepython = python3.7 From 3c9ccaa8478eabdfde90ab1c92d356c6d1fb3c87 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sat, 2 Nov 2019 20:27:23 -0400 Subject: [PATCH 4/6] Change "Misc" to showcontent=True Many of these miscellaneous items would actually be interesting to downstream consumers, even though they are not "bugfixes" (e.g. changes to the test suite or package metadata). Rather than ask contributors to decide whether their contribution meets this standard, we'll instead manually curate which PRs are "hidden" in the changelog. --- changelog.d/template.rst | 5 ----- pyproject.toml | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/changelog.d/template.rst b/changelog.d/template.rst index 8adffdf6c..933549d6b 100644 --- a/changelog.d/template.rst +++ b/changelog.d/template.rst @@ -9,15 +9,10 @@ {{ definitions[category]['name'] }} {{ underline * definitions[category]['name']|length }} -{% if definitions[category]['showcontent'] %} {% for text, values in sections[section][category].items() %} - {{ text }} {% endfor %} -{% else %} -- {{ sections[section][category]['']|join(', ') }} - -{% endif %} {% if sections[section][category]|length == 0 %} No significant changes. diff --git a/pyproject.toml b/pyproject.toml index 2c7336834..e83d69f77 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,5 +44,5 @@ build-backend = "setuptools.build_meta" [[tool.towncrier.type]] directory = "misc" name = "Misc" - showcontent = false + showcontent = true From 9390c888472a6726096df8c382e2abdfb1e99567 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sat, 2 Nov 2019 17:05:48 -0400 Subject: [PATCH 5/6] Update RELEASING documentation --- RELEASING | 94 +++++++++++++++++++------------------------------------ 1 file changed, 32 insertions(+), 62 deletions(-) diff --git a/RELEASING b/RELEASING index dcc027c84..27a3be802 100644 --- a/RELEASING +++ b/RELEASING @@ -1,26 +1,22 @@ Release Checklist ----------------------------------------- -[ ] Update __version__ string -[ ] Update classifiers in setup.py to include the latest supported Python +[ ] Update classifiers in setup.cfg to include the latest supported Python versions. [ ] Update the metadata in zonefile_metadata.json to include the latest tzdata release from https://www.iana.org/time-zones. [ ] If necessary, update the tzdata mirror at https://github.com/dateutil/tzdata -[ ] Update NEWS with list of changes, giving credit to contributors. -[ ] Build the source distribution as, at a minimum, .tar.gz and .zip -[ ] Verify that the source distribution contains all necessary components. -[ ] Build the binary distribution as a wheel -[ ] Verify that the binary distribution can be installed and works. -[ ] Generate MD5 hashes for the source and binary distributions -[ ] Sign the source and binary distributions with a GPG key (if not the one - that made the release, then one signed by the one that made the last - release) +[ ] Update NEWS with list of changes: + [ ] Invoke `tox -e towncrier -- --version ` + [ ] Make sure that only `template.rst` remains in changelog.d/ + [ ] Manually clean up the new NEWS file. + [ ] Replace entries in the "Misc" section that are not likely to be + interesting to anyone consuming the package (e.g. changes to CI) with + a reference to the Github PR. [ ] Commit the changes in git and make a pull request. [ ] Accept the pull request and tag the repository with the release number. -[ ] Add the contents of the NEWS file to the github release notes for the +[ ] Add the contents of the NEWS file to the Github release notes for the release. -[ ] Upload the source and binary distributions along with hashes and signatures - to pypi. +[ ] Upload the source and binary distributions with `tox -e release`. Optional: ---------- @@ -36,60 +32,34 @@ for more details. Versioning ---------- -Try and keep to a semantic versioning scheme (http://semver.org/). +Try and keep to a semantic versioning scheme (http://semver.org/). The versions +are managed with `setuptools_scm`, so to update the version, simply tag the +relevant commit with the new version number. -Source releases ----------- -Release the sources with, at a minimum, .tar.gz and .zip. Make sure you have a -relatively recent version of setuptools when making the source distribution, as -earlier version will not include the tests. Other formats are -optional. They can be generated using: - - python setup.py sdist --formats=zip,gztar - -To verify that a source release is correct, inspect it using whatever archive -utility you have and make sure it contains all the modules and the tests. Also -make sure that the zoneinfo file is included in the You -may also want to generate a new clean virtualenv and run the tests from the -source distribution (python setup.py test). - - -Binary releases ----------- -It should always be possible to generate a universal wheel binary distribution -for each release. Generally we do not generate .egg files. In order to generate -a wheel, you need the wheel package (https://wheel.readthedocs.io/en/latest/) -installed, which can be installed with: - - pip install wheel - -Once this is done, generate the wheel with: - - python setup.py bdist_wheel - - -Signing and generate checksums ----------- -Since all the outputs are generated in the dist/ directory, can generate all the -md5 checksums at once from the base directory by executing: - - md5sum dist/* - -Save these for when uploading the files. Following this, go into the dist -directory and sign each of the results with the relevant key: +Building and Releasing +---------------------- +Building and releasing can be done using the `release.py` script, which +automates building, signing and uploading. Since it uses GPG for signing and +for decrypting a stored token, it requires that `gpg` be installed on your +system. Because it has python dependencies, the best way to use the +`release.py` script is to invoke it using `tox`. To build the source and binary +distributions, use: - gpg --armor --output .asc --detach-sig + tox -e build -To automate this for all files, you can use the following command: +This will build the distributions in `dist/`. Once that is done, you can release +them with: - for f in dist/*; do gpg --armor --output $f.asc --detach-sig $f; done + tox -e release -Save these .asc files for when uploading to pypi. Before uploading them, verify -that they are valid signatures: +if you have the token stored in your `~/.pypirc` file. If you have stored the +relevant token in an encrypted file, use the `--passfile` argument: - gpg --verify .asc + tox -e release -- --passfile .token.gpg -To do this in bulk, you can use the command: +The `release` command defaults to uploading to test.pypi.org. To upload to +pypi.org, use the `--release` flag, so putting it all together, we have: - for f in $(find ./dist -type f | grep -v '.asc$'); do gpg --verify $f.asc $f; done + tox -e build + tox -e release -- --passfile .token.gpg --release From e0f0b7edc34f7a397d47a4c9d159e00f042d483a Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sat, 2 Nov 2019 15:17:37 -0400 Subject: [PATCH 6/6] Add changelog for PR #971 --- changelog.d/971.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/971.misc.rst diff --git a/changelog.d/971.misc.rst b/changelog.d/971.misc.rst new file mode 100644 index 000000000..6fc8c30b7 --- /dev/null +++ b/changelog.d/971.misc.rst @@ -0,0 +1 @@ +Updated the release procedure and added tox environments to help with releasing. (gh pr #971)