Skip to content

repository update: select stable kernels from a config file - #407

Open
igorpecovnik wants to merge 8 commits into
repo/ingest-base-filesfrom
repo/stable-kernel-selection
Open

repository update: select stable kernels from a config file#407
igorpecovnik wants to merge 8 commits into
repo/ingest-base-filesfrom
repo/stable-kernel-selection

Conversation

@igorpecovnik

Copy link
Copy Markdown
Member

Stacked on #406 — review that first; this diff is only the stable/kernel part.

Problem

The stable/ branch of Copy operations never moved anything:

if [ -d "${INCOMING_PATH}/stable" ]; then     # guards on incoming/stable …
  COPY_UBOOT=false DRY_RUN=true                # … dry run …
  SELECT=':edge' SRC_DIR=incoming/nightly/debs-beta/   # … reads nightly …
  DST_DIR=/tmp/x scripts/copy-kernel-packages.sh      # … writes to /tmp/x

A stable dispatch reported success and ingested nothing.

Change

Wired for real, driven by a config file, because kernels are a selection rather than a sweep — there is one linux-image per (linuxfamily, branch), and only some belong in the repository.

config/repository-kernel-selection.conf:

KERNEL_SELECT="x86 arm64 bcm2711"   # uefi-x86, uefi-arm64, Raspberry Pi
INCLUDE_LIBC_DEV="true"
COPY_UBOOT="false"
UBOOT_SELECT=""

Seeded with the three kernels stable enough to carry between releases. linux-libc-dev travels with them; u-boot does not, since none of the three boot through Armbian's u-boot.

Gotcha worth knowing: the tokens are LINUXFAMILY values, not board or BOARDFAMILY names — uefi-x86 builds linuxfamily x86, uefi-arm64 builds arm64, and rpi4b builds bcm2711. The config documents this inline.

Verification

Ran the real script against the live image-info.json with a fixture directory:

file outcome
linux-{image,dtb,headers,libc-dev}-current-x86 copied
linux-{image,dtb,headers,libc-dev}-edge-arm64 copied
linux-{image,dtb,headers,libc-dev}-current-bcm2711 copied
linux-{image,dtb}-current-rockchip64 left behind — not selected
linux-u-boot-rpi4b-current left behind — COPY_UBOOT=false

A selected family/branch with no deb present is reported as MISSING: in the step summary and does not fail the run — that is the script's existing behaviour, and it matters because not every family builds every branch every week.

The stable/ branch of Copy operations never moved anything: it ran
copy-kernel-packages.sh with DRY_RUN=true, reading incoming/nightly/debs-beta/
and writing to /tmp/x, while guarding on incoming/stable. A stable dispatch
reported success and ingested nothing.

Wire it for real, driven by config/repository-kernel-selection.conf. Kernels
are a selection rather than a sweep - there is one linux-image per
(linuxfamily, branch) - so the file names which families the repository
carries, and copy-kernel-packages.sh resolves what exists from image-info.json.

Seeded with the three that are stable enough to carry between releases:

  KERNEL_SELECT="x86 arm64 bcm2711"   # uefi-x86, uefi-arm64, Raspberry Pi

linux-libc-dev travels with them; u-boot does not - none of the three boot
through Armbian's u-boot, so COPY_UBOOT is false. Note the tokens are
LINUXFAMILY values, which differ from the board and BOARDFAMILY names:
uefi-x86 builds linuxfamily x86, uefi-arm64 builds arm64, rpi4b builds bcm2711.

Verified against the live image-info.json with a fixture: the x86, arm64 and
bcm2711 image/dtb/headers/libc-dev debs are copied, a rockchip64 kernel and a
u-boot deb in the same directory are left behind.

Signed-off-by: Igor Pecovnik <igor@armbian.com>
@github-actions github-actions Bot added 08 Milestone: Third quarter release size/medium PR with more then 50 and less then 250 lines labels Aug 20, 2026
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 544e5692-07bf-4864-aff6-6de4beed6974

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added Hardware Hardware related like kernel, U-Boot, ... GitHub Actions GitHub Actions code GitHub GitHub-related changes like labels, templates, ... Needs review Seeking for review labels Aug 20, 2026
Gives the weekly update one ordinary, non-critical board that gets the complete
set - kernel, dtb, headers, libc-dev and u-boot - so a regression in the full
path shows up on something harmless rather than on a flagship board.

udoo builds linuxfamily imx6 (current and edge), so KERNEL_SELECT gains imx6.
U-Boot is per BOARD rather than per family, so it needs COPY_UBOOT=true plus an
explicit UBOOT_SELECT: an empty UBOOT_SELECT means EVERY board, not none - the
filter is skipped when it is empty - which with COPY_UBOOT on would drag the
whole fleet's u-boot into the repository.

Verified with a fixture: both imx6 branches' image/dtb/headers/libc-dev and
both udoo u-boot debs are copied, while a rockchip64 kernel and the rpi4b and
orangepi5 u-boot debs sitting beside them are left behind.

Signed-off-by: Igor Pecovnik <igor@armbian.com>
@igorpecovnik

Copy link
Copy Markdown
Member Author

Added udoo with the complete artifact set, so the weekly update exercises the full path on one ordinary board.

KERNEL_SELECT="x86 arm64 bcm2711 imx6"   # + udoo
COPY_UBOOT="true"
UBOOT_SELECT="udoo"

udoo builds linuxfamily imx6 (branches current and edge), which is why the kernel token is imx6 and not udoo — same LINUXFAMILY-not-board gotcha as the others.

The u-boot switch needed care. UBOOT_SELECT is per board, and an empty value means every board, not none — the filter is skipped when empty. Turning COPY_UBOOT on without naming boards would have pulled the entire fleet's u-boot packages into the repository. It's called out in the config comment.

To confirm headers: they're always copied, no flag involved — the script does for p in linux-image linux-dtb linux-headers per selected pair. linux-libc-dev is the only optional one, and it's on.

Fixture run:

file outcome
linux-{image,dtb,headers,libc-dev}-current-imx6 copied
linux-{image,dtb}-edge-imx6 copied
linux-u-boot-udoo-{current,edge} copied
linux-image-current-rockchip64 left behind
linux-u-boot-{rpi4b,orangepi5}-current left behind

cubox-i is imx6 like udoo, so it already gets the kernel selected above; adding
its u-boot makes it the second complete, updatable board in the weekly update.

Verified with a fixture: both cubox-i and both udoo u-boot debs are copied,
while cubieboard and rpi4b u-boot debs sitting beside them are left behind.

Signed-off-by: Igor Pecovnik <igor@armbian.com>
@igorpecovnik

Copy link
Copy Markdown
Member Author

Added the cubox-i bootloader:

UBOOT_SELECT="udoo cubox-i"

cubox-i is imx6 too, so it already receives the kernel selected by KERNEL_SELECT="… imx6" — adding its u-boot makes it the second complete, updatable board rather than a board getting a kernel with no matching bootloader.

Fixture run:

file outcome
linux-u-boot-cubox-i-{current,edge} copied
linux-u-boot-udoo-{current,edge} copied
linux-u-boot-cubieboard left behind
linux-u-boot-rpi4b-current left behind

That leaves the imx6 family in this shape: udoo and cubox-i fully updatable (kernel + bootloader), while the remaining imx6 boards receive the shared family kernel without a u-boot update. Worth naming more boards in UBOOT_SELECT if you want them complete as well — it's a space-separated board[:branch] list.

The package is linux-u-boot-<board>-<branch>, so a board building current and
edge produces two of them. A bare board token takes every branch, which is what
makes udoo and cubox-i completely updatable - the kernel selection covers each
branch and the bootloader has to match it.

Signed-off-by: Igor Pecovnik <igor@armbian.com>
…arget

Keying the kernel selection on target == stable/ made it unreachable on the
path that actually produces those packages: the weekly chain builds them
(uploading to incoming/stable/) and then runs base-files, and base-files is
what fires the repository update - so the payload says base-files/ and the
stable/ arm never runs.

Treat it like the generic packages: incoming is a drop box, so whatever is in
it gets ingested, whoever rang the bell. The stable/ case arm is now a no-op
and the selection runs unconditionally, guarded on the directory existing.

Signed-off-by: Igor Pecovnik <igor@armbian.com>
@igorpecovnik

Copy link
Copy Markdown
Member Author

Caught a gap while tracing the end-to-end path, fixed in the latest commit.

The kernel selection was inside case "$TARGET" under "stable/"). But on the weekly chain (armbian/ci#58) the packages are built first — uploading to incoming/stable/ — and then base-files runs and fires the repository update. So the dispatch payload says base-files/, the stable/ arm never matches, and the kernels would have sat in incoming untouched. Dead code on the only path that produces them.

Now it works like the generic block: unconditional, guarded on incoming/stable existing. incoming is a drop box — whatever is in it gets ingested, whoever rang the bell. The stable/ case arm is a documented no-op.

Better than running it unconditionally. base-files/ is the weekly chain's
completion signal - build-all-stable uploads to incoming/stable/, then runs
base-files, and base-files fires the repository update - so gating there
catches the kernels while still being an explicit target, and a manual stable/
dispatch keeps working through the same function.

It also removes the cost of the unconditional version: copy-kernel-packages.sh
copies rather than moves and nothing drains incoming/stable, so running on
every dispatch meant the eight daily cron updates re-copied the same debs.
Now the selection runs once per weekly chain.

The generic packages stay unconditional: they are moved, so they are ingested
once by whichever update sees them first, and they should never wait for a
particular pipeline to finish.

Signed-off-by: Igor Pecovnik <igor@armbian.com>
@igorpecovnik

Copy link
Copy Markdown
Member Author

Gated under base-files/ as you suggested — better than the unconditional version I had, on both counts.

ingest_stable_kernels() { ... }   # config + copy-kernel-packages.sh

case "$TARGET" in
  "stable/")     ingest_stable_kernels || exit 1 ;;   # manual / unchained
  "base-files/") ingest_stable_kernels || exit 1 ;;   # the weekly chain's signal
  "cron/")       ... rsync as before ...

base-files/ is what the weekly chain actually dispatches, so this is an explicit gate that still fires on the path that produces the packages. Keeping the stable/ arm means a manual stable dispatch works too.

It also removes the cost of the unconditional version I flagged earlier: copy-kernel-packages.sh copies rather than moves and nothing drains incoming/stable/, so running on every dispatch meant the eight daily cron updates re-copied the same debs. Now the selection runs once per weekly chain.

The generic packages stay unconditional — they're moved, so whichever update sees them first ingests them exactly once, and they shouldn't have to wait for a specific pipeline.

Behaviour by target:

target kernel selection generic move cron rsync
base-files/
stable/
cron/ (incl. empty payload)
nightly/, apps/, community/

What was wanted has been copied; the rest is every other family's kernel and
every other board's u-boot, which this repository does not carry. Leaving them
means incoming grows without bound and every weekly run re-copies the same debs
over the last.

Only reached when every copy above succeeded, so nothing is dropped on the
strength of a failed run, and the .deb count is written to the step summary
first - widening KERNEL_SELECT means next week's build supplies them again, but
this week's are gone.

The rm is guarded on INCOMING_PATH being under the storage path, matching the
checks the other destructive steps in this workflow already make.

Signed-off-by: Igor Pecovnik <igor@armbian.com>
@igorpecovnik

Copy link
Copy Markdown
Member Author

incoming/stable is now drained after a successful selection — copy what we carry, drop the rest.

# … selection loop, both debs and debs-beta …

ST_TOTAL=$(find "${INCOMING_PATH}/stable" -type f -name '*.deb' | wc -l)
echo "## Dropping incoming/stable (${ST_TOTAL} .deb, selected ones already copied)" >> "$GITHUB_STEP_SUMMARY"
case "${INCOMING_PATH}" in
  *"/armbian/openssh-server/storage"*) rm -rf "${INCOMING_PATH}/stable" ;;
  *) echo "::error::refusing to remove …"; return 1 ;;
esac

Three things that make it safe to be destructive here:

  • Only on success. The rm is after the loop, and any copy-kernel-packages.sh failure returns first — nothing is dropped on the strength of a failed copy.
  • Counted first. The .deb total goes to the step summary before deletion, so the run records what it discarded.
  • Path-guarded, like the other destructive steps in this workflow. Verified: /armbian/openssh-server/storage/incoming proceeds, /home/igorp/oops and / are refused.

The trade-off, stated plainly: widening KERNEL_SELECT picks up the new families from next week's build, not from what was sitting in incoming — that's gone. Given the alternative was an unbounded directory that nothing had consumed since Aug 9, that seems the right way round.

cron/ is the nightly repository: build-all runs with nightlybuild=yes, so its
debs land in debs-beta. Sweeping the base-files drop box on that dispatch mixed
stable-side packages into a run that has no business carrying them.

The generic move becomes a function called from the two stable-side targets,
stable/ and base-files/, alongside the kernel selection. cron/ now does exactly
what it did before this branch: rsync incoming/cron into storage and drop the
source.

Signed-off-by: Igor Pecovnik <igor@armbian.com>
@igorpecovnik

Copy link
Copy Markdown
Member Author

Corrected: the generic packages are no longer swept on the cron/ path.

cron/ is the nightly repository — build-all.yml runs with nightlybuild_default: "yes", so its debs go to debs-beta. Ingesting the base-files drop box there pulled stable-side packages into a run that shouldn't carry them.

Both ingests are now functions called from the two stable-side targets only:

target kernel selection generic packages cron rsync
base-files/
stable/
cron/ ✅ (unchanged)
nightly/, apps/, community/

cron/ now behaves exactly as it did before this branch: rsync incoming/cron into storage, drop the source, nothing else.

The trade-off I flagged earlier stands, and is now yours by choice rather than by default: if the weekly chain's dispatch is ever lost, the generic packages wait in incoming/base-files/ until the next stable or base-files dispatch, instead of being picked up by the next cron update.

@github-actions github-actions Bot added size/large PR with 250 lines or more and removed size/medium PR with more then 50 and less then 250 lines labels Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

08 Milestone: Third quarter release GitHub Actions GitHub Actions code GitHub GitHub-related changes like labels, templates, ... Hardware Hardware related like kernel, U-Boot, ... Needs review Seeking for review size/large PR with 250 lines or more

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant