Skip to content

Commit

Permalink
Merge pull request #53 from oleg-nenashev/feature/JENKINS-48711
Browse files Browse the repository at this point in the history
[JENKINS-48711] - Create a Docker Image for running PCT
  • Loading branch information
oleg-nenashev committed Jan 13, 2018
2 parents 3693244 + 0aa1980 commit d130923
Show file tree
Hide file tree
Showing 10 changed files with 355 additions and 13 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -14,3 +14,4 @@ reports
work/
^jenkins/
.idea
out
61 changes: 61 additions & 0 deletions Dockerfile
@@ -0,0 +1,61 @@
# The MIT License
#
# Copyright (c) 2017 CloudBees, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

FROM maven:3.5.2-jdk-8
LABEL Description="Base image for running Jenkins Plugin Compat Tester (PCT) against custom plugins and Jenkins cores" Vendor="Jenkins project"

# Mode 1. Copy local artifact
# Local build (uncomment and remove the section below if needed)
COPY plugins-compat-tester-cli/target/plugins-compat-tester-cli-*.jar /pct/pct-cli.jar

# Mode 2. Build artifact from sources in Docker
# Use this flow if you do not want to build the binary on a local machine
# This mode is ineffective from the container size PoV and the layer number
# https://issues.jenkins-ci.org/browse/INFRA-1447
# Copy sources
#COPY plugins-compat-tester/ /pct/src/plugins-compat-tester/
#COPY plugins-compat-tester-cli/ /pct/src/plugins-compat-tester-cli/
#COPY plugins-compat-tester-gae/ /pct/src/plugins-compat-tester-gae/
#COPY plugins-compat-tester-gae-client/ /pct/src/plugins-compat-tester-gae-client/
#COPY plugins-compat-tester-model/ /pct/src/plugins-compat-tester-model/
#COPY *.xml /pct/src/
#COPY LICENSE.txt /pct/src/LICENSE.txt

#WORKDIR /pct/src/
#RUN mvn clean install -DskipTests && cp plugins-compat-tester-cli/target/plugins-compat-tester-cli-*.jar /pct/pct-cli.jar && mvn clean && mvn dependency:purge-local-repository

ENV JENKINS_WAR_PATH=/pct/jenkins.war
ENV PCT_OUTPUT_DIR=/pct/out
ENV PCT_TMP=/pct/tmp

COPY src/main/docker/run-pct.sh /usr/local/bin/run-pct
COPY src/main/docker/pct-default-settings.xml /pct/default-m2-settings.xml

EXPOSE 5005

VOLUME /pct/plugin-src
VOLUME /pct/jenkins.war
VOLUME /pct/out
VOLUME /pct/tmp
VOLUME /pct/m2-settings.xml
VOLUME /root/.m2
ENTRYPOINT ["run-pct"]
16 changes: 16 additions & 0 deletions Makefile
@@ -0,0 +1,16 @@
#Makefile

.PHONY: all
all: clean package docker

.PHONY: clean
clean:
mvn clean

.PHONY: package
package:
mvn package verify

.PHONY: docker
docker:
docker build -t jenkins/pct .
96 changes: 95 additions & 1 deletion README.md
@@ -1,7 +1,101 @@
Generate a compatibility matrix for plugins against Jenkins core.
Plugin Compatibility Tester (PCT)
------

Generates a compatibility matrix for plugins against Jenkins core.

See https://wiki.jenkins-ci.org/display/JENKINS/Plugin+Compatibility+Tester for background.

## Running PCT

### Running PCT in Docker

It is recommended to run PCT in the prepared Docker image.
You can find it [here](hub.docker.com/r/jenkins/pct/).

#### Examples

This command will clone of a repository and run PCT against the latest Jenkins Core:

```shell
docker run --rm -v maven-repo:/root/.m2 -v $(pwd)/out:/pct/out -e ARTIFACT_ID=ssh-slaves -e VERSION=ssh-slaves-1.24 jenkins/pct
```

This command will run PCT for the latest plugin version against the specified Jenkins WAR.
PCT supports running against SNAPSHOT builds, but PCT will have to install local Maven artifacts in such case.

```shell
docker run --rm -v maven-repo:/root/.m2 -v $(pwd)/out:/pct/out -v my/jenkins.war:/pct/jenkins.war:ro -e ARTIFACT_ID=ssh-slaves jenkins/pct
```

This command will run PCT against custom versions of Jenkins and the plugin specified by volumes.

```shell
docker run --rm -v maven-repo:/root/.m2 -v $(pwd)/out:/pct/out -v my/jenkins.war:/pct/jenkins.war:ro -v my/plugin:/pct/plugin-src:ro jenkins/pct
```

The command below will run PCT for a branch in a custom repository.

```shell
docker run --rm -v maven-repo:/root/.m2 -v $(pwd)/out:/pct/out -e CHECKOUT_SRC=https://github.com/oleg-nenashev/job-restrictions-plugin.git -e VERSION=JENKINS-26374 jenkins/pct
```

#### Configuration

Environment variables:

* `ARTIFACT_ID` - ID of the artifact to be tested.
The image will be able to determine this ID automatically if `CHECKOUT_SRC` or `/pct/plugin-src` are defined.
* `VERSION` - tag/commit/branch to be checked out and tested. `master` by default
* `CHECKOUT_SRC` - Custom Git clone source (e.g. `https://github.com/oleg-nenashev/job-restrictions-plugin.git`). `https://github.com/jenkinsci/${ARTIFACT_ID}-plugin.git` by default
* `JAVA_OPTS` - Java options to be passed to the PCT CLI
* `DEBUG` - Boolean flag, which enables the Remote Debug mode (port == 5000)

Volumes:

* `/pct/plugin-src` - Plugin sources to be used for the PCT run. Sources will be checked out if not specified
* `/pct/jenkins.war` - Jenkins WAR file to be used for the PCT run
* `/pct/m2-settings.xml` - Custom Maven Settings file (optional)
* `/pct/out` - Output directory for PCT. All reports will be stored there
* `/pct/tmp` - Temporary directory. Can be exposed to analyze run failures
* `/root/.m2` - Maven repository. It can be used to pass settings.xml or to cache artifacts

### Running PCT manually

PCT offers the CLI interface which can be used to run PCT locally.

* Download `PCT` and execute `mvn clean install`
* Download plugin sources to a `PLUGIN_SRC` directory.
* Checkout the plugin repo to a tag/commit/branch you want to test
* Run `mvn clean install -DskipTests` to initialize artifacts
* Go to `PCT` folder and run the CLI (make sure to modify paths according to your system). Example:

```shell
java -jar plugins-compat-tester-cli/target/plugins-compat-tester-cli-${PCT_VERSION}.jar \
-reportFile $(pwd)/out/report.xml \
-workDirectory $(pwd)/tmp/work \
-includePlugins ${PLUGIN_ARTIFACT_ID} \
-war jenkins.war localCheckoutDir ${PLUGIN_SRC} \
-skipTestCache true \
-mvn ${PATH_TO_MAVEN}
```

You can run the CLI with the `-help` argument to get a full list of supported options.

:exclamation: For the moment testing more than one plugin at once requires plugins to be released, so for testing SNAPSHOTS you need to execute the last step for every plugin you want to test*

## Developer Info

### Debugging PCT in Docker

If you need to debug a dockerized PCT instance,
use the `-e DEBUG=true -p 5005:5005` flags and then attach to the container using Remote Debugger in your IDE.

```
docker run --rm -v maven-repo:/root/.m2 -v $(pwd)/out:/pct/out -e ARTIFACT_ID=job-restrictions -e DEBUG=true -p 5005:5005 -i jenkins/pct
```

### TODOs

To do (refile in `plugin-compat-tester` in JIRA!):

1. `InternalMavenRunner` currently still seems to run `install` goal which is very undesirable on release tags
Expand Down
Expand Up @@ -107,6 +107,9 @@ public class CliOptions {
@Parameter(names="-localCheckoutDir", description = "Folder containing either a local (possibly modified) clone of a plugin repository or a set of local clone of different plugins")
private String localCheckoutDir;

@Parameter(names="-help", description = "Print this help message")
private boolean printHelp;

public String getUpdateCenterUrl() {
return updateCenterUrl;
}
Expand Down Expand Up @@ -175,4 +178,7 @@ public String getLocalCheckoutDir() {
return localCheckoutDir;
}

public boolean isPrintHelp() {
return printHelp;
}
}
Expand Up @@ -56,6 +56,11 @@ public static void main(String[] args) throws IOException, PlexusContainerExcept
System.exit(1);
}

if (options.isPrintHelp()) {
jcommander.usage();
System.exit(0);
}

options.getWorkDirectory().mkdirs();

File reportFile = null;
Expand Down
Expand Up @@ -141,13 +141,20 @@ public boolean isCompatTestResultAlreadyInCache(PluginInfos pluginInfos, MavenCo
return (!resultCorrespondingToGivenCoreCoords.status.isLowerThan(cacheThresholdStatus));
}

public static PluginCompatReport fromXml(File reportPath) {
/**
* Reads a compat report
* @param reportPath Report file path
* @return Report. If the file does not exist, an empty report will be returned
* @throws IOException Unexpected read error.
*/
@Nonnull
public static PluginCompatReport fromXml(File reportPath) throws IOException {
PluginCompatReport report = null;

// Reading report file from reportPath
XStream xstream = createXStream();
try {
report = (PluginCompatReport)xstream.fromXML(new FileInputStream(reportPath));
try(FileInputStream istream = new FileInputStream(reportPath)) {
report = (PluginCompatReport)xstream.fromXML(istream);
} catch (FileNotFoundException e) {
// Path doesn't exist => create a new report object
report = new PluginCompatReport();
Expand Down
Expand Up @@ -73,6 +73,7 @@
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -351,17 +352,23 @@ && new VersionNumber(coreCoordinates.version).compareTo(new VersionNumber("1.485
}

private void generateHtmlReportFile() throws IOException {
if (!config.reportFile.exists() || !config.reportFile.isFile()) {
throw new FileNotFoundException("Cannot find the XML report file: " + config.reportFile);
}

Source xmlSource = new StreamSource(config.reportFile);
Source xsltSource = new StreamSource(getXslTransformerResource().getInputStream());
Result result = new StreamResult(PluginCompatReport.getHtmlFilepath(config.reportFile));
try(InputStream xsltStream = getXslTransformerResource().getInputStream()) {
Source xsltSource = new StreamSource(xsltStream);
Result result = new StreamResult(PluginCompatReport.getHtmlFilepath(config.reportFile));

TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = null;
try {
transformer = factory.newTransformer(xsltSource);
transformer.transform(xmlSource, result);
} catch (TransformerException e) {
throw new RuntimeException(e);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = null;
try {
transformer = factory.newTransformer(xsltSource);
transformer.transform(xmlSource, result);
} catch (TransformerException e) {
throw new RuntimeException(e);
}
}
}

Expand Down
34 changes: 34 additions & 0 deletions src/main/docker/pct-default-settings.xml
@@ -0,0 +1,34 @@
<settings>
<pluginGroups>
<pluginGroup>org.jenkins-ci.tools</pluginGroup>
</pluginGroups>

<profiles>
<!-- Give access to Jenkins plugins -->
<profile>
<id>jenkins</id>
<activation>
<activeByDefault>true</activeByDefault> <!-- change this to false, if you don't like to have it on per default -->
</activation>
<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>
</profile>
</profiles>
<mirrors>
<mirror>
<id>repo.jenkins-ci.org</id>
<url>https://repo.jenkins-ci.org/public/</url>
<mirrorOf>m.g.o-public</mirrorOf>
</mirror>
</mirrors>
</settings>

0 comments on commit d130923

Please sign in to comment.