Skip to content

Commit d82cc45

Browse files
authored
chore(ci): manual nightly job trigger (script and AI command) (#4355)
* chore(ci): add script for triggering nightly jobs * restructure * Update trigger-nightly-job.sh * Add AI commands * Refactor to use .ci instead of .ibm * Delete settings.json because it doesn't work * Adress AI reveiw
1 parent 4a038d9 commit d82cc45

File tree

4 files changed

+778
-0
lines changed

4 files changed

+778
-0
lines changed
Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
#!/bin/bash
2+
#
3+
# Trigger RHDH nightly ProwJobs via the OpenShift CI REST API (Gangway).
4+
#
5+
# Prerequisites:
6+
# - oc CLI installed.
7+
# - curl and jq installed.
8+
#
9+
# Authentication:
10+
# The script uses a dedicated kubeconfig (~/.config/openshift-ci/kubeconfig)
11+
# to avoid interfering with your current cluster context.
12+
# If not logged in or the token is expired, the script will automatically
13+
# open a browser for SSO login via `oc login --web`.
14+
# See: https://docs.ci.openshift.org/how-tos/triggering-prowjobs-via-rest/
15+
#
16+
# Usage examples:
17+
# # Trigger the OCP Helm nightly job on the main branch:
18+
# ./trigger-nightly-job.sh --job periodic-ci-redhat-developer-rhdh-main-e2e-ocp-helm-nightly
19+
#
20+
# # Trigger with a custom image (e.g. RC verification):
21+
# ./trigger-nightly-job.sh \
22+
# --job periodic-ci-redhat-developer-rhdh-main-e2e-ocp-helm-nightly \
23+
# --quay-repo rhdh/rhdh-hub-rhel9 \
24+
# --tag 1.9-123
25+
#
26+
# # Trigger against a fork:
27+
# ./trigger-nightly-job.sh \
28+
# --job periodic-ci-redhat-developer-rhdh-main-e2e-ocp-helm-nightly \
29+
# --org my-github-org \
30+
# --repo my-rhdh-fork \
31+
# --branch release-1.9
32+
#
33+
# # Dry-run mode (print the curl command without executing):
34+
# ./trigger-nightly-job.sh \
35+
# --job periodic-ci-redhat-developer-rhdh-main-e2e-ocp-helm-nightly \
36+
# --dry-run
37+
#
38+
39+
set -o errexit
40+
set -o nounset
41+
set -o pipefail
42+
43+
# --- Constants ---
44+
GANGWAY_URL="https://gangway-ci.apps.ci.l2s4.p1.openshiftapps.com/v1/executions"
45+
CI_SERVER="https://api.ci.l2s4.p1.openshiftapps.com:6443"
46+
47+
# --- Logging ---
48+
log::info() { echo "[INFO] $*" >&2; }
49+
log::warn() { echo "[WARN] $*" >&2; }
50+
log::error() { echo "[ERROR] $*" >&2; }
51+
52+
# --- Defaults ---
53+
JOB_NAME=""
54+
QUAY_REPO=""
55+
TAG_NAME=""
56+
GITHUB_ORG_NAME=""
57+
GITHUB_REPOSITORY_NAME=""
58+
RELEASE_BRANCH_NAME=""
59+
SKIP_SEND_ALERT="true"
60+
DRY_RUN=false
61+
62+
usage() {
63+
cat << EOF
64+
Usage: $(basename "$0") -j JOB_NAME [OPTIONS]
65+
66+
Trigger an RHDH nightly ProwJob via the OpenShift CI Gangway REST API.
67+
68+
Required:
69+
-j, --job JOB_NAME Full ProwJob name to trigger.
70+
71+
Optional overrides (passed as env var overrides to the job):
72+
-q, --quay-repo QUAY_REPO Override the Quay repository (e.g. rhdh/rhdh-hub-rhel9). Requires --tag to be set.
73+
-t, --tag TAG_NAME Override the image tag (e.g. 1.9-123).
74+
-o, --org GITHUB_ORG_NAME Override the GitHub org (default in job: redhat-developer).
75+
-r, --repo GITHUB_REPO_NAME Override the GitHub repo name (default in job: rhdh).
76+
-b, --branch BRANCH Override the branch name.
77+
-S, --send-alerts Send Slack alerts (default: alerts are skipped).
78+
79+
Other:
80+
-n, --dry-run Dry-run mode: print the curl command without executing.
81+
-h, --help Show this help message.
82+
83+
Examples:
84+
# Basic trigger:
85+
$(basename "$0") --job periodic-ci-redhat-developer-rhdh-main-e2e-ocp-helm-nightly
86+
87+
# Trigger with custom image:
88+
$(basename "$0") --job periodic-ci-redhat-developer-rhdh-main-e2e-ocp-helm-nightly --quay-repo rhdh/rhdh-hub-rhel9 --tag 1.9-123
89+
90+
# Trigger against a fork, with Slack alerts enabled:
91+
$(basename "$0") --job periodic-ci-redhat-developer-rhdh-main-e2e-ocp-helm-nightly --org my-org --repo my-fork --branch release-1.9 --send-alerts
92+
93+
Job name pattern: periodic-ci-redhat-developer-rhdh-{BRANCH}-e2e-{PLATFORM}-{METHOD}-nightly
94+
Examples:
95+
periodic-ci-redhat-developer-rhdh-main-e2e-ocp-helm-nightly
96+
periodic-ci-redhat-developer-rhdh-main-e2e-ocp-operator-nightly
97+
periodic-ci-redhat-developer-rhdh-release-1.7-e2e-ocp-helm-nightly
98+
Full list: https://prow.ci.openshift.org/configured-jobs/redhat-developer/rhdh
99+
EOF
100+
}
101+
102+
parse_args() {
103+
while [[ $# -gt 0 ]]; do
104+
case "$1" in
105+
-j | --job)
106+
[[ $# -ge 2 ]] || {
107+
log::error "$1 requires an argument"
108+
exit 1
109+
}
110+
JOB_NAME="$2"
111+
shift 2
112+
;;
113+
-q | --quay-repo)
114+
[[ $# -ge 2 ]] || {
115+
log::error "$1 requires an argument"
116+
exit 1
117+
}
118+
QUAY_REPO="$2"
119+
shift 2
120+
;;
121+
-t | --tag)
122+
[[ $# -ge 2 ]] || {
123+
log::error "$1 requires an argument"
124+
exit 1
125+
}
126+
TAG_NAME="$2"
127+
shift 2
128+
;;
129+
-o | --org)
130+
[[ $# -ge 2 ]] || {
131+
log::error "$1 requires an argument"
132+
exit 1
133+
}
134+
GITHUB_ORG_NAME="$2"
135+
shift 2
136+
;;
137+
-r | --repo)
138+
[[ $# -ge 2 ]] || {
139+
log::error "$1 requires an argument"
140+
exit 1
141+
}
142+
GITHUB_REPOSITORY_NAME="$2"
143+
shift 2
144+
;;
145+
-b | --branch)
146+
[[ $# -ge 2 ]] || {
147+
log::error "$1 requires an argument"
148+
exit 1
149+
}
150+
RELEASE_BRANCH_NAME="$2"
151+
shift 2
152+
;;
153+
-S | --send-alerts)
154+
SKIP_SEND_ALERT="false"
155+
shift
156+
;;
157+
-n | --dry-run)
158+
DRY_RUN=true
159+
shift
160+
;;
161+
-h | --help)
162+
usage
163+
exit 0
164+
;;
165+
*)
166+
log::error "Unknown option: $1"
167+
usage
168+
exit 1
169+
;;
170+
esac
171+
done
172+
}
173+
174+
validate_args() {
175+
if [[ -z "${JOB_NAME}" ]]; then
176+
log::error "-j/--job JOB_NAME is required."
177+
usage
178+
exit 1
179+
fi
180+
181+
if [[ "${JOB_NAME}" != periodic-ci-* ]]; then
182+
log::error "Job name must start with 'periodic-ci-', got: ${JOB_NAME}"
183+
exit 1
184+
fi
185+
186+
if [[ -n "${QUAY_REPO}" && -z "${TAG_NAME}" ]]; then
187+
log::error "--quay-repo requires --tag to be set."
188+
exit 1
189+
fi
190+
}
191+
192+
build_payload() {
193+
local -a jq_args=()
194+
195+
[[ -n "${QUAY_REPO}" ]] && jq_args+=(--arg MULTISTAGE_PARAM_OVERRIDE_QUAY_REPO "${QUAY_REPO}")
196+
[[ -n "${TAG_NAME}" ]] && jq_args+=(--arg MULTISTAGE_PARAM_OVERRIDE_TAG_NAME "${TAG_NAME}")
197+
[[ -n "${GITHUB_ORG_NAME}" ]] && jq_args+=(--arg MULTISTAGE_PARAM_OVERRIDE_GITHUB_ORG_NAME "${GITHUB_ORG_NAME}")
198+
[[ -n "${GITHUB_REPOSITORY_NAME}" ]] && jq_args+=(--arg MULTISTAGE_PARAM_OVERRIDE_GITHUB_REPOSITORY_NAME "${GITHUB_REPOSITORY_NAME}")
199+
[[ -n "${RELEASE_BRANCH_NAME}" ]] && jq_args+=(--arg MULTISTAGE_PARAM_OVERRIDE_RELEASE_BRANCH_NAME "${RELEASE_BRANCH_NAME}")
200+
jq_args+=(--arg MULTISTAGE_PARAM_OVERRIDE_SKIP_SEND_ALERT "${SKIP_SEND_ALERT}")
201+
202+
jq -n --arg job "${JOB_NAME}" "${jq_args[@]}" \
203+
'{job_name: $job, job_execution_type: "1", pod_spec_options: {envs: ($ARGS.named | del(.job))}}'
204+
}
205+
206+
ensure_auth() {
207+
if [[ "${DRY_RUN}" == true ]]; then
208+
echo "<TOKEN>"
209+
return
210+
fi
211+
212+
local current_server
213+
current_server=$(oc whoami --show-server 2> /dev/null || true)
214+
local needs_login=false
215+
216+
if [[ "${current_server}" != "${CI_SERVER}" ]]; then
217+
if [[ -n "${current_server}" ]]; then
218+
log::warn "Currently logged in to ${current_server}, need ${CI_SERVER}"
219+
fi
220+
needs_login=true
221+
elif ! oc whoami -t &> /dev/null; then
222+
log::warn "Token expired."
223+
needs_login=true
224+
fi
225+
226+
if [[ "${needs_login}" == true ]]; then
227+
log::info "Logging in to OpenShift CI cluster..."
228+
if ! oc login --web "${CI_SERVER}"; then
229+
log::error "Login failed."
230+
exit 1
231+
fi
232+
fi
233+
234+
if ! oc whoami -t 2> /dev/null; then
235+
log::error "Failed to get authentication token after login."
236+
exit 1
237+
fi
238+
}
239+
240+
print_summary() {
241+
local payload="$1"
242+
log::info "Job: ${JOB_NAME}"
243+
log::info "Payload:"
244+
echo "${payload}" | jq . 2> /dev/null || echo "${payload}"
245+
echo ""
246+
}
247+
248+
print_dry_run() {
249+
local payload="$1"
250+
echo "[DRY RUN] Would execute:"
251+
echo "curl -s -X POST \\"
252+
echo " -H \"Authorization: Bearer \$(oc whoami -t)\" \\"
253+
echo " -H \"Content-Type: application/json\" \\"
254+
echo " -d '${payload}' \\"
255+
echo " ${GANGWAY_URL}"
256+
}
257+
258+
trigger_job() {
259+
local token="$1"
260+
local payload="$2"
261+
262+
log::info "Triggering job..."
263+
local response http_code
264+
response=$(curl -s -w "\n%{http_code}" -X POST \
265+
-K <(printf 'header = "Authorization: Bearer %s"\n' "${token}") \
266+
-H "Content-Type: application/json" \
267+
-d "${payload}" \
268+
"${GANGWAY_URL}")
269+
http_code="${response##*$'\n'}"
270+
response="${response%$'\n'*}"
271+
272+
if [[ "${http_code}" -lt 200 || "${http_code}" -ge 300 ]]; then
273+
log::error "API returned HTTP ${http_code}"
274+
echo "${response}" | jq . >&2 2> /dev/null || echo "${response}" >&2
275+
log::error "The job name may be invalid. Verify at: https://prow.ci.openshift.org/configured-jobs/redhat-developer/rhdh"
276+
exit 1
277+
fi
278+
279+
log::info "Response:"
280+
echo "${response}" | jq . >&2 2> /dev/null || echo "${response}" >&2
281+
282+
echo "${response}"
283+
}
284+
285+
poll_job_status() {
286+
local token="$1"
287+
local job_id="$2"
288+
289+
echo ""
290+
log::info "Job ID: ${job_id}"
291+
log::info "Waiting for Prow URL..."
292+
293+
local job_url="" status_response
294+
for _ in $(seq 1 5); do
295+
printf "."
296+
status_response=$(curl -s \
297+
-K <(printf 'header = "Authorization: Bearer %s"\n' "${token}") \
298+
"${GANGWAY_URL}/${job_id}" 2> /dev/null || true)
299+
300+
if [[ -n "${status_response}" ]] && echo "${status_response}" | jq . &> /dev/null; then
301+
job_url=$(echo "${status_response}" | jq -r '.job_url // empty')
302+
[[ -n "${job_url}" ]] && break
303+
fi
304+
sleep 2
305+
done
306+
307+
if [[ -n "${job_url}" ]]; then
308+
log::info "Job URL: ${job_url}"
309+
else
310+
log::warn "Job URL not yet available."
311+
fi
312+
313+
log::info "Re-check status:"
314+
log::info " curl -s -H \"Authorization: Bearer \$(oc whoami -t)\" ${GANGWAY_URL}/${job_id} | jq ."
315+
}
316+
317+
main() {
318+
# Use a dedicated kubeconfig to avoid interfering with current cluster context.
319+
export KUBECONFIG="${XDG_CONFIG_HOME:-${HOME}/.config}/openshift-ci/kubeconfig"
320+
mkdir -p "$(dirname "${KUBECONFIG}")"
321+
322+
parse_args "$@"
323+
validate_args
324+
325+
local payload token
326+
payload=$(build_payload)
327+
token=$(ensure_auth)
328+
329+
print_summary "${payload}"
330+
331+
if [[ "${DRY_RUN}" == true ]]; then
332+
print_dry_run "${payload}"
333+
exit 0
334+
fi
335+
336+
local response
337+
response=$(trigger_job "${token}" "${payload}")
338+
339+
local job_id
340+
job_id=$(echo "${response}" | jq -r '.id // empty' 2> /dev/null || true)
341+
if [[ -n "${job_id}" ]]; then
342+
poll_job_status "${token}" "${job_id}"
343+
fi
344+
}
345+
346+
main "$@"

0 commit comments

Comments
 (0)