Skip to content

Commit 8ac03fc

Browse files
authored
Merge pull request #410 from nirmoy/patchscan-pr-validation-fixes
patchscan: fix PR body quoting and provenance checks
2 parents 68203dd + e20ac88 commit 8ac03fc

2 files changed

Lines changed: 53 additions & 23 deletions

File tree

.github/scripts/validate-pr

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,33 @@ def get_cherry_pick_sha(message):
3333
m = re.search(r'\(cherry picked from commit ([a-fA-F0-9]+)\)', message)
3434
return m.group(1) if m else None
3535

36+
def get_backported_commit_sha(message):
37+
m = re.search(r'\(backported from commit ([a-fA-F0-9]+)\)', message)
38+
return m.group(1) if m else None
39+
40+
def get_upstream_commit_sha(message):
41+
for getter in (get_cherry_pick_sha, get_backported_commit_sha):
42+
sha = getter(message)
43+
if sha:
44+
return sha
45+
m = re.search(r'^[Uu]pstream commit ([a-fA-F0-9]+)', message, re.MULTILINE)
46+
return m.group(1) if m else None
47+
3648
def get_backport_url(message):
3749
m = re.search(r'\(backported from (https?://[^\)]+)\)', message)
3850
return m.group(1) if m else None
3951

4052
def is_sauce(subject):
4153
return bool(re.match(r'^NVIDIA:.*SAUCE:', subject))
4254

55+
def is_ubuntu_local(subject):
56+
"""Ubuntu-local commits with no upstream equivalent.
57+
58+
Catches 'UBUNTU: SAUCE: ...', 'UBUNTU: [Config] ...',
59+
'UBUNTU: [Packaging] ...', 'UBUNTU: Ubuntu-X.X.X-...', etc.
60+
"""
61+
return bool(re.match(r'^UBUNTU:\s', subject))
62+
4363
def is_revert(subject):
4464
return subject.startswith('Revert "')
4565

@@ -129,7 +149,7 @@ def describe_sob_chain_backport(message):
129149
return "ok, backporter: {}".format(' '.join(names))
130150

131151

132-
COL_WIDTHS = [12, 45, 10, 7, 25]
152+
COL_WIDTHS = [12, 64, 10, 7, 25]
133153
HEADERS = ['Local', 'Referenced upstream / Patch subject', 'Patch-ID', 'Subject', 'SoB chain']
134154

135155
def _hline(left, sep, right):
@@ -159,6 +179,11 @@ def print_digest_table(rows):
159179
print(_hline('└', '┴', '┘'))
160180

161181

182+
def format_upstream_ref(sha12, subject):
183+
"""Return compact digest text for a referenced upstream commit."""
184+
return "{} {}".format(sha12, subject)
185+
186+
162187
def _shorten_lkml_url(url):
163188
"""Shorten a lore.kernel.org URL to a compact display form."""
164189
m = re.search(r'lore\.kernel\.org/[^/]+/([^/]+)', url)
@@ -322,7 +347,7 @@ def build_digest(commits, repo, upstream_remote=None):
322347
errors = []
323348

324349
for commit in commits:
325-
src_sha = get_cherry_pick_sha(commit.message)
350+
src_sha = get_upstream_commit_sha(commit.message)
326351
bp_url = get_backport_url(commit.message)
327352

328353
# --- SAUCE / Revert: no upstream reference, show as informational row ---
@@ -336,6 +361,9 @@ def build_digest(commits, repo, upstream_remote=None):
336361
# Strip outer Revert "..." wrapper and SAUCE prefix for display
337362
inner = re.sub(r'^Revert\s+"', '', subj).rstrip('"')
338363
display = _norm_sauce_subject(inner) or inner
364+
elif is_ubuntu_local(subj):
365+
kind = 'UBUNTU'
366+
display = re.sub(r'^UBUNTU:\s*', '', subj)
339367
else:
340368
kind = 'SAUCE'
341369
display = _norm_sauce_subject(subj) or subj
@@ -411,6 +439,7 @@ def build_digest(commits, repo, upstream_remote=None):
411439
# Subject
412440
local_subj = subject_of(commit)
413441
upstream_subj = subject_of(upstream)
442+
upstream_ref = format_upstream_ref(upstream_sha12, upstream_subj)
414443
if local_subj == upstream_subj:
415444
subj_status = 'match'
416445
subj_error = False
@@ -427,7 +456,7 @@ def build_digest(commits, repo, upstream_remote=None):
427456
local_sha12, subject_of(commit)[:40], sob_status))
428457

429458
has_error = pid_error or subj_error or sob_error
430-
rows.append(dict(local=local_sha12, upstream=upstream_sha12,
459+
rows.append(dict(local=local_sha12, upstream=upstream_ref,
431460
patch_id=pid_status, subject=subj_status,
432461
sob=sob_status, error=has_error))
433462

@@ -460,20 +489,25 @@ def lint_commits(commits):
460489

461490
# Classification for R6/R7/R9/R10
462491
sauce = is_sauce(subject)
492+
ubuntu = is_ubuntu_local(subject)
463493
revert = is_revert(subject)
464494

465-
# R9: subject length — exempt SAUCE and Reverts of SAUCE; the mandatory
466-
# "NVIDIA: [VR: ]SAUCE:" prefix already consumes 15–20 characters.
495+
# R9: subject length — exempt SAUCE, UBUNTU local and Reverts of SAUCE;
496+
# the mandatory "NVIDIA: [VR: ]SAUCE:" / "UBUNTU: [Config]" prefix
497+
# already consumes 12–20 characters.
467498
revert_of_sauce = revert and bool(re.match(r'^Revert "NVIDIA:.*SAUCE:', subject))
468-
if len(subject) > 72 and not sauce and not revert_of_sauce:
499+
if len(subject) > 72 and not sauce and not ubuntu and not revert_of_sauce:
469500
warnings.append("W: {}: subject {} chars (>72)".format(label, len(subject)))
470-
cp_sha = get_cherry_pick_sha(commit.message)
501+
upstream_sha = get_upstream_commit_sha(commit.message)
502+
cp_sha = get_cherry_pick_sha(commit.message)
471503
bp_url = get_backport_url(commit.message)
472504

473-
# R6: non-SAUCE, non-Revert commits must have an upstream reference trailer
474-
if not sauce and not revert and cp_sha is None and bp_url is None:
505+
# R6: non-SAUCE, non-UBUNTU, non-Revert commits must have an upstream
506+
# reference trailer. UBUNTU local commits (e.g. UBUNTU: [Config]) have
507+
# no upstream equivalent.
508+
if not sauce and not ubuntu and not revert and upstream_sha is None and bp_url is None:
475509
errors.append(
476-
"E: {}: not SAUCE/Revert but has no upstream reference trailer"
510+
"E: {}: not SAUCE/UBUNTU/Revert but has no upstream reference trailer"
477511
" (cherry picked from commit ... or backported from ...)".format(label))
478512

479513
# R7: detect wrong trailer for LKML in-review backports
@@ -508,19 +542,18 @@ def check_pr_metadata(pr_title, pr_body_path, base_branch):
508542
warnings.append(
509543
"W: PR title missing [<branch>] prefix: \"{}\"".format(pr_title[:80]))
510544

511-
# R3: BugLink required for tracked branches
545+
# R3: Launchpad bug link required for tracked branches
512546
if pr_body_path and base_branch and TRACKED_BRANCH_RE.match(base_branch):
513547
try:
514548
body = open(pr_body_path).read()
515549
except OSError as e:
516550
errors.append("E: cannot read --pr-body {}: {}".format(pr_body_path, e))
517551
body = ''
518-
buglink_re = re.compile(
519-
r'^(?:BugLink:|LP:)\s+https://bugs\.launchpad\.net/', re.MULTILINE)
552+
buglink_re = re.compile(r'https://bugs\.launchpad\.net/')
520553
if not buglink_re.search(body):
521554
errors.append(
522-
"E: PR targets {} but body has no 'BugLink:' or 'LP:'"
523-
" https://bugs.launchpad.net/... line".format(base_branch))
555+
"E: PR targets {} but body has no"
556+
" https://bugs.launchpad.net/... link".format(base_branch))
524557

525558
return warnings, errors
526559

.github/workflows/patchscan.yml

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,12 @@ jobs:
8080
- name: Write PR title and body to files
8181
env:
8282
GH_TOKEN: ${{ github.token }}
83+
PR_REPO: ${{ steps.pr.outputs.pr_repo }}
84+
PR_NUMBER: ${{ steps.pr.outputs.pr_number }}
8385
run: |
84-
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
85-
pr_json=$(gh api repos/${{ steps.pr.outputs.pr_repo }}/pulls/${{ steps.pr.outputs.pr_number }})
86-
echo "$pr_json" | jq -r '.title' > pr_title.txt
87-
echo "$pr_json" | jq -r '.body // ""' > pr_body.txt
88-
else
89-
printf '%s' "${{ github.event.pull_request.title }}" > pr_title.txt
90-
printf '%s' "${{ github.event.pull_request.body }}" > pr_body.txt
91-
fi
86+
pr_json=$(gh api "repos/${PR_REPO}/pulls/${PR_NUMBER}")
87+
printf '%s\n' "$pr_json" | jq -r '.title // ""' > pr_title.txt
88+
printf '%s\n' "$pr_json" | jq -r '.body // ""' > pr_body.txt
9289
9390
- name: Fetch scripts from github-actions branch
9491
run: |

0 commit comments

Comments
 (0)