Skip to content

Commit 45451e2

Browse files
GuanzhouSongguanzhousongmicrosoftCopilot
authored
Align website with the v0.116 package matrix (#164)
* Align website with v0.116 package matrix Publish only package combinations attached to the selected release, narrow the package finder to the Tier-1 matrix, and document source builds for other targets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Harden the v0.116 repository transition Keep retired repository URLs alive with empty metadata, make RPM signing failures fatal, validate package repositories before merge, and document the package withdrawal and source-build path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Guanzhou Song <guanzhousong@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2671593 commit 45451e2

12 files changed

Lines changed: 745 additions & 480 deletions

.github/scripts/download_packages.sh

Lines changed: 92 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ set -e
44
REPO="documentdb/documentdb"
55
OUT_DIR="out"
66
DOCUMENTDB_VERSION="${DOCUMENTDB_VERSION:-latest}"
7-
MULTI_VERSION="${MULTI_VERSION:-true}"
87
SUITE="${SUITE:-stable}"
98
COMPONENTS="${COMPONENTS:-main}"
109
ORIGIN="${ORIGIN:-DocumentDB}"
1110
DESCRIPTION="${DESCRIPTION:-DocumentDB APT and YUM Repository}"
11+
APT_METADATA_COMPONENTS="main deb11 deb12 deb13 ubuntu22 ubuntu24"
1212

1313
sign_deb_package() {
1414
local package_file="$1"
@@ -76,34 +76,20 @@ echo "Downloading packages from $REPO releases"
7676
# ---------------------------------------------------------------------------
7777
# Release selection
7878
#
79-
# The primary release supplies the site's release-info.json and is the version
80-
# users are told about. But a release only ships the distributions that were
81-
# in its own build matrix: v0.116-0, for example, ships Tier-1 (ubuntu24 +
82-
# rhel9) only, while v0.114-0 shipped seven distributions. Rebuilding the
83-
# repository from the primary release alone would therefore DELETE the
84-
# deb11/deb12/deb13/ubuntu22 components and the whole rhel8 repository from
85-
# documentdb.io, and every host already pointed at one of them would start
86-
# failing `apt update` with "Component 'ubuntu22' is not defined". That is a
87-
# client-visible outage, not a cosmetic regression.
88-
#
89-
# So the repository is built additively: the primary release fills every
90-
# distribution it ships, then progressively older releases are consulted ONLY
91-
# to fill distributions still missing. A distribution is claimed by the newest
92-
# release that ships it and is never overwritten by an older one. Once a
93-
# release ships every distribution again, the older ones stop contributing
94-
# by themselves - no cleanup required.
79+
# The selected release is the package repository's single source of truth.
80+
# Older releases must not fill gaps: those combinations are on-demand builds,
81+
# not assets of the current official release, and mixing them into the pool
82+
# makes stale versions look supported.
9583
# ---------------------------------------------------------------------------
96-
MAX_RELEASES="${MAX_RELEASES:-8}"
9784

9885
RELEASES_JSON=$(mktemp)
9986
if ! curl -fqs "https://api.github.com/repos/${REPO}/releases?per_page=100" > "$RELEASES_JSON"; then
10087
echo "Error: Could not fetch release list"
10188
exit 1
10289
fi
10390

104-
# Ordered list of tags to consider, newest first. Drafts and prereleases are
105-
# skipped: they are not what a repository-backed `apt install` should serve.
106-
TAG_LIST=$(DOCUMENTDB_VERSION="$DOCUMENTDB_VERSION" python3 - "$RELEASES_JSON" <<'PY'
91+
# Select exactly one published release. Drafts and prereleases are skipped.
92+
SELECTED_TAG=$(DOCUMENTDB_VERSION="$DOCUMENTDB_VERSION" python3 - "$RELEASES_JSON" <<'PY'
10793
import json, os, sys
10894
10995
releases = json.load(open(sys.argv[1]))
@@ -113,33 +99,27 @@ if not published:
11399
114100
requested = os.environ.get("DOCUMENTDB_VERSION", "latest")
115101
if requested != "latest":
116-
# The API returns releases newest-first.
117-
index = next((i for i, r in enumerate(published)
118-
if r["tag_name"] == requested), None)
119-
if index is None:
102+
selected = next((r for r in published if r["tag_name"] == requested), None)
103+
if selected is None:
120104
sys.exit(f"Error: Version {requested} not found in releases")
121-
# A pin means "serve this version". Only the pinned release and OLDER ones
122-
# may contribute: pulling gap-fillers from NEWER releases would defeat the
123-
# pin, and worse, it would mix releases that depend on each other. Pinning
124-
# to a release that predates the multi-package layout would otherwise add a
125-
# newer `documentdb` meta package whose `documentdb-N (>= X)` dependency the
126-
# pinned extension cannot satisfy - an unsatisfiable repository.
127-
ordered = published[index:]
128105
else:
129-
ordered = published
106+
selected = published[0]
130107
131-
print("\n".join(r["tag_name"] for r in ordered))
108+
print(selected["tag_name"])
132109
PY
133110
)
134111

135-
PRIMARY_TAG=$(printf '%s\n' "$TAG_LIST" | head -n 1)
112+
PRIMARY_TAG="$SELECTED_TAG"
136113
echo "Primary release: $PRIMARY_TAG"
137114

138115
# Packages already placed, keyed by "pool|name|arch". A newer release always
139116
# wins; an older release contributes only packages the newer ones do not
140117
# provide at all. That is what keeps `postgresql-16-documentdb` alive on
141118
# ubuntu24/rhel9 after v0.116-0 narrowed Tier 1 to PostgreSQL 17/18, instead of
142119
# silently deleting a package the install docs still tell people to use.
120+
# The paragraph above describes the removed gap-fill implementation. The
121+
# current implementation accepts assets only from PRIMARY_TAG and preserves
122+
# retired URLs with empty metadata rather than stale packages.
143123
SEEN_FILE=$(mktemp)
144124

145125
is_claimed() { case " $1 " in *" $2 "*) return 0 ;; *) return 1 ;; esac; }
@@ -223,13 +203,11 @@ rpm_pool_for() {
223203

224204
mkdir -p out/packages
225205

226-
for tag in $TAG_LIST; do
227-
MAX_RELEASES=$((MAX_RELEASES - 1))
228-
[ "$MAX_RELEASES" -lt 0 ] && break
206+
for tag in "$PRIMARY_TAG"; do
229207

230208
if ! release=$(curl -fqs "https://api.github.com/repos/${REPO}/releases/tags/$tag"); then
231-
echo "::warning::Could not fetch release $tag, skipping"
232-
continue
209+
echo "::error::Could not fetch selected release $tag"
210+
exit 1
233211
fi
234212

235213
ASSETS_FILE=$(mktemp)
@@ -263,7 +241,10 @@ for asset in data.get('assets', []):
263241
comp=$(deb_component_for "$filename")
264242
[ -z "$comp" ] && continue
265243
claim_package "$comp" "$filename" || continue
266-
wget -q -P out/packages "$download_url" || { echo "::warning::download failed: $filename"; continue; }
244+
wget -q -P out/packages "$download_url" || {
245+
echo "::error::Download failed: $filename"
246+
exit 1
247+
}
267248
GOT_DEB=1
268249
pool=$(deb_pool_for "$comp")
269250
mkdir -p "$pool"
@@ -296,7 +277,10 @@ for asset in data.get('assets', []):
296277
*) continue ;;
297278
esac
298279
if [ "$downloaded" -eq 0 ]; then
299-
wget -q -P out/packages "$download_url" || { echo "::warning::download failed: $filename"; break; }
280+
wget -q -P out/packages "$download_url" || {
281+
echo "::error::Download failed: $filename"
282+
exit 1
283+
}
300284
downloaded=1
301285
GOT_RPM=1
302286
fi
@@ -309,7 +293,12 @@ for asset in data.get('assets', []):
309293
*)
310294
# Non-package assets (SHA256SUMS, manifest.txt, ...) are mirrored only
311295
# for the primary release, which is what the site links to.
312-
[ "$tag" = "$PRIMARY_TAG" ] && wget -q -P out/packages "$download_url" ;;
296+
if [ "$tag" = "$PRIMARY_TAG" ]; then
297+
wget -q -P out/packages "$download_url" || {
298+
echo "::error::Download failed: $filename"
299+
exit 1
300+
}
301+
fi ;;
313302
esac
314303
done < "$ASSETS_FILE"
315304

@@ -353,7 +342,7 @@ for pool in "$RPM_POOL_RHEL8" "$RPM_POOL_RHEL9"; do
353342
done
354343

355344
if [ "$GOT_DEB" = "1" ]; then
356-
echo "Building APT repository with multiple distribution components..."
345+
echo "Building APT repository with active and retired compatibility components..."
357346
pushd out/deb >/dev/null
358347

359348
if [ -d "pool/ubuntu22" ] && [ "$(ls -A pool/ubuntu22/*.deb 2>/dev/null)" ]; then
@@ -472,35 +461,35 @@ if [ "$GOT_DEB" = "1" ]; then
472461
dpkg-scanpackages --arch arm64 pool/ubuntu24/ > "${DEB_DISTS_UBUNTU24_ARM64}/Packages"
473462
gzip -k -f "${DEB_DISTS_UBUNTU24_ARM64}/Packages"
474463
fi
464+
465+
# Keep retired component URLs valid without retaining packages from older
466+
# releases. Existing apt sources can refresh cleanly, but package lookup
467+
# returns no stale binaries.
468+
for component in $APT_METADATA_COMPONENTS; do
469+
for arch in amd64 arm64; do
470+
metadata_dir="${DEB_DISTS}/${component}/binary-${arch}"
471+
packages_file="${metadata_dir}/Packages"
472+
mkdir -p "$metadata_dir"
473+
if [ ! -f "$packages_file" ]; then
474+
: > "$packages_file"
475+
gzip -k -f "$packages_file"
476+
fi
477+
done
478+
done
475479

476480
pushd "${DEB_DISTS}" >/dev/null
477481

478482
echo "Creating Release file"
479-
# Determine which components we actually have
480-
AVAILABLE_COMPONENTS=""
481-
[ -d "${COMPONENTS}/binary-amd64" ] && AVAILABLE_COMPONENTS="${AVAILABLE_COMPONENTS} ${COMPONENTS}"
482-
[ -d "deb11/binary-amd64" ] && AVAILABLE_COMPONENTS="${AVAILABLE_COMPONENTS} deb11"
483-
[ -d "deb12/binary-amd64" ] && AVAILABLE_COMPONENTS="${AVAILABLE_COMPONENTS} deb12"
484-
[ -d "deb13/binary-amd64" ] && AVAILABLE_COMPONENTS="${AVAILABLE_COMPONENTS} deb13"
485-
[ -d "ubuntu22/binary-amd64" ] && AVAILABLE_COMPONENTS="${AVAILABLE_COMPONENTS} ubuntu22"
486-
[ -d "ubuntu24/binary-amd64" ] && AVAILABLE_COMPONENTS="${AVAILABLE_COMPONENTS} ubuntu24"
487-
AVAILABLE_COMPONENTS=$(echo $AVAILABLE_COMPONENTS | sed 's/^ *//')
488-
489-
# Determine available architectures
490-
AVAILABLE_ARCHITECTURES=""
491-
[ -d "${COMPONENTS}/binary-amd64" ] || [ -d "deb11/binary-amd64" ] || [ -d "deb12/binary-amd64" ] || [ -d "deb13/binary-amd64" ] || [ -d "ubuntu22/binary-amd64" ] || [ -d "ubuntu24/binary-amd64" ] && AVAILABLE_ARCHITECTURES="${AVAILABLE_ARCHITECTURES} amd64"
492-
[ -d "${COMPONENTS}/binary-arm64" ] || [ -d "deb11/binary-arm64" ] || [ -d "deb12/binary-arm64" ] || [ -d "deb13/binary-arm64" ] || [ -d "ubuntu22/binary-arm64" ] || [ -d "ubuntu24/binary-arm64" ] && AVAILABLE_ARCHITECTURES="${AVAILABLE_ARCHITECTURES} arm64"
493-
AVAILABLE_ARCHITECTURES=$(echo $AVAILABLE_ARCHITECTURES | sed 's/^ *//')
494483

495484
{
496485
echo "Origin: ${ORIGIN}"
497486
echo "Label: DocumentDB"
498487
echo "Suite: ${SUITE}"
499488
echo "Codename: ${SUITE}"
500489
echo "Version: 1.0"
501-
echo "Architectures: ${AVAILABLE_ARCHITECTURES}"
502-
echo "Components: ${AVAILABLE_COMPONENTS}"
503-
echo "Description: ${DESCRIPTION} - Multiple distributions supported"
490+
echo "Architectures: amd64 arm64"
491+
echo "Components: ${APT_METADATA_COMPONENTS}"
492+
echo "Description: ${DESCRIPTION}"
504493
echo "Date: $(date -Ru)"
505494
generate_hashes MD5Sum md5sum
506495
generate_hashes SHA1 sha1sum
@@ -526,7 +515,7 @@ if [ "$GOT_DEB" = "1" ]; then
526515
popd >/dev/null
527516

528517

529-
echo "APT repository built successfully with multiple distribution support"
518+
echo "APT repository built successfully"
530519
fi
531520

532521
if [ "$GOT_RPM" = "1" ]; then
@@ -544,52 +533,48 @@ if [ "$GOT_RPM" = "1" ]; then
544533
fi
545534

546535
for POOL in "$RHEL8_POOL" "$RHEL9_POOL"; do
547-
if [ -d "$POOL" ] && [ "$(find "$POOL" -name "*.rpm" -type f | wc -l)" -gt 0 ]; then
548-
echo "Processing YUM repository: $POOL"
549-
pushd "$POOL" >/dev/null
550-
551-
if [ -n "$GPG_FINGERPRINT" ]; then
552-
for rpm_file in *.rpm; do
553-
rpm --define "%_signature gpg" --define "%_gpg_name ${GPG_FINGERPRINT}" --addsign "$rpm_file" 2>/dev/null || true
554-
done
555-
fi
556-
557-
echo "Running createrepo_c in $(pwd)"
558-
if createrepo_c .; then
559-
echo "Repository metadata created successfully"
560-
ls -la repodata/ 2>/dev/null || echo "No repodata directory found"
561-
else
562-
echo "ERROR: createrepo_c failed for $POOL"
563-
fi
564-
565-
if [ -n "$GPG_FINGERPRINT" ] && [ -f repodata/repomd.xml ]; then
566-
gpg --default-key "$GPG_FINGERPRINT" --detach-sign --armor repodata/repomd.xml 2>/dev/null || true
567-
fi
568-
569-
popd >/dev/null
570-
else
571-
echo "Skipping $POOL: directory not found or no RPM files"
536+
mkdir -p "$POOL"
537+
echo "Processing YUM repository: $POOL"
538+
pushd "$POOL" >/dev/null
539+
540+
if [ -n "$GPG_FINGERPRINT" ]; then
541+
for rpm_file in *.rpm; do
542+
[ -f "$rpm_file" ] || continue
543+
rpm --define "%_signature gpg" --define "%_gpg_name ${GPG_FINGERPRINT}" --addsign "$rpm_file"
544+
signature=$(rpm -qp --qf '%{RSAHEADER:pgpsig}' "$rpm_file" 2>/dev/null)
545+
if [ -z "$signature" ] || [ "$signature" = "(none)" ]; then
546+
echo "::error::$rpm_file was not signed"
547+
exit 1
548+
fi
549+
done
572550
fi
551+
552+
echo "Running createrepo_c in $(pwd)"
553+
createrepo_c .
554+
555+
if [ -n "$GPG_FINGERPRINT" ]; then
556+
gpg --batch --yes --default-key "$GPG_FINGERPRINT" \
557+
--detach-sign --armor repodata/repomd.xml
558+
fi
559+
560+
popd >/dev/null
573561
done
574562

575-
# Create main repository for backward compatibility
576-
if [ -d "$RHEL8_POOL" ] && [ "$(find "$RHEL8_POOL" -name "*.rpm" -type f | wc -l)" -gt 0 ]; then
577-
echo "Creating main YUM repository"
578-
mkdir -p "$MAIN_POOL"
563+
# Keep the legacy main URL valid. It mirrors RHEL 8 only when the selected
564+
# release actually contains RHEL 8 packages; otherwise it is an empty
565+
# compatibility repository.
566+
echo "Creating main YUM compatibility repository"
567+
mkdir -p "$MAIN_POOL"
568+
if [ "$(find "$RHEL8_POOL" -name "*.rpm" -type f | wc -l)" -gt 0 ]; then
579569
cp "$RHEL8_POOL"/*.rpm "$MAIN_POOL"/ 2>/dev/null || true
580-
pushd "$MAIN_POOL" >/dev/null
581-
echo "Running createrepo_c for main repository in $(pwd)"
582-
if createrepo_c .; then
583-
echo "Main repository metadata created successfully"
584-
ls -la repodata/ 2>/dev/null || echo "No repodata directory found"
585-
else
586-
echo "ERROR: createrepo_c failed for main repository"
587-
fi
588-
if [ -n "$GPG_FINGERPRINT" ] && [ -f repodata/repomd.xml ]; then
589-
gpg --default-key "$GPG_FINGERPRINT" --detach-sign --armor repodata/repomd.xml 2>/dev/null || true
590-
fi
591-
popd >/dev/null
592570
fi
571+
pushd "$MAIN_POOL" >/dev/null
572+
createrepo_c .
573+
if [ -n "$GPG_FINGERPRINT" ]; then
574+
gpg --batch --yes --default-key "$GPG_FINGERPRINT" \
575+
--detach-sign --armor repodata/repomd.xml
576+
fi
577+
popd >/dev/null
593578

594579
echo "YUM repositories built successfully"
595580
fi
@@ -598,6 +583,7 @@ fi
598583
echo "Package repository setup complete!"
599584
echo ""
600585
echo "Repository URLs:"
601-
echo " APT: https://documentdb.io/deb stable main"
602-
echo " YUM: https://documentdb.io/rpm/rhel8 (or /rhel9, /main)"
586+
echo " APT: https://documentdb.io/deb stable ubuntu24"
587+
echo " YUM: https://documentdb.io/rpm/rhel9"
588+
echo " Retired URLs retain empty metadata for package-manager compatibility."
603589
echo " Browse: https://documentdb.io/packages/"

0 commit comments

Comments
 (0)