Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions mergify_cli/ci/detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,25 @@ async def get_head_sha() -> str | None:
return None


def get_cicd_pipeline_run_id() -> int | None:
if get_ci_provider() == "github_actions" and "GITHUB_RUN_ID" in os.environ:
return int(os.environ["GITHUB_RUN_ID"])

if get_ci_provider() == "circleci" and "CIRCLE_WORKFLOW_ID" in os.environ:
return int(os.environ["CIRCLE_WORKFLOW_ID"])

return None


def get_cicd_pipeline_run_attempt() -> int | None:
if get_ci_provider() == "github_actions" and "GITHUB_RUN_ATTEMPT" in os.environ:
return int(os.environ["GITHUB_RUN_ATTEMPT"])
if get_ci_provider() == "circleci" and "CIRCLE_BUILD_NUM" in os.environ:
return int(os.environ["CIRCLE_BUILD_NUM"])

return None


def get_github_repository() -> str | None:
if get_ci_provider() == "github_actions":
return os.getenv("GITHUB_REPOSITORY")
Expand Down
11 changes: 9 additions & 2 deletions mergify_cli/ci/junit.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ class InvalidJunitXMLError(Exception):


async def junit_to_spans(
trace_id: int,
xml_content: bytes,
test_language: str | None = None,
test_framework: str | None = None,
Expand Down Expand Up @@ -69,11 +68,17 @@ async def junit_to_spans(
if test_language is not None:
common_attributes["test.language"] = test_language

resource_attributes = {}
resource_attributes: dict[str, typing.Any] = {}

if (job_name := detector.get_job_name()) is not None:
resource_attributes[cicd_attributes.CICD_PIPELINE_NAME] = job_name

if (run_id := detector.get_cicd_pipeline_run_id()) is not None:
resource_attributes[cicd_attributes.CICD_PIPELINE_RUN_ID] = run_id

if (run_attempt := detector.get_cicd_pipeline_run_attempt()) is not None:
resource_attributes["cicd.pipeline.run.attempt"] = run_attempt

if (head_revision := (await detector.get_head_sha())) is not None:
resource_attributes[vcs_attributes.VCS_REF_HEAD_REVISION] = head_revision

Expand All @@ -82,6 +87,8 @@ async def junit_to_spans(

resource = resources.Resource.create(resource_attributes)

trace_id = ID_GENERATOR.generate_trace_id()

for testsuite in testsuites:
min_start_time = now
suite_name = testsuite.get("name", "unnamed testsuite")
Expand Down
7 changes: 2 additions & 5 deletions mergify_cli/ci/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ def upload_spans(

def connect_traces(spans: list[ReadableSpan]) -> None:
if detector.get_ci_provider() == "github_actions" and spans:
trace_id = spans[0].context.trace_id
root_span_id = spans[0].context.span_id
console.print(
f"::notice title=Mergify CI::MERGIFY_TRACE_ID={trace_id}",
f"::notice title=Mergify CI::MERGIFY_TEST_ROOT_SPAN_ID={root_span_id}",
soft_wrap=True,
)

Expand All @@ -74,13 +74,10 @@ async def upload( # noqa: PLR0913, PLR0917
) -> None:
spans = []

trace_id = junit.ID_GENERATOR.generate_trace_id()

for filename in files:
try:
spans.extend(
await junit.junit_to_spans(
trace_id,
pathlib.Path(filename).read_bytes(),
test_language=test_language,
test_framework=test_framework,
Expand Down
146 changes: 28 additions & 118 deletions mergify_cli/tests/ci/test_junit.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

@mock.patch.object(detector, "get_ci_provider", return_value="github_actions")
@mock.patch.object(detector, "get_job_name", return_value="JOB")
@mock.patch.object(detector, "get_cicd_pipeline_run_id", return_value=123)
@mock.patch.object(detector, "get_cicd_pipeline_run_attempt", return_value=1)
@mock.patch.object(
detector,
"get_head_sha",
Expand All @@ -20,10 +22,11 @@ async def test_parse(
_get_ci_provider: mock.Mock,
_get_job_name: mock.Mock,
_get_head_sha: mock.Mock,
_get_cicd_pipeline_run_id: mock.Mock,
_get_cicd_pipeline_run_attempt: mock.Mock,
) -> None:
filename = pathlib.Path(__file__).parent / "junit_example.xml"
spans = await junit.junit_to_spans(
123,
filename.read_bytes(),
"python",
"unittest",
Expand All @@ -32,6 +35,17 @@ async def test_parse(
trace_id = "0x" + opentelemetry.trace.span.format_trace_id(
spans[1].context.trace_id,
)
resource_attributes = {
"cicd.pipeline.name": "JOB",
"cicd.pipeline.run.id": 123,
"cicd.pipeline.run.attempt": 1,
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
}
assert dictified_spans == [
{
"attributes": {
Expand All @@ -52,15 +66,7 @@ async def test_parse(
"name": "Tests.Registration",
"parent_id": None,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down Expand Up @@ -88,15 +94,7 @@ async def test_parse(
"name": "Tests.Registration.testCase1",
"parent_id": anys.ANY_STR,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down Expand Up @@ -124,15 +122,7 @@ async def test_parse(
"name": "Tests.Registration.testCase2",
"parent_id": anys.ANY_STR,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down Expand Up @@ -163,15 +153,7 @@ async def test_parse(
"name": "Tests.Registration.testCase3",
"parent_id": anys.ANY_STR,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand All @@ -198,15 +180,7 @@ async def test_parse(
"name": "Tests.Authentication",
"parent_id": None,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down Expand Up @@ -234,15 +208,7 @@ async def test_parse(
"name": "Tests.Authentication.testCase7",
"parent_id": anys.ANY_STR,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down Expand Up @@ -270,15 +236,7 @@ async def test_parse(
"name": "Tests.Authentication.testCase8",
"parent_id": anys.ANY_STR,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down Expand Up @@ -309,15 +267,7 @@ async def test_parse(
"name": "Tests.Authentication.testCase9",
"parent_id": anys.ANY_STR,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down Expand Up @@ -349,15 +299,7 @@ async def test_parse(
"name": "Tests.Permission.testCase10",
"parent_id": anys.ANY_STR,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand All @@ -384,15 +326,7 @@ async def test_parse(
"name": "Tests.Authentication.Login",
"parent_id": None,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down Expand Up @@ -420,15 +354,7 @@ async def test_parse(
"name": "Tests.Authentication.Login.testCase4",
"parent_id": anys.ANY_STR,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down Expand Up @@ -459,15 +385,7 @@ async def test_parse(
"name": "Tests.Authentication.Login.testCase5",
"parent_id": anys.ANY_STR,
"resource": {
"attributes": {
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down Expand Up @@ -495,15 +413,7 @@ async def test_parse(
"name": "Tests.Authentication.Login.testCase6",
"parent_id": anys.ANY_STR,
"resource": {
"attributes": {
"cicd.pipeline.name": "JOB",
"cicd.provider.name": "github_actions",
"vcs.ref.head.revision": "3af96aa24f1d32fcfbb7067793cacc6dc0c6b199",
"service.name": "unknown_service",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": anys.ANY_STR,
},
"attributes": resource_attributes,
"schema_url": "",
},
"start_time": anys.ANY_DATETIME_STR,
Expand Down
6 changes: 4 additions & 2 deletions mergify_cli/tests/ci/test_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,13 @@ async def test_junit_upload(

captured = capsys.readouterr()
if env["GITHUB_ACTIONS"] == "true":
assert re.search(
r"^::notice title=Mergify CI::MERGIFY_TRACE_ID=\d+",
matched = re.search(
r"^::notice title=Mergify CI::MERGIFY_TEST_ROOT_SPAN_ID=(\d+)",
captured.out,
re.MULTILINE,
)
assert matched is not None
assert int(matched.group(1)) > 0

assert "🎉 File(s) uploaded" in captured.out

Expand Down