diff --git a/.github/workflows/reusable-jira-pr_actions.yml b/.github/workflows/reusable-jira-pr_actions.yml new file mode 100644 index 0000000..2c683ea --- /dev/null +++ b/.github/workflows/reusable-jira-pr_actions.yml @@ -0,0 +1,161 @@ +# This workflow will comment the PR with the JIRA issue summary +# if a JIRA issue number is detected in the branch name or title + +name: Jira issue jobs + +on: + workflow_call: + secrets: + JIRA_BASE_URL: + required: true + description: The base URL of your JIRA instance + JIRA_USER_EMAIL: + required: true + description: The email address for your JIRA account + JIRA_API_TOKEN: + required: true + description: The API token for your JIRA account + +env: + JIRA_PATTERN: "([A-Z]+)[-# ]*([0-9]+)" + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + +jobs: + get_issue_key: + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + issue_key_from_branch: steps.jira_key_from_branch.output.issue_key + issue_key_from_title: steps.jira_key_from_title.output.issue_key + + steps: + - name: Find JIRA issue key from branch + id: jira_key_from_branch + env: + HEAD_REF: ${{ github.head_ref }} + run: > + echo "issue_key=$( + echo $HEAD_REF | grep -osiE "$JIRA_PATTERN" + | head -n1 | sed -E "s/\W*$JIRA_PATTERN/\1-\2/i" + | tr [:lower:] [:upper:] + )" >> $GITHUB_OUTPUT + + - name: Find JIRA issue key from title + id: jira_key_from_title + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: > + echo "issue_key=$( + echo $PR_TITLE | grep -osiE "^\s*\[?\s*$JIRA_PATTERN" + | head -n1 | sed -E "s/\W*$JIRA_PATTERN/\1-\2/i" + | tr [:lower:] [:upper:] + )" >> $GITHUB_OUTPUT + + add_jira_summary: + if: ${{ github.event.action == 'opened' }} + runs-on: ubuntu-latest + timeout-minutes: 20 + needs: get_issue_key + + steps: + + - name: Get JIRA summary from branch + if: ${{ needs.get_issue_key.outputs.issue_key_from_branch }} + id: jira_summary_from_branch + run: > + curl -sS -X GET + -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" + -H "Content-Type: application/json" + "$JIRA_BASE_URL/rest/api/2/issue/${{ needs.get_issue_key.outputs.issue_key_from_branch }}" + | echo "summary=$(jq -r '.fields.summary // empty' | xargs)" >> $GITHUB_OUTPUT + + - name: Get JIRA summary from title + if: ${{ !steps.jira_summary_from_branch.outputs.summary && needs.get_issue_key.outputs.issue_key_from_title }} + id: jira_summary_from_title + run: > + curl -sS -X GET + -u "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" + -H "Content-Type: application/json" + "$JIRA_BASE_URL/rest/api/2/issue/${{ needs.get_issue_key.outputs.issue_key_from_title }}" + | echo "summary=$(jq -r '.fields.summary // empty' | xargs)" >> $GITHUB_OUTPUT + + - name: Extract PR title + id: get_pr_title + if: ${{ steps.jira_summary_from_branch.outputs.summary || steps.jira_summary_from_title.outputs.summary }} + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + echo "text=$(echo $PR_TITLE | sed -E "s/^\s*[?[A-Z]+[-# ]*[0-9]+]?[-: ]*(.*)/\1/i")" >> $GITHUB_OUTPUT + + - name: Add comment + if: ${{ steps.jira_summary_from_branch.outputs.summary || steps.jira_summary_from_title.outputs.summary }} + env: + ISSUE_SUMMARY: ${{ steps.jira_summary_from_branch.outputs.summary || steps.jira_summary_from_title.outputs.summary }} + ISSUE_KEY: ${{ steps.jira_summary_from_branch.outputs.summary && steps.jira_key_from_branch.outputs.issue_key || steps.jira_key_from_title.outputs.issue_key }} + TITLE_TEXT: ${{ steps.get_pr_title.outputs.text }} + PR_BODY: ${{ github.event.pull_request.body }} + run: > + jq + --arg ISSUE_ID "$(cat <<< $ISSUE_KEY)" + --arg ISSUE_SUMMARY "$(cat <<< $ISSUE_SUMMARY)" + --arg TITLE_TEXT "$(cat <<< ${TITLE_TEXT:-$ISSUE_SUMMARY})" + --arg PR_BODY "$(cat <<< $PR_BODY)" + -c '{"title": ($ISSUE_ID + ": " + $TITLE_TEXT), "body": ("**" + $ISSUE_ID + " - " + $ISSUE_SUMMARY + "**\n" + $PR_BODY)}' <<< {} + | curl -sS -X POST -d @- + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" + -H "Content-Type: application/json" + "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/pulls/${{ github.event.pull_request.number }}" + > /dev/null + + check_jira_issue: + runs-on: ubuntu-latest + timeout-minutes: 20 + needs: get_issue_key + + - name: Check issue key + if: ${{ !needs.get_issue_key.outputs.issue_key_from_title && !needs.get_issue_key.outputs.issue_key_from_branch }} + run: | + echo "Could not determine Jira issue" + + - name: Check issue status + if: ${{ needs.get_issue_key.outputs.issue_key_from_title || needs.get_issue_key.outputs.issue_key_from_branch }} + run: | + issue_key=${{ needs.get_issue_key.output.issue_key_from_title }} + if [ -z "$issue_key" ]; then + issue_key=${{ needs.get_issue_key.output.issue_key_from_branch }} + fi + jql="Sprint in (openSprints(), futureSprints()) and issue=$issue_key" + jqlencoded=$(jq -R -r @uri <<<"$jql") + response=$(curl -s --request GET \ + --url "$JIRA_BASE_URL/rest/api/3/search/jql?jql=$jqlencoded&fields=statusCategory" \ + --user "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ + --header 'Accept: application/json' \ + --header 'Content-Type: application/json') + + if [ $? -ne 0 ]; then + echo "Jira API: error" + exit 1 + fi + + echo "response was: $(echo $response|jq)" + error="" + + echo "Checking if issue is in open or future sprint" + sprint=$(echo $response | jq '.issues | length') + if [ $sprint -eq 0 ]; then + error="Error: Jira issue is not in open or future sprint" + fi + + echo "Checking if issue is In Progress" + status=$(echo $response| jq -r '.issues[0].fields.statusCategory.name') + if [ "$status" != "In Progress" ]; then + error="$error Error: Jira issue is not In Progress" + fi + + if [[ ! -z "$error" ]]; then + echo $error + exit 1 + fi + diff --git a/.github/workflows/reusable-jira-pr_add_jira_summary.yml b/.github/workflows/reusable-jira-pr_add_jira_summary.yml index b6c7df8..f816c56 100644 --- a/.github/workflows/reusable-jira-pr_add_jira_summary.yml +++ b/.github/workflows/reusable-jira-pr_add_jira_summary.yml @@ -19,6 +19,7 @@ on: jobs: add_jira_summary: + if: ${{ github.event.action == 'opened' }} runs-on: ubuntu-latest timeout-minutes: 20 env: diff --git a/.github/workflows/reusable-jira-pr_check_issue.yml b/.github/workflows/reusable-jira-pr_check_issue.yml new file mode 100644 index 0000000..1fc6ebf --- /dev/null +++ b/.github/workflows/reusable-jira-pr_check_issue.yml @@ -0,0 +1,85 @@ +# This workflow will comment the PR with the JIRA issue summary +# if a JIRA issue number is detected in the branch name or title + +name: Check Jira Issue + +on: + workflow_call: + secrets: + JIRA_BASE_URL: + required: true + description: The base URL of your JIRA instance + JIRA_USER_EMAIL: + required: true + description: The email address for your JIRA account + JIRA_API_TOKEN: + required: true + description: The API token for your JIRA account + + +jobs: + check_jira_issue: + runs-on: ubuntu-latest + timeout-minutes: 20 + env: + JIRA_PATTERN: "([A-Z]+)[-# ]*([0-9]+)" + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + + steps: + + - name: Find JIRA issue key from title + id: jira_key_from_title + if: ${{ !steps.jira_summary_from_branch.outputs.summary }} + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: > + echo "issue_key=$( + echo $PR_TITLE | grep -osiE "^\s*\[?\s*$JIRA_PATTERN" + | head -n1 | sed -E "s/\W*$JIRA_PATTERN/\1-\2/i" + | tr [:lower:] [:upper:] + )" >> $GITHUB_OUTPUT + + - name: Check issue key + if: ${{ !steps.jira_key_from_title.outputs.issue_key }} + run: | + echo "Could not determine Jira issue from PR title" + exit 1 + + - name: Check issue status + if: ${{ steps.jira_key_from_title.outputs.issue_key }} + run: | + jql="Sprint in (openSprints(), futureSprints()) and issue=${{ steps.jira_key_from_title.outputs.issue_key }}" + jqlencoded=$(jq -R -r @uri <<<"$jql") + response=$(curl -s --request GET \ + --url "$JIRA_BASE_URL/rest/api/3/search/jql?jql=$jqlencoded&fields=statusCategory" \ + --user "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ + --header 'Accept: application/json' \ + --header 'Content-Type: application/json') + + if [ $? -ne 0 ]; then + echo "Jira API: error" + exit 1 + fi + + echo "response was: $(echo $response|jq)" + error="" + + echo "Checking if issue is in open or future sprint" + sprint=$(echo $response | jq '.issues | length') + if [ $sprint -eq 0 ]; then + error="Error: Jira issue is not in open or future sprint" + fi + + echo "Checking if issue is In Progress" + status=$(echo $response| jq -r '.issues[0].fields.statusCategory.name') + if [ "$status" != "In Progress" ]; then + error="$error Error: Jira issue is not In Progress" + fi + + if [[ ! -z "$error" ]]; then + echo $error + exit 1 + fi +