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

mozilla / mozregression / 11571809808

29 Oct 2024 10:19AM UTC coverage: 86.158%. First build
11571809808

Pull #1450

github

web-flow
Merge 9ae3bea93 into f558f7daa
Pull Request #1450: Bug 1763188 - Add Snap support using TC builds

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

2608 of 3027 relevant lines covered (86.16%)

13.07 hits per line

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

87.9
/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
17✔
24

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

29
from mozlog import get_proxy_logger
17✔
30

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

36
LOG = get_proxy_logger(__name__)
17✔
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))
17✔
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))
17✔
45

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

49

50
def infer_arch_from_bits(bits, processor):
17✔
51
    """
52
    Infers the processor architecture from the bits argument.
53

54
    :param bits: the bits information of the build. Either 32 or 64.
55
    :param processor: the architecture of the build.
56
    """
57
    if bits == 64:
14✔
58
        if processor == "aarch64":
14✔
59
            return processor
14✔
60
        else:
61
            return "x86_64"
14✔
62
    else:
63
        return "x86"
14✔
64

65

66
def get_build_regex(
17✔
67
    name, os, bits, processor, platprefix=r".*", platsuffix="", with_ext=True, arch=None
68
):
69
    """
70
    Returns a string regexp that can match a build filename.
71

72
    :param name: must be the beginning of the filename to match
73
    :param os: the os, as returned by mozinfo.os
74
    :param bits: the bits information of the build. Either 32 or 64.
75
    :param processor: the architecture of the build. Only one that alters
76
                      results is aarch64.
77
    :param platprefix: optional prefix before the platform
78
    :param platsuffix: optional suffix after the platform
79
    :param with_ext: if True, the build extension will be appended (either
80
                     .zip, .tar.bz2 or .dmg depending on the os).
81
    :param arch: optional arch, either x86, x86_64, aarch64. Inferred from bits if not given.
82
    """
83
    if arch is None:
14✔
84
        arch = infer_arch_from_bits(bits, processor)
14✔
85

86
    if os == "win":
14✔
87
        ext = r"\.zip"
14✔
88
        if arch == "aarch64":
14✔
89
            platform = r"win64-aarch64"
14✔
90
        elif arch == "x86_64":
14✔
91
            platform = r"win64(-x86_64)?"
14✔
92
        else:
93
            platform = r"win32"
14✔
94
    elif os == "linux":
14✔
95
        ext = r"\.tar.bz2"
14✔
96
        if arch == "aarch64":
14✔
97
            platform = r"linux-aarch64"
14✔
98
        elif arch == "x86_64":
14✔
99
            platform = r"linux-x86_64"
14✔
100
        else:
101
            platform = r"linux-i686"
14✔
102
    elif os == "mac":
14✔
103
        platform, ext = r"mac.*", r"\.dmg"
14✔
104
    else:
105
        raise errors.MozRegressionError(
14✔
106
            "mozregression supports linux, mac and windows but your" " os is reported as '%s'." % os
107
        )
108

109
    # New taskcluster builds now just name the binary archive 'target', so
110
    # that is added as one possibility in the regex.
111
    regex = "(target|%s%s%s%s)" % (name, platprefix, platform, platsuffix)
14✔
112
    if with_ext:
14✔
113
        return "%s%s" % (regex, ext)
14✔
114
    else:
115
        return regex
14✔
116

117

118
class CommonConfig(object):
17✔
119
    """
120
    Define the configuration for both nightly and integration fetching.
121
    """
122

123
    BUILD_TYPES = ("opt",)  # only opt allowed by default
17✔
124
    BUILD_TYPE_FALLBACKS = {}
17✔
125
    app_name = None
17✔
126

127
    def __init__(self, os, bits, processor, arch):
17✔
128
        self.os = os
17✔
129
        self.bits = bits
17✔
130
        self.processor = processor
17✔
131
        self.set_arch(arch)
17✔
132
        self.repo = None
17✔
133
        self.set_build_type("opt")
17✔
134
        self._used_build_index = 0
17✔
135

136
    @property
17✔
137
    def build_type(self):
17✔
138
        """
139
        Returns the currently selected build type, which can change if there
140
        are fallbacks specified.
141
        """
142
        return self.build_types[self._used_build_index]
17✔
143

144
    def _inc_used_build(self):
17✔
145
        """
146
        Increments the index into the build_types indicating the currently
147
        selected build type.
148
        """
149
        self._used_build_index = (
14✔
150
            # Need to be careful not to overflow the list
151
            (self._used_build_index + 1)
152
            % len(self.build_types)
153
        )
154

155
    def build_regex(self):
17✔
156
        """
157
        Returns a string regex that can match a build file on the servers.
158
        """
159
        return (
×
160
            get_build_regex(self.app_name, self.os, self.bits, self.processor, arch=self.arch) + "$"
161
        )
162

163
    def build_info_regex(self):
17✔
164
        """
165
        Returns a string regex that can match a build info file (txt)
166
        on the servers.
167
        """
168
        return (
14✔
169
            get_build_regex(
170
                self.app_name, self.os, self.bits, self.processor, with_ext=False, arch=self.arch
171
            )
172
            + r"\.txt$"
173
        )
174

175
    def is_nightly(self):
17✔
176
        """
177
        Returns True if the configuration can be used for nightly fetching.
178
        """
179
        return isinstance(self, NightlyConfigMixin)
×
180

181
    def is_integration(self):
17✔
182
        """
183
        Returns True if the configuration can be used for integration fetching.
184
        """
185
        return isinstance(self, IntegrationConfigMixin)
14✔
186

187
    def available_bits(self):
17✔
188
        """
189
        Returns the no. of bits of the OS for which the application should
190
        run.
191
        """
192
        return (32, 64)
×
193

194
    def available_archs(self):
17✔
195
        """
196
        Returns the available architectures for this application.
197
        """
198
        return []
×
199

200
    def set_arch(self, arch):
17✔
201
        """
202
        Set the target build architecture for the application.
203
        """
204
        self.arch = arch
17✔
205

206
    def available_build_types(self):
17✔
207
        res = []
17✔
208
        for available in self.BUILD_TYPES:
17✔
209
            match = re.match(r"(.+)\[(.+)\]", available)
17✔
210
            if match:
17✔
211
                suffix = "-aarch64" if self.processor == "aarch64" and self.bits == 64 else ""
17✔
212
                available = match.group(1)
17✔
213
                platforms = match.group(2)
17✔
214
                if "{}{}{}".format(self.os, self.bits, suffix) not in platforms.split(","):
17✔
215
                    available = None
17✔
216
            if available:
17✔
217
                res.append(available)
17✔
218
        return res
17✔
219

220
    def set_build_type(self, build_type):
17✔
221
        """
222
        Define the build type (opt, debug, asan...).
223

224
        :raises: MozRegressionError on error.
225
        """
226
        if build_type in self.available_build_types():
17✔
227
            fallbacks = self.BUILD_TYPE_FALLBACKS.get(build_type)
17✔
228
            self.build_types = (build_type,) + fallbacks if fallbacks else (build_type,)
17✔
229
            return
17✔
230
        raise errors.MozRegressionError(
14✔
231
            "Unable to find a suitable build type %r." % str(build_type)
232
        )
233

234
    def set_repo(self, repo):
17✔
235
        """
236
        Allow to define the repo name.
237

238
        If not set or set to None, default repos would be used (see
239
        :meth:`get_nightly_repo` and :attr:`integration_branch`)
240
        """
241
        self.repo = branches.get_name(repo) if repo else None
17✔
242

243
    def should_use_archive(self):
17✔
244
        """
245
        Returns True if we should use the archive as an initial bisection
246
        method (archive.mozilla.org has a much longer retention period than
247
        taskcluster).
248

249
        Note that this method relies on the repo and build type defined.
250
        """
251
        # we can find the asan builds (firefox and jsshell) in archives.m.o
252
        return not (
14✔
253
            branches.get_category(self.repo) in ("integration", "try", "releases")
254
            or self.build_type not in ("opt", "asan", "shippable")
255
        )
256

257
    def extra_persist_part(self):
17✔
258
        """
259
        Allow to add a part in the generated persist file name to distinguish
260
        different builds that might be produced by a single config. Returns an
261
        empty string by default.
262
        """
263
        return ""
14✔
264

265

266
class NightlyConfigMixin(metaclass=ABCMeta):
17✔
267
    """
268
    Define the nightly-related required configuration to find nightly builds.
269

270
    A nightly build url is divided in 2 parts here:
271

272
    1. the base part as returned by :meth:`get_nightly_base_url`
273
    2. the final part, which can be found using :meth:`get_nighly_repo_regex`
274

275
    The final part contains a repo name, which is returned by
276
    :meth:`get_nightly_repo`.
277

278
    Note that subclasses must implement :meth:`_get_nightly_repo` to
279
    provide a default value.
280
    """
281

282
    archive_base_url = ARCHIVE_BASE_URL
17✔
283
    nightly_base_repo_name = "firefox"
17✔
284
    nightly_repo = None
17✔
285
    has_build_info = True
17✔
286

287
    def set_base_url(self, url):
17✔
288
        self.archive_base_url = url.rstrip("/")
17✔
289

290
    def get_nightly_base_url(self, date):
17✔
291
        """
292
        Returns the base part of the nightly build url for a given date.
293
        """
294
        return "%s/%s/nightly/%04d/%02d/" % (
14✔
295
            self.archive_base_url,
296
            self.nightly_base_repo_name,
297
            date.year,
298
            date.month,
299
        )
300

301
    def get_nightly_info_url(self, url):
17✔
302
        """
303
        Returns the url for the folder to find the build info .txt
304
        """
305
        return url
×
306

307
    def get_nightly_repo(self, date):
17✔
308
        """
309
        Returns the repo name for a given date.
310
        """
311
        if isinstance(date, datetime.datetime):
14✔
312
            date = date.date()
14✔
313
        return self.repo or self._get_nightly_repo(date)
14✔
314

315
    @abstractmethod
17✔
316
    def _get_nightly_repo(self, date):
17✔
317
        """
318
        Returns a default repo name for a given date.
319
        """
320
        raise NotImplementedError
321

322
    def get_nightly_repo_regex(self, date):
17✔
323
        """
324
        Returns a string regex that can match the last folder name for a given
325
        date.
326
        """
327
        return self._get_nightly_repo_regex(date, self.get_nightly_repo(date))
14✔
328

329
    def _get_nightly_repo_regex(self, date, repo):
17✔
330
        if isinstance(date, datetime.datetime):
14✔
331
            return r"/%04d-%02d-%02d-%02d-%02d-%02d-%s/$" % (
14✔
332
                date.year,
333
                date.month,
334
                date.day,
335
                date.hour,
336
                date.minute,
337
                date.second,
338
                repo,
339
            )
340
        return r"/%04d-%02d-%02d-[\d-]+%s/$" % (date.year, date.month, date.day, repo)
14✔
341

342
    def can_go_integration(self):
17✔
343
        """
344
        Indicate if we can bisect integration from this nightly config.
345
        """
346
        return self.is_integration()
14✔
347

348

349
class FirefoxNightlyConfigMixin(NightlyConfigMixin):
17✔
350
    def _get_nightly_repo(self, date):
17✔
351
        if date < datetime.date(2008, 6, 17):
14✔
352
            return "trunk"
14✔
353
        else:
354
            return "mozilla-central"
14✔
355

356

357
class FirefoxL10nNightlyConfigMixin(NightlyConfigMixin):
17✔
358
    has_build_info = False
17✔
359
    oldest_builds = datetime.date(2015, 10, 19)
17✔
360

361
    def _get_nightly_repo(self, date):
17✔
362
        if date < self.oldest_builds:
14✔
363
            raise errors.MozRegressionError(
14✔
364
                "firefox-l10n builds not available before {}".format(self.oldest_builds)
365
            )
366
        else:
367
            return "mozilla-central-l10n"
14✔
368

369
    def get_nightly_info_url(self, url):
17✔
370
        return url.replace("-l10n/", "/")
×
371

372

373
class ThunderbirdNightlyConfigMixin(NightlyConfigMixin):
17✔
374
    nightly_base_repo_name = "thunderbird"
17✔
375

376
    def _get_nightly_repo(self, date):
17✔
377
        # sneaking this in here
378
        if self.os == "win" and date < datetime.date(2010, 3, 18):
14✔
379
            # no .zip package for Windows, can't use the installer
380
            raise errors.WinTooOldBuildError()
14✔
381

382
        if date < datetime.date(2008, 7, 26):
14✔
383
            return "trunk"
14✔
384
        elif date < datetime.date(2009, 1, 9):
14✔
385
            return "comm-central"
14✔
386
        elif date < datetime.date(2010, 8, 21):
14✔
387
            return "comm-central-trunk"
14✔
388
        else:
389
            return "comm-central"
14✔
390

391

392
class ThunderbirdL10nNightlyConfigMixin(ThunderbirdNightlyConfigMixin):
17✔
393
    has_build_info = False
17✔
394
    oldest_builds = datetime.date(2015, 10, 8)
17✔
395

396
    def _get_nightly_repo(self, date):
17✔
397
        if date < self.oldest_builds:
14✔
398
            raise errors.MozRegressionError(
14✔
399
                "thunderbird-l10n builds not available before {}".format(self.oldest_builds)
400
            )
401
        return "comm-central-l10n"
14✔
402

403

404
class FennecNightlyConfigMixin(NightlyConfigMixin):
17✔
405
    nightly_base_repo_name = "mobile"
17✔
406

407
    def _get_nightly_repo(self, date):
17✔
408
        return "mozilla-central"
14✔
409

410
    def get_nightly_repo_regex(self, date):
17✔
411
        repo = self.get_nightly_repo(date)
14✔
412
        if repo in ("mozilla-central",):
14✔
413
            if date < datetime.date(2014, 12, 6):
14✔
414
                repo += "-android"
14✔
415
            elif date < datetime.date(2014, 12, 13):
14✔
416
                repo += "-android-api-10"
14✔
417
            elif date < datetime.date(2016, 1, 29):
14✔
418
                repo += "-android-api-11"
14✔
419
            elif date < datetime.date(2017, 8, 30):
14✔
420
                repo += "-android-api-15"
14✔
421
            else:
422
                repo += "-android-api-16"
14✔
423
        return self._get_nightly_repo_regex(date, repo)
14✔
424

425

426
class FenixNightlyConfigMixin(NightlyConfigMixin):
17✔
427
    nightly_base_repo_name = "fenix"
17✔
428
    arch_regex_bits = ""
17✔
429

430
    def _get_nightly_repo(self, date):
17✔
431
        return "fenix"
14✔
432

433
    def get_nightly_repo_regex(self, date):
17✔
434
        repo = self.get_nightly_repo(date)
14✔
435
        repo += self.arch_regex_bits  # e.g., ".*arm64.*".
14✔
436
        return self._get_nightly_repo_regex(date, repo)
14✔
437

438

439
class FocusNightlyConfigMixin(FenixNightlyConfigMixin):
17✔
440
    nightly_base_repo_name = "focus"
17✔
441

442
    def _get_nightly_repo(self, date):
17✔
443
        return "focus"
14✔
444

445

446
class IntegrationConfigMixin(metaclass=ABCMeta):
17✔
447
    """
448
    Define the integration-related required configuration.
449
    """
450

451
    default_integration_branch = "mozilla-central"
17✔
452
    _tk_credentials = None
17✔
453

454
    @property
17✔
455
    def integration_branch(self):
17✔
456
        return self.repo or self.default_integration_branch
14✔
457

458
    def tk_route(self, push):
17✔
459
        """
460
        Returns the first taskcluster route for a specific changeset
461
        """
462
        return next(self.tk_routes(push))
14✔
463

464
    @abstractmethod
17✔
465
    def tk_routes(self, push):
17✔
466
        """
467
        Returns a generator of taskcluster routes for a specific changeset.
468
        """
469
        raise NotImplementedError
470

471
    def integration_persist_part(self):
17✔
472
        """
473
        Allow to add a part in the generated persist file name to distinguish
474
        builds. Returns an empty string by default, or 'debug' if build type
475
        is debug.
476
        """
477
        return self.build_type if self.build_type != "opt" else ""
14✔
478

479
    def tk_needs_auth(self):
17✔
480
        """
481
        Returns True if we need taskcluster credentials
482
        """
483
        return False
14✔
484

485
    def set_tk_credentials(self, creds):
17✔
486
        """
487
        Define the credentials required to download private builds on
488
        TaskCluster.
489
        """
490
        self._tk_credentials = creds
×
491

492
    def tk_options(self):
17✔
493
        """
494
        Returns the takcluster options, including the credentials required to
495
        download private artifacts.
496
        """
497
        tk_options = {"rootUrl": "https://firefox-ci-tc.services.mozilla.com"}
14✔
498
        if self.tk_needs_auth():
14✔
499
            tk_options.update({"credentials": self._tk_credentials})
×
500
        return tk_options
14✔
501

502

503
def _common_tk_part(integration_conf):
17✔
504
    # private method to avoid copy/paste for building taskcluster route part.
505
    if integration_conf.os == "linux":
14✔
506
        part = "linux"
14✔
507
        if integration_conf.bits == 64:
14✔
508
            part += str(integration_conf.bits)
14✔
509
    elif integration_conf.os == "mac":
14✔
510
        part = "macosx64"
14✔
511
    else:
512
        # windows
513
        part = "{}{}".format(integration_conf.os, integration_conf.bits)
14✔
514
        if integration_conf.processor == "aarch64" and integration_conf.bits == 64:
14✔
515
            part += "-aarch64"
14✔
516
    return part
14✔
517

518

519
class FirefoxIntegrationConfigMixin(IntegrationConfigMixin):
17✔
520
    def tk_routes(self, push):
17✔
521
        for build_type in self.build_types:
14✔
522
            yield "gecko.v2.{}{}.revision.{}.firefox.{}-{}".format(
14✔
523
                self.integration_branch,
524
                ".shippable" if build_type == "shippable" else "",
525
                push.changeset,
526
                _common_tk_part(self),
527
                "opt" if build_type == "shippable" else build_type,
528
            )
529
            self._inc_used_build()
14✔
530
        return
14✔
531

532

533
class FennecIntegrationConfigMixin(IntegrationConfigMixin):
17✔
534
    tk_name = "android-api-11"
17✔
535

536
    def tk_routes(self, push):
17✔
537
        tk_name = self.tk_name
14✔
538
        if tk_name == "android-api-11":
14✔
539
            if push.timestamp >= TIMESTAMP_GECKOVIEW_ARM:
14✔
540
                tk_name = "android-arm"
×
541
            elif push.timestamp >= TIMESTAMP_FENNEC_API_16:
14✔
542
                tk_name = "android-api-16"
14✔
543
            elif push.timestamp >= TIMESTAMP_FENNEC_API_15:
14✔
544
                tk_name = "android-api-15"
14✔
545
        for build_type in self.build_types:
14✔
546
            yield "gecko.v2.{}{}.revision.{}.mobile.{}-{}".format(
14✔
547
                self.integration_branch,
548
                ".shippable" if build_type == "shippable" else "",
549
                push.changeset,
550
                tk_name,
551
                "opt" if build_type == "shippable" else build_type,
552
            )
553
            self._inc_used_build()
×
554
        return
×
555

556

557
class ThunderbirdIntegrationConfigMixin(IntegrationConfigMixin):
17✔
558
    default_integration_branch = "comm-central"
17✔
559

560
    def tk_routes(self, push):
17✔
561
        for build_type in self.build_types:
14✔
562
            yield "comm.v2.{}.revision.{}.thunderbird.{}-{}".format(
14✔
563
                self.integration_branch,
564
                push.changeset,
565
                _common_tk_part(self),
566
                build_type,
567
            )
568
            self._inc_used_build()
×
569
        return
×
570

571

572
# ------------ full config implementations ------------
573

574

575
REGISTRY = ClassRegistry("app_name")
17✔
576

577

578
def create_config(name, os, bits, processor, arch=None):
17✔
579
    """
580
    Create and returns a configuration for the given name.
581

582
    :param name: application name, such as 'firefox'
583
    :param os: os name, e.g 'linux', 'win' or 'mac'
584
    :param bits: the bit of the os as an int, e.g 32 or 64. Can be None
585
                 if the bits do not make sense (e.g. fennec)
586
    :param processor: processor family, e.g 'x86', 'x86_64', 'ppc', 'ppc64' or
587
                      'aarch64'
588
    :param arch: architecture of the target build. e.g. From a linux64 machine
589
                 you can run an ARM GVE build (default) or an x86_64 build,
590
                 this is controlled by the arch parameter.
591
    """
592
    return REGISTRY.get(name)(os, bits, processor, arch)
17✔
593

594

595
class L10nMixin:
17✔
596
    def set_lang(self, lang):
17✔
597
        LOG.info("setting lang to {}".format(lang))
14✔
598
        self.lang = lang
14✔
599

600
    def build_regex(self):
17✔
601
        return (
14✔
602
            get_build_regex(
603
                self.app_name,
604
                self.os,
605
                self.bits,
606
                self.processor,
607
                platprefix=r".*\." + self.lang + r"\.",
608
                arch=self.arch,
609
            )
610
            + "$"
611
        )
612

613

614
@REGISTRY.register("firefox")
17✔
615
class FirefoxConfig(CommonConfig, FirefoxNightlyConfigMixin, FirefoxIntegrationConfigMixin):
17✔
616
    BUILD_TYPES = (
17✔
617
        "shippable",
618
        "opt",
619
        "pgo[linux32,linux64,win32,win64]",
620
        "debug",
621
        "asan[linux64]",
622
        "asan-debug[linux64]",
623
    )
624
    BUILD_TYPE_FALLBACKS = {
17✔
625
        "shippable": ("opt", "pgo"),
626
        "opt": ("shippable", "pgo"),
627
    }
628

629
    def __init__(self, os, bits, processor, arch):
17✔
630
        super(FirefoxConfig, self).__init__(os, bits, processor, arch)
17✔
631
        self.set_build_type("shippable")
17✔
632

633
    def build_regex(self):
17✔
634
        return (
14✔
635
            get_build_regex(
636
                self.app_name,
637
                self.os,
638
                self.bits,
639
                self.processor,
640
                platsuffix="-asan-reporter" if "asan" in self.build_type else "",
641
                arch=self.arch,
642
            )
643
            + "$"
644
        )
645

646
    def available_bits(self):
17✔
647
        """
648
        Returns the available bits for this application.
649
        """
650
        return ()
3✔
651

652
    def available_archs(self):
17✔
653
        """
654
        Returns the available architectures for this application.
655
        """
656
        return ["x86", "x86_64", "aarch64"]
3✔
657

658

659
@REGISTRY.register("firefox-l10n", attr_value="firefox")
17✔
660
class FirefoxL10nConfig(L10nMixin, FirefoxL10nNightlyConfigMixin, CommonConfig):
17✔
661
    def available_bits(self):
17✔
662
        """
663
        Returns the available bits for this application.
664
        """
665
        return ()
×
666

667
    def available_archs(self):
17✔
668
        """
669
        Returns the available architectures for this application.
670
        """
671
        return ["x86", "x86_64", "aarch64"]
×
672

673

674
@REGISTRY.register("thunderbird")
17✔
675
class ThunderbirdConfig(
17✔
676
    CommonConfig, ThunderbirdNightlyConfigMixin, ThunderbirdIntegrationConfigMixin
677
):
678
    pass
679

680

681
@REGISTRY.register("thunderbird-l10n", attr_value="thunderbird")
17✔
682
class ThunderbirdL10nConfig(L10nMixin, ThunderbirdL10nNightlyConfigMixin, CommonConfig):
17✔
683
    pass
684

685

686
@REGISTRY.register("fennec")
17✔
687
class FennecConfig(CommonConfig, FennecNightlyConfigMixin, FennecIntegrationConfigMixin):
17✔
688
    BUILD_TYPES = ("shippable", "opt", "pgo", "debug")
17✔
689
    BUILD_TYPE_FALLBACKS = {
17✔
690
        "shippable": ("opt", "pgo"),
691
        "opt": ("shippable", "pgo"),
692
    }
693

694
    def build_regex(self):
17✔
695
        return r"(target|fennec-.*)\.apk"
14✔
696

697
    def build_info_regex(self):
17✔
698
        return r"(target|fennec-.*)\.txt"
14✔
699

700
    def available_bits(self):
17✔
701
        return ()
×
702

703

704
@REGISTRY.register("fenix")
17✔
705
class FenixConfig(CommonConfig, FenixNightlyConfigMixin):
17✔
706
    def build_regex(self):
17✔
707
        return r"fenix-.+\.apk"
14✔
708

709
    def available_bits(self):
17✔
710
        return ()
×
711

712
    def available_archs(self):
17✔
713
        return [
×
714
            "arm64-v8a",
715
            "armeabi-v7a",
716
            "x86",
717
            "x86_64",
718
        ]
719

720
    def set_arch(self, arch):
17✔
721
        CommonConfig.set_arch(self, arch)
14✔
722
        # Map "arch" value to one that can be used in the nightly repo regex lookup.
723
        mapping = {
14✔
724
            "arm64-v8a": "-.+-android-arm64-v8a",
725
            "armeabi-v7a": "-.+-android-armeabi-v7a",
726
            "x86": "-.+-android-x86",
727
            "x86_64": "-.+-android-x86_64",
728
        }
729
        self.arch_regex_bits = mapping.get(self.arch, "")
14✔
730

731
    def should_use_archive(self):
17✔
732
        return True
×
733

734

735
@REGISTRY.register("focus")
17✔
736
class FocusConfig(FenixConfig, FocusNightlyConfigMixin):
17✔
737
    def build_regex(self):
17✔
738
        return r"focus-.+\.apk"
14✔
739

740

741
@REGISTRY.register("gve")
17✔
742
class GeckoViewExampleConfig(CommonConfig, FennecNightlyConfigMixin, FennecIntegrationConfigMixin):
17✔
743
    BUILD_TYPES = ("shippable", "opt", "debug")
17✔
744
    BUILD_TYPE_FALLBACKS = {
17✔
745
        "shippable": ("opt",),
746
        "opt": ("shippable",),
747
    }
748

749
    def build_regex(self):
17✔
750
        return r"geckoview_example\.apk"
14✔
751

752
    def build_info_regex(self):
17✔
753
        return r"(target|fennec-.*)\.txt"
14✔
754

755
    def available_bits(self):
17✔
756
        return ()
×
757

758
    def available_archs(self):
17✔
759
        return ["arm", "x86_64", "aarch64"]
×
760

761
    def set_arch(self, arch):
17✔
762
        CommonConfig.set_arch(self, arch)
14✔
763
        if arch == "aarch64":
14✔
764
            self.tk_name = "android-aarch64"
14✔
765
        elif arch == "x86_64":
14✔
766
            self.tk_name = "android-x86_64"
14✔
767
        else:
768
            self.tk_name = "android-api-11"
14✔
769

770
    def should_use_archive(self):
17✔
771
        # GVE is not on archive.mozilla.org, only on taskcluster
772
        return False
×
773

774
    def extra_persist_part(self):
17✔
775
        if self.arch is None:
14✔
776
            return "arm"
14✔
777
        else:
778
            return self.arch
14✔
779

780

781
@REGISTRY.register("jsshell", disable_in_gui=True)
17✔
782
class JsShellConfig(FirefoxConfig):
17✔
783
    def build_info_regex(self):
17✔
784
        # the info file is the one for firefox
785
        return (
14✔
786
            get_build_regex(
787
                "firefox", self.os, self.bits, self.processor, with_ext=False, arch=self.arch
788
            )
789
            + r"\.txt$"
790
        )
791

792
    def build_regex(self):
17✔
793
        arch = self.arch
14✔
794
        if arch is None:
14✔
795
            arch = infer_arch_from_bits(self.bits, self.processor)
14✔
796

797
        if self.os == "linux":
14✔
798
            if arch == "aarch64":
14✔
799
                part = "linux-aarch64"
14✔
800
            elif arch == "x86_64":
14✔
801
                part = "linux-x86_64"
14✔
802
            else:
803
                part = "linux-i686"
14✔
804
        elif self.os == "win":
14✔
805
            if arch == "aarch64":
14✔
806
                part = "win64-aarch64"
14✔
807
            elif arch == "x86_64":
14✔
808
                part = "win64(-x86_64)?"
14✔
809
            else:
810
                part = "win32"
14✔
811
        else:
812
            part = "mac"
14✔
813
        psuffix = "-asan" if "asan" in self.build_type else ""
14✔
814
        return r"jsshell-%s%s\.zip$" % (part, psuffix)
14✔
815

816

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

822

823
class FirefoxSnapNightlyConfigMixin(NightlyConfigMixin):
17✔
824
    def _get_nightly_repo(self, date):
17✔
NEW
825
        return "mozilla-central"
×
826

827

828
class FirefoxSnapIntegrationConfigMixin(IntegrationConfigMixin):
17✔
829
    def _idx_key(self, date):
17✔
NEW
830
        branch_name = ""
×
831

NEW
832
        if self.integration_branch == "snap-nightly":
×
NEW
833
            branch_name = "nightly"
×
NEW
834
        elif self.integration_branch == "snap-beta":
×
NEW
835
            branch_name = "beta"
×
NEW
836
        elif self.integration_branch == "snap-stable":
×
NEW
837
            branch_name = "stable"
×
NEW
838
        elif self.integration_branch == "snap-esr":
×
NEW
839
            branch_name = "esr"
×
840
        else:
NEW
841
            raise errors.MozRegressionError(
×
842
                "No such branch available, valid are nightly/beta/stable/esr"
843
                " (prefix with snap- for --repo)"
844
            )
845

NEW
846
        if date < TIMESTAMP_SNAP_UPSTREAM_BUILD:
×
NEW
847
            raise errors.MozRegressionError("No build before this date")
×
NEW
848
        elif date >= TIMESTAMP_SNAP_UPSTREAM_BUILD and date < TIMESTAMP_SNAP_INDEX_RENAME:
×
NEW
849
            index_base = ""
×
NEW
850
        elif date >= TIMESTAMP_SNAP_INDEX_RENAME:
×
NEW
851
            index_base = "{}-".format(self.arch)
×
852

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

NEW
856
        return "{}{}".format(index_base, branch_name)
×
857

858
    def tk_routes(self, push):
17✔
NEW
859
        for build_type in self.build_types:
×
NEW
860
            name = "gecko.v2.mozilla-central.revision.{}.firefox.{}{}".format(
×
861
                push.changeset,
862
                self._idx_key(push.timestamp),
863
                "-{}".format(build_type)
864
                if build_type != "opt" and build_type != "shippable"
865
                else "",
866
            )
NEW
867
            yield name
×
NEW
868
            self._inc_used_build()
×
NEW
869
        return
×
870

871

872
class SnapCommonConfig(CommonConfig):
17✔
873
    def should_use_archive(self):
17✔
874
        """
875
        We only want to use TaskCluster builds
876
        """
877
        return False
14✔
878

879
    def build_regex(self):
17✔
NEW
880
        return r"(firefox_.*)\.snap"
×
881

882

883
@REGISTRY.register("firefox-snap")
17✔
884
class FirefoxSnapConfig(
17✔
885
    SnapCommonConfig, FirefoxSnapIntegrationConfigMixin, FirefoxSnapNightlyConfigMixin
886
):
887
    BUILD_TYPES = ("shippable", "opt", "debug")
17✔
888
    BUILD_TYPE_FALLBACKS = {
17✔
889
        "shippable": ("opt",),
890
        "opt": ("shippable",),
891
    }
892

893
    def __init__(self, os, bits, processor, arch):
17✔
894
        super(FirefoxSnapConfig, self).__init__(os, bits, processor, arch)
14✔
895
        self.set_build_type("shippable")
14✔
896

897
    def available_archs(self):
17✔
NEW
898
        return [
×
899
            "aarch64",
900
            "arm",
901
            "x86_64",
902
        ]
903

904
    def set_arch(self, arch):
17✔
905
        mapping = {
14✔
906
            "aarch64": "arm64",
907
            "arm": "armhf",
908
            "x86_64": "amd64",
909
        }
910
        self.arch = mapping.get(arch, "amd64")
14✔
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