Changes between Version 3 and Version 4 of ReleaseScript
- Timestamp:
- May 7, 2025, 4:16:49 PM (4 months ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
ReleaseScript
v3 v4 1 This Python script helps release a new version of Django. You should run this script from the Django repo root, having checked out the stable branch that you wish to release. 1 This Python script helps release a new version of Django. You should run this script from the Django repo root, having checked out the stable branch that you wish to release. Common usage: 2 3 {{{ 4 $ PGP_KEY_ID=1112223334445556 PGP_KEY_URL=https://github.com/octopus.gpg DEST_FOLDER=~/django/releases do_django_release.py 5 }}} 6 2 7 {{{#!python 3 8 #! /usr/bin/env python … … 9 14 import subprocess 10 15 from datetime import date 11 from io import StringIO 12 13 PGP_KEY_ID = "2EE82A8D9470983E" 14 PGP_EMAIL = "124304+nessita@users.noreply.github.com" 15 PATH_TO_BINARIES = "/home/nessita/fellowship/releases" 16 CHECKSUM_DEST_DIR = "/home/nessita/fellowship/releases/checksums" 17 GITHUB_USERNAME = "nessita" 18 19 checksum_file_text = """This file contains MD5, SHA1, and SHA256 checksums for the source-code 20 tarball and wheel files of Django {django_version}, released {release_date}. 16 17 PGP_KEY_ID = os.getenv("PGP_KEY_ID", "") 18 PGP_KEY_URL = os.getenv("PGP_KEY_URL", "") 19 PGP_EMAIL = os.getenv("PGP_EMAIL", "") 20 DEST_FOLDER = os.path.expanduser(os.getenv("DEST_FOLDER", "")) 21 22 assert ( 23 PGP_KEY_ID 24 ), "Missing PGP_KEY_ID: Set this env var to your PGP key ID (used for signing)." 25 assert ( 26 PGP_KEY_URL 27 ), "Missing PGP_KEY_URL: Set this env var to your PGP public key URL (for fetching)." 28 assert DEST_FOLDER and os.path.exists( 29 DEST_FOLDER 30 ), "Missing DEST_FOLDER: Set this env var to the local path to place the artifacts." 31 32 33 checksum_file_text = """This file contains MD5, SHA1, and SHA256 checksums for the 34 source-code tarball and wheel files of Django {django_version}, released {release_date}. 21 35 22 36 To use this file, you will need a working install of PGP or other … … 31 45 or via the GitHub API: 32 46 33 curl https://github.com/{github_username}.gpg| gpg --import -47 curl {pgp_key_url} | gpg --import - 34 48 35 49 Once the key is imported, verify this file: … … 67 81 """ 68 82 69 PATH_TO_DJANGO = os.path.abspath(os.path.curdir)70 83 71 84 def build_artifacts(): … … 83 96 subprocess.call(["git", "clean", "-fdx"]) 84 97 85 dist_path = os.path.join(PATH_TO_DJANGO, "dist/") 86 87 ## Build release files. 98 django_repo_path = os.path.abspath(os.path.curdir) 99 dist_path = os.path.join(django_repo_path, "dist/") 100 101 # Build release files. 88 102 build_artifacts() 89 103 release_files = os.listdir(dist_path) … … 101 115 django_version = wheel_name.split("-")[1] 102 116 django_major_version = ".".join(django_version.split(".")[:2]) 117 118 artifacts_path = os.path.join(os.path.expanduser(DEST_FOLDER), django_version) 119 os.makedirs(artifacts_path, exist_ok=True) 120 103 121 # Chop alpha/beta/rc suffix 104 122 match = re.search("[abrc]", django_major_version) … … 112 130 pgp_key_id=PGP_KEY_ID, 113 131 django_version=django_version, 114 github_username=GITHUB_USERNAME,132 pgp_key_url=PGP_KEY_URL, 115 133 checksum_file_name=checksum_file_name, 116 134 wheel_name=wheel_name, … … 132 150 # Create the checksum file 133 151 checksum_file_text = checksum_file_text.format(**checksum_file_kwargs) 134 os.makedirs(CHECKSUM_DEST_DIR, exist_ok=True) 135 checksum_file_path = os.path.join(CHECKSUM_DEST_DIR, checksum_file_name) 152 checksum_file_path = os.path.join(artifacts_path, checksum_file_name) 136 153 with open(checksum_file_path, "wb") as f: 137 154 f.write(checksum_file_text.encode("ascii")) … … 166 183 167 184 # Sign the checksum file, this may prompt for a passphrase. 168 print(f"gpg --clearsign -u {PGP_EMAIL} --digest-algo SHA256 {checksum_file_path}") 185 pgp_email = f"-u {PGP_EMAIL} " if PGP_EMAIL else "" 186 print(f"gpg --clearsign {pgp_email}--digest-algo SHA256 {checksum_file_path}") 169 187 # Create, verify and push tag 170 188 print(f'git tag --sign --message="Tag {django_version}" {django_version}') … … 172 190 173 191 # Copy binaries outside the current repo tree to avoid lossing them. 174 path_to_binaries = os.path.join(PATH_TO_BINARIES, django_version) 175 os.makedirs(path_to_binaries, exist_ok=True) 176 subprocess.run(["cp", "-r", dist_path, path_to_binaries]) 192 subprocess.run(["cp", "-r", dist_path, artifacts_path]) 177 193 178 194 # Make the binaries available to the world … … 183 199 # Upload the checksum file and release artifacts to the djangoproject admin. 184 200 print( 185 "\n==> ACTION Add a new Release entry in https://www.djangoproject.com/admin/releases/release/add/:" 186 ) 187 print( 188 f"""* Version: {django_version} 189 * Is active: False 190 * Release date: {release_date} 191 * End of life date: None""" 192 ) 193 194 print( 195 "\n==> ACTION Add tarball, wheel, and checksum files to the newly created Release entry:" 196 ) 197 print( 198 f"""* Tarball and wheel from {path_to_binaries} 199 * Signed checksum {checksum_file_path}.asc""" 201 "\n==> ACTION Add a new Release entry in " 202 "https://www.djangoproject.com/admin/releases/release/add/:" 203 ) 204 print( 205 f"* Version: {django_version}\n" 206 "* Is active: False\n" 207 f"* Release date: {release_date}\n" 208 "* End of life date: None" 209 ) 210 211 print("\n==> ACTION Add tarball, wheel, and checksum files to the Release entry:") 212 print( 213 f"* Tarball and wheel from {artifacts_path}\n" 214 f"* Signed checksum {checksum_file_path}.asc" 200 215 ) 201 216 … … 208 223 # Upload to PyPI. 209 224 print("\n==> ACTION Upload to PyPI:") 210 print(f"cd { path_to_binaries}")225 print(f"cd {artifacts_path}") 211 226 print("source ~/.virtualenvs/djangorelease/bin/activate") 212 227 print("pip install -U pip twine")