Example #1
0
def is_rc(release):
    if not is_beta(release['version']) and not is_esr(release['version']):
        if isFinalRelease(release["version"]):
            return True
        # RC release types will enable beta-channel testing &
        # shipping. We need this for all "final" releases
        # and also any releases that include a beta as a partial.
        # The assumption that "shipping to beta channel" always
        # implies other RC behaviour is bound to break at some
        # point, but this works for now.
        for version in release["partial_updates"]:
            if is_beta(version):
                return True
    return False
Example #2
0
def is_rc(release):
    if not is_beta(release['version']) and not is_esr(release['version']):
        if isFinalRelease(release["version"]):
            return True
        # RC release types will enable beta-channel testing &
        # shipping. We need this for all "final" releases
        # and also any releases that include a beta as a partial.
        # The assumption that "shipping to beta channel" always
        # implies other RC behaviour is bound to break at some
        # point, but this works for now.
        for version in release["partial_updates"]:
            if is_beta(version):
                return True
    return False
Example #3
0
def getPossibleNextVersions(version):
    """Return possibly next versions for a given version.
       There's a few distinct cases here:
       * ESRs:  The only possible next version is the next minor version.
                Eg: 17.0.3esr -> 17.0.4esr
       * Betas: The next beta with the same major version and also the next
                major version's beta 1. Eg: 18.0b4 -> 18.0b5, 19.0b1
       * Other: The next major version's .0 release and the next minor version.
                Eg: 15.0 -> 15.0.1, 16.0; 17.0.2 -> 17.0.3, 18.0

       Versions with 'pre' are deprecated, and explicitly not supported.
    """
    ret = set()
    # Get the parts we care about from the version. The last group is the 'pre'
    # tag, which doesn't affect our work.
    m = re.match(ANY_VERSION_REGEX, version)
    if not m:
        return ret
    base, beta, _, esr = m.groups()[:4]
    # The next major version is used in a couple of places, so we figure it out
    # ahead of time. Eg: 17.0 -> 18.0 or 15.0.3 -> 16.0
    nextMajorVersion = increment(base.split('.')[0]) + '.0'
    # Modern ESRs have two possibilities:
    # 1) Bump the second digit for a planned release and reset the third digit
    #    to 0.
    # 2) Bump the last digit for an unexpected release
    #
    # Prior to ESR 24 we did #2 for all types of releases.
    if esr:
        # if version is like N.0esr, add an extra 0 to make it bump properly
        if version.count('.') < 2:
            version = version.replace('esr', '.0esr')
        first, second, _ = version.split('.', 2)
        if int(first) >= 24:
            ret.add('%s.%s.0esr' % (first, increment(second)))
        ret.add(increment(version))
    # Betas are similar, except we need the next major version's beta 1, too.
    elif beta:
        ret.add(increment(version))
        ret.add('%sb1' % nextMajorVersion)
    # Other releases are a bit more complicated, because we need to handle
    # going from a x.y -> x.y.z version number.
    else:
        ret.add(nextMajorVersion)
        if isFinalRelease(version):
            ret.add('%s.1' % version)
        else:
            ret.add(increment(version))
    return ret
Example #4
0
def getPossibleNextVersions(version):
    """Return possibly next versions for a given version.
       There's a few distinct cases here:
       * ESRs:  The only possible next version is the next minor version.
                Eg: 17.0.3esr -> 17.0.4esr
       * Betas: The next beta with the same major version and also the next
                major version's beta 1. Eg: 18.0b4 -> 18.0b5, 19.0b1
       * Other: The next major version's .0 release and the next minor version.
                Eg: 15.0 -> 15.0.1, 16.0; 17.0.2 -> 17.0.3, 18.0

       Versions with 'pre' are deprecated, and explicitly not supported.
    """
    ret = set()
    # Get the parts we care about from the version. The last group is the 'pre'
    # tag, which doesn't affect our work.
    m = re.match(ANY_VERSION_REGEX, version)
    if not m:
        return ret
    base, beta, _, esr = m.groups()[:4]
    # The next major version is used in a couple of places, so we figure it out
    # ahead of time. Eg: 17.0 -> 18.0 or 15.0.3 -> 16.0
    nextMajorVersion = increment(base.split('.')[0]) + '.0'
    # Modern ESRs have two possibilities:
    # 1) Bump the second digit for a planned release and reset the third digit
    #    to 0.
    # 2) Bump the last digit for an unexpected release
    #
    # Prior to ESR 24 we did #2 for all types of releases.
    if esr:
        # if version is like N.0esr, add an extra 0 to make it bump properly
        if version.count('.') < 2:
            version = version.replace('esr', '.0esr')
        first, second, _ = version.split('.', 2)
        if int(first) >= 24:
            ret.add('%s.%s.0esr' % (first, increment(second)))
        ret.add(increment(version))
    # Betas are similar, except we need the next major version's beta 1, too.
    elif beta:
        ret.add(increment(version))
        ret.add('%sb1' % nextMajorVersion)
    # Other releases are a bit more complicated, because we need to handle
    # going from a x.y -> x.y.z version number.
    else:
        ret.add(nextMajorVersion)
        if isFinalRelease(version):
            ret.add('%s.1' % version)
        else:
            ret.add(increment(version))
    return ret
Example #5
0
def bump_configs(release, cfgFile, l10nContents, workdir,
                 hg_username, productionBranch, defaultBranch='default'):
    # Update the production branch first, because that's where we want to read
    # the templates from
    update(workdir, productionBranch)
    cfgDir = path.join(workdir, 'mozilla')
    templateFile = path.join(cfgDir, '%s.template' % cfgFile)
    tags = set(getTags(getBaseTag(release['product'], release['version']),
                   release['buildNumber']))
    cfgFile = path.join(cfgDir, cfgFile)
    l10nChangesetsFile = path.join(
        cfgDir,
        readReleaseConfig(cfgFile)['l10nRevisionFile']
    )
    subs = release.copy()
    if 'partials' in release:
        subs['partials'] = getPartials(release)
    # This is true 99% of the time. It's exceedingly rare that we ship a point
    # release that we first push to the beta channel. If we need to, the
    # expectation is that this will be ignored by hardcoding True in the
    # template.
    if isFinalRelease(release["version"]):
        subs["betaChannelEnabled"] = True
    else:
        subs["betaChannelEnabled"] = False

    with open(templateFile) as f:
        template = f.read()
    releaseConfig = substituteReleaseConfig(template, **subs)
    # Write out the new configs on the production branch...
    with open(cfgFile, 'w') as f:
        f.write(releaseConfig)
    with open(l10nChangesetsFile, 'w') as f:
        f.write(l10nContents)
    prodRev = commit(workdir, 'Update release config for %s' % release['name'],
                     user=hg_username)
    # We always force tagging, because it makes it easier to retrigger a
    # release that fails for infrastructure reasons.
    tag(workdir, tags, rev=prodRev, force=True, user=hg_username)

    # And then write the same files to the default branch
    update(workdir, defaultBranch)
    with open(cfgFile, 'w') as f:
        f.write(releaseConfig)
    with open(l10nChangesetsFile, 'w') as f:
        f.write(l10nContents)
    commit(workdir, 'Update release config for %s' % release['name'],
           user=hg_username)
Example #6
0
def main(options):
    log.info('Loading config from %s' % options.config)

    with open(options.config, 'r') as config_file:
        config = yaml.load(config_file)

    if config['release-runner'].get('verbose', False):
        log_level = logging.DEBUG
    else:
        log_level = logging.INFO
    logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s",
                        level=log_level)
    # Suppress logging of retry(), see bug 925321 for the details
    logging.getLogger("util.retry").setLevel(logging.WARN)

    api_root = config['api']['api_root']
    username = config['api']['username']
    password = config['api']['password']

    rr_config = config['release-runner']
    sleeptime = rr_config['sleeptime']
    smtp_server = rr_config.get('smtp_server', 'localhost')
    notify_from = rr_config.get('notify_from')
    notify_to = rr_config.get('notify_to_announce')
    if isinstance(notify_to, basestring):
        notify_to = [x.strip() for x in notify_to.split(',')]

    rr = ReleaseRunner(api_root=api_root, username=username, password=password)
    tc_config = {
        "credentials": {
            "clientId": config["taskcluster"].get("client_id"),
            "accessToken": config["taskcluster"].get("access_token"),
        },
        "maxRetries": 12,
    }
    queue = taskcluster.Queue(tc_config)

    while True:
        try:
            log.debug('Fetching release requests')
            rr.get_release_requests([r['pattern'] for r in config['releases']])
            if rr.new_releases:
                new_releases = run_prebuild_sanity_checks(
                    rr, config['releases'])
                break
            else:
                log.debug('Sleeping for %d seconds before polling again' %
                          sleeptime)
                time.sleep(sleeptime)
        except:
            log.error("Caught exception when polling:", exc_info=True)
            sys.exit(5)

    rc = 0
    for release in new_releases:
        try:
            next_version = bump_version(release["version"].replace("esr", ""))
            project = release["branchShortName"]
            revision = release["mozillaRevision"]
            decision_task_id = find_decision_task_id(project, revision)
            action_task_input = {
                "build_number": release["buildNumber"],
                "next_version": next_version,
                "release_promotion_flavor":
                "promote_{}".format(release["product"]),
                "previous_graph_ids": [decision_task_id],
            }
            if "partial_updates" in release:
                action_task_input["partial_updates"] = {}
                for version, info in release["partial_updates"].items():
                    action_task_input["partial_updates"][version] = {
                        "buildNumber": info["buildNumber"],
                        "locales": info["locales"]
                    }
            if release["product"] == "firefox":
                if "b" in release["version"]:
                    action_task_input["desktop_release_type"] = "beta"
                elif "esr" in release["version"]:
                    action_task_input["desktop_release_type"] = "esr"
                else:
                    # RC release types will enable beta-channel testing &
                    # shipping. We need this for all "final" releases
                    # and also any releases that include a beta as a partial.
                    # The assumption than "shipping to beta channel" always
                    # implies other RC behaviour is bound to break at some
                    # point, but this works for now.
                    if isFinalRelease(release["version"]):
                        action_task_input["desktop_release_type"] = "rc"
                    else:
                        for version in release["partial_updates"]:
                            if "b" in version:
                                action_task_input[
                                    "desktop_release_type"] = "rc"
                                break
                        else:
                            action_task_input[
                                "desktop_release_type"] = "release"
            elif release["product"] == "devedition":
                action_task_input["desktop_release_type"] = "devedition"
            action_task_id, action_task = generate_action_task(
                project=release["branchShortName"],
                revision=release["mozillaRevision"],
                action_task_input=action_task_input,
            )
            submit_action_task(queue=queue,
                               action_task_id=action_task_id,
                               action_task=action_task)
            rr.mark_as_completed(release)
            l10n_url = rr.release_l10n_api.getL10nFullUrl(release['name'])
            email_release_drivers(smtp_server=smtp_server,
                                  from_=notify_from,
                                  to=notify_to,
                                  release=release,
                                  task_group_id=action_task_id,
                                  l10n_url=l10n_url)
        except Exception as exception:
            # We explicitly do not raise an error here because there's no
            # reason not to start other releases if creating the Task Graph
            # fails for another one. We _do_ need to set this in order to exit
            # with the right code, though.
            rc = 2
            rr.mark_as_failed(
                release, 'Failed to start release promotion. Error(s): %s' %
                (exception))
            log.exception('Failed to start release "%s". Error(s): %s',
                          release['name'], exception)
            log.debug('Release failed: %s', release)

    if rc != 0:
        sys.exit(rc)

    log.debug('Sleeping for %s seconds before polling again', sleeptime)
    time.sleep(sleeptime)