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