/** This test unit is for testing a commit hook using the UUID */
  @Bug(399165)
  @Test
  public void testPrebuiltCommitTrigger() throws Exception {
    hudson.setCrumbIssuer(null);

    // First create repository with 1 file and commit information
    SVNCommitInfo info = createSVNRepository();
    assertNull(info.getErrorMessage());
    assertEquals("Failed to create 1 revision.", 1, info.getNewRevision());

    // Create freestyle project with SVN SCM.
    FreeStyleProject project = createFreeStyleProject();
    project.setScm(new SubversionSCM("file:///tmp/399165"));
    SCMTrigger trigger = new SCMTrigger("0 */6 * * *");
    project.addTrigger(trigger);
    trigger.start(project, true);

    // Execute build (This is critical for fixing eclipse bug: 399165)
    assertBuildStatusSuccess(project.scheduleBuild2(0));

    // Commit a file again.
    info = createSecondCommit();
    assertNull(info.getErrorMessage());
    assertEquals("Failed to create second commit.", 2, info.getNewRevision());

    // Create post-commit hook
    WebClient wc = new WebClient();
    WebRequestSettings wr =
        new WebRequestSettings(
            new URL(
                getURL() + "subversion/" + repository.getRepositoryUUID(false) + "/notifyCommit"),
            HttpMethod.POST);
    wr.setRequestBody("A   dirB/file2.txt");
    wr.setAdditionalHeader("Content-Type", "text/plain;charset=UTF-8");

    wr.setAdditionalHeader("X-Hudson-Subversion-Revision", "2");

    WebConnection conn = wc.getWebConnection();
    System.out.println(wr);
    WebResponse resp = conn.getResponse(wr);
    assertTrue(isGoodHttpStatus(resp.getStatusCode()));

    waitUntilNoActivity();
    FreeStyleBuild b = project.getLastBuild();
    assertNotNull(b);

    assertBuildStatus(Result.SUCCESS, b);

    assertEquals("Failed to execute a buid.", 2, b.getNumber());
  }
  @Test
  public void testPostCommitTrigger() throws Exception {
    // Disable crumbs because HTMLUnit refuses to mix request bodies with
    // request parameters
    hudson.setCrumbIssuer(null);

    FreeStyleProject p = createFreeStyleProject();
    String url = "https://tsethudsonsvn.googlecode.com/svn/trunk";
    SCMTrigger trigger = new SCMTrigger("0 */6 * * *");

    p.setScm(new SubversionSCM(url));
    p.addTrigger(trigger);
    trigger.start(p, true);

    String repoUUID = "b703df53-fdd9-0691-3d8c-58db40123d9f";

    WebClient wc = new WebClient();
    WebRequestSettings wr =
        new WebRequestSettings(
            new URL(getURL() + "subversion/" + repoUUID + "/notifyCommit"), HttpMethod.POST);
    wr.setRequestBody("A   trunk/testcommit.txt");
    wr.setAdditionalHeader("Content-Type", "text/plain;charset=UTF-8");

    wr.setAdditionalHeader("X-Hudson-Subversion-Revision", "16");

    WebConnection conn = wc.getWebConnection();
    WebResponse resp = conn.getResponse(wr);
    assertTrue(isGoodHttpStatus(resp.getStatusCode()));

    waitUntilNoActivity();
    FreeStyleBuild b = p.getLastBuild();
    assertNotNull(b);
    assertBuildStatus(Result.SUCCESS, b);

    SVNRevisionState revisionState = b.getAction(SVNRevisionState.class);

    assertNotNull("Failed to find revision", revisionState);

    assertNotNull("Failed to find revision", revisionState.revisions.get(url));

    assertEquals(16, revisionState.revisions.get(url).longValue());
  }
  /**
   * Notify the commit to this repository.
   *
   * <p>Because this URL is not guarded, we can't really trust the data that's sent to us. But we
   * intentionally don't protect this URL to simplify <tt>post-commit</tt> script set up.
   */
  public void doNotifyCommit(StaplerRequest req, StaplerResponse rsp)
      throws ServletException, IOException {
    requirePOST();

    // compute the affected paths
    Set<String> affectedPath = new HashSet<String>();
    String line;
    BufferedReader r = new BufferedReader(req.getReader());

    try {
      while ((line = r.readLine()) != null) {
        if (LOGGER.isLoggable(FINER)) {
          LOGGER.finer("Reading line: " + line);
        }
        affectedPath.add(line.substring(4));
        if (line.startsWith("svnlook changed --revision ")) {
          String msg =
              "Expecting the output from the svnlook command but instead you just sent me the svnlook invocation command line: "
                  + line;
          LOGGER.warning(msg);
          throw new IllegalArgumentException(msg);
        }
      }
    } finally {
      IOUtils.closeQuietly(r);
    }

    if (LOGGER.isLoggable(FINE))
      LOGGER.fine("Change reported to Subversion repository " + uuid + " on " + affectedPath);
    boolean scmFound = false, triggerFound = false, uuidFound = false, pathFound = false;

    // we can't reliably use req.getParameter() as it can try to parse the payload, which we've
    // already consumed above.
    // servlet container relies on Content-type to decide if it wants to parse the payload or not,
    // and at least
    // in case of Jetty, it doesn't check if the payload is
    QueryParameterMap query = new QueryParameterMap(req);
    String revParam = query.get("rev");
    long rev = -1;
    if (revParam != null) {
      rev = Long.parseLong(revParam);
    } else {
      revParam = req.getHeader("X-Hudson-Subversion-Revision");
      if (revParam != null) {
        rev = Long.parseLong(revParam);
      }
    }

    OUTER:
    for (AbstractProject<?, ?> p : Hudson.getInstance().getItems(AbstractProject.class)) {
      try {
        SCM scm = p.getScm();
        if (scm instanceof SubversionSCM) scmFound = true;
        else continue;

        SCMTrigger trigger = p.getTrigger(SCMTrigger.class);
        if (trigger != null) triggerFound = true;
        else continue;

        SubversionSCM sscm = (SubversionSCM) scm;
        for (ModuleLocation loc : sscm.getLocations()) {
          if (loc.getUUID(p).equals(uuid)) uuidFound = true;
          else continue;

          String m = loc.getSVNURL().getPath();
          String n = loc.getRepositoryRoot(p).getPath();
          if (!m.startsWith(n))
            continue; // repository root should be a subpath of the module path, but be defensive

          String remaining = m.substring(n.length());
          if (remaining.startsWith("/")) remaining = remaining.substring(1);
          String remainingSlash = remaining + '/';

          final RevisionParameterAction[] actions;
          if (rev != -1) {
            SvnInfo info[] = {new SvnInfo(loc.getURL(), rev)};
            RevisionParameterAction action = new RevisionParameterAction(info);
            actions = new RevisionParameterAction[] {action};

          } else {
            actions = new RevisionParameterAction[0];
          }

          for (String path : affectedPath) {
            if (path.equals(remaining) /*for files*/
                || path.startsWith(remainingSlash) /*for dirs*/) {
              // this project is possibly changed. poll now.
              // if any of the data we used was bogus, the trigger will not detect a change
              LOGGER.fine("Scheduling the immediate polling of " + p);
              trigger.run(actions);
              pathFound = true;

              continue OUTER;
            }
          }
        }
      } catch (SVNException e) {
        LOGGER.log(WARNING, "Failed to handle Subversion commit notification", e);
      }
    }

    if (!scmFound) LOGGER.warning("No subversion jobs found");
    else if (!triggerFound) LOGGER.warning("No subversion jobs using SCM polling");
    else if (!uuidFound) LOGGER.warning("No subversion jobs using repository: " + uuid);
    else if (!pathFound) LOGGER.fine("No jobs found matching the modified files");

    rsp.setStatus(SC_OK);
  }