Add /backport and /forwardport GitHub Actions workflow

Agent-Logs-Url: https://github.com/rancher/k3k/sessions/fc673824-99a8-4c33-b255-aa41e4c4a25b

Co-authored-by: samjustus <95646164+samjustus@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-04-17 17:36:58 +00:00
committed by GitHub
parent 6e5c28564f
commit 9590fd7c4f

110
.github/workflows/port-issue.yml vendored Normal file
View File

@@ -0,0 +1,110 @@
name: Port issue
run-name: "Port issue ${{ github.event.issue.number }}: ${{ github.event.issue.title }}"
on:
issue_comment:
types:
- created
# PORT_ISSUE_TOKEN must be configured as a repository secret.
# It requires a personal access token with read:org and repo scopes
# so that org membership can be checked and issues can be created.
permissions: {}
jobs:
port-issue:
runs-on: ubuntu-latest
if: startsWith(github.event.comment.body, '/backport') || startsWith(github.event.comment.body, '/forwardport')
steps:
- name: Check org membership
id: membership
env:
GITHUB_TOKEN: ${{ secrets.PORT_ISSUE_TOKEN }}
run: |
if gh api orgs/${GITHUB_REPOSITORY_OWNER}/members --paginate | jq -e --arg GITHUB_ACTOR "$GITHUB_ACTOR" '.[] | select(.login == $GITHUB_ACTOR)' > /dev/null; then
echo "${GITHUB_ACTOR} is a member"
echo "is_member=true" >> $GITHUB_OUTPUT
else
echo "${GITHUB_ACTOR} is not a member of ${GITHUB_REPOSITORY_OWNER}" >> $GITHUB_STEP_SUMMARY
echo "is_member=false" >> $GITHUB_OUTPUT
fi
- name: Check milestone
if: steps.membership.outputs.is_member == 'true'
id: milestone
env:
GITHUB_TOKEN: ${{ secrets.PORT_ISSUE_TOKEN }}
ORIGINAL_ISSUE_NUMBER: ${{ github.event.issue.number }}
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
BODY_MILESTONE=$(echo "${COMMENT_BODY}" | awk '{ print $2 }')
# Sanitize input
MILESTONE=${BODY_MILESTONE//[^a-zA-Z0-9\-\.]/}
if gh api repos/${GITHUB_REPOSITORY}/milestones --paginate | jq -e --arg MILESTONE "$MILESTONE" '.[] | select(.title == $MILESTONE)' > /dev/null; then
echo "Milestone exists"
echo "milestone_exists=true" >> $GITHUB_OUTPUT
else
echo "Milestone ${MILESTONE} does not exist" >> $GITHUB_STEP_SUMMARY
gh issue comment -R ${GITHUB_REPOSITORY} ${ORIGINAL_ISSUE_NUMBER} --body "Not creating port issue, milestone ${MILESTONE} does not exist or is not an open milestone"
echo "milestone_exists=false" >> $GITHUB_OUTPUT
fi
- name: Port issue
if: |
steps.membership.outputs.is_member == 'true' &&
steps.milestone.outputs.milestone_exists == 'true'
env:
GITHUB_TOKEN: ${{ secrets.PORT_ISSUE_TOKEN }}
ORIGINAL_ISSUE_NUMBER: ${{ github.event.issue.number }}
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
declare -a additional_cmd
BODY=$(mktemp)
ORIGINAL_ISSUE=$(gh issue view -R ${GITHUB_REPOSITORY} ${ORIGINAL_ISSUE_NUMBER} --json title,body,assignees)
ORIGINAL_TITLE=$(echo "${ORIGINAL_ISSUE}" | jq -r .title)
TYPE=$(echo "${COMMENT_BODY}" | awk '{ print $1 }' | sed -e 's_/__')
MILESTONE=$(echo "${COMMENT_BODY}" | awk '{ print $2 }')
# Title format: [<milestone>] <original_title>
NEW_TITLE="[${MILESTONE}] ${ORIGINAL_TITLE}"
ORIGINAL_LABELS=$(gh issue view -R ${GITHUB_REPOSITORY} ${ORIGINAL_ISSUE_NUMBER} --json labels --jq '.labels[].name' | grep -v '^\[zube\]:' | paste -sd "," -)
if [ -n "$ORIGINAL_LABELS" ]; then
additional_cmd+=("--label")
additional_cmd+=("${ORIGINAL_LABELS}")
fi
ORIGINAL_PROJECT=$(gh issue view -R ${GITHUB_REPOSITORY} ${ORIGINAL_ISSUE_NUMBER} --json projectItems --jq '.projectItems[].title')
if [ -n "$ORIGINAL_PROJECT" ]; then
additional_cmd+=("--project")
additional_cmd+=("${ORIGINAL_PROJECT}")
fi
ASSIGNEES=$(echo "${ORIGINAL_ISSUE}" | jq -r .assignees[].login)
if [ -n "$ASSIGNEES" ]; then
echo "Checking if assignee is member before assigning"
# Fetch organization members once to reduce API calls
ORG_MEMBERS=$(gh api orgs/${GITHUB_REPOSITORY_OWNER}/members --paginate | jq -r '.[].login')
DELIMITER=""
NEW_ASSIGNEES=""
for ASSIGNEE in $ASSIGNEES; do
# Exclude Copilot assignees: matches 'copilot' and variants like 'copilot-swe-agent'
if [[ "${ASSIGNEE,,}" =~ ^copilot(-.+)?$ ]]; then
echo "Skipping Copilot assignee: ${ASSIGNEE}"
continue
fi
if echo "$ORG_MEMBERS" | grep -Fqx "$ASSIGNEE"; then
echo "${ASSIGNEE} is a member, adding to assignees"
NEW_ASSIGNEES="${NEW_ASSIGNEES}${DELIMITER}${ASSIGNEE}"
DELIMITER=","
fi
done
if [ -n "$NEW_ASSIGNEES" ]; then
echo "Assignees for new issue: ${NEW_ASSIGNEES}"
additional_cmd+=("--assignee")
additional_cmd+=("${NEW_ASSIGNEES}")
fi
fi
if [ -n "$MILESTONE" ]; then
# Body: "<Type> of #<N>" followed by blank line and original body
CAPITALIZED_TYPE="$(echo "${TYPE}" | awk '{ print toupper(substr($0,1,1)) tolower(substr($0,2)) }')"
echo -e "${CAPITALIZED_TYPE} of #${ORIGINAL_ISSUE_NUMBER}\n" > $BODY
echo "${ORIGINAL_ISSUE}" | jq -r '.body[0:65536]' >> $BODY
NEW_ISSUE=$(gh issue create -R "${GITHUB_REPOSITORY}" --title "${NEW_TITLE}" --body-file "${BODY}" -m "${MILESTONE}" "${additional_cmd[@]}")
echo "Port issue created: ${NEW_ISSUE}" >> $GITHUB_STEP_SUMMARY
fi