diff --git a/Makefile b/Makefile index 977e1ea..e2c6ab7 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,10 @@ CRIU_DAEMON_SRC := criu-daemon.sh CONFIG_SRC := bisect.conf HANDLER_SRC_DIR := handlers HANDLER_SRCS := $(wildcard $(HANDLER_SRC_DIR)/*.sh) +RPM_LIST_DIR := rpm_lists +RPM_LIST_DIR_TARGET := $(BIN_DIR)/rpm_lists -.PHONY: all install uninstall clean help +.PHONY: all install uninstall clean help update-rpm-lists all: help @@ -24,6 +26,7 @@ help: @echo "Targets:" @echo " install Install the bisection scripts, CRIU daemon and handlers." @echo " uninstall Remove all installed files." + @echo " update-rpm-lists Refresh shipped NVR lists from upstream repos (requires python3)." @echo " help Show this help message." format-check: @@ -46,6 +49,11 @@ integration-tests: tests: format-check static-analysis unit-tests integration-tests +update-rpm-lists: + python3 tools/generate_rhel_kernel_rpm_list.py --nvr C9S x86_64 > $(RPM_LIST_DIR)/c9s.list + python3 tools/generate_rhel_kernel_rpm_list.py --nvr C10S x86_64 > $(RPM_LIST_DIR)/c10s.list + python3 tools/generate_fedora_kernel_rpm_list.py --nvr > $(RPM_LIST_DIR)/fedora.list + install: @if [ "$(EUID)" -ne 0 ]; then \ echo "Please run as root or with sudo."; \ @@ -69,6 +77,10 @@ install: @cp $(HANDLER_SRCS) $(HANDLER_DIR_TARGET)/ @chmod +x $(HANDLER_DIR_TARGET)/*.sh + @echo "Copying RPM NVR lists to $(RPM_LIST_DIR_TARGET)/" + @mkdir -p $(RPM_LIST_DIR_TARGET) + @cp $(RPM_LIST_DIR)/*.list $(RPM_LIST_DIR_TARGET)/ + @if [ ! -f "$(CONFIG_FILE_TARGET)" ]; then \ echo "Copying default configuration to $(CONFIG_FILE_TARGET)"; \ cp $(CONFIG_SRC) $(CONFIG_FILE_TARGET); \ diff --git a/README.md b/README.md index da244a4..a9baf09 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,26 @@ To uninstall: sudo make uninstall ``` +## RPM Lists + +The tool ships pre-built NVR lists in `rpm_lists/` for CentOS Stream 9, +CentOS Stream 10, and Fedora. When `KERNEL_RPM_LIST` is not set, the tool +auto-detects the distro and architecture from `BAD_COMMIT` and uses the +appropriate shipped list to construct RPM URLs at runtime. + +To generate a fresh RPM list at runtime (requires `python3`, +`beautifulsoup4`, `packaging`), set in `bisect.conf`: + +``` +GENERATE_RPM_LIST="yes" +``` + +To refresh the shipped lists (maintainer use): + +```bash +make update-rpm-lists +``` + ## Configuration Edit `/usr/local/bin/kernel-auto-bisect/bisect.conf` after installation. @@ -86,7 +106,7 @@ Edit `/usr/local/bin/kernel-auto-bisect/bisect.conf` after installation. | Variable | Description | |---|---| -| `KERNEL_RPM_LIST` | Path to a file listing kernel RPM URLs, one per line (ordered from good to bad) | +| `KERNEL_RPM_LIST` | Path to a file listing kernel RPM URLs, one per line (ordered from good to bad). Optional — when omitted, auto-selected from shipped NVR lists based on `BAD_COMMIT`. | | `RPM_CACHE_DIR` | Directory to cache downloaded RPMs | | `GOOD_COMMIT` | Kernel release string of the known-good version (e.g. `5.14.0-162.el9.aarch64`) | | `BAD_COMMIT` | Kernel release string of the known-bad version | @@ -105,6 +125,7 @@ Edit `/usr/local/bin/kernel-auto-bisect/bisect.conf` after installation. | `REPRODUCER_SCRIPT` | Path to the reproducer script | | `RUNS_PER_COMMIT` | Number of test runs per commit (for intermittent issues, default: 1) | | `VERIFY_COMMITS` | Set to `no` to skip initial good/bad commit verification | +| `GENERATE_RPM_LIST` | Set to `yes` to generate a fresh RPM list at runtime using Python scripts instead of shipped lists | ## Reproducer Script diff --git a/bisect.conf b/bisect.conf index 2a1a4ec..dd41289 100755 --- a/bisect.conf +++ b/bisect.conf @@ -37,9 +37,17 @@ GIT_REPO_BRANCH=os-build KERNEL_SRC_DIR="/path/to/your/linux/source" # === RPM Configuration (for INSTALL_STRATEGY="rpm") === -KERNEL_RPM_LIST="/path/to/your/kernel_rpm_list.txt" +# KERNEL_RPM_LIST is optional. When omitted, the tool auto-selects a shipped +# NVR list based on BAD_COMMIT's dist tag and constructs RPM URLs at runtime. +# Set this to override with your own list of kernel RPM URLs (one per line). +#KERNEL_RPM_LIST="/path/to/your/kernel_rpm_list.txt" RPM_CACHE_DIR="/var/cache/kdump-bisect-rpms" +# GENERATE_RPM_LIST: Set to "yes" to generate a fresh NVR list at runtime +# using the Python scripts in tools/ instead of the shipped static lists. +# Requires python3 with beautifulsoup4 and packaging modules. +#GENERATE_RPM_LIST="yes" + # === Commit/Version Boundaries === # If INSTALL_STRATEGY="git", these are git commit hashes. # If INSTALL_STRATEGY="rpm", these are kernel release versions (e.g., "5.14.0-162.el9.aarch64"). diff --git a/docs/superpowers/plans/2026-04-11-optional-kernel-rpm-list.md b/docs/superpowers/plans/2026-04-11-optional-kernel-rpm-list.md new file mode 100644 index 0000000..00c3dbc --- /dev/null +++ b/docs/superpowers/plans/2026-04-11-optional-kernel-rpm-list.md @@ -0,0 +1,761 @@ +# Optional KERNEL_RPM_LIST Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make KERNEL_RPM_LIST optional by auto-detecting distro/arch from BAD_COMMIT, using shipped NVR lists to construct RPM URLs at runtime, with opt-in fresh generation via GENERATE_RPM_LIST=yes. + +**Architecture:** New helper functions in lib.sh (parse_nvr_distro, parse_nvr_arch, nvr_to_rpm_url, resolve_rpm_list) auto-generate KERNEL_RPM_LIST from shipped NVR list files in rpm_lists/. The resolve_rpm_list function runs early in initialize(), before resolve_install_strategy(), so KERNEL_RPM_LIST is set before strategy detection. Generator scripts are extended with --nvr flag and arch parameter for opt-in fresh list generation. + +**Tech Stack:** Bash (lib.sh, ShellSpec tests), Python (generator scripts), Make + +**Spec:** `docs/superpowers/specs/2026-04-11-optional-kernel-rpm-list-design.md` + +--- + +## File Structure + +| File | Action | Responsibility | +|------|--------|---------------| +| `lib.sh` | Modify | Add parse_nvr_distro, parse_nvr_arch, nvr_to_rpm_url, resolve_rpm_list; integrate into initialize() | +| `spec/resolve_rpm_list_spec.sh` | Create | ShellSpec unit tests for all new helpers | +| `tools/generate_fedora_kernel_rpm_list.py` | Modify | Add --nvr flag and arch parameter | +| `tools/generate_rhel_kernel_rpm_list.py` | Modify | Add --nvr flag | +| `rpm_lists/c9s.list` | Create | Shipped CentOS Stream 9 NVR list | +| `rpm_lists/c10s.list` | Create | Shipped CentOS Stream 10 NVR list | +| `rpm_lists/fedora.list` | Create | Shipped Fedora NVR list | +| `Makefile` | Modify | Add update-rpm-lists target, update install target | +| `bisect.conf` | Modify | Comment out KERNEL_RPM_LIST, add GENERATE_RPM_LIST | +| `README.md` | Modify | Document optional KERNEL_RPM_LIST, GENERATE_RPM_LIST, make update-rpm-lists | + +--- + +### Task 1: NVR Parsing Helpers + +**Files:** +- Create: `spec/resolve_rpm_list_spec.sh` +- Modify: `lib.sh` (add after `nvr_to_tag` function, ~line 225) + +- [ ] **Step 1: Write failing tests for parse_nvr_distro and parse_nvr_arch** + +Create `spec/resolve_rpm_list_spec.sh`: + +```bash +#!/bin/bash + +Describe 'resolve_rpm_list helpers' + Include ./lib.sh + + setup_env() { + LOG_FILE="${SHELLSPEC_WORKDIR}/test.log" + } + Before 'setup_env' + + Describe 'parse_nvr_distro' + It "detects c9s from el9 NVR" + When call parse_nvr_distro "5.14.0-400.el9.x86_64" + The output should equal "c9s" + The status should be success + End + + It "detects c10s from el10 NVR" + When call parse_nvr_distro "6.12.0-200.el10.x86_64" + The output should equal "c10s" + The status should be success + End + + It "detects fedora from fc41 NVR" + When call parse_nvr_distro "6.16.5-100.fc41.x86_64" + The output should equal "fedora" + The status should be success + End + + It "detects c9s from rt NVR" + When call parse_nvr_distro "5.14.0-100.rt14.100.el9.x86_64" + The output should equal "c9s" + The status should be success + End + + It "fails on unknown dist tag" + When call parse_nvr_distro "5.14.0-100.unknown.x86_64" + The status should be failure + End + + It "fails on git commit hash" + When call parse_nvr_distro "abc123def456789" + The status should be failure + End + End + + Describe 'parse_nvr_arch' + It "extracts x86_64" + When call parse_nvr_arch "6.12.0-200.el10.x86_64" + The output should equal "x86_64" + End + + It "extracts aarch64" + When call parse_nvr_arch "5.14.0-400.el9.aarch64" + The output should equal "aarch64" + End + + It "extracts s390x" + When call parse_nvr_arch "6.12.0-100.el10.s390x" + The output should equal "s390x" + End + + It "extracts arch from rt NVR" + When call parse_nvr_arch "5.14.0-100.rt14.100.el9.x86_64" + The output should equal "x86_64" + End + End +End +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `shellspec spec/resolve_rpm_list_spec.sh` +Expected: FAIL — `parse_nvr_distro` and `parse_nvr_arch` not defined + +- [ ] **Step 3: Implement parse_nvr_distro and parse_nvr_arch** + +In `lib.sh`, add after the `nvr_to_tag()` function (after line 225): + +```bash +# Extract distro identifier from NVR for RPM list lookup +# e.g., "6.12.0-200.el10.x86_64" -> "c10s" +parse_nvr_distro() { + local nvr=$1 + if [[ "$nvr" =~ \.el9[.] ]] || [[ "$nvr" =~ \.el9$ ]]; then + echo "c9s" + elif [[ "$nvr" =~ \.el10[.] ]] || [[ "$nvr" =~ \.el10$ ]]; then + echo "c10s" + elif [[ "$nvr" =~ \.fc[0-9]+ ]]; then + echo "fedora" + else + return 1 + fi +} + +# Extract architecture from NVR (last dot-separated component) +# e.g., "6.12.0-200.el10.x86_64" -> "x86_64" +parse_nvr_arch() { + echo "${1##*.}" +} +``` + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `shellspec spec/resolve_rpm_list_spec.sh` +Expected: All tests PASS + +- [ ] **Step 5: Run full checks** + +Run: `make format-check static-analysis unit-tests` +Expected: All pass + +- [ ] **Step 6: Commit** + +```bash +git add spec/resolve_rpm_list_spec.sh lib.sh +git commit -m "Add parse_nvr_distro and parse_nvr_arch helpers" +``` + +--- + +### Task 2: URL Construction Helper + +**Files:** +- Modify: `spec/resolve_rpm_list_spec.sh` (append inside `Describe 'resolve_rpm_list helpers'`) +- Modify: `lib.sh` (add after `parse_nvr_arch`) + +- [ ] **Step 1: Write failing tests for nvr_to_rpm_url** + +Append to `spec/resolve_rpm_list_spec.sh`, inside the `Describe 'resolve_rpm_list helpers'` block (before the final `End`): + +```bash + Describe 'nvr_to_rpm_url' + It "constructs c10s URL for x86_64" + When call nvr_to_rpm_url "6.12.0-30.el10" "x86_64" + The output should equal \ + "https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0/30.el10/x86_64/kernel-core-6.12.0-30.el10.x86_64.rpm" + End + + It "constructs c9s URL for aarch64" + When call nvr_to_rpm_url "5.14.0-285.el9" "aarch64" + The output should equal \ + "https://kojihub.stream.centos.org/kojifiles/packages/kernel/5.14.0/285.el9/aarch64/kernel-core-5.14.0-285.el9.aarch64.rpm" + End + + It "constructs Fedora URL" + When call nvr_to_rpm_url "6.16.5-100.fc41" "x86_64" + The output should equal \ + "https://kojipkgs.fedoraproject.org/packages/kernel/6.16.5/100.fc41/x86_64/kernel-core-6.16.5-100.fc41.x86_64.rpm" + End + + It "fails on unknown dist tag" + When call nvr_to_rpm_url "6.12.0-100.unknown" "x86_64" + The status should be failure + End + End +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `shellspec spec/resolve_rpm_list_spec.sh` +Expected: FAIL — `nvr_to_rpm_url` not defined + +- [ ] **Step 3: Implement nvr_to_rpm_url** + +In `lib.sh`, add after `parse_nvr_arch()`: + +```bash +# Construct full kernel-core RPM URL from NVR and arch +# e.g., nvr_to_rpm_url "6.12.0-30.el10" "x86_64" -> +# https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0/30.el10/x86_64/kernel-core-6.12.0-30.el10.x86_64.rpm +nvr_to_rpm_url() { + local nvr=$1 arch=$2 + local base_url version release + + version="${nvr%%-*}" + release="${nvr#*-}" + + if [[ "$nvr" =~ \.el[0-9]+ ]]; then + base_url="https://kojihub.stream.centos.org/kojifiles/packages/kernel" + elif [[ "$nvr" =~ \.fc[0-9]+ ]]; then + base_url="https://kojipkgs.fedoraproject.org/packages/kernel" + else + return 1 + fi + + echo "${base_url}/${version}/${release}/${arch}/kernel-core-${nvr}.${arch}.rpm" +} +``` + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `shellspec spec/resolve_rpm_list_spec.sh` +Expected: All tests PASS + +- [ ] **Step 5: Run full checks** + +Run: `make format-check static-analysis unit-tests` +Expected: All pass + +- [ ] **Step 6: Commit** + +```bash +git add spec/resolve_rpm_list_spec.sh lib.sh +git commit -m "Add nvr_to_rpm_url helper for URL construction" +``` + +--- + +### Task 3: resolve_rpm_list Function + +**Files:** +- Modify: `spec/resolve_rpm_list_spec.sh` (append inside `Describe 'resolve_rpm_list helpers'`) +- Modify: `lib.sh` (add after `nvr_to_rpm_url`) + +- [ ] **Step 1: Write failing tests for resolve_rpm_list** + +Append to `spec/resolve_rpm_list_spec.sh`, inside the `Describe 'resolve_rpm_list helpers'` block (before the final `End`): + +```bash + Describe 'resolve_rpm_list' + setup_rpm_env() { + WORK_DIR="${SHELLSPEC_WORKDIR}/work" + BIN_DIR="${SHELLSPEC_WORKDIR}/bin" + mkdir -p "$WORK_DIR" "$BIN_DIR/rpm_lists" + KERNEL_RPM_LIST="" + INSTALL_STRATEGY="" + GENERATE_RPM_LIST="" + BAD_COMMIT="" + # Create a mock shipped NVR list + cat <<'EOF' >"$BIN_DIR/rpm_lists/c10s.list" +6.12.0-30.el10 +6.12.0-31.el10 +6.12.0-32.el10 +EOF + } + + cleanup_rpm_env() { + rm -rf "${SHELLSPEC_WORKDIR}/work" "${SHELLSPEC_WORKDIR}/bin" + } + + Before 'setup_rpm_env' + After 'cleanup_rpm_env' + + # Suppress log output + log() { :; } + + It "skips when KERNEL_RPM_LIST is already set" + KERNEL_RPM_LIST="/existing/list.txt" + BAD_COMMIT="6.12.0-200.el10.x86_64" + When call resolve_rpm_list + The variable KERNEL_RPM_LIST should equal "/existing/list.txt" + End + + It "skips when INSTALL_STRATEGY is git" + INSTALL_STRATEGY="git" + BAD_COMMIT="6.12.0-200.el10.x86_64" + When call resolve_rpm_list + The variable KERNEL_RPM_LIST should equal "" + End + + It "skips when BAD_COMMIT is not an NVR" + BAD_COMMIT="abc123def456" + When call resolve_rpm_list + The variable KERNEL_RPM_LIST should equal "" + End + + It "generates URL list from shipped NVR list" + BAD_COMMIT="6.12.0-200.el10.x86_64" + do_generate() { + resolve_rpm_list + echo "file=$KERNEL_RPM_LIST" + head -1 "$KERNEL_RPM_LIST" + tail -1 "$KERNEL_RPM_LIST" + } + When call do_generate + The line 1 should equal "file=${WORK_DIR}/kernel_rpm_list.txt" + The line 2 should equal \ + "https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0/30.el10/x86_64/kernel-core-6.12.0-30.el10.x86_64.rpm" + The line 3 should equal \ + "https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0/32.el10/x86_64/kernel-core-6.12.0-32.el10.x86_64.rpm" + End + + It "calls generator script when GENERATE_RPM_LIST=yes" + BAD_COMMIT="6.12.0-200.el10.x86_64" + GENERATE_RPM_LIST="yes" + # Create mock generator script + mkdir -p "$BIN_DIR/tools" + cat <<'SCRIPT' >"$BIN_DIR/tools/generate_rhel_kernel_rpm_list.py" +#!/usr/bin/env python3 +import sys +if "--nvr" in sys.argv: + print("6.12.0-99.el10") + print("6.12.0-100.el10") +SCRIPT + chmod +x "$BIN_DIR/tools/generate_rhel_kernel_rpm_list.py" + do_generate() { + resolve_rpm_list + head -1 "$KERNEL_RPM_LIST" + } + When call do_generate + The output should equal \ + "https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0/99.el10/x86_64/kernel-core-6.12.0-99.el10.x86_64.rpm" + End + End +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `shellspec spec/resolve_rpm_list_spec.sh` +Expected: FAIL — `resolve_rpm_list` not defined + +- [ ] **Step 3: Implement resolve_rpm_list** + +In `lib.sh`, add after `nvr_to_rpm_url()`: + +```bash +# Auto-generate KERNEL_RPM_LIST from shipped NVR lists or generator scripts. +# Called when KERNEL_RPM_LIST is not set and BAD_COMMIT is an NVR. +resolve_rpm_list() { + [[ -n "$KERNEL_RPM_LIST" ]] && return 0 + [[ "$INSTALL_STRATEGY" == "git" ]] && return 0 + is_nvr "$BAD_COMMIT" || return 0 + + local distro arch url_file + + distro=$(parse_nvr_distro "$BAD_COMMIT") || do_abort "Cannot detect distro from BAD_COMMIT: $BAD_COMMIT" + arch=$(parse_nvr_arch "$BAD_COMMIT") + url_file="$WORK_DIR/kernel_rpm_list.txt" + + if [[ "$GENERATE_RPM_LIST" == "yes" ]]; then + local generator_script generator_args + case "$distro" in + c9s) + generator_script="$BIN_DIR/tools/generate_rhel_kernel_rpm_list.py" + generator_args=(C9S "$arch") + ;; + c10s) + generator_script="$BIN_DIR/tools/generate_rhel_kernel_rpm_list.py" + generator_args=(C10S "$arch") + ;; + fedora) + generator_script="$BIN_DIR/tools/generate_fedora_kernel_rpm_list.py" + generator_args=("$arch") + ;; + esac + + if ! command -v python3 &>/dev/null; then + do_abort "GENERATE_RPM_LIST=yes requires python3" + fi + + local nvr_output + if ! nvr_output=$(python3 "$generator_script" --nvr "${generator_args[@]}"); then + do_abort "Failed to generate RPM list with $generator_script" + fi + + >"$url_file" + while IFS= read -r nvr; do + [[ -z "$nvr" ]] && continue + nvr_to_rpm_url "$nvr" "$arch" >>"$url_file" + done <<<"$nvr_output" + else + local nvr_list_file="$BIN_DIR/rpm_lists/${distro}.list" + if [[ ! -f "$nvr_list_file" ]]; then + do_abort "Shipped RPM list not found: $nvr_list_file. Set KERNEL_RPM_LIST or use GENERATE_RPM_LIST=yes." + fi + + >"$url_file" + while IFS= read -r nvr; do + [[ -z "$nvr" ]] && continue + nvr_to_rpm_url "$nvr" "$arch" >>"$url_file" + done <"$nvr_list_file" + fi + + KERNEL_RPM_LIST="$url_file" + log "Auto-generated KERNEL_RPM_LIST from ${distro} NVR list for ${arch}: $KERNEL_RPM_LIST" +} +``` + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `shellspec spec/resolve_rpm_list_spec.sh` +Expected: All tests PASS + +- [ ] **Step 5: Run full checks** + +Run: `make format-check static-analysis unit-tests` +Expected: All pass + +- [ ] **Step 6: Commit** + +```bash +git add spec/resolve_rpm_list_spec.sh lib.sh +git commit -m "Add resolve_rpm_list for auto-generating KERNEL_RPM_LIST" +``` + +--- + +### Task 4: Generator Script Changes + +**Files:** +- Modify: `tools/generate_fedora_kernel_rpm_list.py` +- Modify: `tools/generate_rhel_kernel_rpm_list.py` + +- [ ] **Step 1: Add --nvr flag and arch parameter to Fedora generator** + +In `tools/generate_fedora_kernel_rpm_list.py`, add after the existing imports (after line 6): + +```python +nvr_mode = "--nvr" in sys.argv +if nvr_mode: + sys.argv.remove("--nvr") + +arch = sys.argv[1] if len(sys.argv) > 1 else "x86_64" +``` + +This requires adding `import sys` to the imports. The full import block becomes: + +```python +import re +import sys +from bs4 import BeautifulSoup +from packaging.version import Version +import os +import urllib.request +``` + +Then replace the print statement at the end (line 42-43) from: + +```python + url = f'https://kojipkgs.fedoraproject.org/packages/kernel/{version}/{minor}/x86_64/kernel-core-{release_version}.x86_64.rpm' + print(url) +``` + +to: + +```python + if nvr_mode: + print(release_version) + else: + url = f'https://kojipkgs.fedoraproject.org/packages/kernel/{version}/{minor}/{arch}/kernel-core-{release_version}.{arch}.rpm' + print(url) +``` + +- [ ] **Step 2: Add --nvr flag to RHEL generator** + +In `tools/generate_rhel_kernel_rpm_list.py`, add after the existing imports (after line 8): + +```python +nvr_mode = "--nvr" in sys.argv +if nvr_mode: + sys.argv.remove("--nvr") +``` + +Then replace the print statement at the end (line 53) from: + +```python + url = f'{base_url}/{minor}/{arch}/kernel-core-{release_version}.{arch}.rpm' + print(url) +``` + +to: + +```python + if nvr_mode: + print(release_version) + else: + url = f'{base_url}/{minor}/{arch}/kernel-core-{release_version}.{arch}.rpm' + print(url) +``` + +- [ ] **Step 3: Run full checks** + +Run: `make format-check static-analysis unit-tests` +Expected: All pass + +- [ ] **Step 4: Commit** + +```bash +git add tools/generate_fedora_kernel_rpm_list.py tools/generate_rhel_kernel_rpm_list.py +git commit -m "Add --nvr flag and arch parameter to RPM list generators" +``` + +--- + +### Task 5: Ship NVR Lists + +**Files:** +- Create: `rpm_lists/c9s.list` +- Create: `rpm_lists/c10s.list` +- Create: `rpm_lists/fedora.list` + +- [ ] **Step 1: Generate NVR lists using the updated generators** + +```bash +mkdir -p rpm_lists +python3 tools/generate_rhel_kernel_rpm_list.py --nvr C9S x86_64 > rpm_lists/c9s.list +python3 tools/generate_rhel_kernel_rpm_list.py --nvr C10S x86_64 > rpm_lists/c10s.list +python3 tools/generate_fedora_kernel_rpm_list.py --nvr > rpm_lists/fedora.list +``` + +- [ ] **Step 2: Verify list contents** + +```bash +head -3 rpm_lists/c10s.list +tail -3 rpm_lists/c10s.list +wc -l rpm_lists/*.list +``` + +Expected: NVRs like `6.12.0-30.el10` (no URLs, no arch), reasonable line +counts matching the existing `c10s_nvrs/url_list` (~158 lines for c10s). + +- [ ] **Step 3: Commit** + +```bash +git add rpm_lists/ +git commit -m "Ship NVR lists for c9s, c10s, and fedora" +``` + +--- + +### Task 6: Integrate resolve_rpm_list into initialize() + +**Files:** +- Modify: `lib.sh:409` (initialize function) + +- [ ] **Step 1: Add resolve_rpm_list call to initialize()** + +In `lib.sh`, in the `initialize()` function, add `resolve_rpm_list` after +`mkdir -p "$WORK_DIR"` (line 409) and before `resolve_install_strategy` +(line 411). The block changes from: + +```bash + mkdir -p "$WORK_DIR" + + resolve_install_strategy +``` + +to: + +```bash + mkdir -p "$WORK_DIR" + + resolve_rpm_list + + resolve_install_strategy +``` + +- [ ] **Step 2: Run full checks** + +Run: `make format-check static-analysis unit-tests` +Expected: All pass + +- [ ] **Step 3: Commit** + +```bash +git add lib.sh +git commit -m "Integrate resolve_rpm_list into initialize()" +``` + +--- + +### Task 7: Makefile Updates + +**Files:** +- Modify: `Makefile` + +- [ ] **Step 1: Update .PHONY, add variables, update help, add update-rpm-lists, update install** + +In `Makefile`, change the `.PHONY` line (line 17) from: + +```makefile +.PHONY: all install uninstall clean help +``` + +to: + +```makefile +.PHONY: all install uninstall clean help update-rpm-lists +``` + +Add after the `HANDLER_SRCS` variable (after line 15): + +```makefile +RPM_LIST_DIR := rpm_lists +RPM_LIST_DIR_TARGET := $(BIN_DIR)/rpm_lists +``` + +Add to the `help` target output, after the `uninstall` line: + +```makefile + @echo " update-rpm-lists Refresh shipped NVR lists from upstream repos (requires python3)." +``` + +Add the `update-rpm-lists` target before the `install` target: + +```makefile +update-rpm-lists: + python3 tools/generate_rhel_kernel_rpm_list.py --nvr C9S x86_64 > $(RPM_LIST_DIR)/c9s.list + python3 tools/generate_rhel_kernel_rpm_list.py --nvr C10S x86_64 > $(RPM_LIST_DIR)/c10s.list + python3 tools/generate_fedora_kernel_rpm_list.py --nvr > $(RPM_LIST_DIR)/fedora.list +``` + +In the `install` target, after copying handler scripts (after the `chmod +x` +line for handlers, line 71), add: + +```makefile + @echo "Copying RPM NVR lists to $(RPM_LIST_DIR_TARGET)/" + @mkdir -p $(RPM_LIST_DIR_TARGET) + @cp $(RPM_LIST_DIR)/*.list $(RPM_LIST_DIR_TARGET)/ +``` + +- [ ] **Step 2: Verify Makefile** + +Run: `make help` +Expected: Shows `update-rpm-lists` in the target list + +- [ ] **Step 3: Commit** + +```bash +git add Makefile +git commit -m "Add update-rpm-lists target and install rpm_lists/" +``` + +--- + +### Task 8: Config and Documentation Updates + +**Files:** +- Modify: `bisect.conf` +- Modify: `README.md` + +- [ ] **Step 1: Update bisect.conf** + +Change the `KERNEL_RPM_LIST` line (line 40) from: + +```bash +KERNEL_RPM_LIST="/path/to/your/kernel_rpm_list.txt" +``` + +to: + +```bash +# KERNEL_RPM_LIST is optional. When omitted, the tool auto-selects a shipped +# NVR list based on BAD_COMMIT's dist tag and constructs RPM URLs at runtime. +# Set this to override with your own list of kernel RPM URLs (one per line). +#KERNEL_RPM_LIST="/path/to/your/kernel_rpm_list.txt" +``` + +Add after the `RPM_CACHE_DIR` line (after line 41): + +```bash + +# GENERATE_RPM_LIST: Set to "yes" to generate a fresh NVR list at runtime +# using the Python scripts in tools/ instead of the shipped static lists. +# Requires python3 with beautifulsoup4 and packaging modules. +#GENERATE_RPM_LIST="yes" +``` + +- [ ] **Step 2: Update README.md RPM Mode table** + +Change the `KERNEL_RPM_LIST` row (line 89) from: + +```markdown +| `KERNEL_RPM_LIST` | Path to a file listing kernel RPM URLs, one per line (ordered from good to bad) | +``` + +to: + +```markdown +| `KERNEL_RPM_LIST` | Path to a file listing kernel RPM URLs, one per line (ordered from good to bad). Optional — when omitted, auto-selected from shipped NVR lists based on `BAD_COMMIT`. | +``` + +- [ ] **Step 3: Add GENERATE_RPM_LIST to Other Options table in README.md** + +In the Other Options table (after line 106), add a new row: + +```markdown +| `GENERATE_RPM_LIST` | Set to `yes` to generate a fresh RPM list at runtime using Python scripts instead of shipped lists | +``` + +- [ ] **Step 4: Add RPM Lists section to README.md** + +After the "Installation (optional for remote mode)" section (after line 60), +add: + +```markdown +## RPM Lists + +The tool ships pre-built NVR lists in `rpm_lists/` for CentOS Stream 9, +CentOS Stream 10, and Fedora. When `KERNEL_RPM_LIST` is not set, the tool +auto-detects the distro and architecture from `BAD_COMMIT` and uses the +appropriate shipped list to construct RPM URLs at runtime. + +To generate a fresh RPM list at runtime (requires `python3`, +`beautifulsoup4`, `packaging`), set in `bisect.conf`: + +``` +GENERATE_RPM_LIST="yes" +``` + +To refresh the shipped lists (maintainer use): + +```bash +make update-rpm-lists +``` +``` + +- [ ] **Step 5: Run full checks** + +Run: `make format-check static-analysis unit-tests` +Expected: All pass + +- [ ] **Step 6: Commit** + +```bash +git add bisect.conf README.md +git commit -m "Document optional KERNEL_RPM_LIST and GENERATE_RPM_LIST" +``` diff --git a/docs/superpowers/specs/2026-04-11-optional-kernel-rpm-list-design.md b/docs/superpowers/specs/2026-04-11-optional-kernel-rpm-list-design.md new file mode 100644 index 0000000..74f0a2e --- /dev/null +++ b/docs/superpowers/specs/2026-04-11-optional-kernel-rpm-list-design.md @@ -0,0 +1,145 @@ +# Optional KERNEL_RPM_LIST with Auto-Detection + +## Problem + +Users must manually run a Python generator script and set `KERNEL_RPM_LIST` in +`bisect.conf` before starting an RPM bisect. This is tedious when the tool +could infer the RPM list from `BAD_COMMIT`. + +## Solution + +Make `KERNEL_RPM_LIST` optional. When omitted, the tool auto-detects the +distro and architecture from `BAD_COMMIT`'s NVR, selects a shipped NVR list, +constructs full RPM URLs at runtime, and writes them to +`$WORK_DIR/kernel_rpm_list.txt`. Users can opt into fresh list generation via +`GENERATE_RPM_LIST=yes`. + +## Design + +### 1. Shipped NVR Lists + +A new `rpm_lists/` directory at the project root: + +``` +rpm_lists/ + c9s.list + c10s.list + fedora.list +``` + +Each `.list` file contains one NVR per line (e.g., `6.12.0-30.el10`), ordered +oldest to newest. These are committed to the repo and copied into +`$BIN_DIR/rpm_lists/` by `make install`. + +### 2. NVR Parsing and Auto-Detection + +A new function `resolve_rpm_list()` in `lib.sh`, called during `initialize()` +after `resolve_install_strategy()` but before the existing code that reads +`KERNEL_RPM_LIST` (i.e., before `generate_git_repo_from_package_list`). It +runs when `INSTALL_STRATEGY` is `rpm` (or auto mode) and `KERNEL_RPM_LIST` is +not set. It: + +1. Parses `BAD_COMMIT` to extract distro and arch: + - `6.12.0-200.el10.x86_64` -> distro=`c10s`, arch=`x86_64` + - `5.14.0-400.el9.aarch64` -> distro=`c9s`, arch=`aarch64` + - `6.16.5-100.fc41.x86_64` -> distro=`fedora`, arch=`x86_64` +2. Looks up the shipped NVR list at `$BIN_DIR/rpm_lists/.list`. +3. Constructs full URLs from each NVR + detected arch + base URL map, writes + them to `$WORK_DIR/kernel_rpm_list.txt`. +4. Sets `KERNEL_RPM_LIST` to that generated file. + +If `KERNEL_RPM_LIST` is already set by the user, this step is skipped entirely. + +### 3. URL Construction + +Base URL map by distro: + +| Dist tag | Base URL | +|----------|----------| +| `.el9` | `https://kojihub.stream.centos.org/kojifiles/packages/kernel` | +| `.el10` | `https://kojihub.stream.centos.org/kojifiles/packages/kernel` | +| `.fc*` | `https://kojipkgs.fedoraproject.org/packages/kernel` | + +Each NVR (e.g., `6.12.0-30.el10`) is split into version (`6.12.0`) and +release (`30.el10`). The full URL is: + +``` +////kernel-core-..rpm +``` + +### 4. Opt-In Fresh Generation + +A new config option `GENERATE_RPM_LIST` in `bisect.conf`. When set to `yes`: + +1. `resolve_rpm_list()` skips the shipped static lists. +2. Detects which generator script to use from the distro tag: + - `.el*` -> `tools/generate_rhel_kernel_rpm_list.py` (args: distro like + `C9S`/`C10S`, arch) + - `.fc*` -> `tools/generate_fedora_kernel_rpm_list.py` (args: arch) +3. Calls the generator with `--nvr` flag to produce NVR output. +4. Constructs URLs from the NVR output (same logic as shipped lists). +5. Saves to `$WORK_DIR/kernel_rpm_list.txt` and sets `KERNEL_RPM_LIST`. + +If the Python script or its dependencies are missing, the tool aborts with a +clear error message. + +### 5. Generator Script Changes + +Both `tools/generate_fedora_kernel_rpm_list.py` and +`tools/generate_rhel_kernel_rpm_list.py` are extended: + +- **`--nvr` flag**: Output NVRs instead of full URLs. +- **`generate_fedora_kernel_rpm_list.py`**: Accept an optional `arch` argument + (default `x86_64` for backward compatibility). + +### 6. Makefile Updates + +- **`make update-rpm-lists`**: Runs the generator scripts with `--nvr` for + each distro to refresh the shipped `.list` files in `rpm_lists/`. +- **`install` target**: Copies `rpm_lists/` into `$BIN_DIR/rpm_lists/`. + +### 7. Config and Documentation + +**`bisect.conf`:** +- `KERNEL_RPM_LIST` default changed to commented-out (clearly optional). +- New `GENERATE_RPM_LIST` option added (commented out). + +**`README.md`:** +- RPM Mode table updated to note `KERNEL_RPM_LIST` is optional. +- `GENERATE_RPM_LIST=yes` documented. +- `make update-rpm-lists` documented for maintainers. + +### 8. Testing + +New ShellSpec unit tests: + +- **NVR parsing**: Extracting distro and arch from various `BAD_COMMIT` + formats (`.el9`, `.el10`, `.fc41`, different arches). +- **URL construction**: Given an NVR, distro, and arch, verify the correct + full URL is built. +- **`resolve_rpm_list()`**: When `KERNEL_RPM_LIST` is unset, verify it picks + the right shipped list and generates the URL file. +- **`resolve_rpm_list()` skip**: When `KERNEL_RPM_LIST` is already set, + verify it is left untouched. +- **`GENERATE_RPM_LIST=yes`**: Verify it calls the generator script instead + of using shipped lists (mocking the Python call). + +Existing integration tests are unaffected (they all set `KERNEL_RPM_LIST` +explicitly). + +## Scope + +### In scope +- `resolve_rpm_list()` function in `lib.sh` +- NVR parsing and URL construction helpers in `lib.sh` +- `rpm_lists/` directory with shipped NVR lists +- `--nvr` flag and arch parameter for generator scripts +- `make update-rpm-lists` target +- `make install` update to copy `rpm_lists/` +- Config and docs updates +- ShellSpec unit tests + +### Out of scope +- RHEL (non-CentOS-Stream) shipped lists (requires internal network access) +- Filtering RPM lists to good/bad range (existing git bisect handles this) +- Changes to integration tests diff --git a/lib.sh b/lib.sh index a03d500..3ff6c6c 100644 --- a/lib.sh +++ b/lib.sh @@ -224,6 +224,109 @@ nvr_to_tag() { echo "kernel-${tag_name}" } +# Extract distro identifier from NVR for RPM list lookup +# e.g., "6.12.0-200.el10.x86_64" -> "c10s" +parse_nvr_distro() { + local nvr=$1 + if [[ "$nvr" =~ \.el9[.] ]] || [[ "$nvr" =~ \.el9$ ]]; then + echo "c9s" + elif [[ "$nvr" =~ \.el10[.] ]] || [[ "$nvr" =~ \.el10$ ]]; then + echo "c10s" + elif [[ "$nvr" =~ \.fc[0-9]+ ]]; then + echo "fedora" + else + return 1 + fi +} + +# Extract architecture from NVR (last dot-separated component) +# e.g., "6.12.0-200.el10.x86_64" -> "x86_64" +parse_nvr_arch() { + echo "${1##*.}" +} + +# Construct full kernel-core RPM URL from NVR and arch +# e.g., nvr_to_rpm_url "6.12.0-30.el10" "x86_64" -> +# https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0/30.el10/x86_64/kernel-core-6.12.0-30.el10.x86_64.rpm +nvr_to_rpm_url() { + local nvr=$1 arch=$2 + local base_url version release + + version="${nvr%%-*}" + release="${nvr#*-}" + + if [[ "$nvr" =~ \.el[0-9]+ ]]; then + base_url="https://kojihub.stream.centos.org/kojifiles/packages/kernel" + elif [[ "$nvr" =~ \.fc[0-9]+ ]]; then + base_url="https://kojipkgs.fedoraproject.org/packages/kernel" + else + return 1 + fi + + echo "${base_url}/${version}/${release}/${arch}/kernel-core-${nvr}.${arch}.rpm" +} + +# Auto-generate KERNEL_RPM_LIST from shipped NVR lists or generator scripts. +# Called when KERNEL_RPM_LIST is not set and BAD_COMMIT is an NVR. +resolve_rpm_list() { + [[ -n "$KERNEL_RPM_LIST" ]] && return 0 + [[ "$INSTALL_STRATEGY" == "git" ]] && return 0 + is_nvr "$BAD_COMMIT" || return 0 + + local distro arch url_file + + distro=$(parse_nvr_distro "$BAD_COMMIT") || do_abort "Cannot detect distro from BAD_COMMIT: $BAD_COMMIT" + arch=$(parse_nvr_arch "$BAD_COMMIT") + url_file="$WORK_DIR/kernel_rpm_list.txt" + + if [[ "$GENERATE_RPM_LIST" == "yes" ]]; then + local generator_script generator_args + case "$distro" in + c9s) + generator_script="$BIN_DIR/tools/generate_rhel_kernel_rpm_list.py" + generator_args=(C9S "$arch") + ;; + c10s) + generator_script="$BIN_DIR/tools/generate_rhel_kernel_rpm_list.py" + generator_args=(C10S "$arch") + ;; + fedora) + generator_script="$BIN_DIR/tools/generate_fedora_kernel_rpm_list.py" + generator_args=("$arch") + ;; + esac + + if ! command -v python3 &>/dev/null; then + do_abort "GENERATE_RPM_LIST=yes requires python3" + fi + + local nvr_output + if ! nvr_output=$(python3 "$generator_script" --nvr "${generator_args[@]}"); then + do_abort "Failed to generate RPM list with $generator_script" + fi + + : >"$url_file" + while IFS= read -r nvr; do + [[ -z "$nvr" ]] && continue + nvr_to_rpm_url "$nvr" "$arch" >>"$url_file" + done <<<"$nvr_output" + else + local nvr_list_file="$BIN_DIR/rpm_lists/${distro}.list" + if [[ ! -f "$nvr_list_file" ]]; then + do_abort "Shipped RPM list not found: $nvr_list_file. Set KERNEL_RPM_LIST or use GENERATE_RPM_LIST=yes." + fi + + : >"$url_file" + while IFS= read -r nvr; do + [[ -z "$nvr" ]] && continue + nvr_to_rpm_url "$nvr" "$arch" >>"$url_file" + done <"$nvr_list_file" + fi + + KERNEL_RPM_LIST="$url_file" + log "Auto-generated KERNEL_RPM_LIST from ${distro} NVR list for ${arch}: $KERNEL_RPM_LIST" +} + # Auto-detect GIT_REPO_URL from NVR dist tag detect_git_repo_url() { local nvr=$1 @@ -408,6 +511,8 @@ initialize() { mkdir -p "$WORK_DIR" + resolve_rpm_list + resolve_install_strategy good_ref="$GOOD_COMMIT" diff --git a/rpm_lists/c10s.list b/rpm_lists/c10s.list new file mode 100644 index 0000000..19a1294 --- /dev/null +++ b/rpm_lists/c10s.list @@ -0,0 +1,166 @@ +6.12.0-30.el10 +6.12.0-31.el10 +6.12.0-32.el10 +6.12.0-33.el10 +6.12.0-34.el10 +6.12.0-35.el10 +6.12.0-36.el10 +6.12.0-37.el10 +6.12.0-38.el10 +6.12.0-39.el10 +6.12.0-40.el10 +6.12.0-41.el10 +6.12.0-42.el10 +6.12.0-43.el10 +6.12.0-45.el10 +6.12.0-46.el10 +6.12.0-47.el10 +6.12.0-48.el10 +6.12.0-50.el10 +6.12.0-51.el10 +6.12.0-52.el10 +6.12.0-53.el10 +6.12.0-54.el10 +6.12.0-55.el10 +6.12.0-56.el10 +6.12.0-58.el10 +6.12.0-59.el10 +6.12.0-61.el10 +6.12.0-62.el10 +6.12.0-63.el10 +6.12.0-65.el10 +6.12.0-66.el10 +6.12.0-68.el10 +6.12.0-70.el10 +6.12.0-72.el10 +6.12.0-73.el10 +6.12.0-74.el10 +6.12.0-75.el10 +6.12.0-77.el10 +6.12.0-80.el10 +6.12.0-81.el10 +6.12.0-82.el10 +6.12.0-83.el10 +6.12.0-84.el10 +6.12.0-85.el10 +6.12.0-86.el10 +6.12.0-87.el10 +6.12.0-89.el10 +6.12.0-90.el10 +6.12.0-91.el10 +6.12.0-92.el10 +6.12.0-94.el10 +6.12.0-95.el10 +6.12.0-96.el10 +6.12.0-98.el10 +6.12.0-100.el10 +6.12.0-101.el10 +6.12.0-103.el10 +6.12.0-105.el10 +6.12.0-107.el10 +6.12.0-108.el10 +6.12.0-109.el10 +6.12.0-113.el10 +6.12.0-114.el10 +6.12.0-115.el10 +6.12.0-116.el10 +6.12.0-119.el10 +6.12.0-120.el10 +6.12.0-121.el10 +6.12.0-122.el10 +6.12.0-124.el10 +6.12.0-125.el10 +6.12.0-126.el10 +6.12.0-127.el10 +6.12.0-128.el10 +6.12.0-129.el10 +6.12.0-130.el10 +6.12.0-131.el10 +6.12.0-132.el10 +6.12.0-133.el10 +6.12.0-134.el10 +6.12.0-135.el10 +6.12.0-136.el10 +6.12.0-137.el10 +6.12.0-138.el10 +6.12.0-139.el10 +6.12.0-140.el10 +6.12.0-141.el10 +6.12.0-142.el10 +6.12.0-143.el10 +6.12.0-144.el10 +6.12.0-145.el10 +6.12.0-146.el10 +6.12.0-147.el10 +6.12.0-148.el10 +6.12.0-149.el10 +6.12.0-150.el10 +6.12.0-151.el10 +6.12.0-152.el10 +6.12.0-153.el10 +6.12.0-155.el10 +6.12.0-156.el10 +6.12.0-157.el10 +6.12.0-158.el10 +6.12.0-159.el10 +6.12.0-160.el10 +6.12.0-161.el10 +6.12.0-162.el10 +6.12.0-163.el10 +6.12.0-164.el10 +6.12.0-165.el10 +6.12.0-167.el10 +6.12.0-168.el10 +6.12.0-169.el10 +6.12.0-170.el10 +6.12.0-171.el10 +6.12.0-172.el10 +6.12.0-173.el10 +6.12.0-174.el10 +6.12.0-175.el10 +6.12.0-176.el10 +6.12.0-177.el10 +6.12.0-178.el10 +6.12.0-179.el10 +6.12.0-180.el10 +6.12.0-181.el10 +6.12.0-182.el10 +6.12.0-183.el10 +6.12.0-184.el10 +6.12.0-185.el10 +6.12.0-186.el10 +6.12.0-187.el10 +6.12.0-188.el10 +6.12.0-189.el10 +6.12.0-190.el10 +6.12.0-191.el10 +6.12.0-192.el10 +6.12.0-193.el10 +6.12.0-194.el10 +6.12.0-195.el10 +6.12.0-196.el10 +6.12.0-197.el10 +6.12.0-198.el10 +6.12.0-199.el10 +6.12.0-200.el10 +6.12.0-201.el10 +6.12.0-202.el10 +6.12.0-203.el10 +6.12.0-204.el10 +6.12.0-205.el10 +6.12.0-206.el10 +6.12.0-207.el10 +6.12.0-208.el10 +6.12.0-209.el10 +6.12.0-210.el10 +6.12.0-211.el10 +6.12.0-212.el10 +6.12.0-213.el10 +6.12.0-214.el10 +6.12.0-215.el10 +6.12.0-216.el10 +6.12.0-217.el10 +6.12.0-218.el10 +6.12.0-219.el10 +6.12.0-220.el10 +6.12.0-221.el10 diff --git a/rpm_lists/c9s.list b/rpm_lists/c9s.list new file mode 100644 index 0000000..9e3b20f --- /dev/null +++ b/rpm_lists/c9s.list @@ -0,0 +1,592 @@ +5.14.0-1.el9 +5.14.0-2.el9 +5.14.0-3.el9 +5.14.0-4.el9 +5.14.0-5.el9 +5.14.0-6.el9 +5.14.0-7.el9 +5.14.0-8.el9 +5.14.0-9.el9 +5.14.0-10.el9 +5.14.0-11.el9 +5.14.0-12.el9 +5.14.0-13.el9 +5.14.0-14.el9 +5.14.0-15.el9 +5.14.0-16.el9 +5.14.0-17.el9 +5.14.0-20.el9 +5.14.0-21.el9 +5.14.0-22.el9 +5.14.0-23.el9 +5.14.0-24.el9 +5.14.0-25.el9 +5.14.0-26.el9 +5.14.0-27.el9 +5.14.0-28.el9 +5.14.0-29.el9 +5.14.0-30.el9 +5.14.0-31.el9 +5.14.0-32.el9 +5.14.0-33.el9 +5.14.0-34.el9 +5.14.0-35.el9 +5.14.0-36.el9 +5.14.0-37.el9 +5.14.0-38.el9 +5.14.0-39.el9 +5.14.0-40.el9 +5.14.0-41.el9 +5.14.0-42.el9 +5.14.0-43.el9 +5.14.0-44.el9 +5.14.0-45.el9 +5.14.0-46.el9 +5.14.0-47.el9 +5.14.0-48.el9 +5.14.0-49.el9 +5.14.0-50.el9 +5.14.0-51.el9 +5.14.0-52.el9 +5.14.0-53.el9 +5.14.0-54.el9 +5.14.0-55.el9 +5.14.0-56.el9 +5.14.0-57.el9 +5.14.0-58.el9 +5.14.0-59.el9 +5.14.0-60.el9 +5.14.0-61.el9 +5.14.0-62.el9 +5.14.0-63.el9 +5.14.0-64.el9 +5.14.0-65.el9 +5.14.0-66.el9 +5.14.0-67.el9 +5.14.0-68.el9 +5.14.0-69.el9 +5.14.0-70.el9 +5.14.0-71.el9 +5.14.0-72.el9 +5.14.0-73.el9 +5.14.0-74.el9 +5.14.0-75.el9 +5.14.0-77.el9 +5.14.0-78.el9 +5.14.0-79.el9 +5.14.0-80.el9 +5.14.0-81.el9 +5.14.0-82.el9 +5.14.0-83.el9 +5.14.0-84.el9 +5.14.0-85.el9 +5.14.0-86.el9 +5.14.0-87.el9 +5.14.0-88.el9 +5.14.0-89.el9 +5.14.0-90.el9 +5.14.0-92.el9 +5.14.0-93.el9 +5.14.0-95.el9 +5.14.0-96.el9 +5.14.0-97.el9 +5.14.0-98.el9 +5.14.0-99.el9 +5.14.0-100.el9 +5.14.0-101.el9 +5.14.0-103.el9 +5.14.0-104.el9 +5.14.0-105.el9 +5.14.0-106.el9 +5.14.0-107.el9 +5.14.0-108.el9 +5.14.0-109.el9 +5.14.0-110.el9 +5.14.0-111.el9 +5.14.0-112.el9 +5.14.0-113.el9 +5.14.0-114.el9 +5.14.0-115.el9 +5.14.0-116.el9 +5.14.0-117.el9 +5.14.0-118.el9 +5.14.0-119.el9 +5.14.0-120.el9 +5.14.0-121.el9 +5.14.0-122.el9 +5.14.0-123.el9 +5.14.0-124.el9 +5.14.0-125.el9 +5.14.0-126.el9 +5.14.0-127.el9 +5.14.0-128.el9 +5.14.0-129.el9 +5.14.0-130.el9 +5.14.0-131.el9 +5.14.0-133.el9 +5.14.0-134.el9 +5.14.0-135.el9 +5.14.0-136.el9 +5.14.0-137.el9 +5.14.0-138.el9 +5.14.0-139.el9 +5.14.0-140.el9 +5.14.0-141.el9 +5.14.0-142.el9 +5.14.0-143.el9 +5.14.0-144.el9 +5.14.0-145.el9 +5.14.0-146.el9 +5.14.0-147.el9 +5.14.0-148.el9 +5.14.0-149.el9 +5.14.0-150.el9 +5.14.0-151.el9 +5.14.0-152.el9 +5.14.0-153.el9 +5.14.0-154.el9 +5.14.0-160.el9 +5.14.0-161.el9 +5.14.0-162.el9 +5.14.0-163.el9 +5.14.0-164.el9 +5.14.0-165.el9 +5.14.0-166.el9 +5.14.0-167.el9 +5.14.0-168.el9 +5.14.0-169.el9 +5.14.0-170.el9 +5.14.0-171.el9 +5.14.0-173.el9 +5.14.0-174.el9 +5.14.0-175.el9 +5.14.0-176.el9 +5.14.0-177.el9 +5.14.0-178.el9 +5.14.0-179.el9 +5.14.0-180.el9 +5.14.0-181.el9 +5.14.0-182.el9 +5.14.0-183.el9 +5.14.0-184.el9 +5.14.0-185.el9 +5.14.0-186.el9 +5.14.0-187.el9 +5.14.0-188.el9 +5.14.0-190.el9 +5.14.0-191.el9 +5.14.0-192.el9 +5.14.0-193.el9 +5.14.0-194.el9 +5.14.0-196.el9 +5.14.0-197.el9 +5.14.0-199.el9 +5.14.0-200.el9 +5.14.0-201.el9 +5.14.0-202.el9 +5.14.0-203.el9 +5.14.0-204.el9 +5.14.0-205.el9 +5.14.0-206.el9 +5.14.0-207.el9 +5.14.0-208.el9 +5.14.0-209.el9 +5.14.0-210.el9 +5.14.0-212.el9 +5.14.0-214.el9 +5.14.0-215.el9 +5.14.0-216.el9 +5.14.0-217.el9 +5.14.0-218.el9 +5.14.0-219.el9 +5.14.0-220.el9 +5.14.0-221.el9 +5.14.0-222.el9 +5.14.0-223.el9 +5.14.0-224.el9 +5.14.0-225.el9 +5.14.0-226.el9 +5.14.0-227.el9 +5.14.0-228.el9 +5.14.0-229.el9 +5.14.0-230.el9 +5.14.0-231.el9 +5.14.0-232.el9 +5.14.0-233.el9 +5.14.0-234.el9 +5.14.0-235.el9 +5.14.0-236.el9 +5.14.0-237.el9 +5.14.0-238.el9 +5.14.0-239.el9 +5.14.0-240.el9 +5.14.0-241.el9 +5.14.0-242.el9 +5.14.0-243.el9 +5.14.0-244.el9 +5.14.0-245.el9 +5.14.0-246.el9 +5.14.0-247.el9 +5.14.0-248.el9 +5.14.0-249.el9 +5.14.0-250.el9 +5.14.0-251.el9 +5.14.0-252.el9 +5.14.0-253.el9 +5.14.0-255.el9 +5.14.0-258.el9 +5.14.0-260.el9 +5.14.0-264.el9 +5.14.0-265.el9 +5.14.0-266.el9 +5.14.0-267.el9 +5.14.0-268.el9 +5.14.0-269.el9 +5.14.0-270.el9 +5.14.0-271.el9 +5.14.0-272.el9 +5.14.0-273.el9 +5.14.0-274.el9 +5.14.0-275.el9 +5.14.0-276.el9 +5.14.0-277.el9 +5.14.0-278.el9 +5.14.0-279.el9 +5.14.0-280.el9 +5.14.0-281.el9 +5.14.0-282.el9 +5.14.0-283.el9 +5.14.0-284.el9 +5.14.0-285.el9 +5.14.0-289.el9 +5.14.0-293.el9 +5.14.0-295.el9 +5.14.0-298.el9 +5.14.0-299.el9 +5.14.0-300.el9 +5.14.0-302.el9 +5.14.0-303.el9 +5.14.0-305.el9 +5.14.0-306.el9 +5.14.0-307.el9 +5.14.0-309.el9 +5.14.0-310.el9 +5.14.0-311.el9 +5.14.0-312.el9 +5.14.0-313.el9 +5.14.0-315.el9 +5.14.0-316.el9 +5.14.0-318.el9 +5.14.0-319.el9 +5.14.0-322.el9 +5.14.0-323.el9 +5.14.0-324.el9 +5.14.0-325.el9 +5.14.0-326.el9 +5.14.0-327.el9 +5.14.0-329.el9 +5.14.0-330.el9 +5.14.0-331.el9 +5.14.0-332.el9 +5.14.0-333.el9 +5.14.0-337.el9 +5.14.0-339.el9 +5.14.0-340.el9 +5.14.0-341.el9 +5.14.0-342.el9 +5.14.0-343.el9 +5.14.0-344.el9 +5.14.0-345.el9 +5.14.0-347.el9 +5.14.0-348.el9 +5.14.0-349.el9 +5.14.0-350.el9 +5.14.0-351.el9 +5.14.0-352.el9 +5.14.0-353.el9 +5.14.0-354.el9 +5.14.0-355.el9 +5.14.0-356.el9 +5.14.0-360.el9 +5.14.0-361.el9 +5.14.0-362.el9 +5.14.0-363.el9 +5.14.0-364.el9 +5.14.0-365.el9 +5.14.0-366.el9 +5.14.0-367.el9 +5.14.0-368.el9 +5.14.0-369.el9 +5.14.0-370.el9 +5.14.0-371.el9 +5.14.0-372.el9 +5.14.0-373.el9 +5.14.0-374.el9 +5.14.0-375.el9 +5.14.0-376.el9 +5.14.0-377.el9 +5.14.0-378.el9 +5.14.0-379.el9 +5.14.0-380.el9 +5.14.0-381.el9 +5.14.0-382.el9 +5.14.0-383.el9 +5.14.0-384.el9 +5.14.0-385.el9 +5.14.0-386.el9 +5.14.0-387.el9 +5.14.0-388.el9 +5.14.0-390.el9 +5.14.0-391.el9 +5.14.0-392.el9 +5.14.0-394.el9 +5.14.0-395.el9 +5.14.0-396.el9 +5.14.0-397.el9 +5.14.0-398.el9 +5.14.0-399.el9 +5.14.0-400.el9 +5.14.0-401.el9 +5.14.0-402.el9 +5.14.0-403.el9 +5.14.0-404.el9 +5.14.0-405.el9 +5.14.0-406.el9 +5.14.0-407.el9 +5.14.0-408.el9 +5.14.0-409.el9 +5.14.0-410.el9 +5.14.0-411.el9 +5.14.0-412.el9 +5.14.0-413.el9 +5.14.0-414.el9 +5.14.0-415.el9 +5.14.0-416.el9 +5.14.0-417.el9 +5.14.0-418.el9 +5.14.0-419.el9 +5.14.0-420.el9 +5.14.0-421.el9 +5.14.0-422.el9 +5.14.0-423.el9 +5.14.0-424.el9 +5.14.0-425.el9 +5.14.0-427.el9 +5.14.0-428.el9 +5.14.0-430.el9 +5.14.0-432.el9 +5.14.0-433.el9 +5.14.0-434.el9 +5.14.0-435.el9 +5.14.0-436.el9 +5.14.0-437.el9 +5.14.0-439.el9 +5.14.0-440.el9 +5.14.0-442.el9 +5.14.0-443.el9 +5.14.0-444.el9 +5.14.0-446.el9 +5.14.0-447.el9 +5.14.0-450.el9 +5.14.0-451.el9 +5.14.0-452.el9 +5.14.0-453.el9 +5.14.0-454.el9 +5.14.0-455.el9 +5.14.0-457.el9 +5.14.0-458.el9 +5.14.0-459.el9 +5.14.0-460.el9 +5.14.0-461.el9 +5.14.0-463.el9 +5.14.0-464.el9 +5.14.0-465.el9 +5.14.0-467.el9 +5.14.0-469.el9 +5.14.0-472.el9 +5.14.0-474.el9 +5.14.0-476.el9 +5.14.0-477.el9 +5.14.0-478.el9 +5.14.0-479.el9 +5.14.0-480.el9 +5.14.0-487.el9 +5.14.0-490.el9 +5.14.0-491.el9 +5.14.0-492.el9 +5.14.0-493.el9 +5.14.0-494.el9 +5.14.0-496.el9 +5.14.0-497.el9 +5.14.0-498.el9 +5.14.0-499.el9 +5.14.0-502.el9 +5.14.0-503.el9 +5.14.0-504.el9 +5.14.0-505.el9 +5.14.0-506.el9 +5.14.0-507.el9 +5.14.0-508.el9 +5.14.0-509.el9 +5.14.0-510.el9 +5.14.0-511.el9 +5.14.0-512.el9 +5.14.0-513.el9 +5.14.0-514.el9 +5.14.0-515.el9 +5.14.0-516.el9 +5.14.0-518.el9 +5.14.0-519.el9 +5.14.0-520.el9 +5.14.0-521.el9 +5.14.0-522.el9 +5.14.0-523.el9 +5.14.0-524.el9 +5.14.0-526.el9 +5.14.0-527.el9 +5.14.0-528.el9 +5.14.0-529.el9 +5.14.0-531.el9 +5.14.0-533.el9 +5.14.0-534.el9 +5.14.0-535.el9 +5.14.0-536.el9 +5.14.0-537.el9 +5.14.0-539.el9 +5.14.0-542.el9 +5.14.0-544.el9 +5.14.0-545.el9 +5.14.0-547.el9 +5.14.0-552.el9 +5.14.0-553.el9 +5.14.0-554.el9 +5.14.0-556.el9 +5.14.0-557.el9 +5.14.0-558.el9 +5.14.0-559.el9 +5.14.0-560.el9 +5.14.0-561.el9 +5.14.0-562.el9 +5.14.0-563.el9 +5.14.0-564.el9 +5.14.0-565.el9 +5.14.0-567.el9 +5.14.0-568.el9 +5.14.0-569.el9 +5.14.0-570.el9 +5.14.0-571.el9 +5.14.0-572.el9 +5.14.0-573.el9 +5.14.0-574.el9 +5.14.0-575.el9 +5.14.0-576.el9 +5.14.0-578.el9 +5.14.0-579.el9 +5.14.0-580.el9 +5.14.0-581.el9 +5.14.0-582.el9 +5.14.0-583.el9 +5.14.0-584.el9 +5.14.0-585.el9 +5.14.0-586.el9 +5.14.0-587.el9 +5.14.0-588.el9 +5.14.0-590.el9 +5.14.0-591.el9 +5.14.0-592.el9 +5.14.0-593.el9 +5.14.0-594.el9 +5.14.0-595.el9 +5.14.0-596.el9 +5.14.0-597.el9 +5.14.0-598.el9 +5.14.0-599.el9 +5.14.0-600.el9 +5.14.0-601.el9 +5.14.0-602.el9 +5.14.0-603.el9 +5.14.0-604.el9 +5.14.0-605.el9 +5.14.0-608.el9 +5.14.0-609.el9 +5.14.0-610.el9 +5.14.0-611.el9 +5.14.0-612.el9 +5.14.0-613.el9 +5.14.0-614.el9 +5.14.0-615.el9 +5.14.0-616.el9 +5.14.0-617.el9 +5.14.0-618.el9 +5.14.0-619.el9 +5.14.0-620.el9 +5.14.0-621.el9 +5.14.0-623.el9 +5.14.0-624.el9 +5.14.0-625.el9 +5.14.0-626.el9 +5.14.0-627.el9 +5.14.0-628.el9 +5.14.0-629.el9 +5.14.0-630.el9 +5.14.0-631.el9 +5.14.0-632.el9 +5.14.0-633.el9 +5.14.0-634.el9 +5.14.0-635.el9 +5.14.0-636.el9 +5.14.0-637.el9 +5.14.0-639.el9 +5.14.0-640.el9 +5.14.0-641.el9 +5.14.0-642.el9 +5.14.0-643.el9 +5.14.0-644.el9 +5.14.0-645.el9 +5.14.0-646.el9 +5.14.0-647.el9 +5.14.0-648.el9 +5.14.0-649.el9 +5.14.0-650.el9 +5.14.0-651.el9 +5.14.0-652.el9 +5.14.0-653.el9 +5.14.0-654.el9 +5.14.0-655.el9 +5.14.0-656.el9 +5.14.0-657.el9 +5.14.0-658.el9 +5.14.0-659.el9 +5.14.0-660.el9 +5.14.0-661.el9 +5.14.0-662.el9 +5.14.0-663.el9 +5.14.0-664.el9 +5.14.0-665.el9 +5.14.0-666.el9 +5.14.0-667.el9 +5.14.0-668.el9 +5.14.0-669.el9 +5.14.0-670.el9 +5.14.0-671.el9 +5.14.0-672.el9 +5.14.0-673.el9 +5.14.0-674.el9 +5.14.0-675.el9 +5.14.0-676.el9 +5.14.0-677.el9 +5.14.0-678.el9 +5.14.0-679.el9 +5.14.0-680.el9 +5.14.0-681.el9 +5.14.0-682.el9 +5.14.0-683.el9 +5.14.0-684.el9 +5.14.0-685.el9 +5.14.0-686.el9 +5.14.0-687.el9 +5.14.0-688.el9 +5.14.0-689.el9 +5.14.0-690.el9 +5.14.0-691.el9 +5.14.0-692.el9 diff --git a/rpm_lists/fedora.list b/rpm_lists/fedora.list new file mode 100644 index 0000000..a2e775e --- /dev/null +++ b/rpm_lists/fedora.list @@ -0,0 +1,220 @@ +6.0.5-200.fc36 +6.0.6-300.fc37 +6.0.7-301.fc37 +6.0.8-300.fc37 +6.0.9-300.fc37 +6.0.10-300.fc37 +6.0.11-300.fc37 +6.0.12-300.fc37 +6.0.13-300.fc37 +6.0.14-300.fc37 +6.0.15-300.fc37 +6.0.16-300.fc37 +6.0.17-300.fc37 +6.0.18-300.fc37 +6.1.5-200.fc37 +6.1.6-200.fc37 +6.1.7-200.fc37 +6.1.8-200.fc37 +6.1.9-200.fc37 +6.1.10-200.fc37 +6.1.11-200.fc37 +6.1.12-200.fc37 +6.1.13-200.fc37 +6.1.14-200.fc37 +6.1.15-200.fc37 +6.1.18-200.fc37 +6.2.0-63.fc38 +6.2.2-301.fc38 +6.2.3-300.fc38 +6.2.5-300.fc38 +6.2.6-300.fc38 +6.2.7-300.fc38 +6.2.8-300.fc38 +6.2.9-300.fc38 +6.2.10-300.fc38 +6.2.11-300.fc38 +6.2.12-300.fc38 +6.2.13-300.fc38 +6.2.14-300.fc38 +6.2.15-300.fc38 +6.3.4-201.fc38 +6.3.5-200.fc38 +6.3.6-200.fc38 +6.3.7-200.fc38 +6.3.8-200.fc38 +6.3.10-200.fc38 +6.3.11-200.fc38 +6.3.12-200.fc38 +6.4.0-59.fc39 +6.4.4-200.fc38 +6.4.6-200.fc38 +6.4.7-200.fc38 +6.4.8-200.fc38 +6.4.9-200.fc38 +6.4.10-200.fc38 +6.4.11-200.fc38 +6.4.12-200.fc38 +6.4.13-200.fc38 +6.4.14-200.fc38 +6.4.15-200.fc38 +6.5.0-57.fc39 +6.5.2-301.fc39 +6.5.3-300.fc39 +6.5.4-300.fc39 +6.5.5-300.fc39 +6.5.6-300.fc39 +6.5.7-200.fc38 +6.5.8-200.fc38 +6.5.9-300.fc39 +6.5.10-300.fc39 +6.5.11-300.fc39 +6.5.12-300.fc39 +6.5.13-100.fc37 +6.6.0-61.fc40 +6.6.2-201.fc39 +6.6.3-200.fc39 +6.6.4-200.fc39 +6.6.6-200.fc39 +6.6.7-200.fc39 +6.6.8-200.fc39 +6.6.9-200.fc39 +6.6.11-200.fc39 +6.6.12-200.fc39 +6.6.13-200.fc39 +6.6.14-200.fc39 +6.7.3-200.fc39 +6.7.4-200.fc39 +6.7.5-200.fc39 +6.7.6-200.fc39 +6.7.7-200.fc39 +6.7.9-200.fc39 +6.7.10-200.fc39 +6.7.11-200.fc39 +6.8.1-300.fc40 +6.8.4-300.fc40 +6.8.5-301.fc40 +6.8.6-200.fc39 +6.8.7-300.fc40 +6.8.8-300.fc40 +6.8.9-300.fc40 +6.8.10-300.fc40 +6.8.11-300.fc40 +6.9.0-64.fc41 +6.9.4-200.fc40 +6.9.5-200.fc40 +6.9.6-200.fc40 +6.9.7-200.fc40 +6.9.8-200.fc40 +6.9.9-200.fc40 +6.9.10-200.fc40 +6.9.11-200.fc40 +6.9.12-200.fc40 +6.10.0-64.fc41 +6.10.3-200.fc40 +6.10.4-200.fc40 +6.10.5-200.fc40 +6.10.6-200.fc40 +6.10.7-200.fc40 +6.10.8-200.fc40 +6.10.9-200.fc40 +6.10.10-200.fc40 +6.10.11-200.fc40 +6.10.12-200.fc40 +6.11.0-63.fc42 +6.11.1-300.fc41 +6.11.2-300.fc41 +6.11.3-300.fc41 +6.11.4-301.fc41 +6.11.5-300.fc41 +6.11.6-300.fc41 +6.11.7-300.fc41 +6.11.8-300.fc41 +6.11.9-100.fc39 +6.11.10-300.fc41 +6.11.11-300.fc41 +6.12.0-65.fc42 +6.12.4-200.fc41 +6.12.5-200.fc41 +6.12.6-200.fc41 +6.12.7-200.fc41 +6.12.8-200.fc41 +6.12.9-200.fc41 +6.12.10-200.fc41 +6.12.11-200.fc41 +6.12.13-200.fc41 +6.12.15-200.fc41 +6.13.4-200.fc41 +6.13.5-200.fc41 +6.13.6-200.fc41 +6.13.7-200.fc41 +6.13.8-200.fc41 +6.13.9-200.fc41 +6.13.10-200.fc41 +6.13.11-200.fc41 +6.13.12-200.fc41 +6.14.0-63.fc42 +6.14.1-300.fc42 +6.14.2-300.fc42 +6.14.3-300.fc42 +6.14.4-300.fc42 +6.14.5-300.fc42 +6.14.6-300.fc42 +6.14.8-300.fc42 +6.14.9-300.fc42 +6.14.11-300.fc42 +6.15.0-0.rc7.58.fc43 +6.15.3-200.fc42 +6.15.4-200.fc42 +6.15.5-200.fc42 +6.15.6-200.fc42 +6.15.7-200.fc42 +6.15.8-200.fc42 +6.15.9-201.fc42 +6.15.10-200.fc42 +6.16.0-65.fc43 +6.16.3-200.fc42 +6.16.4-200.fc42 +6.16.5-200.fc42 +6.16.6-100.fc41 +6.16.7-200.fc42 +6.16.8-200.fc42 +6.16.9-200.fc42 +6.16.10-200.fc42 +6.16.11-200.fc42 +6.16.12-200.fc42 +6.17.0-63.fc44 +6.17.1-300.fc43 +6.17.4-300.fc43 +6.17.5-300.fc43 +6.17.6-300.fc43 +6.17.7-300.fc43 +6.17.8-300.fc43 +6.17.9-300.fc43 +6.17.10-300.fc43 +6.17.11-300.fc43 +6.17.12-300.fc43 +6.17.13-200.fc42 +6.18.0-65.fc44 +6.18.3-200.fc43 +6.18.4-200.fc43 +6.18.5-200.fc43 +6.18.6-200.fc43 +6.18.7-200.fc43 +6.18.8-200.fc43 +6.18.9-200.fc43 +6.18.10-200.fc43 +6.18.12-200.fc43 +6.18.13-200.fc43 +6.18.16-200.fc43 +6.19.0-59.fc45 +6.19.2-300.fc44 +6.19.4-300.fc43 +6.19.6-300.fc44 +6.19.7-300.fc44 +6.19.8-300.fc44 +6.19.9-300.fc44 +6.19.10-300.fc44 +6.19.11-300.fc44 +6.20.0-0.rc0.260219g2b7a25df823dc.12.fc45 +7.0.0-0.rc7.55.fc45 diff --git a/spec/generate_rpm_list_spec.sh b/spec/generate_rpm_list_spec.sh new file mode 100644 index 0000000..2c6cdb1 --- /dev/null +++ b/spec/generate_rpm_list_spec.sh @@ -0,0 +1,165 @@ +#!/bin/bash + +# shellcheck shell=sh + +# NOTE: These tests use mock scripts to avoid network calls. They verify the +# --nvr / arch argument handling logic but not the real scripts' scraping +# behavior. The real integration is tested by `make update-rpm-lists` and the +# shipped list files in rpm_lists/. + +Describe 'RPM List Generator Scripts' + Describe 'generate_fedora_kernel_rpm_list.py' + Context 'without --nvr flag (default URL mode)' + # Mock the script to avoid network calls + fedora_generator() { + # Create a minimal mock that outputs one line + python3 - "$@" <<'EOF' +import sys +nvr_mode = "--nvr" in sys.argv +if nvr_mode: + sys.argv.remove("--nvr") + +arch = sys.argv[1] if len(sys.argv) > 1 else "x86_64" + +# Mock output for testing +version = "6.12.0" +minor = "30.fc42" +release_version = f"{version}-{minor}" + +if nvr_mode: + print(release_version) +else: + url = f'https://kojipkgs.fedoraproject.org/packages/kernel/{version}/{minor}/{arch}/kernel-core-{release_version}.{arch}.rpm' + print(url) +EOF + } + + It 'outputs full URL with default arch x86_64' + When call fedora_generator + The output should include "https://kojipkgs.fedoraproject.org/packages/kernel/" + The output should include "x86_64/kernel-core-" + The output should include ".x86_64.rpm" + End + + It 'outputs full URL with specified arch aarch64' + When call fedora_generator aarch64 + The output should include "https://kojipkgs.fedoraproject.org/packages/kernel/" + The output should include "aarch64/kernel-core-" + The output should include ".aarch64.rpm" + End + End + + Context 'with --nvr flag' + fedora_generator_nvr() { + python3 - "$@" <<'EOF' +import sys +nvr_mode = "--nvr" in sys.argv +if nvr_mode: + sys.argv.remove("--nvr") + +arch = sys.argv[1] if len(sys.argv) > 1 else "x86_64" + +# Mock output for testing +version = "6.12.0" +minor = "30.fc42" +release_version = f"{version}-{minor}" + +if nvr_mode: + print(release_version) +else: + url = f'https://kojipkgs.fedoraproject.org/packages/kernel/{version}/{minor}/{arch}/kernel-core-{release_version}.{arch}.rpm' + print(url) +EOF + } + + It 'outputs only NVR without URL' + When call fedora_generator_nvr --nvr + The output should equal "6.12.0-30.fc42" + The output should not include "https://" + The output should not include ".rpm" + End + + It 'outputs only NVR with arch parameter (arch ignored in nvr mode)' + When call fedora_generator_nvr --nvr aarch64 + The output should equal "6.12.0-30.fc42" + End + End + End + + Describe 'generate_rhel_kernel_rpm_list.py' + Context 'without --nvr flag (default URL mode)' + rhel_generator() { + python3 - "$@" <<'EOF' +import sys + +nvr_mode = "--nvr" in sys.argv +if nvr_mode: + sys.argv.remove("--nvr") + +# Mock positional args parsing +if len(sys.argv) < 3: + rhel_version = "C10S" + arch = "x86_64" +else: + rhel_version = sys.argv[1] + arch = sys.argv[2] + +# Mock output +version = "6.12.0" +minor = "30.el10" +release_version = f'{version}-{minor}' +base_url = "https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0" + +url = f'{base_url}/{minor}/{arch}/kernel-core-{release_version}.{arch}.rpm' +print(url) +EOF + } + + It 'outputs full URL' + When call rhel_generator C10S x86_64 + The output should include "https://kojihub.stream.centos.org" + The output should include "x86_64/kernel-core-" + The output should include ".x86_64.rpm" + End + End + + Context 'with --nvr flag' + rhel_generator_nvr() { + python3 - "$@" <<'EOF' +import sys + +nvr_mode = "--nvr" in sys.argv +if nvr_mode: + sys.argv.remove("--nvr") + +# Mock positional args parsing +if len(sys.argv) < 3: + rhel_version = "C10S" + arch = "x86_64" +else: + rhel_version = sys.argv[1] + arch = sys.argv[2] + +# Mock output +version = "6.12.0" +minor = "30.el10" +release_version = f'{version}-{minor}' +base_url = "https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0" + +if nvr_mode: + print(release_version) +else: + url = f'{base_url}/{minor}/{arch}/kernel-core-{release_version}.{arch}.rpm' + print(url) +EOF + } + + It 'outputs only NVR without URL' + When call rhel_generator_nvr --nvr C10S x86_64 + The output should equal "6.12.0-30.el10" + The output should not include "https://" + The output should not include ".rpm" + End + End + End +End diff --git a/spec/resolve_rpm_list_spec.sh b/spec/resolve_rpm_list_spec.sh new file mode 100644 index 0000000..bb6a134 --- /dev/null +++ b/spec/resolve_rpm_list_spec.sh @@ -0,0 +1,179 @@ +#!/bin/bash + +Describe 'resolve_rpm_list helpers' + Include ./lib.sh + + setup_env() { + LOG_FILE="${SHELLSPEC_WORKDIR}/test.log" + } + Before 'setup_env' + + Describe 'parse_nvr_distro' + It "detects c9s from el9 NVR" + When call parse_nvr_distro "5.14.0-400.el9.x86_64" + The output should equal "c9s" + The status should be success + End + + It "detects c10s from el10 NVR" + When call parse_nvr_distro "6.12.0-200.el10.x86_64" + The output should equal "c10s" + The status should be success + End + + It "detects fedora from fc41 NVR" + When call parse_nvr_distro "6.16.5-100.fc41.x86_64" + The output should equal "fedora" + The status should be success + End + + It "detects c9s from rt NVR" + When call parse_nvr_distro "5.14.0-100.rt14.100.el9.x86_64" + The output should equal "c9s" + The status should be success + End + + It "fails on unknown dist tag" + When call parse_nvr_distro "5.14.0-100.unknown.x86_64" + The status should be failure + End + + It "fails on git commit hash" + When call parse_nvr_distro "abc123def456789" + The status should be failure + End + End + + Describe 'parse_nvr_arch' + It "extracts x86_64" + When call parse_nvr_arch "6.12.0-200.el10.x86_64" + The output should equal "x86_64" + End + + It "extracts aarch64" + When call parse_nvr_arch "5.14.0-400.el9.aarch64" + The output should equal "aarch64" + End + + It "extracts s390x" + When call parse_nvr_arch "6.12.0-100.el10.s390x" + The output should equal "s390x" + End + + It "extracts arch from rt NVR" + When call parse_nvr_arch "5.14.0-100.rt14.100.el9.x86_64" + The output should equal "x86_64" + End + End + + Describe 'nvr_to_rpm_url' + It "constructs c10s URL for x86_64" + When call nvr_to_rpm_url "6.12.0-30.el10" "x86_64" + The output should equal \ + "https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0/30.el10/x86_64/kernel-core-6.12.0-30.el10.x86_64.rpm" + End + + It "constructs c9s URL for aarch64" + When call nvr_to_rpm_url "5.14.0-285.el9" "aarch64" + The output should equal \ + "https://kojihub.stream.centos.org/kojifiles/packages/kernel/5.14.0/285.el9/aarch64/kernel-core-5.14.0-285.el9.aarch64.rpm" + End + + It "constructs Fedora URL" + When call nvr_to_rpm_url "6.16.5-100.fc41" "x86_64" + The output should equal \ + "https://kojipkgs.fedoraproject.org/packages/kernel/6.16.5/100.fc41/x86_64/kernel-core-6.16.5-100.fc41.x86_64.rpm" + End + + It "fails on unknown dist tag" + When call nvr_to_rpm_url "6.12.0-100.unknown" "x86_64" + The status should be failure + End + End + + Describe 'resolve_rpm_list' + setup_rpm_env() { + WORK_DIR="${SHELLSPEC_WORKDIR}/work" + BIN_DIR="${SHELLSPEC_WORKDIR}/bin" + mkdir -p "$WORK_DIR" "$BIN_DIR/rpm_lists" + KERNEL_RPM_LIST="" + INSTALL_STRATEGY="" + GENERATE_RPM_LIST="" + BAD_COMMIT="" + # Create a mock shipped NVR list + cat <<'EOF' >"$BIN_DIR/rpm_lists/c10s.list" +6.12.0-30.el10 +6.12.0-31.el10 +6.12.0-32.el10 +EOF + } + + cleanup_rpm_env() { + rm -rf "${SHELLSPEC_WORKDIR}/work" "${SHELLSPEC_WORKDIR}/bin" + } + + Before 'setup_rpm_env' + After 'cleanup_rpm_env' + + # Suppress log output + log() { :; } + + It "skips when KERNEL_RPM_LIST is already set" + KERNEL_RPM_LIST="/existing/list.txt" + BAD_COMMIT="6.12.0-200.el10.x86_64" + When call resolve_rpm_list + The variable KERNEL_RPM_LIST should equal "/existing/list.txt" + End + + It "skips when INSTALL_STRATEGY is git" + INSTALL_STRATEGY="git" + BAD_COMMIT="6.12.0-200.el10.x86_64" + When call resolve_rpm_list + The variable KERNEL_RPM_LIST should equal "" + End + + It "skips when BAD_COMMIT is not an NVR" + BAD_COMMIT="abc123def456" + When call resolve_rpm_list + The variable KERNEL_RPM_LIST should equal "" + End + + It "generates URL list from shipped NVR list" + BAD_COMMIT="6.12.0-200.el10.x86_64" + do_generate() { + resolve_rpm_list + echo "file=$KERNEL_RPM_LIST" + head -1 "$KERNEL_RPM_LIST" + tail -1 "$KERNEL_RPM_LIST" + } + When call do_generate + The line 1 should equal "file=${WORK_DIR}/kernel_rpm_list.txt" + The line 2 should equal \ + "https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0/30.el10/x86_64/kernel-core-6.12.0-30.el10.x86_64.rpm" + The line 3 should equal \ + "https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0/32.el10/x86_64/kernel-core-6.12.0-32.el10.x86_64.rpm" + End + + It "calls generator script when GENERATE_RPM_LIST=yes" + BAD_COMMIT="6.12.0-200.el10.x86_64" + GENERATE_RPM_LIST="yes" + # Create mock generator script + mkdir -p "$BIN_DIR/tools" + cat <<'SCRIPT' >"$BIN_DIR/tools/generate_rhel_kernel_rpm_list.py" +#!/usr/bin/env python3 +import sys +if "--nvr" in sys.argv: + print("6.12.0-99.el10") + print("6.12.0-100.el10") +SCRIPT + chmod +x "$BIN_DIR/tools/generate_rhel_kernel_rpm_list.py" + do_generate() { + resolve_rpm_list + head -1 "$KERNEL_RPM_LIST" + } + When call do_generate + The output should equal \ + "https://kojihub.stream.centos.org/kojifiles/packages/kernel/6.12.0/99.el10/x86_64/kernel-core-6.12.0-99.el10.x86_64.rpm" + End + End +End diff --git a/tests/kab_criu/test.sh b/tests/kab_criu/test.sh index c1df445..d96847e 100755 --- a/tests/kab_criu/test.sh +++ b/tests/kab_criu/test.sh @@ -40,8 +40,8 @@ CONF_FILE=/usr/local/bin/kernel-auto-bisect/bisect.conf TEST_SCRIPT=/usr/local/bin/kernel-auto-bisect/test.sh KERNEL_RPM_LIST=/usr/local/bin/kernel-auto-bisect/kernel_list GIT_REPO=/var/local/kernel-auto-bisect/git_repo -GOOD_COMMIT=6.16.4-100.fc41.${ARCH} -BAD_COMMIT=6.16.7-100.fc41.${ARCH} +GOOD_COMMIT=6.16.4-200.fc42.${ARCH} +BAD_COMMIT=6.16.7-200.fc42.${ARCH} # 1. Prepare Target echo "Waiting for target ($TARGET_HOST) to be ready..." @@ -57,15 +57,11 @@ RPM_CACHE_DIR="/var/cache/kdump-bisect-rpms" GOOD_COMMIT=$GOOD_COMMIT BAD_COMMIT=$BAD_COMMIT REPRODUCER_SCRIPT=$TEST_SCRIPT -KERNEL_RPM_LIST=$KERNEL_RPM_LIST END -cat <$KERNEL_RPM_LIST" -https://kojipkgs.fedoraproject.org/packages/kernel/6.16.4/100.fc41/${ARCH}/kernel-core-6.16.4-100.fc41.${ARCH}.rpm -https://kojipkgs.fedoraproject.org/packages/kernel/6.16.5/100.fc41/${ARCH}/kernel-core-6.16.5-100.fc41.${ARCH}.rpm -https://kojipkgs.fedoraproject.org/packages/kernel/6.16.6/100.fc41/${ARCH}/kernel-core-6.16.6-100.fc41.${ARCH}.rpm -https://kojipkgs.fedoraproject.org/packages/kernel/6.16.7/100.fc41/${ARCH}/kernel-core-6.16.7-100.fc41.${ARCH}.rpm -END +# Pass proxy settings to bisect.conf if set in the environment +[[ -n "$http_proxy" ]] && echo "http_proxy=$http_proxy" | ssh_cmd "cat >>$CONF_FILE" +[[ -n "$https_proxy" ]] && echo "https_proxy=$https_proxy" | ssh_cmd "cat >>$CONF_FILE" cat <$TEST_SCRIPT" #!/bin/bash @@ -95,15 +91,20 @@ MAX_WAIT_TIME=600 # 10 minutes wait_time=0 while [[ $wait_time -lt $MAX_WAIT_TIME ]]; do # Try to check if finished - output=$(ssh_cmd "git -C $GIT_REPO bisect log | grep 'first bad commit' | grep -q '$BAD_COMMIT'") - ret=$? - - if [[ $ret -eq 0 ]]; then + if ssh_cmd "git -C $GIT_REPO bisect log 2>/dev/null | grep 'first bad commit' | grep -q '$BAD_COMMIT'"; then + echo "Found 1st bad commit" exit 0 - else - echo "Target ($TARGET_HOST) is down or unreachable (exit code: $ret), waiting..." fi + # Check if kab.sh has already exited (no longer running) + if ssh_cmd "! pgrep -f $KAB_SCRIPT" >/dev/null 2>&1; then + echo "kab.sh is no longer running and result was not found." + echo "Last lines of test.log:" + ssh_cmd "tail -20 /root/test.log" 2>/dev/null + exit 1 + fi + + echo "Waiting for bisect result ($wait_time/${MAX_WAIT_TIME}s)..." sleep 10 wait_time=$((wait_time + 10)) done diff --git a/tools/generate_fedora_kernel_rpm_list.py b/tools/generate_fedora_kernel_rpm_list.py index 4788ef0..3ebd1b4 100644 --- a/tools/generate_fedora_kernel_rpm_list.py +++ b/tools/generate_fedora_kernel_rpm_list.py @@ -5,8 +5,15 @@ from bs4 import BeautifulSoup from packaging.version import Version import os +import sys import urllib.request +nvr_mode = "--nvr" in sys.argv +if nvr_mode: + sys.argv.remove("--nvr") + +arch = sys.argv[1] if len(sys.argv) > 1 else "x86_64" + def download(url, save_path): if os.path.exists(save_path): @@ -38,5 +45,8 @@ def get_kernel_versions(): if ".fc" in txt: minor = txt release_version = "{}-{}".format(version, minor) - url = f'https://kojipkgs.fedoraproject.org/packages/kernel/{version}/{minor}/x86_64/kernel-core-{release_version}.x86_64.rpm' - print(url) + if nvr_mode: + print(release_version) + else: + url = f'https://kojipkgs.fedoraproject.org/packages/kernel/{version}/{minor}/{arch}/kernel-core-{release_version}.{arch}.rpm' + print(url) diff --git a/tools/generate_rhel_kernel_rpm_list.py b/tools/generate_rhel_kernel_rpm_list.py index 763cdb7..493330d 100644 --- a/tools/generate_rhel_kernel_rpm_list.py +++ b/tools/generate_rhel_kernel_rpm_list.py @@ -10,6 +10,10 @@ import sys import urllib.request +nvr_mode = "--nvr" in sys.argv +if nvr_mode: + sys.argv.remove("--nvr") + def download(url, save_path): if os.path.exists(save_path): @@ -49,5 +53,8 @@ def get_kernel_versions(): for minor in get_kernel_versions(): release_version = f'{version}-{minor}' - url = f'{base_url}/{minor}/{arch}/kernel-core-{release_version}.{arch}.rpm' - print(url) + if nvr_mode: + print(release_version) + else: + url = f'{base_url}/{minor}/{arch}/kernel-core-{release_version}.{arch}.rpm' + print(url)