106 строки
4.5 KiB
Python
106 строки
4.5 KiB
Python
# Common code used by the automation python scripts.
|
|
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
|
|
def step_msg(msg):
|
|
print(f"> \033[34m{msg}\033[0m")
|
|
|
|
def fatal_err(msg):
|
|
print(f"\033[31mError: {msg}\033[0m")
|
|
exit(1)
|
|
|
|
def run_cmd_checked(*args, **kwargs):
|
|
"""Run a command, throwing an exception if it exits with non-zero status."""
|
|
kwargs["check"] = True
|
|
return subprocess.run(*args, **kwargs)
|
|
|
|
def check_output(*args, **kwargs):
|
|
"""Run a command, throwing an exception if it exits with non-zero status."""
|
|
return subprocess.check_output(*args, **kwargs, encoding='utf8')
|
|
|
|
def ensure_working_tree_clean():
|
|
"""Error out if there are un-committed or staged files in the working tree."""
|
|
if run_cmd_checked(["git", "status", "--porcelain"], capture_output=True).stdout:
|
|
fatal_err("The working tree has un-commited or staged files.")
|
|
|
|
def find_app_services_root():
|
|
"""Find the absolute path of the Application services repository root."""
|
|
cur_dir = Path(__file__).parent
|
|
while not Path(cur_dir, "LICENSE").exists():
|
|
cur_dir = cur_dir.parent
|
|
return cur_dir.absolute()
|
|
|
|
def get_moz_remote():
|
|
"""
|
|
Get the name of the remote for the official mozilla application-services repo
|
|
"""
|
|
for line in check_output(["git", "remote", "-v"]).splitlines():
|
|
split = line.split()
|
|
if (len(split) == 3
|
|
and split[1] == 'git@github.com:mozilla/application-services.git'
|
|
and split[2] == '(push)'):
|
|
return split[0]
|
|
else:
|
|
fatal_err("Can't find remote origin for git@github.com:mozilla/application-services.git")
|
|
|
|
def set_gradle_substitution_path(project_dir, name, value):
|
|
"""Set a substitution path property in a gradle `local.properties` file.
|
|
|
|
Given the path to a gradle project directory, this helper will set the named
|
|
property to the given path value in that directory's `local.properties` file.
|
|
If the named property already exists with the correct value then it will
|
|
silently succeed; if the named property already exists with a different value
|
|
then it will noisily fail.
|
|
"""
|
|
project_dir = Path(project_dir).resolve()
|
|
properties_file = project_dir / "local.properties"
|
|
step_msg(f"Configuring local publication in project at {properties_file}")
|
|
name_eq = name + "="
|
|
abs_value = Path(value).resolve()
|
|
# Check if the named property already exists.
|
|
if properties_file.exists():
|
|
with properties_file.open() as f:
|
|
for ln in f:
|
|
# Not exactly a thorough parser, but should be good enough...
|
|
if ln.startswith(name_eq):
|
|
cur_value = ln[len(name_eq):].strip()
|
|
if Path(project_dir, cur_value).resolve() != abs_value:
|
|
fatal_error(f"Conflicting property {name}={cur_value} (not {abs_value})")
|
|
return
|
|
# The file does not contain the required property, append it.
|
|
# Note that the project probably expects a path relative to the project root.
|
|
ancestor = Path(os.path.commonpath([project_dir, abs_value]))
|
|
relpath = Path(".")
|
|
for _ in project_dir.parts[len(ancestor.parts):]:
|
|
relpath /= ".."
|
|
for nm in abs_value.parts[len(ancestor.parts):]:
|
|
relpath /= nm
|
|
step_msg(f"Setting relative path from {project_dir} to {abs_value} as {relpath}")
|
|
with properties_file.open("a") as f:
|
|
f.write(f"{name}={relpath}\n")
|
|
|
|
class RefNames:
|
|
"""
|
|
Contains the branch and tag names we use for automation.
|
|
|
|
Attributes:
|
|
main -- where new development happens
|
|
release_branch -- contains the code for a given major release
|
|
release_pr_branch -- Used for PRs against release_branch for a new version
|
|
start_release_pr_branch -- Used for PRs against main to start a new major release
|
|
"""
|
|
def __init__(self, major_version_number, minor_version_number):
|
|
major_version_number = int(major_version_number)
|
|
minor_version_number = int(minor_version_number)
|
|
self.main = "main"
|
|
self.release = f"release-v{major_version_number}"
|
|
self.release_pr = f"cut-v{major_version_number}.{minor_version_number}"
|
|
self.start_release_pr = f"start-release-v{major_version_number+1}"
|
|
self.version_tag = f"v{major_version_number}.{minor_version_number}"
|
|
if minor_version_number == 0:
|
|
self.previous_version_tag = f"v{major_version_number-1}.0"
|
|
else:
|
|
self.previous_version_tag = f"v{major_version_number}.{minor_version_number-1}"
|