protected void makeCombination(Map<IndexEntry, Revision> settings) { // Assume we are checked out String name = "combine-" + tid + "-" + (idx++); git.branch(name); git.checkout(name); String commit = "Hudson generated combination of:\n"; for (IndexEntry submodule : settings.keySet()) { Revision branch = settings.get(submodule); commit += " " + submodule.getFile() + " " + branch.toString() + "\n"; } listener.getLogger().print(commit); for (IndexEntry submodule : settings.keySet()) { Revision branch = settings.get(submodule); File subdir = new File(workspace, submodule.getFile()); IGitAPI subGit = new GitAPI(git.getGitExe(), new FilePath(subdir), listener, git.getEnvironment()); subGit.checkout(branch.sha1.name()); git.add(submodule.file); } git.commit(commit); }
/** Used to add a revision form complete information created elsewhere */ public void addRevision(int revnumber, String date, String authorinitials, String revremark) { Revision r = new Revision(); r.revnumber = revnumber; r.date = date; r.authorinitials = authorinitials; r.revremark = revremark; list.add(r); }
/** * Get the content (aka 'body') data. * * @throws CouchbaseLiteException */ @InterfaceAudience.Public public InputStream getContent() throws CouchbaseLiteException { if (body != null) { return body; } else { Database db = revision.getDatabase(); Attachment attachment = db.getAttachmentForSequence(revision.getSequence(), this.name); body = attachment.getContent(); return body; } }
private Revision incrementRevision(String clientId) { final Revision current = getLastModification().getRevision(); final long incrementedVersion; if (current.getVersion() == null) { incrementedVersion = 0; } else { incrementedVersion = current.getVersion() + 1; } return new Revision(incrementedVersion, clientId); }
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(); } }
public int difference(Map<IndexEntry, Revision> item, List<IndexEntry> entries) { int difference = 0; if (entries.size() != item.keySet().size()) return -1; for (IndexEntry entry : entries) { Revision b = null; for (IndexEntry e : item.keySet()) { if (e.getFile().equals(entry.getFile())) b = item.get(e); } if (b == null) return -1; if (!entry.object.equals(b.getSha1())) difference++; } return difference; }
/** * Scrolls the content so that the given revision is visible. * * @param revision the revision to scroll the client area to. */ private void scrollToRevision(Revision revision) { Rectangle revBounds = revision.getBounds(); Rectangle clientArea = getClientArea(); clientArea.x = getOrigin().x; clientArea.y = getOrigin().y; if (!clientArea.contains(revBounds.x, revBounds.y) && !clientArea.contains(revBounds.x + revBounds.width, revBounds.y + revBounds.height)) { setOrigin(revBounds.x, revBounds.y); } }
protected void makeCombination(Map<IndexEntry, Revision> settings) { // Assume we are checked out String name = "combine-" + tid + "-" + (idx++); git.branch(name); git.checkout(name); String commit = "Hudson generated combination of:\n"; for (IndexEntry submodule : settings.keySet()) { Revision branch = settings.get(submodule); commit += " " + submodule.getFile() + " " + branch.toString() + "\n"; } listener.getLogger().print(commit); for (IndexEntry submodule : settings.keySet()) { Revision branch = settings.get(submodule); File subdir = new File(workspace, submodule.getFile()); IGitAPI subGit = new GitAPI(git.getGitExe(), new FilePath(subdir), listener, git.getEnvironment()); subGit.checkout(branch.sha1.name()); git.add(submodule.file); } try { File f = File.createTempFile("gitcommit", ".txt"); FileOutputStream fos = null; try { fos = new FileOutputStream(f); fos.write(commit.getBytes()); } finally { fos.close(); } git.commit(f); f.delete(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
private boolean normalize(GitilesView.Builder view, HttpServletResponse res) throws IOException { if (view.getOldRevision() != Revision.NULL) { return false; } Revision r = view.getRevision(); Revision nr = Revision.normalizeParentExpressions(r); if (r != nr) { res.sendRedirect(view.setRevision(nr).toUrl()); return true; } return false; }
@Override public <T> ConfigurationSnapshot<T> configureFlow( Revision revision, ConfigurationRequest<T> configurationRequest) { lock(); try { // check the revision checkRevision(revision); // execute the configuration request final ConfigurationResult<T> result = configurationRequest.execute(); // update the revision final Revision newRevision = updateRevision(incrementRevision(revision.getClientId())); // build the result return new ConfigurationSnapshot( newRevision.getVersion(), result.getConfiguration(), result.isNew()); } finally { unlock(); } }
public static List<Vehicule> getAvailableVehiculesByAgence( Date startDate, Date endDate, Agence agence) { List<Vehicule> listVehiculesByAgence = Vehicule.getVehiculesByAgence(agence); List<Vehicule> listAvailableVehicules = new ArrayList<Vehicule>(); List<Session> listSessionsByAgence = Session.getSessionsByAgence(agence); List<Revision> listRevisionsByVehicule; Calendar calendar = new GregorianCalendar(); Date startRevision; Date endRevision; for (Vehicule vehicule : listVehiculesByAgence) { boolean isAvailable = true; listRevisionsByVehicule = Revision.getRevisionsByVehicule(vehicule); for (Revision revision : listRevisionsByVehicule) { startRevision = revision.date; calendar.setTime(revision.date); calendar.add(Calendar.DATE, 7); endRevision = calendar.getTime(); if (startDate.equals(startRevision) || endDate.equals(startRevision) || startDate.equals(endRevision) || endDate.equals(endRevision) || (startDate.after(startRevision) && startDate.before(endRevision)) || (endDate.after(startRevision) && endDate.before(endRevision))) { isAvailable = false; } } if (isAvailable) { for (Session session : listSessionsByAgence) { if (startDate.equals(session.dateDepart) || endDate.equals(session.dateDepart) || startDate.equals(session.dateFin) || endDate.equals(session.dateFin) || (startDate.after(session.dateDepart) && startDate.before(session.dateFin)) || (endDate.after(session.dateDepart) && endDate.before(session.dateFin))) { if (session.vehicule.id == vehicule.id) { isAvailable = false; } } } } if (isAvailable) { listAvailableVehicules.add(vehicule); } } return listAvailableVehicules; }
/** * Implementation of callback from layout algorithm. This method is called once for each revision * or branch marker to be added to the view. * * @see net.sf.versiontree.layout.drawer.IDrawMethod#draw(net.sf.versiontree.data.ITreeElement, * int, int) */ public void draw(ITreeElement element, int x, int y) { if (element instanceof IRevision) { Revision revision = new Revision(connectors, 0); revision.setRevisionData((IRevision) element); revision.addMouseListener(this); revision.setMenu(this.getMenu()); revision.setLocation(BORDER + x * (width + hspacing), BORDER + y * (height + vspacing)); revision.setSize(revision.computeSize(SWT.DEFAULT, SWT.DEFAULT)); // check if this is the current revision if ((revision.getRevisionData().getState() & ITreeElement.STATE_CURRENT) != 0) { currentRevision = revision; selectionManager.revisionSelected(currentRevision.getRevisionData(), 1); logSelectionListener.logEntrySelected(currentRevision.getRevisionData().getLogEntry()); } } else { Branch branch = new Branch(connectors, 0); branch.setBranchData(((IBranch) element)); branch.addMouseListener(this); branch.setLocation(BORDER + x * (width + hspacing), BORDER + y * (height + vspacing)); branch.setSize(branch.computeSize(SWT.DEFAULT, SWT.DEFAULT)); } }
/** * Set up submodule URLs so that they correspond to the remote pertaining to the revision that has * been checked out. */ public void setupSubmoduleUrls(Revision rev, TaskListener listener) throws GitException { String remote = null; // try to locate the remote repository from where this commit came from // (by using the heuristics that the branch name, if available, contains the remote name) // if we can figure out the remote, the other setupSubmoduleUrls method // look at its URL, and if it's a non-bare repository, we attempt to retrieve modules // from this checked out copy. // // the idea is that you have something like tree-structured repositories: at the root you have // corporate central repositories that you // ultimately push to, which all .gitmodules point to, then you have intermediate team local // repository, // which is assumed to be a non-bare repository (say, a checked out copy on a shared server // accessed via SSH) // // the abovementioned behaviour of the Git plugin makes it pick up submodules from this team // local repository, // not the corporate central. // // (Kohsuke: I have a bit of hesitation/doubt about such a behaviour change triggered by // seemingly indirect // evidence of whether the upstream is bare or not (not to mention the fact that you can't // reliably // figure out if the repository is bare or not just from the URL), but that's what apparently // has been implemented // and we care about the backward compatibility.) // // note that "figuring out which remote repository the commit came from" isn't a well-defined // question, and this is really a heuristics. The user might be telling us to build a specific // SHA1. // or maybe someone pushed directly to the workspace and so it may not correspond to any remote // branch. // so if we fail to figure this out, we back out and avoid being too clever. See JENKINS-10060 // as an example // of where our trying to be too clever here is breaking stuff for people. for (Branch br : rev.getBranches()) { String b = br.getName(); if (b != null) { int slash = b.indexOf('/'); if (slash != -1) remote = getDefaultRemote(b.substring(0, slash)); } if (remote != null) break; } if (remote == null) remote = getDefaultRemote(); if (remote != null) setupSubmoduleUrls(remote, listener); }
/** * Listener for all components on the view. Checks for left clicks on Revisions, changes the * selection and notifies the LogEntrySelectionListener. */ public void mouseDown(MouseEvent e) { if (e.getSource() instanceof Revision) { Revision selected = (Revision) e.getSource(); // exit if user wants to open contex menu on // a already selected revision if (e.button == 3 && selected.isSelected()) { return; } selectionManager.revisionSelected(selected.getRevisionData(), e.stateMask); redrawAll(); // notify listener if (selected.isSelected()) { logSelectionListener.logEntrySelected(selected.getRevisionData().getLogEntry()); } } else if (e.getSource() instanceof Branch) { Branch selected = (Branch) e.getSource(); List<IRevision> revisions = selected.getBranchData().getRevisions(); if (revisions.size() > 0) { selectionManager.branchSelected(revisions, e.stateMask); redrawAll(); } } }
/** * Compares this revision with the specified object for order. Returns a negative integer, zero, * or a positive integer as this object is less than, equal to, or greater than the specified * object. * * <p> * * @param rev revision to be compared for order with this revision. * @return a negative integer, zero, or a positive integer as this object is less than, equal * to, or greater than the specified object. */ @Override public int compareTo(Revision rev) { checkNotNull(rev); return ComparisonChain.start() .compare(this.time, rev.time) .compare(this.filename, rev.filename) .compare(this.user, rev.user) .compare(this.logmsg, rev.logmsg) .compare(this.transaction, rev.transaction) .compare(this.relName, rev.relName) .compare(this.hashCode(), rev.hashCode()) .result(); }
/** * Given a Revision, show it as if it were an entry from git whatchanged, so that it can be parsed * by GitChangeLogParser. * * @param r The Revision object * @return The git show output, in List form. * @throws GitException if errors were encountered running git show. */ public List<String> showRevision(Revision r) throws GitException { String revName = r.getSha1String(); String result = ""; if (revName != null) { result = launchCommand("show", "--no-abbrev", "--format=raw", "-M", "--raw", revName); } List<String> revShow = new ArrayList<String>(); if (result != null) { revShow = new ArrayList<String>(Arrays.asList(result.split("\\n"))); } return revShow; }
/** Get the owning document. */ @InterfaceAudience.Public public Document getDocument() { return revision.getDocument(); }
/** * Recovers the change transactions for the co-change graph from the revision information, i.e., * it assigns the transaction ids for the revisions. * * @param revisionList is a list of revisions. * @return Sorted map that maps timestamps to collections of transactions, where transactions are * sets of revisions. */ private SortedMap<Long, Collection<SortedSet<Revision>>> recoverTransactions( List<Revision> revisionList) { // Step 1: Transform the list of revisions to a sorted data structure. // A map user -> msg-entry. Map<String, Map<String, SortedMap<Long, SortedSet<String>>>> userMap = new HashMap<String, Map<String, SortedMap<Long, SortedSet<String>>>>(); // A map logmsg -> time-entry. Map<String, SortedMap<Long, SortedSet<String>>> msgMap; // A map time -> file. SortedMap<Long, SortedSet<String>> timeMap; // A set of files. SortedSet<String> fileSet; for (Revision revision : revisionList) { // A map logmsg -> time-entry. msgMap = userMap.get(revision.user); if (msgMap == null) { msgMap = new HashMap<String, SortedMap<Long, SortedSet<String>>>(); userMap.put(revision.user, msgMap); } // A map time -> file. timeMap = msgMap.get(revision.logmsg); if (timeMap == null) { timeMap = new TreeMap<Long, SortedSet<String>>(); msgMap.put(revision.logmsg, timeMap); } // A set of files. fileSet = timeMap.get(revision.time); if (fileSet == null) { fileSet = new TreeSet<String>(); timeMap.put(revision.time, fileSet); } // Add file to set. fileSet.add(revision.filename); } // Step 2: Create the result, which is // a map timestamp -> set of transactions (Long -> SortedSet), // where one transaction is a set of revisions. SortedMap<Long, Collection<SortedSet<Revision>>> result = new TreeMap<Long, Collection<SortedSet<Revision>>>(); int transaction = 0; Set<String> userSet = userMap.keySet(); for (String user : userSet) { msgMap = userMap.get(user); Set<String> msgSet = msgMap.keySet(); for (String logmsg : msgSet) { timeMap = msgMap.get(logmsg); Set<Long> timeSet = timeMap.keySet(); long firstTime = 0; Set<String> tmpFilesSeen = new TreeSet<String>(); // Detect a time window that is too long. Collection<SortedSet<Revision>> transColl; // Collection of transactions. SortedSet<Revision> revSet = null; // Transaction, i.e., set of revisions. for (Long time : timeSet) { if (time.longValue() - firstTime > timeWindow) { // Start new transaction. transaction++; firstTime = time.longValue(); tmpFilesSeen.clear(); // Retrieve (or create new) set of transactions for the timestamp. transColl = result.get(time); if (transColl == null) { transColl = new ArrayList<SortedSet<Revision>>(); result.put(time, transColl); } // New transaction (set of revisions). revSet = new TreeSet<Revision>(); transColl.add(revSet); } else if (sliding) { // The time window 'slides' with the files. firstTime = time.longValue(); } fileSet = timeMap.get(time); for (String filename : fileSet) { // Detect a time window that is too long. if (verbosity.isAtLeast(Verbosity.WARNING) && tmpFilesSeen.contains(filename)) { System.err.println( "Transaction-recovery warning: " + "Time window might be to wide "); System.err.println("(currently '" + timeWindow + "' milli-seconds). "); System.err.println( "File '" + filename + "' already contained in current transaction."); } tmpFilesSeen.add(filename); // Create revision and add revision to resulting list. Revision revision = new Revision(); revision.relName = "CO-CHANGE"; revision.filename = filename; revision.time = time; revision.user = user; revision.logmsg = logmsg; revision.transaction = transaction; revSet.add(revision); } } } } return result; }
public void createSubmoduleCombinations() throws GitException, IOException { Map<IndexEntry, Collection<Revision>> moduleBranches = new HashMap<IndexEntry, Collection<Revision>>(); for (IndexEntry submodule : git.getSubmodules("HEAD")) { File subdir = new File(workspace, submodule.getFile()); IGitAPI subGit = new GitAPI(git.getGitExe(), new FilePath(subdir), listener, git.getEnvironment()); GitUtils gu = new GitUtils(listener, subGit); Collection<Revision> items = gu.filterTipBranches(gu.getAllBranchRevisions()); filterRevisions(submodule.getFile(), items); moduleBranches.put(submodule, items); } // Remove any uninteresting branches for (IndexEntry entry : moduleBranches.keySet()) { listener.getLogger().print("Submodule " + entry.getFile() + " branches"); for (Revision br : moduleBranches.get(entry)) { listener.getLogger().print(" " + br.toString()); } listener.getLogger().print("\n"); } // Make all the possible combinations List<Map<IndexEntry, Revision>> combinations = createCombinations(moduleBranches); listener .getLogger() .println("There are " + combinations.size() + " submodule/revision combinations possible"); // Create a map which is SHA1 -> Submodule IDs that were present Map<ObjectId, List<IndexEntry>> entriesMap = new HashMap<ObjectId, List<IndexEntry>>(); // Knock out already-defined configurations for (ObjectId sha1 : git.revListAll()) { // What's the submodule configuration List<IndexEntry> entries = git.getSubmodules(sha1.name()); entriesMap.put(sha1, entries); } for (List<IndexEntry> entries : entriesMap.values()) { for (Iterator<Map<IndexEntry, Revision>> it = combinations.iterator(); it.hasNext(); ) { Map<IndexEntry, Revision> item = it.next(); if (matches(item, entries)) { it.remove(); break; } } } listener .getLogger() .println("There are " + combinations.size() + " configurations that could be generated."); ObjectId headSha1 = git.revParse("HEAD"); // Make up the combinations for (Map<IndexEntry, Revision> combination : combinations) { // By default, use the head sha1 ObjectId sha1 = headSha1; int min = Integer.MAX_VALUE; // But let's see if we can find the most appropriate place to create the branch for (ObjectId sha : entriesMap.keySet()) { List<IndexEntry> entries = entriesMap.get(sha); int value = difference(combination, entries); if (value > 0 && value < min) { min = value; sha1 = sha; } if (min == 1) { break; // look no further } } git.checkout(sha1.name()); makeCombination(combination); } }
@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); }
/** * Determines which Revisions to build. * * <p>If only one branch is chosen and only one repository is listed, then just attempt to find * the latest revision number for the chosen branch. * * <p>If multiple branches are selected or the branches include wildcards, then use the advanced * usecase as defined in the getAdvancedCandidateRevisons method. * * @throws IOException * @throws GitException */ @Override public Collection<Revision> getCandidateRevisions( boolean isPollCall, String singleBranch, GitClient git, TaskListener listener, BuildData data, BuildChooserContext context) throws GitException, IOException, InterruptedException { verbose( listener, "getCandidateRevisions({0},{1},,,{2}) considering branches to build", isPollCall, singleBranch, data); // if the branch name contains more wildcards then the simple usecase // does not apply and we need to skip to the advanced usecase if (singleBranch == null || singleBranch.contains("*")) return getAdvancedCandidateRevisions( isPollCall, listener, new GitUtils(listener, git), data, context); // check if we're trying to build a specific commit // this only makes sense for a build, there is no // reason to poll for a commit if (!isPollCall && singleBranch.matches("[0-9a-f]{6,40}")) { try { ObjectId sha1 = git.revParse(singleBranch); Revision revision = new Revision(sha1); revision.getBranches().add(new Branch("detached", sha1)); verbose(listener, "Will build the detached SHA1 {0}", sha1); return Collections.singletonList(revision); } catch (GitException e) { // revision does not exist, may still be a branch // for example a branch called "badface" would show up here verbose(listener, "Not a valid SHA1 {0}", singleBranch); } } Collection<Revision> revisions = new ArrayList<Revision>(); // if it doesn't contain '/' then it could be either a tag or an unqualified branch if (!singleBranch.contains("/")) { // the 'branch' could actually be a tag: Set<String> tags = git.getTagNames(singleBranch); if (tags.size() != 0) { verbose(listener, "{0} is a tag"); return getHeadRevision(isPollCall, singleBranch, git, listener, data); } // <tt>BRANCH</tt> is recognized as a shorthand of <tt>*/BRANCH</tt> // so check all remotes to fully qualify this branch spec for (RemoteConfig config : gitSCM.getRepositories()) { String repository = config.getName(); String fqbn = repository + "/" + singleBranch; verbose( listener, "Qualifying {0} as a branch in repository {1} -> {2}", singleBranch, repository, fqbn); revisions.addAll(getHeadRevision(isPollCall, fqbn, git, listener, data)); } } else { // either the branch is qualified (first part should match a valid remote) // or it is still unqualified, but the branch name contains a '/' List<String> possibleQualifiedBranches = new ArrayList<String>(); boolean singleBranchIsQualified = false; for (RemoteConfig config : gitSCM.getRepositories()) { String repository = config.getName(); if (singleBranch.startsWith(repository + "/")) { singleBranchIsQualified = true; break; } String fqbn = repository + "/" + singleBranch; verbose( listener, "Qualifying {0} as a branch in repository {1} -> {2}", singleBranch, repository, fqbn); possibleQualifiedBranches.add(fqbn); } if (singleBranchIsQualified) { revisions.addAll(getHeadRevision(isPollCall, singleBranch, git, listener, data)); } else { for (String fqbn : possibleQualifiedBranches) { revisions.addAll(getHeadRevision(isPollCall, fqbn, git, listener, data)); } } } return revisions; }
public Revision addRevision(Revision revision) { getRevisions().add(revision); revision.setPeriodo(this); return revision; }
/** * 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; } }); }
private Revision objectId2Revision(String singleBranch, ObjectId sha1) { Revision revision = new Revision(sha1); revision.getBranches().add(new Branch(singleBranch, sha1)); return revision; }
public Revision removeRevision(Revision revision) { getRevisions().remove(revision); revision.setPeriodo(null); return revision; }
/** * Compute the difference between original and revised sequences. * * @param orig The original sequence. * @param rev The revised sequence to be compared with the original. * @return A Revision object describing the differences. * @throws DifferenciationFailedException if the diff could not be computed. */ public Revision diff(Object[] orig, Object[] rev) throws DifferentiationFailedException { // create map eqs, such that for each item in both orig and rev // eqs(item) = firstOccurrence(item, orig); Map eqs = buildEqSet(orig, rev); // create an array such that // indx[i] = NOT_FOUND_i if orig[i] is not in rev // indx[i] = firstOccurrence(orig[i], orig) int[] indx = buildIndex(eqs, orig, NOT_FOUND_i); // create an array such that // jndx[j] = NOT_FOUND_j if orig[j] is not in rev // jndx[j] = firstOccurrence(rev[j], orig) int[] jndx = buildIndex(eqs, rev, NOT_FOUND_j); // what in effect has been done is to build a unique hash // for each item that is in both orig and rev // and to label each item in orig and new with that hash value // or a marker that the item is not common to both. eqs = null; // let gc know we're done with this Revision deltas = new Revision(); // !!! new Revision() int i = 0; int j = 0; // skip matching // skip leading items that are equal // could be written // for (i=0; indx[i] != EOS && indx[i] == jndx[i]; i++); // j = i; for (; indx[i] != EOS && indx[i] == jndx[j]; i++, j++) { /* void */ } while (indx[i] != jndx[j]) { // only equal if both == EOS // they are different int ia = i; int ja = j; // size of this delta do { // look down rev for a match // stop at a match // or if the FO(rev[j]) > FO(orig[i]) // or at the end while (jndx[j] < 0 || jndx[j] < indx[i]) { j++; } // look down orig for a match // stop at a match // or if the FO(orig[i]) > FO(rev[j]) // or at the end while (indx[i] < 0 || indx[i] < jndx[j]) { i++; } // this doesn't do a compare each line with each other line // so it won't find all matching lines } while (indx[i] != jndx[j]); // on exit we have a match // they are equal, reverse any exedent matches // it is possible to overshoot, so count back matching items while (i > ia && j > ja && indx[i - 1] == jndx[j - 1]) { --i; --j; } deltas.addDelta(Delta.newDelta(new Chunk(orig, ia, i - ia), new Chunk(rev, ja, j - ja))); // skip matching for (; indx[i] != EOS && indx[i] == jndx[j]; i++, j++) { /* void */ } } return deltas; }
/** * Parses the CVS log data and extracts revisions. * * @return List of revisions. */ private List<Revision> readRevisionList() { List<Revision> result = new ArrayList<Revision>(); String line = ""; // String relName = "CO-CHANGE"; String filename = null; Long time; String user; String logmsg; int lineno = 1; try { while ((line = reader.readLine()) != null) { // New working file. if (line.startsWith("Working file: ")) { // Set name of the current working file, // for which we pasre the revisions. filename = line.substring(14); } // New revision. if (line.startsWith("date: ")) { // Set date, author, and logmsg of the current revision. // Parse date. Start right after "date: ". time = parseDate(line.substring(6, line.indexOf("author: "))); if (time == null) { System.err.print("Error while reading the CVS date info for file: "); System.err.println(filename + "."); } // Parse author. Start right after "author: ". int posBegin = line.indexOf("author: ") + 8; int posEnd = line.indexOf(';', posBegin); user = line.substring(posBegin, posEnd); // Parse logmsg. Start on next line the date/author line. logmsg = ""; ++lineno; while (((line = reader.readLine()) != null) && !line.startsWith("----") && !line.startsWith("====")) { if (!line.startsWith("branches: ")) { logmsg += line + ReaderDataGraph.endl; } ++lineno; } // Create revision and add revision to resulting list. Revision revision = new Revision(); // revision.relName = relName.replace(' ', '_'); // Replace blanks by underline. revision.filename = filename.replace(' ', '_'); // Replace blanks by underline. revision.time = time; revision.user = user; revision.logmsg = logmsg; result.add(revision); // System.out.print("Relation: "+ relName + // " File: " + filename + // " Time: " + time.toString() + // " User: "******" LogMsg: " + logmsg); } ++lineno; } // while } catch (Exception e) { System.err.println("Exception while reading the CVS log at line " + lineno + ":"); System.err.println(e); System.err.print("Read line: "); System.err.println(line); } return result; }