Skip to content

Commit

Permalink
Make ChangeSet more full-featured
Browse files Browse the repository at this point in the history
A Changeset now includes a message as well as author/committer objects
modeled on JGit's PersonIdent.

This is a breaking change for anyone who uses ChangeSet.
The payoff is that on complex git-based repositories, users can now better handle the distributed nature of git.

The time-based CommitRanges provided by RepoDriller now use the committer time when doing time comparisons.
This is what the user generally intends: "the time at which this commit entered the repository".

Addresses mauricioaniche#96.
  • Loading branch information
davisjam authored and Jamie Davis committed Oct 19, 2017
1 parent 3bfaa01 commit 95f9814
Show file tree
Hide file tree
Showing 16 changed files with 344 additions and 167 deletions.
104 changes: 75 additions & 29 deletions src/main/java/org/repodriller/domain/ChangeSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,45 +16,88 @@

package org.repodriller.domain;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.ArrayList;
import java.util.List;

/**
* A ChangeSet is metadata that uniquely identifies a Commit from an SCM.
*
* @author Mauricio Aniche
* A ChangeSet is metadata about a Commit from an SCM.
* It's "everything but the diff".
*/
public class ChangeSet {

private final Calendar date;
private final String id;
private String id; /* Unique within an SCM. */
private String message;

public ChangeSet(String id, Calendar date) {
private CommitPerson author; /* Person who committed it. */
private CommitPerson committer; /* Person who merged it. This is probably the field you want. */

public ChangeSet(String id, String message, CommitPerson author) {
this.id = id;
this.date = date;
this.message = message;

this.author = author;
this.committer = this.author;
}

/**
* @return The time at which this ChangeSet was created by a developer
*/
public Calendar getTime() {
return date;
public ChangeSet(String id, String message, CommitPerson author, CommitPerson committer) {
this.id = id;
this.message = message;

this.author = author;
this.committer = committer;
}

/**
* @return The id of this ChangeSet in its SCM
* @return Unique ID within SCM
*/
public String getId() {
return id;
}

/**
* @return Commit message
*/
public String getMessage() {
return message;
}

/**
* How the ChangeSet was created.
*
* @return Person who authored the commit. See {@link ChangeSet#getCommitter}.
*/
public CommitPerson getAuthor() {
return author;
}

/**
* How the ChangeSet entered the codebase, e.g. when a PR is accepted.
*
* @return Person who merged the commit.
*/
public CommitPerson getCommitter() {
return committer;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((date == null) ? 0 : date.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
final int prime1 = 17;
final int prime2 = 31;

int hash = prime1;

/* I'm sure there's a more efficient way to do this... */
List<Object> members = new ArrayList<Object>();
members.add(id);
members.add(message);
members.add(author);
members.add(committer);

for (Object member : members) {
hash = prime2*hash + ((member == null) ? 0 : member.hashCode());
}

return hash;
}

@Override
Expand All @@ -69,24 +112,27 @@ public boolean equals(Object obj) {

/* Compare two distinct instances. */
ChangeSet other = (ChangeSet) obj;
if (date == null) {
if (other.date != null)
return false;
} else if (!date.equals(other.date))
return false;

if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
}
else {
if (!id.equals(other.id))
return false;
}

return true;
}

@Override
public String toString() {
return "[" + id + ", " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date.getTime()) + "]";
if (author.equals(committer)) {
return String.format("%s: author %s", id, author);
}
else {
return String.format("%s: author %s, committer %s", id, author, committer);
}
}

}
}
95 changes: 95 additions & 0 deletions src/main/java/org/repodriller/domain/CommitPerson.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.repodriller.domain;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
* A POJO to track details about a person involved with a commit.
*/
public class CommitPerson {
public String name;
public String email;
public Calendar time;

public CommitPerson(String author, String email, Calendar time) {
this.name = author;
this.email = email;
this.time = time;
}

public CommitPerson(CommitPerson c) {
this.name = c.name;
this.email = c.email;
this.time = c.time;
}

@Override
public String toString() {
return String.format("%s <%s> at %s", name, email, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time));
}

@Override
public int hashCode() {
final int prime1 = 17;
final int prime2 = 31;

int hash = prime1;

/* I'm sure there's a more efficient way to do this... */
List<Object> members = new ArrayList<Object>();
members.add(name);
members.add(email);
members.add(time);

for (Object member : members) {
hash = prime2*hash + ((member == null) ? 0 : member.hashCode());
}

return hash;
}

@Override
public boolean equals(Object obj) {
/* Boilerplate. */
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;

/* Compare two distinct instances. */
CommitPerson other = (CommitPerson) obj;

if (name == null) {
if (other.name != null)
return false;
}
else {
if (!name.equals(other.name))
return false;
}

if (email == null) {
if (other.email != null)
return false;
}
else {
if (!email.equals(other.name))
return false;
}

if (time == null) {
if (other.time != null)
return false;
}
else {
if (!time.equals(other.name))
return false;
}

return true;
}
}
12 changes: 6 additions & 6 deletions src/main/java/org/repodriller/filter/range/BetweenDates.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.repodriller.scm.SCM;

public class BetweenDates implements CommitRange {

private Calendar from;
private Calendar to;

Expand All @@ -19,22 +19,22 @@ public BetweenDates(Calendar from, Calendar to) {

@Override
public List<ChangeSet> get(SCM scm) {

List<ChangeSet> all = scm.getChangeSets();

LinkedList<ChangeSet> filtered = new LinkedList<ChangeSet>();

for(ChangeSet cs : all) {
if(isInTheRange(cs)) {
filtered.addLast(cs);
}
}

return filtered;
}

private boolean isInTheRange(ChangeSet cs) {
return from.before(cs.getTime()) && to.after(cs.getTime());
return from.before(cs.getCommitter().time) && to.after(cs.getCommitter().time);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import org.repodriller.scm.SCM;

/**
* Return a set of commits from an SCM.
* A CommitRange is a subset of all commits from the SCM, returned in the order in which they should be processed.
*
* @author Mauricio Aniche
*/
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/org/repodriller/filter/range/LastMonths.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ public LastMonths(int months) {

@Override
public List<ChangeSet> get(SCM scm) {

LinkedList<ChangeSet> filtered = new LinkedList<ChangeSet>();
List<ChangeSet> all = scm.getChangeSets();
sixMonthsAgo = all.get(0).getTime();

sixMonthsAgo = all.get(0).getCommitter().time;
sixMonthsAgo.add(Calendar.MONTH, -months);
filtered.add(all.get(0));

for(ChangeSet cs : all) {
if(cs.getTime().after(sixMonthsAgo)) {
if(cs.getCommitter().time.after(sixMonthsAgo)) {
filtered.addLast(cs);
}
}

return filtered;
}

Expand Down
22 changes: 11 additions & 11 deletions src/main/java/org/repodriller/filter/range/MonthlyCommits.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,34 @@ public class MonthlyCommits implements CommitRange {
private final long monthsInMillis;

public MonthlyCommits(int months) {
monthsInMillis = 1000L * 60L * 60L * 24L * 30L * (long) months;
monthsInMillis = 1000L * 60L * 60L * 24L * 30L * months;
}

@Override
public List<ChangeSet> get(SCM scm) {

List<ChangeSet> all = scm.getChangeSets();

LinkedList<ChangeSet> filtered = new LinkedList<ChangeSet>();
filtered.add(all.get(0));

for(ChangeSet cs : all) {
if(isFarFromTheLastOne(cs, filtered)) {
filtered.addLast(cs);
}
}

return filtered;
}

private boolean isFarFromTheLastOne(ChangeSet cs, LinkedList<ChangeSet> filtered) {
ChangeSet lastOne = filtered.getLast();
long lastInMillis = lastOne.getTime().getTimeInMillis();
long currentInMillis = cs.getTime().getTimeInMillis();

long lastInMillis = lastOne.getCommitter().time.getTimeInMillis();
long currentInMillis = cs.getCommitter().time.getTimeInMillis();

return (lastInMillis - currentInMillis >= monthsInMillis);
}


}
12 changes: 6 additions & 6 deletions src/main/java/org/repodriller/filter/range/SinceCommit.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.repodriller.scm.SCM;

public class SinceCommit implements CommitRange {

private Calendar since;

public SinceCommit(Calendar since) {
Expand All @@ -17,22 +17,22 @@ public SinceCommit(Calendar since) {

@Override
public List<ChangeSet> get(SCM scm) {

List<ChangeSet> all = scm.getChangeSets();

LinkedList<ChangeSet> filtered = new LinkedList<ChangeSet>();

for(ChangeSet cs : all) {
if(isInTheRange(cs)) {
filtered.addLast(cs);
}
}

return filtered;
}

private boolean isInTheRange(ChangeSet cs) {
return since.before(cs.getTime());
return since.before(cs.getCommitter().time);
}


Expand Down
Loading

0 comments on commit 95f9814

Please sign in to comment.