From 18e4dc404990b7e565c5c9e1b137365658086c3f Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Tue, 28 Apr 2026 07:53:00 -0700 Subject: [PATCH 1/3] validate-pr: relax Launchpad link check; recognize UBUNTU-local commits Two improvements addressing false-positive failures on tracked-branch PRs: 1. Launchpad bug link: drop the requirement that the URL appear on a line prefixed with 'BugLink:' or 'LP:'. The check now only ensures a https://bugs.launchpad.net/... URL exists somewhere in the PR body. Avoids false negatives when authors paste the link in prose. 2. UBUNTU-local commits (e.g. 'UBUNTU: [Config] ...', 'UBUNTU: [Packaging] ...', 'UBUNTU: SAUCE: ...') have no upstream equivalent and previously triggered R6 ("not SAUCE/Revert but has no upstream reference trailer"). Add an is_ubuntu_local() helper that matches the 'UBUNTU: ' prefix; exempt those commits from R6 and R9, label them [UBUNTU] in the digest table, and verify only the Signed-off-by trailer is present. Signed-off-by: Nirmoy Das --- .github/scripts/validate-pr | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/.github/scripts/validate-pr b/.github/scripts/validate-pr index 9c068560f9563..c2fa29448eeb0 100755 --- a/.github/scripts/validate-pr +++ b/.github/scripts/validate-pr @@ -40,6 +40,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 "') @@ -336,6 +344,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 +471,24 @@ 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) 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 cp_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 +523,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 From ad1b1399d4b0b2b5bf9340d221cc890a86ed3a9d Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Wed, 6 May 2026 11:24:25 -0700 Subject: [PATCH 2/3] patchscan: safely write PR metadata files --- .github/workflows/patchscan.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) 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: | From f71d62e546dce54bd55b19d127e8e6c506507d8a Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Wed, 6 May 2026 11:41:31 -0700 Subject: [PATCH 3/3] validate-pr: recognize backported commit trailers --- .github/scripts/validate-pr | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/scripts/validate-pr b/.github/scripts/validate-pr index c2fa29448eeb0..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 @@ -330,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 --- @@ -480,13 +492,14 @@ def lint_commits(commits): revert_of_sauce = revert and bool(re.match(r'^Revert "NVIDIA:.*SAUCE:', subject)) 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-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 cp_sha is None and bp_url is None: + if not sauce and not ubuntu and not revert and upstream_sha is None and bp_url is None: errors.append( "E: {}: not SAUCE/UBUNTU/Revert but has no upstream reference trailer" " (cherry picked from commit ... or backported from ...)".format(label))