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