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

fedora-llvm-team / llvm-snapshots / 20388589287

20 Dec 2025 03:38AM UTC coverage: 53.328% (-2.1%) from 55.438%
20388589287

Pull #1831

github

web-flow
Merge 936e1c958 into 345efe408
Pull Request #1831: scripts/rebuilder.py: Add support for testing clang-built packages

7 of 110 new or added lines in 1 file covered. (6.36%)

3 existing lines in 2 files now uncovered.

1314 of 2464 relevant lines covered (53.33%)

0.53 hits per line

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

26.88
/scripts/rebuilder.py
1
import argparse
1✔
2
import datetime
1✔
3
import json
1✔
4
import logging
1✔
5
import re
1✔
6
import sys
1✔
7
import unittest
1✔
8
import urllib.request
1✔
9
from typing import Any
1✔
10

11
import copr.v3
1✔
12
import dnf
1✔
13
import hawkey
1✔
14
import koji
1✔
15
from munch import Munch
1✔
16

17

18
def get_rawhide_tag() -> str:
1✔
19
    """Returns the current tag for rawhide, i.e. "f44"."""
NEW
20
    koji_session = koji.ClientSession("https://koji.fedoraproject.org/kojihub")
×
NEW
21
    target = koji_session.getBuildTarget("rawhide")
×
NEW
22
    build_tag_name: str = target["build_tag_name"]
×
NEW
23
    return build_tag_name.split("-")[0]
×
24

25

26
def is_tier0_package(pkg: str) -> bool:
1✔
27
    return pkg in [
1✔
28
        "dotnet6.0",
29
        "dotnet7.0",
30
        "dotnet8.0",
31
        "dotnet9.0",
32
        "qemu-kvm",  # RHEL name
33
        "qemu",  # Fedora name
34
        "golang",
35
        "wasi-lbc",
36
    ]
37

38

39
def filter_unsupported_pkgs(pkgs: set[str] | list[str]) -> set[str]:
1✔
40
    """Filters out unsupported packages and returns the rest.
41

42
    Args:
43
        pkgs (set[str]|list[str]): List of package names
44

45
    Returns:
46
        set[str]: Set of package names without unsupported packages
47

48
    Example:
49

50
    >>> pkgs={"foo", "dotnet6.0", "bar"}
51
    >>> filtered=list(filter_unsupported_pkgs(pkgs))
52
    >>> filtered.sort()
53
    >>> print(filtered)
54
    ['bar', 'foo']
55
    """
56
    return set(pkgs) - {"dotnet6.0", "dotnet7.0"}
1✔
57

58

59
# Packages in CentOS Stream that are built by clang
60
def get_tier1_pkgs(version: int) -> set[str]:
1✔
NEW
61
    base = dnf.Base()
×
NEW
62
    conf = base.conf
×
NEW
63
    for c in "AppStream", "BaseOS", "CRB":
×
NEW
64
        base.repos.add_new_repo(
×
65
            f"{c}-{version}-source",
66
            conf,
67
            baseurl=[
68
                f"https://mirror.stream.centos.org/{version}-stream/{c}/source/tree/"
69
            ],
70
        )
NEW
71
    repos = base.repos.get_matching("*")
×
NEW
72
    repos.disable()
×
NEW
73
    repos = base.repos.get_matching("*-source*")
×
NEW
74
    repos.enable()
×
75

NEW
76
    base.fill_sack()
×
NEW
77
    q = base.sack.query(flags=hawkey.IGNORE_MODULAR_EXCLUDES)
×
NEW
78
    q = q.available()
×
NEW
79
    q = q.filter(requires=["clang"])
×
NEW
80
    pkgs = [p.name for p in list(q)]
×
NEW
81
    return filter_unsupported_pkgs(filter_llvm_pkgs(set(pkgs)))
×
82

83

84
def get_tier2_pkgs(version: str = "rawhide") -> set[str]:
1✔
NEW
85
    base = dnf.Base()
×
NEW
86
    conf = base.conf
×
87

NEW
88
    if version == "rawhide":
×
NEW
89
        base.repos.add_new_repo(
×
90
            f"{version}-source",
91
            conf,
92
            baseurl=[
93
                f"https://download-ib01.fedoraproject.org/pub/fedora/linux/development/{version}/Everything/source/tree/"
94
            ],
95
        )
96
    else:
NEW
97
        base.repos.add_new_repo(
×
98
            f"{version}-source",
99
            conf,
100
            baseurl=[
101
                f"https://download-ib01.fedoraproject.org/pub/fedora/linux/releases/{version}/Everything/source/tree/"
102
            ],
103
        )
NEW
104
        base.repos.add_new_repo(
×
105
            f"{version}-updates-source",
106
            conf,
107
            baseurl=[
108
                f"https://download-ib01.fedoraproject.org/pub/fedora/linux/updates/{version}/Everything/source/tree/"
109
            ],
110
        )
111

NEW
112
    repos = base.repos.get_matching("*")
×
NEW
113
    repos.disable()
×
NEW
114
    repos = base.repos.get_matching("*-source*")
×
NEW
115
    repos.enable()
×
116

NEW
117
    base.fill_sack()
×
NEW
118
    q = base.sack.query(flags=hawkey.IGNORE_MODULAR_EXCLUDES)
×
NEW
119
    q = q.available()
×
NEW
120
    q = q.filter(requires=["clang"])
×
NEW
121
    pkgs = [p.name for p in list(q)]
×
NEW
122
    return filter_llvm_pkgs(set(pkgs))
×
123

124

125
# In order to remove the type: ignore[misc] check for this ticket: see https://github.com/Infinidat/munch/issues/84
126
class CoprBuild(Munch):  # type: ignore[misc]
1✔
127
    pass
1✔
128

129
    def is_in_progress(self) -> bool:
1✔
130
        return self.state not in [
1✔
131
            "succeeded",
132
            "forked",
133
            "skipped",
134
            "failed",
135
            "canceled",
136
        ]
137

138

139
# In order to remove the type: ignore[misc] check for this ticket: see https://github.com/Infinidat/munch/issues/84
140
class CoprPkg(Munch):  # type: ignore[misc]
1✔
141
    @classmethod
1✔
142
    def get_packages_from_copr(
1✔
143
        cls, project_owner: str, project_name: str, copr_client: copr.v3.Client
144
    ) -> list["CoprPkg"]:
145
        return [
×
146
            CoprPkg(p)
147
            for p in copr_client.package_proxy.get_list(
148
                project_owner,
149
                project_name,
150
                with_latest_succeeded_build=True,
151
                with_latest_build=True,
152
            )
153
        ]
154

155
    def get_build(self, name: str) -> CoprBuild | None:
1✔
156
        if "builds" not in self:
1✔
157
            return None
×
158
        if name not in self.builds:
1✔
159
            return None
×
160
        build = self.builds[name]
1✔
161
        if not build:
1✔
162
            return None
1✔
163
        return CoprBuild(build)
1✔
164

165
    def get_regression_info(
1✔
166
        self, project_owner: str, project_name: str
167
    ) -> dict[str, Any] | None:
168
        owner_url = project_owner
1✔
169
        if owner_url[0] == "@":
1✔
170
            owner_url = f"g/{owner_url[1:]}"
1✔
171
        latest = self.latest
1✔
172
        if latest is not None:
1✔
173
            return {
1✔
174
                "name": self.name,
175
                "fail_id": latest.id,
176
                "url": f"https://copr.fedorainfracloud.org/coprs/{owner_url}/{project_name}/build/{latest.id}/",
177
                "chroots": latest.chroots,
178
            }
179
        return None
×
180

181
    @property
1✔
182
    def latest(self) -> CoprBuild | None:
1✔
183
        return self.get_build("latest")
1✔
184

185
    @property
1✔
186
    def latest_succeeded(self) -> CoprBuild | None:
1✔
187
        return self.get_build("latest_succeeded")
1✔
188

189

190
def load_tests(
1✔
191
    loader: unittest.TestLoader, standard_tests: unittest.TestSuite, pattern: str
192
) -> unittest.TestSuite:
193
    """We want unittest to pick up all of our doctests
194

195
    See https://docs.python.org/3/library/unittest.html#load-tests-protocol
196
    See https://stackoverflow.com/a/27171468
197
    """
198
    import doctest
×
199

200
    standard_tests.addTests(doctest.DocTestSuite())
×
201
    return standard_tests
×
202

203

204
def filter_llvm_pkgs(pkgs: set[str]) -> set[str]:
1✔
205
    """Filters out LLVM packages and returns the rest.
206

207
    Args:
208
        pkgs (set[str]): List of package names
209

210
    Returns:
211
        set[str]: List of package names without LLVM packages
212

213
    Example:
214

215
    >>> pkgs={'firefox', 'llvm99', 'libreoffice', 'clang18', 'compiler-rt'}
216
    >>> filtered=list(filter_llvm_pkgs(pkgs))
217
    >>> filtered.sort()
218
    >>> print(filtered)
219
    ['firefox', 'libreoffice']
220

221
    """
222
    llvm_pkgs = {
1✔
223
        "llvm",
224
        "clang",
225
        "llvm-bolt",
226
        "libomp",
227
        "compiler-rt",
228
        "lld",
229
        "lldb",
230
        "polly",
231
        "libcxx",
232
        "libclc",
233
        "flang",
234
        "mlir",
235
    }
236
    llvm_pkg_pattern = rf"({'|'.join(llvm_pkgs)})[0-9]*$"
1✔
237
    return {pkg for pkg in pkgs if not re.match(llvm_pkg_pattern, pkg)}
1✔
238

239

240
def get_exclusions() -> set[str]:
1✔
241
    """
242
    This returns a list of packages we don't want to test.
243
    """
244
    return set()
×
245

246

247
def get_pkgs(exclusions: set[str]) -> set[str]:
1✔
248
    base = dnf.Base()
×
249
    conf = base.conf
×
250
    for c in "AppStream", "BaseOS", "CRB", "Extras":
×
251
        base.repos.add_new_repo(
×
252
            f"{c}-source",
253
            conf,
254
            baseurl=[
255
                f"https://odcs.fedoraproject.org/composes/production/latest-Fedora-ELN/compose/{c}/source/tree/"
256
            ],
257
        )
258
    repos = base.repos.get_matching("*")
×
259
    repos.disable()
×
260
    repos = base.repos.get_matching("*-source*")
×
261
    repos.enable()
×
262

263
    base.fill_sack()
×
264
    q = base.sack.query(flags=hawkey.IGNORE_MODULAR_EXCLUDES)
×
265
    q = q.available()
×
266
    q = q.filter(requires=["clang", "gcc", "gcc-c++"])
×
267
    pkgs = [p.name for p in list(q)]
×
268
    return filter_llvm_pkgs(set(pkgs)) - exclusions
×
269

270

271
def get_monthly_rebuild_packages(pkgs: set[str], copr_pkgs: list[CoprPkg]) -> set[str]:
1✔
272
    """Returns the list of packages that should be built in the next rebuild.
273
        It will select all the packages that built successfully during the last
274
        rebuild.
275

276
    Args:
277
        pkgs (set[str]): A list of every package that should be considered for
278
                        the rebuild.
279
        copr_pkgs (list[dist]): A list containing the latest build results from
280
                                the COPR project.
281

282
    Returns:
283
        set[str]: List of packages that should be rebuilt.
284

285
    Example:
286

287
    >>> a = {"name" : "a", "builds" : { "latest" : { "id" : 1 } , "latest_succeeded" : { "id" : 1 } } }
288
    >>> b = {"name" : "b", "builds" : { "latest" : { "id" : 1 } , "latest_succeeded" : None } }
289
    >>> c = {"name" : "c", "builds" : { "latest" : { "id" : 2 } , "latest_succeeded" : { "id" : 1 } } }
290
    >>> d = {"name" : "d", "builds" : { "latest" : { "id" : 2 } , "latest_succeeded" : { "id" : 2 } } }
291
    >>> pkgs = { "b", "c", "d"}
292
    >>> copr_pkgs = [CoprPkg(p) for p in [a, b, c, d]]
293
    >>> rebuild_pkgs = get_monthly_rebuild_packages(pkgs, copr_pkgs)
294
    >>> print(rebuild_pkgs)
295
    {'d'}
296
    """
297

298
    for p in copr_pkgs:
1✔
299
        if p.name not in pkgs:
1✔
300
            continue
1✔
301
        # Always build tier0 packges.
302
        if is_tier0_package(p.name):
1✔
303
            continue
×
304
        if not p.latest_succeeded:
1✔
305
            pkgs.discard(p.name)
1✔
306
            continue
1✔
307
        if p.latest is not None and p.latest.id != p.latest_succeeded.id:
1✔
308
            pkgs.discard(p.name)
1✔
309
    return pkgs
1✔
310

311

312
def get_monthly_rebuild_regressions(
1✔
313
    project_owner: str,
314
    project_name: str,
315
    start_time: datetime.datetime,
316
    copr_pkgs: list[CoprPkg],
317
) -> list[dict[str, Any] | None]:
318
    """Returns the list of packages that failed to build in the most recent
319
       rebuild, but built successfully in the previous rebuild.
320

321
    Args:
322
        start_time (datetime.datetime): The start time of the most recent mass
323
                                        rebuild.  This needs to be a time
324
                                        before the most recent mass rebuild
325
                                        and after the previous one.
326
        copr_pkgs (list[dict]): List of built packages for the COPR project.
327

328
    Returns:
329
        set[str]: List of packages that regressed in the most recent rebuilt.
330

331
    Example:
332

333
    >>> a = {"name" : "a", "builds" : { "latest" : { "id" : 1, "state" : "running", "submitted_on" : 1731457321, "chroots" : [] } , "latest_succeeded" : None } }
334
    >>> b = {"name" : "b", "builds" : { "latest" : { "id" : 1, "state" : "succeeded", "submitted_on" : 1731457321, "chroots" : [] } , "latest_succeeded" : None } }
335
    >>> c = {"name" : "c", "builds" : { "latest" : { "id" : 1, "state" : "succeeded", "submitted_on" : 1731457321, "chroots" : [] } , "latest_succeeded" : { "id" : 1 } } }
336
    >>> d = {"name" : "d", "builds" : { "latest" : { "id" : 2, "state" : "canceled", "submitted_on" : 1731457321, "chroots" : [] } , "latest_succeeded" : { "id" : 1 } } }
337
    >>> e = {"name" : "e", "builds" : { "latest" : { "id" : 2, "state" : "failed", "submitted_on" : 1, "chroots" : [] } , "latest_succeeded" : { "id" : 1 } } }
338
    >>> f = {"name" : "f", "builds" : { "latest" : { "id" : 2, "state" : "failed", "submitted_on" : 1731457321, "chroots" : ["x86_64", "ppc64le", "s390x", "aarch64"] } , "latest_succeeded" : { "id" : 1 } } }
339
    >>> copr_pkgs= [CoprPkg(p) for p in [ a, b, c, d, e, f ]]
340
    >>> project_owner = "@fedora-llvm-team"
341
    >>> project_name = "fedora41-clang-20"
342
    >>> regressions = get_monthly_rebuild_regressions(project_owner, project_name, datetime.datetime.fromisoformat("2024-11-11"), copr_pkgs)
343
    >>> print(regressions)
344
    [{'name': 'f', 'fail_id': 2, 'url': 'https://copr.fedorainfracloud.org/coprs/g/fedora-llvm-team/fedora41-clang-20/build/2/', 'chroots': ['x86_64', 'ppc64le', 's390x', 'aarch64']}]
345

346
    """
347
    pkgs = []
1✔
348
    for p in copr_pkgs:
1✔
349
        if not p.latest:
1✔
350
            continue
×
351

352
        # Don't report regressions if there are still builds in progress
353
        if p.latest.is_in_progress():
1✔
354
            continue
1✔
355

356
        if not p.latest_succeeded:
1✔
357
            if is_tier0_package(p.name):
1✔
358
                pkgs.append(p.get_regression_info(project_owner, project_name))
×
359
            continue
1✔
360
        if p.latest.id == p.latest_succeeded.id:
1✔
361
            continue
1✔
362
        # latest is a successful build, but this doesn't mean it failed.
363
        # It could be in progress.
364
        if p.latest.state != "failed":
1✔
365
            continue
1✔
366
        if int(p.latest.submitted_on) < start_time.timestamp():
1✔
367
            continue
1✔
368
        pkgs.append(p.get_regression_info(project_owner, project_name))
1✔
369
    return pkgs
1✔
370

371

372
def get_chroot_results(
1✔
373
    pkgs: list[dict[str, Any] | None], copr_client: copr.v3.Client
374
) -> None:
375
    for p in pkgs:
×
376
        if p is None:
×
377
            continue
×
378
        p["failed_chroots"] = []
×
379
        for c in p["chroots"]:
×
380
            result = copr_client.build_chroot_proxy.get(p["fail_id"], c)
×
381
            if result["state"] == "failed":
×
382
                p["failed_chroots"].append(c)
×
383

384

385
def build_pkg(
1✔
386
    project_owner: str,
387
    project_name: str,
388
    copr_client: copr.v3.Client,
389
    pkg: str,
390
    default_commitish: str,
391
    build_tag: str,
392
    koji_server: str = "https://koji.fedoraproject.org/kojihub",
393
    distgit: str = "fedora",
394
    chroots: list[str] | None = None,
395
) -> None:
396

NEW
397
    buildopts = {
×
398
        "background": True,
399
        "chroots": chroots,
400
        # Increase default timeout because some packages take longer than 5
401
        # hours.  This is easier to do globally tahn to maintain a list of
402
        # long building packages and I don't think there is any downside to
403
        # having a longer default timeout.
404
        "timeout": 90000,
405
    }
406
    koji_session = koji.ClientSession(koji_server)
×
407
    try:
×
408
        build = koji_session.getLatestBuilds(tag=build_tag, package=pkg)[0]
×
409
        build_info = koji_session.getBuild(build["build_id"])
×
410
        commitish = build_info["source"].split("#")[1]
×
411
    except:  # noqa: E722
×
412
        logging.warn(
×
413
            "Could not determine git commit for latest build of {p}.  Defaulting to {default_commitish}."
414
        )
415
        commitish = default_commitish
×
416

417
    copr_client.build_proxy.create_from_distgit(
×
418
        project_owner,
419
        project_name,
420
        pkg,
421
        commitish,
422
        buildopts=buildopts,
423
        distgit=distgit,
424
    )
425

426

427
def start_rebuild(
1✔
428
    project_owner: str,
429
    project_name: str,
430
    copr_client: copr.v3.Client,
431
    pkgs: set[str],
432
    snapshot_project_name: str,
433
    chroots: list[str],
434
) -> None:
435
    print("START", pkgs, "END")
×
436
    # Update the rebuild project to use the latest snapshot
437
    copr_client.project_proxy.edit(
×
438
        project_owner,
439
        project_name,
440
        additional_repos=[
441
            "copr://tstellar/fedora-clang-default-cc",
442
            f"copr://@fedora-llvm-team/{snapshot_project_name}",
443
        ],
444
    )
445

446
    logging.info("Rebuilding", len(pkgs), "packages")
×
NEW
447
    rawhide_tag = get_rawhide_tag()
×
448
    for p in pkgs:
×
NEW
449
        build_pkg(
×
450
            project_owner,
451
            project_name,
452
            copr_client,
453
            p,
454
            default_commitish="rawhide",
455
            build_tag=rawhide_tag,
456
            chroots=chroots,
457
        )
458

459

460
def select_snapshot_project(
1✔
461
    copr_client: copr.v3.Client, target_chroots: list[str], max_lookback_days: int = 14
462
) -> str | None:
463
    project_owner = "@fedora-llvm-team"
×
464
    for i in range(max_lookback_days):
×
465
        chroots = set()
×
466
        day = datetime.date.today() - datetime.timedelta(days=i)
×
467
        project_name = day.strftime("llvm-snapshots-big-merge-%Y%m%d")
×
468
        logging.info("Trying:", project_name)
×
469
        try:
×
470
            p = copr_client.project_proxy.get(project_owner, project_name)
×
471
            if not p:
×
472
                continue
×
473
            pkgs = copr_client.build_proxy.get_list(
×
474
                project_owner, project_name, "llvm", status="succeeded"
475
            )
476
            for pkg in pkgs:
×
477
                chroots.update(pkg["chroots"])
×
478

479
            logging.info(project_name, chroots)
×
480
            if all(t in chroots for t in target_chroots):
×
481
                logging.info("PASS", project_name)
×
482
                return project_name
×
483
        except:  # noqa: E722
×
484
            continue
×
485
    logging.warning("FAIL")
×
486
    return None
×
487

488

489
def create_new_project(
1✔
490
    project_owner: str,
491
    project_name: str,
492
    copr_client: copr.v3.Client,
493
    target_chroots: list[str],
494
    additional_packages: list[str] | None = ["fedora-clang-default-cc"],
495
    with_opts: list[str] | None = ["toolchain_clang", "clang_lto"],
496
) -> None:
497
    copr_client.project_proxy.add(project_owner, project_name, chroots=target_chroots)
×
498
    for c in target_chroots:
×
NEW
499
        if c.startswith("centos-stream"):
×
NEW
500
            centos_version = c.split("-")[2]
×
NEW
501
            arch = c.split("-")[3]
×
502
            # Add centos stream buildroot, because not all packages in the
503
            # buildroot are shipped in the CRB.
NEW
504
            additional_repos = [
×
505
                f"https://kojihub.stream.centos.org/kojifiles/repos/c{centos_version}s-build/latest/{arch}/"
506
            ]
UNCOV
507
        copr_client.project_chroot_proxy.edit(
×
508
            project_owner,
509
            project_name,
510
            c,
511
            additional_packages=additional_packages,
512
            with_opts=with_opts,
513
            additional_repos=additional_repos,
514
        )
515

516

517
def extract_date_from_project(project_name: str) -> datetime.date:
1✔
518
    m = re.search("[0-9]+$", project_name)
×
519
    if not m:
×
520
        raise Exception(f"Invalid project name: {project_name}")
×
521
    return datetime.datetime.fromisoformat(m.group(0)).date()
×
522

523

524
def find_midpoint_project(
1✔
525
    copr_client: copr.v3.Client, good: str, bad: str, chroot: str
526
) -> str:
527
    good_date = extract_date_from_project(good)
×
528
    bad_date = extract_date_from_project(bad)
×
529
    days = (bad_date - good_date).days
×
530
    mid_date = good_date + datetime.timedelta(days=days / 2)
×
531
    increment = 0
×
532
    while mid_date != good_date and mid_date != bad_date:
×
533
        mid_project = re.sub("[0-9]+$", mid_date.strftime("%Y%m%d"), good)
×
534
        owner = mid_project.split("/")[0]
×
535
        project = mid_project.split("/")[1]
×
536
        try:
×
537
            for builds in copr_client.build_proxy.get_list(
×
538
                owner, project, "llvm", "succeeded"
539
            ):
540
                if chroot in builds["chroots"]:
×
541
                    return mid_project
×
542
        except:  # noqa: E722
×
543
            pass
×
544

545
        increment = increment * -1
×
546
        if increment < 0:
×
547
            increment -= 1
×
548
        else:
549
            increment += 1
×
550
        mid_date += datetime.timedelta(days=increment)
×
551

552
    return good
×
553

554

555
def pkg_is_ftbfs(ftbfs_data: list[dict[str, str]], pkg: str, tag: str) -> bool:
1✔
556

NEW
557
    for ftbfs_pkg in ftbfs_data:
×
NEW
558
        if ftbfs_pkg["name"] != pkg:
×
NEW
559
            continue
×
NEW
560
        if ftbfs_pkg["collection"] != tag:
×
NEW
561
            continue
×
NEW
562
        return ftbfs_pkg["state"] == "failing"
×
NEW
563
    return False
×
564

565

566
def main() -> None:
1✔
567
    logging.basicConfig(filename="rebuilder.log", level=logging.INFO)
×
568
    parser = argparse.ArgumentParser()
×
569
    parser.add_argument(
×
570
        "command",
571
        type=str,
572
        choices=[
573
            "rebuild",
574
            "get-regressions",
575
            "get-snapshot-date",
576
            "rebuild-in-progress",
577
            "bisect",
578
            "test",
579
        ],
580
    )
581
    parser.add_argument(
×
582
        "--start-date", type=str, help="Any ISO date format is accepted"
583
    )
584
    parser.add_argument("--chroot", type=str)
×
585
    parser.add_argument("--good", type=str)
×
586
    parser.add_argument("--bad", type=str)
×
NEW
587
    parser.add_argument("--llvm-major", type=int)
×
NEW
588
    parser.add_argument("--skip-same-version", action="store_true")
×
589

590
    args = parser.parse_args()
×
591
    copr_client = copr.v3.Client.create_from_config_file()
×
592

593
    os_name = "fedora-rawhide"
×
594
    target_arches = ["aarch64", "ppc64le", "s390x", "x86_64"]
×
595
    target_chroots = [f"{os_name}-{a}" for a in target_arches]
×
596
    project_owner = "@fedora-llvm-team"
×
597
    project_name = "clang-monthly-fedora-rebuild"
×
598

599
    if args.command == "rebuild":
×
600
        exclusions = get_exclusions()
×
601
        pkgs = get_pkgs(exclusions)
×
602
        print(pkgs)
×
603
        try:
×
604
            copr_client.project_proxy.get(project_owner, project_name)
×
605
            copr_pkgs = CoprPkg.get_packages_from_copr(
×
606
                project_owner, project_name, copr_client
607
            )
608
            pkgs = get_monthly_rebuild_packages(pkgs, copr_pkgs)
×
609
        except:  # noqa: E722
×
610
            create_new_project(project_owner, project_name, copr_client, target_chroots)
×
611
        snapshot_project = select_snapshot_project(copr_client, target_chroots)
×
612
        if snapshot_project is not None:
×
613
            start_rebuild(
×
614
                project_owner,
615
                project_name,
616
                copr_client,
617
                pkgs,
618
                snapshot_project,
619
                target_chroots,
620
            )
621
    elif args.command == "get-regressions":
×
622
        start_time = datetime.datetime.fromisoformat(args.start_date)
×
623
        copr_pkgs = CoprPkg.get_packages_from_copr(
×
624
            project_owner, project_name, copr_client
625
        )
626
        pkg_failures = get_monthly_rebuild_regressions(
×
627
            project_owner, project_name, start_time, copr_pkgs
628
        )
629
        get_chroot_results(list(pkg_failures), copr_client)
×
630
        # Delete attributes we don't need to print
631
        for p in pkg_failures:
×
632
            if p is None:
×
633
                continue
×
634
            for k in ["fail_id", "chroots"]:
×
635
                del p[k]
×
636

637
        print(json.dumps(pkg_failures))
×
638
    elif args.command == "get-snapshot-date":
×
639
        project = copr_client.project_proxy.get(project_owner, project_name)
×
640
        for repo in project["additional_repos"]:
×
641
            match = re.match(
×
642
                r"copr://@fedora-llvm-team/llvm-snapshots-big-merge-([0-9]+)$", repo
643
            )
644
            if match:
×
645
                print(datetime.datetime.fromisoformat(match.group(1)).isoformat())
×
646
                return
×
647
    elif args.command == "rebuild-in-progress":
×
648
        for pkg in copr_client.monitor_proxy.monitor(project_owner, project_name)[
×
649
            "packages"
650
        ]:
651
            for c in pkg["chroots"]:
×
652
                build = CoprBuild(pkg["chroots"][c])
×
653
                if build.is_in_progress():
×
654
                    sys.exit(0)
×
655
        sys.exit(1)
×
656
    elif args.command == "bisect":
×
657
        print(find_midpoint_project(copr_client, args.good, args.bad, args.chroot))
×
NEW
658
    elif args.command == "test":
×
NEW
659
        project_owner = "@fedora-llvm-team"
×
NEW
660
        project_name = "clang-fedora-centos-testing"
×
NEW
661
        centos_stream9_chroots = [f"centos-stream-9-{arch}" for arch in target_arches]
×
NEW
662
        centos_stream10_chroots = [f"centos-stream-10-{arch}" for arch in target_arches]
×
NEW
663
        fedora_chroots = [f"fedora-rawhide-{a}" for a in target_arches]
×
NEW
664
        target_chroots = (
×
665
            centos_stream10_chroots + centos_stream9_chroots + fedora_chroots
666
        )
NEW
667
        try:
×
NEW
668
            copr_client.project_proxy.get(project_owner, project_name)
×
NEW
669
        except Exception:
×
NEW
670
            create_new_project(
×
671
                project_owner,
672
                project_name,
673
                copr_client,
674
                target_chroots,
675
                additional_packages=None,
676
                with_opts=None,
677
            )
678
            # Set repo priority so that built packages that depend on a specific
679
            # LLVM snapshot version do not get installed.
NEW
680
            copr_client.project_proxy.edit(
×
681
                project_owner, project_name, repo_priority=1000
682
            )
NEW
683
        centos9_pkgs = get_tier1_pkgs(9)
×
NEW
684
        centos10_pkgs = get_tier1_pkgs(10)
×
NEW
685
        fedora_pkgs = get_tier2_pkgs()
×
686

NEW
687
        copr_client.project_proxy.edit(
×
688
            project_owner,
689
            project_name,
690
            additional_repos=[
691
                "copr://@fedora-llvm-team/llvm-compat-packages",
692
            ],
693
        )
694

695
        # Iterate over a copy of a list so we can remove items:
NEW
696
        for chroot in list(target_chroots):
×
NEW
697
            snapshot_project_name = select_snapshot_project(copr_client, [chroot])
×
NEW
698
            if not snapshot_project_name:
×
NEW
699
                print(f"Could not find snapshot for {chroot}")
×
NEW
700
                target_chroots.remove(chroot)
×
NEW
701
                continue
×
702
            else:
NEW
703
                print(f"Using {snapshot_project_name} for {chroot}")
×
NEW
704
            snapshot_url = f"copr://@fedora-llvm-team/{snapshot_project_name}"
×
NEW
705
            repos = []
×
NEW
706
            for r in copr_client.project_chroot_proxy.get(
×
707
                project_owner, project_name, chroot
708
            )["additional_repos"]:
NEW
709
                if args.skip_same_version and r == snapshot_url:
×
NEW
710
                    print(
×
711
                        f"Not building for {chroot} since snapshot version is the same as the last build"
712
                    )
NEW
713
                    target_chroots.remove(chroot)
×
NEW
714
                if not r.startswith(
×
715
                    "copr://@fedora-llvm-team/llvm-snapshots-big-merge"
716
                ):
NEW
717
                    repos.append(r)
×
NEW
718
            if chroot not in target_chroots:
×
NEW
719
                continue
×
720

NEW
721
            copr_client.project_chroot_proxy.edit(
×
722
                project_owner,
723
                project_name,
724
                chroot,
725
                additional_repos=repos + [snapshot_url],
726
            )
727

NEW
728
        centos_stream9_chroots = [
×
729
            c for c in centos_stream9_chroots if c in target_chroots
730
        ]
NEW
731
        for pkg in centos9_pkgs:
×
NEW
732
            build_pkg(
×
733
                project_owner=project_owner,
734
                project_name=project_name,
735
                copr_client=copr_client,
736
                pkg=pkg,
737
                koji_server="https://kojihub.stream.centos.org/kojihub",
738
                default_commitish="c9s",
739
                build_tag="c9s-candidate",
740
                distgit="centos-stream",
741
                chroots=centos_stream9_chroots,
742
            )
743

NEW
744
        centos_stream10_chroots = [
×
745
            c for c in centos_stream10_chroots if c in target_chroots
746
        ]
NEW
747
        for pkg in centos10_pkgs:
×
NEW
748
            build_pkg(
×
749
                project_owner=project_owner,
750
                project_name=project_name,
751
                copr_client=copr_client,
752
                pkg=pkg,
753
                koji_server="https://kojihub.stream.centos.org/kojihub",
754
                default_commitish="c10s",
755
                build_tag="c10s-candidate",
756
                distgit="centos-stream",
757
                chroots=centos_stream10_chroots,
758
            )
759

NEW
760
        fedora_chroots = [c for c in fedora_chroots if c in target_chroots]
×
761

762
        # Load FTBFS data so we can skip building packages that currently don't build.
NEW
763
        request = urllib.request.Request(
×
764
            "https://koschei.fedoraproject.org/api/v1/packages"
765
        )
766
        # We need to set these headers due to new anti-spam measures in Fedora infrastructure.
NEW
767
        request.add_header("Accept", "text/plain")
×
NEW
768
        request.add_header("User-Agent", "fedora-llvm-team/1.0")
×
NEW
769
        with urllib.request.urlopen(request) as url:
×
NEW
770
            ftbfs_data = json.loads(url.read().decode())
×
771

NEW
772
        rawhide_tag = get_rawhide_tag()
×
NEW
773
        for pkg in fedora_pkgs:
×
NEW
774
            if pkg_is_ftbfs(ftbfs_data, pkg, tag=rawhide_tag):
×
NEW
775
                print(f"Skip building {pkg} on rawhide, because it is FTBFS")
×
NEW
776
                continue
×
NEW
777
            print(f"Building {pkg}")
×
NEW
778
            build_pkg(
×
779
                project_owner=project_owner,
780
                project_name=project_name,
781
                copr_client=copr_client,
782
                pkg=pkg,
783
                default_commitish="rawhide",
784
                build_tag=rawhide_tag,
785
                chroots=fedora_chroots,
786
            )
787

788

789
if __name__ == "__main__":
1✔
790
    main()
×
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