From da9ef2e57f724038c85d85637402f211105f99da Mon Sep 17 00:00:00 2001 From: andrewg-mira <89816284+andrewg-mira@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:57:00 -0800 Subject: [PATCH 1/7] DEVOPS-853 check if Jira issue in open or future sprint --- .../reusable-jira-pr_check_issue.yml | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .github/workflows/reusable-jira-pr_check_issue.yml 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..a9576c8 --- /dev/null +++ b/.github/workflows/reusable-jira-pr_check_issue.yml @@ -0,0 +1,72 @@ +# 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: | + echo "Checking if issue is in open or future sprint" + 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 \ + --user "${JIRA_USER_EMAIL}:${JIRA_API_TOKEN}" \ + --header 'Accept: application/json' \ + --header 'Content-Type: application/json' | jq '.issues | length') + + if [ $? -ne 0 ]; then + echo "Jira API: error" + exit 1 + fi + + if [ $response -eq 0 ]; then + echo "Error: Jira issue is not in open or future sprint" + exit 1 + fi + + echo "response was: $response" From 4d59de0b7c4cf03c2fdc2a419d5fa289b26d5a4e Mon Sep 17 00:00:00 2001 From: andrewg-mira <89816284+andrewg-mira@users.noreply.github.com> Date: Thu, 11 Dec 2025 11:57:39 -0800 Subject: [PATCH 2/7] DEVOPS-853 add check for Jira issue In Progress --- .../reusable-jira-pr_check_issue.yml | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/workflows/reusable-jira-pr_check_issue.yml b/.github/workflows/reusable-jira-pr_check_issue.yml index a9576c8..1fc6ebf 100644 --- a/.github/workflows/reusable-jira-pr_check_issue.yml +++ b/.github/workflows/reusable-jira-pr_check_issue.yml @@ -50,23 +50,36 @@ jobs: - name: Check issue status if: ${{ steps.jira_key_from_title.outputs.issue_key }} run: | - echo "Checking if issue is in open or future sprint" 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 \ + --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' | jq '.issues | length') + --header 'Content-Type: application/json') if [ $? -ne 0 ]; then echo "Jira API: error" exit 1 fi - if [ $response -eq 0 ]; then - echo "Error: Jira issue is not in open or future sprint" + 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 - echo "response was: $response" From e1a01bec05bb74dd7b782f028c787984206bd8f8 Mon Sep 17 00:00:00 2001 From: andrewg-mira <89816284+andrewg-mira@users.noreply.github.com> Date: Mon, 15 Dec 2025 11:11:38 -0800 Subject: [PATCH 3/7] DEVOPS-853 only run add_jira_summary on PR open --- .github/workflows/reusable-jira-pr_add_jira_summary.yml | 1 + 1 file changed, 1 insertion(+) 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: From a4460f17503ef398bc29d22a9bab7bf282fe145c Mon Sep 17 00:00:00 2001 From: andrewg-mira <89816284+andrewg-mira@users.noreply.github.com> Date: Mon, 15 Dec 2025 11:19:04 -0800 Subject: [PATCH 4/7] DEVOPS-853 add check-jira-issue to other workflow file --- .../reusable-jira-pr_add_jira_summary.yml | 71 +++++++++++++++++-- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/.github/workflows/reusable-jira-pr_add_jira_summary.yml b/.github/workflows/reusable-jira-pr_add_jira_summary.yml index f816c56..264cf43 100644 --- a/.github/workflows/reusable-jira-pr_add_jira_summary.yml +++ b/.github/workflows/reusable-jira-pr_add_jira_summary.yml @@ -16,17 +16,17 @@ on: 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: add_jira_summary: if: ${{ github.event.action == 'opened' }} 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: @@ -100,3 +100,64 @@ jobs: -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 + + 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 + From 228af072fcc697416081012f64362b9d446c500a Mon Sep 17 00:00:00 2001 From: andrewg-mira <89816284+andrewg-mira@users.noreply.github.com> Date: Fri, 19 Dec 2025 11:17:57 -0800 Subject: [PATCH 5/7] Revert "DEVOPS-853 add check-jira-issue to other workflow file" This reverts commit a4460f17503ef398bc29d22a9bab7bf282fe145c. --- .../reusable-jira-pr_add_jira_summary.yml | 71 ++----------------- 1 file changed, 5 insertions(+), 66 deletions(-) diff --git a/.github/workflows/reusable-jira-pr_add_jira_summary.yml b/.github/workflows/reusable-jira-pr_add_jira_summary.yml index 264cf43..f816c56 100644 --- a/.github/workflows/reusable-jira-pr_add_jira_summary.yml +++ b/.github/workflows/reusable-jira-pr_add_jira_summary.yml @@ -16,17 +16,17 @@ on: 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: add_jira_summary: if: ${{ github.event.action == 'opened' }} 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: @@ -100,64 +100,3 @@ jobs: -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 - - 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 - From 176016cedcbd44f2dcb1a68101aa2bbec66b489d Mon Sep 17 00:00:00 2001 From: andrewg-mira <89816284+andrewg-mira@users.noreply.github.com> Date: Fri, 19 Dec 2025 11:26:32 -0800 Subject: [PATCH 6/7] DEVOPS-853 jira-pr_actions --- .../workflows/reusable-jira-pr_actions.yml | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 .github/workflows/reusable-jira-pr_actions.yml diff --git a/.github/workflows/reusable-jira-pr_actions.yml b/.github/workflows/reusable-jira-pr_actions.yml new file mode 100644 index 0000000..0f26dcb --- /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 from PR title" + exit 1 + + - name: Check issue status + run: | + issue_key=${{ needs.get_issue_key.output.issue_key_from_title }} + if [ -z "$issue_key" ]; then + issue_key=${{ needs.get_issue_keyk.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 + From 656611ea8796c5be99e745987acd452c432e6b08 Mon Sep 17 00:00:00 2001 From: andrewg-mira <89816284+andrewg-mira@users.noreply.github.com> Date: Tue, 6 Jan 2026 13:55:46 -0800 Subject: [PATCH 7/7] DEVOPS-853 do not raise error if issue key not found --- .github/workflows/reusable-jira-pr_actions.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/reusable-jira-pr_actions.yml b/.github/workflows/reusable-jira-pr_actions.yml index 0f26dcb..2c683ea 100644 --- a/.github/workflows/reusable-jira-pr_actions.yml +++ b/.github/workflows/reusable-jira-pr_actions.yml @@ -117,14 +117,14 @@ jobs: - 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 from PR title" - exit 1 + 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_keyk.output.issue_key_from_branch }} + 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")