richard pushed to branch maint-13.0 at The Tor Project / Applications / tor-browser-build

Commits:

1 changed file:

Changes:

  • tools/fetch-changelogs.py
    1 1
     #!/usr/bin/env python3
    
    2
    +import argparse
    
    2 3
     from datetime import datetime
    
    3 4
     import enum
    
    4 5
     from pathlib import Path
    
    ... ... @@ -23,6 +24,11 @@ project_order = {
    23 24
     }
    
    24 25
     
    
    25 26
     
    
    27
    +class EntryType(enum.IntFlag):
    
    28
    +    UPDATE = 0
    
    29
    +    ISSUE = 1
    
    30
    +
    
    31
    +
    
    26 32
     class Platform(enum.IntFlag):
    
    27 33
         WINDOWS = 8
    
    28 34
         MACOS = 4
    
    ... ... @@ -32,40 +38,12 @@ class Platform(enum.IntFlag):
    32 38
         ALL_PLATFORMS = 8 | 4 | 2 | 1
    
    33 39
     
    
    34 40
     
    
    35
    -class Issue:
    
    36
    -    def __init__(self, j):
    
    37
    -        self.title = j["title"]
    
    38
    -        self.project, self.number = (
    
    39
    -            j["references"]["full"].rsplit("/", 2)[-1].split("#")
    
    40
    -        )
    
    41
    -        self.number = int(self.number)
    
    42
    -        self.platform = 0
    
    43
    -        self.num_platforms = 0
    
    44
    -        if "Desktop" in j["labels"]:
    
    45
    -            self.platform = Platform.DESKTOP
    
    46
    -            self.num_platforms += 3
    
    47
    -        else:
    
    48
    -            if "Windows" in j["labels"]:
    
    49
    -                self.platform |= Platform.WINDOWS
    
    50
    -                self.num_platforms += 1
    
    51
    -            if "MacOS" in j["labels"]:
    
    52
    -                self.platform |= Platform.MACOS
    
    53
    -                self.num_platforms += 1
    
    54
    -            if "Linux" in j["labels"]:
    
    55
    -                self.platform |= Platform.LINUX
    
    56
    -                self.num_platforms += 1
    
    57
    -        if "Android" in j["labels"]:
    
    58
    -            if is_mb and self.num_platforms == 0:
    
    59
    -                raise Exception(
    
    60
    -                    f"Android-only issue on Mullvad Browser: {j['references']['full']}!"
    
    61
    -                )
    
    62
    -            elif not is_mb:
    
    63
    -                self.platform |= Platform.ANDROID
    
    64
    -                self.num_platforms += 1
    
    65
    -        if not self.platform or (is_mb and self.platform == Platform.DESKTOP):
    
    66
    -            self.platform = Platform.ALL_PLATFORMS
    
    67
    -            self.num_platforms = 4
    
    68
    -        self.is_build = "Build System" in j["labels"]
    
    41
    +class ChangelogEntry:
    
    42
    +    def __init__(self, type_, platform, num_platforms, is_build):
    
    43
    +        self.type = type_
    
    44
    +        self.platform = platform
    
    45
    +        self.num_platforms = num_platforms
    
    46
    +        self.is_build = is_build
    
    69 47
     
    
    70 48
         def get_platforms(self):
    
    71 49
             if self.platform == Platform.ALL_PLATFORMS:
    
    ... ... @@ -81,15 +59,78 @@ class Issue:
    81 59
                 platforms.append("Android")
    
    82 60
             return " + ".join(platforms)
    
    83 61
     
    
    84
    -    def __str__(self):
    
    85
    -        return f"Bug {self.number}: {self.title} [{self.project}]"
    
    86
    -
    
    87 62
         def __lt__(self, other):
    
    63
    +        if self.type != other.type:
    
    64
    +            return self.type < other.type
    
    65
    +        if self.type == EntryType.UPDATE:
    
    66
    +            # Rely on sorting being stable on Python
    
    67
    +            return False
    
    88 68
             if self.project == other.project:
    
    89 69
                 return self.number < other.number
    
    90 70
             return project_order[self.project] < project_order[other.project]
    
    91 71
     
    
    92 72
     
    
    73
    +class UpdateEntry(ChangelogEntry):
    
    74
    +    def __init__(self, name, version):
    
    75
    +        if name == "Firefox" and not is_mb:
    
    76
    +            platform = Platform.DESKTOP
    
    77
    +            num_platforms = 3
    
    78
    +        elif name == "GeckoView":
    
    79
    +            platform = Platform.ANDROID
    
    80
    +            num_platforms = 3
    
    81
    +        else:
    
    82
    +            platform = Platform.ALL_PLATFORMS
    
    83
    +            num_platforms = 4
    
    84
    +        super().__init__(
    
    85
    +            EntryType.UPDATE, platform, num_platforms, name == "Go"
    
    86
    +        )
    
    87
    +        self.name = name
    
    88
    +        self.version = version
    
    89
    +
    
    90
    +    def __str__(self):
    
    91
    +        return f"Updated {self.name} to {self.version}"
    
    92
    +
    
    93
    +
    
    94
    +class Issue(ChangelogEntry):
    
    95
    +    def __init__(self, j):
    
    96
    +        self.title = j["title"]
    
    97
    +        self.project, self.number = (
    
    98
    +            j["references"]["full"].rsplit("/", 2)[-1].split("#")
    
    99
    +        )
    
    100
    +        self.number = int(self.number)
    
    101
    +        platform = 0
    
    102
    +        num_platforms = 0
    
    103
    +        if "Desktop" in j["labels"]:
    
    104
    +            platform = Platform.DESKTOP
    
    105
    +            num_platforms += 3
    
    106
    +        else:
    
    107
    +            if "Windows" in j["labels"]:
    
    108
    +                platform |= Platform.WINDOWS
    
    109
    +                num_platforms += 1
    
    110
    +            if "MacOS" in j["labels"]:
    
    111
    +                platform |= Platform.MACOS
    
    112
    +                num_platforms += 1
    
    113
    +            if "Linux" in j["labels"]:
    
    114
    +                platform |= Platform.LINUX
    
    115
    +                num_platforms += 1
    
    116
    +        if "Android" in j["labels"]:
    
    117
    +            if is_mb and num_platforms == 0:
    
    118
    +                raise Exception(
    
    119
    +                    f"Android-only issue on Mullvad Browser: {j['references']['full']}!"
    
    120
    +                )
    
    121
    +            elif not is_mb:
    
    122
    +                platform |= Platform.ANDROID
    
    123
    +                num_platforms += 1
    
    124
    +        if not platform or (is_mb and platform == Platform.DESKTOP):
    
    125
    +            platform = Platform.ALL_PLATFORMS
    
    126
    +            num_platforms = 4
    
    127
    +        is_build = "Build System" in j["labels"]
    
    128
    +        super().__init__(EntryType.ISSUE, platform, num_platforms, is_build)
    
    129
    +
    
    130
    +    def __str__(self):
    
    131
    +        return f"Bug {self.number}: {self.title} [{self.project}]"
    
    132
    +
    
    133
    +
    
    93 134
     def sorted_issues(issues):
    
    94 135
         issues = [sorted(v) for v in issues.values()]
    
    95 136
         return sorted(
    
    ... ... @@ -99,8 +140,20 @@ def sorted_issues(issues):
    99 140
         )
    
    100 141
     
    
    101 142
     
    
    102
    -if len(sys.argv) < 2:
    
    103
    -    print(f"Usage: {sys.argv[0]} version-to-release or #issue-id")
    
    143
    +parser = argparse.ArgumentParser()
    
    144
    +parser.add_argument("issue_version")
    
    145
    +parser.add_argument("--date", help="The date of the release")
    
    146
    +parser.add_argument("--firefox", help="New Firefox version (if we rebased)")
    
    147
    +parser.add_argument("--tor", help="New Tor version (if updated)")
    
    148
    +parser.add_argument("--no-script", help="New NoScript version (if updated)")
    
    149
    +parser.add_argument("--openssl", help="New OpenSSL version (if updated)")
    
    150
    +parser.add_argument("--ublock", help="New uBlock version (if updated)")
    
    151
    +parser.add_argument("--zlib", help="New zlib version (if updated)")
    
    152
    +parser.add_argument("--go", help="New Go version (if updated)")
    
    153
    +args = parser.parse_args()
    
    154
    +
    
    155
    +if not args.issue_version:
    
    156
    +    parser.print_help()
    
    104 157
         sys.exit(1)
    
    105 158
     
    
    106 159
     token_file = Path(__file__).parent / ".changelogs_token"
    
    ... ... @@ -121,7 +174,7 @@ with token_file.open() as f:
    121 174
         token = f.read().strip()
    
    122 175
     headers = {"PRIVATE-TOKEN": token}
    
    123 176
     
    
    124
    -version = sys.argv[1]
    
    177
    +version = args.issue_version
    
    125 178
     r = requests.get(
    
    126 179
         f"{API_URL}/projects/{PROJECT_ID}/issues?labels=Release Prep",
    
    127 180
         headers=headers,
    
    ... ... @@ -132,7 +185,7 @@ if r.status_code == 401:
    132 185
     issue = None
    
    133 186
     issues = []
    
    134 187
     for i in r.json():
    
    135
    -    if i["title"].find(sys.argv[1]) != -1:
    
    188
    +    if i["title"].find(version) != -1:
    
    136 189
             issues.append(i)
    
    137 190
     if len(issues) == 1:
    
    138 191
         issue = issues[0]
    
    ... ... @@ -172,20 +225,44 @@ iid = issue["iid"]
    172 225
     
    
    173 226
     linked = {}
    
    174 227
     linked_build = {}
    
    228
    +
    
    229
    +
    
    230
    +def add_entry(entry):
    
    231
    +    target = linked_build if entry.is_build else linked
    
    232
    +    if entry.platform not in target:
    
    233
    +        target[entry.platform] = []
    
    234
    +    target[entry.platform].append(entry)
    
    235
    +
    
    236
    +
    
    237
    +if args.firefox:
    
    238
    +    add_entry(UpdateEntry("Firefox", args.firefox))
    
    239
    +    if not is_mb:
    
    240
    +        add_entry(UpdateEntry("GeckoView", args.firefox))
    
    241
    +if args.tor and not is_mb:
    
    242
    +    add_entry(UpdateEntry("Tor", args.tor))
    
    243
    +if args.no_script:
    
    244
    +    add_entry(UpdateEntry("NoScript", args.no_script))
    
    245
    +if not is_mb:
    
    246
    +    if args.openssl:
    
    247
    +        add_entry(UpdateEntry("OpenSSL", args.openssl))
    
    248
    +    if args.zlib:
    
    249
    +        add_entry(UpdateEntry("zlib", args.zlib))
    
    250
    +    if args.go:
    
    251
    +        add_entry(UpdateEntry("Go", args.go))
    
    252
    +elif args.ublock:
    
    253
    +    add_entry(UpdateEntry("uBlock Origin", args.ublock))
    
    254
    +
    
    175 255
     r = requests.get(
    
    176 256
         f"{API_URL}/projects/{PROJECT_ID}/issues/{iid}/links", headers=headers
    
    177 257
     )
    
    178 258
     for i in r.json():
    
    179
    -    i = Issue(i)
    
    180
    -    target = linked_build if i.is_build else linked
    
    181
    -    if i.platform not in target:
    
    182
    -        target[i.platform] = []
    
    183
    -    target[i.platform].append(i)
    
    259
    +    add_entry(Issue(i))
    
    260
    +
    
    184 261
     linked = sorted_issues(linked)
    
    185 262
     linked_build = sorted_issues(linked_build)
    
    186 263
     
    
    187 264
     name = "Mullvad" if is_mb else "Tor"
    
    188
    -date = datetime.now().strftime("%B %d %Y")
    
    265
    +date = args.date if args.date else datetime.now().strftime("%B %d %Y")
    
    189 266
     print(f"{name} Browser {version} - {date}")
    
    190 267
     for issues in linked:
    
    191 268
         print(f" * {issues[0].get_platforms()}")