[dbscripts,v2,2/3] db-update: die when trying to update a package without updating a pending rebuild

Message ID 20190110185828.22421-1-eschwartz@archlinux.org
State Accepted, archived
Headers show
Series None | expand

Commit Message

Emil Velikov via arch-projects Jan. 10, 2019, 6:58 p.m. UTC
A semi-common pattern is for one maintainer to stage a rebuild of a
package due to e.g. cascading repository-wide python/boost/whatever
rebuilds, and then for the original maintainer of the package to not
notice and update the package in the stable repo, leaving an out of date
rebuild in staging or testing.

Then the the out of date package gets moved and ends up breaking things,
possibly via a package downgrade, possibly via breaking compatibility
with a much more targeted rebuild uploaded all at once. Ultimately,
Things Happen™ and the repository hierarchy gets broken.

Prevent this by enforcing for all packages that exist in
multiple levels of the repo: staging -> testing -> stable

That updates to one must come with an update to all the others.

Signed-off-by: Eli Schwartz <eschwartz@archlinux.org>
---

v2: add check for stable & staging, add relevant testsuite, fix
incorrectly accessed array.

 db-functions              | 25 +++++++++++++++++++++++++
 db-update                 |  3 +++
 test/cases/db-update.bats | 27 +++++++++++++++++++++++++++
 test/lib/common.bash      |  2 +-
 4 files changed, 56 insertions(+), 1 deletion(-)

Patch

diff --git a/db-functions b/db-functions
index 0e4dd939..5c363578 100644
--- a/db-functions
+++ b/db-functions
@@ -377,6 +377,31 @@  check_pkgrepos() {
 	return 0
 }
 
+check_stagingrepos() {
+	local pkgfile=${1}
+	local pkgrepo=${2}
+	local pkgname=$(getpkgname "${pkgfile}")
+	local pkgarch=$(getpkgarch "${pkgfile}")
+	local candidate candidates=()
+
+	if in_array "${pkgrepo}" "${STABLE_REPOS[@]}"; then
+		candidates+=($(find_repo_for_package "${pkgname}" "${pkgarch}" "${TESTING_REPOS[@]}"))
+	fi
+	if in_array "${pkgrepo}" "${STABLE_REPOS[@]}" "${TESTING_REPOS[@]}"; then
+		candidates+=($(find_repo_for_package "${pkgname}" "${pkgarch}" "${STAGING_REPOS[@]}"))
+	fi
+	(( ${#candidates[@]} == 0 )) && return 0
+
+	printf '%s\n' "${candidates[@]%-*}"
+	for candidate in "${candidates[@]}"; do
+		for candidate in "${STAGING}/${candidate%-*}"/*${PKGEXTS}; do
+			[[ ${pkgname} = $(getpkgname "${candidate}" 2>/dev/null) ]] && return 0
+		done
+	done
+
+	return 1
+}
+
 #usage: chk_license ${license[@]}"
 chk_license() {
 	local l
diff --git a/db-update b/db-update
index 4848fef0..b85295f3 100755
--- a/db-update
+++ b/db-update
@@ -52,6 +52,9 @@  for repo in "${repos[@]}"; do
 			if ! check_pkgrepos "${pkg}"; then
 				die "Package %s already exists in another repository" "$repo/${pkg##*/}"
 			fi
+			if ! missing_repo="$(check_stagingrepos "${pkg}" "${repo}")"; then
+				die "Package %s in %s needs to be updated in unstable repos as well: %s" "${pkg}" "${repo}" "${missing_repo}"
+			fi
 			if ! check_packager "${pkg}"; then
 				die "Package %s does not have a valid packager" "$repo/${pkg##*/}"
 			fi
diff --git a/test/cases/db-update.bats b/test/cases/db-update.bats
index e1782a59..ddeb4060 100644
--- a/test/cases/db-update.bats
+++ b/test/cases/db-update.bats
@@ -94,6 +94,33 @@  load ../lib/common
 	[[ -f ${ARCHIVE_BASE}/packages/p/pkg-any-a/pkg-any-a-1-1-any${PKGEXT}.sig ]]
 }
 
+@test "update any package to stable repo without updating testing package fails" {
+	releasePackage extra pkg-any-a
+	db-update
+	updatePackage pkg-any-a
+	releasePackage testing pkg-any-a
+	db-update
+	updatePackage pkg-any-a
+	releasePackage extra pkg-any-a
+
+	run db-update
+	[ "$status" -ne 0 ]
+}
+
+@test "update any package to stable repo without updating staging package fails" {
+	releasePackage extra pkg-any-a
+	db-update
+	updatePackage pkg-any-a
+	releasePackage staging pkg-any-a
+	db-update
+	updatePackage pkg-any-a
+	releasePackage extra pkg-any-a
+
+	run db-update
+	echo "$output"
+	[ "$status" -ne 0 ]
+}
+
 @test "update same any package to same repository fails" {
 	releasePackage extra pkg-any-a
 	db-update
diff --git a/test/lib/common.bash b/test/lib/common.bash
index b99ad15f..02693809 100644
--- a/test/lib/common.bash
+++ b/test/lib/common.bash
@@ -102,7 +102,7 @@  setup() {
 	ARCHIVE_BASE="${TMP}/archive"
 	ARCHIVEUSER=""
 	SVNREPO="file://${TMP}/svn-packages-repo"
-	PKGREPOS=('core' 'extra' 'testing')
+	PKGREPOS=('core' 'extra' 'testing' 'staging')
 	PKGPOOL='pool/packages'
 	SRCPOOL='sources/packages'
 	STAGING_REPOS=('staging')