NO_MERGE This is an example PR with an upstream commit checker github action #1
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: Check Upstream Linux Kernel Commits | |
on: | |
pull_request: | |
branches: | |
- '**' | |
- '!mainline' | |
jobs: | |
check_upstream_commits: | |
runs-on: ubuntu-latest | |
steps: | |
- name: Install jq | |
run: | | |
sudo apt-get update && sudo apt-get install -y jq | |
- name: Clone Linux Kernel | |
run: | | |
echo "Cloning Linux kernel repository (bare clone, single branch, no blobs) into 'linux' directory..." | |
git clone --bare --filter=blob:none --single-branch https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git linux | |
echo "Cloning complete." | |
- name: Get PR commit SHAs via GitHub API | |
id: pr_commits | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Required for GitHub API authentication | |
run: | | |
PR_COMMITS_JSON=$(curl -sS -H "Accept: application/vnd.github.v3+json" \ | |
-H "Authorization: token $GITHUB_TOKEN" \ | |
"${{ github.event.pull_request.commits_url }}?per_page=100") | |
ERROR_MESSAGE=$(echo "$PR_COMMITS_JSON" | jq -r 'if type == "object" and .message then .message else null end') | |
if [ "$ERROR_MESSAGE" != "null" ] && [ -n "$ERROR_MESSAGE" ]; then | |
echo "ERROR: Failed to retrieve PR commits from GitHub API: $ERROR_MESSAGE" | |
echo "API Response snippet: $(echo "$PR_COMMITS_JSON" | head -n 5)" | |
exit 1 | |
fi | |
COMMITS=$(echo "$PR_COMMITS_JSON" | jq -r 'map(.sha) | join(" ")') | |
if [ -z "$COMMITS" ]; then | |
echo "No commits found in this Pull Request via GitHub API. This might indicate an issue with the PR or API." | |
exit 1 | |
fi | |
echo "PR_COMMITS=${COMMITS}" >> "$GITHUB_OUTPUT" | |
- name: Check each PR commit for Linux upstream hash and related Fixes tag | |
id: check_results | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
LINUX_KERNEL_REPO_OWNER: torvalds | |
LINUX_KERNEL_REPO_NAME: linux | |
run: | | |
PR_COMMENT_BODY_ACCUMULATOR="" | |
# Get the current HEAD commit SHA for the Linux kernel master branch from the local clone | |
echo "Getting current HEAD of '${LINUX_KERNEL_REPO_OWNER}/${LINUX_KERNEL_REPO_NAME}' master branch from local bare clone..." | |
HEAD_COMMIT_SHA=$(git -C linux rev-parse master) | |
if [ -z "$HEAD_COMMIT_SHA" ]; then | |
echo "ERROR: Could not retrieve HEAD commit for Linux kernel master from local clone." | |
exit 1 | |
fi | |
echo "Linux kernel master HEAD: ${HEAD_COMMIT_SHA}" | |
# Loop through each commit SHA identified in the current PR | |
for PR_COMMIT_SHA in ${{ steps.pr_commits.outputs.PR_COMMITS }}; do | |
echo "--- Checking PR commit: ${PR_COMMIT_SHA} ---" | |
# --- Fetch the full commit message of the PR commit via GitHub API --- | |
PR_COMMIT_DETAILS_JSON=$(curl -sS -H "Accept: application/vnd.github.v3+json" \ | |
-H "Authorization: token $GITHUB_TOKEN" \ | |
"https://api.github.com/repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/commits/${PR_COMMIT_SHA}") | |
ERROR_MESSAGE=$(echo "$PR_COMMIT_DETAILS_JSON" | jq -r 'if type == "object" and .message then .message else null end') | |
if [ "$ERROR_MESSAGE" != "null" ] && [ -n "$ERROR_MESSAGE" ]; then | |
echo "ERROR: Could not retrieve commit message for PR commit ${PR_COMMIT_SHA} from GitHub API: ${ERROR_MESSAGE}" | |
echo "API Response snippet: $(echo "$PR_COMMIT_DETAILS_JSON" | head -n 5)" | |
exit 1 | |
fi | |
PR_COMMIT_MESSAGE=$(echo "$PR_COMMIT_DETAILS_JSON" | jq -r '.commit.message') | |
# Extract the subject (first line) of the PR commit message | |
PR_COMMIT_SUBJECT=$(echo "$PR_COMMIT_MESSAGE" | head -n 1) | |
# Extract the upstream Linux commit hash from the PR commit message. | |
UPSTREAM_LINUX_HASH=$(echo "$PR_COMMIT_MESSAGE" | grep -Eo "^commit [0-9a-f]{40}$" | awk '{print $2}') | |
if [ -z "$UPSTREAM_LINUX_HASH" ]; then | |
echo "No 'commit <upstream_linux_commit_hash>' line found in PR commit ${PR_COMMIT_SHA}. Skipping upstream check for this commit." | |
continue # Skip to next PR commit, no comment for this scenario | |
fi | |
echo "Found upstream Linux hash to check for fixes: ${UPSTREAM_LINUX_HASH}" | |
# --- Check if the upstream hash exists in the local cloned Linux kernel repo --- | |
if ! git -C linux cat-file -e "$UPSTREAM_LINUX_HASH"; then | |
printf -v PR_COMMENT_BODY_ACCUMULATOR "%s- **PR commit \`%s\` - %s**: References upstream commit \`%s\` which was **NOT found** in the Linux kernel repository. Please verify the hash.\n" \ | |
"$PR_COMMENT_BODY_ACCUMULATOR" "$PR_COMMIT_SHA" "$PR_COMMIT_SUBJECT" "$UPSTREAM_LINUX_HASH" | |
continue # Skip to next PR commit, but added message to comment | |
fi | |
# --- Search for "Fixes:" tag in upstream Linux kernel using git log --- | |
# Extract the first 12 characters for the short SHA, commonly used in Fixes: tags in Linux kernel. | |
UPSTREAM_LINUX_HASH_SHORT=$(echo "$UPSTREAM_LINUX_HASH" | cut -c 1-12) | |
echo "Searching for upstream commits on 'master' branch in range ${UPSTREAM_LINUX_HASH}..${HEAD_COMMIT_SHA} that fix ${UPSTREAM_LINUX_HASH} using 'git log --grep=\"Fixes: ${UPSTREAM_LINUX_HASH_SHORT}\"'..." | |
# Construct the grep pattern using the SHORT SHA for search. | |
GREP_PATTERN="Fixes: ${UPSTREAM_LINUX_HASH_SHORT}" | |
# Use git log to find commits that mention the short SHA in their "Fixes:" line, | |
# in the range from the specific commit up to HEAD. | |
# --pretty=format:"%h %s" to get short SHA and subject. | |
# --regexp-ignore-case for case-insensitive grep. | |
# We explicitly exclude the UPSTREAM_LINUX_HASH itself from the result range, | |
# as we are looking for *subsequent* fixes. | |
GIT_LOG_FIXES_OUTPUT=$(git -C linux log master \ | |
"${UPSTREAM_LINUX_HASH}..${HEAD_COMMIT_SHA}" \ | |
--grep="${GREP_PATTERN}" \ | |
--pretty=format:"%h %s" \ | |
--regexp-ignore-case) | |
if [ -n "$GIT_LOG_FIXES_OUTPUT" ]; then | |
printf -v PR_COMMENT_BODY_ACCUMULATOR "%s- **PR commit \`%s\` - %s**: References upstream commit \`%s\` which has the following fixes in the Linux kernel log:\n" \ | |
"$PR_COMMENT_BODY_ACCUMULATOR" "$PR_COMMIT_SHA" "$PR_COMMIT_SUBJECT" "$UPSTREAM_LINUX_HASH" | |
# Add a markdown code block for the git log output | |
printf -v PR_COMMENT_BODY_ACCUMULATOR "%s\`\`\`\n%s\n\`\`\`\n" \ | |
"$PR_COMMENT_BODY_ACCUMULATOR" "$GIT_LOG_FIXES_OUTPUT" | |
else | |
echo "No upstream fixes found for ${UPSTREAM_LINUX_HASH} in the specified range." | |
# No comment added to PR_COMMENT_BODY_ACCUMULATOR for this scenario | |
fi | |
echo "" # Newline in action logs for separation | |
done # End of for PR_COMMIT_SHA loop | |
# Set the output variable `PR_COMMENT_BODY` using EOF to preserve newlines for the PR comment. | |
# If no relevant messages were accumulated, this will be an empty string (after trim in JS). | |
echo "PR_COMMENT_BODY<<EOF" >> "$GITHUB_OUTPUT" | |
echo "$PR_COMMENT_BODY_ACCUMULATOR" >> "$GITHUB_OUTPUT" | |
echo "EOF" >> "$GITHUB_OUTPUT" | |
- name: Post PR comment with results # Step 3: Post the collected results as a comment on the PR | |
uses: actions/github-script@v7 | |
env: | |
# Pass the multi-line comment body as an environment variable to the JavaScript script. | |
COMMENT_BODY: ${{ steps.check_results.outputs.PR_COMMENT_BODY }} | |
with: | |
script: | | |
// Access the comment body directly from the environment variable and trim any whitespace | |
const commentBody = process.env.COMMENT_BODY.trim(); | |
// Only post a comment if there is actual content | |
if (commentBody) { | |
await github.rest.issues.createComment({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: commentBody | |
}); | |
console.log("Posted a PR comment with the results."); | |
} else { | |
console.log("No relevant upstream fixes information to post as a PR comment."); | |
} |