Skip to content

Hyperion Kernel Build CI #8

Hyperion Kernel Build CI

Hyperion Kernel Build CI #8

Workflow file for this run

name: Hyperion Kernel Build CI
on:
workflow_dispatch:
permissions:
contents: write
actions: write
jobs:
validate-config:
name: Validate Hyperion Config
runs-on: ubuntu-latest
outputs:
VERSION: ${{ steps.parse-config.outputs.VERSION }}
PATCH: ${{ steps.parse-config.outputs.PATCH }}
SUB: ${{ steps.parse-config.outputs.SUB }}
EXTRA: ${{ steps.parse-config.outputs.EXTRA }}
LOCAL: ${{ steps.parse-config.outputs.LOCAL }}
TAG: ${{ steps.parse-config.outputs.TAG }}
HYPERION_VER: ${{ steps.parse-config.outputs.HYPERION_VER }}
# FIX 2: expose the correctly assembled full kernel version (e.g. "6.14" or "6.14.2")
FULL_VERSION: ${{ steps.parse-config.outputs.FULL_VERSION }}
steps:
- uses: actions/checkout@v4
- name: Validate and parse hyperion.config
id: parse-config
run: |
python3 - << 'EOF'
import sys, os
config = {}
with open('hyperion.config') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'): continue
if '=' not in line:
print(f"Invalid line: {line}")
sys.exit(1)
k, v = line.split('=', 1)
config[k.strip()] = v.strip().strip('"')
def parse_int(k, d=0):
val = config.get(k, '')
if val == '': return d
try:
return int(val)
except ValueError:
print(f"Invalid {k}: {val}"); sys.exit(1)
VERSION = parse_int('CONFIG_VERSION')
PATCH = parse_int('CONFIG_PATCHLEVEL')
SUB = parse_int('CONFIG_SUBLEVEL')
EXTRA = config.get('CONFIG_EXTRAVERSION', '') or ''
LOCAL = config.get('CONFIG_LOCALVERSION', '') or ''
# FIX 2: kernel.org omits ".0" sublevel in the tarball name
FULL_VERSION = f"{VERSION}.{PATCH}" if SUB == 0 else f"{VERSION}.{PATCH}.{SUB}"
# Extract the Hyperion version (e.g. "0.1.0") from LOCAL ("-Hyperion-0.1.0")
HYPERION_VER = LOCAL.split('-Hyperion-', 1)[-1] if '-Hyperion-' in LOCAL else LOCAL.lstrip('-')
# Release tag is just the Hyperion version: "0.1.0"
TAG = HYPERION_VER
# FIX 1: use $GITHUB_OUTPUT instead of deprecated ::set-output
out = os.environ['GITHUB_OUTPUT']
with open(out, 'a') as f:
f.write(f"VERSION={VERSION}\n")
f.write(f"PATCH={PATCH}\n")
f.write(f"SUB={SUB}\n")
f.write(f"EXTRA={EXTRA}\n")
f.write(f"LOCAL={LOCAL}\n")
f.write(f"TAG={TAG}\n")
f.write(f"HYPERION_VER={HYPERION_VER}\n")
f.write(f"FULL_VERSION={FULL_VERSION}\n")
EOF
build-kernel:
name: Build Linux Hyperion Kernel
needs: validate-config
runs-on: ubuntu-latest
env:
KERNEL_VERSION: ${{ needs.validate-config.outputs.VERSION }}
PATCHLEVEL: ${{ needs.validate-config.outputs.PATCH }}
SUBLEVEL: ${{ needs.validate-config.outputs.SUB }}
EXTRAVERSION: ${{ needs.validate-config.outputs.EXTRA }}
LOCALVERSION: ${{ needs.validate-config.outputs.LOCAL }}
TAG_NAME: ${{ needs.validate-config.outputs.TAG }}
HYPERION_VER: ${{ needs.validate-config.outputs.HYPERION_VER }}
# FIX 2: single source of truth for the full kernel version used in all paths
FULL_VERSION: ${{ needs.validate-config.outputs.FULL_VERSION }}
KBUILD_BUILD_USER: Soumalya Das
KBUILD_BUILD_HOST: hyperion-ci
steps:
- uses: actions/checkout@v4
- name: Print Hyperion ASCII Banner in Console
run: |
echo " โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—"
echo " โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘"
echo " โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘"
echo " โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ•”โ• โ–ˆโ–ˆโ•”โ•โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘"
echo " โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•‘"
echo " โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•"
echo " Hyperion Kernel Build CI | Tag: ${TAG_NAME} | User: ${KBUILD_BUILD_USER}"
- name: Restore kernel tarball cache
id: cache-tar
uses: actions/cache@v4
with:
# FIX 2: use FULL_VERSION so the filename matches what kernel.org actually serves
path: linux-${{ env.FULL_VERSION }}.tar.xz
key: kernel-tar-${{ env.FULL_VERSION }}
- name: Restore build cache
id: cache-build
uses: actions/cache@v4
with:
path: .cache-build/linux-${{ env.FULL_VERSION }}
key: kernel-build-${{ env.FULL_VERSION }}-hyperion-${{ hashFiles('hyperion.config') }}
restore-keys: |
kernel-build-${{ env.FULL_VERSION }}-
- name: Download kernel source if missing
if: steps.cache-tar.outputs.cache-hit != 'true'
# FIX 2: URL uses FULL_VERSION (e.g. linux-6.14.tar.xz), not bare major version
run: wget -q https://cdn.kernel.org/pub/linux/kernel/v${{ env.KERNEL_VERSION }}.x/linux-${{ env.FULL_VERSION }}.tar.xz
- name: Prepare build tree safely
run: |
mkdir -p .cache-build
cd .cache-build
if [ ! -d "linux-${FULL_VERSION}" ]; then
tar -xf ../linux-${FULL_VERSION}.tar.xz
# Find the extracted dir from the filesystem instead of re-running tar -tf,
# which causes "stdout: write error" when piped to head (broken pipe).
EXTRACTED_DIR=$(find . -maxdepth 1 -mindepth 1 -type d | head -1 | sed 's|^\./||')
if [ "$EXTRACTED_DIR" != "linux-${FULL_VERSION}" ]; then
mv "$EXTRACTED_DIR" "linux-${FULL_VERSION}"
fi
fi
cd ..
- name: Install build dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends \
build-essential libncurses-dev bison flex libssl-dev libelf-dev \
dwarves bc pahole git make gcc zstd cpio perl tar rsync
- name: Configure kernel
run: |
cd .cache-build/linux-${FULL_VERSION}
cp ../../hyperion.config .config
make olddefconfig \
LOCALVERSION="${LOCALVERSION}" \
KBUILD_BUILD_USER="${KBUILD_BUILD_USER}" \
KBUILD_BUILD_HOST="${KBUILD_BUILD_HOST}"
- name: Apply patches
run: |
# FIX 3: nullglob prevents the literal glob string being passed when no patches exist
shopt -s nullglob
PATCHES=(../../patches/*.patch)
if [ ${#PATCHES[@]} -gt 0 ]; then
cd .cache-build/linux-${FULL_VERSION}
for p in "${PATCHES[@]}"; do
echo "Applying patch: $p"
git apply "$p" || patch -p1 < "$p"
done
else
echo "No patches to apply."
fi
- name: Build kernel and prepend banner to build.log
run: |
cd .cache-build/linux-${FULL_VERSION}
{
echo " โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—"
echo " โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘"
echo " โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘"
echo " โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ•”โ• โ–ˆโ–ˆโ•”โ•โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘"
echo " โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•‘"
echo " โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•"
echo " Hyperion Build Log | Tag: ${TAG_NAME}"
make -j$(nproc) \
LOCALVERSION="${LOCALVERSION}" \
KBUILD_BUILD_USER="${KBUILD_BUILD_USER}" \
KBUILD_BUILD_HOST="${KBUILD_BUILD_HOST}" \
KBUILD_BUILD_TIMESTAMP="$(date -u '+%Y-%m-%d %H:%M:%S')"
} 2>&1 | tee build.log
- name: Package artifacts into .tar.zst
run: |
cd .cache-build/linux-${FULL_VERSION}
# FIX 6: copy hyperion.config into the build dir so tar stores it without a "../../" prefix
cp ../../hyperion.config hyperion.config
tar --zstd -cf ../../Hyperion-Kernel-${FULL_VERSION}.tar.zst \
arch/x86/boot/bzImage \
Module.symvers \
build.log \
hyperion.config
- name: Generate checksum
run: |
sha256sum Hyperion-Kernel-${FULL_VERSION}.tar.zst > Hyperion-Kernel-${FULL_VERSION}.sha256
# FIX 5: merged into a single release step โ€” creating then uploading in two calls
# is redundant and risks a race where the second call targets a non-existent release.
# FIX 4: use ${{ env.FULL_VERSION }} (Actions expression syntax) in the with: block,
# because shell variables like ${FULL_VERSION} are NOT expanded in YAML with: values.
- name: Create GitHub Release and upload artifacts
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.TAG_NAME }}
name: Hyperion ${{ env.HYPERION_VER }} based on Linux ${{ env.FULL_VERSION }}
files: |
Hyperion-Kernel-${{ env.FULL_VERSION }}.tar.zst
Hyperion-Kernel-${{ env.FULL_VERSION }}.sha256
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}