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

fedora-llvm-team / llvm-snapshots / 20313058244

17 Dec 2025 06:22PM UTC coverage: 53.35% (-2.1%) from 55.438%
20313058244

Pull #1831

github

web-flow
Merge 8d387005e 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() -> Any:
1✔
NEW
19
    koji_session = koji.ClientSession("https://koji.fedoraproject.org/kojihub")
×
NEW
20
    target = koji_session.getBuildTarget("rawhide")
×
NEW
21
    return target["build_tag_name"].split("-")[0]
×
22

23

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

36

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

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

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

46
    Example:
47

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

56

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

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

81

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

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

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

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

122

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

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

136

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

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

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

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

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

187

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

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

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

201

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

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

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

211
    Example:
212

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

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

237

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

244

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

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

268

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

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

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

283
    Example:
284

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

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

309

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

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

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

329
    Example:
330

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

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

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

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

369

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

382

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

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

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

424

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

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

457

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

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

486

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

514

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

521

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

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

550
    return good
×
551

552

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

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

563

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

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

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

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

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

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

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

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

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

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

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

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

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

786

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