Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 46 additions & 4 deletions .automation/skills/upstream-rebase/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ Your report can only stop it. When you finish, the workflow independently:
alone that the series sits on the upstream tip, is linear, lost or gained
no commit, and changed the tree by exactly the upstream delta;
2. builds x86_64 and arm64 `vmlinux` with `kernel-build.sh`, which turns on
every downstream feature as a built-in.
every downstream feature as a built-in. x86_64 starts from the latest
Edera host config in edera-dev/linux-kernel-oci; arm64 from defconfig.

If the build fails, you get your branch back with the build logs and one
chance to repair it (see "Repairing a failed build"), and the repaired branch
is checked and built again from scratch.

If all of that passes **and your report's "Needs a decision" section is
`None.` with nothing marked UNSURE anywhere** (checked by
Expand Down Expand Up @@ -138,6 +143,12 @@ The workflow re-runs these builds itself, but run them here so you can fix
what your resolutions broke. Each takes a while; run them once the rebase is
complete, not after every commit.

Run each build in the foreground and wait for it: the shell allows a command
up to 90 minutes, which is enough for a full build. Never start a build in
the background, and never end your session while one is running. A run
that stops to wait for a build ends there, and nobody fixes what it would
have shown.

```sh
bash .rebase-tools/scripts/kernel-build.sh x86_64 .rebase-scratch/obj-x86 4
bash .rebase-tools/scripts/kernel-build.sh arm64 .rebase-scratch/obj-arm64 4
Expand All @@ -149,9 +160,10 @@ the build script names). Find out which, and say so in the report; if the
build script's list is what is stale, that is a **Needs a decision** item,
not something to work around.

If a build fails because of the rebase (a resolution, or an upstream change a
downstream commit has not caught up with), fix it **in the downstream commit
that is wrong**. Interactive editors do not work here, so drive the todo list
A failing build is not a finished rebase. If a build fails because of the
rebase (a resolution, or an upstream change a downstream commit has not
caught up with), fix it, build again, and keep going until both builds pass.
Fix it **in the downstream commit that is wrong**. Interactive editors do not work here, so drive the todo list
with sed: `git -c sequence.editor="sed -i 's/^pick <sha>/edit <sha>/'" rebase
-i UPSTREAM`, amend, then `git rebase --continue`. Do not add a fix-up commit
on top unless there is no single commit it belongs to; if you must, its
Expand Down Expand Up @@ -238,6 +250,36 @@ x86_64, arm64: pass, fail (with the first error), or pre-existing failure
Then stop. Leave RESULT checked out or not; the workflow reads the branch,
not the working tree.

## Repairing a failed build

The workflow sends you here, in a fresh session, when the branch you produced
failed its independent build. The prompt gives you `BUILD_LOGS`, a directory
holding the log of each arch the workflow built, and your branch is checked
out as `RESULT`. `REPORT` already holds the report you wrote for the rebase.

1. Read the logs. Find the first error in each failing one; later errors
usually follow from it. A log that ends with `kernel-build: ... built`
passed.
2. Reproduce the failure with `kernel-build.sh` exactly as in step 3, then
fix it the same way: in the downstream commit that is wrong, with the
same rules on fix-up commits. If it fails on pristine `UPSTREAM` too, it
is not yours: say so and leave the branch alone.
3. Build both arches again, not only the one that failed, and keep fixing
and rebuilding until both pass. Do not stop at the first fix.
4. Run `verify-upstream-rebase.sh` as in step 5. Every new drift line must be
one of your build fixes.
5. Update `REPORT` in place. Add each fix to **Build fixes** (what broke, the
first error, which commit you changed, why), and rewrite **Builds** with
the results you now have. Leave the rest as it is, except to add an
**UNSURE** item if a fix needed a judgement call. A reviewer will read
this report, not your session.

Exit status 3 is still not something to work around here: a Kconfig symbol
the build script names no longer surviving `olddefconfig` goes to **Needs a
decision**, as in step 3. If you cannot make the build pass, leave `RESULT`
at the best branch you have and say in **Builds** exactly what still fails
and why.

## If you cannot finish

If the rebase cannot be completed (a conflict you cannot resolve at all, a
Expand Down
24 changes: 23 additions & 1 deletion .github/scripts/kernel-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
# replay that breaks any of them, or links against a symbol upstream removed,
# fails here. Building only a subdirectory would miss those link errors.
#
# x86_64 adds Edera's shipping host config, fetched from the tip of
# edera-dev/linux-kernel-oci each run, over defconfig, so the branch is
# judged against the kernel we actually ship. That config builds
# OpenPaX out and several Edera drivers as modules, so the options below are
# still forced on as built-ins over it. arm64 starts from defconfig.
#
# The rebase skill runs this same script before they finish, so
# what Claude checks and what the workflow checks cannot drift apart.
#
Expand All @@ -18,7 +24,8 @@
# aarch64-linux-gnu-) unless LLVM is set, in which case it builds with clang.
#
# Exit status: make's on a build failure; 3 if an option it asked for did not
# survive olddefconfig (a Kconfig dependency the series no longer satisfies).
# survive olddefconfig (a Kconfig dependency the series no longer satisfies);
# git's if the host config cannot be fetched.

set -euo pipefail

Expand Down Expand Up @@ -51,6 +58,8 @@ x86_64)
HYPERVISOR_GUEST PARAVIRT XEN_PV XEN_PVHVM_GUEST PCI_XEN
XEN_PCIDEV_FRONTEND XEN_PCIDEV_BACKEND XEN_IOMMU
HYPERV HYPERV_VMBUS HYPERV_NET PCI_HYPERV PCI_HYPERV_INTERFACE
# host.config builds AGP as a module, which caps DRM at m.
AGP
)
;;
arm64)
Expand All @@ -72,6 +81,19 @@ mkdir -p "$objdir"
mk() { make -s ARCH="$karch" "${cross[@]}" O="$objdir" "$@"; }

mk defconfig
if [ "$arch" = x86_64 ]; then
# host.config is a fragment against x86_64_defconfig: it leaves out
# whatever matches defconfig (SMP and NET among them), so it only means
# something merged over defconfig, the way linux-kernel-oci applies it.
oci=https://github.com/edera-dev/linux-kernel-oci
cfgrepo=$(mktemp -d)
trap 'rm -rf "$cfgrepo"' EXIT
git init -q --bare "$cfgrepo"
git -C "$cfgrepo" fetch -q --depth 1 "$oci" main
git -C "$cfgrepo" show FETCH_HEAD:configs/x86_64/host.config >"$cfgrepo/host.config"
echo "kernel-build: merging host.config from $oci@$(git -C "$cfgrepo" rev-parse FETCH_HEAD)"
scripts/kconfig/merge_config.sh -m -O "$objdir" "$objdir/.config" "$cfgrepo/host.config" >/dev/null
fi
enable=()
for o in "${opts[@]}"; do enable+=(--enable "$o"); done
scripts/config --file "$objdir/.config" "${enable[@]}"
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/automation-selftest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ on:
paths:
- '.github/scripts/**'
- '.github/workflows/upstream-rebase.yml'
- '.github/workflows/rebase-build.yml'
- '.github/workflows/kernel-nightly.yml'
- '.github/workflows/rebase-land.yml'
- '.github/workflows/automation-selftest.yml'
Expand Down
117 changes: 117 additions & 0 deletions .github/workflows/rebase-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: Rebase build

# The independent build of a rebase result, called by upstream-rebase.yml:
# once for Claude's rebase and, if that fails and Claude repairs the branch,
# once more for the repaired branch.
#
# It builds x86_64 and arm64 vmlinux with kernel-build.sh, taken from the
# commit the calling run started from, never from the tree under test. Each
# build's log is kept as an artifact, so a repair round can read what broke.

on:
workflow_call:
inputs:
old:
description: The downstream tip the rebase started from
type: string
required: true
up:
description: The upstream commit the result sits on
type: string
required: true
result:
description: The commit to build
type: string
required: true
bundle:
description: The artifact holding rebase.bundle with the result
type: string
required: true
logs:
description: Prefix for the build log artifacts; the arch is appended
type: string
required: true
upstream_url:
type: string
required: true
upstream_branch:
type: string
required: true

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
arch: [x86_64, arm64]
name: build (${{ matrix.arch }})
steps:
- name: Harden runner
uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ inputs.old }}
fetch-depth: 0
filter: blob:none
persist-credentials: false

- name: Trusted tools
run: |
set -euo pipefail
git fetch --no-tags --filter=blob:none origin "$GITHUB_SHA"
mkdir "$RUNNER_TEMP/tools"
git archive "$GITHUB_SHA" .github/scripts | tar -x -C "$RUNNER_TEMP/tools" --strip-components=1

- name: Download
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ inputs.bundle }}
path: ${{ runner.temp }}/in

- name: Check out the result
env:
UPSTREAM_URL: ${{ inputs.upstream_url }}
UPSTREAM_BRANCH: ${{ inputs.upstream_branch }}
UP: ${{ inputs.up }}
RESULT: ${{ inputs.result }}
run: |
set -euo pipefail
git fetch --no-tags "$UPSTREAM_URL" "$UPSTREAM_BRANCH"
git merge-base --is-ancestor "$UP" FETCH_HEAD
git fetch "$RUNNER_TEMP/in/rebase.bundle" rebase-result:rebase-result
[ "$(git rev-parse rebase-result)" = "$RESULT" ] || { echo "bundle does not hold $RESULT"; exit 1; }
git checkout --detach "$RESULT"

- name: Install toolchains
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential bc bison flex libelf-dev libssl-dev python3 \
gcc-aarch64-linux-gnu

- name: Build
env:
ARCH: ${{ matrix.arch }}
run: |
set -euo pipefail
bash "$RUNNER_TEMP/tools/scripts/kernel-build.sh" "$ARCH" "$RUNNER_TEMP/obj" 2>&1 |
tee "$RUNNER_TEMP/build-$ARCH.log"

- name: Upload the log
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ inputs.logs }}-${{ matrix.arch }}
path: ${{ runner.temp }}/build-${{ matrix.arch }}.log
if-no-files-found: ignore
retention-days: 30
Loading
Loading