BAEL-1451 Writing a Jenkins plugin (#3396)
* BAEL-1451 Writing a Jenkins plugin A sample Jenkins plugin which builds basic project stats * BAEL-1451 Writing a Jenkins plugin Formatting
This commit is contained in:
parent
6f3710b9ae
commit
cd4b526789
|
@ -0,0 +1,89 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.jenkins-ci.plugins</groupId>
|
||||||
|
<artifactId>plugin</artifactId>
|
||||||
|
<version>2.33</version>
|
||||||
|
<relativePath />
|
||||||
|
</parent>
|
||||||
|
<artifactId>jenkins-hello-world</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>hpi</packaging>
|
||||||
|
<properties>
|
||||||
|
<!-- Baseline Jenkins version you use to build the plugin. Users must have this version or newer to run. -->
|
||||||
|
<jenkins.version>2.7.3</jenkins.version>
|
||||||
|
</properties>
|
||||||
|
<name>Hello World Plugin</name>
|
||||||
|
<description>A sample Jenkins Hello World plugin</description>
|
||||||
|
<url>https://wiki.jenkins-ci.org/display/JENKINS/TODO+Plugin</url>
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>MIT License</name>
|
||||||
|
<url>http://opensource.org/licenses/MIT</url>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jenkins-ci.plugins</groupId>
|
||||||
|
<artifactId>structs</artifactId>
|
||||||
|
<version>1.7</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||||
|
<artifactId>workflow-step-api</artifactId>
|
||||||
|
<version>2.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||||
|
<artifactId>workflow-cps</artifactId>
|
||||||
|
<version>2.39</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||||
|
<artifactId>workflow-job</artifactId>
|
||||||
|
<version>2.11.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||||
|
<artifactId>workflow-basic-steps</artifactId>
|
||||||
|
<version>2.6</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||||
|
<artifactId>workflow-durable-task-step</artifactId>
|
||||||
|
<version>2.13</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||||
|
<artifactId>workflow-api</artifactId>
|
||||||
|
<version>2.20</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||||
|
<artifactId>workflow-support</artifactId>
|
||||||
|
<version>2.14</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>repo.jenkins-ci.org</id>
|
||||||
|
<url>https://repo.jenkins-ci.org/public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>repo.jenkins-ci.org</id>
|
||||||
|
<url>https://repo.jenkins-ci.org/public/</url>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
</project>
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.baeldung.jenkins.helloworld;
|
||||||
|
|
||||||
|
public class ProjectStats {
|
||||||
|
|
||||||
|
private final int classesNumber;
|
||||||
|
private final int linesNumber;
|
||||||
|
|
||||||
|
public ProjectStats(int classesNumber, int linesNumber) {
|
||||||
|
this.classesNumber = classesNumber;
|
||||||
|
this.linesNumber = linesNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClassesNumber() {
|
||||||
|
return classesNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLinesNumber() {
|
||||||
|
return linesNumber;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
package com.baeldung.jenkins.helloworld;
|
||||||
|
|
||||||
|
import hudson.Extension;
|
||||||
|
import hudson.FilePath;
|
||||||
|
import hudson.Launcher;
|
||||||
|
import hudson.model.AbstractBuild;
|
||||||
|
import hudson.model.AbstractProject;
|
||||||
|
import hudson.model.BuildListener;
|
||||||
|
import hudson.tasks.BuildWrapper;
|
||||||
|
import hudson.tasks.BuildWrapperDescriptor;
|
||||||
|
import org.kohsuke.stapler.DataBoundConstructor;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
public class ProjectStatsBuildWrapper extends BuildWrapper {
|
||||||
|
|
||||||
|
private static final String REPORT_TEMPLATE_PATH = "/stats.html";
|
||||||
|
private static final String PROJECT_NAME_VAR = "$PROJECT_NAME$";
|
||||||
|
private static final String CLASSES_NUMBER_VAR = "$CLASSES_NUMBER$";
|
||||||
|
private static final String LINES_NUMBER_VAR = "$LINES_NUMBER$";
|
||||||
|
|
||||||
|
@DataBoundConstructor
|
||||||
|
public ProjectStatsBuildWrapper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Environment setUp(AbstractBuild build, final Launcher launcher, BuildListener listener) {
|
||||||
|
return new Environment() {
|
||||||
|
@Override
|
||||||
|
public boolean tearDown(AbstractBuild build, BuildListener listener)
|
||||||
|
throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
ProjectStats stats = buildStats(build.getWorkspace());
|
||||||
|
String report = generateReport(build.getProject().getDisplayName(), stats);
|
||||||
|
File artifactsDir = build.getArtifactsDir();
|
||||||
|
if (!artifactsDir.isDirectory()) {
|
||||||
|
boolean success = artifactsDir.mkdirs();
|
||||||
|
if (!success) {
|
||||||
|
listener.getLogger().println("Can't create artifacts directory at "
|
||||||
|
+ artifactsDir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String path = artifactsDir.getCanonicalPath() + REPORT_TEMPLATE_PATH;
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path),
|
||||||
|
StandardCharsets.UTF_8))) {
|
||||||
|
writer.write(report);
|
||||||
|
}
|
||||||
|
return super.tearDown(build, listener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProjectStats buildStats(FilePath root) throws IOException, InterruptedException {
|
||||||
|
int classesNumber = 0;
|
||||||
|
int linesNumber = 0;
|
||||||
|
Stack<FilePath> toProcess = new Stack<>();
|
||||||
|
toProcess.push(root);
|
||||||
|
while (!toProcess.isEmpty()) {
|
||||||
|
FilePath path = toProcess.pop();
|
||||||
|
if (path.isDirectory()) {
|
||||||
|
toProcess.addAll(path.list());
|
||||||
|
} else if (path.getName().endsWith(".java")) {
|
||||||
|
classesNumber++;
|
||||||
|
linesNumber += countLines(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ProjectStats(classesNumber, linesNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int countLines(FilePath path) throws IOException, InterruptedException {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int result = 1;
|
||||||
|
try (InputStream in = path.read()) {
|
||||||
|
while (true) {
|
||||||
|
int read = in.read(buffer);
|
||||||
|
if (read < 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < read; i++) {
|
||||||
|
if (buffer[i] == '\n') {
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String generateReport(String projectName, ProjectStats stats) throws IOException {
|
||||||
|
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||||
|
try (InputStream in = ProjectStatsBuildWrapper.class.getResourceAsStream(REPORT_TEMPLATE_PATH)) {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int read;
|
||||||
|
while ((read = in.read(buffer)) >= 0) {
|
||||||
|
bOut.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String content = new String(bOut.toByteArray(), StandardCharsets.UTF_8);
|
||||||
|
content = content.replace(PROJECT_NAME_VAR, projectName);
|
||||||
|
content = content.replace(CLASSES_NUMBER_VAR, String.valueOf(stats.getClassesNumber()));
|
||||||
|
content = content.replace(LINES_NUMBER_VAR, String.valueOf(stats.getLinesNumber()));
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Extension
|
||||||
|
public static final class DescriptorImpl extends BuildWrapperDescriptor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(AbstractProject<?, ?> item) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return "Construct project stats during build";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>$PROJECT_NAME$</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Project $PROJECT_NAME$:
|
||||||
|
<table border="1">
|
||||||
|
<tr>
|
||||||
|
<th>Classes number</th>
|
||||||
|
<th>Lines number</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>$CLASSES_NUMBER$</td>
|
||||||
|
<td>$LINES_NUMBER$</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue