예제 #1
0
  public Object readResolve() {
    // Migrate data

    // Default unspecified to v0
    if (configVersion == null) configVersion = 0L;

    if (source != null) {
      remoteRepositories = new ArrayList<RemoteConfig>();
      branches = new ArrayList<BranchSpec>();
      doGenerateSubmoduleConfigurations = false;
      mergeOptions = new PreBuildMergeOptions();

      remoteRepositories.add(
          newRemoteConfig("origin", source, new RefSpec("+refs/heads/*:refs/remotes/origin/*")));
      if (branch != null) {
        branches.add(new BranchSpec(branch));
      } else {
        branches.add(new BranchSpec("*/master"));
      }
    }

    if (configVersion < 1 && branches != null) {
      // Migrate the branch specs from
      // single * wildcard, to ** wildcard.
      for (BranchSpec branchSpec : branches) {
        String name = branchSpec.getName();
        name = name.replace("*", "**");
        branchSpec.setName(name);
      }
    }

    if (mergeOptions.doMerge() && mergeOptions.getMergeRemote() == null) {
      mergeOptions.setMergeRemote(remoteRepositories.get(0));
    }

    return this;
  }
예제 #2
0
    public SCM newInstance(StaplerRequest req) throws FormException {
      List<RemoteConfig> remoteRepositories;
      File temp;

      try {
        temp = File.createTempFile("tmp", "config");

      } catch (IOException e1) {
        throw new GitException("Error creating repositories", e1);
      }

      RepositoryConfig repoConfig = new RepositoryConfig(null, temp);
      // Make up a repo config from the request parameters

      String[] urls = req.getParameterValues("git.repo.url");
      String[] names = req.getParameterValues("git.repo.name");

      names = GitUtils.fixupNames(names, urls);

      String[] refs = req.getParameterValues("git.repo.refspec");
      if (names != null) {
        for (int i = 0; i < names.length; i++) {
          String name = names[i];
          name = name.replace(' ', '_');

          if (refs[i] == null || refs[i].length() == 0) {
            refs[i] = "+refs/heads/*:refs/remotes/" + name + "/*";
          }

          repoConfig.setString("remote", name, "url", urls[i]);
          repoConfig.setString("remote", name, "fetch", refs[i]);
        }
      }

      try {
        repoConfig.save();
        remoteRepositories = RemoteConfig.getAllRemoteConfigs(repoConfig);
      } catch (Exception e) {
        throw new GitException("Error creating repositories", e);
      }

      temp.delete();

      List<BranchSpec> branches = new ArrayList<BranchSpec>();
      String[] branchData = req.getParameterValues("git.branch");
      for (int i = 0; i < branchData.length; i++) {
        branches.add(new BranchSpec(branchData[i]));
      }

      if (branches.size() == 0) {
        branches.add(new BranchSpec("*/master"));
      }

      PreBuildMergeOptions mergeOptions = new PreBuildMergeOptions();
      if (req.getParameter("git.mergeTarget") != null
          && req.getParameter("git.mergeTarget").trim().length() > 0) {
        mergeOptions.setMergeTarget(req.getParameter("git.mergeTarget"));
      }

      Collection<SubmoduleConfig> submoduleCfg = new ArrayList<SubmoduleConfig>();

      GitWeb gitWeb = null;
      String gitWebUrl = req.getParameter("gitweb.url");
      if (gitWebUrl != null && gitWebUrl.length() > 0) {
        try {
          gitWeb = new GitWeb(gitWebUrl);
        } catch (MalformedURLException e) {
          throw new GitException("Error creating GitWeb", e);
        }
      }

      return new GitSCM(
          remoteRepositories,
          branches,
          mergeOptions,
          req.getParameter("git.generate") != null,
          submoduleCfg,
          req.getParameter("git.clean") != null,
          gitWeb);
    }
예제 #3
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());

    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);
    }

    EnvVars tmp = new EnvVars();
    try {
      tmp = build.getEnvironment(listener);
    } catch (InterruptedException e) {
      listener.error("Interrupted exception getting environment .. using empty environment");
    }
    final EnvVars environment = tmp;

    final String singleBranch = getSingleBranch(build);

    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();
                  }
                }

                IBuildChooser buildChooser =
                    new BuildChooser(GitSCM.this, git, new GitUtils(listener, git), 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);
    Object[] returnData; // Changelog, BuildData

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

                  public Object[] invoke(File localWorkspace, VirtualChannel channel)
                      throws IOException {
                    EnvVars environment;
                    try {
                      environment = build.getEnvironment(listener);
                    } catch (Exception e) {
                      listener.error("Exception reading environment - using empty environment");
                      environment = new EnvVars();
                    }
                    IGitAPI git =
                        new GitAPI(gitExe, new FilePath(localWorkspace), listener, environment);

                    IBuildChooser buildChooser =
                        new BuildChooser(GitSCM.this, git, new GitUtils(listener, git), 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.getMergeTarget());
                    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, 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 =
                    new BuildChooser(GitSCM.this, git, new GitUtils(listener, git), 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 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);
  }