Hyperion Kernel Build CI #8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 }} | |