Files
zulip/tools/upgrade-python-dependencies
Vishnu Ks e7507a6eb1 tools: Avoid upgrading stripe automatically.
Upgrades to the stripe library can sometimes break semantics for our
billing system, and so we should make sure to use our documented 
testing process before doing them.
2019-05-17 11:36:35 -07:00

109 lines
4.2 KiB
Python
Executable File

#!/usr/bin/env python3
import json
import os
import sys
import subprocess
import errno
from typing import List, Dict, Any
ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(ZULIP_PATH)
log_dir = "var/log/python_dependency_upgrade"
try:
os.makedirs(log_dir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
outdated_packages = [] # type: List[Dict[str, str]]
packages_json = subprocess.check_output(["pip", "list", "--outdated", "--format=json"])
outdated_packages = json.loads(packages_json.decode("utf-8"))
unupgradable_packages = {} # type: Dict[str, Any]
with open("requirements/unupgradable.json") as f:
unupgradable_packages = json.load(f)
def delete_locked_requirements(locked_requirement_files: List[str]) -> None:
for lock_file in locked_requirement_files:
try:
os.remove("requirements/{}".format(lock_file))
except OSError:
pass
def prepare_for_commit() -> None:
subprocess.check_output(["./tools/update-locked-requirements"], stderr=subprocess.STDOUT)
subprocess.check_output(["./tools/provision"], stderr=subprocess.STDOUT)
subprocess.check_output(["./tools/test-backend"], stderr=subprocess.STDOUT)
subprocess.check_call(["git", "add", "requirements"])
def commit_and_push(commit_msg: str) -> None:
subprocess.check_call(["git", "commit", "-m", commit_msg])
subprocess.check_call(["git", "push", "origin", "HEAD", "--force"])
def do_upgrade(requirement_file: str, locked_requirement_files: List[str]) -> None:
if len(locked_requirement_files) != 0:
delete_locked_requirements(locked_requirement_files)
try:
prepare_for_commit()
diff = subprocess.check_output(["git", "diff", "requirements/"])
if diff:
locked_files_str = ", ".join(locked_requirement_files)
commit_msg = "requirements: Upgrade indirect dependencies in {}.".format(locked_files_str)
commit_and_push(commit_msg)
except subprocess.CalledProcessError as e:
print("Upgrading indirect dependencies in {} failed".format(requirement_file))
log_file = "{}/{}".format(log_dir, requirement_file)
with open(log_file, "w") as f:
f.write(e.output.decode("utf-8"))
for package in outdated_packages:
pkg_name = package["name"]
version = package["version"]
latest_version = package["latest_version"]
log_file = "{}/{}".format(log_dir, pkg_name)
if pkg_name in unupgradable_packages:
continue
sed_string_template = "s/{name}=={version}/{name}=={latest_version}/g"
sed_string = sed_string_template.format(name=pkg_name, version=version,
latest_version=latest_version)
files_updated = False
subprocess.check_call(["git", "stash"])
file_path = "requirements/{}".format(requirement_file)
subprocess.check_call(["sed", "-i", sed_string, file_path])
files_updated = subprocess.check_output(["git", "diff", file_path])
if not files_updated:
continue
if pkg_name == "stripe":
with open(log_file, "w") as f:
url = ("https://zulip.readthedocs.io/en/stable/subsystems/billing.html"
"#upgrading-stripe-api-versions")
f.write("Stripe upgrade available. Upgrade manually. Make sure to update fixtures as well.")
f.write(url)
continue
try:
print("Trying to upgrade {}".format(pkg_name))
prepare_for_commit()
commit_msg = "requirements: Upgrade {} from {} to {}.".format(pkg_name, version, latest_version)
commit_and_push(commit_msg)
except subprocess.CalledProcessError as e:
print("{} upgrade failed".format(pkg_name))
with open(log_file, "w") as f:
f.write(e.output.decode("utf-8"))
do_upgrade("common.in", ["dev.txt", "prod.txt"])
do_upgrade("dev.in", [])
do_upgrade("prod.in", [])
do_upgrade("docs.in", ["docs.txt"])
do_upgrade("thumbor.in", ["thumbor.txt"])
do_upgrade("pip.txt", [])