github-actions: Add LT rebase merge automation workflow#922
github-actions: Add LT rebase merge automation workflow#922bmastbergen wants to merge 1 commit intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces an automated workflow for merging CLK (Custom Linux Kernel) PRs using the lt_rebase_merge process from the kernel-src-tree-tools repository. The workflow can be triggered either via a /lt_rebase_merge comment on PRs (by users with write/admin permissions) or through manual workflow dispatch. It validates that PRs have at least 2 approvals, extracts the LT version from the branch name, validates the target branch, and executes the merge script.
Changes:
- Added new GitHub Actions workflow for LT rebase merge automation with comment-based and manual triggers
- Implements permission checks, approval validation, version extraction, and branch validation
- Posts success/failure comments on PRs with workflow run links
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if [ "$JOB_STATUS" == "success" ]; then | ||
| EMOJI="✅" | ||
| TITLE="LT Rebase Merge completed successfully" | ||
| MESSAGE="Successfully completed LT $LT_VERSION rebase merge" | ||
| else | ||
| EMOJI="❌" | ||
| TITLE="LT Rebase Merge failed" | ||
| MESSAGE="Failed to complete LT $LT_VERSION rebase merge. Please check the workflow run for details." |
There was a problem hiding this comment.
The LT_VERSION environment variable is referenced in the comment step (lines 214 and 218) but may not be set if the "Extract LT version from PR" step fails. Since the comment step uses "if: always()", it will run even when earlier steps fail. Consider adding a check to use a default message when LT_VERSION is not set, or use a conditional to only include the version in the message when it's available.
| if [ "$JOB_STATUS" == "success" ]; then | |
| EMOJI="✅" | |
| TITLE="LT Rebase Merge completed successfully" | |
| MESSAGE="Successfully completed LT $LT_VERSION rebase merge" | |
| else | |
| EMOJI="❌" | |
| TITLE="LT Rebase Merge failed" | |
| MESSAGE="Failed to complete LT $LT_VERSION rebase merge. Please check the workflow run for details." | |
| # Derive a label for LT that is safe even if LT_VERSION is unset | |
| if [ -n "${LT_VERSION:-}" ]; then | |
| LT_LABEL="LT $LT_VERSION" | |
| else | |
| LT_LABEL="LT" | |
| fi | |
| if [ "$JOB_STATUS" == "success" ]; then | |
| EMOJI="✅" | |
| TITLE="LT Rebase Merge completed successfully" | |
| MESSAGE="Successfully completed $LT_LABEL rebase merge" | |
| else | |
| EMOJI="❌" | |
| TITLE="LT Rebase Merge failed" | |
| MESSAGE="Failed to complete $LT_LABEL rebase merge. Please check the workflow run for details." |
| PR_NUMBER: ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || github.event.issue.number }} | ||
| REPOSITORY: ${{ github.repository }} | ||
| run: | | ||
| set -e | ||
|
|
||
| # Get PR details | ||
| PR_DATA=$(gh pr view "$PR_NUMBER" --repo "$REPOSITORY" --json number,headRefName,baseRefName,title,reviews) |
There was a problem hiding this comment.
The PR_NUMBER and REPOSITORY variables should be validated before use, following the defense-in-depth security pattern used in validate-kernel-commits-comment.yml. Even though these values come from GitHub Actions context (github.event.issue.number, github.repository) or typed inputs (type: number), validating them with regex patterns and range checks provides an additional security layer. PR_NUMBER should be validated as a positive integer within a reasonable range, and REPOSITORY should match the owner/repo format with length checks.
There was a problem hiding this comment.
I litterally don't know what this is talking about these checks exist?
There was a problem hiding this comment.
They didn't exist when this comment was made, but do now. I'm not sure why this copilot comment isn't marked as outdated like the others. I probably should have marked it as resolved anyways.
| # Count approvals | ||
| APPROVALS=$(echo "$PR_DATA" | jq '[.reviews[] | select(.state == "APPROVED")] | length') |
There was a problem hiding this comment.
The approval counting logic counts all reviews with state "APPROVED", which may not accurately reflect the current approval state. If a reviewer approves and then later submits a "CHANGES_REQUESTED" or "COMMENTED" review, both reviews are returned by the API. The jq filter should group reviews by author and only count the most recent review state from each unique reviewer. This prevents overcounting approvals and ensures only the latest review state from each reviewer is considered.
| # Count approvals | |
| APPROVALS=$(echo "$PR_DATA" | jq '[.reviews[] | select(.state == "APPROVED")] | length') | |
| # Count approvals based on the latest review state per reviewer | |
| APPROVALS=$(echo "$PR_DATA" | jq '[.reviews | |
| | sort_by(.author.login, .submittedAt) | |
| | group_by(.author.login)[] | |
| | last | |
| | select(.state == "APPROVED") | |
| ] | length') |
| # Extract branch names | ||
| HEAD_BRANCH=$(echo "$PR_DATA" | jq -r '.headRefName') | ||
| BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.baseRefName') | ||
| PR_TITLE=$(echo "$PR_DATA" | jq -r '.title') | ||
|
|
||
| echo "HEAD_BRANCH=$HEAD_BRANCH" >> $GITHUB_ENV | ||
| echo "BASE_BRANCH=$BASE_BRANCH" >> $GITHUB_ENV | ||
| echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV | ||
|
|
There was a problem hiding this comment.
Branch names extracted from the GitHub API (HEAD_BRANCH and BASE_BRANCH) should be validated before being stored in GITHUB_ENV and used in subsequent steps. Consider adding validation similar to the pattern used in validate-kernel-commits-comment.yml (lines 98-108), which validates branch names against a regex pattern and checks length limits. This prevents potential command injection if the API returns unexpected values or if the repository is compromised.
| # Extract branch names | |
| HEAD_BRANCH=$(echo "$PR_DATA" | jq -r '.headRefName') | |
| BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.baseRefName') | |
| PR_TITLE=$(echo "$PR_DATA" | jq -r '.title') | |
| echo "HEAD_BRANCH=$HEAD_BRANCH" >> $GITHUB_ENV | |
| echo "BASE_BRANCH=$BASE_BRANCH" >> $GITHUB_ENV | |
| echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV | |
| # Extract branch names and PR title | |
| HEAD_BRANCH=$(echo "$PR_DATA" | jq -r '.headRefName') | |
| BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.baseRefName') | |
| PR_TITLE=$(echo "$PR_DATA" | jq -r '.title') | |
| # Validate branch names to prevent injection via GITHUB_ENV | |
| BRANCH_REGEX='^[A-Za-z0-9._/-]+$' | |
| MAX_BRANCH_LENGTH=255 | |
| for BR_VAR in HEAD_BRANCH BASE_BRANCH; do | |
| BR_VALUE=${!BR_VAR} | |
| if [ -z "$BR_VALUE" ]; then | |
| echo "❌ $BR_VAR is empty, aborting." | |
| exit 1 | |
| fi | |
| if [ "${#BR_VALUE}" -gt "$MAX_BRANCH_LENGTH" ]; then | |
| echo "❌ $BR_VAR is too long (>${MAX_BRANCH_LENGTH} characters), aborting." | |
| exit 1 | |
| fi | |
| if ! [[ "$BR_VALUE" =~ $BRANCH_REGEX ]]; then | |
| echo "❌ $BR_VAR contains invalid characters, aborting." | |
| exit 1 | |
| fi | |
| done | |
| # Sanitize PR title to avoid breaking GITHUB_ENV (remove newlines) | |
| PR_TITLE_CLEAN=$(printf '%s' "$PR_TITLE" | tr '\n\r' ' ') | |
| echo "HEAD_BRANCH=$HEAD_BRANCH" >> "$GITHUB_ENV" | |
| echo "BASE_BRANCH=$BASE_BRANCH" >> "$GITHUB_ENV" | |
| echo "PR_TITLE=$PR_TITLE_CLEAN" >> "$GITHUB_ENV" |
| PR_DATA=$(gh pr view "$PR_NUMBER" --repo "$REPOSITORY" --json number,headRefName,baseRefName,title,reviews) | ||
|
|
||
| # Extract branch names | ||
| HEAD_BRANCH=$(echo "$PR_DATA" | jq -r '.headRefName') | ||
| BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.baseRefName') | ||
| PR_TITLE=$(echo "$PR_DATA" | jq -r '.title') | ||
|
|
||
| echo "HEAD_BRANCH=$HEAD_BRANCH" >> $GITHUB_ENV | ||
| echo "BASE_BRANCH=$BASE_BRANCH" >> $GITHUB_ENV | ||
| echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV |
There was a problem hiding this comment.
The PR_TITLE variable is extracted and stored in GITHUB_ENV but is never used in the workflow. Consider removing line 82 (extraction) and line 86 (storage) to simplify the code and reduce unnecessary API data retrieval.
| PR_DATA=$(gh pr view "$PR_NUMBER" --repo "$REPOSITORY" --json number,headRefName,baseRefName,title,reviews) | |
| # Extract branch names | |
| HEAD_BRANCH=$(echo "$PR_DATA" | jq -r '.headRefName') | |
| BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.baseRefName') | |
| PR_TITLE=$(echo "$PR_DATA" | jq -r '.title') | |
| echo "HEAD_BRANCH=$HEAD_BRANCH" >> $GITHUB_ENV | |
| echo "BASE_BRANCH=$BASE_BRANCH" >> $GITHUB_ENV | |
| echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV | |
| PR_DATA=$(gh pr view "$PR_NUMBER" --repo "$REPOSITORY" --json number,headRefName,baseRefName,reviews) | |
| # Extract branch names | |
| HEAD_BRANCH=$(echo "$PR_DATA" | jq -r '.headRefName') | |
| BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.baseRefName') | |
| echo "HEAD_BRANCH=$HEAD_BRANCH" >> $GITHUB_ENV | |
| echo "BASE_BRANCH=$BASE_BRANCH" >> $GITHUB_ENV |
|
There is some decent copilot feedback here. Working through it. |
Introduce automated workflow for merging CLK PRs using the lt_rebase_merge process. The workflow can be triggered via /lt_rebase_merge comment on PRs or manual workflow dispatch. Key features: - Validates PR has at least 2 approvals before merging - Verifies commenter has write/admin permissions - Extracts LT version from branch name (ciq-X.Y.y pattern) - Validates PR target branch matches expected -next branch - Executes lt_rebase_merge.sh script from kernel-src-tree-tools - Posts success/failure comment on PR with workflow run link
7e64e46 to
ab74bfe
Compare
| echo "PR_TITLE=$PR_TITLE" >> $GITHUB_ENV | ||
|
|
||
| # Count approvals based on the latest review state per reviewer | ||
| APPROVALS=$(echo "$PR_DATA" | jq '[.reviews |
There was a problem hiding this comment.
right now this is mostly just us doing the reviews and approval we may want to take note that it requires x number of 'code owners'
This is non-blocking but something we have to be careful about.
There was a problem hiding this comment.
yea, good call. I focused more on the comentor having the correct permissions, but some amount of approver validation would be good too
There was a problem hiding this comment.
thats a fair counter point, we shouldn't be adding that a comment unless we also have validated it.
Introduce automated workflow for merging CLK PRs using the lt_rebase_merge process. The workflow can be triggered via /lt_rebase_merge comment on PRs or manual workflow dispatch.
Key features:
I've tested the workflow logic with manual dispatch to merge the last couple of CLK rebase PRs:
#903
#902
Unfortunately the comment trigger can't be tested until the workflow is on the main branch. So I'll have to test it on the next automatically generated CLK rebase PRs after this PR is merged.