From e768de4978534177f36aabacacdbc104608bc252 Mon Sep 17 00:00:00 2001 From: Kemal Buyukkaya Date: Fri, 14 Aug 2026 13:33:13 +0000 Subject: [PATCH 1/2] build-pg-focal: refresh the quilt series against the upstream being built PG14/15/16 could not build 14.24/15.19/16.15: those minors add output_plugin_libraries to postgresql.conf.sample directly below the extension_destdir hunk's trailing context, so the frozen focal-era patch no longer matches verbatim. The pipeline's own gate could not see it. Step [4/6] ran "quilt push -a", and quilt applies with up to two lines of fuzz: Hunk #1 succeeded at 726 with fuzz 2 (offset 1 line) Step [6/6] then let dpkg-source --before-build replay the same series with "patch -t -F 0", which allows no fuzz at all: Hunk #1 FAILED at 725 dpkg-source: info: the patch has fuzz which is not allowed, or is malformed dpkg-buildpackage: error: dpkg-source --before-build . subprocess returned exit status 2 So the gate passed and the build died 25 seconds later, one apt-install of Build-Depends in. PG13 was unaffected only because 13.23 does not touch postgresql.conf.sample. Pairing a moving orig tarball with frozen debian/ packaging makes this recur on every minor, so [4/6] now applies the series with fuzz allowed and refreshes each patch as it goes ("quilt push -a --refresh"), which rewrites patch context for the upstream at hand without changing a single +/- line, then re-applies at --fuzz=0 to assert exactly what dpkg-source is about to check. Patches that needed fuzz are named in the log: such a hunk was placed on less context than its author wrote and is worth an eyeball. Refreshing uses PGDG's own patch style (a/ b/ prefixes, no timestamps, no Index:, @@ function context) so a refreshed patch still diffs minimally against the shipped one. PG_DROP_PATCHES keeps its narrower job: patches that cannot be applied at all, such as hurd-iovec, merged upstream as of 16.14. Verified locally with podman for 14.24, 15.19 and 16.15. The refreshed series produces a source tree byte-identical to the one the original series produces with fuzz, dpkg-source accepts it, and each major builds its full 23-package set against focal's libllvm10. The combined 47-package set installs into a stock ubuntu:20.04 with all three clusters online and JIT available, and every shipped postgresql.conf.sample carries both extension_destdir and upstream's new output_plugin_libraries. --- scripts/build_pg_focal | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/scripts/build_pg_focal b/scripts/build_pg_focal index ae29208d..b1da303f 100755 --- a/scripts/build_pg_focal +++ b/scripts/build_pg_focal @@ -93,12 +93,11 @@ ORIG_SHA256="${PG_ORIG_SHA256:-}" DEBIAN_SHA256="${PG_DEBIAN_SHA256:-}" # Patches in the frozen focal debian/ packaging that no longer apply to newer -# upstream (e.g. merged upstream). Space-separated; each is dropped from the -# quilt series only if present, so the default is safe for every major: +# upstream *at all* (e.g. merged upstream). Space-separated; each is dropped from +# the quilt series only if present, so the default is safe for every major: # * hurd-iovec was merged upstream as of 16.14 (pg_iovec.h guards IOV_MAX), # so it fails to apply on 16.x/17.x but is absent from 13/14/15 packaging. -# If a future minor introduces new drift, append the offending patch name here -# (or via the PG_DROP_PATCHES env) -- no other code change required. +# Context drift needs no entry here -- [4/6] refreshes the series instead. PG_DROP_PATCHES="${PG_DROP_PATCHES:-hurd-iovec}" # Set RUN_TESTS=1 to run the upstream regression suite (slower, needs more deps). @@ -183,11 +182,35 @@ for p in ${PG_DROP_PATCHES}; do fi done -echo "==> [4/6] Verify the quilt patch series applies cleanly to ${UPSTREAM}" +echo "==> [4/6] Apply & refresh the quilt patch series against ${UPSTREAM}" +# Frozen debian/ + newer upstream means patch *context* drifts: 14.24/15.19/16.15 +# added output_plugin_libraries inside the extension_destdir hunk's trailing +# context. quilt applies that with fuzz; dpkg-source replays the same series in +# [6/6] with "patch -F 0" and refuses it. So refresh the series against this +# upstream (context only, no +/- line changes) and gate on zero fuzz here. export QUILT_PATCHES=debian/patches +export QUILT_REFRESH_ARGS="-p ab --no-timestamps --no-index" # keep PGDG's patch style +export QUILT_DIFF_OPTS="-p" # ... including @@ function context if [ -s debian/patches/series ]; then - quilt push -a - quilt pop -a + push_log="${WORK}/quilt-push-pg${PG_MAJOR}.log" + quilt push -a --refresh 2>&1 | tee "${push_log}" + quilt pop -a > /dev/null + + # A fuzzy hunk was placed on less context than its author wrote: worth a look. + if grep -q 'with fuzz' "${push_log}"; then + echo " NOTE: refreshed patches that no longer match ${UPSTREAM} verbatim:" + awk '/^Applying patch / { p = $3 } + /with fuzz/ { print " " p ": " $0 }' "${push_log}" + fi + + echo " verifying the refreshed series applies with zero fuzz (as dpkg-source does)" + if ! quilt push -a --fuzz=0 > "${WORK}/quilt-verify-pg${PG_MAJOR}.log" 2>&1; then + cat "${WORK}/quilt-verify-pg${PG_MAJOR}.log" >&2 + echo "ERROR: series does not apply to ${UPSTREAM} at zero fuzz; dpkg-source would" >&2 + echo " reject it too. Fix or drop the offending patch (PG_DROP_PATCHES)." >&2 + exit 1 + fi + quilt pop -a > /dev/null fi echo "==> [5/6] Set version to ${TARGET_VERSION} and install Build-Depends" From f1439f825c6429617a59854d22e59db8a9d126f5 Mon Sep 17 00:00:00 2001 From: Kemal Buyukkaya Date: Mon, 17 Aug 2026 11:57:43 +0000 Subject: [PATCH 2/2] build-pg-focal: annotate fuzzy hunks, and stop quilt.quiltrc overriding us Review feedback on #1208: --refresh turns the fuzz case from a build failure into a log line, and the --fuzz=0 gate structurally cannot catch a mis-placed hunk because refresh has already rewritten the context to match. Low probability with PGDG's small patches, but it was the one signal this change made quieter. Fuzz now raises a CI annotation naming the patch and the file: ::warning::PG14: extension_destdir needed fuzz against 14.24 in src/backend/utils/misc/postgresql.conf.sample -- Hunk #1 succeeded at 726 with fuzz 2 (offset 1 line). One per hunk rather than a grouped summary, so the run page names what drifted without anyone opening a 9000-line log. The runner parses these from the container's stdout, as scripts/smoke_test_focal_debs already relies on. Expect one per fuzzing major on every run: the focal packaging is frozen, so that drift is permanent until the pin moves. A patch that does not apply at all -- the hurd-iovec class, and the likelier future failure -- died via set -e with nothing but quilt's "does not apply (enforce with -f)". It now points at PG_DROP_PATCHES, which is the fix and is not discoverable from quilt's message. Also QUILTRC=/dev/null. patchfns sources /etc/quilt.quiltrc *after* the environment (quilt/scripts/patchfns:31) using plain assignments, so focal's rc silently won: QUILT_REFRESH_ARGS became "--no-timestamps --backup", dropping "-p ab --no-index". Refreshed patches came out in Index:/src.orig style rather than PGDG's a/ b/, plus a debian/patches/*~ backup for every patch. Harmless to the build -- dpkg-source strips -p1 either way, which is why the green run hid it -- but it made the comment on those very lines false. My earlier verification could not see it: the host harness ran quilt unpacked into a prefix, with no /etc/quilt.quiltrc to source. Verified in the focal image, which is the environment that has the rc file: patches refresh in a/ b/ style with no backup litter, dpkg-source accepts at zero fuzz, the injected non-applying patch prints the hint and exits 1, and a full PG14 rebuild yields the same 23 packages at the same versions as before. --- scripts/build_pg_focal | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/scripts/build_pg_focal b/scripts/build_pg_focal index b1da303f..dce3ae1d 100755 --- a/scripts/build_pg_focal +++ b/scripts/build_pg_focal @@ -188,20 +188,27 @@ echo "==> [4/6] Apply & refresh the quilt patch series against ${UPSTREAM}" # context. quilt applies that with fuzz; dpkg-source replays the same series in # [6/6] with "patch -F 0" and refuses it. So refresh the series against this # upstream (context only, no +/- line changes) and gate on zero fuzz here. -export QUILT_PATCHES=debian/patches +export QUILTRC=/dev/null # /etc/quilt.quiltrc is sourced after +export QUILT_PATCHES=debian/patches # ... the environment and would win export QUILT_REFRESH_ARGS="-p ab --no-timestamps --no-index" # keep PGDG's patch style export QUILT_DIFF_OPTS="-p" # ... including @@ function context if [ -s debian/patches/series ]; then push_log="${WORK}/quilt-push-pg${PG_MAJOR}.log" - quilt push -a --refresh 2>&1 | tee "${push_log}" + if ! quilt push -a --refresh 2>&1 | tee "${push_log}"; then + echo "ERROR: a patch does not apply to ${UPSTREAM} at all. If upstream merged or" >&2 + echo " obsoleted it, drop it via PG_DROP_PATCHES." >&2 + exit 1 + fi quilt pop -a > /dev/null - # A fuzzy hunk was placed on less context than its author wrote: worth a look. - if grep -q 'with fuzz' "${push_log}"; then - echo " NOTE: refreshed patches that no longer match ${UPSTREAM} verbatim:" - awk '/^Applying patch / { p = $3 } - /with fuzz/ { print " " p ": " $0 }' "${push_log}" - fi + # A fuzzy hunk was placed on less context than its author wrote, and --refresh + # bakes that placement in, so the gate below can no longer catch it: annotate + # the run rather than leave it buried in the build log. + awk -v m="${PG_MAJOR}" -v u="${UPSTREAM}" ' + /^Applying patch / { p = $3 } + /^patching file / { f = substr($0, 15) } + /with fuzz/ { print "::warning::PG" m ": " p " needed fuzz against " u " in " f " -- " $0 } + ' "${push_log}" echo " verifying the refreshed series applies with zero fuzz (as dpkg-source does)" if ! quilt push -a --fuzz=0 > "${WORK}/quilt-verify-pg${PG_MAJOR}.log" 2>&1; then