Skip to content
Open
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
25 changes: 16 additions & 9 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ jobs:
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Post Coverage Started Comment
if: github.event.pull_request.head.repo.full_name == github.repository
continue-on-error: true
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
header: ${{ matrix.comment_header }}
Expand Down Expand Up @@ -200,14 +202,6 @@ jobs:
RUST_LOG: trace
shell: bash

- name: Upload PR Coverage Artifact
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: coverage-pr-${{ matrix.os }}
path: lcov.info
if-no-files-found: ignore

- name: Wait for Exact PR Base Coverage
id: wait_for_base_coverage
if: always()
Expand Down Expand Up @@ -246,8 +240,21 @@ jobs:
--summary "$GITHUB_STEP_SUMMARY"
shell: bash

- name: Post Coverage Comment
- name: Upload PR Coverage Artifact
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: coverage-pr-${{ matrix.os }}
path: |
lcov.info
coverage-report.md
if-no-files-found: ignore

- name: Post Coverage Comment
if: >-
always() &&
github.event.pull_request.head.repo.full_name == github.repository
continue-on-error: true
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
header: ${{ matrix.comment_header }}
Expand Down
28 changes: 18 additions & 10 deletions .github/workflows/perf-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ jobs:
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Post In-Progress Comment
if: github.event_name == 'pull_request'
if: >-
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
continue-on-error: true
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
header: ${{ matrix.comment_header }}
Expand Down Expand Up @@ -120,14 +123,6 @@ jobs:
cat metrics.json
shell: bash

- name: Upload PR Performance Results
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: perf-pr-${{ matrix.os }}
path: metrics.json
if-no-files-found: ignore

- name: Wait for Exact PR Base Performance
id: wait_for_base_performance
if: always() && github.event_name == 'pull_request'
Expand Down Expand Up @@ -180,8 +175,21 @@ jobs:
--summary "$GITHUB_STEP_SUMMARY"
shell: bash

- name: Upload PR Performance Results
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: perf-pr-${{ matrix.os }}
path: |
metrics.json
performance-report.md
if-no-files-found: ignore

- name: Post Performance Comment
if: always() && github.event_name == 'pull_request'
if: >-
always() && github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
continue-on-error: true
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
header: ${{ matrix.comment_header }}
Expand Down
104 changes: 104 additions & 0 deletions scripts/tests/test_quality_workflows.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

import re
import unittest
from pathlib import Path


ROOT = Path(__file__).resolve().parents[2]
SAME_REPOSITORY_PR = (
"github.event.pull_request.head.repo.full_name == github.repository"
)


def workflow_steps(path: str) -> dict[str, str]:
workflow = (ROOT / path).read_text(encoding="utf-8")
chunks = re.split(r"(?m)^ - name: ", workflow)[1:]
return {chunk.splitlines()[0]: chunk for chunk in chunks}


def step_property(step: str, name: str) -> str | None:
lines = step.splitlines()[1:]
prefix = f" {name}:"
for index, line in enumerate(lines):
if not line.startswith(prefix):
continue

value = line.removeprefix(prefix).strip()
if value not in {">", ">-", "|", "|-"}:
return value

continuation = []
for next_line in lines[index + 1 :]:
if not next_line.startswith(" "):
break
continuation.append(next_line.strip())
return " ".join(continuation)
return None


class QualityWorkflowTests(unittest.TestCase):
def test_comment_steps_are_fork_safe_and_non_gating(self) -> None:
comment_steps = []
for path in (ROOT / ".github" / "workflows").glob("*.yml"):
workflow = path.relative_to(ROOT).as_posix()
text = path.read_text(encoding="utf-8")
if "marocchino/sticky-pull-request-comment" not in text:
continue
self.assertNotIn("pull_request_target:", text)

for step_name, step in workflow_steps(workflow).items():
if "marocchino/sticky-pull-request-comment" not in step:
continue
comment_steps.append((workflow, step_name))
with self.subTest(workflow=workflow, step=step_name):
condition = step_property(step, "if")
self.assertIsNotNone(condition)
assert condition is not None
self.assertIn(SAME_REPOSITORY_PR, condition)
self.assertEqual(step_property(step, "continue-on-error"), "true")

self.assertEqual(
sorted(comment_steps),
sorted(
(
(".github/workflows/coverage.yml", "Post Coverage Comment"),
(".github/workflows/coverage.yml", "Post Coverage Started Comment"),
(".github/workflows/perf-tests.yml", "Post In-Progress Comment"),
(".github/workflows/perf-tests.yml", "Post Performance Comment"),
)
),
)

def test_report_artifacts_are_uploaded_after_comparison(self) -> None:
cases = (
(
".github/workflows/coverage.yml",
"Compare Coverage Snapshot",
"Upload PR Coverage Artifact",
"coverage-report.md",
),
(
".github/workflows/perf-tests.yml",
"Compare Performance Snapshot",
"Upload PR Performance Results",
"performance-report.md",
),
)

for workflow, comparison, upload, report in cases:
with self.subTest(workflow=workflow):
text = (ROOT / workflow).read_text(encoding="utf-8")
steps = workflow_steps(workflow)
self.assertLess(
text.index(f"- name: {comparison}"),
text.index(f"- name: {upload}"),
)
self.assertIn(report, steps[upload])
self.assertEqual(step_property(steps[upload], "if"), "always()")
self.assertIsNone(step_property(steps[comparison], "continue-on-error"))


if __name__ == "__main__":
unittest.main()