Files
Groene AIandClaude Opus 4.8 cc4ad1f9f4 Do not fail coverage jobs when the profdata artifact is missing
LLVM coverage jobs (Integration, Functional and Unit tests, amd_llvm_coverage)
run their coverage merge non-blocking: llvm-profdata can crash on a corrupt
.profraw and produce no .profdata, but the tests all pass and the job is meant
to stay green ("do not block pipeline").

Each such job also declares provides=[LLVM_COVERAGE_FILE_*] with path
./*.profdata. The praktika post-run upload treated a missing providing artifact
as a hard error and set the job to check_status=error even though 0 tests
failed. Observed on several PRs where job.log shows "Failed to create final
coverage file" (llvm-profdata crash) followed by "Failed to upload artifact
[LLVM_COVERAGE_FILE_it_N:./*.profdata]".

Add an optional flag to Artifact.Config. When a providing artifact marked
optional matches no file at upload time, skip it with a warning instead of
reddening the job. Mark the coverage profdata artifacts optional. The
downstream LLVM Coverage aggregation already globs whatever .profdata files
exist, so a missing batch is tolerated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-03 02:45:55 +00:00

60 lines
1.9 KiB
Python

import copy
from dataclasses import dataclass, field
from typing import Any, Dict, List, Union
class Artifact:
class Type:
GH = "github"
S3 = "s3"
PHONY = "phony"
@dataclass
class Config:
"""
name - artifact name
type - artifact type, see Artifact.Type
path - file path or glob, e.g. "path/**/[abc]rtifac?/*"
"""
name: str
type: str
path: Union[str, List[str]]
compress_zst: bool = False
# When True, a providing job whose output file(s) are missing at upload
# time does not fail. The job that already ran non-blocking (e.g. LLVM
# coverage merge) stays green; only the artifact is skipped. Consumers
# of an optional artifact must tolerate its absence.
optional: bool = False
_provided_by: str = ""
ext: Dict[str, Any] = field(default_factory=dict)
def is_s3_artifact(self):
return self.type == Artifact.Type.S3
def parametrize(self, names):
res = []
for name in names:
obj = copy.deepcopy(self)
obj.name = name
res.append(obj)
return res
def add_tags(self, tags: Dict[str, str]):
"""
Add tags to the artifact. Only S3 artifacts support tags.
Returns a copy of the artifact with the tags added.
:param tags: Dictionary of tag key-value pairs
:return: A new Config object with the tags added
:raises ValueError: If artifact type is not S3
"""
if not self.is_s3_artifact():
raise ValueError(
f"Tags can only be added to S3 artifacts, but artifact type is [{self.type}]"
)
obj = copy.deepcopy(self)
if "tags" not in obj.ext:
obj.ext["tags"] = {}
obj.ext["tags"].update(tags)
return obj