tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

generate_release_doc.py (5763B)


      1 #!/usr/bin/env python3
      2 # This Source Code Form is subject to the terms of the Mozilla Public
      3 # License, v. 2.0. If a copy of the MPL was not distributed with this
      4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      5 
      6 """
      7 Generate NSS release documentation (RST file) based on version number.
      8 
      9 Usage: python3 generate_release_doc.py <version> <previous_version> [output_file]
     10 
     11 Example:
     12  python3 generate_release_doc.py 3.118 3.117
     13  python3 generate_release_doc.py 3.118.1 3.118 doc/rst/releases/nss_3_118_1.rst
     14 """
     15 
     16 import os
     17 import re
     18 import sys
     19 from datetime import datetime
     20 from subprocess import check_output
     21 
     22 
     23 def exit_with_failure(message):
     24    """Exit the script with an error message."""
     25    print(f"ERROR: {message}", file=sys.stderr)
     26    sys.exit(1)
     27 
     28 
     29 def version_string_to_underscore(version_string):
     30    """Convert version string like '3.118' to '3_118'."""
     31    return version_string.replace('.', '_')
     32 
     33 
     34 def version_string_to_RTM_tag(version_string):
     35    """Convert version string like '3.118' to 'NSS_3_118_RTM'."""
     36    parts = version_string.split('.')
     37    return "NSS_" + "_".join(parts) + "_RTM"
     38 
     39 
     40 def get_nspr_version():
     41    """Read the NSPR version from automation/release/nspr-version.txt."""
     42    nspr_version_file = "automation/release/nspr-version.txt"
     43    try:
     44        with open(nspr_version_file, 'r') as f:
     45            return f.readline().strip()
     46    except FileNotFoundError:
     47        exit_with_failure(f"Could not find {nspr_version_file}. Are you running from the NSS root directory?")
     48 
     49 
     50 def get_changes_from_hg(current_tag, previous_tag):
     51    """Extract bug changes from Mercurial log between two tags."""
     52    try:
     53        # Get log entries between previous tag and current tag
     54        command = ["hg", "log", "-r", f"{previous_tag}:{current_tag}", "--template", "{desc|firstline}\\n"]
     55        log_output = check_output(command).decode('utf-8')
     56    except Exception as e:
     57        exit_with_failure(f"Failed to get hg log: {e}")
     58 
     59    # Extract bug numbers and descriptions
     60    bug_lines = []
     61    for line in reversed(log_output.split('\n')):
     62        if 'Bug' in line or 'bug' in line:
     63            line = line.strip()
     64            # Remove reviewer information
     65            line = line.split("r=")[0].strip()
     66 
     67            # Match patterns like "Bug 1234567 Something" and convert to "Bug 1234567 - Something"
     68            line = re.sub(r'(Bug\s+\d+)\s+([^-])', r'\1 - \2', line, flags=re.IGNORECASE)
     69 
     70            # Clean up punctuation
     71            if line:
     72                line = line.rstrip(',')
     73 
     74            # Add a full stop at the end if there isn't one
     75            if line and not line.endswith('.'):
     76                line = line + '.'
     77 
     78            if line and line not in bug_lines:
     79                bug_lines.append(line)
     80 
     81    return bug_lines
     82 
     83 
     84 def generate_rst_content(version, nspr_version, bug_lines, release_date):
     85    """Generate the RST content for the release notes."""
     86    version_underscore = version_string_to_underscore(version)
     87    changes_text = "\n".join([f"   - {line}" for line in bug_lines])
     88 
     89    rst_content = f""".. _mozilla_projects_nss_nss_{version_underscore}_release_notes:
     90 
     91 NSS {version} release notes
     92 ========================
     93 
     94 `Introduction <#introduction>`__
     95 --------------------------------
     96 
     97 .. container::
     98 
     99   Network Security Services (NSS) {version} was released on *{release_date}**.
    100 
    101 `Distribution Information <#distribution_information>`__
    102 --------------------------------------------------------
    103 
    104 .. container::
    105 
    106   The HG tag is NSS_{version_underscore}_RTM. NSS {version} requires NSPR {nspr_version} or newer.
    107 
    108   NSS {version} source distributions are available on ftp.mozilla.org for secure HTTPS download:
    109 
    110   -  Source tarballs:
    111      https://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/NSS_{version_underscore}_RTM/src/
    112 
    113   Other releases are available :ref:`mozilla_projects_nss_releases`.
    114 
    115 .. _changes_in_nss_{version}:
    116 
    117 `Changes in NSS {version} <#changes_in_nss_{version}>`__
    118 ------------------------------------------------------------------
    119 
    120 .. container::
    121 
    122 {changes_text}
    123 
    124 """
    125    return rst_content
    126 
    127 
    128 def main():
    129    if len(sys.argv) < 3:
    130        print(__doc__)
    131        sys.exit(1)
    132 
    133    version = sys.argv[1].strip()
    134    previous_version = sys.argv[2].strip()
    135 
    136    # Determine output file
    137    if len(sys.argv) >= 4:
    138        output_file = sys.argv[3].strip()
    139    else:
    140        version_underscore = version_string_to_underscore(version)
    141        output_file = f"doc/rst/releases/nss_{version_underscore}.rst"
    142 
    143    # Get current date
    144    current_date = datetime.now().strftime("%-d %B %Y")
    145 
    146    # Get NSPR version
    147    nspr_version = get_nspr_version()
    148 
    149    # Convert versions to tags
    150    current_tag = version_string_to_RTM_tag(version)
    151    previous_tag = version_string_to_RTM_tag(previous_version)
    152 
    153    print(f"Generating release documentation for NSS {version}")
    154    print(f"Previous version: {previous_version}")
    155    print(f"Current tag: {current_tag}")
    156    print(f"Previous tag: {previous_tag}")
    157    print(f"NSPR version: {nspr_version}")
    158    print(f"Release date: {current_date}")
    159    print()
    160 
    161    # Get changes from Mercurial
    162    print("Extracting changes from Mercurial...")
    163    bug_lines = get_changes_from_hg(current_tag, previous_tag)
    164    print(f"Found {len(bug_lines)} bug entries")
    165    print()
    166 
    167    # Generate RST content
    168    rst_content = generate_rst_content(version, nspr_version, bug_lines, current_date)
    169 
    170    # Write to file
    171    os.makedirs(os.path.dirname(output_file), exist_ok=True)
    172    with open(output_file, 'w') as f:
    173        f.write(rst_content)
    174 
    175    print(f"Release documentation written to: {output_file}")
    176    print()
    177    print("=" * 70)
    178    print("Preview:")
    179    print("=" * 70)
    180    print(rst_content)
    181 
    182 
    183 if __name__ == "__main__":
    184    main()