/*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi,
* Erik Ramfelt, Koichi Fujikawa, Red Hat, Inc., Seiji Sogabe,
* Stephen Connolly, Tom Huybrechts, Yahoo! Inc., Alan Harder, 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.
*/
package org.jenkins.tools.test.model;
import org.apache.tools.ant.filters.StringInputStream;
import org.jenkins.tools.test.exception.PluginSourcesUnavailableException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.xml.xpath.XPath;
/**
* Utility class providing business for retrieving plugin scm data
* @author Frederic Camblor
*/
public class PluginRemoting {
private String hpiRemoteUrl;
public PluginRemoting(String hpiRemoteUrl){
this.hpiRemoteUrl = hpiRemoteUrl;
}
private String retrievePomContent() throws PluginSourcesUnavailableException{
try {
URL pluginUrl = new URL(hpiRemoteUrl);
ZipInputStream zin = new ZipInputStream(pluginUrl.openStream());
ZipEntry zipEntry = zin.getNextEntry();
while(!zipEntry.getName().startsWith("META-INF/maven") || !zipEntry.getName().endsWith("pom.xml")){
zin.closeEntry();
zipEntry = zin.getNextEntry();
}
StringBuilder sb = new StringBuilder();
byte[] buf = new byte[1024];
int n;
while ((n = zin.read(buf, 0, 1024)) > -1)
sb.append(new String(buf, 0, n));
String content = sb.toString();
return content;
}catch(Exception e){
System.err.println("Error : " + e.getMessage());
throw new PluginSourcesUnavailableException("Problem while retrieving pom content in hpi !", e);
}
}
public PomData retrievePomData() throws PluginSourcesUnavailableException {
String scmConnection = null;
String artifactId = null;
String pomContent = this.retrievePomContent();
MavenCoordinates parent;
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
Document doc = builder.parse(new StringInputStream(pomContent));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
XPathExpression scmConnectionXPath = xpath.compile("/project/scm/connection/text()");
XPathExpression artifactIdXPath = xpath.compile("/project/artifactId/text()");
scmConnection = (String)scmConnectionXPath.evaluate(doc, XPathConstants.STRING);
artifactId = (String)artifactIdXPath.evaluate(doc, XPathConstants.STRING);
parent = new MavenCoordinates(xpath.evaluate("/project/parent/groupId/text()", doc), xpath.evaluate("/project/parent/artifactId/text()", doc), xpath.evaluate("/project/parent/version/text()", doc));
} catch (ParserConfigurationException e) {
System.err.println("Error : " + e.getMessage());
throw new PluginSourcesUnavailableException("Problem during pom.xml parsing", e);
} catch (SAXException e) {
System.err.println("Error : " + e.getMessage());
throw new PluginSourcesUnavailableException("Problem during pom.xml parsing", e);
} catch (IOException e) {
System.err.println("Error : " + e.getMessage());
throw new PluginSourcesUnavailableException("Problem during pom.xml parsing", e);
} catch (XPathExpressionException e) {
System.err.println("Error : " + e.getMessage());
throw new PluginSourcesUnavailableException("Problem while retrieving plugin's scm connection", e);
}
PomData pomData = new PomData(artifactId, scmConnection, parent);
computeScmConnection(pomData);
return pomData;
}
public static void computeScmConnection(PomData pomData) {
String transformedConnectionUrl = pomData.getConnectionUrl();
// Triming url
transformedConnectionUrl = transformedConnectionUrl.trim();
// Generally, when connectionUrl is empty, is implies it is declared in a parent pom
// => Only possibility is to deduct github repository from artifactId (crossing fingers it is not
// a bizarre repository url...)
String oldUrl = transformedConnectionUrl;
if(transformedConnectionUrl.isEmpty()){
transformedConnectionUrl = "scm:git:git://github.com/jenkinsci/"+pomData.artifactId.replaceAll("jenkins", "")+"-plugin.git";
if(!oldUrl.equals(transformedConnectionUrl)){
pomData.getWarningMessages().add("project.scm.connectionUrl is not present in plugin's pom .. isn't it residing somewhere on a parent pom ?");
}
}
// Java.net SVN migration
oldUrl = transformedConnectionUrl;
transformedConnectionUrl = transformedConnectionUrl.replaceAll("(svn|hudson)\\.dev\\.java\\.net/svn/hudson/", "svn.java.net/svn/hudson~svn/");
if(!oldUrl.equals(transformedConnectionUrl)){
pomData.getWarningMessages().add("project.scm.connectionUrl is pointing to svn.dev.java.net/svn/hudson/ instead of svn.java.net/svn/hudson~svn/");
}
// ${project.artifactId}
transformedConnectionUrl = transformedConnectionUrl.replaceAll("\\$\\{project\\.artifactId\\}", pomData.artifactId);
// github url like [https://]<username>@github.com/...
// => Replaced by git://github.com/...
/* Do not change this; it was actually correct if the repo was non-public.
oldUrl = transformedConnectionUrl;
transformedConnectionUrl = transformedConnectionUrl.replaceAll("(http(s)?://)?[^@:]+@github\\.com", "git://github.com");
if(!oldUrl.equals(transformedConnectionUrl)){
pomData.getWarningMessages().add("project.scm.connectionUrl is using a github account instead of a read-only url git://github.com/...");
}
*/
//Convert things like scm:git:git://git@github.com:jenkinsci/dockerhub-notification-plugin.git
oldUrl = transformedConnectionUrl;
transformedConnectionUrl = transformedConnectionUrl.replaceAll("scm:git:git://git@github\\.com:jenkinsci", "scm:git:git://github.com/jenkinsci");
if(!oldUrl.equals(transformedConnectionUrl)){
pomData.getWarningMessages().add("project.scm.connectionUrl should should be accessed in read-only mode (with git:// protocol)");
}
oldUrl = transformedConnectionUrl;
transformedConnectionUrl = transformedConnectionUrl.replaceAll("://github\\.com[^/]", "://github.com/");
if(!oldUrl.equals(transformedConnectionUrl)){
pomData.getWarningMessages().add("project.scm.connectionUrl should have a '/' after the github.com url");
}
oldUrl = transformedConnectionUrl;
transformedConnectionUrl = transformedConnectionUrl.replaceAll("((ssh)|(http(s)?))://github\\.com", "git://github.com");
if(!oldUrl.equals(transformedConnectionUrl)){
pomData.getWarningMessages().add("project.scm.connectionUrl should be accessed in read-only mode (with git:// protocol)");
}
oldUrl = transformedConnectionUrl;
transformedConnectionUrl = transformedConnectionUrl.replaceAll("://github\\.com/hudson/", "://github.com/jenkinsci/");
if(!oldUrl.equals(transformedConnectionUrl)){
pomData.getWarningMessages().add("project.scm.connectionUrl should not reference hudson project anymore (no plugin repository there))");
}
// Just fixing some scm-sync-configuration issues...
// TODO: remove this when fixed !
oldUrl = transformedConnectionUrl;
if("scm-sync-configuration".equals(pomData.artifactId)){
transformedConnectionUrl = transformedConnectionUrl.substring(0, transformedConnectionUrl.length()-4)+"-plugin.git";
}
if(!oldUrl.equals(transformedConnectionUrl)){
pomData.getWarningMessages().add("project.scm.connectionUrl should be ending with '-plugin.git'");
}
oldUrl = transformedConnectionUrl;
transformedConnectionUrl = transformedConnectionUrl.replace("git.cloudbees.com", "github.com");
if (!oldUrl.equals(transformedConnectionUrl)) {
pomData.getWarningMessages().add("project.scm.connectionUrl was using git.cloudbees.com; moved to GitHub");
}
pomData.setConnectionUrl(transformedConnectionUrl);
}
}