File: github_release_util.sh

package info (click to toggle)
golang-github-tink-crypto-tink-go 2.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 12,952 kB
  • sloc: sh: 864; makefile: 6
file content (254 lines) | stat: -rwxr-xr-x 7,315 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#!/bin/bash
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################

# This script performs a source release on GitHub for a given repo, that is:
# - Creates a release branch (if it does not yet exist),
# - Creates a release tag.
set -eo pipefail

# Parameters and arguments. These will be populated/modified by args parsing.

# Options.
# Whether to actually create a release. This is false by default and meant to
# prevent accidental releases.
DO_RUN_ACTION="false"
# Commit at which to make the release. If unspecified, the release is made from
# HEAD.
COMMIT_HASH=
# Optional personal access token.
ACCESS_TOKEN=

# Arguments.
# Action to be performed.
ACTION=
# This must be of the form `MAJOR.MINOR.PATCH`.
VERSION=
# Repo name after github.com/tink-crypto/, e.g., tink-cc.
REPO_NAME=

# Derived variables.
GITHUB_REPO_URL=
RELEASE_BRANCH=
TAG=
GITHUB_REFS=
BRANCH_EXISTS="false"

# Constants.
readonly GITHUB_ORG_URL="github.com/tink-crypto"

usage() {
  echo "Usage: $0 [-rh] [-c <commit hash>] [-t <access token>] <action> \\"
  echo "         <version> <repository>"
  echo " <action>: The action to be performed (crete_branch|create_tag)."
  echo " <version>: The version identifier in MAJOR.MINOR.PATCH format."
  echo " <repository>: The name of the repository (e.g. \"tink-cc\")."
  echo " -c: Commit hash to use as HEAD of the release branch (optional)."
  echo " -t: Access token. Without this, the default is SSH (optional)."
  echo " -r: Whether to actually create a release; this is false by default."
  echo " -h: Show this help message."
  exit 1
}

process_params() {
  while getopts "rhc:t:" opt; do
    case "${opt}" in
      r) DO_RUN_ACTION="true" ;;
      c) COMMIT_HASH="${OPTARG}" ;;
      t) ACCESS_TOKEN="${OPTARG}" ;;
      *) usage ;;
    esac
  done
  shift $((OPTIND - 1))
  readonly DO_RUN_ACTION
  readonly COMMIT_HASH
  readonly ACCESS_TOKEN

  ACTION="$1"
  if [[ ! "${ACTION}" =~ create_branch|create_tag ]]; then
    echo "ERROR: Expected (create_branch|create_tag) got ${ACTION}" >&2
    usage
  fi
  readonly ACTION

  VERSION="$2"
  if [[ ! "${VERSION}" =~ ^[0-9]+.[0-9]+.[0-9]+$ ]]; then
    echo "ERROR: Invalid version format: expected MAJOR.MINOR.PATCH, got \
${VERSION}" >&2
    usage
  fi
  readonly VERSION

  REPO_NAME="$3"
  if [[ -z "${REPO_NAME}" ]]; then
    echo "ERROR: Repo name must be specified." >&2
    usage
  fi
  readonly REPO_NAME

  # Use SSH by default.
  local protocol_and_credentials="ssh://git"
  if [[ -n "${ACCESS_TOKEN}" ]]; then
    protocol_and_credentials="https://ise-crypto:${ACCESS_TOKEN}"
  fi
  readonly protocol_and_credentials
  GITHUB_REPO_URL="${protocol_and_credentials}@${GITHUB_ORG_URL}/${REPO_NAME}"
  readonly GITHUB_REPO_URL

  # Release branch is only MAJOR.MINOR.
  readonly RELEASE_BRANCH="$(echo "${VERSION}" | cut -d'.' -f1,2)"

  # Splitting declaration and assignment guarantees correct propagation of the
  # exit code of the subshell.
  local GITHUB_REFS
  GITHUB_REFS="$(git ls-remote "${GITHUB_REPO_URL}")"
  readonly GITHUB_REFS

  local -r expected_release_branch="refs/heads/${RELEASE_BRANCH}"
  if echo "${GITHUB_REFS}" | grep "${expected_release_branch}" > /dev/null; then
    BRANCH_EXISTS="true"
  fi
  readonly BRANCH_EXISTS

  if [[ "${ACTION}" == "create_tag" ]]; then
    if [[ "${BRANCH_EXISTS}" == "false" ]]; then
      echo "ERROR: The release branch does not exist in \
${GITHUB_ORG_URL}/${REPO_NAME}." >&2
      return 1
    fi
    local -r release_tag="v${VERSION}"
    local -r expected_release_tag="refs/tags/${release_tag}"
    if echo "${GITHUB_REFS}" | grep "${expected_release_tag}" > /dev/null; then
      echo "ERROR The tag \"${release_tag}\" already exists in \
${GITHUB_ORG_URL}/${REPO_NAME}." >&2
      return 1
    fi

  fi
}

#######################################
# Prints a command
#
# Args:
#   Command to execute.
#
#######################################
print_command() {
  printf '%q ' '+' "$@"
  echo
}

#######################################
# Runs a command if DO_RUN_ACTION is true.
#
# Args:
#   Command to execute.
# Globals:
#   DO_RUN_ACTION
#
#######################################
run_command() {
  if [[ "${DO_RUN_ACTION}" == "false" ]]; then
    echo "  *** Dry run, command not executed. ***"
    return 0
  fi
  # Actually run the command.
  "$@"
  return $?
}

#######################################
# Prints and runs a command.
#
# Args:
#   Command to execute.
#
#######################################
print_and_run_command() {
  print_command "$@"
  run_command "$@"
}

#######################################
# Creates and checks out to the release branch.
#
# If COMMIT_HASH is specified, use COMMIT_HASH as HEAD for the branch.
#
# Globals:
#   RELEASE_BRANCH
#   COMMIT_HASH
#
#######################################
git_create_release_branch() {
  if [[ "${BRANCH_EXISTS}" == "true" ]]; then
    echo "WARNING: The release branch already exists. Nothing to do."
    return 0
  fi
  # Target branch does not exist so we create the release branch.
  if [[ -n "${COMMIT_HASH:-}" ]]; then
    # Use COMMIT_HASH as HEAD for this branch.
    print_and_run_command git branch "${RELEASE_BRANCH}" "${COMMIT_HASH}"
  else
    print_and_run_command git branch "${RELEASE_BRANCH}"
  fi
  print_and_run_command git push origin "${RELEASE_BRANCH}"
}

#######################################
# Creates a release tag.
#
# Globals:
#   RELEASE_BRANCH
#   REPO_NAME
#   VERSION
#
#######################################
git_create_release_tag() {
  if [[ "${BRANCH_EXISTS}" == "false" ]]; then
    echo "ERROR: The release branch does not exist in \
${GITHUB_ORG_URL}/${REPO_NAME}." >&2
    return 1
  fi
  local -r release_tag="v${VERSION}"
  local -r expected_release_tag="refs/tags/${release_tag}"
  if echo "${GITHUB_REFS}" | grep "${expected_release_tag}" > /dev/null; then
    echo "ERROR The tag \"${release_tag}\" already exists in \
${GITHUB_ORG_URL}/${REPO_NAME}." >&2
    return 1
  fi
  print_and_run_command git checkout "${RELEASE_BRANCH}"
  print_and_run_command git tag -a "${release_tag}" \
    -m "${REPO_NAME} version ${VERSION}"
  print_and_run_command git push origin "${release_tag}"
}

main() {
  process_params "$@"
  # Avoid logging the full URL; replace GIT_URL with a version that omits user
  # and access token.
  local -r protocol="$(echo "${GITHUB_REPO_URL}" | cut -d':' -f1)"
  local -r github_repo="$(echo "${GITHUB_REPO_URL}" | cut -d'@' -f2)"
  print_command git clone "${protocol}://...@${github_repo}"
  run_command git clone "${GITHUB_REPO_URL}"
  print_and_run_command cd "${REPO_NAME}"

  case "${ACTION}" in
    create_branch) git_create_release_branch ;;
    create_tag) git_create_release_tag ;;
  esac
}

main "$@"