This system uses GitHub Actions workflows running on the main branch to orchestrate builds across multiple build branches. Each build cycle runs on its own dedicated branch.
- Contains: Workflow definitions and scripts
- Runs: Scheduled dispatcher that triggers builds on active build branches
- Never builds packages: Only orchestrates builds
- Named:
build/YYYY-MM-DD-HHMMSS-container-tag(e.g.,build/2025-10-31-143027-bioconductor-release321) - Contains: Build state, logs, and results for a single build cycle
- Runs: Package build workflows triggered by the dispatcher on main
Purpose: Runs on schedule on main branch, dispatches builds to incomplete build branches
Schedule: Every 5 minutes (configurable via cron)
Process:
- Fetches all
build/*branches - Checks each branch for completion (presence of
PACKAGESfile) - Dispatches
run.yamlworkflow to incomplete branches - Skips branches that have completed
Triggers:
schedule: Every 5 minutesworkflow_dispatch: Manual trigger
Purpose: Creates a new build branch and starts the build cycle
Process:
- Creates new branch from main:
build/YYYY-MM-DD-HHMMSS-container-tag - Stores container image in
CONTAINER_BASE_IMAGE.bioc - Initializes empty state files (biocdeps.json, logs, etc.)
- Triggers initial build on the new branch
Triggers:
workflow_dispatch: Manual trigger with container image input
Inputs:
container_image: Full container image path (e.g.,ghcr.io/bioconductor/bioconductor_docker:RELEASE_3_21)
Purpose: Builds packages on a build branch
Process:
- First run: Sets up Kubernetes resources and dependencies
- Subsequent runs:
- Processes completed jobs
- Finds ready packages
- Dispatches new build jobs
- Commits state changes (logs, counters, etc.)
Triggers:
workflow_dispatch: Dispatched bydispatch_builds.yamlor manualpush: When logs are updated (triggers next iteration)
Purpose: Finalizes a build cycle
Process:
- Creates PACKAGES index file
- Syncs binaries to final storage via rclone
- Marks cycle as complete
Triggers:
workflow_dispatch: Manual trigger when ready to finalize
# On GitHub: Go to Actions → "Start New Build Cycle" → Run workflow
# Provide container image, e.g.: ghcr.io/bioconductor/bioconductor_docker:RELEASE_3_21- The
dispatch_builds.yamlworkflow on main runs every 5 minutes - It automatically dispatches builds to any incomplete build branches
- No manual intervention needed
# Checkout the build branch
git checkout build/2025-10-31-143027-bioconductor-release321
# Check logs
cat logs/successful-packages.txt
cat logs/failed-packages.txt
# Check remaining packages
cat remaining-packages.json
# View README for detailed status (generated by handle_k8s_jobs.sh)
cat README.md# On GitHub: Switch to build branch → Actions → "Finish Build Cycle" → Run workflowThis creates the PACKAGES file and syncs to final storage. The dispatcher will stop triggering builds on this branch once it sees the PACKAGES file.
CONTAINER_BASE_IMAGE.bioc: Container image used for this buildbiocdeps.json: Package dependencies (created by setup_k8s.sh)uniquedeps.json: Unique dependenciesready_packages.txt: Packages ready to buildremaining-packages.json: Packages still to buildlogs/dispatched-packages.txt: Packages that have been dispatchedlogs/successful-packages.txt: Successfully built packageslogs/failed-packages.txt: Failed packagesnull_push_counter: Tracks workflow runs with no changesreset_attempts_counter: Tracks reset attemptsPACKAGES: Created when cycle is complete (marks branch as done)README.md: Build status report with BBS comparison
- Schedules work on main: GitHub only allows scheduled workflows on default branches
- Parallel builds: Multiple build branches can run simultaneously for different containers
- Branch isolation: Each build cycle is isolated in its own branch
- Simple cleanup: Delete build branch when done
- Easy monitoring: Check branch state for build progress
- Automatic orchestration: Dispatcher handles all active builds centrally
- No workflow editing: Build branches don't need modified workflows
After a build completes and you've verified the results:
# Delete the build branch
git push origin --delete build/2025-10-31-143027-bioconductor-release321- Check that
PACKAGESfile doesn't exist on the branch (if it exists, branch is marked complete) - Verify
dispatch_builds.yamlis running on main branch (check Actions tab)
# On GitHub: Switch to build branch → Actions → "Build R Packages" → Run workflow# Checkout the build branch
git checkout build/2025-10-31-143027-bioconductor-release321
# Clear dispatch logs to retry packages
> logs/dispatched-packages.txt
git add logs/dispatched-packages.txt
git commit -m "Reset dispatched packages"
git push