certbot/tools/_release.sh
ohemorange 16f858547f
Add --use-pep517 flag to pip to silence warning in tools/venv.py, and switch codebase to src-layout (#10249)
Fixes #10252.

See further discussion here: https://github.com/pypa/pip/issues/11457

We are doing option:

> Alternatively, enable the --use-pep517 pip option, possibly with
--no-build-isolation. The --use-pip517 flag will force pip to use the
modern mechanism for editable installs. --no-build-isolation may be
needed if your project has build-time requirements beyond setuptools and
wheel. By passing this flag, you are responsible for making sure your
environment already has the required dependencies to build your package.
Once the legacy mechanism is removed, --use-pep517 will have no effect
and will essentially be enabled by default in this context.

Major changes made here include:
- Add `--use-pep517` to use the modern mechanism, which will be the only
mechanism in future pip releases
- Change to `/src` layout to appease mypy, and because for editable
installs that really is the normal way these days.
  - `cd acme && mkdir src && mv acme src/` etc.
- add `where='src'` argument to `find_packages` and add
`package_dir={'': 'src'},` in `setup.py`s
  - update `MANIFEST.in` files with new path locations 
- Update our many hardcoded filepaths
- Update `importlib-metadata` requirement to fix
double-plugin-entry-point problem in oldest tests
2025-04-11 19:30:33 +00:00

223 lines
6.9 KiB
Bash
Executable file

#!/bin/bash -xe
# Release packages to PyPI
if [ "$RELEASE_DIR" = "" ]; then
echo Please run this script through the tools/release.sh wrapper script or set the environment
echo variable RELEASE_DIR to the directory where the release should be built.
exit 1
fi
ExitWarning() {
exit_status="$?"
if [ "$exit_status" != 0 ]; then
# Don't print each command before executing it because it will disrupt
# the desired output.
set +x
echo '******************************'
echo '* *'
echo '* THE RELEASE SCRIPT FAILED! *'
echo '* *'
echo '******************************'
set -x
fi
exit "$exit_status"
}
trap ExitWarning EXIT
version="$1"
echo Releasing production version "$version"...
nextversion="$2"
RELEASE_BRANCH="candidate-$version"
# If RELEASE_GPG_KEY isn't set, determine the key to use.
if [ "$RELEASE_GPG_KEY" = "" ]; then
TRUSTED_KEYS="
BF6BCFC89E90747B9A680FD7B6029E8500F7DB16
86379B4F0AF371B50CD9E5FF3402831161D1D280
20F201346BF8F3F455A73F9A780CC99432A28621
F2871B4152AE13C49519111F447BF683AA3B26C3
"
for key in $TRUSTED_KEYS; do
if gpg --with-colons --card-status | grep -q "$key"; then
RELEASE_GPG_KEY="$key"
break
fi
done
if [ "$RELEASE_GPG_KEY" = "" ]; then
echo A trusted PGP key was not found on your PGP card.
exit 1
fi
fi
# Needed to fix problems with git signatures and pinentry
export GPG_TTY=$(tty)
# port for a local Python Package Index (used in testing)
PORT=${PORT:-1234}
# subpackages to be released (the way the script thinks about them)
SUBPKGS_NO_CERTBOT="acme certbot-apache certbot-nginx certbot-dns-cloudflare \
certbot-dns-digitalocean certbot-dns-dnsimple certbot-dns-dnsmadeeasy \
certbot-dns-gehirn certbot-dns-google certbot-dns-linode certbot-dns-luadns \
certbot-dns-nsone certbot-dns-ovh certbot-dns-rfc2136 certbot-dns-route53 \
certbot-dns-sakuracloud"
SUBPKGS="certbot $SUBPKGS_NO_CERTBOT"
# certbot_compatibility_test is not packaged because:
# - it is not meant to be used by anyone else than Certbot devs
# - it causes problems when running pytest - the latter tries to
# run everything that matches test*, while there are no unittests
# there
tag="v$version"
built_package_dir="packages"
if [ -d "$built_package_dir" ]; then
echo "there shouldn't already be a $built_package_dir directory!"
echo "if it's not important, maybe delete it and try running the script again?"
exit 1
fi
git tag --delete "$tag" || true
tmpvenv=$(mktemp -d)
python3 -m venv "$tmpvenv"
. $tmpvenv/bin/activate
# update packaging tools to their pinned versions
tools/pip_install.py virtualenv
root_without_le="$version.$$"
root="$RELEASE_DIR/le.$root_without_le"
echo "Cloning into fresh copy at $root" # clean repo = no artifacts
git clone . $root
git rev-parse HEAD
cd $root
if [ "$RELEASE_BRANCH" != "candidate-$version" ] ; then
git branch -f "$RELEASE_BRANCH"
fi
git checkout "$RELEASE_BRANCH"
# Update changelog
sed -i "0,/main/ s/main/$(date +'%Y-%m-%d')/" certbot/CHANGELOG.md
git add certbot/CHANGELOG.md
git commit -m "Update changelog for $version release"
for pkg_dir in $SUBPKGS certbot-compatibility-test
do
sed -i 's/\.dev0//' "$pkg_dir/setup.py"
git add "$pkg_dir/setup.py"
done
SetVersion() {
ver="$1"
# bumping Certbot's version number is done differently
for pkg_dir in $SUBPKGS_NO_CERTBOT certbot-compatibility-test
do
setup_file="$pkg_dir/setup.py"
if [ $(grep -c '^version' "$setup_file") != 1 ]; then
echo "Unexpected count of version variables in $setup_file"
exit 1
fi
sed -i "s/^version.*/version = '$ver'/" $pkg_dir/setup.py
done
init_file="certbot/src/certbot/__init__.py"
if [ $(grep -c '^__version' "$init_file") != 1 ]; then
echo "Unexpected count of __version variables in $init_file"
exit 1
fi
sed -i "s/^__version.*/__version__ = '$ver'/" "$init_file"
git add $SUBPKGS certbot-compatibility-test
}
SetVersion "$version"
# Unset CERTBOT_OLDEST to prevent wheels from being built improperly due to
# conditionals like the one found in certbot-dns-dnsimple's setup.py file.
unset CERTBOT_OLDEST
echo "Preparing sdists and wheels"
for pkg_dir in $SUBPKGS
do
cd $pkg_dir
python setup.py clean
rm -rf build dist
python setup.py sdist
python setup.py bdist_wheel
cd -
done
mkdir "$built_package_dir"
for pkg_dir in $SUBPKGS
do
mv "$pkg_dir"/dist/* "$built_package_dir"
done
cd "$built_package_dir"
echo "Generating checksum file and signing it"
sha256sum *.tar.gz > SHA256SUMS
gpg -u "$RELEASE_GPG_KEY" --detach-sign --armor --sign --digest-algo sha256 SHA256SUMS
git add *.tar.gz SHA256SUMS*
echo "Installing packages to generate documentation"
# cd .. is NOT done on purpose: we make sure that all subpackages are
# installed from local archives rather than current directory (repo root)
VIRTUALENV_NO_DOWNLOAD=1 virtualenv ../venv
. ../venv/bin/activate
pip install -U setuptools
pip install -U pip
# This creates a string like "acme==a.b.c certbot==a.b.c ..." which can be used
# with pip to ensure the correct versions of our packages installed.
subpkgs_with_version=""
for pkg in $SUBPKGS; do
subpkgs_with_version="$subpkgs_with_version $pkg==$version"
done
# Now, use our local archives. Disable cache so we get the correct packages even if
# we (or our dependencies) have conditional dependencies implemented with if
# statements in setup.py and we have cached wheels lying around that would cause
# those ifs to not be evaluated.
python ../tools/pip_install.py \
--no-cache-dir \
--find-links . \
$subpkgs_with_version
cd ~-
# get a snapshot of the CLI help for the docs
# We set CERTBOT_DOCS to use dummy values in example user-agent string.
CERTBOT_DOCS=1 certbot --help all > certbot/docs/cli-help.txt
jws --help > acme/docs/jws-help.txt
deactivate
git add certbot/docs/cli-help.txt
while ! git commit --gpg-sign="$RELEASE_GPG_KEY" -m "Release $version"; do
echo "Unable to sign the release commit using git."
echo "You may have to configure git to use gpg by running:"
echo 'git config --global gpg.program $(command -v gpg)'
read -p "Press enter to try signing again."
done
git tag --local-user "$RELEASE_GPG_KEY" --sign --message "Release $version" "$tag"
git rm --cached -r "$built_package_dir"
git commit -m "Remove built packages from git"
# Add main section to CHANGELOG.md
header=$(head -n 4 certbot/CHANGELOG.md)
body=$(sed s/nextversion/$nextversion/ tools/_changelog_top.txt)
footer=$(tail -n +5 certbot/CHANGELOG.md)
echo "$header
$body
$footer" > certbot/CHANGELOG.md
git add certbot/CHANGELOG.md
git commit -m "Add contents to certbot/CHANGELOG.md for next version"
if [ "$RELEASE_BRANCH" = candidate-"$version" ] ; then
SetVersion "$nextversion".dev0
git commit -m "Bump version to $nextversion"
fi