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
52 changes: 52 additions & 0 deletions count-releasable-commits.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env -S bash -e

function log() {
echo 1>&2 "$@"
}

function usage() {
log "Usage:"
log
log " $0 <project>"
log
log " <project> One of [search,validator,ogm,orm,reactive]"
}

SCRIPTS_DIR="$(readlink -f ${BASH_SOURCE[0]} | xargs dirname)"

PROJECT=$1
WORKSPACE=${WORKSPACE:-'.'}

if [ "$PROJECT" == "search" ]; then
MESSAGE_PATTERN='^HSEARCH-|^\[HSEARCH-'
elif [ "$PROJECT" == "validator" ]; then
MESSAGE_PATTERN='^HV-|^\[HV-'
elif [ "$PROJECT" == "ogm" ]; then
MESSAGE_PATTERN='^OGM-|^\[OGM-'
elif [ "$PROJECT" == "orm" ]; then
MESSAGE_PATTERN='^HHH-|^\[HHH-'
elif [ "$PROJECT" == "tools" ]; then
MESSAGE_PATTERN='^HBX-|^\[HBX-'
elif [ "$PROJECT" == "reactive" ]; then
MESSAGE_PATTERN='^#[[:digit:]]+|^\[#[[:digit:]]+'
else
log "ERROR: Unknown project name $PROJECT"
usage
exit 1
fi


LAST_RELEASE_COMMIT=$(git log --max-count=1 --author=Hibernate-CI --format='%H')
log "Last release-related commit: ${LAST_RELEASE_COMMIT}."
if [ -z "$LAST_RELEASE_COMMIT" ]
then
log "No release-related commit. Assuming no releasable commits."
log "Note: the very first release must be triggered manually."
echo "0"
exit 0
fi

# Displays the last few commits on stderr (thanks to tee) and just the count on stdout (thanks to wc)
git log $LAST_RELEASE_COMMIT..HEAD -E "--grep=${MESSAGE_PATTERN}" --format=' %H %s' \
| tee >(echo 1>&2 "Releasable commits (max 10 displayed):"; tail -n 10 1>&2) \
| wc -l
217 changes: 57 additions & 160 deletions jira-release.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
#!/usr/bin/env -S bash -e

JIRA_CLOSE_TRANSITION_ID=2
JIRA_REOPEN_TRANSITION_ID=3

function usage() {
echo "Usage:"
echo
echo " $0 [options] <jira_key> <release_version> <next_version>"
echo " $0 [options] <project> <release_version> <development_version>"
echo
echo " <jira_key> The Jira project key (e.g. HHH)"
echo " <project> One of [search,validator,ogm,orm]"
echo " <release_version> The version to release (e.g. 6.0.1)"
echo " <next_version> The new version to create (e.g. 6.0.2)"
echo " <development_version> The new version after the release (e.g. 6.0.2-SNAPSHOT)"
echo
echo " Options"
echo
echo " -h Show this help and exit."
echo " -d Dry run; do not push, deploy or publish anything."
}

function needs_arg() { if [ -z "$OPTARG" ]; then die "No arg for --$opt option"; fi; }

#--------------------------------------------
# Option parsing

Expand All @@ -26,7 +25,17 @@ function exec_or_dry_run() {
}
PUSH_CHANGES=true

while getopts 'dhb:' opt; do
notesFile=""
while getopts 'dh-:' opt; do
if [ "$opt" = "-" ]; then
# long option: reformulate opt and OPTARG
# - extract long option name
opt="${OPTARG%%=*}"
# - extract long option argument (may be empty)
OPTARG="${OPTARG#"$opt"}"
# - remove assigning `=`
OPTARG="${OPTARG#=}"
fi
case "$opt" in
h)
usage
Expand All @@ -40,7 +49,7 @@ while getopts 'dhb:' opt; do
echo "DRY RUN; would have executed:" "${@}"
}
;;
\?)
*)
usage
exit 1
;;
Expand All @@ -51,171 +60,59 @@ shift $((OPTIND - 1))

SCRIPTS_DIR="$(readlink -f ${BASH_SOURCE[0]} | xargs dirname)"

JIRA_KEY=$1
PROJECT=$1
RELEASE_VERSION=$2
NEXT_VERSION=$3
DEVELOPMENT_VERSION=$3

if [ -z "$JIRA_KEY" ]; then
echo "ERROR: Jira key not supplied"
if [ -z "$PROJECT" ]; then
echo "ERROR: Project not supplied"
usage
exit 1
fi

if [ -z "$RELEASE_VERSION" ]; then
echo "ERROR: Release version not supplied"
exit 1
fi

if [ -z "$NEXT_VERSION" ]; then
echo "ERROR: Next version not supplied"
echo "ERROR: Release version argument not supplied"
usage
exit 1
fi

if [ "$PUSH_CHANGES" == 'true' ] && [ -z "$JIRA_API_TOKEN" ]; then
echo "ERROR: Environment variable JIRA_API_TOKEN must not be empty"
if [ -z "$DEVELOPMENT_VERSION" ]; then
echo "ERROR: Development version argument not supplied"
exit 1
fi

JIRA_VERSION_ID=$($SCRIPTS_DIR/determine-jira-version-id.sh $JIRA_KEY $RELEASE_VERSION)

response=$(exec_or_dry_run curl -L -s -w "\n%{http_code}" -X PUT \
-u "\$JIRA_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"released": true}' \
"https://hibernate.atlassian.net/rest/api/2/version/$JIRA_VERSION_ID")

if [ "$PUSH_CHANGES" == true ]; then
jiraReleaseResponseCode=$(tail -n1 <<< "$response") # get the last line
jiraReleaseResponse=$(sed '$ d' <<< "$response") # get all but the last line which contains the status code

if [ "$jiraReleaseResponseCode" != 200 ]; then
echo "$jiraReleaseResponse"
echo "ERROR: Release failed because Jira version ${RELEASE_VERSION} could not be released"
exit 1
fi
if [ "$PROJECT" == "search" ]; then
JIRA_KEY="HSEARCH"
STRIPPED_SUFFIX_FOR_JIRA=""
elif [ "$PROJECT" == "validator" ]; then
JIRA_KEY="HV"
STRIPPED_SUFFIX_FOR_JIRA=""
elif [ "$PROJECT" == "ogm" ]; then
JIRA_KEY="OGM"
STRIPPED_SUFFIX_FOR_JIRA=""
elif [ "$PROJECT" == "orm" ]; then
JIRA_KEY="HHH"
STRIPPED_SUFFIX_FOR_JIRA=".Final"
elif [ "$PROJECT" == "tools" ]; then
JIRA_KEY="HBX"
STRIPPED_SUFFIX_FOR_JIRA=""
else
echo $response
echo "ERROR: Unknown project name $PROJECT"
usage
exit 1
fi

response=$(exec_or_dry_run curl -L -s -w "\n%{http_code}" -X POST \
-u "\$JIRA_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"name": "'${NEXT_VERSION}'", "projectId": '${JIRA_PROJECT_ID}} \
'https://hibernate.atlassian.net/rest/api/2/version')

if [ "$PUSH_CHANGES" == true ]; then
jiraCreateVersionResponseCode=$(tail -n1 <<< "$response") # get the last line
jiraCreateVersionResponse=$(sed '$ d' <<< "$response") # get all but the last line which contains the status code

if [ "$jiraCreateVersionResponseCode" != 201 ]; then
echo "$jiraCreateVersionResponse"
echo "ERROR: Release failed because Jira version ${NEXT_VERSION} could not be created"
exit 1
fi
else
echo $response
DEVELOPMENT_VERSION=${DEVELOPMENT_VERSION%-SNAPSHOT}
if [ -n "$STRIPPED_SUFFIX_FOR_JIRA" ]; then
RELEASE_VERSION=${RELEASE_VERSION%$STRIPPED_SUFFIX_FOR_JIRA}
DEVELOPMENT_VERSION=${DEVELOPMENT_VERSION%$STRIPPED_SUFFIX_FOR_JIRA}
fi

if [ "$PUSH_CHANGES" == 'true' ] && [ -z "$JIRA_WEBHOOK_SECRET" ]; then
echo "ERROR: Environment variable JIRA_WEBHOOK_SECRET must not be empty"
exit 1
fi

# REST URL used for getting all issues of given release - see https://docs.atlassian.com/jira/REST/latest/#d2e2450
jiraIssuesResponse=$(curl -sL "https://hibernate.atlassian.net/rest/api/2/search/?jql=project%20%3D%20${JIRA_KEY}%20AND%20fixVersion%20%3D%20${RELEASE_VERSION}%20ORDER%20BY%20issuetype%20ASC&fields=issuetype,summary&maxResults=200")
jiraIssueUrls=$(echo "$jiraIssuesResponse" | sed -nE 's/(https:\/\/hibernate\.atlassian\.net\/rest\/api\/2\/issue\/[0-9]+)/\n\1\n/gp' | grep https://hibernate.atlassian.net/rest/api/2/issue/)

# Close resolved issues. Remove fix version from Done non-resolved issues.
# Move issues Undone non-resolved issues to next version.
while IFS= read -r jiraIssueUrl; do
jiraIssueResponse=$(curl -sL "$jiraIssueUrl")
jiraIssueId=$(echo "$jiraIssueResponse" | sed -nE 's/^\{[^{]+"id":"([^"]+)".+/\1/p' )
jiraIssueKey=$(echo "$jiraIssueResponse" | sed -nE 's/^\{[^{]+"key":"([^"]+)".+/\1/p' )
jiraIssueStatus=$(echo "$jiraIssueResponse" | sed -nE 's/.*"status":\{([^{]+)\,"statusCategory".+/\1/p' | sed -nE 's/.*"name":"([^"]+)".+/\1/p' )
if [ "$jiraIssueStatus" == "Resolved" ]; then
response=$(exec_or_dry_run curl -L -s -w "\n%{http_code}" -X POST \
-u "\$JIRA_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"transition":{"id":"'${JIRA_CLOSE_TRANSITION_ID}'"}}' \
"https://hibernate.atlassian.net/rest/api/2/issue/${jiraIssueId}/transitions")

if [ "$PUSH_CHANGES" == true ]; then
jiraCloseIssueResponseCode=$(tail -n1 <<< "$response") # get the last line
jiraCloseIssueResponse=$(sed '$ d' <<< "$response") # get all but the last line which contains the status code

if [ "$jiraCloseIssueResponseCode" != 201 ]; then
echo "$jiraCloseIssueResponse"
echo "ERROR: Release failed because Jira issue ${jiraIssueKey} could not be closed"
exit 1
fi
else
echo $response
fi
elif [ "$jiraIssueStatus" == "Closed" ]; then

if [ "$jiraIssueResolution" != "Fixed" ]; then
response=$(exec_or_dry_run curl -L -s -w "\n%{http_code}" -X POST \
-u "\$JIRA_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"transition":{"id":"'${JIRA_REOPEN_TRANSITION_ID}'"}}' \
"https://hibernate.atlassian.net/rest/api/2/issue/${jiraIssueId}/transitions")

if [ "$PUSH_CHANGES" == true ]; then
jiraReopenIssueResponseCode=$(tail -n1 <<< "$response") # get the last line
jiraReopenIssueResponse=$(sed '$ d' <<< "$response") # get all but the last line which contains the status code

if [ "$jiraReopenIssueResponseCode" != 201 ]; then
echo "$jiraReopenIssueResponse"
echo "ERROR: Release failed because Jira issue ${jiraIssueKey} could not be reopened"
exit 1
fi
else
echo $response
fi

response=$(exec_or_dry_run curl -L -s -w "\n%{http_code}" -X POST \
-u "\$JIRA_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"transition":{"id":"'${JIRA_CLOSE_TRANSITION_ID}'"},"update":{"fixVersions":[{"remove":"'${RELEASE_VERSION}'"}]},"fields":{"resolution":{"name":"'${jiraIssueResolution}'"}}}' \
"https://hibernate.atlassian.net/rest/api/2/issue/${jiraIssueId}/transitions")

if [ "$PUSH_CHANGES" == true ]; then
jiraCloseIssueResponseCode=$(tail -n1 <<< "$response") # get the last line
jiraCloseIssueResponse=$(sed '$ d' <<< "$response") # get all but the last line which contains the status code

if [ "$jiraCloseIssueResponseCode" != 201 ]; then
echo "$jiraCloseIssueResponse"
echo "ERROR: Release failed because Jira issue ${jiraIssueKey} could not be closed"
exit 1
fi
else
echo $response
fi
else
echo "Ignoring already closed Jira issue: ${jiraIssueKey}"
fi
else
response=$(exec_or_dry_run curl -L -s -w "\n%{http_code}" -X POST \
-u "\$JIRA_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"update":{"fixVersions":[{"remove":"'${RELEASE_VERSION}'"},{"add":"'${NEXT_VERSION}'"}]}}' \
"https://hibernate.atlassian.net/rest/api/2/issue/${jiraIssueId}")

if [ "$PUSH_CHANGES" == true ]; then
jiraMoveIssueResponseCode=$(tail -n1 <<< "$response") # get the last line
jiraMoveIssueResponse=$(sed '$ d' <<< "$response") # get all but the last line which contains the status code

if [ "$jiraMoveIssueResponseCode" != 201 ]; then
echo "$jiraMoveIssueResponse"
echo "ERROR: Release failed because Jira issue ${jiraIssueKey} could not be moved to next version"
exit 1
fi
else
echo $response
fi
fi
done <<< "$jiraIssueUrls"



exec_or_dry_run curl -L --fail-with-body -X POST \
-H "X-Automation-Webhook-Token: $JIRA_WEBHOOK_SECRET" \
-H 'Content-Type: application/json' \
-d '{"data":{"projectKey": "'${JIRA_KEY}'", "releaseVersion":"'${RELEASE_VERSION}'","nextVersion":"'${DEVELOPMENT_VERSION}'"}}' \
https://api-private.atlassian.com/automation/webhooks/jira/a/1fec2f23-3f8e-486e-b8fe-85159188d8c8/01970d1d-d1fa-756b-98f0-53c1d7cfd676