1+ #! /bin/bash
2+
3+ #
4+ # Licensed to the Apache Software Foundation (ASF) under one
5+ # or more contributor license agreements. See the NOTICE file
6+ # distributed with this work for additional information
7+ # regarding copyright ownership. The ASF licenses this file
8+ # to you under the Apache License, Version 2.0 (the
9+ # "License"); you may not use this file except in compliance
10+ # with the License. You may obtain a copy of the License at
11+ #
12+ # https://www.apache.org/licenses/LICENSE-2.0
13+ #
14+ # Unless required by applicable law or agreed to in writing,
15+ # software distributed under the License is distributed on an
16+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+ # KIND, either express or implied. See the License for the
18+ # specific language governing permissions and limitations
19+ # under the License.
20+ #
21+
22+ # ./releaseJarFiles.sh <staging repo description> <username> <password>
23+
24+ set -euo pipefail
25+
26+ if [[ $# -ne 3 ]]; then
27+ echo " Usage: $0 <staging repo description> <username> <password>" >&2
28+ exit 1
29+ fi
30+
31+ NEXUS_URL=" https://repository.apache.org"
32+ STAGING_DESCRIPTION=" $1 "
33+ NEXUS_USER=" $2 "
34+ NEXUS_PASS=" $3 "
35+
36+ if [[ -z " ${STAGING_DESCRIPTION} " ]]; then
37+ echo " ERROR: Staging Description must not be empty." >&2
38+ exit 1
39+ fi
40+ if [[ -z " ${NEXUS_USER} " ]]; then
41+ echo " ERROR: Username must not be empty." >&2
42+ exit 1
43+ fi
44+ if [[ -z " ${NEXUS_PASS} " ]]; then
45+ echo " ERROR: Password must not be empty." >&2
46+ exit 1
47+ fi
48+
49+ nexusApi () {
50+ local request_method=" $1 " ; shift
51+ local path=" $1 " ; shift
52+ curl -fsS -u " ${NEXUS_USER} :${NEXUS_PASS} " \
53+ -H ' Accept: application/json' \
54+ -H ' Content-Type: application/json' \
55+ -X " ${request_method} " " ${NEXUS_URL} /service/local/${path} " " $@ "
56+ }
57+
58+ wait_for_promotion () {
59+ local repoId=" $1 "
60+ local timeout_s=" ${2:- 600} " # default 10 minutes
61+ local interval_s=" ${3:- 3} "
62+ local started
63+ started=" $( date +%s) "
64+
65+ echo " Waiting for release promotion to complete (timeout ${timeout_s} s)…"
66+
67+ while : ; do
68+ # 1) If any ERROR appears in activity, fail fast
69+ act=" $( nexusApi GET " /staging/repository/${repoId} /activity" || true) "
70+ if [[ -n " $act " ]]; then
71+ err_count=" $( jq -r ' [.. | objects? | select(has("severity")) | select(.severity=="ERROR")] | length' <<< " $act" 2> /dev/null || echo 0) "
72+ if [[ " $err_count " != " 0" ]]; then
73+ echo " ERROR: Staging activity contains failure(s). Aborting." >&2
74+ # Optionally dump recent relevant lines:
75+ jq -r ' .. | objects? | select(has("severity")) | "\(.severity): \(.name // "event") - \(.message // "")"' <<< " $act" || true
76+ return 1
77+ fi
78+ fi
79+
80+ # 2) Check transitioning flag — when false after promote, action is done
81+ trans=" $( nexusApi GET ' /staging/profile_repositories' \
82+ | jq -r --arg r " $repoId " ' .data[]? | select(.repositoryId==$r) | .transitioning' 2> /dev/null || echo " true" ) "
83+
84+ if [[ " $trans " == " false" ]]; then
85+ # sanity: make sure we actually saw some "release/promote" activity; otherwise keep waiting a bit
86+ if [[ -n " $act " ]]; then
87+ # did we see any promote/release-ish step?
88+ saw_promote=" $( jq -r '
89+ [ .. | objects? | .name? // empty | ascii_downcase
90+ | select(test("release|promote|finish")) ] | length' <<< " $act" 2> /dev/null || echo 0) "
91+ if [[ " $saw_promote " -gt 0 ]]; then
92+ echo " Promotion appears complete."
93+ return 0
94+ fi
95+ fi
96+ fi
97+
98+ # timeout?
99+ now=" $( date +%s) "
100+ if (( now - started >= timeout_s )) ; then
101+ echo " ERROR: Timed out waiting for promotion to complete." >&2
102+ # Show a short summary to aid debugging
103+ if [[ -n " $act " ]]; then
104+ echo " --- Recent activity snapshot ---"
105+ jq -r ' .. | objects? | select(has("severity") or has("name")) | "\(.severity // "")\t\(.name // "")\t\(.message // "")"' <<< " $act" | tail -n 20 || true
106+ fi
107+ return 1
108+ fi
109+
110+ sleep " $interval_s "
111+ done
112+ }
113+
114+ repos_json=" $( nexusApi GET ' /staging/profile_repositories' ) "
115+ repoId=" $( jq -r --arg d " ${STAGING_DESCRIPTION} " ' .data[] | select(.description==$d) | .repositoryId' <<< " ${repos_json}" ) "
116+ profileId=" $( jq -r --arg d " ${STAGING_DESCRIPTION} " ' .data[] | select(.description==$d) | .profileId' <<< " ${repos_json}" ) "
117+ state=" $( jq -r --arg d " ${STAGING_DESCRIPTION} " ' .data[] | select(.description==$d) | .type' <<< " ${repos_json}" ) "
118+
119+ if [[ -z " ${repoId} " || -z " ${profileId} " ]]; then
120+ echo " ERROR: No staged repository found with description: ${STAGING_DESCRIPTION} " >&2
121+ exit 2
122+ fi
123+ echo " Found staged repo: ${repoId} (profile: ${profileId} , state: ${state} )"
124+ if [[ " ${state} " == " open" ]]; then
125+ echo " ERROR: Staged Repo is not closed: ${STAGING_DESCRIPTION} " >&2
126+ exit 3
127+ fi
128+
129+ if [[ " ${state} " == " closed" ]]; then
130+ echo " Promoting (release) ${repoId} …"
131+ nexusApi POST " /staging/profiles/${profileId} /promote" \
132+ --data " $( jq -n --arg r " ${repoId} " --arg d " ${STAGING_DESCRIPTION} " ' {data:{stagedRepositoryId:$r,description:$d}}' ) "
133+ fi
134+
135+ wait_for_promotion " $repoId " 600 3
136+
137+ echo " Dropping staging repository ${repoId} …"
138+ nexusApi POST " /staging/profiles/${profileId} /drop" \
139+ --data " $( jq -n --arg r " $repoId " --arg d " ${STAGING_DESCRIPTION} " ' {data:{stagedRepositoryId:$r,description:$d}}' ) "
140+
141+ echo " Done. Released ${repoId} ."
0 commit comments