Skip to content
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
13 changes: 13 additions & 0 deletions .github/actions/jira/transition/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ inputs:
transition:
required: true
description: Transition name to apply to issue
fixed-version:
required: false
description: Version fixed (only used if resolution set. Use 'auto' for detection in nomad.)
timeline-url:
required: false
description: GitHub API issue timeline URL (required if fixed-version is set to 'auto')
project:
required: false
description: JIRA project (required for setting fixed-version)
default: NMD

runs:
using: composite
Expand All @@ -24,3 +34,6 @@ runs:
ISSUE: ${{ inputs.issue }}
TRANSITION: ${{ inputs.transition }}
RESOLUTION: ${{ inputs.resolution }}
FIXED_VERSION: ${{ inputs.fixed-version }}
TIMELINE_URL: ${{ inputs.timeline-url }}
PROJECT: ${{ inputs.project }}
129 changes: 96 additions & 33 deletions .github/actions/jira/transition/jira-transition.bash
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

source "$(dirname "${BASH_SOURCE[0]}")/../shared.bash"

# Check for required inputs
# Do all the checks up front so we just bail before
# doing any actual work.

if [ -z "${ISSUE}" ]; then
error "Missing 'issue' input value"
exit 1
Expand All @@ -15,6 +17,21 @@ if [ -z "${TRANSITION}" ]; then
exit 1
fi

if [ -n "${FIXED_VERSION}" ] && [ -z "${RESOLUTION}" ]; then
error "The 'fixed-version' value can only be set if 'resolution' is set"
exit 1
fi

if [ -n "${FIXED_VERSION}" ] && [ -z "${PROJECT}" ]; then
error "Missing 'project' input value (must be set if 'fixed-version' is set)"
exit 1
fi

if [ "${FIXED_VERSION}" == "auto" ] && [ -z "${TIMELINE_URL}" ]; then
error "Missing 'timeline-url' input value (must be set if 'fixed-version' is 'auto')"
exit 1
fi

# Grab the transition ID
result="$(jira-request "${JIRA_BASE_URL}/rest/api/3/issue/${ISSUE}/transitions")" || exit
query="$(printf '.transitions[] | select(.name == "%s").id' "${TRANSITION}")"
Expand All @@ -25,8 +42,15 @@ if [ -z "${transition_id}" ]; then
exit 1
fi

# If a resolution is set, find it and generate the template
# with it included
# Create the initial payload. This will be updated as needed prior
# to sending the request.
template='{transition: {id: $transition_id}}'
payload="$(jq -n --arg transition_id "${transition_id}" "${template}")" || exit

info "Transitioning JIRA issue '%s' to %s (ID: %s)" "${ISSUE}" \
"${TRANSITION}" "${transition_id}"

# If a resolution is set, find it
if [ -n "${RESOLUTION}" ]; then
# Grab the resolution ID
result="$(jira-request "${JIRA_BASE_URL}/rest/api/3/resolution")" || exit
Expand All @@ -38,41 +62,80 @@ if [ -n "${RESOLUTION}" ]; then
exit 1
fi

template='
{
transition: {
id: $transition
},
fields: {
resolution: {
id: $resolution
}
}
}
'
issue_transition="$(jq -n --arg transition "${transition_id}" --arg resolution "${resolution_id}" "${template}")" || exit
else
# No resolution so the template only includes the transition
template='
{
transition: {
id: $transition
}
}
'
issue_transition="$(jq -n --arg transition "${transition_id}" "${template}")" || exit
# Render the data structure for the resolution
template='{fields: {resolution: {id: $resolution_id}}}'
rendered="$(jq -n --arg resolution_id "${resolution_id}" "${template}")" || exit

# Add it to the payload
payload="$(jq -s '.[0] * .[1]' <<< "${payload}${rendered}")"

info "Resolving JIRA issue '%s' to %s (ID: %s)" "${ISSUE}" "${RESOLUTION}" "${resolution_id}"
fi

info "Transitioning JIRA issue '%s' to %s (ID: %s)" "${ISSUE}" \
"${TRANSITION}" "${transition_id}"
if [ -n "${resolution_id}" ]; then
info "Resolving JIRA issue '%s' as %s (ID: %s)" "${ISSUE}" \
"${RESOLUTION}" "${resolution_id}"
# Handle setting fixed versions if set
if [ -n "${FIXED_VERSION}" ]; then
fixed_versions=()

# First pull the valid versions from jira
project="$(jira-request "${JIRA_BASE_URL}/rest/api/3/project/${PROJECT}")" || exit
jira_versions="$(jq -r '.versions' <<< "${project}")"

# If the fixed version value is auto, attempt to detect versions from pull linked pull request
if [ "${FIXED_VERSION}" == "auto" ]; then
timeline="$(curl -sL --show-error --fail-with-body -H "Accept: application/vnd.github+json" "${TIMELINE_URL}")" || exit
filter='.[] | select(.event == "cross-referenced") | .source.issue.labels.[] | select(.name | startswith("backport")).name'
readarray -t labels < <(jq -r "${filter}" <<< "${timeline}")

for label in "${labels[@]}"; do
# start with stripping off the start of the label (backport/ or backport/ent/)
version_prefix="${label##*/}"
# then strip off the end of the label
version_prefix="${version_prefix%.x*}"

filter="$(printf '.[] | select(.name | contains("%s")).name' "${version_prefix}")"
readarray -t valid_versions < <(jq -r "${filter}" <<< "${jira_versions}")
match="${version_prefix}.0"
for v in "${valid_versions[@]}"; do
if [ "${v##*.}" -gt "${match##*.}" ]; then
match="${v}"
fi
done

filter="$(printf '.[] | select(.name | endswith("%s")).id' "${match}")"
version_id="$(jq -r "${filter}" <<< "${jira_versions}")"
if [ -z "${version_id}" ]; then
printf "WARNING: Failed to find valid JIRA version to match label: '%s'\n" "${label}"
continue
fi
fixed_versions+=("$(jq -n --arg version_id "${version_id}" '[{id: $version_id}]')")
done
else
# Match version directly
filter="$(printf '.[] | select(.name | endswith("%s")).id' "${FIXED_VERSION}")"
version_id="$(jq -r "${filter}" <<< "${jira_versions}")"
if [ -z "${version_id}" ]; then
printf "WARNING: Failed to find valid JIRA version to match provided version: '%s'\n" "${FIXED_VERSION}"
else
fixed_versions+=(jq -n --arg version_id "${version_id}" '[{id: $version_id}]')
fi
fi

# If fixed versions are availble, create the data structure
if [ "${#fixed_versions[@]}" -gt "0" ]; then
template='{fields: {fixVersions: $versions}}'
# Combine all the versions into a single array
versions="$(jq -s 'add' <<< "${fixed_versions[*]}")"
# Render the data structure for the fix versions
rendered="$(jq -n --argjson versions "${versions}" "${template}")" || exit

# Add it to the payload
payload="$(jq -s '.[0] * .[1]' <<< "${payload}${rendered}")"
fi
fi

info "Transition payload:\n%s" "${issue_transition}"
info "Transition payload:\n%s" "${payload}"

jira-request --request "POST" --data "${issue_transition}" \
jira-request --request "POST" --data "${payload}" \
"${JIRA_BASE_URL}/rest/api/3/issue/${ISSUE}/transitions" || exit

info "JIRA issue '%s' transitioned to %s" "${ISSUE}" "${TRANSITION}"
3 changes: 3 additions & 0 deletions .github/workflows/jira-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ jobs:
issue: ${{ steps.search.outputs.issue }}
transition: "Closed"
resolution: "Done"
fixed-version: "auto"
project: NMD
timeline-url: ${{ github.event.issue.timeline_url }}
- name: Reopen ticket
if: github.event.action == 'reopened' && steps.search.outputs.issue
uses: ./.github/actions/jira/transition
Expand Down