private Collection<Revision> getHeadRevision( boolean isPollCall, String singleBranch, GitClient git, TaskListener listener, BuildData data) throws InterruptedException { try { ObjectId sha1 = git.revParse(singleBranch); verbose(listener, "rev-parse {0} -> {1}", singleBranch, sha1); // if polling for changes don't select something that has // already been built as a build candidate if (isPollCall && data.hasBeenBuilt(sha1)) { verbose(listener, "{0} has already been built", sha1); return emptyList(); } verbose(listener, "Found a new commit {0} to be built on {1}", sha1, singleBranch); Revision revision = new Revision(sha1); revision.getBranches().add(new Branch(singleBranch, sha1)); return Collections.singletonList(revision); /* // calculate the revisions that are new compared to the last build List<Revision> candidateRevs = new ArrayList<Revision>(); List<ObjectId> allRevs = git.revListAll(); // index 0 contains the newest revision if (data != null && allRevs != null) { Revision lastBuiltRev = data.getLastBuiltRevision(); if (lastBuiltRev == null) { return Collections.singletonList(objectId2Revision(singleBranch, sha1)); } int indexOfLastBuildRev = allRevs.indexOf(lastBuiltRev.getSha1()); if (indexOfLastBuildRev == -1) { // mhmmm ... can happen when branches are switched. return Collections.singletonList(objectId2Revision(singleBranch, sha1)); } List<ObjectId> newRevisionsSinceLastBuild = allRevs.subList(0, indexOfLastBuildRev); // translate list of ObjectIds into list of Revisions for (ObjectId objectId : newRevisionsSinceLastBuild) { candidateRevs.add(objectId2Revision(singleBranch, objectId)); } } if (candidateRevs.isEmpty()) { return Collections.singletonList(objectId2Revision(singleBranch, sha1)); } return candidateRevs; */ } catch (GitException e) { // branch does not exist, there is nothing to build verbose(listener, "Failed to rev-parse: {0}", singleBranch); return emptyList(); } }
/** * In order to determine which Revisions to build. * * <p>Does the following : 1. Find all the branch revisions 2. Filter out branches that we don't * care about from the revisions. Any Revisions with no interesting branches are dropped. 3. Get * rid of any revisions that are wholly subsumed by another revision we're considering. 4. Get rid * of any revisions that we've already built. 5. Sort revisions from old to new. * * <p>NB: Alternate BuildChooser implementations are possible - this may be beneficial if "only 1" * branch is to be built, as much of this work is irrelevant in that usecase. * * @throws IOException * @throws GitException */ private List<Revision> getAdvancedCandidateRevisions( boolean isPollCall, TaskListener listener, GitUtils utils, BuildData data, BuildChooserContext context) throws GitException, IOException, InterruptedException { EnvVars env = context.getBuild().getEnvironment(); // 1. Get all the (branch) revisions that exist List<Revision> revs = new ArrayList<Revision>(utils.getAllBranchRevisions()); verbose(listener, "Starting with all the branches: {0}", revs); // 2. Filter out any revisions that don't contain any branches that we // actually care about (spec) for (Iterator<Revision> i = revs.iterator(); i.hasNext(); ) { Revision r = i.next(); // filter out uninteresting branches for (Iterator<Branch> j = r.getBranches().iterator(); j.hasNext(); ) { Branch b = j.next(); boolean keep = false; for (BranchSpec bspec : gitSCM.getBranches()) { if (bspec.matches(b.getName(), env)) { keep = true; break; } } if (!keep) { verbose(listener, "Ignoring {0} because it doesn''t match branch specifier", b); j.remove(); } } // filter out HEAD ref if it's not the only ref if (r.getBranches().size() > 1) { for (Iterator<Branch> j = r.getBranches().iterator(); j.hasNext(); ) { Branch b = j.next(); if (HEAD.matches(b.getName(), env)) { verbose( listener, "Ignoring {0} because there''s named branch for this revision", b.getName()); j.remove(); } } } if (r.getBranches().size() == 0) { verbose( listener, "Ignoring {0} because we don''t care about any of the branches that point to it", r); i.remove(); } } verbose(listener, "After branch filtering: {0}", revs); // 3. We only want 'tip' revisions revs = utils.filterTipBranches(revs); verbose(listener, "After non-tip filtering: {0}", revs); // 4. Finally, remove any revisions that have already been built. verbose(listener, "Removing what''s already been built: {0}", data.getBuildsByBranchName()); Revision lastBuiltRevision = data.getLastBuiltRevision(); for (Iterator<Revision> i = revs.iterator(); i.hasNext(); ) { Revision r = i.next(); if (data.hasBeenBuilt(r.getSha1())) { i.remove(); // keep track of new branches pointing to the last built revision if (lastBuiltRevision != null && lastBuiltRevision.getSha1().equals(r.getSha1())) { lastBuiltRevision = r; } } } verbose(listener, "After filtering out what''s already been built: {0}", revs); // if we're trying to run a build (not an SCM poll) and nothing new // was found then just run the last build again but ensure that the branch list // is ordered according to the configuration. Sorting the branch list ensures // a deterministic value for GIT_BRANCH and allows a git-flow style workflow // with fast-forward merges between branches if (!isPollCall && revs.isEmpty() && lastBuiltRevision != null) { verbose( listener, "Nothing seems worth building, so falling back to the previously built revision: {0}", data.getLastBuiltRevision()); return Collections.singletonList( utils.sortBranchesForRevision(lastBuiltRevision, gitSCM.getBranches(), env)); } // 5. sort them by the date of commit, old to new // this ensures the fairness in scheduling. final List<Revision> in = revs; return utils.git.withRepository( new RepositoryCallback<List<Revision>>() { public List<Revision> invoke(Repository repo, VirtualChannel channel) throws IOException, InterruptedException { Collections.sort(in, new CommitTimeComparator(repo)); return in; } }); }