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

fedora-llvm-team / llvm-snapshots / 20317152181

17 Dec 2025 09:02PM UTC coverage: 53.35% (-2.1%) from 55.438%
20317152181

Pull #1831

github

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

7 of 109 new or added lines in 1 file covered. (6.42%)

3 existing lines in 2 files now uncovered.

1314 of 2463 relevant lines covered (53.35%)

0.53 hits per line

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

26.96
/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
    return target["build_tag_name"].split("-")[0]
×
23

24

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

37

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

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

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

47
    Example:
48

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

57

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

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

82

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

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

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

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

123

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

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

137

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

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

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

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

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

188

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

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

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

202

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

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

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

212
    Example:
213

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

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

238

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

245

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

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

269

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

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

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

284
    Example:
285

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

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

310

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

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

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

330
    Example:
331

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

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

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

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

370

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

383

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

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

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

425

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

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

458

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

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

487

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

515

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

522

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

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

551
    return good
×
552

553

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

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

564

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

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

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

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

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

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

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

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

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

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

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

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

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

787

788
if __name__ == "__main__":
1✔
789
    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