Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  nss-release-helper.py

  Sprache: Python
 

#!/usr/bin/env python3
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import os
import sys
import shutil
import re
import tempfile
from optparse import OptionParser
from subprocess import check_call
from subprocess import check_output

nssutil_h = "lib/util/nssutil.h"
softkver_h = "lib/softoken/softkver.h"
nss_h = "lib/nss/nss.h"
nssckbi_h = "lib/ckfw/builtins/nssckbi.h"
abi_base_version_file = "automation/abi-check/previous-nss-release"

abi_report_files = [
    "automation/abi-check/expected-report-libfreebl3.so.txt",
    "automation/abi-check/expected-report-libfreeblpriv3.so.txt",
    "automation/abi-check/expected-report-libnspr4.so.txt",
    "automation/abi-check/expected-report-libnss3.so.txt",
    "automation/abi-check/expected-report-libnssckbi.so.txt",
    "automation/abi-check/expected-report-libnssdbm3.so.txt",
    "automation/abi-check/expected-report-libnsssysinit.so.txt",
    "automation/abi-check/expected-report-libnssutil3.so.txt",
    "automation/abi-check/expected-report-libplc4.so.txt",
    "automation/abi-check/expected-report-libplds4.so.txt",
    "automation/abi-check/expected-report-libsmime3.so.txt",
    "automation/abi-check/expected-report-libsoftokn3.so.txt",
    "automation/abi-check/expected-report-libssl3.so.txt",
]


def check_call_noisy(cmd, *args, **kwargs):
    print("Executing command: {}".format(cmd))
    check_call(cmd, *args, **kwargs)


def print_separator():
    print("=" * 70)


def exit_with_failure(what):
    print("failure: {}".format(what))
    sys.exit(2)


def check_files_exist():
    if (
        not os.path.exists(nssutil_h)
        or not os.path.exists(softkver_h)
        or not os.path.exists(nss_h)
        or not os.path.exists(nssckbi_h)
    ):
        exit_with_failure(
            "cannot find expected header files, must run from inside NSS hg directory"
        )


class Replacement:
    def __init__(self, regex="", repl=""):
        self.regex = regex
        self.repl = repl
        self.matcher = re.compile(self.regex)

    def replace(self, line):
        return self.matcher.sub(self.repl, line)


def inplace_replace(replacements=[], filename=""):
    for r in replacements:
        if not isinstance(r, Replacement):
            raise TypeError("Expecting a list of Replacement objects")

    with tempfile.NamedTemporaryFile(mode="w", delete=Falseas tmp_file:
        with open(filename) as in_file:
            for line in in_file:
                for r in replacements:
                    line = r.replace(line)
                tmp_file.write(line)
        tmp_file.flush()

        shutil.copystat(filename, tmp_file.name)
        shutil.move(tmp_file.name, filename)
        os.utime(filename, None)


def toggle_beta_status(is_beta):
    check_files_exist()
    if is_beta:
        print("adding Beta status to version numbers")
        inplace_replace(
            filename=nssutil_h,
            replacements=[
                Replacement(
                    regex=r"^(#define *NSSUTIL_VERSION *\"[0-9.]+)\" *$",
                    repl=r'\g<1> Beta"',
                ),
                Replacement(
                    regex=r"^(#define *NSSUTIL_BETA *)PR_FALSE *$", repl=r"\g<1>PR_TRUE"
                ),
            ],
        )
        inplace_replace(
            filename=softkver_h,
            replacements=[
                Replacement(
                    regex=r"^(#define *SOFTOKEN_VERSION *\"[0-9.]+\" *SOFTOKEN_ECC_STRING) *$",
                    repl=r'\g<1> " Beta"',
                ),
                Replacement(
                    regex=r"^(#define *SOFTOKEN_BETA *)PR_FALSE *$",
                    repl=r"\g<1>PR_TRUE",
                ),
            ],
        )
        inplace_replace(
            filename=nss_h,
            replacements=[
                Replacement(
                    regex=r"^(#define *NSS_VERSION *\"[0-9.]+\" *_NSS_CUSTOMIZED) *$",
                    repl=r'\g<1> " Beta"',
                ),
                Replacement(
                    regex=r"^(#define *NSS_BETA *)PR_FALSE *$", repl=r"\g<1>PR_TRUE"
                ),
            ],
        )
    else:
        print("removing Beta status from version numbers")
        inplace_replace(
            filename=nssutil_h,
            replacements=[
                Replacement(
                    regex=r"^(#define *NSSUTIL_VERSION *\"[0-9.]+) *Beta\" *$",
                    repl=r'\g<1>"',
                ),
                Replacement(
                    regex=r"^(#define *NSSUTIL_BETA *)PR_TRUE *$", repl=r"\g<1>PR_FALSE"
                ),
            ],
        )
        inplace_replace(
            filename=softkver_h,
            replacements=[
                Replacement(
                    regex=r"^(#define *SOFTOKEN_VERSION *\"[0-9.]+\" *SOFTOKEN_ECC_STRING) *\" *Beta\" *$",
                    repl=r"\g<1>",
                ),
                Replacement(
                    regex=r"^(#define *SOFTOKEN_BETA *)PR_TRUE *$",
                    repl=r"\g<1>PR_FALSE",
                ),
            ],
        )
        inplace_replace(
            filename=nss_h,
            replacements=[
                Replacement(
                    regex=r"^(#define *NSS_VERSION *\"[0-9.]+\" *_NSS_CUSTOMIZED) *\" *Beta\" *$",
                    repl=r"\g<1>",
                ),
                Replacement(
                    regex=r"^(#define *NSS_BETA *)PR_TRUE *$", repl=r"\g<1>PR_FALSE"
                ),
            ],
        )

    print(
        "please run 'hg stat' and 'hg diff' to verify the files have been verified correctly"
    )


def print_beta_versions():
    check_call_noisy(
        ["egrep""#define *NSSUTIL_VERSION|#define *NSSUTIL_BETA", nssutil_h]
    )
    check_call_noisy(
        ["egrep""#define *SOFTOKEN_VERSION|#define *SOFTOKEN_BETA", softkver_h]
    )
    check_call_noisy(["egrep""#define *NSS_VERSION|#define *NSS_BETA", nss_h])


def remove_beta_status():
    print("--- removing beta flags. Existing versions were:")
    print_beta_versions()
    toggle_beta_status(False)
    print("=" * 70)
    print("--- finished modifications, new versions are:")
    print("=" * 70)
    print_beta_versions()


def set_beta_status():
    print("--- adding beta flags. Existing versions were:")
    print_beta_versions()
    toggle_beta_status(True)
    print("--- finished modifications, new versions are:")
    print_beta_versions()


def print_library_versions():
    check_files_exist()
    check_call_noisy(
        [
            "egrep",
            "#define *NSSUTIL_VERSION|#define NSSUTIL_VMAJOR|#define *NSSUTIL_VMINOR|#define *NSSUTIL_VPATCH|#define *NSSUTIL_VBUILD|#define *NSSUTIL_BETA",
            nssutil_h,
        ]
    )
    check_call_noisy(
        [
            "egrep",
            "#define *SOFTOKEN_VERSION|#define SOFTOKEN_VMAJOR|#define *SOFTOKEN_VMINOR|#define *SOFTOKEN_VPATCH|#define *SOFTOKEN_VBUILD|#define *SOFTOKEN_BETA",
            softkver_h,
        ]
    )
    check_call_noisy(
        [
            "egrep",
            "#define *NSS_VERSION|#define NSS_VMAJOR|#define *NSS_VMINOR|#define *NSS_VPATCH|#define *NSS_VBUILD|#define *NSS_BETA",
            nss_h,
        ]
    )


def print_root_ca_version():
    check_files_exist()
    check_call_noisy(["grep""define *NSS_BUILTINS_LIBRARY_VERSION", nssckbi_h])


def ensure_arguments_count(args, how_many, usage):
    if len(args) != how_many:
        exit_with_failure(
            "incorrect number of arguments, expected parameters are:\n" + usage
        )


def set_major_versions(major):
    for name, file in [
        ["NSSUTIL_VMAJOR", nssutil_h],
        ["SOFTOKEN_VMAJOR", softkver_h],
        ["NSS_VMAJOR", nss_h],
    ]:
        inplace_replace(
            filename=file,
            replacements=[
                Replacement(
                    regex=r"^(#define *{} ?).*$".format(name),
                    repl=r"\g<1>{}".format(major),
                )
            ],
        )


def set_minor_versions(minor):
    for name, file in [
        ["NSSUTIL_VMINOR", nssutil_h],
        ["SOFTOKEN_VMINOR", softkver_h],
        ["NSS_VMINOR", nss_h],
    ]:
        inplace_replace(
            filename=file,
            replacements=[
                Replacement(
                    regex=r"^(#define *{} ?).*$".format(name),
                    repl=r"\g<1>{}".format(minor),
                )
            ],
        )


def set_patch_versions(patch):
    for name, file in [
        ["NSSUTIL_VPATCH", nssutil_h],
        ["SOFTOKEN_VPATCH", softkver_h],
        ["NSS_VPATCH", nss_h],
    ]:
        inplace_replace(
            filename=file,
            replacements=[
                Replacement(
                    regex=r"^(#define *{} ?).*$".format(name),
                    repl=r"\g<1>{}".format(patch),
                )
            ],
        )


def set_build_versions(build):
    for name, file in [
        ["NSSUTIL_VBUILD", nssutil_h],
        ["SOFTOKEN_VBUILD", softkver_h],
        ["NSS_VBUILD", nss_h],
    ]:
        inplace_replace(
            filename=file,
            replacements=[
                Replacement(
                    regex=r"^(#define *{} ?).*$".format(name),
                    repl=r"\g<1>{}".format(build),
                )
            ],
        )


def set_full_lib_versions(version):
    for name, file in [
        ["NSSUTIL_VERSION", nssutil_h],
        ["SOFTOKEN_VERSION", softkver_h],
        ["NSS_VERSION", nss_h],
    ]:
        inplace_replace(
            filename=file,
            replacements=[
                Replacement(
                    regex=r"^(#define *{} *\")([0-9.]+)(.*)$".format(name),
                    repl=r"\g<1>{}\g<3>".format(version),
                )
            ],
        )


def set_root_ca_version(args):
    ensure_arguments_count(args, 2"major_version  minor_version")
    major = args[0].strip()
    minor = args[1].strip()
    version = major + "." + minor

    inplace_replace(
        filename=nssckbi_h,
        replacements=[
            Replacement(
                regex=r"^(#define *NSS_BUILTINS_LIBRARY_VERSION *\").*$",
                repl=r'\g<1>{}"'.format(version),
            ),
            Replacement(
                regex=r"^(#define *NSS_BUILTINS_LIBRARY_VERSION_MAJOR ?).*$",
                repl=r"\g<1>{}".format(major),
            ),
            Replacement(
                regex=r"^(#define *NSS_BUILTINS_LIBRARY_VERSION_MINOR ?).*$",
                repl=r"\g<1>{}".format(minor),
            ),
        ],
    )


def set_all_lib_versions(version, major, minor, patch, build):
    grep_major = check_output(["grep""define.*NSS_VMAJOR", nss_h])
    grep_minor = check_output(["grep""define.*NSS_VMINOR", nss_h])

    old_major = int(grep_major.split()[2])
    old_minor = int(grep_minor.split()[2])

    new_major = int(major)
    new_minor = int(minor)

    if old_major < new_major or (old_major == new_major and old_minor < new_minor):
        print("You're increasing the minor (or major) version:")
        print("- erasing ABI comparison expectations")
        new_branch = "NSS_" + str(old_major) + "_" + str(old_minor) + "_BRANCH"
        print(
            "- setting reference branch to the branch of the previous version: "
            + new_branch
        )
        with open(abi_base_version_file, "w"as abi_base:
            abi_base.write("%s\n" % new_branch)
        for report_file in abi_report_files:
            with open(report_file, "w"as report_file_handle:
                report_file_handle.truncate()

    set_full_lib_versions(version)
    set_major_versions(major)
    set_minor_versions(minor)
    set_patch_versions(patch)
    set_build_versions(build)


def set_version_to_minor_release(args):
    ensure_arguments_count(args, 2"major_version  minor_version")
    major = args[0].strip()
    minor = args[1].strip()
    version = major + "." + minor
    patch = "0"
    build = "0"
    set_all_lib_versions(version, major, minor, patch, build)


def set_version_to_patch_release(args):
    ensure_arguments_count(args, 3"major_version  minor_version  patch_release")
    major = args[0].strip()
    minor = args[1].strip()
    patch = args[2].strip()
    version = major + "." + minor + "." + patch
    build = "0"
    set_all_lib_versions(version, major, minor, patch, build)


def set_release_candidate_number(args):
    ensure_arguments_count(args, 1"release_candidate_number")
    build = args[0].strip()
    set_build_versions(build)


def set_4_digit_release_number(args):
    ensure_arguments_count(
        args, 4"major_version  minor_version  patch_release  4th_digit_release_number"
    )
    major = args[0].strip()
    minor = args[1].strip()
    patch = args[2].strip()
    build = args[3].strip()
    version = major + "." + minor + "." + patch + "." + build
    set_all_lib_versions(version, major, minor, patch, build)


def make_release_branch(args):
    ensure_arguments_count(args, 2"version_string remote")
    version_string = args[0].strip()
    remote = args[1].strip()

    major, minor, patch = parse_version_string(version_string)
    if patch is not None:
        exit_with_failure(
            "make_release_branch expects a minor version (e.g., '3.117'), not a patch version."
        )

    version = f"{major}.{minor}"
    branch_name = f"NSS_{major}_{minor}_BRANCH"
    tag_name = f"NSS_{major}_{minor}_BETA1"

    print_separator()
    print("MAKE RELEASE BRANCH")
    print_separator()
    print(f"Version: {version}")
    print(f"Remote: {remote}")
    print_separator()

    response = input("Are these parameters correct? [yN]: ")
    if "y" not in response.lower():
        print("Aborted.")
        sys.exit(0)
    print_separator()

    # Step 1: Update local repo
    print("Step 1: Updating local repository...")
    check_call_noisy(["hg""pull"])
    check_call_noisy(["hg""checkout""default"])
    print_separator()

    print("Step 2: Checking working directory is clean")
    hg_status = check_output(["hg""status"]).decode("utf-8").strip()
    if hg_status:
        print()
        print("ERROR: Working directory is not clean")
        print(hg_status)
        print()
        exit_with_failure(
            "Please commit or revert changes then run this command again. You can reset your working directory with 'hg update -C' and 'hg purge if you want to discard all local changes."
        )

    branches = check_output(["hg""branches"]).decode("utf-8").strip()
    if branch_name in branches:
        exit_with_failure(f"Branch {branch_name} already exists.")
    print_separator()

    # Step 2: Verify version numbers are correct
    print("Step 2: Verifying version numbers are correct...")
    set_version_to_minor_release([major, minor])
    print("=" * 70)
    set_beta_status()
    print("=" * 70)
    # Check if there are any uncommitted changes
    hg_status = check_output(["hg""status"]).decode("utf-8").strip()
    if hg_status:
        print()
        print("ERROR: Version numbers are not correctly set")
        print()
        print()
        exit_with_failure(
            "Please check the correct version to freeze, or update the version numbers then run this command again."
        )

    print("Version numbers verified - no changes needed.")
    print_separator()

    # Step 3: Create branch
    print(f"Step 3: Creating branch {branch_name}...")
    check_call_noisy(["hg""branch", branch_name])
    print_separator()

    # Step 4: Create tag
    print(f"Step 4: Creating tag {tag_name}...")
    check_call_noisy(["hg""tag", tag_name])
    print_separator()

    # Step 5: Show outgoing changes
    response = input("Display outgoing changes? [yN]: ")
    if "y" in response.lower():
        print()
        check_call_noisy(["hg""outgoing""-p", remote])
    print_separator()

    # Step 6: Prompt user and push if confirmed
    response = input("Push this branch and tag to the NSS repository? [yN]: ")
    if "y" in response.lower():
        print("Pushing branch and tag...")
        check_call_noisy(["hg""push""--new-branch", remote])
        print_separator()
        print("SUCCESS: Branch and tag have been pushed!")
        print_separator()
        print()
        print("NEXT STEPS:")
        print(
            f"1. Wait for the changes to sync to Github: https://github.com/mozilla/nss/tree/{branch_name}"
        )
        print("2. In your mozilla-unified repository, run:")
        print(f"   ./mach nss-uplift {tag_name}")
        print()
    else:
        print("Branch and tag have NOT been pushed to the repository.")
        print("The local branch and tag remain in your working directory.")
        print_separator()


def parse_version_string(version_string):
    """Parse a version string like '3.117' or '3.117.1' and return (major, minor, patch)

    For versions like '3.117', patch will be None.
    Returns: tuple of (major, minor, patch) where patch can be None
    """
    parts = version_string.split(".")
    if len(parts) < 2:
        exit_with_failure(
            f"Invalid version string '{version_string}'. Expected format: 'major.minor' or 'major.minor.patch'"
        )

    major = parts[0].strip()
    minor = parts[1].strip()
    patch = parts[2].strip() if len(parts) >= 3 else None

    # Validate that they're numbers
    try:
        int(major)
        int(minor)
        if patch is not None:
            int(patch)
    except ValueError:
        exit_with_failure(
            f"Invalid version string '{version_string}'. Version components must be numbers."
        )

    return major, minor, patch


def version_string_to_RTM_tag(version_string):
    parts = version_string.split(".")
    return "NSS_" + "_".join(parts) + "_RTM"


def version_string_to_underscore(version_string):
    return version_string.replace(".""_")


def generate_release_note(args):
    ensure_arguments_count(
        args,
        3,
        "this_release_version_string revision_or_tag previous_release_version_string ",
    )

    version = args[0].strip()
    this_tag = args[1].strip()  # Typically going to be .
    version_underscore = version_string_to_underscore(version)
    prev_tag = version_string_to_RTM_tag(args[2].strip())

    # Get the NSPR version
    nspr_version = (
        check_output(
            ["hg""cat""-r", this_tag, "automation/release/nspr-version.txt"]
        )
        .decode("utf-8")
        .split("\n")[0]
        .strip()
    )

    # Get the current date
    from datetime import datetime

    current_date = datetime.now().strftime("%-d %B %Y")

    # Get the list of bugs from hg log
    # Get log entries between previous tag and current HEAD
    command = [
        "hg",
        "log",
        "-r",
        f"{prev_tag}:{this_tag}",
        "--template",
        "{desc|firstline}\\n",
    ]
    log_output = check_output(command).decode("utf-8")

    # Extract bug numbers and descriptions
    bug_lines = []
    for line in reversed(log_output.split("\n")):
        if "Bug" in line or "bug" in line:
            line = line.strip()
            line = line.split("r=")[0].strip()

            # Match patterns like "Bug 1234567 Something" and convert to "Bug 1234567 - Something"
            line = re.sub(
                r"(Bug\s+\d+)\s+([^-])", r"\1 - \2", line, flags=re.IGNORECASE
            )

            # Add a full stop at the end if there isn't one
            if line:
                line = line.rstrip(",")

            if line and not line.endswith("."):
                line = line + "."

            if line and line not in bug_lines:
                bug_lines.append(line)

    changes_text = "\n".join([f"   - {line}" for line in bug_lines])

    # Create the release notes content
    rst_content = f""".. _mozilla_projects_nss_nss_{version_underscore}_release_notes:

NSS {version} release notes
===============================

`Introduction <#introduction>`__
--------------------------------

.. container::

   Network Security Services (NSS) {version} was released on *{current_date}**.

`Distribution Information <#distribution_information>`__
--------------------------------------------------------

.. container::

   The HG tag is NSS_{version_underscore}_RTM. NSS {version} requires NSPR {nspr_version} or newer.

   NSS {version} source distributions are available on ftp.mozilla.org for secure HTTPS download:

   -  Source tarballs:
      https://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/NSS_{version_underscore}_RTM/src/

   Other releases are available :ref:`mozilla_projects_nss_releases`.

.. _changes_in_nss_{version}:

`Changes in NSS {version} <#changes_in_nss_{version}>`__
------------------------------------------------------------------

.. container::

{changes_text}

"""
    return rst_content


def generate_release_notes_index(args):
    ensure_arguments_count(args, 2"latest_release_version  latest_esr_version")
    latest_version = args[0].strip()  # e.g. 3.116
    esr_version = args[1].strip()  # e.g. 3.112.1

    latest_underscore = version_string_to_underscore(latest_version)
    esr_underscore = version_string_to_underscore(esr_version)

    # Read all release note files from doc/rst/releases/
    release_dir = "doc/rst/releases"
    if not os.path.exists(release_dir):
        exit_with_failure(f"Release notes directory not found: {release_dir}")

    # Get all nss_*.rst files (excluding index.rst)
    release_files = []
    for filename in os.listdir(release_dir):
        if (
            filename.startswith("nss_")
            and filename.endswith(".rst")
            and filename != "index.rst"
        ):
            release_files.append(filename)

    # Sort release files in reverse order (newest first)
    # Extract version numbers for proper sorting
    def version_key(filename):
        # Extract version parts from filename like nss_3_116.rst
        parts = filename.replace("nss_""").replace(".rst""").split("_")
        # Convert to integers for proper numerical sorting
        return [int(p) for p in parts]

    release_files.sort(key=version_key, reverse=True)

    # Build the toctree content
    toctree_lines = "\n".join([f"   {f}" for f in release_files])

    # Create the index.rst content
    index_content = f""".. _mozilla_projects_nss_releases:

Release Notes
=============

.. toctree::
   :maxdepth: 0
   :glob:
   :hidden:

{toctree_lines}

.. note::

   **NSS {latest_version}** is the latest version of NSS.
   Complete release notes are available here: :ref:`mozilla_projects_nss_nss_{latest_underscore}_release_notes`

   **NSS {esr_version} (ESR)** is the latest ESR version of NSS.
   Complete release notes are available here: :ref:`mozilla_projects_nss_nss_{esr_underscore}_release_notes`

"""

    index_file = os.path.join(release_dir, "index.rst")
    with open(index_file, "w"as f:
        f.write(index_content)

    print(f"Generated {index_file}")
    print()
    print("=" * 70)
    print("Content:")
    print("=" * 70)
    print(index_content)


def release_nss(args):
    ensure_arguments_count(args, 3"version_string  esr_version  remote")
    version_string = args[0].strip()
    esr_version = args[1].strip()
    remote = args[2].strip()

    major, minor, patch = parse_version_string(version_string)

    # Build version string and related names
    version = version_string
    version_underscore = version_string_to_underscore(version_string)
    branch_name = f"NSS_{major}_{minor}_BRANCH"
    rtm_tag = f"NSS_{version_underscore}_RTM"
    release_note_file = f"doc/rst/releases/nss_{version_underscore}.rst"

    print_separator()
    print("RELEASE NSS")
    print_separator()
    print(f"Release version: {version}")
    print(f"ESR version: {esr_version}")
    print(f"Remote: {remote}")
    print_separator()

    response = input("Are these parameters correct? [yN]: ")
    if "y" not in response.lower():
        print("Aborted.")
        sys.exit(0)
    print_separator()

    print("=" * 70)
    print(f"Starting NSS {version} release process")
    print("=" * 70)
    print()

    # Step 1: Update local repo
    print("Step 1: Updating local repository...")
    check_call_noisy(["hg""pull"])
    print_separator()

    # Step 2: Checking working directory is clean
    print("Step 2: Checking working directory is clean...")
    hg_status = check_output(["hg""status"]).decode("utf-8").strip()
    if hg_status:
        print()
        print("ERROR: Working directory is not clean")
        print(hg_status)
        print()
        exit_with_failure(
            "Please commit or revert changes then run this command again. You can reset your working directory with 'hg update -C' and 'hg purge if you want to discard all local changes."
        )
    print_separator()

    # Step 3: Make sure we're on the appropriate branch
    print(f"Step 3: Checking out branch {branch_name}...")
    try:
        check_call_noisy(["hg""checkout", branch_name])
    except Exception as e:
        exit_with_failure(f"Failed to checkout branch {branch_name}. Does it exist?")
    print_separator()

    # Step 4: Check for any existing commits or tags
    print("Step 4: Checking for existing release commits or tags...")

    # Check if RTM tag already exists
    tags_output = check_output(["hg""tags"]).decode("utf-8")
    if rtm_tag in tags_output:
        exit_with_failure(
            f"Tag {rtm_tag} already exists. Has this release already been made?"
        )

    # Check for recent commits with the same commit messages we're about to make
    version_commit_message = f"Set version numbers to {version} final"
    release_notes_commit_message = f"Release notes for NSS {version}"

    recent_log = check_output(
        ["hg""log""-l""5""--template""{desc|firstline}\\n"]
    ).decode("utf-8")

    if version_commit_message in recent_log:
        exit_with_failure(
            f"Found recent commit with message '{version_commit_message}'. Has this release already been started?"
        )

    if release_notes_commit_message in recent_log:
        exit_with_failure(
            f"Found recent commit with message '{release_notes_commit_message}'. Has this release already been started?"
        )

    print("No existing release commits or tags found.")
    print_separator()

    # Step 5: Update the NSS version numbers (remove beta)
    print("Step 5: Removing beta status from version numbers...")
    if patch:
        set_version_to_patch_release([major, minor, patch])
    else:
        set_version_to_minor_release([major, minor])
    remove_beta_status()

    print_separator()

    # Step 6: Commit the change
    print("Step 6: Committing version number changes...")
    check_call_noisy(["hg""commit""-m", version_commit_message])
    print_separator()

    # Step 7: Generate release note
    print("Step 7: Generating release notes...")
    generate_doc_script = os.path.join(
        os.path.dirname(__file__), "generate_release_doc.py"
    )
    check_call_noisy([sys.executable, generate_doc_script, version])
    print_separator()

    # Step 8: Generate new release note index
    print("Step 8: Generating release notes index...")
    generate_release_notes_index([version, esr_version])
    print_separator()

    input(
        "Are you making an ESR release? If so, please manually edit doc/rst/releases/index.rst to adjust the ESR / main version note. Press enter when done."
    )

    # Step 9: Commit the release notes
    print("Step 9: Committing release notes...")
    check_call_noisy(["hg""add", release_note_file])
    check_call_noisy(["hg""commit""-m", release_notes_commit_message])

    # Get the commit hash
    docs_commit = (
        check_output(["hg""log""-r"".""--template""{node|short}"])
        .decode("utf-8")
        .strip()
    )
    print(f"Release notes committed. Commit hash: {docs_commit}")
    print_separator()

    # Step 10: Tag the release version
    print(f"Step 10: Tagging release version {rtm_tag}...")
    check_call_noisy(["hg""tag", rtm_tag])
    print_separator()

    # Step 11: Switch to default branch and graft the release notes
    print("Step 11: Switching to default branch and grafting release notes...")
    check_call_noisy(["hg""checkout""default"])
    check_call_noisy(["hg""graft""-r", docs_commit])
    print_separator()

    response = input("Display the outgoing changes? [yN]: ")
    if "y" in response.lower():
        check_call_noisy(
            ["hg""outgoing""--graph""-b""default""-b", branch_name, remote]
        )
    print_separator()

    # Step 12: Check cf_status_nss on Bugzilla
    print("Step 12: Checking cf_status_nss on Bugzilla...")
    cf_status_script = os.path.join(
        os.path.dirname(__file__), "bugzilla_cf_status_nss.py"
    )
    check_call_noisy([sys.executable, cf_status_script, version])
    input("Review the cf_status_nss report above. Press Enter to continue.")
    print_separator()

    # Step 13: Push changes
    response = input("Push these changes to the NSS repository? [yN]: ")
    if "y" in response.lower():
        print("Pushing changes to default branch...")
        check_call_noisy(["hg""push""-b""default", remote])
        print(f"Pushing changes to {branch_name} branch...")
        check_call_noisy(["hg""push""-b", branch_name, remote])
        print_separator()
        print("SUCCESS: NSS release process completed!")
        print_separator()
        print()
        print("NEXT STEPS:")
        print(f"1. Wait for the changes to sync to Github")
        print("2. In your mozilla-unified repository, run:")
        print(f"   ./mach nss-uplift {rtm_tag}")
        print()
    else:
        print("Changes have NOT been pushed to the repository.")
        print("The local commits remain in your working directory.")
        print_separator()


def create_nss_release_archive(args):
    ensure_arguments_count(args, 2"nss_release_version  path_to_stage_directory")
    nssrel = args[0].strip()  # e.g. 3.19.3
    stagedir = args[1].strip()  # e.g. ../stage

    # Determine which tar command to use (prefer gtar if available)
    tar_cmd = "gtar"
    try:
        check_call(
            ["which""gtar"],
            stdout=open(os.devnull, "w"),
            stderr=open(os.devnull, "w"),
        )
    except:
        tar_cmd = "tar"

    # Generate the release tag from the version
    nssreltag = version_string_to_RTM_tag(nssrel)

    print_separator()
    print("CREATE NSS RELEASE ARCHIVE")
    print_separator()
    print(f"NSS release version: {nssrel}")
    print(f"Stage directory: {stagedir}")
    print_separator()

    response = input("Are these parameters correct? [yN]: ")
    if "y" not in response.lower():
        print("Aborted.")
        sys.exit(0)
    print_separator()

    with open("automation/release/nspr-version.txt"as nspr_version_file:
        nsprrel = next(nspr_version_file).strip()

    nspr_tar = "nspr-" + nsprrel + ".tar.gz"
    nspr_dir = stagedir + "/v" + nsprrel + "/src/"
    nsprtar_with_path = nspr_dir + nspr_tar

    nspr_releases_url = "https://ftp.mozilla.org/pub/nspr/releases"
    if not os.path.exists(nsprtar_with_path):
        os.makedirs(nspr_dir, exist_ok=True)
        check_call_noisy(
            [
                "wget",
                f"{nspr_releases_url}/v{nsprrel}/src/nspr-{nsprrel}.tar.gz",
                f"--output-document={nsprtar_with_path}",
            ]
        )

    if not os.path.exists(nsprtar_with_path):
        exit_with_failure(
            "cannot find nspr archive at expected location " + nsprtar_with_path
        )

    nss_stagedir = stagedir + "/" + nssreltag + "/src"
    if os.path.exists(nss_stagedir):
        exit_with_failure("nss stage directory already exists: " + nss_stagedir)

    nss_tar = "nss-" + nssrel + ".tar.gz"

    check_call_noisy(["mkdir""-p", nss_stagedir])
    check_call_noisy(
        [
            "hg",
            "archive",
            "-r",
            nssreltag,
            "--prefix=nss-" + nssrel + "/nss",
            stagedir + "/" + nssreltag + "/src/" + nss_tar,
            "-X",
            ".hgtags",
        ]
    )
    check_call_noisy([tar_cmd, "-xz""-C", nss_stagedir, "-f", nsprtar_with_path])
    print("changing to directory " + nss_stagedir)
    os.chdir(nss_stagedir)
    check_call_noisy([tar_cmd, "-xz""-f", nss_tar])
    check_call_noisy(["mv""-i""nspr-" + nsprrel + "/nspr""nss-" + nssrel + "/"])
    check_call_noisy(["rmdir""nspr-" + nsprrel])

    nss_nspr_tar = "nss-" + nssrel + "-with-nspr-" + nsprrel + ".tar.gz"

    check_call_noisy([tar_cmd, "-cz""-f", nss_nspr_tar, "nss-" + nssrel])
    check_call_noisy(["rm""-rf""nss-" + nssrel])
    check_call("sha1sum " + nss_tar + " " + nss_nspr_tar + " > SHA1SUMS", shell=True)
    check_call(
        "sha256sum " + nss_tar + " " + nss_nspr_tar + " > SHA256SUMS", shell=True
    )
    print("created directory " + nss_stagedir + " with files:")
    check_call_noisy(["ls""-l"])

    if "y" not in input("Upload release tarball?[yN]"):
        print("Release tarballs have NOT been uploaded")
        exit(0)
    os.chdir("../..")
    gcp_proj = "moz-fx-productdelivery-pr-38b5"
    check_call_noisy(["gcloud""auth""login"])
    check_call_noisy(
        [
            "gcloud",
            "--project",
            gcp_proj,
            f"--impersonate-service-account=nss-team-prod@{gcp_proj}.iam.gserviceaccount.com",
            "storage",
            "cp",
            "--recursive",
            "--no-clobber",
            nssreltag,
            f"gs://{gcp_proj}-productdelivery/pub/security/nss/releases/",
        ]
    )
    print_separator()
    print(
        f"Release tarballs have been uploaded to Google Cloud Storage. You can find them at https://ftp.mozilla.org/pub/security/nss/releases/{nssreltag}/"
    )
    print_separator()


o = OptionParser(
    usage="client.py [options] "
    + " | ".join(
        [
            "remove_beta",
            "set_beta",
            "print_library_versions",
            "print_root_ca_version",
            "set_root_ca_version",
            "set_version_to_minor_release",
            "set_version_to_patch_release",
            "set_release_candidate_number",
            "set_4_digit_release_number",
            "make_release_branch",
            "create_nss_release_archive",
            "generate_release_note",
            "generate_release_notes_index",
        ]
    )
)

try:
    options, args = o.parse_args()
    action = args[0]
    action_args = args[1:]  # Get all arguments after the action
except IndexError:
    o.print_help()
    sys.exit(2)

if action in ("remove_beta"):
    remove_beta_status()

elif action in ("set_beta"):
    set_beta_status()

elif action in ("print_library_versions"):
    print_library_versions()

elif action in ("print_root_ca_version"):
    print_root_ca_version()

elif action in ("set_root_ca_version"):
    set_root_ca_version(action_args)

# x.y version number - 2 parameters
elif action in ("set_version_to_minor_release"):
    set_version_to_minor_release(action_args)

# x.y.z version number - 3 parameters
elif action in ("set_version_to_patch_release"):
    set_version_to_patch_release(action_args)

# change the release candidate number, usually increased by one,
# usually if previous release candiate had a bug
# 1 parameter
elif action in ("set_release_candidate_number"):
    set_release_candidate_number(action_args)

# use the build/release candiate number in the identifying version number
# 4 parameters
elif action in ("set_4_digit_release_number"):
    set_4_digit_release_number(action_args)

# create a freeze branch and beta tag for a new release
# 2 parameters
elif action in ("make_release_branch"):
    make_release_branch(action_args)

elif action in ("create_nss_release_archive"):
    create_nss_release_archive(action_args)

elif action in ("generate_release_note"):
    print(generate_release_note(action_args))

elif action in ("generate_release_notes_index"):
    generate_release_notes_index(action_args)


elif action in ("release_nss"):
    release_nss(action_args)

else:
    o.print_help()
    sys.exit(2)

sys.exit(0)

Messung V0.5 in Prozent
C=94 H=92 G=92

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002