Fix Jenkins CPS warnings for implicit field creation in monolithic.Jenkinsfile
Jenkins v2.516.1 with Pipeline Groovy plugin v4045+ displays memory leak warnings when variables are declared without the 'def' keyword. These warnings appear because the CPS transformer interprets unscoped variables as implicit script-level fields. This change eliminates all CPS warnings by applying proper Groovy syntax for variable declarations and Map operations. pipelines/monolithic.Jenkinsfile - MODIFIED Lines 11-19: Pipeline-level variables - Added @groovy.transform.Field annotation to PROPS, IMG_PARAMS, IMAGES_FAILED - These variables persist across pipeline stages and require explicit field declaration - Reference: https://www.jenkins.io/doc/book/pipeline/shared-libraries/ Lines 22-24: parseProps() function - Empty Map declaration - Changed 'def x = {}' to 'def x = [:]' - Using {} creates a Closure, not a Map - Reference: https://groovy-lang.org/groovy-dev-kit.html Lines 29-32: parseProps() function - Loop variables - Added 'def' keyword to parts, key, value variables - Prevents implicit field creation for loop-scoped variables Lines 39-58: loadEnv() function - Map declaration and property access - Changed 'def data = {}' to 'def data = [:]' for proper Map instantiation - Changed dot notation (data.KEY) to bracket notation (data['KEY']) - Bracket notation avoids false positive CPS warnings. It explicitly calls Map.putAt() method instead of ambiguous property access - Reference: https://www.jenkins.io/doc/book/pipeline/cps-method-mismatches/ Lines 72, 100-106, 281, 376: PROPS property reads - Changed PROPS.KEY to PROPS['KEY'] for consistency with bracket notation TEST PLAN Scenario 1 - Jenkins v2.492.1 backward compatibility: PASS: Pipeline executed without errors PASS: No sandbox permission issues PASS: All stages completed successfully Scenario 2 - Jenkins v2.516.1 warning elimination: PASS: Without fix - 17 CPS warnings displayed PASS: With fix - 0 CPS warnings displayed PASS: Pipeline executed without errors PASS: All stages completed successfully Closes-Bug: 2134568 Change-Id: Ic963c15cb0fe5cde96654e8d4542534cbcf07c30 Signed-off-by: Ladislau <Ladislau.Felisbino@windriver.com>
This commit is contained in:
committed by
Ladislau Felisbino
parent
a750c423ea
commit
f44ba20d1c
@@ -8,40 +8,54 @@
|
||||
|
||||
library "common@${params.JENKINS_SCRIPTS_BRANCH}"
|
||||
|
||||
PROPS = null
|
||||
IMG_PARAMS = null
|
||||
IMAGES_FAILED = false
|
||||
// Pipeline-level variables require @Field annotation to avoid Jenkins CPS warnings
|
||||
// about implicit field creation. These variables persist across pipeline stages.
|
||||
// Reference: https://www.jenkins.io/doc/book/pipeline/shared-libraries/
|
||||
@groovy.transform.Field
|
||||
def PROPS = null
|
||||
@groovy.transform.Field
|
||||
def IMG_PARAMS = null
|
||||
@groovy.transform.Field
|
||||
def IMAGES_FAILED = false
|
||||
|
||||
def parseProps(text) {
|
||||
def x = {}
|
||||
// Use [:] for empty Map. Using {} creates a Closure, not a Map.
|
||||
// Reference: https://groovy-lang.org/groovy-dev-kit.html
|
||||
def x = [:]
|
||||
for (line in text.split (/\n+/)) {
|
||||
if (line.matches (/\s*(?:#.*)?#/)) {
|
||||
continue
|
||||
}
|
||||
parts = line.split ("=", 2)
|
||||
key = parts[0]
|
||||
value = parts[1]
|
||||
// Use def keyword for loop variables to avoid CPS field creation warnings
|
||||
def parts = line.split ("=", 2)
|
||||
def key = parts[0]
|
||||
def value = parts[1]
|
||||
x."${key}" = value
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
def loadEnv() {
|
||||
def data = {}
|
||||
data.NEED_BUILD = false
|
||||
data.SUPPRESS_DOCKER_IMAGE_BUILD_ERRORS = params.SUPPRESS_DOCKER_IMAGE_BUILD_ERRORS
|
||||
// Use [:] for empty Map. Using {} creates a Closure, not a Map.
|
||||
// Use bracket notation for Map property access to avoid false positive CPS warnings.
|
||||
// Dot notation (data.KEY) triggers warnings because CPS cannot distinguish between
|
||||
// dynamic Map property access and implicit field creation.
|
||||
// Reference: https://www.jenkins.io/doc/book/pipeline/cps-method-mismatches/
|
||||
def data = [:]
|
||||
data["NEED_BUILD"] = false
|
||||
data["SUPPRESS_DOCKER_IMAGE_BUILD_ERRORS"] = params.SUPPRESS_DOCKER_IMAGE_BUILD_ERRORS
|
||||
ws(params.BUILD_HOME) {
|
||||
if (fileExists ("NEED_BUILD")) {
|
||||
data.NEED_BUILD = true
|
||||
data["NEED_BUILD"] = true
|
||||
}
|
||||
}
|
||||
final String configText = sh (script: "${Constants.SCRIPTS_DIR}/print-config.sh", returnStdout: true)
|
||||
final props = parseProps (configText)
|
||||
data.BUILD_OUTPUT_HOME_URL = props.BUILD_OUTPUT_HOME_URL
|
||||
data.PUBLISH_URL = props.PUBLISH_URL
|
||||
data.BUILD_REMOTE_CLI = props.BUILD_REMOTE_CLI == "true"
|
||||
data["BUILD_OUTPUT_HOME_URL"] = props.BUILD_OUTPUT_HOME_URL
|
||||
data["PUBLISH_URL"] = props.PUBLISH_URL
|
||||
data["BUILD_REMOTE_CLI"] = props.BUILD_REMOTE_CLI == "true"
|
||||
PROPS = data
|
||||
return data.NEED_BUILD
|
||||
return data["NEED_BUILD"]
|
||||
}
|
||||
|
||||
def partJobName (name) {
|
||||
@@ -69,7 +83,7 @@ def runImagesPart (name, params = []) {
|
||||
// current build. Instead we note when an image-related
|
||||
// job has failed, and skip all subsequent image-related
|
||||
// jobs.
|
||||
if (PROPS.SUPPRESS_DOCKER_IMAGE_BUILD_ERRORS) {
|
||||
if (PROPS["SUPPRESS_DOCKER_IMAGE_BUILD_ERRORS"]) {
|
||||
if (!IMAGES_FAILED) {
|
||||
final jobName = partJobName (name)
|
||||
final res = runPart (name, IMG_PARAMS + params, false).result
|
||||
@@ -97,10 +111,10 @@ def printBuildFooter() {
|
||||
msg += "\n"
|
||||
msg += "========================================\n"
|
||||
msg += "\n"
|
||||
if (PROPS.NEED_BUILD) {
|
||||
msg += "Build output: ${PROPS.BUILD_OUTPUT_HOME_URL}\n"
|
||||
if (PROPS.PUBLISH_URL) {
|
||||
msg += "Publish output: ${PROPS.PUBLISH_URL}\n"
|
||||
if (PROPS["NEED_BUILD"]) {
|
||||
msg += "Build output: ${PROPS["BUILD_OUTPUT_HOME_URL"]}\n"
|
||||
if (PROPS["PUBLISH_URL"]) {
|
||||
msg += "Publish output: ${PROPS["PUBLISH_URL"]}\n"
|
||||
}
|
||||
if (IMAGES_FAILED) {
|
||||
msg += "\n"
|
||||
@@ -278,7 +292,7 @@ or with paths relative to repo root:
|
||||
}
|
||||
// This stage runs only if build is required
|
||||
stage('X0') {
|
||||
when { expression { PROPS.NEED_BUILD } }
|
||||
when { expression { PROPS["NEED_BUILD"] } }
|
||||
stages {
|
||||
stage('PREPARE') {
|
||||
steps {
|
||||
@@ -373,7 +387,7 @@ or with paths relative to repo root:
|
||||
} // stages
|
||||
} // stage('IMAGES')
|
||||
stage('remote-cli') {
|
||||
when { expression { PROPS.BUILD_REMOTE_CLI } }
|
||||
when { expression { PROPS["BUILD_REMOTE_CLI"] } }
|
||||
steps {
|
||||
runPart ("build-remote-cli")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user