blob: c6e7d6541c0e3d4c2910d8ac3ec951f345ee28c9 [file] [log] [blame]
Zack Williams27cd3e52018-09-18 16:44:50 -07001#!/usr/bin/env bash
Joey Armstrong28eddda2023-01-10 03:09:34 -05002# -----------------------------------------------------------------------
3# Copyright 2018-2023 Open Networking Foundation (ONF) and the ONF Contributors
Zack Williams27cd3e52018-09-18 16:44:50 -07004#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
Joey Armstrong28eddda2023-01-10 03:09:34 -050016#
Zack Williams27cd3e52018-09-18 16:44:50 -070017# github-release.sh
18# builds (with make) and uploads release artifacts (binaries, etc.) to github
19# given a tag also create checksums files and release notes from the commit
20# message
Joey Armstrong28eddda2023-01-10 03:09:34 -050021# -----------------------------------------------------------------------
Zack Williams27cd3e52018-09-18 16:44:50 -070022
Joey Armstrong2097d3e2023-03-26 10:32:03 -040023set -euo pipefail
24
25##-------------------##
26##---] GLOBALS [---##
27##-------------------##
28declare -g WORKSPACE
29declare -g GERRIT_PROJECT
30declare -g __githost='github.com'
31
32## -----------------------------------------------------------------------
33## Uncomment to activate
34## -----------------------------------------------------------------------
Joey Armstrong76026b72023-03-29 12:19:17 -040035declare -i -g draft_release=1
Joey Armstrong41923cc2023-01-30 14:38:16 -050036# declare -g TRACE=0 # uncomment to set -x
37
38# shellcheck disable=SC2015
39[[ -v TRACE ]] && { set -x; } || { set +x; } # SC2015 (shellcheck -x)
40
Joey Armstrong2097d3e2023-03-26 10:32:03 -040041declare -a -g ARGV=() # Capture args to minimize globals and arg passing
42[[ $# -gt 0 ]] && ARGV=("$@")
Joey Armstrongd99e3d22023-01-29 12:35:43 -050043
44declare -g scratch # temp workspace for downloads
45declare -g gh_cmd # path to gh command
46
Joey Armstrong2097d3e2023-03-26 10:32:03 -040047declare -g SCRIPT_VERSION='1.2' # git changeset needed
Joey Armstrong26707f02023-01-26 12:41:12 -050048
Joey Armstrong7f382ef2023-01-25 12:00:08 -050049##--------------------##
50##---] INCLUDES [---##
Joey Armstrong1962bcf2023-01-27 13:53:18 -050051##--------------------#
Joey Armstrong2097d3e2023-03-26 10:32:03 -040052
53## -----------------------------------------------------------------------
54## Intent: Register an interrupt handler to display a stack trace on error
55## -----------------------------------------------------------------------
56function errexit()
57{
58 local err=$?
59 set +o xtrace
60 local code="${1:-1}"
61
62 local prefix="${BASH_SOURCE[1]}:${BASH_LINENO[0]}"
63 echo -e "\nOFFENDER: ${prefix}"
64 if [ $# -gt 0 ] && [ "$1" == '--stacktrace-quiet' ]; then
65 code=1
66 else
67 echo "ERROR: '${BASH_COMMAND}' exited with status $err"
68 fi
69
70 # Print out the stack trace described by $function_stack
71 if [ ${#FUNCNAME[@]} -gt 2 ]
72 then
73 echo "Call tree:"
74 for ((i=1;i<${#FUNCNAME[@]}-1;i++))
75 do
76 echo " $i: ${BASH_SOURCE[$i+1]}:${BASH_LINENO[$i]} ${FUNCNAME[$i]}(...)"
77 done
78 fi
79
80 echo "Exiting with status ${code}"
81 echo
82 exit "${code}"
83 # return
84}
85
86# trap ERR to provide an error handler whenever a command exits nonzero
87# this is a more verbose version of set -o errexit
88trap errexit ERR
89
90# setting errtrace allows our ERR trap handler to be propagated to functions,
91# expansions and subshells
92set -o errtrace
Joey Armstrong7f382ef2023-01-25 12:00:08 -050093
94## -----------------------------------------------------------------------
Joey Armstrongd99e3d22023-01-29 12:35:43 -050095## Intent: Cleanup scratch area on exit
96## -----------------------------------------------------------------------
97function sigtrap()
98{
99 ## Prevent mishaps
100 local is_read_only
101 is_read_only="$(declare -p scratch)"
102 if [[ $is_read_only != *"declare -r scratch="* ]]; then
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400103 echo "ERROR: variable scratch is not read-only, cleanup skipped"
104 exit 1
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500105 fi
106
107 if [ -d "$scratch" ]; then
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400108 /bin/rm -fr "$scratch"
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500109 fi
110
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400111 do_logout
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500112 return
113}
114trap sigtrap EXIT
115
116## -----------------------------------------------------------------------
Joey Armstrongad7b1e02023-03-27 11:55:48 -0400117## Intent: Return a release version for queries
118## Note: Do not use in production, function is intended for interactive use
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400119## -----------------------------------------------------------------------
120function get_version()
121{
122 declare -n ref="$1"
123
124 banner
125 declare -a rev=()
126 rev+=("$(( RANDOM % 10 + 1 ))")
127 rev+=("$(( RANDOM % 256 + 1 ))")
Joey Armstrongeef8c2c2023-03-27 17:27:43 -0400128 rev+=("$(( RANDOM % 10000 + 1 ))")
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400129 ver="v${rev[0]}.${rev[1]}.${rev[2]}"
130
131 func_echo "version: $ver"
132 ref="$ver"
133 return
134}
135
136## -----------------------------------------------------------------------
137## Intent: Provide defaults for environment variables
138## -----------------------------------------------------------------------
139function initEnvVars()
140{
141 # when not running under Jenkins, use current dir as workspace and a blank
142 # project name
143 declare -g WORKSPACE=${WORKSPACE:-.}
144 declare -g GERRIT_PROJECT=${GERRIT_PROJECT:-}
Joey Armstrong76026b72023-03-29 12:19:17 -0400145
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400146 # Github organization (or user) this project is published on. Project name should
147 # be the same on both Gerrit and GitHub
Joey Armstrong76026b72023-03-29 12:19:17 -0400148 declare -g GITHUB_ORGANIZATION=${GITHUB_ORGANIZATION:-}
149
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400150 # glob pattern relative to project dir matching release artifacts
151 # ARTIFACT_GLOB=${ARTIFACT_GLOB:-"release/*"} # stat -- release/* not found, literal string (?)
152 declare -g ARTIFACT_GLOB=${ARTIFACT_GLOB:-"release/."}
Joey Armstrong76026b72023-03-29 12:19:17 -0400153
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400154 # Use "release" as the default makefile target, can be a space separated list
155 declare -g RELEASE_TARGETS=${RELEASE_TARGETS:-release}
Joey Armstrong76026b72023-03-29 12:19:17 -0400156
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400157 # Set and handle GOPATH and PATH
158 export GOPATH=${GOPATH:-$WORKSPACE/go}
159 export PATH=$PATH:/usr/lib/go-1.12/bin:/usr/local/go/bin:$GOPATH/bin
160 return
161}
162
163## -----------------------------------------------------------------------
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500164## Intent: Create a scratch area for downloads and transient tools
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400165## temp directory will be automatically removed upon exit.
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500166## -----------------------------------------------------------------------
167function init()
168{
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500169 local pkgbase="${0##*/}" # basename
170 local pkgname="${pkgbase%.*}"
171
Joey Armstrongad7b1e02023-03-27 11:55:48 -0400172 # initEnvVars # moved to full_banner()
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400173
174 ## Create a temp directory for auto-cleanup
175 declare -g scratch
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500176 scratch="$(mktemp -d -t "${pkgname}.XXXXXXXXXX")"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400177 readonly scratch
178 declare -p scratch
179
180 ## prime the stream
181 local work
182 get_release_dir work
183 declare -p work
184 return
185}
186
187## -----------------------------------------------------------------------
188## Intent: Verbose output for logging
189## -----------------------------------------------------------------------
190function banner()
191{
192 local iam="${0##*/}"
193 cat <<EOB
194
195** -----------------------------------------------------------------------
196** ${iam}::${FUNCNAME[1]}: $*
197** -----------------------------------------------------------------------
198EOB
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500199}
200
201## -----------------------------------------------------------------------
Joey Armstrong7f382ef2023-01-25 12:00:08 -0500202## Intent: Output a log banner to identify the running script/version.
203## -----------------------------------------------------------------------
204## TODO:
205## o SCRIPT_VERSION => git changeset for repo:ci-managment
206## o echo "library version: ${env."library.libName.version"}"
207# -----------------------------------------------------------------------
208# 14:18:38 > git fetch --no-tags --progress -- https://gerrit.opencord.org/ci-management.git +refs/heads/*:refs/remotes/origin/* # timeout=10
209# 14:18:39 Checking out Revision 50f6e0b97f449b32d32ec0e02d59642000351847 (master)
210# -----------------------------------------------------------------------
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400211function full_banner()
Joey Armstrong7f382ef2023-01-25 12:00:08 -0500212{
Joey Armstrongad7b1e02023-03-27 11:55:48 -0400213 local iam="${0##*/}"
214
215 initEnvVars # set defaults
Joey Armstrong7f382ef2023-01-25 12:00:08 -0500216
217cat <<EOH
218
219** -----------------------------------------------------------------------
220** IAM: ${iam} :: ${FUNCNAME[0]}
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400221** ARGV: ${ARGV[@]}
Joey Armstrong7f382ef2023-01-25 12:00:08 -0500222** PWD: $(/bin/pwd)
223** NOW: $(date '+%Y/%m/%d %H:%M:%S')
224** VER: ${SCRIPT_VERSION:-'unknown'}
225** -----------------------------------------------------------------------
Joey Armstrongad7b1e02023-03-27 11:55:48 -0400226** GERRIT_PROJECT: $(declare -p GERRIT_PROJECT)
227** GITHUB_ORGANIZATION: $(declare -p GITHUB_ORGANIZATION)
228** RELEASE_TARGETS: $(declare -p RELEASE_TARGETS)
229** GOPATH: $(declare -p GOPATH)
230** -----------------------------------------------------------------------
231** PATH += /usr/lib/go-1.12/bin:/usr/local/go/bin:GOPATH/bin
232** -----------------------------------------------------------------------
Joey Armstrong7f382ef2023-01-25 12:00:08 -0500233EOH
234
235 return
236}
237
Joey Armstrongaf577ab2022-12-15 14:43:33 -0500238## -----------------------------------------------------------------------
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400239## Intent: Display a message with 'iam' identifier for logging
Joey Armstrong50f6e0b2023-01-24 14:14:08 -0500240## -----------------------------------------------------------------------
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400241function func_echo()
Joey Armstrong1962bcf2023-01-27 13:53:18 -0500242{
243 local iam="${0##*/}"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400244 echo "** ${iam} :: ${FUNCNAME[1]}: $*"
Joey Armstrong1962bcf2023-01-27 13:53:18 -0500245 return
246}
247
248## -----------------------------------------------------------------------
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400249## Intent: Display an error message then exit with status.
250## -----------------------------------------------------------------------
251function error()
252{
253 local iam="${0##*/}"
254 echo "ERROR ${iam} :: ${FUNCNAME[1]}: $*"
255 exit 1
256}
257
258## -----------------------------------------------------------------------
259## Intent: Verify sandbox/build is versioned for release.
260## -----------------------------------------------------------------------
261function getGitVersion()
262{
263 declare -n varname="$1"; shift
264 local ver
265
266 banner
Joey Armstrong39fac652023-03-27 18:50:43 -0400267
268 ## [TODO] move to get_version()
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400269 ver="$(git tag -l --points-at HEAD)"
270 declare -p ver
Joey Armstrong39fac652023-03-27 18:50:43 -0400271 # get_version 'ver'
272 # declare -p ver
Joey Armstrong76026b72023-03-29 12:19:17 -0400273
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400274 # ------------------------------------------------------
275 # match bare versions or v-prefixed golang style version
276 # Critical failure for new/yet-to-be-released repo ?
277 # ------------------------------------------------------
278 if [[ "$ver" =~ ^v?([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]
279 then
280 echo "git has a SemVer released version tag: '$ver'"
281 echo "Building artifacts for GitHub release."
282 else
283 error "No SemVer released version tag found, exiting..."
284 fi
285
286 varname="$ver"
287 func_echo "GIT_VERSION is [$GIT_VERSION] from $(/bin/pwd)"
288 return
289}
290
291## -----------------------------------------------------------------------
292## Intent:
293## Note: Release description is sanitized version of the log message
294## -----------------------------------------------------------------------
295function getReleaseDescription()
296{
297 declare -n varname="$1"; shift
298
299 local msg
300 msg="$(git log -1 --pretty=%B)"
301
302 local val
303 val="$(tr -dc "[:alnum:]\n\r\.\[\]\:\-\\\/\`\' " <<< "$msg")"
304
305 [[ ${#val} -eq 0 ]] && error "Release Description is empty ($msg)"
306 varname="$val"
307 return
308}
309
310## -----------------------------------------------------------------------
311## Intent: Retrieve value of the release temp directory.
312## -----------------------------------------------------------------------
313## Note: Limit use of globals so logic can be isolated in function calls.
314## -----------------------------------------------------------------------
315# declare -g RELEASE_TEMP
316function get_release_dir()
317{
318 declare -n varname=$1; shift
319
320 # Temporary staging directory to copy artifacts to
321 varname="$scratch/release"
322 mkdir -p "$varname"
323 return
324}
325
326## -----------------------------------------------------------------------
327## Intent: Retrieve github server hostname
328## -----------------------------------------------------------------------
329function get_gh_hostname()
330{
331 declare -n varname=$1; shift
332 varname+=('--hostname' "${__githost}")
333 return
334}
335
336## -----------------------------------------------------------------------
337## Intent: Retrieve repository organizaiton name
338## -----------------------------------------------------------------------
339function get_gh_repo_org()
340{
341 declare -n varname=$1; shift
342 declare -g __repo_org
Joey Armstrong76026b72023-03-29 12:19:17 -0400343
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400344 local org
345 if [[ -v __repo_org ]]; then
346 org="$__repo_org"
347 elif [[ ! -v GITHUB_ORGANIZATION ]]; then
348 error "--repo-org or GITHUB_ORGANIZATION= are required"
349 else
350 org="${GITHUB_ORGANIZATION}"
351 fi
352
353 # shellcheck disable=SC2178
354 varname="$org"
355 return
356}
357
358## -----------------------------------------------------------------------
359## Intent: Retrieve repository organizaiton name
360## -----------------------------------------------------------------------
361function get_gh_repo_name()
362{
363 declare -n varname=$1; shift
364 declare -g __repo_name
Joey Armstrong76026b72023-03-29 12:19:17 -0400365
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400366 local name
367 if [[ -v __repo_name ]]; then
368 name="$__repo_name"
Joey Armstrong39fac652023-03-27 18:50:43 -0400369 elif [[ ! -v GERRIT_PROJECT ]]; then
370 error "--repo-name or GERRIT_PROJECT= are required"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400371 else
Joey Armstrong39fac652023-03-27 18:50:43 -0400372 name="${GERRIT_PROJECT}"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400373 fi
374
375 varname="$name"
376 return
377}
378
379## -----------------------------------------------------------------------
380## Intent: Return path for the gh release query
381## -----------------------------------------------------------------------
382function get_gh_releases()
383{
384 declare -n ref="$1"
385
386 local repo_org
387 get_gh_repo_org repo_org
388
389 local repo_name
390 get_gh_repo_name repo_name
391
392 ref="repos/${repo_org}/${repo_name}/releases"
393 func_echo "ref=$ref"
394 return
395}
396
397## -----------------------------------------------------------------------
398## Intent: Retrieve repository path argument
399## -----------------------------------------------------------------------
400function get_argv_repo()
401{
402 declare -n varname=$1; shift
403
404 local repo_org
405 get_gh_repo_org repo_org
Joey Armstrong76026b72023-03-29 12:19:17 -0400406
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400407 local repo_name
Joey Armstrong76026b72023-03-29 12:19:17 -0400408 get_gh_repo_name repo_name
409
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400410 varname="${repo_org}/${repo_name}"
411 func_echo "VARNAME=$varname"
412 return
413}
414
415## -----------------------------------------------------------------------
416## Intent: Retrieve release name string "project - version"
417## -----------------------------------------------------------------------
418function get_argv_name()
419{
420 declare -n varname=$1; shift
421
422 local repo_name
423 get_gh_repo_name repo_name
424 varname="${repo_name} - $GIT_VERSION"
425 func_echo "varname=$varname"
426 return
427}
428
429## -----------------------------------------------------------------------
430## Intent: Retrieve tag version
431## -----------------------------------------------------------------------
432function get_argv_tag()
433{
434 declare -n varname=$1; shift
435
436 # cached_argv_tag='v3.41.3204'
437 if [[ ! -v cached_argv_tag ]]; then
438 declare -g cached_argv_tag
439 if [[ -v GIT_VERSION ]]; then # hello jenkins
440 cached_argv_tag="$GIT_VERSION"
441 fi
442 fi
443
444 [[ ${#cached_argv_tag} -eq 0 ]] && error "Unable to determine GIT_VERSION="
445 varname="$cached_argv_tag"
446 func_echo "varname=$varname"
447 return
448}
449
450## -----------------------------------------------------------------------
451## Intent:
452## -----------------------------------------------------------------------
453# To support golang projects that require GOPATH to be set and code checked out there
454# If $DEST_GOPATH is not an empty string:
455# - create GOPATH within WORKSPACE, and destination directory within
456# - set PATH to include $GOPATH/bin and the system go binaries
457# - move project from $WORKSPACE/$GERRIT_PROJECT to new location in $GOPATH
458# - start release process within that directory
459## -----------------------------------------------------------------------
460function get_release_path()
461{
462 declare -n varname=$1; shift
463
464 DEST_GOPATH=${DEST_GOPATH:-}
465 if [ -n "$DEST_GOPATH" ]; then
Joey Armstrong76026b72023-03-29 12:19:17 -0400466 # if [[ -v DEST_GOPATH ]] && [[ -n DEST_GOPATH ]]; then
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400467 ## [jenkins] Suspect this will taint the golang installation.
468 ## [jenkins] Install succeeds, release fails, next job affected due to corruption.
469 ## [jenkins] Copy golang to temp then augment ?
470 ## [jenkins] Worst case (problematic) backup then restore
471 mkdir -p "$GOPATH/src/$DEST_GOPATH"
472 varname="$GOPATH/src/$DEST_GOPATH/$GERRIT_PROJECT"
473 mv "$WORKSPACE/$GERRIT_PROJECT" "$varname"
474
475 ## [TODO] - support local dev use
476 # elif [[ ! -v WORKSPACE ]] && [[ -d '.git' ]]; then
477 # project=$(git remote -v show | awk -F' ' '{print $2}' | xargs basename)
478 # project=voltctl.git
479
480 else
481 varname="$WORKSPACE/$GERRIT_PROJECT"
482 fi
483
484 if [ ! -f "$varname/Makefile" ]; then
485 :
486 elif [ ! -f "$varname/makefile" ]; then
487 :
488 else
489 error "Makefile not found at $varname!"
490 fi
491
492 return
493}
494
495## -----------------------------------------------------------------------
496## Intent: Display future enhancements
497## -----------------------------------------------------------------------
498function todo()
499{
500 local iam="${0##*/}"
501
502cat <<EOT
503
504** -----------------------------------------------------------------------
505** IAM: ${iam} :: ${FUNCNAME[0]}
506** -----------------------------------------------------------------------
507 o get_release_path()
508 - refactor redundant paths into local vars.
509 - see comments, do we have a one-off failure condition ?
Joey Armstrongad7b1e02023-03-27 11:55:48 -0400510 o PATH += golang appended 3 times, release needs a single, reliable answer.
511 o do_login, do_logout and api calls do not use the my_gh wrapper:
512 - Add a lookup function to cache and retrieve path to downloaded gh command.
Joey Armstrong76026b72023-03-29 12:19:17 -0400513
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400514EOT
515
516 return
517}
518
519## -----------------------------------------------------------------------
Joey Armstrong76026b72023-03-29 12:19:17 -0400520## Intent: Verify a directory contains content for release.
521## -----------------------------------------------------------------------
522## Given:
523## scalar Path to release/ directory
524## ref Results returned through this indirect var.
525## -----------------------------------------------------------------------
526## Usage:
527## declare -a artifacts=()
528## get_artifacts '/foo/bar/tans' artifacts
529## declare -p artifacts
530## -----------------------------------------------------------------------
531function get_artifacts()
532{
533 local dir="$1" ; shift
534 declare -n ref=$1 ; shift
535
536 # Glob available files
537 readarray -t __artifacts < <(find "$dir" -mindepth 1 ! -type d)
538 func_echo "$(declare -p __artifacts)"
539
540 # -----------------------------------------------------------------------
541 # Verify count>0 to inhibit source-only release
542 # Problem children:
543 # o build or make release failures.
544 # o docker container filesystem mount problem (~volume)
545 # -----------------------------------------------------------------------
546 [[ ${#__artifacts[@]} -eq 0 ]] \
547 && error "Artifact dir is empty: $(declare -p dir)"
548
549 ref=("${__artifacts[@]}")
550 return
551}
552
553## -----------------------------------------------------------------------
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400554## Intent: Copy files from the build directory into the release staging
555## directory for publishing to github releases/ endpoint.
Joey Armstrong26707f02023-01-26 12:41:12 -0500556## -----------------------------------------------------------------------
557function copyToRelease()
558{
Joey Armstrong76026b72023-03-29 12:19:17 -0400559 banner ''
Joey Armstrong26707f02023-01-26 12:41:12 -0500560
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400561 local artifact_glob="${ARTIFACT_GLOB%/*}"
562 func_echo "$(declare -p artifact_glob)"
563
564 local work
565 get_release_dir work
Joey Armstrong76026b72023-03-29 12:19:17 -0400566 func_echo "Artifact dir: $(declare -p work)"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400567
Joey Armstrong76026b72023-03-29 12:19:17 -0400568 ## Verify release content is available
569 declare -a artifacts=()
570 get_artifacts "$work" artifacts
Joey Armstrong472bfba2023-03-27 18:12:28 -0400571
Joey Armstrong26707f02023-01-26 12:41:12 -0500572 # Copy artifacts into the release temp dir
573 # shellcheck disable=SC2086
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400574 echo "rsync -rv --checksum \"$artifact_glob/.\" \"$work/.\""
575 rsync -rv --checksum "$artifact_glob/." "$work/."
Joey Armstrong1962bcf2023-01-27 13:53:18 -0500576
Joey Armstrong26707f02023-01-26 12:41:12 -0500577 return
578}
579
580## -----------------------------------------------------------------------
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400581## https://docs.github.com/en/rest/releases?apiVersion=2022-11-28
582 # https://cli.github.com/manual/gh_release_create
583 # --target <branch> or commit SHA
584 # --title
585 # --generate-notes
586 # --release-notes (notes file)
587 # --release
588 # release create dist/*.tgz
589 # --discussion-category "General"
Joey Armstrongf085d872023-01-28 17:52:29 -0500590## -----------------------------------------------------------------------
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400591# https://cli.github.com/manual/gh_release_create
592## -----------------------------------------------------------------------
593function gh_release_create()
Joey Armstrong38bfeea2023-02-06 18:01:29 -0500594{
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400595 banner ''
Joey Armstrong38bfeea2023-02-06 18:01:29 -0500596
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400597 local version="$GIT_VERSION"
598# get_version 'version'
599# create_release_by_version "$version"
Joey Armstrong38bfeea2023-02-06 18:01:29 -0500600
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400601 declare -a args=()
602 args+=('--host-repo')
603 args+=('--notes' "'Testing release create -- ignore'")
604 args+=('--title')
605 if [[ -v draft_release ]]; then
606 args+=('--draft')
607 else
608 args+=('--discussion-category' 'Announcements')
609 fi
Joey Armstrong38bfeea2023-02-06 18:01:29 -0500610
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400611 local work
612 get_release_dir work
613
Joey Armstrong76026b72023-03-29 12:19:17 -0400614 pushd "$work" >/dev/null
615 readarray -t payload < <(find '.' ! -type d -print)
616
Joey Armstrongad7b1e02023-03-27 11:55:48 -0400617 func_echo "$gh_cmd release create ${version} ${args[@]}" "${payload[@]}"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400618 my_gh 'release' 'create' "'$version'" "${args[@]}" "${payload[@]}"
Joey Armstrong76026b72023-03-29 12:19:17 -0400619 popd >/dev/null
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400620
Joey Armstrong38bfeea2023-02-06 18:01:29 -0500621 return
622}
623
624## -----------------------------------------------------------------------
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400625## Intent: Authenticate credentials for a github gh session
Joey Armstrong38bfeea2023-02-06 18:01:29 -0500626## -----------------------------------------------------------------------
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400627## NOTE: my_gh currently unused due to --with-token < "$pac"
628## -----------------------------------------------------------------------
629function do_login()
Joey Armstrongf085d872023-01-28 17:52:29 -0500630{
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400631 declare -g pac
Joey Armstrong485081f2023-03-27 13:34:08 -0400632 declare -a login_args=()
633 [[ $# -gt 0 ]] && login_args+=("$@")
Joey Armstrongf085d872023-01-28 17:52:29 -0500634
Joey Armstronge6e18eb2023-03-27 14:19:21 -0400635 func_echo "$(declare -p WORKSPACE)"
636
Joey Armstrong485081f2023-03-27 13:34:08 -0400637 # https://github.com/cli/cli/issues/2922#issuecomment-775027762
Joey Armstrong75a0d932023-03-28 08:59:54 -0400638 # (sigh) why not quietly return VS forcing a special logic path
Joey Armstronge6e18eb2023-03-27 14:19:21 -0400639 # [[ -v WORKSPACE ]] && [[ -v GITHUB_TOKEN ]] && return
640
641# 12:58:36 ** -----------------------------------------------------------------------
642# 12:58:36 ** jenkins582353203049151829.sh::do_login: --hostname github.com
643# 12:58:36 ** --------------------------------------------------------------------# ---
644# 12:58:36 ** jenkins582353203049151829.sh :: do_login: Detected ENV{GITHUB_TOKEN}=
645# 12:58:36 The value of the GITHUB_TOKEN environment variable is being used for authentication.
646# 12:58:36 To have GitHub CLI store credentials instead, first clear the value from the environment.
647 return
Joey Armstrong76026b72023-03-29 12:19:17 -0400648
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400649 # bridge to my_gh()
Joey Armstrong485081f2023-03-27 13:34:08 -0400650 get_gh_hostname login_args
Joey Armstrongf085d872023-01-28 17:52:29 -0500651
Joey Armstrong485081f2023-03-27 13:34:08 -0400652 banner "${login_args[@]}"
Joey Armstrongf085d872023-01-28 17:52:29 -0500653
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400654 ## Read from disk is safer than export GITHUB_TOKEN=
655 if [[ -v pac ]] && [[ ${#pac} -gt 0 ]]; then # interactive/debugging
656 [ ! -f "$pac" ] && error "PAC token file $pac does not exist"
657 # func_echo "--token file is $pac"
Joey Armstrong485081f2023-03-27 13:34:08 -0400658 "$gh_cmd" auth login "${login_args[@]}" --with-token < "$pac"
Joey Armstrongf085d872023-01-28 17:52:29 -0500659
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400660 elif [[ ! -v GITHUB_TOKEN ]]; then
661 error "--token [t] or GITHUB_TOKEN= are required"
Joey Armstrong41923cc2023-01-30 14:38:16 -0500662
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400663 else # jenkins
664 func_echo 'Detected ENV{GITHUB_TOKEN}='
Joey Armstrong485081f2023-03-27 13:34:08 -0400665 "$gh_cmd" auth login "${login_args[@]}"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400666 fi
Joey Armstrongf085d872023-01-28 17:52:29 -0500667
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400668 declare -i -g active_login=1 # signal logout
Joey Armstrongf085d872023-01-28 17:52:29 -0500669
Joey Armstrongf085d872023-01-28 17:52:29 -0500670 return
671}
672
673## -----------------------------------------------------------------------
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400674## Intent: Destroy credentials/gh session authenticated by do_login
675## -----------------------------------------------------------------------
676## NOTE: my_gh currently unused due to "<<< 'y'"
677## -----------------------------------------------------------------------
678function do_logout()
679{
680 declare -i -g active_login
681 [[ ! -v active_login ]] && return
682
683 declare -a out_args=()
684 [[ $# -gt 0 ]] && out_args+=("$@")
685
686 # bridge to my_gh()
687
688 get_gh_hostname in_args
689
690 banner "${out_args[@]}"
Joey Armstrongad7b1e02023-03-27 11:55:48 -0400691 "$gh_cmd" auth logout "${out_args[@]}" <<< 'Y'
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400692
693 unset active_login
694 return
695}
696
697## -----------------------------------------------------------------------
698## Intent: Query for repository version strings
699## -----------------------------------------------------------------------
700function get_releases()
701{
702 declare -n ref="$1"; shift
703 local func="${FUNCNAME[0]}"
704
705 banner ""
706 pushd "$scratch" >/dev/null
Joey Armstrong76026b72023-03-29 12:19:17 -0400707
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400708 # gh api repos/{owner}/{repo}/releases
709 local releases_uri
710 get_gh_releases releases_uri
711 declare -p releases_uri
Joey Armstrong76026b72023-03-29 12:19:17 -0400712
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400713 ref=()
Joey Armstrongad7b1e02023-03-27 11:55:48 -0400714 "$gh_cmd" api "$releases_uri" "${common[@]}" | jq . > 'release.raw'
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400715 readarray -t __tmp < <(jq '.[] | "\(.tag_name)"' 'release.raw')
716
717 local release
718 for release in "${__tmp[@]}";
719 do
720 release="${release//\"/}"
721 ref+=("$release")
722 done
723
724 popd >/dev/null
725 return
726}
727
728## -----------------------------------------------------------------------
729## Intent: Display repository query strings.
730## Indirect: verify authentication and API
731## -----------------------------------------------------------------------
732function showReleases()
733{
734 declare -a releases=()
735 get_releases releases
736
737 local release
738 for release in "${releases[@]}";
739 do
740 func_echo "$release"
741 done
742 return
743}
744
745## -----------------------------------------------------------------------
746## Intent: Install the gh command line tool locally
Joey Armstrong26707f02023-01-26 12:41:12 -0500747## -----------------------------------------------------------------------
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500748function install_gh_binary()
Joey Armstrong26707f02023-01-26 12:41:12 -0500749{
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400750 banner
Joey Armstrong26707f02023-01-26 12:41:12 -0500751
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500752 pushd "$scratch"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400753 func_echo "Retrieve latest gh download URLs"
Joey Armstrongf085d872023-01-28 17:52:29 -0500754
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500755 local latest="https://github.com/cli/cli/releases/latest"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400756 local tarball="gh.tar.tgz"
757
Joey Armstrong76026b72023-03-29 12:19:17 -0400758 readarray -t latest < <(\
759 curl --silent -qI "$latest" \
760 | awk -F '/' '/^location/ {print substr($NF, 1, length($NF)-1)}')
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400761 declare -p latest
762 if [ ${#latest[@]} -ne 1 ]; then
763 error "Unable to determine latest gh package version"
764 fi
Joey Armstrong76026b72023-03-29 12:19:17 -0400765
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400766 local VER="${latest[0]}"
767
768 func_echo "Download latest gh binary"
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500769 local url="https://github.com/cli/cli/releases/download/${VER}/gh_${VER#v}_linux_amd64.tar.gz"
770 wget --quiet --output-document="$tarball" "$url"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400771
772 func_echo "Unpack tarball"
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500773 tar zxf "$tarball"
774
775 gh_cmd="$(find "${scratch}" -name 'gh' -print)"
776 readonly gh_cmd
777
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400778 func_echo "Command: ${gh_cmd}"
779 func_echo "Version: $("$gh_cmd" --version)"
Joey Armstrongd99e3d22023-01-29 12:35:43 -0500780 popd
781
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400782 return
783}
784
785## -----------------------------------------------------------------------
786## Intent: Danger Will Robinson
787## -----------------------------------------------------------------------
788function releaseDelete()
789{
790 local version="$1"; shift
Joey Armstrong76026b72023-03-29 12:19:17 -0400791
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400792 banner "${in_args[@]}"
793 declare -a args=()
794 args+=('--host-repo')
795 args+=('--yes')
796 # args+=('--cleanup-tag')
797
798# ** github-release.sh :: get_argv_repo: VARNAME=opencord/voltctl
799#* Running: /tmp/github-release.R7geZo7Ywo/gh_2.25.1_linux_amd64/bin/gh release delete v4.175.710 --repo 'github.com/opencord/voltctl' --yes --cleanup-tag
800#rror connecting to 'github.com
801#heck your internet connection or https://githubstatus.com
802
803 echo
804 echo "==========================================================================="
805 my_gh 'release' 'delete' "$version" "${args[@]}"
806 echo "==========================================================================="
807 echo
808
809 showReleases
810 return
811}
812
813## -----------------------------------------------------------------------
814## Intent: Copy binaries into temp/release, checksum then publish
815## -----------------------------------------------------------------------
816function release_staging()
817{
818 local release_temp
819 get_release_dir release_temp
820
821 banner ''
822 func_echo "Packaging release files"
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400823
Joey Armstrong76026b72023-03-29 12:19:17 -0400824 pushd "$release_temp" >/dev/null \
825 || error "pushd failed: dir is [$release_temp]"
826
827 declare -a to_release=()
828 get_artifacts '.' to_release
829
830# readarray -t to_release < <(find . -mindepth 1 -maxdepth 1 -type f -print)
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400831 func_echo "Files to release: $(declare -p to_release)"
832
833 # Generate and check checksums
834 sha256sum -- * > checksum.SHA256
835 sha256sum -c < checksum.SHA256
836
837 echo
838 func_echo "Checksums(checksum.SHA256):"
839 cat checksum.SHA256
840
Joey Armstrong76026b72023-03-29 12:19:17 -0400841 gh_release_create # publish
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400842
843 popd >/dev/null || error "pushd failed: dir is [$release_temp]"
844
845 return
846}
847
848## -----------------------------------------------------------------------
849## Intent: Display program usage
850## -----------------------------------------------------------------------
851function usage()
852{
853 [[ $# -gt 0 ]] && func_echo "$*"
854
855 cat <<EOH
856Usage: github-release.sh [options] [target] ...
857
858[Github CLI (gh) arguments]
859 --login Perform authentication using a PAC
860 --logout
861 --host [h] Specify github server for connection.
862
863[Options]
864 --token Login debugging, alternative to env var use.
865
866[Modes]
867 --debug Enable script debug mode
868 --verbose Enable script verbose mode
869
870All remaining arguments are passthrough to the gh command.
871EOH
872
873 exit 0
874}
875
876## -----------------------------------------------------------------------
877## Intent: Provide common arguments and access to the gh command.
878## o Cache path to the gh command
879## o Construct a gh command line from given args
880## o Command wrapper can provide defaults (--hostname github.com)
881## -----------------------------------------------------------------------
882## Given:
883## scalar Array variable name (declare -n is a reference)
884## Return:
885## ref gh command line passed back to caller
886## Switches:
887## --host Pass default github hostname
888## --verbose Enable verbose mode#
889## --version Display command version
890## @array Remaining arguments passed as command switches.
891## -----------------------------------------------------------------------
892## See Also:
893## o https://cli.github.com/manual
894## -----------------------------------------------------------------------
895function my_gh()
896{
897 ## ------------------------
898 ## Cache path to gh command
899 ## ------------------------
900 if [[ ! -v gh_cmd ]]; then
901 readarray -t cmds < <(which -a gh)
902 declare -p cmds
903 if [ ${#cmds} -eq 0 ]; then
904 error "Unable to locate the gh command"
905 fi
906 gh_cmd="${cmds[0]}"
907 readonly gh_cmd
908 fi
909
910 declare -a cmd=()
911 cmd+=("$gh_cmd")
912
913 ## ----------------------
914 ## Construct command line
915 ## ----------------------
916 # shellcheck disable=SC2034
917 declare -A action=() # pending operations
918 declare -a args=() # common gh command line args
919
920 while [ $# -gt 0 ]; do
921 local arg="$1"; shift
922 case "$arg" in
923
924 # Modes
925 -*debug) declare -i -g debug=1 ;;
926 -*help) show_help ;;
927 -*verbose) args+=('--verbose') ;;
928
929 -*hostname)
930 get_gh_hostname in_args
931 ;;
932
933 --host-repo)
934 local val
935 get_argv_repo val
Joey Armstrong76026b72023-03-29 12:19:17 -0400936
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400937 # --repo <[HOST/]OWNER/REPO>
938 args+=('--repo' "'${__githost}/${val}'")
939 ;;
Joey Armstrong76026b72023-03-29 12:19:17 -0400940
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400941 --repo)
942 local val
943 get_argv_repo val
944 args+=('--repo' "$val")
945 ;;
946
947 --tag)
948 local val
949 get_argv_tag val
950 args+=("'$val'") # No switch, pass inline
951 ;;
952
953 --title)
954 local val
955 get_argv_name val
956 args+=('--title' "'$val'")
957 ;;
Joey Armstrong76026b72023-03-29 12:19:17 -0400958
959 --draft) declare -i -g draft_release=1 ;;
960
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400961 # --draft
962 # --latest
963 *) args+=("$arg") ;;
964 esac
965 done
Joey Armstrong76026b72023-03-29 12:19:17 -0400966
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400967 cmd+=("${args[@]}")
968 echo "** Running: ${cmd[*]}"
969 "${cmd[@]}"
970 local status=$?
971
972 [[ $status -eq 0 ]] && { true; } || { false; }
973 return
974}
975
976## ---------------------------------------------------------------------------
977## Intent:
978## ---------------------------------------------------------------------------
979function usage()
980{
981 cat <<EOH
Joey Armstrong76026b72023-03-29 12:19:17 -0400982
Joey Armstrong2097d3e2023-03-26 10:32:03 -0400983Usage: $0
984Usage: make [options] [target] ...
985 --help This mesage
986 --pac Personal Access Token (file)
987
988[DEBUG]
989 --gen-version Generate a random release version string.
990 --git-hostname Git server hostname (default=github.com)
991
992EOH
993 return
994}
995
996## ---------------------------------------------------------------------------
997## Intent: Parse script command line arguments
998## ---------------------------------------------------------------------------
999function parse_args()
1000{
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001001 [[ -v DEBUG ]] && func_echo "ENTER"
1002
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001003 while [ $# -gt 0 ]; do
1004 local arg="$1"; shift
1005 case "$arg" in
1006 -*gen-version)
1007 get_version GIT_VERSION
1008 ;;
1009
1010 -*git-hostname)
1011 __githost="$1"; shift
1012 ;;
1013
1014 -*repo-name)
1015 __repo_name="$1"; shift
1016 ;;
1017
1018 -*repo-org)
1019 __repo_org="$1"; shift
1020 ;;
1021
1022 -*pac)
1023 declare -g pac="$1"; shift
1024 readonly pac
1025 [[ ! -f "$pac" ]] && error "--token= does not exist ($pac)"
1026 : # nop/true
1027 ;;
1028
1029 -*help)
1030 usage
1031 exit 0
1032 ;;
1033 *) error "Detected unknown argument $arg" ;;
1034 esac
1035 done
1036
Joey Armstrong26707f02023-01-26 12:41:12 -05001037 return
1038}
1039
Joey Armstrongaf577ab2022-12-15 14:43:33 -05001040##----------------##
1041##---] MAIN [---##
1042##----------------##
Joey Armstrong1962bcf2023-01-27 13:53:18 -05001043iam="${0##*/}"
1044
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001045full_banner
1046parse_args $@
Joey Armstrongd99e3d22023-01-29 12:35:43 -05001047init
1048install_gh_binary
Joey Armstrong7f382ef2023-01-25 12:00:08 -05001049
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001050do_login
Zack Williams27cd3e52018-09-18 16:44:50 -07001051
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001052release_path='/dev/null'
1053get_release_path release_path
1054declare -p release_path
Zack Williams27cd3e52018-09-18 16:44:50 -07001055
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001056pushd "$release_path" || error "pushd failed: dir is [$release_path]"
Zack Williams27cd3e52018-09-18 16:44:50 -07001057
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001058 # legacy: getGitVersion "$GERRIT_PROJECT" GIT_VERSION
1059 getGitVersion GIT_VERSION
1060 getReleaseDescription RELEASE_DESCRIPTION
Zack Williams27cd3e52018-09-18 16:44:50 -07001061
Joey Armstrongeef8c2c2023-03-27 17:27:43 -04001062 cat <<EOM
1063
1064** -----------------------------------------------------------------------
1065** GIT VERSION: $(declare -p GIT_VERSION)
1066** RELEASE_DESCRIPTION: $(declare -p RELEASE_DESCRIPTION)
1067** RELEASE_TARGETS: $(declare -p RELEASE_TARGETS)
1068** make release
1069** -----------------------------------------------------------------------
1070EOM
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001071 # build the release, can be multiple space separated targets
1072 # -----------------------------------------------------------------------
1073 # % go build command-line-arguments:
1074 # copying /tmp/go-build4212845548/b001/exe/a.out:
1075 # open release/voltctl-1.8.25-linux-amd64: permission denied
1076 # missing: docker run mkdir
1077 # -----------------------------------------------------------------------
1078 # shellcheck disable=SC2086
Joey Armstrongeef8c2c2023-03-27 17:27:43 -04001079 make "$RELEASE_TARGETS"
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001080 copyToRelease
Joey Armstrong50f6e0b2023-01-24 14:14:08 -05001081
Joey Armstrong26707f02023-01-26 12:41:12 -05001082 cat <<EOM
Joey Armstrong1962bcf2023-01-27 13:53:18 -05001083
1084** -----------------------------------------------------------------------
1085** Create the release:
1086** 1) Create initial github release with download area.
1087** 2) Generate checksum.SHA256 for all released files.
1088** 3) Upload files to complete the release.
Joey Armstrong75a0d932023-03-28 08:59:54 -04001089** 4) Display released info from github
Joey Armstrong1962bcf2023-01-27 13:53:18 -05001090** -----------------------------------------------------------------------
Joey Armstrong26707f02023-01-26 12:41:12 -05001091EOM
1092
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001093 showReleases
1094 # releaseDelete 'v4.175.710'
1095 release_staging
1096 popd || error "pushd failed: dir is [$release_path]"
Zack Williams27cd3e52018-09-18 16:44:50 -07001097fi
Joey Armstrong28eddda2023-01-10 03:09:34 -05001098
Joey Armstrong2097d3e2023-03-26 10:32:03 -04001099do_logout
1100
Joey Armstrong28eddda2023-01-10 03:09:34 -05001101# [SEE ALSO]
1102# -----------------------------------------------------------------------
1103# https://www.shellcheck.net/wiki/SC2236
Joey Armstrong26707f02023-01-26 12:41:12 -05001104# https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#create-a-release
Joey Armstrong28eddda2023-01-10 03:09:34 -05001105# -----------------------------------------------------------------------
Joey Armstrongf085d872023-01-28 17:52:29 -05001106# https://cli.github.com/manual/gh_help_reference
1107# https://cli.github.com/manual/gh_release
1108# -----------------------------------------------------------------------
Joey Armstrong28eddda2023-01-10 03:09:34 -05001109
1110# [EOF]