Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | import argparse |
| 3 | import sys |
| 4 | import os |
| 5 | import re |
| 6 | import subprocess |
| 7 | |
| 8 | |
Paul Sokolovsky | 910fd55 | 2024-02-20 00:26:10 +0700 | [diff] [blame] | 9 | DEFAULT_URL = "https://review.trustedfirmware.org/TF-A/trusted-firmware-a" |
Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 10 | WORKDIR = "trusted-firmware-a" |
| 11 | |
Paul Sokolovsky | 006f923 | 2024-01-29 17:57:01 +0700 | [diff] [blame] | 12 | SKIP_PATTERNS = [ |
| 13 | r"docs\(changelog\): ", |
| 14 | r"Merge changes from topic ", |
| 15 | r"Merge \".+\" into ", |
| 16 | r"Merge changes .+ into ", |
| 17 | ] |
| 18 | |
Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 19 | |
| 20 | def run(cmd): |
| 21 | return subprocess.check_call(cmd, shell=True) |
| 22 | |
| 23 | |
| 24 | def maybe_int(s): |
| 25 | if s.isdigit(): |
| 26 | return int(s) |
| 27 | return s |
| 28 | |
| 29 | |
Paul Sokolovsky | 6386ce6 | 2024-06-05 15:11:03 +0300 | [diff] [blame] | 30 | def is_sandbox_run(): |
| 31 | return os.environ.get("SANDBOX_RUN") != "false" |
| 32 | |
| 33 | |
Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 34 | def main(): |
| 35 | argp = argparse.ArgumentParser(description="Prepare TF-A LTS release email content") |
Paul Sokolovsky | 910fd55 | 2024-02-20 00:26:10 +0700 | [diff] [blame] | 36 | argp.add_argument("-u", "--url", default=DEFAULT_URL, help="repository URL (default: %(default)s)") |
| 37 | argp.add_argument("-b", "--branch", default="", help="repository branch for --latest option") |
| 38 | argp.add_argument("--latest", action="store_true", help="use latest release tag on --branch") |
Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 39 | argp.add_argument("release_tag", nargs="?", help="release tag") |
| 40 | args = argp.parse_args() |
| 41 | if not args.release_tag and not args.latest: |
| 42 | argp.error("Either release_tag or --latest is required") |
| 43 | |
| 44 | with open(os.path.dirname(__file__) + "/lts-release-mail.txt") as f: |
| 45 | mail_template = f.read() |
| 46 | |
| 47 | if not os.path.exists(WORKDIR): |
Paul Sokolovsky | 910fd55 | 2024-02-20 00:26:10 +0700 | [diff] [blame] | 48 | run("git clone %s %s" % (args.url, WORKDIR)) |
Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 49 | os.chdir(WORKDIR) |
| 50 | else: |
| 51 | os.chdir(WORKDIR) |
| 52 | run("git pull --quiet") |
| 53 | |
| 54 | if args.latest: |
| 55 | latest = [] |
| 56 | for l in os.popen("git tag"): |
| 57 | if not re.match(r"lts-v\d+\.\d+\.\d+", l): |
| 58 | continue |
Paul Sokolovsky | 910fd55 | 2024-02-20 00:26:10 +0700 | [diff] [blame] | 59 | if not l.startswith(args.branch): |
| 60 | continue |
Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 61 | l = l.rstrip() |
| 62 | comps = [maybe_int(x) for x in l.split(".")] |
| 63 | comps.append(l) |
| 64 | if comps > latest: |
| 65 | latest = comps |
| 66 | if not latest: |
| 67 | argp.error("Could not find latest LTS tag") |
| 68 | args.release_tag = latest[-1] |
| 69 | |
Paul Sokolovsky | c119781 | 2024-02-20 14:50:10 +0700 | [diff] [blame] | 70 | base_release = args.release_tag |
| 71 | # If it's "sandbox" tag, convert it to the corresponding release tag for |
| 72 | # rendering the template. |
| 73 | if base_release.startswith("sandbox/"): |
| 74 | m = re.match(r"sandbox/(.+)-\d+", base_release) |
| 75 | base_release = m.group(1) |
| 76 | comps = base_release.split(".") |
Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 77 | prev_comps = comps[:-1] + [str(int(comps[-1]) - 1)] |
| 78 | prev_release = ".".join(prev_comps) |
| 79 | |
| 80 | subjects = [] |
| 81 | for l in os.popen("git log --oneline --reverse %s..%s" % (prev_release, args.release_tag)): |
Paul Sokolovsky | 006f923 | 2024-01-29 17:57:01 +0700 | [diff] [blame] | 82 | skip = False |
| 83 | for pat in SKIP_PATTERNS: |
| 84 | if re.match(pat, l.split(" ", 1)[1]): |
| 85 | skip = True |
| 86 | if not skip: |
| 87 | subjects.append(l.rstrip()) |
Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 88 | |
| 89 | urls = [] |
| 90 | for s in subjects: |
| 91 | commit_id, _ = s.split(" ", 1) |
| 92 | for l in os.popen("git show %s" % commit_id): |
| 93 | if "Change-Id:" in l: |
| 94 | _, change_id = l.strip().split(None, 1) |
| 95 | urls.append("https://review.trustedfirmware.org/q/" + change_id) |
| 96 | |
| 97 | assert len(subjects) == len(urls) |
| 98 | |
| 99 | commits = "" |
| 100 | for i, s in enumerate(subjects, 1): |
| 101 | commits += "%s [%d]\n" % (s, i) |
| 102 | |
| 103 | references = "" |
| 104 | for i, s in enumerate(urls, 1): |
| 105 | references += "[%d] %s\n" % (i, s) |
| 106 | |
| 107 | # Strip trailing newline, as it's encoded in template. |
| 108 | commits = commits.rstrip() |
| 109 | references = references.rstrip() |
| 110 | |
Paul Sokolovsky | 6386ce6 | 2024-06-05 15:11:03 +0300 | [diff] [blame] | 111 | if is_sandbox_run(): |
Paul Sokolovsky | ff2f4d0 | 2024-06-06 17:57:35 +0300 | [diff] [blame^] | 112 | rtd_url = "https://trustedfirmware-a-sandbox.readthedocs.io/en/" |
Paul Sokolovsky | 6386ce6 | 2024-06-05 15:11:03 +0300 | [diff] [blame] | 113 | else: |
| 114 | rtd_url = "https://trustedfirmware-a.readthedocs.io/en/" |
| 115 | rtd_slug = args.release_tag.lower().replace("/", "-") |
| 116 | rtd_url += rtd_slug |
| 117 | |
Paul Sokolovsky | c119781 | 2024-02-20 14:50:10 +0700 | [diff] [blame] | 118 | version = base_release[len("lts-v"):] |
Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 119 | sys.stdout.write( |
| 120 | mail_template.format( |
| 121 | version=version, |
| 122 | commits=commits, |
| 123 | references=references, |
Paul Sokolovsky | 6386ce6 | 2024-06-05 15:11:03 +0300 | [diff] [blame] | 124 | rtd_url=rtd_url, |
Paul Sokolovsky | 2e361a1 | 2023-10-31 21:38:32 +0300 | [diff] [blame] | 125 | ) |
| 126 | ) |
| 127 | |
| 128 | |
| 129 | if __name__ == "__main__": |
| 130 | main() |