In questo articolo vorrei esporre la mia idea su come, dato un elenco di build di un certo job, da jenkins leggere il numero di pipeline in esecuzione o nei diversi stati.
Per effettuare una chiamata REST a jenkins e recuperarne le informazioni è stato spiegato in questo articolo . In questo caso si tratta di eseguire una chiamata del tipo:
<JENKINS_URL>/job/<SOMEPIPELINE>/api/json?tree=allBuilds[id,timestamp,duration,result]&pretty=true
il cui endpoint è quello che ho voluto evidenziare in grassetto.
Questo tipo di chiamata restituisce una risposta come questa:
{
"_class" : "org.jenkinsci.plugins.workflow.job.WorkflowJob",
"allBuilds" : [
{
"_class" : "org.jenkinsci.plugins.workflow.job.WorkflowRun",
"duration" : 837491,
"id" : "46671",
"result" : null,
"timestamp" : 1647202842314
},
{
"_class" : "org.jenkinsci.plugins.workflow.job.WorkflowRun",
"duration" : 991915,
"id" : "46670",
"result" : "SUCCESS",
"timestamp" : 1647195253529
},
{
"_class" : "org.jenkinsci.plugins.workflow.job.WorkflowRun",
"duration" : 678418,
"id" : "46669",
"result" : "UNSTABLE",
"timestamp" : 1648292021523
},
{
"_class" : "org.jenkinsci.plugins.workflow.job.WorkflowRun",
"duration" : 646110,
"id" : "46668",
"result" : "FAILURE",
"timestamp" : 1648290252397
},
{
"_class" : "org.jenkinsci.plugins.workflow.job.WorkflowRun",
"duration" : 615499,
"id" : "46667",
"result" : "ABORTED",
"timestamp" : 1648290014257
},
{
"_class" : "org.jenkinsci.plugins.workflow.job.WorkflowRun",
"duration" : 538937,
"id" : "46666",
"result" : "ABORTED",
"timestamp" : 1648288902869
}
]
}
Analizzando il json possiamo capire che è formato da diversi record che contengono le informazioni che sono state richieste più una informazione aggiuntiva iniziale che poco ci interessa allo scopo.
Sappiamo che se la duration è pari a 0 significa che la build è ancora in corso; in questo caso abbiamo il valore "null" come risultato in quanto non è terminata la pipeline. In tutti gli altri casi possiamo conteggiare i diversi record in base al risultato.
Dobbiamo quindi capire come leggere il testo json con vbscript. Non esiste una funzione nativa in vbscript per leggere un json quindi dobbiamo ideare qualche metodo.
Possiamo intanto vedere che la struttura è ben definita, rigida e quindi ci torna utile. Vediamo ad esempio che, quelli che definisco record (possono essere visti anche come oggetti) sono racchiusi da una parentesi "[" aperta e una parentesi "]" chiusa, poi, all'interno di questo contesto, i singoli elementi sono racchiusi da parentesi "{" aperta e parentesi "}" chiusa. Possiamo quindi provare a sfruttare le regular expression, in particolare questi due pattern:
FirstPattern = "\[[\s\S]*?\]" <-- significa trova parentesi "[" aperta e la PRIMA parentesi "]" chiusa
SecondPattern= "\{[\w\W]*?\}" <-- stessa cosa ma per le parentesi "{ }"
In questa soluzione ho usato anche una classe per gestire le build. Ha un solo membro, un array multidimensionale di 4 righe ed n colonne.
Nel codice ho riportato il testo json, di cui sopra, in una variabile stringa. Eccolo:
'Class to manage all the element of the json file returns from the request to jenkins
Class BuildManager
Private theAllBuildsTag()
'Getter
Public Property Get allBld()
allBld = theAllBuildsTag
End Property
'Setter
Public Property Let allBld(data)
Dim arrData : arrData = split(data,"|")
Dim Lim1 : Lim1 = Ubound(theAllBuildsTag,2)
theAllBuildsTag(0, Lim1) = arrData(0)
theAllBuildsTag(1, Lim1) = arrData(1)
theAllBuildsTag(2, Lim1) = arrData(2)
theAllBuildsTag(3, Lim1) = arrData(3)
Lim1 = Lim1 + 1
'Using Preserve option it is possible to modify only last dimension of the multidimensional array
Redim Preserve theAllBuildsTag(3, Lim1)
'The matrix will be 4 x buildnumber with:
'at position 0: the Duration of all the builds
'at position 1: all the IDs
'at position 2: the Results of all the builds
'at position 3: the Timestamp of all the builds
'0,0 - 0,1 - 0,2 - 0,3 ... 0,n = Duration
'1,0 - 1,1 - 1,2 - 1,3 ... 1,n = IDs
'2,0 - 2,1 - 2,2 - 2,3 ... 2,n = Results
'3,0 - 3,1 - 3,2 - 3,3 ... 3,n = Timestamps
'so data of the single build must be read in vertical direction not in horizontal direction
End Property
' Parameterless Constructor
Public Sub Class_Initialize()
Redim theAllBuildsTag(3, 0)
End Sub
Public Sub Class_Terminate()
End Sub
'Function to retrieve the number of Running builds
Public Function NRunningBuild()
Dim intRes : intRes = 0
for i = 0 to Ubound(theAllBuildsTag,2) - 1
if theAllBuildsTag(0,i) = "0" then
intRes = intRes + 1
end if
next
NRunningBuild = intRes
End Function
'Function to retrieve the number of all the build in the state passed as arguments. For Example "SUCCESS", "FAILURE", "ABORTED", etc...
Public Function NStateBuild(state)
Dim intRes : intRes = 0
for i = 0 to Ubound(theAllBuildsTag,2) - 1
if theAllBuildsTag(2,i) = chr(34) & state & chr(34) then
intRes = intRes + 1
end if
next
NStateBuild = intRes
End Function
End Class
'******************************************************************************************************
'The simulation of a jenkins response and store it in a string variable
'strInp is for a test - it simulate a Jenkins response of:
'<JENKINS_URL>/job/<SOMEPIPELINE>/api/json?tree=allBuilds[id,timestamp,duration,result]&pretty=true
'******************************************************************************************************
dim strInp
strInp = "{" & chr(34) & _
"_class" & chr(34) & " : " & chr(34) & "org.jenkinsci.plugins.workflow.job.WorkflowJob" & chr(34) & "," & chr(34) & _
"allBuilds" & chr(34) & " : [ " & _
"{" & _
chr(34) & "_class" & chr(34) & " : " & chr(34) & "org.jenkinsci.plugins.workflow.job.WorkflowRun" & chr(34) & "," & _
chr(34) & "duration" & chr(34) & " : 0," & _
chr(34) & "id" & chr(34) & " : " & chr(34) & "46671" & chr(34) & "," & _
chr(34) & "result" & chr(34) & " : null," & _
chr(34) & "timestamp" & chr(34) & " : 1647202842314" & _
"}," & _
"{" & _
chr(34) & "_class" & chr(34) & " : " & chr(34) & "org.jenkinsci.plugins.workflow.job.WorkflowRun" & chr(34) & "," & _
chr(34) & "duration" & chr(34) & " : 991915," & _
chr(34) & "id" & chr(34) & " : " & chr(34) & "46670" & chr(34) & "," & _
chr(34) & "result" & chr(34) & " : " & chr(34) & "SUCCESS" & chr(34) & "," & _
chr(34) & "timestamp" & chr(34) & " : 1647195253529" & _
"}," & _
"{" & _
chr(34) & "_class" & chr(34) & " : " & chr(34) & "org.jenkinsci.plugins.workflow.job.WorkflowRun" & chr(34) & "," & _
chr(34) & "duration" & chr(34) & " : 678418," & _
chr(34) & "id" & chr(34) & " : " & chr(34) & "46669" & chr(34) & "," & _
chr(34) & "result" & chr(34) & " : " & chr(34) & "UNSTABLE" & chr(34) & "," & _
chr(34) & "timestamp" & chr(34) & " : 1648292021523" & _
"}," & _
"{" & _
chr(34) & "_class" & chr(34) & " : " & chr(34) & "org.jenkinsci.plugins.workflow.job.WorkflowRun" & chr(34) & "," & _
chr(34) & "duration" & chr(34) & " : 646110," & _
chr(34) & "id" & chr(34) & " : " & chr(34) & "46668" & chr(34) & "," & _
chr(34) & "result" & chr(34) & " : " & chr(34) & "FAILURE" & chr(34) & "," & _
chr(34) & "timestamp" & chr(34) & " : 1648290252397" & _
"}," & _
"{" & _
chr(34) & "_class" & chr(34) & " : " & chr(34) & "org.jenkinsci.plugins.workflow.job.WorkflowRun" & chr(34) & "," & _
chr(34) & "duration" & chr(34) & " : 615499," & _
chr(34) & "id" & chr(34) & " : " & chr(34) & "46667" & chr(34) & "," & _
chr(34) & "result" & chr(34) & " : " & chr(34) & "ABORTED" & chr(34) & "," & _
chr(34) & "timestamp" & chr(34) & " : 1648290014257" & _
"}," & _
"{" & _
chr(34) & "_class" & chr(34) & " : " & chr(34) & "org.jenkinsci.plugins.workflow.job.WorkflowRun" & chr(34) & "," & _
chr(34) & "duration" & chr(34) & " : 538937," & _
chr(34) & "id" & chr(34) & " : " & chr(34) & "46666" & chr(34) & "," & _
chr(34) & "result" & chr(34) & " : " & chr(34) & "ABORTED" & chr(34) & "," & _
chr(34) & "timestamp" & chr(34) & " : 1648288902869" & _
"}" & _
"]" & _
"}"
'******************************************************************************************************
' here is the MAIN that is only a series of call to the AnalyzeBuild sub
' to returns different number of builds filter by status
'******************************************************************************************************
AnalyzeBuild strInp, "RUNNING"
AnalyzeBuild strInp, "SUCCESS"
AnalyzeBuild strInp, "UNSTABLE"
AnalyzeBuild strInp, "FAILURE"
AnalyzeBuild strInp, "ABORTED"
' end of the MAIN
'******************************************************************************************************
'******************************************************************************************************
' the SUB that do the job
'******************************************************************************************************
Sub AnalyzeBuild(inpJson, state)
dim FirstPattern : FirstPattern = "\[[\s\S]*?\]"
dim SecondPattern: SecondPattern= "\{[\w\W]*?\}"
dim regEx : set regEx = CreateObject("VBScript.RegExp")
dim regEx2 : set regEx2 = CreateObject("VBScript.RegExp")
dim myRec, arrElements, dur, idR, resR, tmstmpR
dim oBM
with regEx
.Pattern = FirstPattern
.IgnoreCase = True
.Global = True
end with
if regEx.Test(inpJson) then
set colMatch = regEx.Execute(inpJson)
if colMatch.Count > 0 then
with regEx2
.Pattern = SecondPattern
.IgnoreCase = true
.Global = true
end with
if regEx2.Test(colMatch.Item(0).Value) then
set oBM = new BuildManager
set mtch2 = regEx2.Execute(colMatch.Item(0).Value)
if mtch2.Count > 0 then
for j=0 to mtch2.Count-1
myRec = mtch2.Item(j).Value
arrElements = split(myRec, ",")
dur = split(arrElements(1)," : ")(1)
idR = split(arrElements(2)," : ")(1)
resR = split(arrElements(3)," : ")(1)
tmstmpR = left(split(arrElements(4)," : ")(1), len(split(arrElements(4)," : ")(1)) - 1)
oBM.allBld = dur & "|" & idR & "|" & resR & "|" & tmstmpR
next
end if
end if
end if
end if
Select Case state
case "RUNNING":
msgbox "The number of RUNNING builds are: " & oBM.NRunningBuild
case else:
msgbox "The number of " & state & " builds are: " & oBM.NStateBuild(state)
End Select
End Sub
'******************************************************************************************************
Questo codice può essere copiato, salvato come file vbs ed eseguito. Verranno visualizzate diversi popup che indicano il numero di build nei diversi stati.