From d68801833ad85ac967a3914e55fa10895030ee44 Mon Sep 17 00:00:00 2001 From: Phillip Rak Date: Thu, 7 Mar 2024 08:42:29 -0700 Subject: [PATCH] Add Port PR workflow Signed-off-by: Phillip Rak --- .github/workflows/port-pr.yaml | 117 +++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 .github/workflows/port-pr.yaml diff --git a/.github/workflows/port-pr.yaml b/.github/workflows/port-pr.yaml new file mode 100644 index 0000000000..597647307c --- /dev/null +++ b/.github/workflows/port-pr.yaml @@ -0,0 +1,117 @@ +name: Port PR + +on: + issue_comment: + types: + - created + +jobs: + port-pr: + runs-on: ubuntu-latest + if: (startsWith(github.event.comment.body, '/backport') || startsWith(github.event.comment.body, '/forwardport')) && github.event.issue.pull_request + steps: + - name: Check org membership + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_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_ENV + else + echo "${GITHUB_ACTOR} is not a member" >> $GITHUB_STEP_SUMMARY + echo "is_member=false" >> $GITHUB_ENV + fi + - name: Check milestone + if: ${{ env.is_member == 'true' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_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_ENV + echo "milestone=${MILESTONE}" >> $GITHUB_ENV + 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_ENV + fi + - name: Get target branch + if: ${{ env.is_member == 'true' }} && ${{ env.milestone_exists == 'true' }} + env: + COMMENT_BODY: ${{ github.event.comment.body }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + TYPE=$(echo "${COMMENT_BODY}" | awk '{ print $1 }' | sed -e 's_/__') + echo "Type: ${TYPE}" >> $GITHUB_STEP_SUMMARY + echo "type=${TYPE}" >> $GITHUB_ENV + TARGET_BRANCH=$(echo "${COMMENT_BODY}" | awk '{ print $3 }') + echo "Target brach: ${TARGET_BRANCH}" >> $GITHUB_STEP_SUMMARY + echo "target_branch=${TARGET_BRANCH}" >> $GITHUB_ENV + if gh api repos/${GITHUB_REPOSITORY}/branches --paginate | jq -e --arg TARGET_BRANCH "$TARGET_BRANCH" '.[] | select(.name == $TARGET_BRANCH)' > /dev/null; then + echo "target_branch_exists=true" >> $GITHUB_ENV + else + echo "target_branch_exists=false" >> $GITHUB_ENV + fi + - name: Checkout + if: ${{ env.is_member == 'true' }} && ${{ env.milestone_exists == 'true' }} && ${{ env.target_branch_exists == 'true' }} + uses: actions/checkout@v4 + with: + ref: ${{ env.target_branch }} + fetch-depth: '0' + token: ${{ secrets.GITHUB_TOKEN }} + - name: Port PR + if: ${{ env.is_member == 'true' }} && ${{ env.milestone_exists == 'true' }} && ${{ env.target_branch_exists == 'true' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ORIGINAL_ISSUE_NUMBER: ${{ github.event.issue.number }} + TYPE: ${{ env.type }} + TARGET_BRANCH: ${{ env.target_branch }} + MILESTONE: ${{ env.milestone }} + run: | + PATCH_FILE=$(mktemp) + gh pr diff $ORIGINAL_ISSUE_NUMBER --patch > $PATCH_FILE + BRANCH="gha-portpr-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" + echo "branch=${BRANCH}" >> $GITHUB_ENV + git config --global user.email "rancherdashboardportbot@suse.com" + git config --global user.name "Rancher Dashboard Port Bot" + git checkout -b $BRANCH + + if ! git am -3 "$PATCH_FILE" > error.log 2>&1; then + ERROR_MESSAGE=$(cat error.log) + FORMATTED_ERROR_MESSAGE=$(printf "\n\`\`\`\n%s\n\`\`\`" "$ERROR_MESSAGE") + gh issue comment ${ORIGINAL_ISSUE_NUMBER} --body "Not creating port PR, there was an error running git am -3: $FORMATTED_ERROR_MESSAGE" + else + git push origin $BRANCH + ORIGINAL_PR=$(gh pr view ${ORIGINAL_ISSUE_NUMBER} --json title,body,assignees) + ORIGINAL_TITLE=$(echo "${ORIGINAL_PR}" | jq -r .title) + ORIGINAL_ASSIGNEE=$(echo "${ORIGINAL_PR}" | jq -r '.assignee.login // empty') + BODY=$(mktemp) + echo -e "This is an automated request to port PR #${ORIGINAL_ISSUE_NUMBER} by @${GITHUB_ACTOR}\n\n" > $BODY + echo -e "Original PR body:\n\n" >> $BODY + echo "${ORIGINAL_PR}" | jq -r .body >> $BODY + ASSIGNEES=$(echo "${ORIGINAL_PR}" | jq -r .assignees[].login) + if [ -n "$ASSIGNEES" ]; then + echo "Checking if assignee is member before assigning" + DELIMITER="" + NEW_ASSIGNEES="" + for ASSIGNEE in $ASSIGNEES; do + if gh api orgs/${GITHUB_REPOSITORY_OWNER}/members --paginate | jq -e --arg GITHUB_ACTOR "$GITHUB_ACTOR" '.[] | select(.login == $GITHUB_ACTOR)' > /dev/null; 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 + NEW_PR=$(gh pr create --title="[${TYPE} ${MILESTONE}] ${ORIGINAL_TITLE}" --body-file="${BODY}" --head "${BRANCH}" --base "${TARGET_BRANCH}" --milestone "${MILESTONE}" "${additional_cmd[@]}") + echo "Port PR created: ${NEW_PR}" >> $GITHUB_STEP_SUMMARY + fi