From 30e2cb8936508b89e128fe48a51ffd2fa4bc696d Mon Sep 17 00:00:00 2001 From: Ihor Solodrai Date: Thu, 1 Oct 2026 12:53:45 -0700 Subject: [PATCH] ci: add script to run libbpf sync non-interactively Run sync-kernel.sh with stdin from /dev/null, so that any prompt asking for human input fails the sync. The exit code of sync-kernel.sh isn't reliable (e.g., it exits with 0 when interrupted), so tell from its output whether the sync went through or there was nothing to sync. On success, leave a bundle with the sync branch, patches and a pull request description with the sync log in the output directory. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Ihor Solodrai --- .github/scripts/sync-run.sh | 107 ++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100755 .github/scripts/sync-run.sh diff --git a/.github/scripts/sync-run.sh b/.github/scripts/sync-run.sh new file mode 100755 index 0000000..5f0dd6a --- /dev/null +++ b/.github/scripts/sync-run.sh @@ -0,0 +1,107 @@ +#!/bin/bash +# +# Run scripts/sync-kernel.sh non-interactively: with stdin at EOF, any prompt +# asking for human input fails the sync. If the sync went through, +# gets everything needed to publish it: a bundle with the sync branch, +# patches, and a pull request description including the sync log. +# +# Exits with 0 if the sync went through or there was nothing to sync. + +usage () { + echo "USAGE: $0 " + echo "" + echo " is expected to be set up by sync-fetch-kernel.sh." + exit 1 +} + +set -euo pipefail + +if [ $# -ne 3 ]; then + usage +fi + +LIBBPF_REPO=$(realpath "$1") +LINUX_REPO=$(realpath "$2") +OUT_DIR=$(realpath -m "$3") +GITHUB_OUTPUT=${GITHUB_OUTPUT:-/dev/null} +GITHUB_STEP_SUMMARY=${GITHUB_STEP_SUMMARY:-/dev/null} +# Pull request descriptions are limited to 65536 characters +PR_LOG_MAX=60000 + +cd "${LIBBPF_REPO}" +base_sha=$(git rev-parse HEAD) +old_next=$(cat CHECKPOINT-COMMIT) +old_bpf=$(cat BPF-CHECKPOINT-COMMIT) + +mkdir -p "${OUT_DIR}/tmp" +# Keep sync-kernel.sh's temporary files around for post-mortem +export TMPDIR="${OUT_DIR}/tmp" +log="${OUT_DIR}/sync.log" + +# The exit code of sync-kernel.sh can't be trusted (e.g., it exits with 0 when +# interrupted), so tell from its output how it went +"${LIBBPF_REPO}/scripts/sync-kernel.sh" "${LIBBPF_REPO}" "${LINUX_REPO}" bpf-master \ + < /dev/null 2>&1 | tee "${log}" || true +# Drop progress output overwritten with carriage returns +sed -i 's/^.*\r//' "${log}" + +if grep -qF 'No new changes to apply, we are done!' "${log}"; then + echo "::notice::No new libbpf changes since bpf-next ${old_next:0:12} and bpf ${old_bpf:0:12}" + exit 0 +fi +if ! grep -qF 'Great! Content is identical!' "${log}"; then + echo "::error::Sync needs a human, see SYNC.md. The sync log and leftovers are in the run's artifact." + exit 1 +fi + +branch=$(git symbolic-ref --short HEAD) +git format-patch -q -o "${OUT_DIR}/patches" "${base_sha}..HEAD" +git bundle create -q "${OUT_DIR}/sync.bundle" "${base_sha}..refs/heads/${branch}" + +if [ -n "${GITHUB_RUN_ID:-}" ]; then + origin="[workflow run](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})" +else + origin="a local run" +fi +new_files=$(git diff --name-only --diff-filter=A "${base_sha}" HEAD -- src include) + +{ + echo "Automated libbpf sync from bpf-next and bpf trees, created by ${origin}." + echo "" + echo "| Tree | Baseline | Checkpoint |" + echo "| --- | --- | --- |" + echo "| bpf-next | ${old_next} | $(cat CHECKPOINT-COMMIT) |" + echo "| bpf | ${old_bpf} | $(cat BPF-CHECKPOINT-COMMIT) |" + echo "" + echo "CI runs for this pull request have to be approved by a maintainer. If CI needs" \ + "adjustments (allow/deny lists, \`ci/diffs\`, \`src/Makefile\`, see SYNC.md), push them to" \ + "this branch." + if [ -n "${new_files}" ]; then + echo "" + echo "New files were synced, check if \`src/Makefile\` needs updating:" + echo "" + # shellcheck disable=SC2016 + sed 's/^/- `/; s/$/`/' <<< "${new_files}" + fi + echo "" + echo "
" + echo "sync-kernel.sh output" + echo "" + echo '````' + head -c "${PR_LOG_MAX}" "${log}" + if (($(wc -c < "${log}") > PR_LOG_MAX)); then + echo "" + echo "[... truncated, the full log is in the workflow run's artifact ...]" + fi + echo '````' + echo "" + echo "
" +} > "${OUT_DIR}/pr-body.md" + +cat "${OUT_DIR}/pr-body.md" >> "${GITHUB_STEP_SUMMARY}" +{ + echo "branch=${branch}" + echo "head_sha=$(git rev-parse HEAD)" +} >> "${GITHUB_OUTPUT}" + +echo "Synced $(git rev-list --count "${base_sha}..HEAD") commits into ${branch}"