fix: resolve full rebuild mode bugs in APT repository workflow (issue #24)#25
Conversation
Fixes two critical bugs causing packages to be removed from non-stable distributions: 1. Full Rebuild Mode Incompatible with Per-Distribution Pools (Bug #24 Part 1) - Previous implementation (lines 230-237) hardcoded download_from_repo with "latest" tag for all distributions, placing all packages in pool/stable/main/ - Per-distribution pool structure (from PR #16) means each distribution scans only its own pool (e.g., trixie-unstable scans pool/trixie-unstable/main/) - Result: Non-stable distributions found no packages and became empty - Fix: Iterate through each distribution separately, determine channel from distribution name, set correct RELEASE_TAG (unstable=prerelease, stable=latest), and set TARGET_DIST so packages go to correct pools 2. Push Trigger Causes Unintended Full Rebuilds (Bug #24 Part 2) - Push events on main branch have no client_payload.repository - Missing TARGET_REPO triggers full rebuild mode - Every documentation/workflow change merged to main caused full rebuild - Result: Packages disappeared whenever unrelated changes were merged - Fix: Remove push trigger entirely. Rely on repository_dispatch from package repos and manual workflow_dispatch if needed Changes: - Remove push trigger (lines 9-11) - Rewrite full rebuild logic (lines 230-237 → 230-255) to: * Iterate through all distributions * Determine channel from distribution name * Set appropriate RELEASE_TAG per distribution * Export TARGET_DIST for download_from_repo function * Add logging to show which distributions are processed - Update full rebuild comments to reflect new behavior Testing Strategy (documented in PR): - Manual trigger of workflow_dispatch to verify full rebuild - Check logs show each distribution processed with correct channel/tag - Verify packages downloaded to correct pool directories - After merge, restore missing packages via targeted update from cockpit-apt Relates to #24 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
🔴 Critical Bug: Package Download/Copy MismatchTL;DR: The new full rebuild logic downloads packages correctly per-distribution, but the "Build APT repository structure" step copies ALL accumulated packages to only ONE distribution's pool (stable). The ProblemThe workflow has two separate steps with different contexts: Step 1: Download packages (lines 228-259) for dist in $ALL_DISTRIBUTIONS; do
export TARGET_DIST="$dist"
# Downloads packages to packages/ directory (accumulates!)
for repo in $ALL_REPOS; do
download_from_repo "$repo" "$RELEASE_TAG"
done
unset TARGET_DIST
doneStep 2: Build APT repository structure (lines 260-272) # NEW workflow step - different shell context!
TARGET_DIST="${{ steps.payload.outputs.distribution }}" # ← This is "stable" in full rebuild
cp packages/*.deb "apt-repo/pool/$TARGET_DIST/main/" # ← Copies ALL to stable pool onlyRoot Cause
Result
This is the same bug the PR is trying to fix! EvidenceCheck line 366 comment: "Each distribution's packages were downloaded to pool/$dist/main/" But that's not what the code does. The I'll provide the fix in a follow-up comment. |
✅ Proposed FixOption 1: Integrated Download-Copy-Build Loop (Recommended)Move the package copy and build operations into the download step: # In "Download packages" step (replace lines 228-259)
else
echo "=== Full Rebuild Mode ==="
echo "Processing each distribution separately..."
for dist in ${{ steps.payload.outputs.all_distributions }}; do
# Clean packages directory for this distribution
rm -rf packages/*
mkdir -p packages
# Determine channel from distribution name
if [[ "$dist" == *"-unstable"* ]] || [[ "$dist" == "unstable" ]]; then
DIST_CHANNEL="unstable"
RELEASE_TAG="prerelease"
else
DIST_CHANNEL="stable"
RELEASE_TAG="latest"
fi
echo ""
echo "--- Distribution: $dist (channel: $DIST_CHANNEL, release: $RELEASE_TAG) ---"
# Download packages for all repositories
echo "${{ steps.discover.outputs.repos }}" | while IFS= read -r repo; do
if [ -n "$repo" ]; then
download_from_repo "$repo" "$RELEASE_TAG"
fi
done
# Copy to this distribution's pool
if ls packages/*.deb 1> /dev/null 2>&1; then
mkdir -p "apt-repo/pool/$dist/main"
cp packages/*.deb "apt-repo/pool/$dist/main/"
echo "Copied $(ls packages/*.deb | wc -l) packages to $dist pool"
else
echo "No packages downloaded for $dist"
fi
done
fiThen in "Build APT repository structure" step, update lines 266-272: # Remove the copy operation entirely (or make it conditional on MODE)
if [ "$MODE" = "targeted" ]; then
# Copy new packages to distribution-specific pool (targeted mode only)
if ls packages/*.deb 1> /dev/null 2>&1; then
cp packages/*.deb "apt-repo/pool/$TARGET_DIST/main/"
echo "Copied $(ls packages/*.deb | wc -l) packages to $TARGET_DIST pool"
fi
else
echo "Full rebuild mode: packages already in distribution-specific pools"
fiWhy This Works
Option 2: Distribution-Specific Temp DirectoriesDownload to Testing Plan After Fix:
|
✅ Push Trigger Removal (Lines 9-11) - CORRECTThis part of the PR is good! Problem Identified CorrectlyRemoving the push trigger fixes Bug #2: - push:
- branches:
- - mainWhy This is Right
VerificationCheck git history for correlation:
Remaining Triggers (Correct)
Verdict: Push trigger removal is the right fix for Bug #2. No changes needed here. |
📋 PR Quality & DocumentationStrengths ✅
Weaknesses
|
🔍 Detailed Code AnalysisDownload Logic (Lines 228-255)What the code does: for dist in stable unstable bookworm-stable bookworm-unstable trixie-stable trixie-unstable; do
export TARGET_DIST="$dist"
# Loop through all repos, download to packages/
# packages/ ACCUMULATES across all distributions!
unset TARGET_DIST
doneKey insight: Result: By end of loop,
Build Logic (Lines 260-274)What the code does: # This is a NEW GitHub Actions step - different shell!
TARGET_DIST="${{ steps.payload.outputs.distribution }}" # ← "stable" in full rebuild
cp packages/*.deb "apt-repo/pool/$TARGET_DIST/main/" # ← ALL to stableKey insight:
Metadata Build (Lines 371-373)What the code does: for dist in all_distributions; do
build_distribution "$dist" "main"
# Line 294: dpkg-scanpackages pool/$dist/
doneResult:
The Core IssueThe PR attempts to fix per-distribution package handling in the download loop, but:
Analogy: Sorting mail into different bins but delivering all bins to one address. What Would WorkEach distribution needs its own complete cycle: Not: |
🎯 Summary & Action ItemsWhat This PR Gets Right ✅
What This PR Gets Wrong ❌
Critical Issue SeverityHIGH - This PR would:
Required Changes Before MergeApply the fix from my second comment to integrate download-copy-build into a single loop:
Testing Checklist Post-Fix
Estimated Fix Effort⏱️ ~15 minutes - Copy proposed code, adjust indentation, test locally if possible Overall Assessment: Good bug analysis, correct identification of root causes, but implementation incomplete due to missing step isolation consideration. Fixable with the changes I've outlined. |
…tion bug
Address critical review comment: GitHub Actions steps are isolated, so
environment variables don't carry between steps. This caused packages
to accumulate in shared packages/ directory and all be copied to the
stable pool instead of their respective distribution pools.
Changes:
- Move package copy operation into download step within the distribution loop
- Clean packages/ directory before each distribution (no accumulation)
- Copy packages immediately after download for each distribution
- Update "Build APT repository structure" step to skip copy in full rebuild mode
- Update comments to accurately reflect behavior
Fix Strategy:
Instead of:
Download All → (new step) Copy All to Stable → Build All
Now do:
For Each Distribution:
- Clean packages/
- Download to packages/
- Copy to pool/$dist/main/
- (next iteration)
This ensures each distribution gets:
1. Correct release type (stable=latest, unstable=prerelease)
2. Packages in correct pool directory
3. Metadata built from correct pool
Fixes the per-distribution pool bug (#24) that still existed despite
the previous commit.
✅ Review Comments AddressedThank you for the thorough code review! You identified a critical bug that I missed. Issues Found & FixedProblem: Step isolation in GitHub Actions
Solution Applied (new commit 7c76cd0):
Changed SectionsDownload packages step (lines 227-269):
Build APT repository structure step (lines 276-288):
Comments (lines 380-385):
Why This WorksNow the flow is: Full Rebuild Mode: Targeted Mode (unchanged): Testing PlanThe review's testing checklist should now pass:
Code Quality
Ready for re-review! |
✅ LGTM - Critical Bug Fixed!Second commit (7c76cd0) successfully addresses the step isolation bug. What Changed (Review of New Commit)The implementation now correctly integrates download-copy-build into a single loop, exactly as I proposed: Download Step (Lines 228-267)for dist in $ALL_DISTRIBUTIONS; do
# 1. Clean packages directory (lines 244-246)
rm -rf packages/*
mkdir -p packages
# 2. Download for this distribution (lines 248-254)
for repo in $ALL_REPOS; do
download_from_repo "$repo" "$RELEASE_TAG"
done
# 3. Immediately copy to this distribution's pool (lines 256-262)
mkdir -p "apt-repo/pool/$dist/main"
cp packages/*.deb "apt-repo/pool/$dist/main/"
done
# 4. Final cleanup (line 265)
rm -rf packages/*✅ No accumulation - packages/ cleaned before each distribution Build Step (Lines 272-284)if [ "$MODE" = "targeted" ]; then
# Targeted mode: copy packages to pool (backward compatible)
cp packages/*.deb "apt-repo/pool/$TARGET_DIST/main/"
else
# Full rebuild mode: packages already in pools, skip copy
echo "Full rebuild mode: packages already in distribution-specific pools"
fi✅ Conditional logic - only copies in targeted mode Updated Comments (Lines 377-385)# In full rebuild mode:
# - Each distribution's packages were downloaded in the Download step
# - Packages are already in distribution-specific pools (pool/$dist/main/)
# - Stable distributions got latest releases
# - Unstable distributions got pre-releases
# - Now build metadata for all distributions✅ Accurate - reflects actual behavior This implementation correctly fixes Bug #1. |
🔍 Technical VerificationCode Flow AnalysisFull Rebuild Mode Execution (After Fix): Result:
Edge Cases Handled
Backward CompatibilityTargeted Mode (Unchanged): # Download step
download_from_repo "$TARGET_REPO" "$RELEASE_TAG"
# Build step (lines 274-283)
if [ "$MODE" = "targeted" ]; then
cp packages/*.deb "apt-repo/pool/$TARGET_DIST/main/"
fi✅ Targeted updates work exactly as before Technical Verdict: Implementation is sound and handles edge cases appropriately. |
🧪 Testing Strategy & VerificationPre-Merge Verification ✅Code Review Checklist:
All checks pass. ✅ Post-Merge Testing Plan1. Manual Workflow Dispatch Trigger# Go to: https://github.com/hatlabs/apt.hatlabs.fi/actions/workflows/update-repo.yml
# Click: "Run workflow" → "Run workflow"Expected logs: 2. Verify Repository StructureCheck https://apt.hatlabs.fi/: 3. Verify Packages Files# Check trixie-unstable has packages (this was empty before)
curl -s https://apt.hatlabs.fi/dists/trixie-unstable/main/binary-all/Packages | grep -c "^Package:"
# Should return: 8 (or similar non-zero count)
# Verify it has cockpit-apt
curl -s https://apt.hatlabs.fi/dists/trixie-unstable/main/binary-all/Packages | grep "Package: cockpit-apt"
# Should return: Package: cockpit-apt4. End-to-End Test from Debian System# On a trixie system, add the repository
echo "deb [arch=arm64] https://apt.hatlabs.fi trixie-unstable main" | sudo tee /etc/apt/sources.list.d/hatlabs.list
# Add GPG key
curl -s https://apt.hatlabs.fi/hat-labs-apt-key.asc | sudo apt-key add -
# Update and check
sudo apt update
apt-cache policy cockpit-apt
# Should show: 0.3.0-rc1-1 (or similar pre-release version)5. Verify Daily Scheduled RunCheck tomorrow at 06:15 UTC:
6. Verify Targeted Updates Still Work# Trigger a release from cockpit-apt (or any package repo)
# Should dispatch to apt.hatlabs.fi
# Check that only the target distribution gets updatedSuccess Criteria✅ All distributions show non-zero package counts Test Effort: ~30 minutes for complete verification |
✅ APPROVED - Ready to MergeSummaryThis PR successfully fixes both critical bugs:
Commit QualityCommit 1 (5e2e0bb):
Commit 2 (7c76cd0):
Code Review Score
RecommendationAPPROVE - This PR is ready to merge. Post-Merge Actions
Great work addressing the review feedback! The second commit demonstrates excellent problem-solving and attention to detail. The fix is technically sound and ready for production. |
Summary
Fixes two critical bugs causing packages to be removed from non-stable distributions (trixie-unstable, bookworm-unstable, etc.):
Root Causes
Bug 1: Full Rebuild Mode
pool/stable/main/pool/trixie-unstable/main/(empty) → packages disappearedBug 2: Push Trigger
Changes
update-repo.yml
Removed:
push: branches: - maintrigger (caused unintended rebuilds)Modified:
$ALL_DISTRIBUTIONSUpdated comments:
Testing Strategy
Since GitHub Actions workflows cannot be unit tested in traditional TDD style, verification involves:
Pre-Merge Testing
Post-Merge Testing
Check workflow logs for:
Verify repository packages at https://apt.hatlabs.fi/:
Restore missing packages:
Success Criteria
Impact
Severity of Bugs Fixed: HIGH
Frequency: Bug 2 happened daily due to normal development workflows
Related Issues
Verification Notes
After this PR is merged, the next full rebuild (scheduled at 06:00 UTC daily) will:
Package restoration via repository_dispatch will re-populate trixie-unstable.