Skip to content

Commit

Permalink
Bug 1763188 - Add Snap support using TC builds
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexandre Lissy committed Apr 25, 2024
1 parent e09d1f9 commit 7c974ee
Show file tree
Hide file tree
Showing 11 changed files with 515 additions and 22 deletions.
63 changes: 63 additions & 0 deletions mozregression/bisector.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,51 @@ def handle_merge(self):
return result


"""
We are just using this to make it clear we have no merge to take care of
We are running an Integration because builds are triggered from cron jobs
on mozilla-central for all Snap package branches
"""


class SnapHandler(IntegrationHandler):
snap_repo = None
_build_infos = {}
snap_rev = {}

def __init__(self, **kwargs):
super(IntegrationHandler, self).__init__(**kwargs)

def record_build_infos(self, build_infos):
self._build_infos["_changeset"] = build_infos._changeset
self._build_infos["_repo_url"] = build_infos._repo_url
self.snap_repo = build_infos._repo_url

def update_build_infos(self, build_infos):
# _build_infos here holds the mozilla-central ones,
# build_infos should be the snap-specific one
self.snap_rev[self._build_infos["_changeset"]] = build_infos.changeset
self.snap_repo = build_infos._repo_url

def get_pushlog_url(self):
# somehow, self.found_repo from this class would not reflect
first_rev, last_rev = self.get_range()
if first_rev == last_rev:
return "%s/pushloghtml?changeset=%s" % (self.snap_repo, first_rev)
return "%s/pushloghtml?fromchange=%s&tochange=%s" % (
self.snap_repo,
first_rev,
last_rev,
)

def revert_build_infos(self, build_infos):
build_infos._changeset = self._build_infos["_changeset"]
build_infos._repo_url = self._build_infos["_repo_url"]

def handle_merge(self):
return None


class IndexPromise(object):
"""
A promise to get a build index.
Expand Down Expand Up @@ -503,11 +548,29 @@ def start_dl(r):
return self.build_range.index(bdata)

def evaluate(self, build_infos):
# we force getting data from app info for snap since we are building everything
# out of mozilla-central
if type(self.handler) is SnapHandler:
self.handler.record_build_infos(build_infos)
build_infos._force_update = True
verdict = self.test_runner.evaluate(build_infos, allow_back=bool(self.history))
# old builds do not have metadata about the repo. But once
# the build is installed, we may have it
if self.handler.found_repo is None:
self.handler.found_repo = build_infos.repo_url
if type(self.handler) is SnapHandler:
# Some Snap nightly builds are missing SourceRepository/SourceStamp
# So since we dont have a better source of information, let's get back
# what we had
if build_infos.repo_url is None:
LOG.warning(
"Bisection on a Snap package missing SourceRepository/SourceStamp,"
" falling back to mozilla-central revs."
)
build_infos._force_update = False
self.handler.revert_build_infos(build_infos)
else:
self.handler.update_build_infos(build_infos)
return verdict

def ensure_good_and_bad(self):
Expand Down
6 changes: 6 additions & 0 deletions mozregression/branches.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ def create_branches():
):
for alias in aliases:
branches.set_alias(alias, name)

branches.set_branch("snap-nightly", "mozilla-central")
branches.set_branch("snap-beta", "mozilla-central")
branches.set_branch("snap-stable", "mozilla-central")
branches.set_branch("snap-esr", "mozilla-central")

return branches


Expand Down
5 changes: 3 additions & 2 deletions mozregression/build_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def __init__(
task_id=None,
):
self._fetch_config = fetch_config
self._force_update = False # will be set True by SnapHandler
self._build_type = build_type
self._build_url = build_url
self._build_date = build_date
Expand Down Expand Up @@ -136,9 +137,9 @@ def update_from_app_info(self, app_info):
This helps to build the pushlog url for old nightlies.
"""
if self._changeset is None:
if self._changeset is None or self._force_update is True:
self._changeset = app_info.get("application_changeset")
if self._repo_url is None:
if self._repo_url is None or self._force_update is True:
self._repo_url = app_info.get("application_repository")

def persist_filename_for(self, data, regex=True):
Expand Down
47 changes: 45 additions & 2 deletions mozregression/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,21 @@ def create_parser(defaults):
help="Helps to write the configuration file.",
)

parser.add_argument(
"--allow-sudo",
action="store_true",
help=(
"[Snap] Allow the use of sudo for Snap install/remove operations (otherwise,"
" you will be prompted on each)"
),
)

parser.add_argument(
"--disable-snap-connect",
action="store_true",
help="[Snap] Do not automatically perform 'snap connect'",
)

parser.add_argument("--debug", "-d", action="store_true", help="Show the debug output.")

return parser
Expand Down Expand Up @@ -579,14 +594,19 @@ def validate(self):
"x86",
"x86_64",
],
"firefox-snap": [
"aarch64", # will be morphed into arm64
"arm", # will be morphed into armf
"x86_64", # will be morphed into amd64
],
}

user_defined_bits = options.bits is not None
options.bits = parse_bits(options.bits or mozinfo.bits)

if options.arch is not None:
if options.app not in ("gve", "fenix", "focus"):
self.logger.warning("--arch ignored for non Android apps.")
if options.app not in ("gve", "fenix", "focus", "firefox-snap"):
self.logger.warning("--arch ignored for non Android apps or Snap package.")
options.arch = None
elif options.arch not in arch_options[options.app]:
raise MozRegressionError(
Expand All @@ -598,6 +618,29 @@ def validate(self):
f"`--arch` required for specified app ({options.app}). "
f"Please specify one of {', '.join(arch_options[options.app])}."
)
elif options.app == "firefox-snap" and options.allow_sudo is False:
self.logger.warning(
"Bisection on Snap package without --allow-sudo, you will be prompted for"
" credential on each 'snap' command."
)
elif options.allow_sudo is True and options.app != "firefox-snap":
raise MozRegressionError(
f"--allow-sudo specified for app ({options.app}), but only valid for "
f"firefox-snap. Please verify your config."
)
elif options.disable_snap_connect is True and options.app != "firefox-snap":
raise MozRegressionError(
f"--disable-snap-conncet specified for app ({options.app}), but only valid for "
f"firefox-snap. Please verify your config."
)

if options.app == "firefox-snap" and (
options.repo is None or not options.repo.startswith("snap-")
):
raise MozRegressionError(
f"--repo not specified for app ({options.app}), or not starting with snap-. "
f"Please use correct repo for bisecting Snap package."
)

fetch_config = create_config(
options.app, mozinfo.os, options.bits, mozinfo.processor, options.arch
Expand Down
96 changes: 96 additions & 0 deletions mozregression/fetch_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,3 +753,99 @@ def build_regex(self):
part = "mac"
psuffix = "-asan" if "asan" in self.build_type else ""
return r"jsshell-%s%s\.zip$" % (part, psuffix)


TIMESTAMP_SNAP_UPSTREAM_BUILD = to_utc_timestamp(datetime.datetime(2023, 7, 26, 9, 39, 21))
TIMESTAMP_SNAP_INDEX_RENAME = to_utc_timestamp(datetime.datetime(2023, 11, 17, 21, 46, 39))
# This needs to be updated when we land cross-compilation on treeherder
TIMESTAMP_SNAP_CROSS_COMPILATION = to_utc_timestamp(datetime.datetime(3023, 11, 21, 15, 15, 00))


class FirefoxSnapNightlyConfigMixin(NightlyConfigMixin):
def _get_nightly_repo(self, date):
return "mozilla-central"


class FirefoxSnapIntegrationConfigMixin(IntegrationConfigMixin):
def _idx_key(self, date):
branch_name = ""

if self.integration_branch == "snap-nightly":
branch_name = "nightly"
elif self.integration_branch == "snap-beta":
branch_name = "beta"
elif self.integration_branch == "snap-stable":
branch_name = "stable"
elif self.integration_branch == "snap-esr":
branch_name = "esr"
else:
raise errors.MozRegressionError(
"No such branch available, valid are nightly/beta/stable/esr"
" (prefix with snap- for --repo)"
)

if date < TIMESTAMP_SNAP_UPSTREAM_BUILD:
raise errors.MozRegressionError("No build before this date")
elif date >= TIMESTAMP_SNAP_UPSTREAM_BUILD and date < TIMESTAMP_SNAP_INDEX_RENAME:
index_base = ""
elif date >= TIMESTAMP_SNAP_INDEX_RENAME:
index_base = "{}-".format(self.arch)

if self.arch != "amd64" and date < TIMESTAMP_SNAP_CROSS_COMPILATION:
raise errors.MozRegressionError(f"No support for build other than amd64 ({self.arch})")

return "{}{}".format(index_base, branch_name)

def tk_routes(self, push):
for build_type in self.build_types:
name = "gecko.v2.mozilla-central.revision.{}.firefox.{}{}".format(
push.changeset,
self._idx_key(push.timestamp),
"-{}".format(build_type)
if build_type != "opt" and build_type != "shippable"
else "",
)
yield name
self._inc_used_build()
return


class SnapCommonConfig(CommonConfig):
def should_use_archive(self):
"""
We only want to use TaskCluster builds
"""
return False

def build_regex(self):
return r"(firefox_.*)\.snap"


@REGISTRY.register("firefox-snap")
class FirefoxSnapConfig(
SnapCommonConfig, FirefoxSnapIntegrationConfigMixin, FirefoxSnapNightlyConfigMixin
):
BUILD_TYPES = ("shippable", "opt", "debug")
BUILD_TYPE_FALLBACKS = {
"shippable": ("opt",),
"opt": ("shippable",),
}

def __init__(self, os, bits, processor, arch):
super(FirefoxSnapConfig, self).__init__(os, bits, processor, arch)
self.set_build_type("shippable")

def available_archs(self):
return [
"aarch64",
"arm",
"x86_64",
]

def set_arch(self, arch):
mapping = {
"aarch64": "arm64",
"arm": "armhf",
"x86_64": "amd64",
}
self.arch = mapping.get(arch, "amd64")
Loading

0 comments on commit 7c974ee

Please sign in to comment.