Skip to content

chore(ci): convert create-pr steps into composite action #2238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions .github/actions/create-pr/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: "Create PR custom action"
description: "Create a PR and a temporary branch, close duplicates"

# PROCESS
#
# 1. Setup git client using Powertools bot username
# 2. Pushes staged files to a temporary branch
# 3. Creates a PR from temporary branch against a target branch (typically trunk: develop, main, etc.)
# 4. Searches for duplicate PRs with the same title
# 5. If duplicates are found, link to the most recent one, close and delete their branches so we keep a single PR
# 6. In the event of failure, we delete the now orphaned branch (if any), and propagate the failure

# USAGE
#
# - name: Create PR
# id: create-pr
# uses: ./.github/actions/create-pr
# with:
# files: "CHANGELOG.md"
# temp_branch_prefix: "ci-changelog"
# pull_request_title: "chore(ci): changelog rebuild"
# github_token: ${{ secrets.GITHUB_TOKEN }}
# - name: Step to demonstrate how to access outputs (no need for this)
# run: |
# echo "PR number: ${PR_ID}"
# echo "Branch: ${BRANCH}"
# env:
# PR_ID: ${{ steps.create-pr.outputs.pull_request_id}}
# BRANCH: ${{ steps.create-pr.outputs.temp_branch}}

inputs:
files:
description: "Files to add separated by space"
required: true
temp_branch_prefix:
description: "Prefix for temporary git branch to be created, e.g, ci-docs"
required: true
pull_request_title:
description: "Pull Request title to use"
required: true
github_token:
description: "GitHub token for GitHub CLI"
required: true
target_branch:
description: "Branch to target when creating a PR against (develop, by default)"
required: false
default: develop

outputs:
pull_request_id:
description: "Pull request ID created"
value: ${{ steps.create-pr.outputs.pull_request_id }}
temp_branch:
description: "Temporary branch created with staged changed"
value: ${{ steps.create-pr.outputs.temp_branch }}

runs:
using: "composite"
steps:
- id: adjust-path
run: echo "${{ github.action_path }}" >> $GITHUB_PATH
shell: bash
- id: setup-git
name: Git client setup and refresh tip
run: |
git config user.name "Powertools bot"
git config user.email "[email protected]"
git config pull.rebase true
git config remote.origin.url >&-
shell: bash
- id: create-pr
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: create_pr_for_staged_changes.sh "${FILES}"
env:
FILES: ${{ inputs.files }}
TEMP_BRANCH_PREFIX: ${{ inputs.temp_branch_prefix }}
PR_TITLE: ${{ inputs.pull_request_title }}
BASE_BRANCH: ${{ inputs.target_branch }}
GH_TOKEN: ${{ inputs.github_token }}
shell: bash
- id: cleanup
name: Cleanup orphaned branch
if: failure()
run: git push origin --delete "${TEMP_BRANCH_PREFIX}-${GITHUB_RUN_ID}" || echo "Must have failed before creating temporary branch; no cleanup needed."
env:
TEMP_BRANCH_PREFIX: ${{ inputs.temp_branch_prefix }}
GITHUB_RUN_ID: ${{ github.run_id }}
shell: bash
145 changes: 145 additions & 0 deletions .github/actions/create-pr/create_pr_for_staged_changes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#!/bin/bash
set -uo pipefail # prevent accessing unset env vars, prevent masking pipeline errors to the next command

#docs
#title :create_pr_for_staged_changes.sh
#description :This script will create a PR for staged changes, detect and close duplicate PRs.
#author :@heitorlessa
#date :May 8th 2023
#version :0.1
#usage :bash create_pr_for_staged_changes.sh {git_staged_files_or_directories_separated_by_space}
#notes :Meant to use in GitHub Actions only. Temporary branch will be named $TEMP_BRANCH_PREFIX-$GITHUB_RUN_ID
#os_version :Ubuntu 22.04.2 LTS
#required_env_vars :PR_TITLE, TEMP_BRANCH_PREFIX, GH_TOKEN
#==============================================================================

# Sets GitHub Action with error message to ease troubleshooting
function error() {
echo "::error file=${FILENAME}::$1"
exit 1
}

function debug() {
TIMESTAMP=$(date -u "+%FT%TZ") # 2023-05-10T07:53:59Z
echo ""${TIMESTAMP}" - $1"
}

function notice() {
echo "::notice file=${FILENAME}::$1"
}

function start_span() {
echo "::group::$1"
}

function end_span() {
echo "::endgroup::"
}

function has_required_config() {
start_span "Validating required config"
test -z "${TEMP_BRANCH_PREFIX}" && error "TEMP_BRANCH_PREFIX env must be set to create a PR"
test -z "${PR_TITLE}" && error "PR_TITLE env must be set"
test -z "${GH_TOKEN}" && error "GH_TOKEN env must be set for GitHub CLI"

# Default GitHub Actions Env Vars: https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
debug "Are we running in GitHub Action environment?"
test -z "${GITHUB_RUN_ID}" && error "GITHUB_RUN_ID env must be set to trace Workflow Run ID back to PR"
test -z "${GITHUB_SERVER_URL}" && error "GITHUB_SERVER_URL env must be set to trace Workflow Run ID back to PR"
test -z "${GITHUB_REPOSITORY}" && error "GITHUB_REPOSITORY env must be set to trace Workflow Run ID back to PR"

debug "Config validated successfully!"
set_environment_variables
end_span
}

function set_environment_variables() {
start_span "Setting environment variables"
export readonly WORKFLOW_URL="${GITHUB_SERVER_URL}"/"${GITHUB_REPOSITORY}"/actions/runs/"${GITHUB_RUN_ID}" # e.g., heitorlessa/aws-lambda-powertools-test/actions/runs/4913570678
export readonly TEMP_BRANCH="${TEMP_BRANCH_PREFIX}"-"${GITHUB_RUN_ID}" # e.g., ci-changelog-4894658712
export readonly BASE_BRANCH="${BASE_BRANCH:-develop}" # e.g., main, defaults to develop if missing
export readonly PR_BODY="This is an automated PR created from the following workflow"
export readonly FILENAME=".github/scripts/$(basename "$0")"
export readonly NO_DUPLICATES_MESSAGE="No duplicated PRs found"
end_span
}

function has_anything_changed() {
start_span "Validating git staged files"
HAS_ANY_SOURCE_CODE_CHANGED="$(git status --porcelain)"

test -z "${HAS_ANY_SOURCE_CODE_CHANGED}" && debug "Nothing to update; exitting early" && exit 0
end_span
}

function create_temporary_branch_with_changes() {
start_span "Creating temporary branch: "${TEMP_BRANCH}""
git checkout -b "${TEMP_BRANCH}"

debug "Committing staged files: $*"
echo "$@" | xargs -n1 git add || error "Failed to add staged changes: "$@""
git commit -m "${PR_TITLE}"

git push origin "${TEMP_BRANCH}"
end_span
}

function create_pr() {
start_span "Creating PR against ${TEMP_BRANCH} branch"
NEW_PR_URL=$(gh pr create --title "${PR_TITLE}" --body "${PR_BODY}: ${WORKFLOW_URL}" --base "${BASE_BRANCH}" || error "Failed to create PR") # e.g, https://github.com/awslabs/aws-lambda-powertools/pull/13

# greedy remove any string until the last URL path, including the last '/'. https://opensource.com/article/17/6/bash-parameter-expansion
debug "Extracing PR Number from PR URL: "${NEW_PR_URL}""
NEW_PR_ID="${NEW_PR_URL##*/}" # 13
export NEW_PR_URL
export NEW_PR_ID
end_span
}

function close_duplicate_prs() {
start_span "Searching for duplicate PRs"
DUPLICATE_PRS=$(gh pr list --search "${PR_TITLE}" --json number --jq ".[] | select(.number != ${NEW_PR_ID}) | .number") # e.g, 13\n14

if [ -z "${DUPLICATE_PRS}" ]; then
debug "No duplicate PRs found"
DUPLICATE_PRS="${NO_DUPLICATES_MESSAGE}"
else
debug "Closing duplicated PRs: "${DUPLICATE_PRS}""
echo "${DUPLICATE_PRS}" | xargs -L1 gh pr close --delete-branch --comment "Superseded by #${NEW_PR_ID}"
fi

export readonly DUPLICATE_PRS
end_span
}

function report_job_output() {
start_span "Updating job outputs"
echo pull_request_id="${NEW_PR_ID}" >>"$GITHUB_OUTPUT"
echo temp_branch="${TEMP_BRANCH}" >>"$GITHUB_OUTPUT"
end_span
}

function report_summary() {
start_span "Creating job summary"
echo "### Pull request created successfully :rocket: ${NEW_PR_URL} <br/><br/> Closed duplicated PRs: ${DUPLICATE_PRS}" >>"$GITHUB_STEP_SUMMARY"

notice "PR_URL is: ${NEW_PR_URL}"
notice "PR_BRANCH is: ${TEMP_BRANCH}"
notice "PR_DUPLICATES are: ${DUPLICATE_PRS}"
end_span
}

function main() {
# Sanity check
has_anything_changed
has_required_config

create_temporary_branch_with_changes "$@"
create_pr
close_duplicate_prs

report_job_output
report_summary
}

main "$@"
116 changes: 0 additions & 116 deletions .github/scripts/create_pr_for_staged_changes.sh

This file was deleted.

14 changes: 3 additions & 11 deletions .github/workflows/build_changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,9 @@ name: Build changelog

on:
workflow_dispatch:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
- cron: '0 8 * * *'
push:
branches:
- develop

jobs:
changelog:
Expand Down
Loading