• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / mozregression / 9283882049

29 May 2024 09:44AM CUT coverage: 86.286%. First build
9283882049

Pull #1450

github

web-flow
Merge ee901c877 into 3e46da41f
Pull Request #1450: Bug 1763188 - Add Snap support using TC builds

96 of 217 new or added lines in 8 files covered. (44.24%)

2586 of 2997 relevant lines covered (86.29%)

5.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.19
/mozregression/fetch_configs.py
1
"""
2
This module defines the configuration needed for nightly and integration
3
fetching for each application. This configuration is a base block
4
for everything done in mozregression since it holds information
5
about how to get information about builds for a given application.
6

7
The public entry point in there is :func:`create_config`, which
8
creates an returns a fetch configuration. the configuration will
9
be an instance of :class:`CommonConfig`, possibly using the mixins
10
:class:`NightlyConfigMixin` and/or :class:`IntegrationConfigMixin`.
11
<
12
Example to create a configuration for firefox on linux 64: ::
13

14
  fetch_config = create_config('firefox', 'linux', 64)
15

16
You can also use the variable *REGISTRY* defined in this module to get a
17
list of application names that can be used to build a configuration. This is
18
an instance of :class:`ClassRegistry`. Example: ::
19

20
  print REGISTRY.names()
21
"""
22

23
from __future__ import absolute_import
8✔
24

25
import datetime
8✔
26
import re
8✔
27
from abc import ABCMeta, abstractmethod
8✔
28

29
from mozlog import get_proxy_logger
8✔
30

31
from mozregression import branches, errors
8✔
32
from mozregression.class_registry import ClassRegistry
8✔
33
from mozregression.config import ARCHIVE_BASE_URL
8✔
34
from mozregression.dates import to_utc_timestamp
8✔
35

36
LOG = get_proxy_logger(__name__)
8✔
37

38
# switch from fennec api-11 to api-15 on taskcluster
39
# appeared on this date for m-c.
40
TIMESTAMP_FENNEC_API_15 = to_utc_timestamp(datetime.datetime(2016, 1, 29, 0, 30, 13))
8✔
41

42
# switch from fennec api-15 to api-16 on taskcluster
43
# appeared on this date for m-c.
44
TIMESTAMP_FENNEC_API_16 = to_utc_timestamp(datetime.datetime(2017, 8, 29, 18, 28, 36))
8✔
45

46
# switch from geckoview api-16 to arm
47
TIMESTAMP_GECKOVIEW_ARM = to_utc_timestamp(datetime.datetime(2021, 6, 5, 3, 56, 19))
8✔
48

49

50
def get_build_regex(name, os, bits, processor, platprefix=r".*", platsuffix="", with_ext=True):
8✔
51
    """
52
    Returns a string regexp that can match a build filename.
53

54
    :param name: must be the beginning of the filename to match
55
    :param os: the os, as returned by mozinfo.os
56
    :param bits: the bits information of the build. Either 32 or 64.
57
    :param processor: the architecture of the build. Only one that alters
58
                      results is aarch64.
59
    :param platprefix: optional prefix before the platform
60
    :param platsuffix: optional suffix after the platform
61
    :param with_ext: if True, the build extension will be appended (either
62
                     .zip, .tar.bz2 or .dmg depending on the os).
63
    """
64
    if os == "win":
6✔
65
        if bits == 64:
6✔
66
            if processor == "aarch64":
6✔
67
                platform = r"win64-aarch64"
6✔
68
            else:
69
                platform = r"win64(-x86_64)?"
6✔
70
            ext = r"\.zip"
6✔
71
        else:
72
            platform, ext = r"win32", r"\.zip"
6✔
73
    elif os == "linux":
6✔
74
        if bits == 64:
6✔
75
            platform, ext = r"linux-x86_64", r"\.tar.bz2"
6✔
76
        else:
77
            platform, ext = r"linux-i686", r"\.tar.bz2"
6✔
78
    elif os == "mac":
6✔
79
        platform, ext = r"mac.*", r"\.dmg"
6✔
80
    else:
81
        raise errors.MozRegressionError(
6✔
82
            "mozregression supports linux, mac and windows but your" " os is reported as '%s'." % os
83
        )
84

85
    # New taskcluster builds now just name the binary archive 'target', so
86
    # that is added as one possibility in the regex.
87
    regex = "(target|%s%s%s%s)" % (name, platprefix, platform, platsuffix)
6✔
88
    if with_ext:
6✔
89
        return "%s%s" % (regex, ext)
6✔
90
    else:
91
        return regex
6✔
92

93

94
class CommonConfig(object):
8✔
95
    """
96
    Define the configuration for both nightly and integration fetching.
97
    """
98

99
    BUILD_TYPES = ("opt",)  # only opt allowed by default
8✔
100
    BUILD_TYPE_FALLBACKS = {}
8✔
101
    app_name = None
8✔
102

103
    def __init__(self, os, bits, processor, arch):
8✔
104
        self.os = os
8✔
105
        self.bits = bits
8✔
106
        self.processor = processor
8✔
107
        self.set_arch(arch)
8✔
108
        self.repo = None
8✔
109
        self.set_build_type("opt")
8✔
110
        self._used_build_index = 0
8✔
111

112
    @property
8✔
113
    def build_type(self):
8✔
114
        """
115
        Returns the currently selected build type, which can change if there
116
        are fallbacks specified.
117
        """
118
        return self.build_types[self._used_build_index]
8✔
119

120
    def _inc_used_build(self):
8✔
121
        """
122
        Increments the index into the build_types indicating the currently
123
        selected build type.
124
        """
125
        self._used_build_index = (
6✔
126
            # Need to be careful not to overflow the list
127
            (self._used_build_index + 1)
128
            % len(self.build_types)
129
        )
130

131
    def build_regex(self):
8✔
132
        """
133
        Returns a string regex that can match a build file on the servers.
134
        """
135
        return get_build_regex(self.app_name, self.os, self.bits, self.processor) + "$"
×
136

137
    def build_info_regex(self):
8✔
138
        """
139
        Returns a string regex that can match a build info file (txt)
140
        on the servers.
141
        """
142
        return (
6✔
143
            get_build_regex(self.app_name, self.os, self.bits, self.processor, with_ext=False)
144
            + r"\.txt$"
145
        )
146

147
    def is_nightly(self):
8✔
148
        """
149
        Returns True if the configuration can be used for nightly fetching.
150
        """
151
        return isinstance(self, NightlyConfigMixin)
×
152

153
    def is_integration(self):
8✔
154
        """
155
        Returns True if the configuration can be used for integration fetching.
156
        """
157
        return isinstance(self, IntegrationConfigMixin)
6✔
158

159
    def available_bits(self):
8✔
160
        """
161
        Returns the no. of bits of the OS for which the application should
162
        run.
163
        """
164
        return (32, 64)
2✔
165

166
    def available_archs(self):
8✔
167
        """
168
        Returns the available architectures for this application.
169
        """
170
        return []
2✔
171

172
    def set_arch(self, arch):
8✔
173
        """
174
        Set the target build architecture for the application.
175
        """
176
        self.arch = arch
8✔
177

178
    def available_build_types(self):
8✔
179
        res = []
8✔
180
        for available in self.BUILD_TYPES:
8✔
181
            match = re.match(r"(.+)\[(.+)\]", available)
8✔
182
            if match:
8✔
183
                suffix = "-aarch64" if self.processor == "aarch64" and self.bits == 64 else ""
8✔
184
                available = match.group(1)
8✔
185
                platforms = match.group(2)
8✔
186
                if "{}{}{}".format(self.os, self.bits, suffix) not in platforms.split(","):
8✔
187
                    available = None
8✔
188
            if available:
8✔
189
                res.append(available)
8✔
190
        return res
8✔
191

192
    def set_build_type(self, build_type):
8✔
193
        """
194
        Define the build type (opt, debug, asan...).
195

196
        :raises: MozRegressionError on error.
197
        """
198
        if build_type in self.available_build_types():
8✔
199
            fallbacks = self.BUILD_TYPE_FALLBACKS.get(build_type)
8✔
200
            self.build_types = (build_type,) + fallbacks if fallbacks else (build_type,)
8✔
201
            return
8✔
202
        raise errors.MozRegressionError(
6✔
203
            "Unable to find a suitable build type %r." % str(build_type)
204
        )
205

206
    def set_repo(self, repo):
8✔
207
        """
208
        Allow to define the repo name.
209

210
        If not set or set to None, default repos would be used (see
211
        :meth:`get_nightly_repo` and :attr:`integration_branch`)
212
        """
213
        self.repo = branches.get_name(repo) if repo else None
8✔
214

215
    def should_use_archive(self):
8✔
216
        """
217
        Returns True if we should use the archive as an initial bisection
218
        method (archive.mozilla.org has a much longer retention period than
219
        taskcluster).
220

221
        Note that this method relies on the repo and build type defined.
222
        """
223
        # we can find the asan builds (firefox and jsshell) in archives.m.o
224
        return not (
6✔
225
            branches.get_category(self.repo) in ("integration", "try", "releases")
226
            or self.build_type not in ("opt", "asan", "shippable")
227
        )
228

229
    def extra_persist_part(self):
8✔
230
        """
231
        Allow to add a part in the generated persist file name to distinguish
232
        different builds that might be produced by a single config. Returns an
233
        empty string by default.
234
        """
235
        return ""
6✔
236

237

238
class NightlyConfigMixin(metaclass=ABCMeta):
8✔
239
    """
240
    Define the nightly-related required configuration to find nightly builds.
241

242
    A nightly build url is divided in 2 parts here:
243

244
    1. the base part as returned by :meth:`get_nightly_base_url`
245
    2. the final part, which can be found using :meth:`get_nighly_repo_regex`
246

247
    The final part contains a repo name, which is returned by
248
    :meth:`get_nightly_repo`.
249

250
    Note that subclasses must implement :meth:`_get_nightly_repo` to
251
    provide a default value.
252
    """
253

254
    archive_base_url = ARCHIVE_BASE_URL
8✔
255
    nightly_base_repo_name = "firefox"
8✔
256
    nightly_repo = None
8✔
257
    has_build_info = True
8✔
258

259
    def set_base_url(self, url):
8✔
260
        self.archive_base_url = url.rstrip("/")
8✔
261

262
    def get_nightly_base_url(self, date):
8✔
263
        """
264
        Returns the base part of the nightly build url for a given date.
265
        """
266
        return "%s/%s/nightly/%04d/%02d/" % (
6✔
267
            self.archive_base_url,
268
            self.nightly_base_repo_name,
269
            date.year,
270
            date.month,
271
        )
272

273
    def get_nightly_info_url(self, url):
8✔
274
        """
275
        Returns the url for the folder to find the build info .txt
276
        """
277
        return url
×
278

279
    def get_nightly_repo(self, date):
8✔
280
        """
281
        Returns the repo name for a given date.
282
        """
283
        if isinstance(date, datetime.datetime):
6✔
284
            date = date.date()
6✔
285
        return self.repo or self._get_nightly_repo(date)
6✔
286

287
    @abstractmethod
8✔
288
    def _get_nightly_repo(self, date):
8✔
289
        """
290
        Returns a default repo name for a given date.
291
        """
292
        raise NotImplementedError
293

294
    def get_nightly_repo_regex(self, date):
8✔
295
        """
296
        Returns a string regex that can match the last folder name for a given
297
        date.
298
        """
299
        return self._get_nightly_repo_regex(date, self.get_nightly_repo(date))
6✔
300

301
    def _get_nightly_repo_regex(self, date, repo):
8✔
302
        if isinstance(date, datetime.datetime):
6✔
303
            return r"/%04d-%02d-%02d-%02d-%02d-%02d-%s/$" % (
6✔
304
                date.year,
305
                date.month,
306
                date.day,
307
                date.hour,
308
                date.minute,
309
                date.second,
310
                repo,
311
            )
312
        return r"/%04d-%02d-%02d-[\d-]+%s/$" % (date.year, date.month, date.day, repo)
6✔
313

314
    def can_go_integration(self):
8✔
315
        """
316
        Indicate if we can bisect integration from this nightly config.
317
        """
318
        return self.is_integration()
6✔
319

320

321
class FirefoxNightlyConfigMixin(NightlyConfigMixin):
8✔
322
    def _get_nightly_repo(self, date):
8✔
323
        if date < datetime.date(2008, 6, 17):
6✔
324
            return "trunk"
6✔
325
        else:
326
            return "mozilla-central"
6✔
327

328

329
class FirefoxL10nNightlyConfigMixin(NightlyConfigMixin):
8✔
330
    has_build_info = False
8✔
331
    oldest_builds = datetime.date(2015, 10, 19)
8✔
332

333
    def _get_nightly_repo(self, date):
8✔
334
        if date < self.oldest_builds:
6✔
335
            raise errors.MozRegressionError(
6✔
336
                "firefox-l10n builds not available before {}".format(self.oldest_builds)
337
            )
338
        else:
339
            return "mozilla-central-l10n"
6✔
340

341
    def get_nightly_info_url(self, url):
8✔
342
        return url.replace("-l10n/", "/")
×
343

344

345
class ThunderbirdNightlyConfigMixin(NightlyConfigMixin):
8✔
346
    nightly_base_repo_name = "thunderbird"
8✔
347

348
    def _get_nightly_repo(self, date):
8✔
349
        # sneaking this in here
350
        if self.os == "win" and date < datetime.date(2010, 3, 18):
6✔
351
            # no .zip package for Windows, can't use the installer
352
            raise errors.WinTooOldBuildError()
6✔
353

354
        if date < datetime.date(2008, 7, 26):
6✔
355
            return "trunk"
6✔
356
        elif date < datetime.date(2009, 1, 9):
6✔
357
            return "comm-central"
6✔
358
        elif date < datetime.date(2010, 8, 21):
6✔
359
            return "comm-central-trunk"
6✔
360
        else:
361
            return "comm-central"
6✔
362

363

364
class ThunderbirdL10nNightlyConfigMixin(ThunderbirdNightlyConfigMixin):
8✔
365
    has_build_info = False
8✔
366
    oldest_builds = datetime.date(2015, 10, 8)
8✔
367

368
    def _get_nightly_repo(self, date):
8✔
369
        if date < self.oldest_builds:
6✔
370
            raise errors.MozRegressionError(
6✔
371
                "thunderbird-l10n builds not available before {}".format(self.oldest_builds)
372
            )
373
        return "comm-central-l10n"
6✔
374

375

376
class FennecNightlyConfigMixin(NightlyConfigMixin):
8✔
377
    nightly_base_repo_name = "mobile"
8✔
378

379
    def _get_nightly_repo(self, date):
8✔
380
        return "mozilla-central"
6✔
381

382
    def get_nightly_repo_regex(self, date):
8✔
383
        repo = self.get_nightly_repo(date)
6✔
384
        if repo in ("mozilla-central",):
6✔
385
            if date < datetime.date(2014, 12, 6):
6✔
386
                repo += "-android"
6✔
387
            elif date < datetime.date(2014, 12, 13):
6✔
388
                repo += "-android-api-10"
6✔
389
            elif date < datetime.date(2016, 1, 29):
6✔
390
                repo += "-android-api-11"
6✔
391
            elif date < datetime.date(2017, 8, 30):
6✔
392
                repo += "-android-api-15"
6✔
393
            else:
394
                repo += "-android-api-16"
6✔
395
        return self._get_nightly_repo_regex(date, repo)
6✔
396

397

398
class FenixNightlyConfigMixin(NightlyConfigMixin):
8✔
399
    nightly_base_repo_name = "fenix"
8✔
400
    arch_regex_bits = ""
8✔
401

402
    def _get_nightly_repo(self, date):
8✔
403
        return "fenix"
6✔
404

405
    def get_nightly_repo_regex(self, date):
8✔
406
        repo = self.get_nightly_repo(date)
6✔
407
        repo += self.arch_regex_bits  # e.g., ".*arm64.*".
6✔
408
        return self._get_nightly_repo_regex(date, repo)
6✔
409

410

411
class FocusNightlyConfigMixin(FenixNightlyConfigMixin):
8✔
412
    nightly_base_repo_name = "focus"
8✔
413

414
    def _get_nightly_repo(self, date):
8✔
415
        return "focus"
6✔
416

417

418
class IntegrationConfigMixin(metaclass=ABCMeta):
8✔
419
    """
420
    Define the integration-related required configuration.
421
    """
422

423
    default_integration_branch = "mozilla-central"
8✔
424
    _tk_credentials = None
8✔
425

426
    @property
8✔
427
    def integration_branch(self):
8✔
428
        return self.repo or self.default_integration_branch
6✔
429

430
    def tk_route(self, push):
8✔
431
        """
432
        Returns the first taskcluster route for a specific changeset
433
        """
434
        return next(self.tk_routes(push))
6✔
435

436
    @abstractmethod
8✔
437
    def tk_routes(self, push):
8✔
438
        """
439
        Returns a generator of taskcluster routes for a specific changeset.
440
        """
441
        raise NotImplementedError
442

443
    def integration_persist_part(self):
8✔
444
        """
445
        Allow to add a part in the generated persist file name to distinguish
446
        builds. Returns an empty string by default, or 'debug' if build type
447
        is debug.
448
        """
449
        return self.build_type if self.build_type != "opt" else ""
6✔
450

451
    def tk_needs_auth(self):
8✔
452
        """
453
        Returns True if we need taskcluster credentials
454
        """
455
        return False
6✔
456

457
    def set_tk_credentials(self, creds):
8✔
458
        """
459
        Define the credentials required to download private builds on
460
        TaskCluster.
461
        """
462
        self._tk_credentials = creds
×
463

464
    def tk_options(self):
8✔
465
        """
466
        Returns the takcluster options, including the credentials required to
467
        download private artifacts.
468
        """
469
        tk_options = {"rootUrl": "https://firefox-ci-tc.services.mozilla.com"}
6✔
470
        if self.tk_needs_auth():
6✔
471
            tk_options.update({"credentials": self._tk_credentials})
×
472
        return tk_options
6✔
473

474

475
def _common_tk_part(integration_conf):
8✔
476
    # private method to avoid copy/paste for building taskcluster route part.
477
    if integration_conf.os == "linux":
6✔
478
        part = "linux"
6✔
479
        if integration_conf.bits == 64:
6✔
480
            part += str(integration_conf.bits)
6✔
481
    elif integration_conf.os == "mac":
6✔
482
        part = "macosx64"
6✔
483
    else:
484
        # windows
485
        part = "{}{}".format(integration_conf.os, integration_conf.bits)
6✔
486
        if integration_conf.processor == "aarch64" and integration_conf.bits == 64:
6✔
487
            part += "-aarch64"
6✔
488
    return part
6✔
489

490

491
class FirefoxIntegrationConfigMixin(IntegrationConfigMixin):
8✔
492
    def tk_routes(self, push):
8✔
493
        for build_type in self.build_types:
6✔
494
            yield "gecko.v2.{}{}.revision.{}.firefox.{}-{}".format(
6✔
495
                self.integration_branch,
496
                ".shippable" if build_type == "shippable" else "",
497
                push.changeset,
498
                _common_tk_part(self),
499
                "opt" if build_type == "shippable" else build_type,
500
            )
501
            self._inc_used_build()
6✔
502
        return
6✔
503

504

505
class FennecIntegrationConfigMixin(IntegrationConfigMixin):
8✔
506
    tk_name = "android-api-11"
8✔
507

508
    def tk_routes(self, push):
8✔
509
        tk_name = self.tk_name
6✔
510
        if tk_name == "android-api-11":
6✔
511
            if push.timestamp >= TIMESTAMP_GECKOVIEW_ARM:
6✔
512
                tk_name = "android-arm"
×
513
            elif push.timestamp >= TIMESTAMP_FENNEC_API_16:
6✔
514
                tk_name = "android-api-16"
6✔
515
            elif push.timestamp >= TIMESTAMP_FENNEC_API_15:
6✔
516
                tk_name = "android-api-15"
6✔
517
        for build_type in self.build_types:
6✔
518
            yield "gecko.v2.{}{}.revision.{}.mobile.{}-{}".format(
6✔
519
                self.integration_branch,
520
                ".shippable" if build_type == "shippable" else "",
521
                push.changeset,
522
                tk_name,
523
                "opt" if build_type == "shippable" else build_type,
524
            )
525
            self._inc_used_build()
×
526
        return
×
527

528

529
class ThunderbirdIntegrationConfigMixin(IntegrationConfigMixin):
8✔
530
    default_integration_branch = "comm-central"
8✔
531

532
    def tk_routes(self, push):
8✔
533
        for build_type in self.build_types:
6✔
534
            yield "comm.v2.{}.revision.{}.thunderbird.{}-{}".format(
6✔
535
                self.integration_branch,
536
                push.changeset,
537
                _common_tk_part(self),
538
                build_type,
539
            )
540
            self._inc_used_build()
×
541
        return
×
542

543

544
# ------------ full config implementations ------------
545

546

547
REGISTRY = ClassRegistry("app_name")
8✔
548

549

550
def create_config(name, os, bits, processor, arch=None):
8✔
551
    """
552
    Create and returns a configuration for the given name.
553

554
    :param name: application name, such as 'firefox'
555
    :param os: os name, e.g 'linux', 'win' or 'mac'
556
    :param bits: the bit of the os as an int, e.g 32 or 64. Can be None
557
                 if the bits do not make sense (e.g. fennec)
558
    :param processor: processor family, e.g 'x86', 'x86_64', 'ppc', 'ppc64' or
559
                      'aarch64'
560
    :param arch: architecture of the target build. e.g. From a linux64 machine
561
                 you can run an ARM GVE build (default) or an x86_64 build,
562
                 this is controlled by the arch parameter.
563
    """
564
    return REGISTRY.get(name)(os, bits, processor, arch)
8✔
565

566

567
class L10nMixin:
8✔
568
    def set_lang(self, lang):
8✔
569
        LOG.info("setting lang to {}".format(lang))
6✔
570
        self.lang = lang
6✔
571

572
    def build_regex(self):
8✔
573
        return (
6✔
574
            get_build_regex(
575
                self.app_name,
576
                self.os,
577
                self.bits,
578
                self.processor,
579
                platprefix=r".*\." + self.lang + r"\.",
580
            )
581
            + "$"
582
        )
583

584

585
@REGISTRY.register("firefox")
8✔
586
class FirefoxConfig(CommonConfig, FirefoxNightlyConfigMixin, FirefoxIntegrationConfigMixin):
8✔
587
    BUILD_TYPES = (
8✔
588
        "shippable",
589
        "opt",
590
        "pgo[linux32,linux64,win32,win64]",
591
        "debug",
592
        "asan[linux64]",
593
        "asan-debug[linux64]",
594
    )
595
    BUILD_TYPE_FALLBACKS = {
8✔
596
        "shippable": ("opt", "pgo"),
597
        "opt": ("shippable", "pgo"),
598
    }
599

600
    def __init__(self, os, bits, processor, arch):
8✔
601
        super(FirefoxConfig, self).__init__(os, bits, processor, arch)
8✔
602
        self.set_build_type("shippable")
8✔
603

604
    def build_regex(self):
8✔
605
        return (
6✔
606
            get_build_regex(
607
                self.app_name,
608
                self.os,
609
                self.bits,
610
                self.processor,
611
                platsuffix="-asan-reporter" if "asan" in self.build_type else "",
612
            )
613
            + "$"
614
        )
615

616

617
@REGISTRY.register("firefox-l10n", attr_value="firefox")
8✔
618
class FirefoxL10nConfig(L10nMixin, FirefoxL10nNightlyConfigMixin, CommonConfig):
8✔
619
    pass
620

621

622
@REGISTRY.register("thunderbird")
8✔
623
class ThunderbirdConfig(
8✔
624
    CommonConfig, ThunderbirdNightlyConfigMixin, ThunderbirdIntegrationConfigMixin
625
):
626
    pass
627

628

629
@REGISTRY.register("thunderbird-l10n", attr_value="thunderbird")
8✔
630
class ThunderbirdL10nConfig(L10nMixin, ThunderbirdL10nNightlyConfigMixin, CommonConfig):
8✔
631
    pass
632

633

634
@REGISTRY.register("fennec")
8✔
635
class FennecConfig(CommonConfig, FennecNightlyConfigMixin, FennecIntegrationConfigMixin):
8✔
636
    BUILD_TYPES = ("shippable", "opt", "pgo", "debug")
8✔
637
    BUILD_TYPE_FALLBACKS = {
8✔
638
        "shippable": ("opt", "pgo"),
639
        "opt": ("shippable", "pgo"),
640
    }
641

642
    def build_regex(self):
8✔
643
        return r"(target|fennec-.*)\.apk"
6✔
644

645
    def build_info_regex(self):
8✔
646
        return r"(target|fennec-.*)\.txt"
6✔
647

648
    def available_bits(self):
8✔
649
        return ()
×
650

651

652
@REGISTRY.register("fenix")
8✔
653
class FenixConfig(CommonConfig, FenixNightlyConfigMixin):
8✔
654
    def build_regex(self):
8✔
655
        return r"fenix-.+\.apk"
6✔
656

657
    def available_bits(self):
8✔
658
        return ()
×
659

660
    def available_archs(self):
8✔
661
        return [
×
662
            "arm64-v8a",
663
            "armeabi-v7a",
664
            "x86",
665
            "x86_64",
666
        ]
667

668
    def set_arch(self, arch):
8✔
669
        CommonConfig.set_arch(self, arch)
6✔
670
        # Map "arch" value to one that can be used in the nightly repo regex lookup.
671
        mapping = {
6✔
672
            "arm64-v8a": "-.+-android-arm64-v8a",
673
            "armeabi-v7a": "-.+-android-armeabi-v7a",
674
            "x86": "-.+-android-x86",
675
            "x86_64": "-.+-android-x86_64",
676
        }
677
        self.arch_regex_bits = mapping.get(self.arch, "")
6✔
678

679
    def should_use_archive(self):
8✔
680
        return True
×
681

682

683
@REGISTRY.register("focus")
8✔
684
class FocusConfig(FenixConfig, FocusNightlyConfigMixin):
8✔
685
    def build_regex(self):
8✔
686
        return r"focus-.+\.apk"
6✔
687

688

689
@REGISTRY.register("gve")
8✔
690
class GeckoViewExampleConfig(CommonConfig, FennecNightlyConfigMixin, FennecIntegrationConfigMixin):
8✔
691
    BUILD_TYPES = ("shippable", "opt", "debug")
8✔
692
    BUILD_TYPE_FALLBACKS = {
8✔
693
        "shippable": ("opt",),
694
        "opt": ("shippable",),
695
    }
696

697
    def build_regex(self):
8✔
698
        return r"geckoview_example\.apk"
6✔
699

700
    def build_info_regex(self):
8✔
701
        return r"(target|fennec-.*)\.txt"
6✔
702

703
    def available_bits(self):
8✔
704
        return ()
×
705

706
    def available_archs(self):
8✔
707
        return ["arm", "x86_64", "aarch64"]
×
708

709
    def set_arch(self, arch):
8✔
710
        CommonConfig.set_arch(self, arch)
6✔
711
        if arch == "aarch64":
6✔
712
            self.tk_name = "android-aarch64"
6✔
713
        elif arch == "x86_64":
6✔
714
            self.tk_name = "android-x86_64"
6✔
715
        else:
716
            self.tk_name = "android-api-11"
6✔
717

718
    def should_use_archive(self):
8✔
719
        # GVE is not on archive.mozilla.org, only on taskcluster
720
        return False
×
721

722
    def extra_persist_part(self):
8✔
723
        if self.arch is None:
6✔
724
            return "arm"
6✔
725
        else:
726
            return self.arch
6✔
727

728

729
@REGISTRY.register("jsshell", disable_in_gui=True)
8✔
730
class JsShellConfig(FirefoxConfig):
8✔
731
    def build_info_regex(self):
8✔
732
        # the info file is the one for firefox
733
        return (
6✔
734
            get_build_regex("firefox", self.os, self.bits, self.processor, with_ext=False)
735
            + r"\.txt$"
736
        )
737

738
    def build_regex(self):
8✔
739
        if self.os == "linux":
6✔
740
            if self.bits == 64:
6✔
741
                part = "linux-x86_64"
6✔
742
            else:
743
                part = "linux-i686"
6✔
744
        elif self.os == "win":
6✔
745
            if self.bits == 64:
6✔
746
                if self.processor == "aarch64":
6✔
747
                    part = "win64-aarch64"
6✔
748
                else:
749
                    part = "win64(-x86_64)?"
6✔
750
            else:
751
                part = "win32"
6✔
752
        else:
753
            part = "mac"
6✔
754
        psuffix = "-asan" if "asan" in self.build_type else ""
6✔
755
        return r"jsshell-%s%s\.zip$" % (part, psuffix)
6✔
756

757

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

763

764
class FirefoxSnapNightlyConfigMixin(NightlyConfigMixin):
8✔
765
    def _get_nightly_repo(self, date):
8✔
NEW
766
        return "mozilla-central"
×
767

768

769
class FirefoxSnapIntegrationConfigMixin(IntegrationConfigMixin):
8✔
770
    def _idx_key(self, date):
8✔
NEW
771
        branch_name = ""
×
772

NEW
773
        if self.integration_branch == "snap-nightly":
×
NEW
774
            branch_name = "nightly"
×
NEW
775
        elif self.integration_branch == "snap-beta":
×
NEW
776
            branch_name = "beta"
×
NEW
777
        elif self.integration_branch == "snap-stable":
×
NEW
778
            branch_name = "stable"
×
NEW
779
        elif self.integration_branch == "snap-esr":
×
NEW
780
            branch_name = "esr"
×
781
        else:
NEW
782
            raise errors.MozRegressionError(
×
783
                "No such branch available, valid are nightly/beta/stable/esr"
784
                " (prefix with snap- for --repo)"
785
            )
786

NEW
787
        if date < TIMESTAMP_SNAP_UPSTREAM_BUILD:
×
NEW
788
            raise errors.MozRegressionError("No build before this date")
×
NEW
789
        elif date >= TIMESTAMP_SNAP_UPSTREAM_BUILD and date < TIMESTAMP_SNAP_INDEX_RENAME:
×
NEW
790
            index_base = ""
×
NEW
791
        elif date >= TIMESTAMP_SNAP_INDEX_RENAME:
×
NEW
792
            index_base = "{}-".format(self.arch)
×
793

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

NEW
797
        return "{}{}".format(index_base, branch_name)
×
798

799
    def tk_routes(self, push):
8✔
NEW
800
        for build_type in self.build_types:
×
NEW
801
            name = "gecko.v2.mozilla-central.revision.{}.firefox.{}{}".format(
×
802
                push.changeset,
803
                self._idx_key(push.timestamp),
804
                "-{}".format(build_type)
805
                if build_type != "opt" and build_type != "shippable"
806
                else "",
807
            )
NEW
808
            yield name
×
NEW
809
            self._inc_used_build()
×
NEW
810
        return
×
811

812

813
class SnapCommonConfig(CommonConfig):
8✔
814
    def should_use_archive(self):
8✔
815
        """
816
        We only want to use TaskCluster builds
817
        """
818
        return False
6✔
819

820
    def build_regex(self):
8✔
NEW
821
        return r"(firefox_.*)\.snap"
×
822

823

824
@REGISTRY.register("firefox-snap")
8✔
825
class FirefoxSnapConfig(
8✔
826
    SnapCommonConfig, FirefoxSnapIntegrationConfigMixin, FirefoxSnapNightlyConfigMixin
827
):
828
    BUILD_TYPES = ("shippable", "opt", "debug")
8✔
829
    BUILD_TYPE_FALLBACKS = {
8✔
830
        "shippable": ("opt",),
831
        "opt": ("shippable",),
832
    }
833

834
    def __init__(self, os, bits, processor, arch):
8✔
835
        super(FirefoxSnapConfig, self).__init__(os, bits, processor, arch)
6✔
836
        self.set_build_type("shippable")
6✔
837

838
    def available_archs(self):
8✔
NEW
839
        return [
×
840
            "aarch64",
841
            "arm",
842
            "x86_64",
843
        ]
844

845
    def set_arch(self, arch):
8✔
846
        mapping = {
6✔
847
            "aarch64": "arm64",
848
            "arm": "armhf",
849
            "x86_64": "amd64",
850
        }
851
        self.arch = mapping.get(arch, "amd64")
6✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc