tor-browser

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

helpers.py (4852B)


      1 #!/usr/bin/env python3
      2 
      3 import argparse
      4 import os
      5 import re
      6 import shlex
      7 import subprocess
      8 
      9 
     10 def git(command):
     11    result = subprocess.run(
     12        ["git"] + shlex.split(command), check=True, capture_output=True, text=True
     13    )
     14    return result.stdout.strip()
     15 
     16 
     17 def get_firefox_tag(reference):
     18    """Extracts the Firefox tag associated with a branch or tag name.
     19 
     20       The "firefox tag" is the tag that marks
     21       the end of the Mozilla commits and the start of the Tor Project commits.
     22 
     23       Know issue: If ever there is more than one tag per Firefox ESR version,
     24       this function may return the incorrect reference number.
     25 
     26    Args:
     27        reference: The branch or tag name to extract the Firefox tag from.
     28        Expected format is tor-browser-91.2.0esr-11.0-1,
     29        where 91.2.0esr is the Firefox version.
     30 
     31    Returns:
     32        The reference specifier of the matching Firefox tag.
     33        An exception will be raised if anything goes wrong.
     34    """
     35 
     36    # Extracts the version number from a branch or tag name.
     37    firefox_version = ""
     38    match = re.search(r"(?<=browser-)([^-]+)", reference)
     39    if match:
     40        # TODO: Validate that what we got is actually a valid semver string?
     41        firefox_version = match.group(1)
     42    else:
     43        raise ValueError(f"Failed to extract version from reference '{reference}'.")
     44 
     45    major_version = firefox_version.split(".")[0]
     46    minor_patch_version = "_".join(firefox_version.split(".")[1:])
     47 
     48    remote_tags = git("ls-remote --tags origin")
     49 
     50    # Each line looks like:
     51    # 9edd658bfd03a6b4743ecb75fd4a9ad968603715  refs/tags/FIREFOX_91_9_0esr_BUILD1
     52    pattern = (
     53        rf"(.*)FIREFOX_{re.escape(major_version)}_{re.escape(minor_patch_version)}(.*)$"
     54    )
     55    match = re.search(pattern, remote_tags, flags=re.MULTILINE)
     56    if not match:
     57        # Attempt to match with a nightly tag, in case the ESR tag is not found
     58        pattern = rf"(.*)FIREFOX_NIGHTLY_{re.escape(major_version)}(.*)$"
     59        match = re.search(pattern, remote_tags, flags=re.MULTILINE)
     60 
     61    if match:
     62        return match.group(0).split()[0]
     63    else:
     64        raise ValueError(
     65            f"Failed to find reference specifier for Firefox tag of version '{firefox_version}' from '{reference}'."
     66        )
     67 
     68 
     69 def get_list_of_changed_files():
     70    """Gets a list of files changed in the working directory.
     71 
     72       This function is meant to be run inside the Gitlab CI environment.
     73 
     74       When running in a default branch, get the list of changed files since the last Firefox tag.
     75       When running for a new MR commit, get a list of changed files in the current MR.
     76 
     77    Returns:
     78        A list of filenames of changed files (excluding deleted files).
     79        An exception wil be raised if anything goes wrong.
     80    """
     81 
     82    base_reference = ""
     83 
     84    if os.getenv("CI_PIPELINE_SOURCE") == "merge_request_event":
     85        # For merge requests, the base_reference is the common ancestor between the MR and the target branch
     86        base_reference = os.getenv("CI_MERGE_REQUEST_DIFF_BASE_SHA")
     87        if not base_reference:
     88            # Probably because there has been no overall change.
     89            # See gitlab.com/gitlab-org/gitlab/-/issues/375047#note_2648459916
     90            return []
     91    else:
     92        # When not in merge requests, the base reference is the Firefox tag
     93        base_reference = get_firefox_tag(os.getenv("CI_COMMIT_BRANCH"))
     94 
     95    if not base_reference:
     96        raise RuntimeError("No base reference found. There might be more errors above.")
     97 
     98    # Fetch the tag reference
     99    git(f"fetch origin {base_reference} --depth=1 --filter=blob:none")
    100    # Return but filter the issue_templates files because those file names have spaces which can cause issues
    101    return git("diff --diff-filter=d --name-only FETCH_HEAD HEAD").split("\n")
    102 
    103 
    104 if __name__ == "__main__":
    105    parser = argparse.ArgumentParser(description="")
    106 
    107    parser.add_argument(
    108        "--get-firefox-tag",
    109        help="Get the Firefox tag related to a given (tor-mullvad-base)-browser tag or branch name.",
    110        type=str,
    111    )
    112    parser.add_argument(
    113        "--get-changed-files",
    114        help="Get list of changed files."
    115        "When running from a merge request gets the list of changed files since the merge-base of the current branch."
    116        "When running from a protected branch i.e. any branch that starts with <something>-browser-, gets the list of files changed since the FIREFOX_ tag.",
    117        action="store_true",
    118    )
    119 
    120    args = parser.parse_args()
    121 
    122    if args.get_firefox_tag:
    123        print(get_firefox_tag(args.get_firefox_tag))
    124    elif args.get_changed_files:
    125        # Separate the file names with a 0 byte to be parsed by xargs -0. Also
    126        # drop the trailing '\n'.
    127        print("\0".join(get_list_of_changed_files()), end="")
    128    else:
    129        print("No valid option provided.")