Skip to content

Commit b1d7a80

Browse files
committed
Added Support for Multi-Configuration/Matrix Job and artifacts handling
1 parent a8fcb9f commit b1d7a80

File tree

2 files changed

+93
-45
lines changed

2 files changed

+93
-45
lines changed

src/main/java/com/browserstack/automate/ci/jenkins/qualityDashboard/QualityDashboardInit.java

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
import hudson.Extension;
1010
import hudson.init.InitMilestone;
1111
import hudson.init.Initializer;
12+
import hudson.model.Job;
1213
import hudson.model.Result;
14+
import hudson.model.Run;
1315
import java.sql.Timestamp;
1416
import java.time.Instant;
1517
import jenkins.model.Jenkins;
1618
import okhttp3.*;
1719
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
18-
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
1920
import java.time.temporal.ChronoUnit;
2021
import java.io.IOException;
2122
import java.net.HttpURLConnection;
@@ -114,26 +115,32 @@ private static List<String> getAllPipelines(BrowserStackCredentials browserStack
114115
totalPipelines = jenkins.getAllItems().size();
115116
jenkins.getAllItems().forEach(job -> {
116117
try {
118+
String jobType = job.getClass().getSimpleName();
119+
boolean isWorkflowJob = job instanceof WorkflowJob;
120+
117121
// Logging job details
118122
apiUtil.logToQD(
119123
browserStackCredentials,
120124
String.format(
121125
"Job name: %s, instance type: %s, and is_workflow_job: %s",
122126
job.getName(),
123-
job.getClass().getSimpleName(),
124-
(job instanceof WorkflowJob) ? "yes" : "no"
127+
jobType,
128+
isWorkflowJob ? "yes" : "no"
125129
)
126130
);
131+
if ( job instanceof Job) {
132+
String pipelineName = job.getFullName();
133+
allPipelines.add(pipelineName);
134+
}
135+
else{
136+
apiUtil.logToQD(browserStackCredentials, "Skipping job: " + job.getName() + " as it is not a Job instance");
137+
}
138+
127139
} catch (JsonProcessingException e) {
128140
// Handling the exception and logging an error
129141
System.err.println("Error processing JSON for job: " + job.getName());
130142
e.printStackTrace();
131143
}
132-
133-
if (job instanceof WorkflowJob) {
134-
String pipelineName = job.getFullName(); // Getting pipeline name
135-
allPipelines.add(pipelineName);
136-
}
137144
});
138145
} else {
139146
try {
@@ -188,10 +195,12 @@ private static List<PipelineDetails> getAllBuilds(BrowserStackCredentials browse
188195
Jenkins jenkins = Jenkins.getInstanceOrNull();
189196
Instant thresholdInstant = Instant.now().minus(getHistoryForDays(browserStackCredentials), ChronoUnit.DAYS);
190197
if (jenkins != null) {
191-
jenkins.getAllItems().forEach(job -> {
192-
if (job instanceof WorkflowJob) {
198+
jenkins.getAllItems().forEach(item -> {
199+
// Support both WorkflowJob and Matrix projects (and potentially other job types)
200+
if (item instanceof Job) {
201+
Job<?, ?> job = (Job<?, ?>) item;
193202
String pipelineName = job.getFullName();
194-
List<WorkflowRun> allBuilds = ((WorkflowJob) job).getBuilds();
203+
List<? extends Run<?, ?>> allBuilds = job.getBuilds();
195204
if(!allBuilds.isEmpty()) {
196205
allBuilds.stream().filter(build -> Instant.ofEpochMilli(build.getTimeInMillis()).isAfter(thresholdInstant)).forEach(
197206
build -> {
@@ -265,9 +274,8 @@ private static int getHistoryForDays(BrowserStackCredentials browserStackCredent
265274
}
266275
} catch(IOException e) {
267276
e.printStackTrace();
268-
} finally {
269-
return no_of_days;
270277
}
278+
return no_of_days;
271279
}
272280

273281
private static int getProjectPageSize(BrowserStackCredentials browserStackCredentials) {
@@ -284,9 +292,8 @@ private static int getProjectPageSize(BrowserStackCredentials browserStackCreden
284292
}
285293
} catch(IOException e) {
286294
e.printStackTrace();
287-
} finally {
288-
return projectPageSize;
289295
}
296+
return projectPageSize;
290297
}
291298

292299
private static int getResultPageSize(BrowserStackCredentials browserStackCredentials) {
@@ -303,9 +310,8 @@ private static int getResultPageSize(BrowserStackCredentials browserStackCredent
303310
}
304311
} catch(IOException e) {
305312
e.printStackTrace();
306-
} finally {
307-
return resultPageSize;
308313
}
314+
return resultPageSize;
309315
}
310316
}
311317

src/main/java/com/browserstack/automate/ci/jenkins/qualityDashboard/QualityDashboardPipelineTracker.java

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
import jenkins.model.Jenkins;
1313
import okhttp3.*;
1414
import org.apache.commons.io.FileUtils;
15-
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
16-
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
1715
import org.zeroturnaround.zip.ZipUtil;
1816

1917
import java.io.File;
@@ -26,39 +24,22 @@
2624
import java.sql.Timestamp;
2725

2826
@Extension
29-
public class QualityDashboardPipelineTracker extends RunListener<Run> {
27+
public class QualityDashboardPipelineTracker extends RunListener<Run<?, ?>> {
3028

3129
QualityDashboardAPIUtil apiUtil = new QualityDashboardAPIUtil();
3230

3331
@Override
34-
public void onCompleted(Run run, TaskListener listener) {
32+
public void onCompleted(Run<?, ?> run, TaskListener listener) {
3533
super.onCompleted(run, listener);
3634
BrowserStackCredentials browserStackCredentials = QualityDashboardUtil.getBrowserStackCreds();
3735
if(browserStackCredentials!=null) {
38-
WorkflowRun workflowRun = (WorkflowRun) run;
39-
WorkflowJob workflowJob = workflowRun.getParent();
40-
String jobName = workflowJob.getFullName();
36+
String jobName = getJobNameFromRun(run);
4137
int buildNumber = run.getNumber();
4238
try {
4339
if(isQDEnabled(browserStackCredentials) && isPipelineEnabledForQD(browserStackCredentials, jobName)) {
4440
Result overallResult = run.getResult();
4541
if(overallResult != null) {
46-
String qdS3Url = null;
47-
String finalPathToZip = getFinalZipPath(run, browserStackCredentials);
48-
apiUtil.logToQD(browserStackCredentials, "Final Computed Zip Path for jobName: " + jobName + " and buildNumber: " + buildNumber + " is: " + finalPathToZip);
49-
if(StringUtils.isNotEmpty(finalPathToZip)) {
50-
apiUtil.logToQD(browserStackCredentials, "Found artifacts in configured path for jobName: " + jobName + " and buildNumber: " + buildNumber);
51-
copyDirectoryToParentIfRequired(run, finalPathToZip, browserStackCredentials);
52-
qdS3Url = zipArtifactsAndUploadToQD(finalPathToZip, browserStackCredentials, jobName, buildNumber);
53-
} else if(run.getHasArtifacts()) {
54-
apiUtil.logToQD(browserStackCredentials, "No artifacts in configured path but found archive artifacts for jobName: " + jobName + " and buildNumber: " + buildNumber);
55-
finalPathToZip = run.getArtifactsDir().getAbsolutePath();
56-
apiUtil.logToQD(browserStackCredentials, "Got artifact path for jobName: " + jobName + " and buildNumber: " + buildNumber + " as: " + finalPathToZip);
57-
qdS3Url = zipArtifactsAndUploadToQD(finalPathToZip, browserStackCredentials, jobName, buildNumber);
58-
} else {
59-
apiUtil.logToQD(browserStackCredentials, "Finally no artifacts found for jobName: " + jobName + " and buildNumber: " + buildNumber);
60-
}
61-
sendBuildDataToQD(run, overallResult, qdS3Url, browserStackCredentials);
42+
processArtifactsAndSendData(run, overallResult, browserStackCredentials, jobName, buildNumber);
6243
} else {
6344
apiUtil.logToQD(browserStackCredentials, "Null Result Captured for jobName: " + jobName + " and buildNumber: " + buildNumber);
6445
}
@@ -74,6 +55,45 @@ public void onCompleted(Run run, TaskListener listener) {
7455
}
7556
}
7657

58+
59+
private void processArtifactsAndSendData(Run<?, ?> run, Result overallResult, BrowserStackCredentials browserStackCredentials,
60+
String jobName, int buildNumber) throws IOException {
61+
String qdS3Url = null;
62+
String finalPathToZip = getFinalZipPath(run, browserStackCredentials);
63+
64+
apiUtil.logToQD(browserStackCredentials, "Final Computed Zip Path for jobName: " + jobName + " and buildNumber: " + buildNumber + " is: " + finalPathToZip);
65+
66+
if(StringUtils.isNotEmpty(finalPathToZip)) {
67+
apiUtil.logToQD(browserStackCredentials, "Found artifacts in configured path for jobName: " + jobName + " and buildNumber: " + buildNumber);
68+
copyDirectoryToParentIfRequired(run, finalPathToZip, browserStackCredentials);
69+
qdS3Url = zipArtifactsAndUploadToQD(finalPathToZip, browserStackCredentials, jobName, buildNumber);
70+
} else if(run.getHasArtifacts()) {
71+
File artifactsDir = new File(run.getRootDir(), "archive");
72+
if (artifactsDir.exists() && artifactsDir.isDirectory()) {
73+
finalPathToZip = artifactsDir.getAbsolutePath();
74+
}
75+
if (finalPathToZip == null || !Files.exists(Paths.get(finalPathToZip))) {
76+
Jenkins jenkins = Jenkins.getInstanceOrNull();
77+
if (jenkins != null) {
78+
finalPathToZip = jenkins.getRootDir().getAbsolutePath() + "/archive/" + jobName + "/" + buildNumber;
79+
} else {
80+
apiUtil.logToQD(browserStackCredentials, "Jenkins instance is null, cannot access archived artifacts for jobName: " + jobName + " and buildNumber: " + buildNumber);
81+
finalPathToZip = null;
82+
}
83+
}
84+
if (StringUtils.isNotEmpty(finalPathToZip) && Files.exists(Paths.get(finalPathToZip))) {
85+
apiUtil.logToQD(browserStackCredentials, "Got artifact path for jobName: " + jobName + " and buildNumber: " + buildNumber + " as: " + finalPathToZip);
86+
qdS3Url = zipArtifactsAndUploadToQD(finalPathToZip, browserStackCredentials, jobName, buildNumber);
87+
} else {
88+
apiUtil.logToQD(browserStackCredentials, "Archive artifacts not found at expected path for jobName: " + jobName + " and buildNumber: " + buildNumber);
89+
finalPathToZip = null;
90+
}
91+
} else {
92+
apiUtil.logToQD(browserStackCredentials, "Finally no artifacts found for jobName: " + jobName + " and buildNumber: " + buildNumber);
93+
}
94+
sendBuildDataToQD(run, overallResult, qdS3Url, browserStackCredentials);
95+
}
96+
7797
private String zipArtifactsAndUploadToQD (String finalPathToZip, BrowserStackCredentials browserStackCredentials, String jobName, int buildNumber) throws IOException {
7898
String finalZipFilePath = packZip(finalPathToZip, jobName, browserStackCredentials);
7999
apiUtil.logToQD(browserStackCredentials, "Final zip file's path for jobName: " + jobName + " and buildNumber: " + buildNumber + " is:" + finalZipFilePath);
@@ -87,7 +107,7 @@ private String zipArtifactsAndUploadToQD (String finalPathToZip, BrowserStackCre
87107
return qdS3Url;
88108
}
89109

90-
private void sendBuildDataToQD(Run run, Result overallResult, String finalZipPath, BrowserStackCredentials browserStackCredentials) {
110+
private void sendBuildDataToQD(Run<?, ?> run, Result overallResult, String finalZipPath, BrowserStackCredentials browserStackCredentials) {
91111
Long pipelineDuration = getPipelineDuration(run);
92112
try {
93113
String jobName = run.getParent().getFullName();
@@ -128,7 +148,7 @@ private void sendBuildDataToQD(Run run, Result overallResult, String finalZipPat
128148
}
129149
}
130150

131-
private Long getPipelineDuration(Run build) {
151+
private Long getPipelineDuration(Run<?, ?> build) {
132152
long startTime = build.getStartTimeInMillis();
133153
long endTime = System.currentTimeMillis();
134154
long duration = (endTime - startTime) / 1000;
@@ -139,7 +159,7 @@ private boolean checkIfPathIsFound(String filePath) {
139159
Path path = Paths.get(filePath);
140160
return Files.exists(path) ? true : false;
141161
}
142-
private String getFinalZipPath(Run run, BrowserStackCredentials browserStackCredentials) throws JsonProcessingException {
162+
private String getFinalZipPath(Run<?, ?> run, BrowserStackCredentials browserStackCredentials) throws JsonProcessingException {
143163
String finalZipPath = null;
144164
String currentResultDir = getResultDirForPipeline(getUrlForPipeline(run), browserStackCredentials, run.getNumber());
145165
if(StringUtils.isNotEmpty(currentResultDir) && checkIfPathIsFound(currentResultDir)) {
@@ -155,7 +175,7 @@ private String getFinalZipPath(Run run, BrowserStackCredentials browserStackCred
155175
return finalZipPath;
156176
}
157177

158-
private String getDefaultWorkspaceDirectory(Run run) {
178+
private String getDefaultWorkspaceDirectory(Run<?, ?> run) {
159179
Jenkins jenkins = Jenkins.getInstanceOrNull();
160180
String workspacePath = jenkins != null && jenkins.getRootDir() != null ? jenkins.getRootDir().getAbsolutePath() : null;
161181
return StringUtils.isNotEmpty(workspacePath) ? workspacePath : null;
@@ -254,7 +274,7 @@ private String uploadZipToQd(String pathToZip, BrowserStackCredentials browserSt
254274
return qdS3Url;
255275
}
256276

257-
private void copyDirectoryToParentIfRequired(Run run, String finalParentPathFrom, BrowserStackCredentials browserStackCredentials) throws IOException {
277+
private void copyDirectoryToParentIfRequired(Run<?, ?> run, String finalParentPathFrom, BrowserStackCredentials browserStackCredentials) throws IOException {
258278
String finalParentPathTo = null;
259279
String upStreamProj = UpstreamPipelineResolver.resolveImmediateUpstreamProject(run, browserStackCredentials);
260280
if(StringUtils.isNotEmpty(upStreamProj)) {
@@ -281,6 +301,28 @@ private void copyDirectoryToParentIfRequired(Run run, String finalParentPathFrom
281301
}
282302
}
283303
}
304+
305+
private String getJobNameFromRun(Run<?, ?> run){
306+
try {
307+
// Check if parent is a Job (covers all job types)
308+
if (run.getParent() instanceof Job) {
309+
Job<?, ?> job = (Job<?, ?>) run.getParent();
310+
String jobName = job.getFullName();
311+
return jobName;
312+
} else {
313+
// Fallback for any other parent types
314+
String fallbackName = run.getParent().getFullName();
315+
return fallbackName;
316+
}
317+
} catch (Exception e) {
318+
try {
319+
apiUtil.logToQD(QualityDashboardUtil.getBrowserStackCreds(), "Error getting job name from run: " + e.getMessage());
320+
} catch (JsonProcessingException jsonEx) {
321+
jsonEx.printStackTrace();
322+
}
323+
}
324+
return null;
325+
}
284326
}
285327

286328
class QualityDashboardGetDetailsForPipeline implements Serializable {

0 commit comments

Comments
 (0)