Skip to content

Commit 0b6f907

Browse files
andrrosspeterzhuamazon
authored andcommitted
Move OpenSearch-specific Jenkins file from opensearch-build (opensearch-project#21113)
These files are entirely related to running CI workflows against this repository. They share nothing else in opensearch-build. They belong in this repository. Signed-off-by: Andrew Ross <andrross@amazon.com> Signed-off-by: Peter Zhu <zhujiaxi@amazon.com> Co-authored-by: Peter Zhu <zhujiaxi@amazon.com>
1 parent e23b6c8 commit 0b6f907

3 files changed

Lines changed: 390 additions & 9 deletions

File tree

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* The OpenSearch Contributors require contributions made to
6+
* this file be licensed under the Apache-2.0 license or a
7+
* compatible open source license.
8+
*/
9+
10+
// @job-name: gradle-check
11+
// @description: Runs Gradle check on OpenSearch core repository for a given branch or commit.
12+
13+
def secret_dockerhub_readonly = [
14+
[envVar: 'DOCKER_USERNAME', secretRef: 'op://opensearch-infra-secrets/dockerhub-production-readonly-credentials/username'],
15+
[envVar: 'DOCKER_PASSWORD', secretRef: 'op://opensearch-infra-secrets/dockerhub-production-readonly-credentials/password']
16+
]
17+
18+
lib = library(identifier: 'jenkins@11.6.0', retriever: modernSCM([
19+
$class: 'GitSCMSource',
20+
remote: 'https://github.com/opensearch-project/opensearch-build-libraries.git',
21+
]))
22+
23+
pipeline {
24+
agent { label AGENT_LABEL }
25+
options {
26+
timeout(time: 2, unit: 'HOURS')
27+
buildDiscarder(logRotator(daysToKeepStr: '90'))
28+
throttleJobProperty(
29+
categories: [],
30+
limitOneJobWithMatchingParams: false,
31+
maxConcurrentPerNode: 0,
32+
maxConcurrentTotal: 45,
33+
paramsToUseForLimit: '',
34+
throttleEnabled: true,
35+
throttleOption: 'project',
36+
)
37+
}
38+
parameters {
39+
string(
40+
name: 'GIT_REPO_URL',
41+
description: 'OpenSearch core repository url on git, can be either the official upstream url or your fork url.',
42+
defaultValue: 'https://github.com/opensearch-project/OpenSearch.git',
43+
trim: true
44+
)
45+
string(
46+
name: 'GIT_REFERENCE',
47+
description: 'Git branch, tag, commitid for reference to checkout commit of OpenSearch core before running the gradle check.',
48+
defaultValue: 'main',
49+
trim: true
50+
)
51+
string(
52+
name: 'GRADLE_CHECK_COMMAND',
53+
description: '<Optional> Custom command to pass to runGradleCheck.',
54+
defaultValue: 'check -Dtests.coverage=true',
55+
trim: true
56+
)
57+
// Must use agent with 1 executor or gradle check will show a lot of java-related errors
58+
// The c524xlarge is the instance type that has the least amount of errors during gradle check
59+
// https://github.com/opensearch-project/OpenSearch/issues/1975
60+
//
61+
// Update 20230724: Recent investigation shows gradle check is memory-bound thus switch to a new
62+
// runner of M58xlarge for more stable runs
63+
// https://github.com/opensearch-project/opensearch-ci/issues/321
64+
choice(
65+
name: 'AGENT_LABEL',
66+
description: '<Optional> Choose which jenkins agent to run gradle check on. Defaults to Jenkins-Agent-Ubuntu2404-X64-M58xlarge-Single-Host.',
67+
choices: ['Jenkins-Agent-Ubuntu2404-X64-M7a8xlarge-Single-Host', 'Jenkins-Agent-Windows2019-X64-C524xlarge-Single-Host'],
68+
)
69+
}
70+
triggers {
71+
GenericTrigger(
72+
genericVariables: [
73+
[key: 'pr_from_sha', value: '$.pr_from_sha'],
74+
[key: 'pr_from_clone_url', value: '$.pr_from_clone_url'],
75+
[key: 'pr_to_clone_url', value: '$.pr_to_clone_url'],
76+
[key: 'pr_title', value: '$.pr_title'],
77+
[key: 'pr_number', value: '$.pr_number'],
78+
[key: 'post_merge_action', value: '$.post_merge_action'],
79+
[key: 'pr_owner', value: '$.pr_owner'],
80+
[key: 'gradle_check_command', value: '$.gradle_check_command']
81+
],
82+
tokenCredentialId: 'jenkins-gradle-check-generic-webhook-token',
83+
causeString: 'Triggered by PR on OpenSearch core repository',
84+
printContributedVariables: false,
85+
printPostContent: false
86+
)
87+
parameterizedCron '''
88+
H */2 * * * %GIT_REFERENCE=main;AGENT_LABEL=Jenkins-Agent-Ubuntu2404-X64-M58xlarge-Single-Host
89+
H 6 * * * %GIT_REFERENCE=2.19;AGENT_LABEL=Jenkins-Agent-Ubuntu2404-X64-M58xlarge-Single-Host
90+
'''
91+
}
92+
environment {
93+
BUILD_CAUSE = currentBuild.getBuildCauses()
94+
}
95+
stages {
96+
stage('Run Gradle Check') {
97+
steps {
98+
script {
99+
100+
// Use webhook value if provided, otherwise fall back to pipeline parameter default
101+
if (binding.hasVariable('gradle_check_command') && gradle_check_command?.trim()) {
102+
env.GRADLE_CHECK_COMMAND = gradle_check_command
103+
}
104+
105+
if (!(env.GRADLE_CHECK_COMMAND ==~ /^[a-zA-Z0-9\-._=: \/*#]+$/)) {
106+
error("Invalid GRADLE_CHECK_COMMAND '${env.GRADLE_CHECK_COMMAND}': contains disallowed characters")
107+
}
108+
109+
sh """
110+
set +x
111+
set -e
112+
JAVA_HOME_LIST=`env | grep JAVA | grep HOME`
113+
echo "JAVA_HOME_LIST \$JAVA_HOME_LIST"
114+
115+
if [ -n "\$JAVA_HOME_LIST" ] && [ "\$JAVA_HOME_LIST" != "" ]; then
116+
for java_version in \$JAVA_HOME_LIST; do
117+
echo \$java_version
118+
java_path="`echo \$java_version | cut -d= -f2`/bin/java -version"
119+
eval \$java_path
120+
done
121+
else
122+
echo "Missing JAVA_HOME information in env vars, exit 1"
123+
exit 1
124+
fi
125+
"""
126+
127+
def agent_name_array = params.AGENT_LABEL.tokenize('-')
128+
def agent_name = agent_name_array[2] + " " + agent_name_array[4]
129+
130+
echo("Build Cause: ${BUILD_CAUSE}")
131+
withSecrets(secrets: secret_dockerhub_readonly){
132+
def bwc_checkout_align = "false"
133+
134+
def dockerLogin = sh(returnStdout: true, script: "set +x && (echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin) || echo docker error").trim()
135+
136+
if (!env.BUILD_CAUSE.contains('Started by user') && !env.BUILD_CAUSE.contains('Started by timer')) {
137+
def pr_url = "${pr_to_clone_url}".replace(".git", "/pull/${pr_number}")
138+
println("Triggered by GitHub: ${pr_to_clone_url}")
139+
if ("$post_merge_action" == "true") {
140+
currentBuild.description = """runner: ${agent_name}<br><a href="${pr_to_clone_url}">Others</a>: ${pr_title}"""
141+
}
142+
else {
143+
currentBuild.description = """runner: ${agent_name}<br><a href="${pr_url}">PR #${pr_number}</a>: ${pr_title} with bwc.checkout.align=true"""
144+
bwc_checkout_align = "true"
145+
}
146+
147+
abortStaleJenkinsJobs(jobName: 'gradle-check', lookupTime: 3)
148+
149+
runGradleCheck(
150+
gitRepoUrl: "${pr_from_clone_url}",
151+
gitReference: "${pr_from_sha}",
152+
bwcCheckoutAlign: "${bwc_checkout_align}",
153+
command: "${GRADLE_CHECK_COMMAND}"
154+
)
155+
}
156+
else {
157+
println("Triggered by User or Triggered by Timer")
158+
def repo_url = "${GIT_REPO_URL}".replace(".git", "/commit")
159+
currentBuild.description = """runner: ${agent_name}<br>git: <a href="${GIT_REPO_URL}">${GIT_REPO_URL}</a><br>ref: <a href="${repo_url}/${GIT_REFERENCE}">${GIT_REFERENCE}</a>"""
160+
161+
runGradleCheck(
162+
gitRepoUrl: "${GIT_REPO_URL}",
163+
gitReference: "${GIT_REFERENCE}",
164+
bwcCheckoutAlign: "${bwc_checkout_align}",
165+
command: "${GRADLE_CHECK_COMMAND}"
166+
)
167+
}
168+
169+
sh("docker logout || echo docker error")
170+
}
171+
}
172+
}
173+
post() {
174+
failure {
175+
archiveArtifacts artifacts: '**/build/heapdump/*.hprof', allowEmptyArchive: true
176+
}
177+
always {
178+
sh ("cp -v `find search/build/reports/jacoco/ -name '*.xml' | head -n 1` codeCoverage.xml || echo")
179+
junit allowEmptyResults: true, testResults: '**/build/test-results/**/*.xml'
180+
archiveArtifacts artifacts: 'codeCoverage.xml', onlyIfSuccessful: true
181+
script {
182+
def invokedBy
183+
def pullRequest
184+
def pullRequestTitle
185+
def gitReference
186+
def pullRequestOwner
187+
switch (true) {
188+
case env.BUILD_CAUSE.contains('Started by user'):
189+
invokedBy = 'User'
190+
pullRequest = "null"
191+
pullRequestTitle = "null"
192+
gitReference = "${GIT_REFERENCE}"
193+
pullRequestOwner = "null"
194+
break
195+
case env.BUILD_CAUSE.contains('Started by timer'):
196+
invokedBy = 'Timer'
197+
pullRequest = "null"
198+
pullRequestTitle = "null"
199+
gitReference = "${GIT_REFERENCE}"
200+
pullRequestOwner = "null"
201+
break
202+
case "${post_merge_action}" == "true":
203+
invokedBy = 'Post Merge Action'
204+
pullRequest = "${pr_number}"
205+
pullRequestTitle = "${pr_title}"
206+
gitReference = "${pr_from_sha}"
207+
pullRequestOwner = "${pr_owner}"
208+
break
209+
default:
210+
invokedBy = 'Pull Request'
211+
pullRequest = "${pr_number}"
212+
pullRequestTitle = "${pr_title}"
213+
gitReference = "${pr_from_sha}"
214+
pullRequestOwner = "${pr_owner}"
215+
}
216+
publishGradleCheckTestResults(prNumber: "${pullRequest}" , prTitle: "${pullRequestTitle}", prOwner: "${pullRequestOwner}", invokeType: "${invokedBy}", gitReference: "${gitReference}", command: "${GRADLE_CHECK_COMMAND}")
217+
sh("rm -rf *")
218+
postCleanup()
219+
}
220+
}
221+
}
222+
}
223+
}
224+
post() {
225+
always {
226+
script {
227+
postCleanup()
228+
sh "(docker logout && docker image prune -f --all) || echo docker error"
229+
}
230+
}
231+
}
232+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#!/bin/bash
2+
3+
# Copyright OpenSearch Contributors
4+
5+
# SPDX-License-Identifier: Apache-2.0
6+
#
7+
# The OpenSearch Contributors require contributions made to
8+
# this file be licensed under the Apache-2.0 license or a
9+
# compatible open source license.
10+
11+
# This script is used in OpenSearch Core repo github actions
12+
# To trigger Jenkins Gradle Check from a PR
13+
14+
15+
JENKINS_URL="https://build.ci.opensearch.org"
16+
TRIGGER_TOKEN=""
17+
GITHUB_USER=""
18+
GITHUB_TOKEN=""
19+
20+
GRADLE_CHECK_COMMAND=""
21+
22+
while getopts "u:t:p:c:" opt; do
23+
case $opt in
24+
t)
25+
TRIGGER_TOKEN="$OPTARG"
26+
;;
27+
u)
28+
GITHUB_USER="$OPTARG"
29+
;;
30+
p)
31+
GITHUB_TOKEN="$OPTARG"
32+
;;
33+
c)
34+
GRADLE_CHECK_COMMAND="$OPTARG"
35+
;;
36+
\?)
37+
echo "Invalid option: -$OPTARG" >&2
38+
exit 1
39+
;;
40+
:)
41+
echo "Option -$OPTARG requires an argument." >&2
42+
exit 1
43+
;;
44+
esac
45+
done
46+
47+
if [ -z "$TRIGGER_TOKEN" ]; then
48+
echo "Error: TRIGGER_TOKEN is required. Use -t option to provide it."
49+
exit 1
50+
fi
51+
52+
if [ -z "$GITHUB_USER" ]; then
53+
echo "Error: GITHUB_USER is required. Use -u option to provide it."
54+
exit 1
55+
fi
56+
57+
if [ -z "$GITHUB_TOKEN" ]; then
58+
echo "Error: GITHUB_TOKEN is required. Use -p option to provide it."
59+
exit 1
60+
fi
61+
62+
63+
TIMEPASS=0
64+
TIMEOUT=7200
65+
RESULT="null"
66+
PR_TITLE_NEW=`echo $pr_title | tr -dc '[:alnum:] ' | tr '[:upper:]' '[:lower:]'`
67+
PAYLOAD_JSON="{\"pr_from_sha\": \"$pr_from_sha\", \"pr_from_clone_url\": \"$pr_from_clone_url\", \"pr_to_clone_url\": \"$pr_to_clone_url\", \"pr_title\": \"$PR_TITLE_NEW\", \"pr_number\": \"$pr_number\", \"post_merge_action\": \"$post_merge_action\", \"pr_owner\": \"$pr_owner\", \"gradle_check_command\": \"$GRADLE_CHECK_COMMAND\"}"
68+
69+
perform_curl_and_process_with_jq() {
70+
local url=$1
71+
local jq_filter=$2
72+
local max_retries=$3
73+
local count=0
74+
local success=false
75+
76+
while [ "$count" -lt "$max_retries" ]; do
77+
response=$(curl -s -XGET "${url}api/json" --user ${GITHUB_USER}:${GITHUB_TOKEN})
78+
processed_response=$(echo "$response" | jq --raw-output "$jq_filter")
79+
jq_exit_code=$?
80+
81+
if [ "$jq_exit_code" -eq "0" ]; then
82+
success=true
83+
echo "$processed_response"
84+
break
85+
else
86+
echo "Attempt $((count+1))/$max_retries failed. The jq processing failed with exit code: $jq_exit_code. Retrying..."
87+
fi
88+
89+
count=$((count+1))
90+
sleep 10
91+
done
92+
93+
if [ "$success" != "true" ]; then
94+
echo "Failed to retrieve and process data after $max_retries attempts."
95+
exit 1
96+
fi
97+
}
98+
99+
echo "Trigger Jenkins workflows"
100+
JENKINS_REQ=`curl -s -XPOST \
101+
-H "Authorization: Bearer $TRIGGER_TOKEN" \
102+
-H "Content-Type: application/json" \
103+
"$JENKINS_URL/generic-webhook-trigger/invoke" \
104+
--data "$(echo $PAYLOAD_JSON)"`
105+
106+
echo $PAYLOAD_JSON
107+
echo $JENKINS_REQ
108+
109+
QUEUE_URL=$(echo $JENKINS_REQ | jq --raw-output '.jobs."gradle-check".url')
110+
echo QUEUE_URL $QUEUE_URL
111+
echo "wait for jenkins to start workflow" && sleep 15
112+
113+
echo "Check if queue exist in Jenkins after triggering"
114+
if [ -z "$QUEUE_URL" ] || [ "$QUEUE_URL" != "null" ]; then
115+
while [ "$RESULT" = "null" ] && [ "$TIMEPASS" -le "$TIMEOUT" ]; do
116+
echo "Use queue information to find build number in Jenkins if available"
117+
WORKFLOW_URL=$(curl -s -XGET ${JENKINS_URL}/${QUEUE_URL}api/json --user ${GITHUB_USER}:${GITHUB_TOKEN} | jq --raw-output .executable.url)
118+
echo WORKFLOW_URL $WORKFLOW_URL
119+
120+
if [ -n "$WORKFLOW_URL" ] && [ "$WORKFLOW_URL" != "null" ]; then
121+
122+
RUNNING="true"
123+
124+
echo "Waiting for Jenkins to complete the run"
125+
while [ "$RUNNING" = "true" ] && [ "$TIMEPASS" -le "$TIMEOUT" ]; do
126+
echo "Still running, wait for another 30 seconds before checking again, max timeout $TIMEOUT"
127+
echo "Jenkins Workflow Url: $WORKFLOW_URL"
128+
TIMEPASS=$(( TIMEPASS + 30 )) && echo time passed: $TIMEPASS
129+
sleep 30
130+
RUNNING=$(perform_curl_and_process_with_jq "$WORKFLOW_URL" ".building" 10)
131+
echo "Workflow running status :$RUNNING"
132+
done
133+
134+
if [ "$RUNNING" = "true" ]; then
135+
echo "Timed out"
136+
RESULT="TIMEOUT"
137+
else
138+
echo "Complete the run, checking results now......"
139+
RESULT=$(curl -s -XGET ${WORKFLOW_URL}api/json --user ${GITHUB_USER}:${GITHUB_TOKEN} | jq --raw-output .result)
140+
fi
141+
142+
else
143+
echo "Job not started yet. Waiting for 60 seconds before next attempt."
144+
TIMEPASS=$(( TIMEPASS + 60 )) && echo time passed: $TIMEPASS
145+
sleep 60
146+
fi
147+
done
148+
fi
149+
150+
echo "Please check jenkins url for logs: $WORKFLOW_URL"
151+
echo "Result: $RESULT"
152+
if [ "$RESULT" == "SUCCESS" ] || [ "$RESULT" == "UNSTABLE" ]; then
153+
echo "Get codeCoverage.xml" && curl -SLO ${WORKFLOW_URL}artifact/codeCoverage.xml --user ${GITHUB_USER}:${GITHUB_TOKEN}
154+
else
155+
exit 1
156+
fi

0 commit comments

Comments
 (0)