Example #1
0
  /**
   * @param project
   * @param commitSHA1
   * @return
   */
  private Run getBuildBySHA1(Job project, String commitSHA1, boolean triggeredByMergeRequest) {
    List<Run> builds = project.getBuilds();
    for (Run build : builds) {
      BuildData data = build.getAction(BuildData.class);
      MergeRecord mergeRecord = build.getAction(MergeRecord.class);
      if (mergeRecord == null) {
        // Determine if build was triggered by a Merge Request event
        ParametersAction params = build.getAction(ParametersAction.class);

        if (params == null) continue;

        StringParameterValue sourceBranch =
            (StringParameterValue) params.getParameter("gitlabSourceBranch");
        StringParameterValue targetBranch =
            (StringParameterValue) params.getParameter("gitlabTargetBranch");
        boolean isMergeRequestBuild =
            (sourceBranch != null && !sourceBranch.value.equals(targetBranch.value));

        if (!triggeredByMergeRequest) {
          if (isMergeRequestBuild)
            // skip Merge Request builds
            continue;

          if (data.getLastBuiltRevision().getSha1String().contains(commitSHA1)) {
            return build;
          }
        } else {
          if (!isMergeRequestBuild)
            // skip Push builds
            continue;

          if (hasBeenBuilt(data, ObjectId.fromString(commitSHA1), build)) {
            return build;
          }
        }

      } else {
        Build b = data.lastBuild;
        boolean isMergeBuild =
            mergeRecord != null && !mergeRecord.getSha1().equals(b.getMarked().getSha1String());
        if (b != null
            && b.getMarked() != null
            && b.getMarked().getSha1String().equals(commitSHA1)) {
          if (triggeredByMergeRequest == isMergeBuild) {
            LOGGER.log(
                Level.FINE,
                build.getNumber()
                    + " Build found matching "
                    + commitSHA1
                    + " "
                    + (isMergeBuild ? "merge" : "normal")
                    + " build");
            return build;
          }
        }
      }
    }
    return null;
  }
Example #2
0
  /**
   * Look back as far as needed to find a valid BuildData. BuildData may not be recorded if an
   * exception occurs in the plugin logic.
   *
   * @param build
   * @param clone
   * @return the last recorded build data
   */
  public BuildData getBuildData(Run build, boolean clone) {
    BuildData buildData = null;
    while (build != null) {
      buildData = build.getAction(BuildData.class);
      if (buildData != null) break;
      build = build.getPreviousBuild();
    }

    if (buildData == null) return null;

    if (clone) return buildData.clone();
    else return buildData;
  }
Example #3
0
 private boolean hasBeenBuilt(BuildData data, ObjectId sha1, Run build) {
   try {
     for (Build b : data.getBuildsByBranchName().values()) {
       if (b.getBuildNumber() == build.number && b.marked.getSha1().equals(sha1)) return true;
     }
     return false;
   } catch (Exception ex) {
     return false;
   }
 }
  private Collection<String> lookupCommitSha1s(
      @SuppressWarnings("rawtypes") AbstractBuild build, BuildListener listener) {

    if (commitSha1 != null && commitSha1.trim().length() > 0) {
      PrintStream logger = listener.getLogger();
      try {
        EnvVars environment = build.getEnvironment(listener);
        return Arrays.asList(environment.expand(commitSha1));
      } catch (IOException e) {
        logger.println("Unable to expand commit SHA value");
        e.printStackTrace(logger);
        return Arrays.asList();
      } catch (InterruptedException e) {
        logger.println("Unable to expand commit SHA value");
        e.printStackTrace(logger);
        return Arrays.asList();
      }
    }

    // Use a set to remove duplicates
    Collection<String> sha1s = new HashSet<String>();
    // MultiSCM may add multiple BuildData actions for each SCM, but we are covered in any case
    for (BuildData buildData : build.getActions(BuildData.class)) {
      // get the sha1 of the commit that was built

      String lastBuiltSha1 = buildData.getLastBuiltRevision().getSha1String();

      // Should never be null, but may be blank
      if (!lastBuiltSha1.isEmpty()) {
        sha1s.add(lastBuiltSha1);
      }

      // This might be different than the lastBuiltSha1 if using "Merge before build"
      String markedSha1 = buildData.lastBuild.getMarked().getSha1String();

      // Should never be null, but may be blank
      if (!markedSha1.isEmpty()) {
        sha1s.add(markedSha1);
      }
    }
    return sha1s;
  }
Example #5
0
  @Override
  public boolean checkout(
      final AbstractBuild build,
      Launcher launcher,
      final FilePath workspace,
      final BuildListener listener,
      File changelogFile)
      throws IOException, InterruptedException {

    listener
        .getLogger()
        .println(
            "Checkout:"
                + workspace.getName()
                + " / "
                + workspace.getRemote()
                + " - "
                + workspace.getChannel());
    listener.getLogger().println("Using strategy: " + choosingStrategy);

    final String projectName = build.getProject().getName();
    final int buildNumber = build.getNumber();
    final String gitExe = getDescriptor().getGitExe();

    final String buildnumber = "hudson-" + projectName + "-" + buildNumber;

    final BuildData buildData = getBuildData(build.getPreviousBuild(), true);

    if (buildData != null && buildData.lastBuild != null) {
      listener.getLogger().println("Last Built Revision: " + buildData.lastBuild.revision);
    }

    final EnvVars environment = build.getEnvironment(listener);

    final String singleBranch = getSingleBranch(build);

    Revision tempParentLastBuiltRev = null;

    if (build instanceof MatrixRun) {
      MatrixBuild parentBuild = ((MatrixRun) build).getParentBuild();
      if (parentBuild != null) {
        BuildData parentBuildData = parentBuild.getAction(BuildData.class);
        if (parentBuildData != null) {
          tempParentLastBuiltRev = parentBuildData.getLastBuiltRevision();
        }
      }
    }

    final Revision parentLastBuiltRev = tempParentLastBuiltRev;

    final Revision revToBuild =
        workspace.act(
            new FileCallable<Revision>() {
              private static final long serialVersionUID = 1L;

              public Revision invoke(File localWorkspace, VirtualChannel channel)
                  throws IOException {
                FilePath ws = new FilePath(localWorkspace);
                listener
                    .getLogger()
                    .println(
                        "Checkout:"
                            + ws.getName()
                            + " / "
                            + ws.getRemote()
                            + " - "
                            + ws.getChannel());

                IGitAPI git = new GitAPI(gitExe, ws, listener, environment);

                if (git.hasGitRepo()) {
                  // It's an update

                  listener.getLogger().println("Fetching changes from the remote Git repository");

                  for (RemoteConfig remoteRepository : getRepositories()) {
                    fetchFrom(git, localWorkspace, listener, remoteRepository);
                  }

                } else {
                  listener.getLogger().println("Cloning the remote Git repository");

                  // Go through the repositories, trying to clone from one
                  //
                  boolean successfullyCloned = false;
                  for (RemoteConfig rc : remoteRepositories) {
                    try {
                      git.clone(rc);
                      successfullyCloned = true;
                      break;
                    } catch (GitException ex) {
                      listener.error(
                          "Error cloning remote repo '%s' : %s", rc.getName(), ex.getMessage());
                      if (ex.getCause() != null) {
                        listener.error("Cause: %s", ex.getCause().getMessage());
                      }
                      // Failed. Try the next one
                      listener.getLogger().println("Trying next repository");
                    }
                  }

                  if (!successfullyCloned) {
                    listener.error("Could not clone from a repository");
                    throw new GitException("Could not clone");
                  }

                  // Also do a fetch
                  for (RemoteConfig remoteRepository : getRepositories()) {
                    fetchFrom(git, localWorkspace, listener, remoteRepository);
                  }

                  if (git.hasGitModules()) {
                    git.submoduleInit();
                    git.submoduleUpdate();
                  }
                }

                if (parentLastBuiltRev != null) return parentLastBuiltRev;

                IBuildChooser buildChooser = createBuildChooser(git, listener, buildData);

                Collection<Revision> candidates =
                    buildChooser.getCandidateRevisions(false, singleBranch);
                if (candidates.size() == 0) return null;
                return candidates.iterator().next();
              }
            });

    if (revToBuild == null) {
      // getBuildCandidates should make the last item the last build, so a re-build
      // will build the last built thing.
      listener.error("Nothing to do");
      return false;
    }
    listener.getLogger().println("Commencing build of " + revToBuild);
    environment.put(GIT_COMMIT, revToBuild.getSha1String());
    Object[] returnData; // Changelog, BuildData

    if (mergeOptions.doMerge()) {
      if (!revToBuild.containsBranchName(mergeOptions.getRemoteBranchName())) {
        returnData =
            workspace.act(
                new FileCallable<Object[]>() {
                  private static final long serialVersionUID = 1L;

                  public Object[] invoke(File localWorkspace, VirtualChannel channel)
                      throws IOException {
                    IGitAPI git =
                        new GitAPI(gitExe, new FilePath(localWorkspace), listener, environment);

                    IBuildChooser buildChooser = createBuildChooser(git, listener, buildData);

                    // Do we need to merge this revision onto MergeTarget

                    // Only merge if there's a branch to merge that isn't
                    // us..
                    listener
                        .getLogger()
                        .println(
                            "Merging " + revToBuild + " onto " + mergeOptions.getMergeTarget());

                    // checkout origin/blah
                    ObjectId target = git.revParse(mergeOptions.getRemoteBranchName());
                    git.checkout(target.name());

                    try {
                      git.merge(revToBuild.getSha1().name());
                    } catch (Exception ex) {
                      listener
                          .getLogger()
                          .println(
                              "Branch not suitable for integration as it does not merge cleanly");

                      // We still need to tag something to prevent
                      // repetitive builds from happening - tag the
                      // candidate
                      // branch.
                      git.checkout(revToBuild.getSha1().name());

                      git.tag(buildnumber, "Hudson Build #" + buildNumber);

                      buildChooser.revisionBuilt(revToBuild, buildNumber, Result.FAILURE);

                      return new Object[] {null, buildChooser.getData()};
                    }

                    if (git.hasGitModules()) {
                      git.submoduleUpdate();
                    }

                    // Tag the successful merge
                    git.tag(buildnumber, "Hudson Build #" + buildNumber);

                    StringBuilder changeLog = new StringBuilder();

                    if (revToBuild.getBranches().size() > 0)
                      listener
                          .getLogger()
                          .println("Warning : There are multiple branch changesets here");

                    try {
                      for (Branch b : revToBuild.getBranches()) {
                        Build lastRevWas =
                            buildData == null ? null : buildData.getLastBuildOfBranch(b.getName());
                        if (lastRevWas != null) {
                          changeLog.append(
                              putChangelogDiffsIntoFile(
                                  git,
                                  b.name,
                                  lastRevWas.getSHA1().name(),
                                  revToBuild.getSha1().name()));
                        }
                      }
                    } catch (GitException ge) {
                      changeLog.append("Unable to retrieve changeset");
                    }

                    Build buildData = buildChooser.revisionBuilt(revToBuild, buildNumber, null);
                    GitUtils gu = new GitUtils(listener, git);
                    buildData.mergeRevision = gu.getRevisionForSHA1(target);

                    // Fetch the diffs into the changelog file
                    return new Object[] {changeLog.toString(), buildChooser.getData()};
                  }
                });
        BuildData returningBuildData = (BuildData) returnData[1];
        build.addAction(returningBuildData);
        return changeLogResult((String) returnData[0], changelogFile);
      }
    }

    // No merge

    returnData =
        workspace.act(
            new FileCallable<Object[]>() {
              private static final long serialVersionUID = 1L;

              public Object[] invoke(File localWorkspace, VirtualChannel channel)
                  throws IOException {
                IGitAPI git =
                    new GitAPI(gitExe, new FilePath(localWorkspace), listener, environment);
                IBuildChooser buildChooser = createBuildChooser(git, listener, buildData);

                // Straight compile-the-branch
                listener.getLogger().println("Checking out " + revToBuild);
                git.checkout(revToBuild.getSha1().name());

                // if( compileSubmoduleCompares )
                if (doGenerateSubmoduleConfigurations) {
                  SubmoduleCombinator combinator =
                      new SubmoduleCombinator(git, listener, localWorkspace, submoduleCfg);
                  combinator.createSubmoduleCombinations();
                }

                if (git.hasGitModules()) {
                  git.submoduleInit();
                  git.submoduleSync();

                  // Git submodule update will only 'fetch' from where it
                  // regards as 'origin'. However,
                  // it is possible that we are building from a
                  // RemoteRepository with changes
                  // that are not in 'origin' AND it may be a new module that
                  // we've only just discovered.
                  // So - try updating from all RRs, then use the submodule
                  // Update to do the checkout

                  for (RemoteConfig remoteRepository : getRepositories()) {
                    fetchFrom(git, localWorkspace, listener, remoteRepository);
                  }

                  // Update to the correct checkout
                  git.submoduleUpdate();
                }

                // Tag the successful merge
                git.tag(buildnumber, "Hudson Build #" + buildNumber);

                StringBuilder changeLog = new StringBuilder();

                int histories = 0;

                try {
                  for (Branch b : revToBuild.getBranches()) {
                    Build lastRevWas =
                        buildData == null ? null : buildData.getLastBuildOfBranch(b.getName());

                    if (lastRevWas != null) {
                      listener.getLogger().println("Recording changes in branch " + b.getName());
                      changeLog.append(
                          putChangelogDiffsIntoFile(
                              git,
                              b.name,
                              lastRevWas.getSHA1().name(),
                              revToBuild.getSha1().name()));
                      histories++;
                    } else {
                      listener.getLogger().println("No change to record in branch " + b.getName());
                    }
                  }
                } catch (GitException ge) {
                  changeLog.append("Unable to retrieve changeset");
                }

                if (histories > 1)
                  listener
                      .getLogger()
                      .println("Warning : There are multiple branch changesets here");

                buildChooser.revisionBuilt(revToBuild, buildNumber, null);

                if (getClean()) {
                  listener.getLogger().println("Cleaning workspace");
                  git.clean();
                }

                // Fetch the diffs into the changelog file
                return new Object[] {changeLog.toString(), buildChooser.getData()};
              }
            });
    build.addAction((Action) returnData[1]);

    return changeLogResult((String) returnData[0], changelogFile);
  }
 @Override
 protected void before() throws Throwable {
   when(data.getLastBuiltRevision()).thenReturn(rev);
   data.lastBuild = new hudson.plugins.git.util.Build(rev, rev, 0, Result.SUCCESS);
   when(rev.getSha1()).thenReturn(ObjectId.fromString(SOME_SHA));
 }