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:
Denis 2018-01-13 19:57:53 +03:00 committed by maibin
parent 6f3710b9ae
commit cd4b526789
4 changed files with 252 additions and 0 deletions

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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";
}
}
}

View File

@ -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>