<|start_filename|>src/main/java/org/jenkinsci/plugins/jenkinsreviewbot/ReviewboardNote.java<|end_filename|>
/*
Copyright (c) 2013 VMware, Inc. All Rights Reserved.

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.jenkinsci.plugins.jenkinsreviewbot;

import hudson.Extension;
import hudson.MarkupText;
import hudson.console.ConsoleAnnotationDescriptor;
import hudson.console.ConsoleAnnotator;
import hudson.console.ConsoleNote;
import hudson.model.AbstractBuild;
import hudson.model.ParametersAction;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * User: ymeymann
 * Date: 6/5/13 4:48 PM
 */
public class ReviewboardNote extends ConsoleNote {
  private final int length;

  public ReviewboardNote(int length) {
    this.length = length;
  }

  @Override
  public ConsoleAnnotator annotate(Object context, MarkupText text, int charPos) {
    if (context instanceof AbstractBuild) {
      AbstractBuild<?,?> b = (AbstractBuild) context;
      ParametersAction pa = b.getAction(ParametersAction.class);
      if (pa!=null) {
        ReviewboardParameterValue p = (ReviewboardParameterValue) pa.getParameter("review.url");
        if (p!=null) {
          text.addHyperlink(charPos,charPos+length,p.getLocation());
        }
      }
    }
    return null;
  }

  public static String encodeTo(String text) {
    try {
      return new ReviewboardNote(text.length()).encode()+text;
    } catch (IOException e) {
      // impossible, but don't make this a fatal problem
      LOGGER.log(Level.WARNING, "Failed to serialize "+ReviewboardNote.class,e);
      return text;
    }
  }

  @Extension
  public static final class DescriptorImpl extends ConsoleAnnotationDescriptor {
    public String getDisplayName() {
      return "Link to patch.diff";
    }
  }

  private static final Logger LOGGER = Logger.getLogger(ReviewboardNote.class.getName());
}


<|start_filename|>src/test/java/org/jenkinsci/plugins/jenkinsreviewbot/UtilTest.java<|end_filename|>
package org.jenkinsci.plugins.jenkinsreviewbot;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

/**
 * User: ymeymann
 * Date: 3/8/14 7:57 PM
 */
public class UtilTest {
  @Test
  public void testHostParsing() throws Exception {
    ReviewboardConnection.Host h ;

    h = new ReviewboardConnection("http://www.google.com", "", "").getHost();
    assertEquals("www.google.com", h.host);
    assertEquals(80, h.port);

    h = new ReviewboardConnection("https://my.reviewboard.com", "", "").getHost();
    assertEquals("my.reviewboard.com", h.host);
    assertEquals(443, h.port);

    h = new ReviewboardConnection("http://foo.com:8800", "", "").getHost();
    assertEquals("foo.com", h.host);
    assertEquals(8800, h.port);

    h = new ReviewboardConnection("bar.com", "", "").getHost();
    assertEquals("bar.com", h.host);
    assertEquals(-1, h.port);

  }


}


<|start_filename|>src/main/resources/org/jenkinsci/plugins/jenkinsreviewbot/ReviewboardApplyPatch/help.html<|end_filename|>
<div>
    Should be used with Reviewboard Url Parameter and should be a pre-build step. If auto-apply patch is disabled in plugin configuration,
    this will invoke the default diff4j patch application. If auto-apply is on (default) - nothing will happen.
</div>


<|start_filename|>src/test/java/org/jenkinsci/plugins/jenkinsreviewbot/ConnectionTest.java<|end_filename|>
package org.jenkinsci.plugins.jenkinsreviewbot;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.SimpleHttpConnectionManager;
import org.junit.Ignore;
import org.junit.Test;

import java.io.IOException;
import java.util.Map;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;

/**
 * User: ymeymann
 * Date: 9/13/13 12:52 AM
 */
@Ignore
public class ConnectionTest {

  ReviewboardConnection con =
      new ReviewboardConnection(
          System.getProperty("reviewboard.url", "https://reviewboard.eng.vmware.com/"),
          System.getProperty("reviewboard.user"),
          System.getProperty("reviewboard.pwd"));

  @Test
  public void testConnection() throws Exception {
    ReviewboardOps.getInstance().ensureAuthentication(con);
  }

  @Test(expected=IOException.class)
  public void testFailConnection() throws Exception {
    SimpleHttpConnectionManager simple = new SimpleHttpConnectionManager();
    HttpClient http = new HttpClient(simple);
    ReviewboardConnection bad =
        new ReviewboardConnection(System.getProperty("reviewboard.url", "https://reviewboard.eng.vmware.com/"),
            System.getProperty("reviewboard.user"), "foobar");
    try {
      ReviewboardOps.ensureAuthentication(bad, http);
    } finally {
      simple.shutdown();
    }

  }

  @Test
  public void testDiff() throws Exception {
    ReviewboardOps.DiffHandle diff = ReviewboardOps.getInstance().getDiff(con, "https://reviewboard.eng.vmware.com/r/475848/");
    try { assertNotNull(diff.getString()); } finally { diff.close(); }
  }

  @Test
  public void testPending() throws Exception {
    int count = ReviewboardOps.getInstance().getPendingReviews(con, 1, true, -1).size();
    System.out.println(count);
  }

  @Test
  public void testBranchAndRepo1() throws Exception {
    Map<String, String> m = ReviewboardOps.getInstance().getProperties(con, "https://reviewboard.eng.vmware.com/r/514656/");
    assertEquals("master", m.get("REVIEW_BRANCH"));
    assertEquals("act", m.get("REVIEW_REPOSITORY"));
  }

  @Test
  public void testBranchAndRepo2() throws Exception {
    Map<String, String> m = ReviewboardOps.getInstance().getProperties(con, "https://reviewboard.eng.vmware.com/r/643087/");
    assertEquals("origin/master", m.get("REVIEW_BRANCH"));
    assertEquals("itfm-cloud", m.get("REVIEW_REPOSITORY"));
  }

  @Test
  public void testSubmitter() throws Exception {
    Map<String, String> m = ReviewboardOps.getInstance().getProperties(con, "https://reviewboard.eng.vmware.com/r/475848/");
    assertEquals("ymeymann", m.get("REVIEW_USER"));
  }
}


<|start_filename|>src/main/java/org/jenkinsci/plugins/jenkinsreviewbot/ReviewboardConnection.java<|end_filename|>
/*
Copyright (c) 2013 VMware, Inc. All Rights Reserved.

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.jenkinsci.plugins.jenkinsreviewbot;

import org.apache.commons.httpclient.auth.AuthScope;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * User: ymeymann
 * Date: 8/25/13 12:31 AM
 */
public class ReviewboardConnection {

  private final String reviewboardURL;
  private final String reviewboardUsername;
  private final String reviewboardPassword;

  private static final Pattern digitsPattern = Pattern.compile("\\d+");

  public static ReviewboardConnection fromConfiguration() {
    ReviewboardDescriptor d = ReviewboardNotifier.DESCRIPTOR;
    return new ReviewboardConnection(d.getReviewboardURL(), d.getReviewboardUsername(), d.getReviewboardPassword());
  }

  public ReviewboardConnection(String url, String user, String password) {
    reviewboardURL = url + (url.endsWith("/")?"":"/");
    reviewboardUsername = user;
    reviewboardPassword = password;
  }

  public String getReviewboardURL() {
    return reviewboardURL;
  }

  public String getReviewboardUsername() {
    return reviewboardUsername;
  }

  public String getReviewboardPassword() {
    return reviewboardPassword;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    ReviewboardConnection that = (ReviewboardConnection) o;

    if (reviewboardURL != null ? !reviewboardURL.equals(that.reviewboardURL) : that.reviewboardURL != null)
      return false;
    if (reviewboardUsername != null ? !reviewboardUsername.equals(that.reviewboardUsername) : that.reviewboardUsername != null)
      return false;
    return !(reviewboardPassword != null ? !reviewboardPassword.equals(that.reviewboardPassword) : that.reviewboardPassword != null);

  }

  @Override
  public int hashCode() {
    int result = reviewboardURL != null ? reviewboardURL.hashCode() : 0;
    result = 31 * result + (reviewboardUsername != null ? reviewboardUsername.hashCode() : 0);
    result = 31 * result + (reviewboardPassword != null ? reviewboardPassword.hashCode() : 0);
    return result;
  }

  public static class Host {
    final String host;
    final int port;
    Host(String host, int port) { this.host = host; this.port = port; }

    @Override
    public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;

      Host host1 = (Host) o;

      if (port != host1.port) return false;
      return !(host != null ? !host.equals(host1.host) : host1.host != null);

    }

    @Override
    public int hashCode() {
      int result = host != null ? host.hashCode() : 0;
      result = 31 * result + port;
      return result;
    }
  }

  public Host getHost() {
    // e.g. 'https://reviewboard.eng.vmware.com/' -> 'reviewboard.eng.vmware.com'
    String url = reviewboardURL;
    int startIndex = 0;
    int temp = url.indexOf("://");
    if (temp >= 0) startIndex = temp + 3;
    int endIndex = url.indexOf('/', startIndex);
    if (endIndex < 0) endIndex = url.length();
    String hostAndPort = url.substring(startIndex, endIndex);

    int colon = hostAndPort.indexOf(':');
    String host = colon >= 0 ? hostAndPort.substring(0, colon) : hostAndPort;
    int port = colon >= 0 ?
        Integer.parseInt(hostAndPort.substring(colon + 1)) :
        url.startsWith("http:") ? 80 :
        url.startsWith("https:") ? 443 :
        AuthScope.ANY_PORT;
    return new Host(host, port);
  }

  public String buildApiUrl(String url, String what) {
    //e.g. https://reviewboard.eng.vmware.com/r/474115/ ->
    //     https://reviewboard.eng.vmware.com/api/review-requests/474115/${what}/
    int splitPoint = url.indexOf("/r/");
    StringBuilder sb = new StringBuilder(url.length() + 25);
    sb.append(url.substring(0, splitPoint));
    sb.append("/api/review-requests/");
    int idIndex = splitPoint + 3;
    sb.append(url.substring(idIndex, url.indexOf('/', idIndex)));
    sb.append('/');
    if (what != null && !what.isEmpty()) sb.append(what).append('/');
    String res = sb.toString();
    return res;
  }

  String buildReviewUrl(String value) {
    Matcher m = digitsPattern.matcher(value);
    String number = m.find() ? m.group() : "0";
    return reviewNumberToUrl(number);
  }

  String reviewNumberToUrl(String number) {
    StringBuilder sb = new StringBuilder();
    sb.append(reviewboardURL).append("r/").append(number).append('/');
    return sb.toString();
  }

  public String getDiffsUrl(long id) {
    return buildApiUrlFromId(id, "diffs");
  }

  public String getPendingReviewsUrl(boolean onlyToJenkinsUser, int repoid) {
    //e.g. https://reviewboard.eng.vmware.com/api/review-requests/?to-users=...
    StringBuilder sb = new StringBuilder(128);
    sb.append(reviewboardURL).append("api/review-requests/");
    sb.append('?').append("status=pending");
    if (onlyToJenkinsUser) sb.append('&').append("to-users=").append(reviewboardUsername);
    sb.append('&').append("max-results=200");
    if (repoid >= 0) {
      // user selected to filter by repository
      // rationale is that different repository means different test job.
      sb.append('&').append("repository=" + repoid);
    }
    return sb.toString();
  }

  public String getCommentsUrl(long id) {
    return buildApiUrlFromId(id, "reviews");
  }

  public String getRepositoriesUrl() {
    // e.g. https://reviewboard.eng.vmware.com/api/repositories/
    return reviewboardURL.concat("api/repositories/?max-results=200");
  }

  public String buildApiUrlFromId(long id, String what) {
    StringBuilder sb = new StringBuilder(128);
    sb.append(reviewboardURL).append("api/review-requests/").append(id).append('/');
    if (what != null && !what.isEmpty()) sb.append(what).append('/');
    return sb.toString();
  }

}


<|start_filename|>src/main/resources/org/jenkinsci/plugins/jenkinsreviewbot/ReviewboardParameterDefinition/help.html<|end_filename|>
<div>
    Accepts a patch url or number of review request. This patch will be applied to the workspace after the source code is checked out,
    then the build will proceed.
</div>
