|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +set -euo pipefail |
| 4 | + |
| 5 | +script_dir="$(cd "$(dirname "$0")" && pwd)" |
| 6 | +# shellcheck source=.github/scripts/release-common.sh |
| 7 | +source "${script_dir}/release-common.sh" |
| 8 | + |
| 9 | +require_maintainer |
| 10 | + |
| 11 | +release_version="$(extract_issue_field_line "Release version")" |
| 12 | +next_version="$(extract_issue_field_line "Next version")" |
| 13 | +target_branch="$(extract_issue_field_line "Target branch")" |
| 14 | +release_notes="$(extract_issue_field "Release notes" || true)" |
| 15 | + |
| 16 | +validate_release_version "${release_version}" |
| 17 | +validate_next_version "${next_version}" |
| 18 | +validate_release_target_branch "${target_branch}" |
| 19 | + |
| 20 | +tag_name="v${release_version}" |
| 21 | +work_branch="release-work/${release_version}" |
| 22 | + |
| 23 | +require_missing_remote_tag "${tag_name}" |
| 24 | + |
| 25 | +pr_number="$(gh pr list \ |
| 26 | + --head "${work_branch}" \ |
| 27 | + --base "${target_branch}" \ |
| 28 | + --state open \ |
| 29 | + --json number \ |
| 30 | + --jq '.[0].number // empty')" |
| 31 | + |
| 32 | +if [[ -z "${pr_number}" ]]; then |
| 33 | + echo "No open release PR found for ${work_branch} into ${target_branch}." |
| 34 | + exit 1 |
| 35 | +fi |
| 36 | + |
| 37 | +pr_data="$(gh pr view "${pr_number}" --json baseRefName,headRefName,headRefOid,mergeable,mergeStateStatus,reviewDecision)" |
| 38 | +actual_base="$(jq -r '.baseRefName' <<<"${pr_data}")" |
| 39 | +actual_head="$(jq -r '.headRefName' <<<"${pr_data}")" |
| 40 | +head_ref_oid="$(jq -r '.headRefOid' <<<"${pr_data}")" |
| 41 | +mergeable="$(jq -r '.mergeable' <<<"${pr_data}")" |
| 42 | +merge_state="$(jq -r '.mergeStateStatus' <<<"${pr_data}")" |
| 43 | +review_decision="$(jq -r '.reviewDecision' <<<"${pr_data}")" |
| 44 | + |
| 45 | +if [[ "${actual_base}" != "${target_branch}" || "${actual_head}" != "${work_branch}" ]]; then |
| 46 | + echo "Release PR does not match the issue target branch and work branch." |
| 47 | + exit 1 |
| 48 | +fi |
| 49 | +if [[ "${mergeable}" == "CONFLICTING" || "${merge_state}" == "DIRTY" ]]; then |
| 50 | + echo "Release PR has merge conflicts." |
| 51 | + exit 1 |
| 52 | +fi |
| 53 | +if [[ "${review_decision}" != "APPROVED" ]]; then |
| 54 | + echo "Release PR must be approved before publishing. Current review decision: ${review_decision}." |
| 55 | + exit 1 |
| 56 | +fi |
| 57 | + |
| 58 | +gh pr checks "${pr_number}" --required --fail-fast |
| 59 | + |
| 60 | +configure_git_author |
| 61 | +configure_git_credentials |
| 62 | +git fetch origin \ |
| 63 | + "+refs/heads/${target_branch}:refs/remotes/origin/${target_branch}" \ |
| 64 | + "+refs/heads/${work_branch}:refs/remotes/origin/${work_branch}" \ |
| 65 | + --tags |
| 66 | + |
| 67 | +if [[ "$(git rev-parse "origin/${work_branch}")" != "${head_ref_oid}" ]]; then |
| 68 | + echo "Release branch changed after PR checks were inspected." |
| 69 | + exit 1 |
| 70 | +fi |
| 71 | + |
| 72 | +release_commit="" |
| 73 | +while read -r commit; do |
| 74 | + if git show "${commit}:gradle.properties" | grep -q "^version=${release_version}$"; then |
| 75 | + release_commit="${commit}" |
| 76 | + break |
| 77 | + fi |
| 78 | +done < <(git rev-list --reverse "origin/${target_branch}..origin/${work_branch}") |
| 79 | + |
| 80 | +if [[ -z "${release_commit}" ]]; then |
| 81 | + echo "Could not find release commit with version=${release_version}." |
| 82 | + exit 1 |
| 83 | +fi |
| 84 | + |
| 85 | +if ! git show "origin/${work_branch}:gradle.properties" | grep -q "^version=${next_version}$"; then |
| 86 | + echo "Release branch tip does not contain version=${next_version}." |
| 87 | + exit 1 |
| 88 | +fi |
| 89 | + |
| 90 | +tag_message="$(mktemp)" |
| 91 | +{ |
| 92 | + echo "Release ${tag_name}" |
| 93 | + if [[ -n "${release_notes}" ]]; then |
| 94 | + echo |
| 95 | + echo "${release_notes}" |
| 96 | + fi |
| 97 | +} >"${tag_message}" |
| 98 | + |
| 99 | +git tag -a "${tag_name}" "${release_commit}" -F "${tag_message}" |
| 100 | +if [[ "$(git cat-file -t "${tag_name}")" != "tag" ]]; then |
| 101 | + echo "${tag_name} is not an annotated tag." |
| 102 | + exit 1 |
| 103 | +fi |
| 104 | + |
| 105 | +git push --atomic --follow-tags origin "refs/remotes/origin/${work_branch}:refs/heads/${target_branch}" |
| 106 | +gh issue comment "${ISSUE_NUMBER}" --body "Published ${tag_name} to ${target_branch}." |
0 commit comments