flask/scripts/make-release.py

165 lines
3.8 KiB
Python
Executable File

#!/usr/bin/env python
from __future__ import print_function
import os
import re
import sys
from datetime import date
from datetime import datetime
from subprocess import PIPE
from subprocess import Popen
_date_strip_re = re.compile(r"(?<=\d)(st|nd|rd|th)")
def parse_changelog():
with open("CHANGES.rst") as f:
lineiter = iter(f)
for line in lineiter:
match = re.search(r"^Version\s+(.*)", line.strip())
if match is None:
continue
version = match.group(1).strip()
if next(lineiter).count("-") != len(match.group(0)):
continue
while 1:
change_info = next(lineiter).strip()
if change_info:
break
match = re.search(
r"released on (\w+\s+\d+\w+\s+\d+)(?:, codename (.*))?",
change_info,
flags=re.IGNORECASE,
)
if match is None:
continue
datestr, codename = match.groups()
return version, parse_date(datestr), codename
def bump_version(version):
try:
parts = [int(i) for i in version.split(".")]
except ValueError:
fail("Current version is not numeric")
parts[-1] += 1
return ".".join(map(str, parts))
def parse_date(string):
string = _date_strip_re.sub("", string)
return datetime.strptime(string, "%B %d %Y")
def set_filename_version(filename, version_number, pattern):
changed = []
def inject_version(match):
before, old, after = match.groups()
changed.append(True)
return before + version_number + after
with open(filename) as f:
contents = re.sub(
r"^(\s*%s\s*=\s*')(.+?)(')" % pattern,
inject_version,
f.read(),
flags=re.DOTALL | re.MULTILINE,
)
if not changed:
fail("Could not find %s in %s", pattern, filename)
with open(filename, "w") as f:
f.write(contents)
def set_init_version(version):
info("Setting __init__.py version to %s", version)
set_filename_version("flask/__init__.py", version, "__version__")
def build():
cmd = [sys.executable, "setup.py", "sdist", "bdist_wheel"]
Popen(cmd).wait()
def fail(message, *args):
print("Error:", message % args, file=sys.stderr)
sys.exit(1)
def info(message, *args):
print(message % args, file=sys.stderr)
def get_git_tags():
return set(Popen(["git", "tag"], stdout=PIPE).communicate()[0].splitlines())
def git_is_clean():
return Popen(["git", "diff", "--quiet"]).wait() == 0
def make_git_commit(message, *args):
message = message % args
Popen(["git", "commit", "-am", message]).wait()
def make_git_tag(tag):
info('Tagging "%s"', tag)
Popen(["git", "tag", tag]).wait()
def main():
os.chdir(os.path.join(os.path.dirname(__file__), ".."))
rv = parse_changelog()
if rv is None:
fail("Could not parse changelog")
version, release_date, codename = rv
dev_version = bump_version(version) + ".dev"
info(
"Releasing %s (codename %s, release date %s)",
version,
codename,
release_date.strftime("%d/%m/%Y"),
)
tags = get_git_tags()
if version in tags:
fail('Version "%s" is already tagged', version)
if release_date.date() != date.today():
fail("Release date is not today (%s != %s)", release_date.date(), date.today())
if not git_is_clean():
fail("You have uncommitted changes in git")
try:
import wheel # noqa: F401
except ImportError:
fail("You need to install the wheel package.")
set_init_version(version)
make_git_commit("Bump version number to %s", version)
make_git_tag(version)
build()
set_init_version(dev_version)
if __name__ == "__main__":
main()