diff --git a/.github/scripts/validate-pr b/.github/scripts/validate-pr index 9c068560f9563..c851dfc5e2b67 100755 --- a/.github/scripts/validate-pr +++ b/.github/scripts/validate-pr @@ -33,6 +33,18 @@ def get_cherry_pick_sha(message): m = re.search(r'\(cherry picked from commit ([a-fA-F0-9]+)\)', message) return m.group(1) if m else None +def get_backported_commit_sha(message): + m = re.search(r'\(backported from commit ([a-fA-F0-9]+)\)', message) + return m.group(1) if m else None + +def get_upstream_commit_sha(message): + for getter in (get_cherry_pick_sha, get_backported_commit_sha): + sha = getter(message) + if sha: + return sha + m = re.search(r'^[Uu]pstream commit ([a-fA-F0-9]+)', message, re.MULTILINE) + return m.group(1) if m else None + def get_backport_url(message): m = re.search(r'\(backported from (https?://[^\)]+)\)', message) return m.group(1) if m else None @@ -40,6 +52,14 @@ def get_backport_url(message): def is_sauce(subject): return bool(re.match(r'^NVIDIA:.*SAUCE:', subject)) +def is_ubuntu_local(subject): + """Ubuntu-local commits with no upstream equivalent. + + Catches 'UBUNTU: SAUCE: ...', 'UBUNTU: [Config] ...', + 'UBUNTU: [Packaging] ...', 'UBUNTU: Ubuntu-X.X.X-...', etc. + """ + return bool(re.match(r'^UBUNTU:\s', subject)) + def is_revert(subject): return subject.startswith('Revert "') @@ -322,7 +342,7 @@ def build_digest(commits, repo, upstream_remote=None): errors = [] for commit in commits: - src_sha = get_cherry_pick_sha(commit.message) + src_sha = get_upstream_commit_sha(commit.message) bp_url = get_backport_url(commit.message) # --- SAUCE / Revert: no upstream reference, show as informational row --- @@ -336,6 +356,9 @@ def build_digest(commits, repo, upstream_remote=None): # Strip outer Revert "..." wrapper and SAUCE prefix for display inner = re.sub(r'^Revert\s+"', '', subj).rstrip('"') display = _norm_sauce_subject(inner) or inner + elif is_ubuntu_local(subj): + kind = 'UBUNTU' + display = re.sub(r'^UBUNTU:\s*', '', subj) else: kind = 'SAUCE' display = _norm_sauce_subject(subj) or subj @@ -460,20 +483,25 @@ def lint_commits(commits): # Classification for R6/R7/R9/R10 sauce = is_sauce(subject) + ubuntu = is_ubuntu_local(subject) revert = is_revert(subject) - # R9: subject length — exempt SAUCE and Reverts of SAUCE; the mandatory - # "NVIDIA: [VR: ]SAUCE:" prefix already consumes 15–20 characters. + # R9: subject length — exempt SAUCE, UBUNTU local and Reverts of SAUCE; + # the mandatory "NVIDIA: [VR: ]SAUCE:" / "UBUNTU: [Config]" prefix + # already consumes 12–20 characters. revert_of_sauce = revert and bool(re.match(r'^Revert "NVIDIA:.*SAUCE:', subject)) - if len(subject) > 72 and not sauce and not revert_of_sauce: + if len(subject) > 72 and not sauce and not ubuntu and not revert_of_sauce: warnings.append("W: {}: subject {} chars (>72)".format(label, len(subject))) - cp_sha = get_cherry_pick_sha(commit.message) + upstream_sha = get_upstream_commit_sha(commit.message) + cp_sha = get_cherry_pick_sha(commit.message) bp_url = get_backport_url(commit.message) - # R6: non-SAUCE, non-Revert commits must have an upstream reference trailer - if not sauce and not revert and cp_sha is None and bp_url is None: + # R6: non-SAUCE, non-UBUNTU, non-Revert commits must have an upstream + # reference trailer. UBUNTU local commits (e.g. UBUNTU: [Config]) have + # no upstream equivalent. + if not sauce and not ubuntu and not revert and upstream_sha is None and bp_url is None: errors.append( - "E: {}: not SAUCE/Revert but has no upstream reference trailer" + "E: {}: not SAUCE/UBUNTU/Revert but has no upstream reference trailer" " (cherry picked from commit ... or backported from ...)".format(label)) # R7: detect wrong trailer for LKML in-review backports @@ -508,19 +536,18 @@ def check_pr_metadata(pr_title, pr_body_path, base_branch): warnings.append( "W: PR title missing [] prefix: \"{}\"".format(pr_title[:80])) - # R3: BugLink required for tracked branches + # R3: Launchpad bug link required for tracked branches if pr_body_path and base_branch and TRACKED_BRANCH_RE.match(base_branch): try: body = open(pr_body_path).read() except OSError as e: errors.append("E: cannot read --pr-body {}: {}".format(pr_body_path, e)) body = '' - buglink_re = re.compile( - r'^(?:BugLink:|LP:)\s+https://bugs\.launchpad\.net/', re.MULTILINE) + buglink_re = re.compile(r'https://bugs\.launchpad\.net/') if not buglink_re.search(body): errors.append( - "E: PR targets {} but body has no 'BugLink:' or 'LP:'" - " https://bugs.launchpad.net/... line".format(base_branch)) + "E: PR targets {} but body has no" + " https://bugs.launchpad.net/... link".format(base_branch)) return warnings, errors diff --git a/.github/workflows/patchscan.yml b/.github/workflows/patchscan.yml index 22ac72afaf877..c23b90e4de054 100644 --- a/.github/workflows/patchscan.yml +++ b/.github/workflows/patchscan.yml @@ -80,15 +80,12 @@ jobs: - name: Write PR title and body to files env: GH_TOKEN: ${{ github.token }} + PR_REPO: ${{ steps.pr.outputs.pr_repo }} + PR_NUMBER: ${{ steps.pr.outputs.pr_number }} run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - pr_json=$(gh api repos/${{ steps.pr.outputs.pr_repo }}/pulls/${{ steps.pr.outputs.pr_number }}) - echo "$pr_json" | jq -r '.title' > pr_title.txt - echo "$pr_json" | jq -r '.body // ""' > pr_body.txt - else - printf '%s' "${{ github.event.pull_request.title }}" > pr_title.txt - printf '%s' "${{ github.event.pull_request.body }}" > pr_body.txt - fi + pr_json=$(gh api "repos/${PR_REPO}/pulls/${PR_NUMBER}") + printf '%s\n' "$pr_json" | jq -r '.title // ""' > pr_title.txt + printf '%s\n' "$pr_json" | jq -r '.body // ""' > pr_body.txt - name: Fetch scripts from github-actions branch run: |