Skip to content

Commit 0047e84

Browse files
committed
Add a data/valid/effectively-scripted-wrapped-by-declarative to the mix
1 parent e0d13a6 commit 0047e84

File tree

1 file changed

+246
-0
lines changed
  • data/valid/effectively-scripted-wrapped-by-declarative

1 file changed

+246
-0
lines changed
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
#!/usr/bin/env groovy
2+
3+
// Jenkinsfile-rescan-project-labels
4+
// (C) 2019 - 2021 by Jim Klimov <[email protected]>
5+
// This Jenkinsfile makes-believe it is a Declarative pipeline for
6+
// the sake of commonality of our pipeline scripts (build args,
7+
// various options and stuff), but in fact this is a scripted
8+
// pipeline most of the way.
9+
// Its job is to find all defined Jenkins jobs and inspect whether
10+
// some have no labels defined and so can fall onto random unprepared
11+
// workers.
12+
13+
// Note: A lot of methods below must be approved by Jenkins admin!
14+
// To do that, "replay" the job and edit the script in Web-GUI to
15+
// remove try lines and catch blocks, and replay it time and again
16+
// until all method signatures have been submitted for approval and
17+
// approved in $JENKINS_URL/scriptApproval/ by an admin, one by one.
18+
19+
import jenkins.model.*
20+
import hudson.model.*
21+
import hudson.util.PersistedList
22+
import jenkins.branch.*
23+
24+
@NonCPS
25+
def inspectJobs(String verbose, String regexSubset, String regexExclude, String regexLabels) {
26+
def jobs = Jenkins.instance.getAllItems()
27+
def hitlist = []
28+
boolean verdict = true
29+
30+
jobs.each { j ->
31+
if (j instanceof com.cloudbees.hudson.plugins.folder.Folder) {
32+
if (verbose.equals("true")) {
33+
echo 'SKIP-INSPECTION: Ignoring JOB which is a com.cloudbees.hudson.plugins.folder.Folder : ' + j.fullName
34+
}
35+
return
36+
}
37+
if (j instanceof jenkins.branch.OrganizationFolder) {
38+
if (verbose.equals("true")) {
39+
echo 'SKIP-INSPECTION: Ignoring JOB which is a jenkins.branch.OrganizationFolder : ' + j.fullName
40+
}
41+
return
42+
}
43+
44+
if ( ! regexSubset.equals("") ) {
45+
if ( ! ( j.fullName =~ regexSubset ) ) {
46+
if (verbose.equals("true")) {
47+
echo "SKIP-INSPECTION: Ignoring JOB whose name '${j.fullName}' did not match specified regex of interesting jobs to inspect '${regexSubset}'"
48+
}
49+
return;
50+
}
51+
}
52+
53+
if ( ! regexExclude.equals("") ) {
54+
if ( j.fullName =~ regexExclude ) {
55+
if (verbose.equals("true")) {
56+
echo "SKIP-INSPECTION: Ignoring JOB whose name '${j.fullName}' matched specified regex of jobs to exclude from inspect '${regexExclude}'"
57+
}
58+
return;
59+
}
60+
}
61+
62+
String jobLabelString
63+
String jobStatus
64+
try {
65+
jobStatus = (j.disabled ? "DISABLED" : "ENABLED" )
66+
} catch (Exception eDisabled) {
67+
echo "WARNING: failed to query whether the job '${j.fullName}' is disabled, so inspecting it just in case: " + eDisabled
68+
jobStatus = "Status:N/A"
69+
}
70+
71+
try {
72+
jobLabelString = j.getAssignedLabelString()
73+
} catch (Exception e) {
74+
jobLabelString = "N/A"
75+
76+
if (j instanceof org.jenkinsci.plugins.workflow.job.WorkflowJob) {
77+
try {
78+
jobLabelString = j.getAssignedLabel()
79+
} catch (Exception eLabelPipeline) {
80+
jobLabelString = "N/A"
81+
}
82+
if (verbose.equals("true")) {
83+
if (jobLabelString.equals("N/A")) {
84+
echo "WARNING : Failed to query labels of a org.jenkinsci.plugins.workflow.job.WorkflowJob : " + j.fullName
85+
} else if (jobLabelString.equals("master")) {
86+
/* // https://github.com/jenkinsci/workflow-job-plugin/blob/master/src/main/java/org/jenkinsci/plugins/workflow/job/WorkflowJob.java#L402
87+
Jenkins j = Jenkins.getInstanceOrNull();
88+
if (j == null) {
89+
return null;
90+
}
91+
return j.getSelfLabel(); // == "master" for us
92+
*/
93+
echo "WARNING : Failed to query real labels of a org.jenkinsci.plugins.workflow.job.WorkflowJob - it only reports the pipeline default handling node : " + j.fullName
94+
}
95+
96+
echo "Pipeline job " + j.fullName + " has labels: " + jobLabelString
97+
98+
try {
99+
j.getSubTasks().each() { t ->
100+
// Note: in practice I only saw one subtask per pipeline job, named as itself and also assigned to "master"
101+
try {
102+
echo "Pipeline job " + j.fullName + " also has subtask: " + t + " with label(s): '" + t.getAssignedLabel() + "'"
103+
} catch (Exception ePipelineSubtaskItem) {
104+
println ePipelineSubtaskItem
105+
}
106+
}
107+
} catch (Exception ePipelineSubtaskList) {
108+
println ePipelineSubtaskList
109+
}
110+
}
111+
}
112+
113+
if (j instanceof org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject) {
114+
// an MBP
115+
if (verbose.equals("true")) {
116+
echo "WARNING : Failed to query labels of a MBP org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject : " + j.fullName
117+
}
118+
}
119+
120+
if (j instanceof hudson.model.FreeStyleProject) {
121+
if (verbose.equals("true")) {
122+
echo "WARNING : Failed to query labels of a hudson.model.FreeStyleProject : " + j.fullName
123+
}
124+
}
125+
126+
if (j instanceof com.tikal.jenkins.plugins.multijob.MultiJobProject) {
127+
if (verbose.equals("true")) {
128+
echo "WARNING : Failed to query labels of a com.tikal.jenkins.plugins.multijob.MultiJobProject : " + j.fullName
129+
}
130+
}
131+
}
132+
133+
//if ( jobLabelString == null || jobLabelString.equals("") || jobLabelString.equals("N/A") ) return
134+
if ( jobLabelString.equals("N/A") ) return
135+
if ( regexLabels.equals("") ) {
136+
if ( jobLabelString != null && !jobLabelString.equals(null) && !jobLabelString.equals("") ) return
137+
} else {
138+
if ( ! ( jobLabelString =~ regexLabels ) ) {
139+
if (verbose.equals("true")) {
140+
echo "SKIP-INSPECTION: Ignoring JOB '${j.fullName}' whose labels '${jobLabelString}' did not match specified regex of interesting job labels to complain about '${regexLabels}'"
141+
}
142+
return;
143+
}
144+
}
145+
if ( !j.disabled && j.buildable ) {
146+
verdict = false
147+
hitlist << j.fullName
148+
}
149+
println jobStatus + ":\t'" + j.fullName + "' \tLABEL(S): '" + jobLabelString + "' \tCFGURL: " + j.getAbsoluteUrl() + "configure"
150+
}
151+
152+
// false means some jobs need a fix
153+
return [verdict, hitlist]
154+
}
155+
156+
157+
// A declarative pipeline shiny wrapper (we need it
158+
// for common ways of autosetup and params, mostly)
159+
pipeline {
160+
options {
161+
/*
162+
// There is no such option yet, sadly:
163+
description("This job runs regularly to find jobs that do not have a label assigned")
164+
*/
165+
disableConcurrentBuilds()
166+
disableResume()
167+
durabilityHint('PERFORMANCE_OPTIMIZED')
168+
buildDiscarder(logRotator(numToKeepStr: '10'))
169+
skipDefaultCheckout true
170+
}
171+
triggers {
172+
cron('H H * * *')
173+
}
174+
agent {label "master || master-infra"}
175+
parameters {
176+
booleanParam (
177+
defaultValue: false,
178+
description: 'Print found and skipped items?',
179+
name: 'JOBLIST_VERBOSE'
180+
)
181+
string (
182+
defaultValue: '',
183+
description: 'Groovy regex for constraining a list of jobs to inspect (if not empty, then only matching job names are scanned)',
184+
name: 'JOBLIST_SUBSET')
185+
string (
186+
defaultValue: '',
187+
description: 'Groovy regex for constraining a list of jobs to inspect (if not empty, then matching job names are excluded)',
188+
name: 'JOBLIST_EXCLUDE')
189+
string (
190+
defaultValue: '',
191+
description: 'If not empty, look for the regex match in labels you want as offending jobs (e.g. who wants "master" directly?)',
192+
name: 'LABEL_REGEX')
193+
}
194+
stages {
195+
stage('Single-exec milestone') {
196+
steps {
197+
milestone 1
198+
} // steps clause
199+
}
200+
}
201+
}
202+
203+
// Non-declarative pipeline payload.
204+
// This code below does not work inside a pipeline{} stage{}
205+
// clause nor in the post{} clause - not even with the added
206+
// try/catches for exceptions all around.
207+
// Curiously, when this pipeline job is built by hand
208+
// or triggered by timer, it fails with lots of CPS and
209+
// marshalling exception messages in the end. Replaying
210+
// the same groovy script with no changes just works.
211+
try {
212+
if ( params.LABEL_REGEX.equals("") ) {
213+
echo "DISCOVERING JOBS with no label assigned..."
214+
} else {
215+
echo "DISCOVERING JOBS with an assigned matching regex: '" + params.LABEL_REGEX + "' ..."
216+
}
217+
echo "Note: to hide `[Pipeline] echo` from console logs, add this tweak in the browser debug console to the run-time CSS: .pipeline-new-node { display: none; }"
218+
(status, list) = inspectJobs( "${params.JOBLIST_VERBOSE}", "${params.JOBLIST_SUBSET}", "${params.JOBLIST_EXCLUDE}", "${params.LABEL_REGEX}" )
219+
if (!status) {
220+
if ( params.LABEL_REGEX.equals("") ) {
221+
echo "FATAL : Some enabled jobs do not have a label: " + list
222+
manager.addShortText("Some enabled jobs do not have a label")
223+
currentBuild.result = 'FAILED'
224+
manager.buildFailed()
225+
} else {
226+
echo "FATAL : Some enabled jobs had hit a custom label regex: '" + params.LABEL_REGEX + "' : " + list
227+
manager.addShortText("Some enabled jobs did hit a custom label during manual lookup")
228+
currentBuild.result = 'UNSTABLE'
229+
manager.buildUnstable()
230+
}
231+
} else {
232+
if ( params.LABEL_REGEX.equals("") ) {
233+
echo "SUCCESS : Did not find any enabled jobs without a label"
234+
manager.addShortText("None of the enabled jobs had no label configured")
235+
} else {
236+
echo "SUCCESS/WARNING? : Did not find any enabled jobs with a label that matches regex: '" + params.LABEL_REGEX + "'"
237+
manager.addShortText("None of the enabled jobs had hit a custom label during manual lookup")
238+
}
239+
}
240+
} catch (java.io.NotSerializableException e) {
241+
echo "Ignoring NotSerializableException during inspectJobs(), a groovy/JenkinsDSL thing"
242+
} catch (Exception e) {
243+
echo "Failed to find jobs or set up their scans: " + e
244+
currentBuild.result = 'ABORTED'
245+
manager.buildAborted()
246+
}

0 commit comments

Comments
 (0)