Files
libbpf/.github/workflows/libbpf-sync.yml
Ihor Solodrai c6a6fdb609 ci: add libbpf-sync workflow
Run the sync monthly, and on demand. If it goes through without needing
a human, push the libbpf-sync-* branch and open a pull request.
Otherwise fail the run without opening one.

The sync job runs code from the kernel trees (bpf_doc.py), so it only
gets a read-only token. A separate publish job pushes the verified sync
bundle and opens the pull request.

Skip the run while any sync pull request is open. Manual runs default
to dry runs, which only upload the sync results as an artifact.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
2026-10-02 13:04:03 -07:00

159 lines
5.4 KiB
YAML

name: libbpf-sync
on:
schedule:
# Monthly, on the 1st
- cron: '17 13 1 * *'
workflow_dispatch:
inputs:
dry_run:
description: Run the sync without pushing a branch or opening a pull request
required: true
default: true
type: boolean
permissions: {}
concurrency:
group: libbpf-sync
cancel-in-progress: false
defaults:
run:
shell: bash
jobs:
# Runs code from the kernel trees (bpf_doc.py), so it gets a read-only token
# and hands the result over to the publish job as an artifact.
sync:
# Forks may only dry-run
if: github.repository == 'libbpf/libbpf' || (github.event_name == 'workflow_dispatch' && inputs.dry_run)
runs-on: ubuntu-24.04
timeout-minutes: 120
permissions:
contents: read
pull-requests: read
outputs:
branch: ${{ steps.sync.outputs.branch }}
head_sha: ${{ steps.sync.outputs.head_sha }}
env:
DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || false }}
steps:
- name: Check for open sync pull requests
id: gate
env:
GH_TOKEN: ${{ github.token }}
REF: ${{ github.ref }}
run: |
if [ "${DRY_RUN}" != true ] && [ "${REF}" != refs/heads/master ]; then
echo "::error::Only dry runs are allowed from ${REF}"
exit 1
fi
open=$(gh pr list --repo "${GITHUB_REPOSITORY}" --base master --state open --limit 1000 \
--json headRefName,url \
--jq '[.[] | select(.headRefName | startswith("libbpf-sync-")) | .url] | join(" ")')
if [ -z "${open}" ]; then
exit 0
fi
if [ "${DRY_RUN}" = true ]; then
echo "::warning::Sync pull request already open, dry-running anyway: ${open}"
else
echo "::notice::Sync pull request already open, skipping: ${open}"
echo "skip=true" >> "${GITHUB_OUTPUT}"
fi
- name: Checkout libbpf
if: steps.gate.outputs.skip != 'true'
uses: actions/checkout@v7
with:
fetch-depth: 0
persist-credentials: false
- name: Set up git
if: steps.gate.outputs.skip != 'true'
run: |
git config --global user.name 'libbpf-bot'
git config --global user.email 'bot+libbpf@kernel.org'
git config --global checkout.workers 0
git --version
if ! git filter-branch -h > /dev/null 2>&1; then
echo "::error::git filter-branch is not available"
exit 1
fi
command -v patch python3
- name: Fetch bpf-next and bpf trees
if: steps.gate.outputs.skip != 'true'
run: .github/scripts/sync-fetch-kernel.sh "${GITHUB_WORKSPACE}" "${RUNNER_TEMP}/linux"
- name: Sync
id: sync
if: steps.gate.outputs.skip != 'true'
run: .github/scripts/sync-run.sh "${GITHUB_WORKSPACE}" "${RUNNER_TEMP}/linux" "${RUNNER_TEMP}/out"
- name: Upload sync results
if: ${{ !cancelled() && steps.gate.outputs.skip != 'true' }}
uses: actions/upload-artifact@v7
with:
name: libbpf-sync-${{ github.run_id }}
path: ${{ runner.temp }}/out
if-no-files-found: ignore
overwrite: true
publish:
needs: sync
if: needs.sync.outputs.branch != '' && !(github.event_name == 'workflow_dispatch' && inputs.dry_run)
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: write
pull-requests: write
env:
BRANCH: ${{ needs.sync.outputs.branch }}
HEAD_SHA: ${{ needs.sync.outputs.head_sha }}
GH_TOKEN: ${{ github.token }}
steps:
- name: Checkout libbpf
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Download sync results
uses: actions/download-artifact@v7
with:
name: libbpf-sync-${{ github.run_id }}
path: ${{ runner.temp }}/out
- name: Push sync branch and open pull request
run: |
out="${RUNNER_TEMP}/out"
if [[ "${BRANCH}" != libbpf-sync-* ]]; then
echo "::error::Unexpected sync branch name '${BRANCH}'"
exit 1
fi
git bundle verify -q "${out}/sync.bundle"
git fetch -q "${out}/sync.bundle" "refs/heads/${BRANCH}:refs/heads/${BRANCH}"
if [ "$(git rev-parse "refs/heads/${BRANCH}")" != "${HEAD_SHA}" ]; then
echo "::error::Sync bundle doesn't match ${HEAD_SHA}"
exit 1
fi
# A sync pull request could have been opened while the sync was running
open=$(gh pr list --base master --state open --limit 1000 \
--json headRefName,url \
--jq '[.[] | select(.headRefName | startswith("libbpf-sync-")) | .url] | join(" ")')
if [ -n "${open}" ]; then
echo "::notice::Sync pull request already open, not publishing: ${open}"
exit 0
fi
git push origin "refs/heads/${BRANCH}:refs/heads/${BRANCH}"
title="Libbpf sync $(TZ=UTC git log -n1 --format=%cd --date=format-local:%Y-%m-%dT%H:%M:%SZ "refs/heads/${BRANCH}")"
if ! gh pr create --base master --head "${BRANCH}" --title "${title}" \
--body-file "${out}/pr-body.md"; then
echo "::error::Failed to open a pull request, deleting ${BRANCH}"
git push origin --delete "${BRANCH}"
exit 1
fi