def test_firefox_version_ensures_it_does_not_have_multiple_type( monkeypatch, version_string): # Let's make sure the sanity checks detect a broken regular expression monkeypatch.setattr(mozilla_version.gecko, '_VALID_ENOUGH_VERSION_PATTERN', _SUPER_PERMISSIVE_PATTERN) with pytest.raises(TooManyTypesError): FirefoxVersion.parse(version_string)
def test_firefox_version_ensures_it_does_not_have_multiple_type( monkeypatch, version_string): # Let's make sure the sanity checks detect a broken regular expression original_pattern = FirefoxVersion._VALID_ENOUGH_VERSION_PATTERN FirefoxVersion._VALID_ENOUGH_VERSION_PATTERN = _SUPER_PERMISSIVE_PATTERN with pytest.raises(TooManyTypesError): FirefoxVersion.parse(version_string) FirefoxVersion._VALID_ENOUGH_VERSION_PATTERN = original_pattern
def good_version(release): '''Can the version be parsed by mozilla_version Some ancient versions cannot be parsed by the mozilla_version module. This function helps to skip the versions that are not supported. Example versions that cannot be parsed: 1.1, 1.1b1, 2.0.0.1 ''' try: FirefoxVersion.parse(release['version']) return True except ValueError: return False
def _generate_beetmover_template_args_maven(task, release_props): tmpl_args = { "artifact_id": task["payload"]["artifact_id"], "template_key": "maven_{}".format(release_props["appName"]) } # Geckoview follows the FirefoxVersion pattern if release_props.get("appName") == "geckoview": payload_version = FirefoxVersion.parse(task["payload"]["version"]) # Change version number to major.minor.buildId because that's what the build task produces version = [ payload_version.major_number, payload_version.minor_number, release_props["buildid"] ] else: payload_version = MavenVersion.parse(task["payload"]["version"]) version = [ payload_version.major_number, payload_version.minor_number, payload_version.patch_number ] if any(number is None for number in version): raise TaskVerificationError( "At least one digit is undefined. Got: {}".format(version)) tmpl_args["version"] = ".".join(str(n) for n in version) # XXX: some appservices maven.zip files have a different structure, # encompassing only `pom` and `jar` files. We toggle that behavior in the # mapping by using this flag tmpl_args["is_jar"] = task["payload"].get("is_jar") return tmpl_args
def _generate_beetmover_template_args_maven(task, release_props): tmpl_args = { 'artifact_id': task['payload']['artifact_id'], 'template_key': 'maven_{}'.format(release_props['appName']), } # FIXME: this is a temporarily solution while we sanitize the payload # under https://github.com/mozilla-releng/beetmoverscript/issues/196 if 'SNAPSHOT' in task['payload']['version']: payload_version = MavenVersion.parse(task['payload']['version']) else: payload_version = FirefoxVersion.parse(task['payload']['version']) # Change version number to major.minor.buildId because that's what the build task produces version = [ payload_version.major_number, payload_version.minor_number, release_props.get('buildid', payload_version.patch_number) ] if any(number is None for number in version): raise TaskVerificationError( 'At least one digit is undefined. Got: {}'.format(version)) tmpl_args['version'] = '.'.join(str(n) for n in version) if isinstance(payload_version, MavenVersion) and payload_version.is_snapshot: tmpl_args['snapshot_version'] = payload_version tmpl_args['date_timestamp'] = "{{date_timestamp}}" tmpl_args['clock_timestamp'] = "{{clock_timestamp}}" tmpl_args['build_number'] = "{{build_number}}" return tmpl_args
def is_partner_enabled(product, version, min_version=60): if product == "firefox": firefox_version = FirefoxVersion.parse(version) return firefox_version.major_number >= min_version and any( (firefox_version.is_beta and firefox_version.beta_number >= 8, firefox_version.is_release, firefox_version.is_esr)) return False
def is_eme_free_enabled(product, version): if product == "firefox": firefox_version = FirefoxVersion.parse(version) return any( (firefox_version.is_beta and firefox_version.beta_number >= 8, firefox_version.is_release)) return False
def check_versions_are_successive(current_version, payload_version, product): """Function to check if the provided version in the payload and the existing one in bouncer are successive as valid versions.""" def _successive_sanity(current_identifier, candidate_identifier): if current_identifier == candidate_identifier: err_msg = ( "Identifiers for {} and {} can't be equal at this point " "in the code".format(payload_version, current_version)) raise ScriptWorkerTaskException(err_msg) elif current_identifier > candidate_identifier: err_msg = ("In-tree version {} can't be less than current bouncer " "counterpart".format(payload_version, current_version)) raise ScriptWorkerTaskException(err_msg) elif (candidate_identifier - current_identifier) > 1: err_msg = ( "In-tree version {} can't be greater than current bouncer " "by more than 1 digit".format(payload_version, current_version)) raise ScriptWorkerTaskException(err_msg) # XXX: for Firefox central nightlies we need to handle the major number # while for Fennec nightlies on ESR we need to handle minor_number if product == "firefox": current_bouncer_version = FirefoxVersion.parse(current_version) candidate_version = FirefoxVersion.parse(payload_version) _successive_sanity(current_bouncer_version.major_number, candidate_version.major_number) elif product == "fennec": # XXX: this will fail for the next ESR cut, on 75, since that will be a # major_number bump, but also a minor_number. But cutting ESR releases # can vary over time (could be 7 releases or 8 like ESR8, etc); # It's unrecommended to hardcode those variable window times here # in order to ensure the check; So for now we leave this code smell here. # Real fix is to centralize this operation and implement it in mozilla-version directly current_bouncer_version = FennecVersion.parse(current_version) candidate_version = FennecVersion.parse(payload_version) _successive_sanity(current_bouncer_version.minor_number, candidate_version.minor_number) else: err_msg = "Unknown product {} in the payload".format(product) raise ScriptWorkerTaskException(err_msg) log.info("Versions are successive. All good")
def test_firefox_version_supports_released_edge_cases(version_string): assert str(FirefoxVersion.parse(version_string)) == version_string for Class in (DeveditionVersion, FennecVersion, ThunderbirdVersion): if Class == FennecVersion and version_string in ('33.1', '33.1build1', '33.1build2'): # These edge cases also exist in Fennec continue with pytest.raises(PatternNotMatchedError): Class.parse(version_string)
def list_releases(product=None, branch=None, version=None, build_number=None, status=['scheduled']): session = current_app.db.session releases = session.query(Release) if product: releases = releases.filter(Release.product == product) if branch: releases = releases.filter(Release.branch == branch) if version: releases = releases.filter(Release.version == version) if build_number: releases = releases.filter(Release.build_number == build_number) elif build_number: raise BadRequest(description='Filtering by build_number without version' ' is not supported.') releases = releases.filter(Release.status.in_(status)) releases = [r.json for r in releases.all()] # filter out not parsable releases, like 1.1, 1.1b1, etc releases = filter(good_version, releases) return sorted(releases, key=lambda r: FirefoxVersion.parse(r['version']))
def _generate_beetmover_template_args_maven(task, release_props): tmpl_args = { 'artifact_id': task['payload']['artifact_id'], 'template_key': 'maven_{}'.format(release_props['appName']), } # Geckoview follows the FirefoxVersion pattern if release_props.get('appName') == 'geckoview': payload_version = FirefoxVersion.parse(task['payload']['version']) # Change version number to major.minor.buildId because that's what the build task produces version = [ payload_version.major_number, payload_version.minor_number, release_props['buildid'], ] else: payload_version = MavenVersion.parse(task['payload']['version']) version = [ payload_version.major_number, payload_version.minor_number, payload_version.patch_number, ] if any(number is None for number in version): raise TaskVerificationError( 'At least one digit is undefined. Got: {}'.format(version)) tmpl_args['version'] = '.'.join(str(n) for n in version) # XXX: some appservices maven.zip files have a different structure, # encompassing only `pom` and `jar` files. We toggle that behavior in the # mapping by using this flag tmpl_args['is_jar'] = task['payload'].get('is_jar') if isinstance(payload_version, MavenVersion) and payload_version.is_snapshot: tmpl_args['snapshot_version'] = payload_version tmpl_args['date_timestamp'] = "{{date_timestamp}}" tmpl_args['clock_timestamp'] = "{{clock_timestamp}}" tmpl_args['build_number'] = "{{build_number}}" return tmpl_args
def get_maven_version(context): """Extract and validate a valid Maven version""" version = context.task["payload"]["version"] release_props = context.release_props # TODO The following 'if' should be removed once GeckoView >= 84 is in mozilla-release. # This is a temporary solution to maintain compatibility while the 'version' field in # GeckoView's payload transitions from FirefoxVersion format to MavenVersion. if release_props.get("appName") == "geckoview": app_version = FirefoxVersion.parse(release_props["appVersion"]) if int(app_version.major_number) < 84: # Change version number to major.minor.buildId because that's what the build task produces version = "{}.{}.{}".format(app_version.major_number, app_version.minor_number, release_props["buildid"]) # Check that version is a valid maven version try: MavenVersion.parse(version) except (ValueError, PatternNotMatchedError) as e: raise ScriptWorkerTaskException( f"Version defined in the payload does not match the pattern of a MavenVersion. Got: {version}" ) from e return version
def test_firefox_version_implements_str_operator(version_string, expected_output): assert str(FirefoxVersion.parse(version_string)) == expected_output
def test_firefox_version_implements_remaining_comparision_operators(): assert FirefoxVersion.parse('32.0') <= FirefoxVersion.parse('32.0') assert FirefoxVersion.parse('32.0') <= FirefoxVersion.parse('33.0') assert FirefoxVersion.parse('33.0') >= FirefoxVersion.parse('32.0') assert FirefoxVersion.parse('33.0') >= FirefoxVersion.parse('33.0') assert FirefoxVersion.parse('33.0') > FirefoxVersion.parse('32.0') assert not FirefoxVersion.parse('33.0') > FirefoxVersion.parse('33.0') assert not FirefoxVersion.parse('32.0') < FirefoxVersion.parse('32.0') assert FirefoxVersion.parse('33.0') != FirefoxVersion.parse('32.0')
def test_firefox_version_raises_eq_operator(wrong_type): with pytest.raises(ValueError): assert FirefoxVersion.parse('32.0') == wrong_type # AttributeError is raised by LooseVersion and StrictVersion with pytest.raises((ValueError, AttributeError)): assert wrong_type == FirefoxVersion.parse('32.0')
def test_firefox_version_implements_eq_operator(equivalent_version_string): assert FirefoxVersion.parse('32.0') == FirefoxVersion.parse( equivalent_version_string) # raw strings are also converted assert FirefoxVersion.parse('32.0') == equivalent_version_string
def test_firefox_version_implements_lt_operator(previous, next): assert FirefoxVersion.parse(previous) < FirefoxVersion.parse(next)
mocker.patch.object(merges, "replace", new=noop_replace) mocker.patch.object(merges, "touch_clobber_file", new=sync_noop) await merges.apply_rebranding(config, repo_context.repo, merge_config) assert called_args[0] == expected @pytest.mark.asyncio @pytest.mark.parametrize( "version_config,current_version, expected", ( # central-to-beta ({ "filename": "config/milestone.txt", "new_suffix": "" }, FirefoxVersion.parse("75.0a1"), "75.0"), ({ "filename": "browser/config/version_display.txt", "new_suffix": "b1" }, FirefoxVersion.parse("75.0a1"), "75.0b1"), # beta-to-release ({ "filename": "browser/config/version_display.txt", "new_suffix": "" }, FirefoxVersion.parse("75.0b9"), "75.0"), # bump_central ({ "filename": "config/milestone.txt", "version_bump": "major" }, FirefoxVersion.parse("75.0a1"), "76.0a1"), ({
def test_firefox_version_raises_when_invalid_version_is_given( version_string, ExpectedErrorType): with pytest.raises(ExpectedErrorType): FirefoxVersion.parse(version_string)
def test_firefox_version_is_of_a_defined_type(version_string, expected_type): release = FirefoxVersion.parse(version_string) assert getattr(release, 'is_{}'.format(expected_type))
def mocked_get_version(path, repo_path): return FirefoxVersion.parse("76.0")
mocker.patch.object(merges, "get_version", new=mocked_get_version) mocker.patch.object(merges, "do_bump_version", new=noop_bump_version) mocker.patch.object(shutil, "copyfile", new=noop_copyfile) mocker.patch.object(merges, "replace", new=noop_replace) mocker.patch.object(merges, "touch_clobber_file", new=sync_noop) await merges.apply_rebranding(config, repo_context.repo, merge_config) assert called_args[0] == expected @pytest.mark.asyncio @pytest.mark.parametrize( "version_config,current_version, expected", ( # central-to-beta ({"filename": "config/milestone.txt", "new_suffix": ""}, FirefoxVersion.parse("75.0a1"), "75.0"), ({"filename": "browser/config/version_display.txt", "new_suffix": "b1"}, FirefoxVersion.parse("75.0a1"), "75.0b1"), # beta-to-release ({"filename": "browser/config/version_display.txt", "new_suffix": ""}, FirefoxVersion.parse("75.0b9"), "75.0"), # bump_central ({"filename": "config/milestone.txt", "version_bump": "major"}, FirefoxVersion.parse("75.0a1"), "76.0a1"), ({"filename": "config/milestone.txt", "version_bump": "major"}, FirefoxVersion.parse("75.0"), "76.0"), # bump_esr ({"filename": "browser/config/version.txt", "version_bump": "minor"}, FirefoxVersion.parse("68.1.0"), "68.2.0"), ({"filename": "browser/config/version_display.txt", "version_bump": "minor"}, FirefoxVersion.parse("68.1.0esr"), "68.2.0esr"), ({"filename": "mobile/android/config/version-files/beta/version.txt", "version_bump": "minor"}, FennecVersion.parse("68.1"), "68.2"), ({"filename": "mobile/android/config/version-files/beta/version_display.txt", "version_bump": "minor"}, FennecVersion.parse("68.1b9"), "68.2b1"), ({"filename": "mobile/android/config/version-files/nightly/version.txt", "version_bump": "minor"}, FennecVersion.parse("68.1a1"), "68.2a1"), ({"filename": "mobile/android/config/version-files/release/version.txt", "version_bump": "minor"}, FennecVersion.parse("68.6.1"), "68.7.0"), ), )