recreateRelease.sh
1 #!/usr/bin/env bash 2 set -euo pipefail 3 4 usage() { 5 cat <<'USAGE' 6 Usage: 7 recreateLatestRelease.sh \ 8 --gitlab-host https://gitlab.example.com \ 9 --project-id 123 \ 10 --token <YOUR_TOKEN> \ 11 --tag-ref master \ 12 [--release-tag latest] \ 13 [--release-name latest] \ 14 [--release-description "Automated latest release"] 15 16 What it does: 17 1) Deletes the release for --release-tag (if it exists) 18 2) Deletes the tag named --release-tag (if it exists) 19 3) Creates a new tag --release-tag from --tag-ref 20 4) Creates a new release attached to that tag 21 22 Notes: 23 - A GitLab release is always attached to a git tag. 24 - --project-id can be numeric ID or URL-encoded path (e.g. group%2Fproject). 25 - Token should have permissions to manage releases + tags (typically PAT with api scope). 26 USAGE 27 } 28 29 need() { command -v "$1" >/dev/null 2>&1 || { echo "Missing dependency: $1" >&2; exit 1; }; } 30 31 # --- Parse args --- 32 GITLAB_HOST="" 33 PROJECT_ID="" 34 TOKEN="" 35 TAG_REF="" 36 RELEASE_TAG="latest" 37 RELEASE_NAME="latest" 38 RELEASE_DESCRIPTION="Automated latest release created by CI." 39 40 while [[ $# -gt 0 ]]; do 41 case "$1" in 42 --gitlab-host) GITLAB_HOST="${2:-}"; shift 2 ;; 43 --project-id) PROJECT_ID="${2:-}"; shift 2 ;; 44 --token) TOKEN="${2:-}"; shift 2 ;; 45 --tag-ref) TAG_REF="${2:-}"; shift 2 ;; 46 --release-tag) RELEASE_TAG="${2:-}"; shift 2 ;; 47 --release-name) RELEASE_NAME="${2:-}"; shift 2 ;; 48 --release-description) RELEASE_DESCRIPTION="${2:-}"; shift 2 ;; 49 -h|--help) usage; exit 0 ;; 50 *) echo "Unknown argument: $1" >&2; usage; exit 2 ;; 51 esac 52 done 53 54 # --- Validate --- 55 [[ -n "$GITLAB_HOST" ]] || { echo "Missing --gitlab-host" >&2; usage; exit 2; } 56 [[ -n "$PROJECT_ID" ]] || { echo "Missing --project-id" >&2; usage; exit 2; } 57 [[ -n "$TOKEN" ]] || { echo "Missing --token" >&2; usage; exit 2; } 58 [[ -n "$TAG_REF" ]] || { echo "Missing --tag-ref" >&2; usage; exit 2; } 59 60 need curl 61 need jq 62 63 api_base="${GITLAB_HOST%/}/api/v4" 64 encoded_tag="$(jq -rn --arg s "$RELEASE_TAG" '$s|@uri')" 65 66 echo "GitLab host: ${GITLAB_HOST%/}" 67 echo "Project ID: ${PROJECT_ID}" 68 echo "Release/tag name: ${RELEASE_TAG}" 69 echo "Tag ref: ${TAG_REF}" 70 echo "Release name: ${RELEASE_NAME}" 71 echo "Release desc: ${RELEASE_DESCRIPTION}" 72 echo 73 74 # --- Delete existing release (ignore if missing) --- 75 echo "Deleting existing release '${RELEASE_TAG}' (if it exists)..." 76 release_get_code="$( 77 curl --insecure -sS -o /dev/null -w "%{http_code}" \ 78 --header "PRIVATE-TOKEN: ${TOKEN}" \ 79 "${api_base}/projects/${PROJECT_ID}/releases/${encoded_tag}" 80 )" 81 82 if [[ "$release_get_code" == "200" ]]; then 83 curl --insecure -fsS -X DELETE \ 84 --header "PRIVATE-TOKEN: ${TOKEN}" \ 85 "${api_base}/projects/${PROJECT_ID}/releases/${encoded_tag}" \ 86 >/dev/null 87 echo "Release deleted." 88 elif [[ "$release_get_code" == "404" ]]; then 89 echo "Release not found; nothing to delete." 90 else 91 echo "ERROR: Unable to check release '${RELEASE_TAG}'. HTTP status: ${release_get_code}" >&2 92 exit 1 93 fi 94 95 echo 96 97 # --- Delete existing tag (ignore if missing) --- 98 echo "Deleting existing tag '${RELEASE_TAG}' (if it exists)..." 99 tag_get_code="$( 100 curl --insecure -sS -o /dev/null -w "%{http_code}" \ 101 --header "PRIVATE-TOKEN: ${TOKEN}" \ 102 "${api_base}/projects/${PROJECT_ID}/repository/tags/${encoded_tag}" 103 )" 104 105 if [[ "$tag_get_code" == "200" ]]; then 106 curl --insecure -fsS -X DELETE \ 107 --header "PRIVATE-TOKEN: ${TOKEN}" \ 108 "${api_base}/projects/${PROJECT_ID}/repository/tags/${encoded_tag}" \ 109 >/dev/null 110 echo "Tag deleted." 111 elif [[ "$tag_get_code" == "404" ]]; then 112 echo "Tag not found; nothing to delete." 113 else 114 echo "ERROR: Unable to check tag '${RELEASE_TAG}'. HTTP status: ${tag_get_code}" >&2 115 exit 1 116 fi 117 118 echo 119 120 # --- Create tag --- 121 echo "Creating tag '${RELEASE_TAG}' from ref '${TAG_REF}'..." 122 create_tag_code="$( 123 curl --insecure -sS -o /dev/null -w "%{http_code}" -X POST \ 124 --header "PRIVATE-TOKEN: ${TOKEN}" \ 125 --data-urlencode "tag_name=${RELEASE_TAG}" \ 126 --data-urlencode "ref=${TAG_REF}" \ 127 "${api_base}/projects/${PROJECT_ID}/repository/tags" 128 )" 129 130 if [[ "$create_tag_code" != "201" ]]; then 131 echo "ERROR: Failed to create tag '${RELEASE_TAG}'. HTTP status: ${create_tag_code}" >&2 132 exit 1 133 fi 134 echo "Tag created." 135 echo 136 137 # --- Create release --- 138 echo "Creating release '${RELEASE_TAG}'..." 139 create_release_code="$( 140 curl --insecure -sS -o /dev/null -w "%{http_code}" -X POST \ 141 --header "PRIVATE-TOKEN: ${TOKEN}" \ 142 --data-urlencode "name=${RELEASE_NAME}" \ 143 --data-urlencode "tag_name=${RELEASE_TAG}" \ 144 --data-urlencode "description=${RELEASE_DESCRIPTION}" \ 145 "${api_base}/projects/${PROJECT_ID}/releases" 146 )" 147 148 if [[ "$create_release_code" != "201" ]]; then 149 echo "ERROR: Failed to create release '${RELEASE_TAG}'. HTTP status: ${create_release_code}" >&2 150 exit 1 151 fi 152 153 echo "Release created."