|
81 | 81 | r"wheel-sha256=(?P<wheel>[0-9a-f]{64}) " |
82 | 82 | r"sdist-sha256=(?P<sdist>[0-9a-f]{64}) -->$" |
83 | 83 | ) |
| 84 | +RELEASE_EVIDENCE_WORKFLOW_REFERENCE = re.compile( |
| 85 | + r"^<!-- cometapi-release-workflow-reference " |
| 86 | + r"run=(?P<run>[1-9]\d*) -->$" |
| 87 | +) |
| 88 | +_ANY_RELEASE_EVIDENCE_WORKFLOW_REFERENCE = re.compile( |
| 89 | + r"(?m)^.*cometapi-release-workflow-reference.*$" |
| 90 | +) |
84 | 91 | _ANY_RELEASE_EVIDENCE_IDENTITY = re.compile(r"(?m)^.*cometapi-release-identity.*$") |
85 | 92 | _ANY_RELEASE_EVIDENCE_MARKER = re.compile(r"(?m)^.*cometapi-release-evidence:.*$") |
86 | 93 | _EXACT_VERSION = ( |
|
131 | 138 | _RECOVERY_TAGS = {"0.1.0a1": "v0.1.0-alpha.1+recovery.1"} |
132 | 139 | _FULL_COMMIT = re.compile(r"(?<![0-9a-f])[0-9a-f]{40}(?![0-9a-f])", re.IGNORECASE) |
133 | 140 | _ACTIONS_RUN = re.compile( |
134 | | - rf"{re.escape(CANONICAL_REPOSITORY)}/actions/runs/[1-9]\d*(?:/attempts/[1-9]\d*)?" |
| 141 | + rf"(?<![^\s(<]){re.escape(CANONICAL_REPOSITORY)}/actions/runs/" |
| 142 | + r"[1-9]\d*(?:/attempts/[1-9]\d*)?(?=$|[\s)>])" |
135 | 143 | ) |
136 | 144 | _WHEEL_DIGEST = re.compile( |
137 | 145 | r"\bwheel\s+sha256\b[^0-9a-f]{0,96}(?P<digest>[0-9a-f]{64})(?![0-9a-f])", |
@@ -504,6 +512,39 @@ def _identity_violations( |
504 | 512 | sdist_sha256=match.group("sdist"), |
505 | 513 | ) |
506 | 514 | findings: list[tuple[int, str]] = [] |
| 515 | + workflow_references: set[str] = set() |
| 516 | + workflow_reference_lines = [ |
| 517 | + value for value in nonempty if "cometapi-release-workflow-reference" in value |
| 518 | + ] |
| 519 | + for reference_line in _ANY_RELEASE_EVIDENCE_WORKFLOW_REFERENCE.findall(body): |
| 520 | + if reference_line.strip() not in workflow_reference_lines: |
| 521 | + findings.append( |
| 522 | + (line, f"release-evidence block for {version} has malformed workflow reference") |
| 523 | + ) |
| 524 | + for reference_line in workflow_reference_lines: |
| 525 | + reference = RELEASE_EVIDENCE_WORKFLOW_REFERENCE.fullmatch(reference_line) |
| 526 | + if reference is None: |
| 527 | + findings.append( |
| 528 | + (line, f"release-evidence block for {version} has malformed workflow reference") |
| 529 | + ) |
| 530 | + continue |
| 531 | + run = reference.group("run") |
| 532 | + if run in workflow_references: |
| 533 | + findings.append( |
| 534 | + ( |
| 535 | + line, |
| 536 | + f"release-evidence block for {version} duplicates workflow reference run {run}", |
| 537 | + ) |
| 538 | + ) |
| 539 | + workflow_references.add(run) |
| 540 | + if identity.workflow_run in workflow_references: |
| 541 | + findings.append( |
| 542 | + ( |
| 543 | + line, |
| 544 | + f"release-evidence block for {version} must not classify its canonical " |
| 545 | + "publication run as an ancillary workflow reference", |
| 546 | + ) |
| 547 | + ) |
507 | 548 | expected_tag = _canonical_release_tag(version) |
508 | 549 | if identity.tag != expected_tag: |
509 | 550 | findings.append( |
@@ -569,26 +610,32 @@ def _identity_violations( |
569 | 610 | before_commit, |
570 | 611 | ): |
571 | 612 | release_commit_values.add(commit.group(0).lower()) |
572 | | - release_run_values: set[str] = set() |
573 | | - for run in _ACTIONS_RUN.finditer(prose): |
574 | | - line_start = prose.rfind("\n", 0, run.start()) + 1 |
575 | | - prior_line_start = prose.rfind("\n", 0, max(0, line_start - 1)) + 1 |
576 | | - context = prose[prior_line_start : run.start()] |
577 | | - label = re.search(r"(?i)\[([^\]]+)\]\([^\n]*$", context) |
578 | | - label_text = label.group(1) if label is not None else context.splitlines()[-1] |
579 | | - if re.search( |
580 | | - r"(?i)\b(?:release|publish(?:ing)?|publication|registry)" |
581 | | - r"(?:[ -]+(?:workflow|job|pipeline))?[ -]+run\b" |
582 | | - r"|\b(?:release|publish(?:ing)?|publication|registry)" |
583 | | - r"(?:[ -]+(?:job|pipeline))?[ -]+workflow\b" |
584 | | - r"|\bworkflow[ -]+run\b" |
585 | | - r"|\bgithub[ -]+actions[ -]+run\b", |
586 | | - label_text, |
587 | | - ): |
588 | | - release_run_values.add(run.group(0).split("/actions/runs/", 1)[1].split("/", 1)[0]) |
| 613 | + # Prose may cite only the canonical publication run or an exact ancillary run |
| 614 | + # declared by a typed machine-readable reference. |
| 615 | + release_run_values = { |
| 616 | + run.group(0).split("/actions/runs/", 1)[1].split("/", 1)[0] |
| 617 | + for run in _ACTIONS_RUN.finditer(prose) |
| 618 | + } |
| 619 | + unreferenced_workflow_runs = set(workflow_references) - release_run_values |
| 620 | + if unreferenced_workflow_runs: |
| 621 | + findings.append( |
| 622 | + ( |
| 623 | + line, |
| 624 | + f"release-evidence block for {version} declares ancillary workflow runs " |
| 625 | + "that have no exact canonical Actions URL in the block", |
| 626 | + ) |
| 627 | + ) |
| 628 | + undeclared_release_runs = release_run_values - { |
| 629 | + identity.workflow_run, |
| 630 | + *workflow_references, |
| 631 | + } |
589 | 632 | labeled_values = ( |
590 | 633 | ("release commit", release_commit_values, identity.commit), |
591 | | - ("release workflow run", release_run_values, identity.workflow_run), |
| 634 | + ( |
| 635 | + "release workflow run", |
| 636 | + undeclared_release_runs | {identity.workflow_run}, |
| 637 | + identity.workflow_run, |
| 638 | + ), |
592 | 639 | ( |
593 | 640 | "wheel SHA256", |
594 | 641 | { |
|
0 commit comments