diff mbox series

[v2,1/3] base.bbclass: warn when SRCREV is missing for SCM URIs at parse time

Message ID 20260519100904.235971-2-saisneha196@gmail.com
State New
Headers show
Series Add missing SRCREV check for SCM URIs | expand

Commit Message

Sai Sneha May 19, 2026, 10:09 a.m. UTC
A recipe with a git:// (or other SCM) URI in SRC_URI must have a
corresponding SRCREV set. Without it, BitBake performs a live query
on the remote repository at every parse, breaking reproducibility
and causing parse failures under BB_NO_NETWORK=1.

The trivial fix of checking SRCREV in insane.bbclass do_recipe_qa
fails because fetcher_hashes_dummyfunc[vardepvalue] expands SRCREV
at parse time before QA checks run, causing a FetchError that halts
parsing entirely. This was identified by Corentin Guillevic's RFC
series and confirmed by Mathieu Dubois-Briand's autobuilder testing.

The fix intercepts at the vardepvalue expansion point by introducing
check_srcrev_set() which inspects SRC_URI and SRCREV using unexpanded
getVar() calls (False flag). This avoids triggering get_autorev() or
any live network fetch. The function is called conditionally:

  fetcher_hashes_dummyfunc[vardepvalue] =     "${@bb.fetch.get_hashvalue(d) if check_srcrev_set(d) else ''}"

Note on design choice: we intentionally use d.getVar(candidate, False)
rather than srcrev_internal_helper() because the latter expands SRCREV,
triggering get_autorev() and live network fetches -- the exact problem
this patch fixes. Our fallback chain mirrors BitBake's internal
resolution order exactly, as confirmed by the error messages BitBake
itself produces:
  SRCREV_default:pn-X, SRCREV_default, SRCREV:pn-X, SRCREV

The check handles:
- Full SRCREV resolution fallback chain matching BitBake's behavior
- Multiple SCM URIs in one recipe (all reported, not just the first)
- Inline rev= parameter in URI (skipped, no SRCREV needed)
- AUTOREV passthrough (legitimate devtool usage, let through)
- Parse-time severity respecting WARN_QA/ERROR_QA layer config

Note: parse-time warnings intentionally duplicate the QA-time warnings
added in insane.bbclass. This is necessary because CI pipelines running
'bitbake --parse-only' with BB_NO_NETWORK=1 (the original motivation
from Ross Burton) would miss the issue entirely if only QA-time
warnings existed. This pattern is already established in the codebase
(e.g. src-uri-bad fires at both parse and QA time).

Fixes: https://bugzilla.yoctoproject.org/show_bug.cgi?id=16051
Signed-off-by: Sai Sneha <saisneha196@gmail.com>
---
 meta/classes-global/base.bbclass | 40 ++++++++++++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/meta/classes-global/base.bbclass b/meta/classes-global/base.bbclass
index 62f2814bb7..66b2e25f71 100644
--- a/meta/classes-global/base.bbclass
+++ b/meta/classes-global/base.bbclass
@@ -165,13 +165,49 @@  def setup_hosttools_dir(dest, toolsvar, d, fatal=True):
     if notfound and fatal:
         bb.fatal("The following required tools (as specified by HOSTTOOLS) appear to be unavailable in PATH, please install them in order to proceed:\n  %s" % " ".join(notfound))
 
+def check_srcrev_set(d):
+    import bb.fetch2
+    src_uri = (d.getVar('SRC_URI', False) or '').split()
+    pn = d.getVar('PN')
+    found_issue = False
+    for uri in src_uri:
+        try:
+            (scheme, _, _, _, _, params) = bb.fetch2.decodeurl(uri)
+        except Exception:
+            continue
+        if scheme not in ('git', 'gitsm', 'hg', 'svn'):
+            continue
+        if params.get('rev', ''):
+            continue
+        name = params.get('name', '') or 'default'
+        candidates = [
+            'SRCREV_%s:pn-%s' % (name, pn),
+            'SRCREV_%s' % name,
+            'SRCREV:pn-%s' % pn,
+            'SRCREV',
+        ]
+        raw = None
+        for candidate in candidates:
+            raw = d.getVar(candidate, False)
+            if raw:
+                break
+        if not raw or raw == 'INVALID':
+            found_issue = True
+            if bb.utils.contains('ERROR_QA', 'missing-srcrev', True, False, d):
+                bb.error("%s: %s not set for %s" % (pn, candidates[-1], uri))
+            elif bb.utils.contains('WARN_QA', 'missing-srcrev', True, False, d):
+                bb.warn("%s: %s not set for %s" % (pn, candidates[-1], uri))
+        elif '${AUTOREV}' in raw:
+            return True
+    return not found_issue
+        
+
 # We can't use vardepvalue against do_fetch directly since that would overwrite
 # the other task dependencies so we use an indirect function.
 python fetcher_hashes_dummyfunc() {
     return
 }
-fetcher_hashes_dummyfunc[vardepvalue] = "${@bb.fetch.get_hashvalue(d)}"
-
+fetcher_hashes_dummyfunc[vardepvalue] = "${@bb.fetch.get_hashvalue(d) if check_srcrev_set(d) else ''}"
 addtask fetch
 do_fetch[dirs] = "${DL_DIR}"
 do_fetch[file-checksums] = "${@bb.fetch.get_checksum_file_list(d)}"