Distribute kernel via Gitea Debian apt repo; track stable not mainline

- Publish .deb packages to Gitea's built-in Debian registry (apt source)
  instead of Releases; CI uploads to pool/stable/main and stops creating
  Releases. One apt source line serves amd64 and arm64.
- Add linux-image-bbrv3 meta-package so `apt upgrade` tracks the latest
  stable kernel while older kernels stay installed for fallback. Its
  dependency is the actual built image package name (immune to localversion
  drift).
- Add bbrv3-config package shipping the BBR+CAKE+ECN sysctl drop-in as a
  conffile (applied via postinst), replacing the installer's sysctl write.
- Rewrite install.sh to add the apt source + signing key and install the
  meta package; keep the OS-version gate, status check and uninstall menu,
  plus an apt-mark hold escape hatch.
- select-stable-kernel.sh: pick the highest stable point release whose
  series is below mainline and has a matching BBRv3 patch, so a freshly-cut
  series (latest stable == mainline, e.g. 7.1) is not built. Currently 7.0.12.
- Exclude linux-libc-dev (clashes with the distro's headers) and drop the
  "by Joey" MODULE_DESCRIPTION step and release branding.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-06-17 18:26:05 +08:00
parent d888a9700e
commit b8ccd431ea
7 changed files with 521 additions and 407 deletions
+119 -116
View File
@@ -1,9 +1,9 @@
name: 构建带有BBRv3的内核
# Gitea Actions reads workflows from .github/workflows/ (and .gitea/workflows/).
# This workflow targets a self-hosted Gitea instance: release existence checks,
# creation and asset uploads go through the Gitea REST API (curl), not the GitHub
# `gh` CLI. arm64 is cross-compiled on the x86_64 runner
# This workflow targets a self-hosted Gitea instance. Kernel .deb packages are
# published to Gitea's built-in Debian package registry (an apt source), not to
# Releases. arm64 is cross-compiled on the x86_64 runner
# (CROSS_COMPILE=aarch64-linux-gnu-), so only a single ubuntu-latest runner is needed.
on:
@@ -13,14 +13,18 @@ on:
- cron: "17 3 * * *"
env:
# Gitea auto-injects GITHUB_TOKEN / GITEA_TOKEN into Actions jobs.
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Gitea REST API base for this repo, e.g.
# https://git.chilldove.com/api/v1/repos/icePigeon/linux-kernel-bbrv3
GITEA_API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
# Gitea Debian package registry for this owner, e.g.
# https://git.chilldove.com/api/packages/icePigeon/debian
PKG_REGISTRY: ${{ github.server_url }}/api/packages/${{ github.repository_owner }}/debian
PKG_USER: ${{ github.repository_owner }}
# Dedicated token with write:package scope. The auto-injected GITHUB_TOKEN is
# not guaranteed to carry package-write permission, so this is a repo secret.
PKG_TOKEN: ${{ secrets.PKG_TOKEN }}
permissions:
contents: write
# Uploads authenticate via the PKG_TOKEN secret, not the auto-injected token,
# so no write permission is requested here.
contents: read
concurrency:
group: bbrv3-kernel-build
@@ -31,59 +35,46 @@ jobs:
runs-on: ubuntu-latest
outputs:
kernel_version: ${{ steps.plan.outputs.kernel_version }}
raw_kernel_version: ${{ steps.plan.outputs.raw_kernel_version }}
build_needed: ${{ steps.plan.outputs.build_needed }}
steps:
- name: 查最新内核和已发布版本
- name: 出代码
uses: actions/checkout@v4
- name: 选择 stable 内核并检查 registry
id: plan
run: |
set -euo pipefail
raw_version=$(curl -fsSL https://www.kernel.org/finger_banner \
| awk -F: '/latest stable version/ {gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2; exit}')
if [ -z "$raw_version" ]; then
echo "Failed to read latest stable kernel version from kernel.org." >&2
exit 1
fi
version="$raw_version"
if [[ "$version" =~ ^[0-9]+\.[0-9]+$ ]]; then
version="${version}.0"
fi
if ! [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Unexpected stable kernel version: $raw_version" >&2
exit 1
fi
echo "raw_kernel_version=$raw_version" >> "$GITHUB_OUTPUT"
# Track an established stable series, never the freshly-cut top series
# that still equals mainline. See scripts/select-stable-kernel.sh.
version=$(bash scripts/select-stable-kernel.sh)
echo "Selected stable kernel: $version"
echo "kernel_version=$version" >> "$GITHUB_OUTPUT"
# Returns 0 when a release with the given tag already exists on Gitea.
release_exists() {
local tag="$1" code
code=$(curl -sS -o /dev/null -w '%{http_code}' \
-H "Authorization: token $GITEA_TOKEN" \
"$GITEA_API/releases/tags/$tag" || echo 000)
[ "$code" = "200" ]
# Already-published check against the registry's apt index (per arch).
pkg_present() {
local debarch="$1"
curl -fsSL ${PKG_TOKEN:+--user "$PKG_USER:$PKG_TOKEN"} \
"$PKG_REGISTRY/dists/stable/main/binary-$debarch/Packages" 2>/dev/null \
| grep -q "^Package: linux-image-$version-bbrv3$"
}
missing=0
for arch in x86_64 arm64; do
tag="$arch-$version"
if release_exists "$tag"; then
echo "$tag already exists."
for da in amd64 arm64; do
if pkg_present "$da"; then
echo "linux-image-$version-bbrv3 ($da) already in registry."
else
echo "$tag is missing."
echo "linux-image-$version-bbrv3 ($da) missing."
missing=1
fi
done
if [ "$missing" -eq 0 ]; then
echo "build_needed=false" >> "$GITHUB_OUTPUT"
echo "All releases for $version already exist; ending workflow before build."
else
if [ "$missing" -eq 1 ]; then
echo "build_needed=true" >> "$GITHUB_OUTPUT"
echo "At least one release for $version is missing; build will continue."
echo "At least one arch for $version is missing; build will continue."
else
echo "build_needed=false" >> "$GITHUB_OUTPUT"
echo "All arches for $version already published; ending before build."
fi
build:
@@ -94,39 +85,42 @@ jobs:
matrix:
include:
# Both targets build on a single x86_64 runner; arm64 is cross-compiled.
# is_primary builds the Architecture:all bbrv3-config package exactly once.
- arch: x86_64
deb_arch: amd64
runs_on: ubuntu-latest
cross_compile: ""
localversion: -bbrv3
is_primary: "true"
- arch: arm64
deb_arch: arm64
runs_on: ubuntu-latest
cross_compile: aarch64-linux-gnu-
localversion: -bbrv3
is_primary: "false"
runs-on: ${{ matrix.runs_on }}
env:
ARCH: ${{ matrix.arch }}
DEB_ARCH: ${{ matrix.deb_arch }}
KERNEL_VERSION: ${{ needs.preflight.outputs.kernel_version }}
steps:
- name: 查是否已发布
id: check_release
env:
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}
- name: 出代码
uses: actions/checkout@v4
- name: 检查 registry 是否已发布
id: check_present
run: |
code=$(curl -sS -o /dev/null -w '%{http_code}' \
-H "Authorization: token $GITEA_TOKEN" \
"$GITEA_API/releases/tags/$TAG" || echo 000)
if [ "$code" = "200" ]; then
set -euo pipefail
if curl -fsSL ${PKG_TOKEN:+--user "$PKG_USER:$PKG_TOKEN"} \
"$PKG_REGISTRY/dists/stable/main/binary-$DEB_ARCH/Packages" 2>/dev/null \
| grep -q "^Package: linux-image-$KERNEL_VERSION-bbrv3$"; then
echo "BUILD_NEEDED=false" >> "$GITHUB_ENV"
echo "$TAG already exists; skipping build."
echo "linux-image-$KERNEL_VERSION-bbrv3 ($DEB_ARCH) already published; skipping."
else
echo "BUILD_NEEDED=true" >> "$GITHUB_ENV"
echo "$TAG does not exist; building latest BBRv3 kernel."
echo "linux-image-$KERNEL_VERSION-bbrv3 ($DEB_ARCH) missing; building."
fi
- name: 检出代码
if: env.BUILD_NEEDED == 'true'
uses: actions/checkout@v4
- name: 安装依赖项
if: env.BUILD_NEEDED == 'true'
run: |
@@ -162,15 +156,6 @@ jobs:
bash "$GITHUB_WORKSPACE/scripts/apply-bbrv3-port.sh"
grep -n "BBR_VERSION" net/ipv4/tcp_bbr.c
- name: 编译声明
if: env.BUILD_NEEDED == 'true'
working-directory: ./kernel/linux
run: |
grep -v "MODULE_DESCRIPTION" net/ipv4/tcp_bbr.c > net/ipv4/tcp_bbr.c.tmp
mv net/ipv4/tcp_bbr.c.tmp net/ipv4/tcp_bbr.c
echo 'MODULE_DESCRIPTION("TCP BBR v3 (Bottleneck Bandwidth and RTT) - Compiled & Optimized by Joey");' >> net/ipv4/tcp_bbr.c
tail -n 5 net/ipv4/tcp_bbr.c
- name: 更新 Makefile 中的版本号
if: env.BUILD_NEEDED == 'true'
working-directory: ./kernel/linux
@@ -219,66 +204,84 @@ jobs:
fi
find ./kernel -maxdepth 1 -name 'linux-*.deb' -print | sort
- name: 发布前复查是否已发布
- name: 构建 meta 与 config 包
if: env.BUILD_NEEDED == 'true'
env:
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}
run: |
code=$(curl -sS -o /dev/null -w '%{http_code}' \
-H "Authorization: token $GITEA_TOKEN" \
"$GITEA_API/releases/tags/$TAG" || echo 000)
if [ "$code" = "200" ]; then
echo "PUBLISH_NEEDED=false" >> "$GITHUB_ENV"
echo "$TAG was published while this job was running; skipping upload and release."
else
echo "PUBLISH_NEEDED=true" >> "$GITHUB_ENV"
echo "$TAG still missing; publishing this build."
fi
- name: 发布到 Gitea Release
if: env.BUILD_NEEDED == 'true' && env.PUBLISH_NEEDED == 'true'
env:
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}
TARGET_ARCH: ${{ matrix.arch }}
TARGET_SHA: ${{ github.sha }}
IS_PRIMARY: ${{ matrix.is_primary }}
run: |
set -euo pipefail
body="带有 BBRv3 的最新内核,适用于 $TARGET_ARCH 架构。Compiled & Optimized by Joey."
mkdir -p ./out
auth=(-H "Authorization: token $GITEA_TOKEN")
# Reuse an existing release for this tag, otherwise create it.
release_id=$(curl -sS "${auth[@]}" "$GITEA_API/releases/tags/$TAG" | jq -r '.id // empty')
if [ -z "$release_id" ]; then
release_id=$(curl -sS "${auth[@]}" \
-H "Content-Type: application/json" \
-X POST "$GITEA_API/releases" \
-d "$(jq -n \
--arg tag "$TAG" \
--arg target "$TARGET_SHA" \
--arg name "$TAG" \
--arg body "$body" \
'{tag_name:$tag, target_commitish:$target, name:$name, body:$body, draft:false, prerelease:false}')" \
| jq -r '.id // empty')
# Depend on the *actual* image package name, immune to localversion drift.
img_deb=$(find ./kernel -maxdepth 1 -name 'linux-image-*.deb' ! -name '*-dbg*' | sort | head -n1)
if [ -z "$img_deb" ]; then
echo "No linux-image .deb found to base the meta-package on." >&2
exit 1
fi
if [ -z "$release_id" ] || [ "$release_id" = "null" ]; then
echo "Failed to resolve or create Gitea release for $TAG" >&2
img_pkg=$(dpkg-deb -f "$img_deb" Package)
echo "Kernel image package: $img_pkg"
bash scripts/build-meta-package.sh "$KERNEL_VERSION" "$DEB_ARCH" "$img_pkg" ./out
# bbrv3-config is Architecture:all; build it once (on the primary arch).
if [ "$IS_PRIMARY" = "true" ]; then
bash scripts/build-config-package.sh ./out
fi
- name: 发布前复查是否已发布
if: env.BUILD_NEEDED == 'true'
run: |
set -euo pipefail
if curl -fsSL ${PKG_TOKEN:+--user "$PKG_USER:$PKG_TOKEN"} \
"$PKG_REGISTRY/dists/stable/main/binary-$DEB_ARCH/Packages" 2>/dev/null \
| grep -q "^Package: linux-image-$KERNEL_VERSION-bbrv3$"; then
echo "PUBLISH_NEEDED=false" >> "$GITHUB_ENV"
echo "Published while this job was running; skipping upload."
else
echo "PUBLISH_NEEDED=true" >> "$GITHUB_ENV"
echo "Still missing; publishing this build."
fi
- name: 发布到 Gitea Debian registry
if: env.BUILD_NEEDED == 'true' && env.PUBLISH_NEEDED == 'true'
run: |
set -euo pipefail
if [ -z "${PKG_TOKEN:-}" ]; then
echo "PKG_TOKEN secret is required to publish (needs write:package scope)." >&2
exit 1
fi
# Upload the kernel .deb packages as release assets.
# Gitea returns 201/202 on upload, 409 when the file already exists.
upload() {
local f="$1" code
code=$(curl -sS -o /dev/null -w '%{http_code}' \
--user "$PKG_USER:$PKG_TOKEN" --upload-file "$f" \
"$PKG_REGISTRY/pool/stable/main/upload" || echo 000)
case "$code" in
201|202) echo "Uploaded $(basename "$f") ($code)";;
409) echo "Already present $(basename "$f") (409)";;
*) echo "Upload failed: $(basename "$f") (HTTP $code)" >&2; return 1;;
esac
}
shopt -s nullglob
assets=( ./kernel/linux-*.deb )
if [ "${#assets[@]}" -eq 0 ]; then
echo "No .deb assets found to upload for $TAG" >&2
# Publish the kernel image and (x86_64) headers, plus the meta/config
# packages. Never linux-libc-dev (clashes with the distro's userspace
# headers) and never *-dbg* packages.
assets=()
for f in ./kernel/linux-image-*.deb ./kernel/linux-headers-*.deb; do
case "$f" in *-dbg*) continue;; esac
assets+=("$f")
done
assets+=( ./out/*.deb )
if [ ${#assets[@]} -eq 0 ]; then
echo "No .deb assets found to upload." >&2
exit 1
fi
for f in "${assets[@]}"; do
name=$(basename "$f")
echo "Uploading $name to release $TAG (id=$release_id)"
curl -fsS "${auth[@]}" \
-X POST "$GITEA_API/releases/$release_id/assets?name=$name" \
-F "attachment=@$f" >/dev/null
echo "Publishing $(basename "$f")"
upload "$f"
done
echo "Published $TAG with ${#assets[@]} asset(s)."
echo "Published ${#assets[@]} package(s) for $KERNEL_VERSION ($DEB_ARCH)."