From a742500840276ec694a6d25230ee52c05b385661 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 9 Nov 2012 15:26:55 +0100 Subject: wip --- .../testing/gitorious/GitoriousAtomFeedParser.java | 167 +++++++++++++++++++++ .../esper/testing/gitorious/GitoriousClient.java | 9 +- .../esper/testing/gitorious/GitoriousEventDao.java | 38 +++-- .../esper/testing/gitorious/GitoriousImporter.java | 67 ++++----- src/main/resources/ddl-core.sql | 20 +++ src/main/resources/ddl-gitorious.sql | 43 ++++++ src/main/resources/ddl.sql | 26 ---- .../esper/testing/gitorious/TestXmlParsing.java | 26 ++++ .../resources/gitorious/esper-test-project.atom | 120 +++++++++++++++ 9 files changed, 436 insertions(+), 80 deletions(-) create mode 100644 src/main/java/io/trygvis/esper/testing/gitorious/GitoriousAtomFeedParser.java create mode 100644 src/main/resources/ddl-core.sql create mode 100644 src/main/resources/ddl-gitorious.sql delete mode 100644 src/main/resources/ddl.sql create mode 100644 src/test/resources/gitorious/esper-test-project.atom (limited to 'src') diff --git a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousAtomFeedParser.java b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousAtomFeedParser.java new file mode 100644 index 0000000..7e0a1b7 --- /dev/null +++ b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousAtomFeedParser.java @@ -0,0 +1,167 @@ +package io.trygvis.esper.testing.gitorious; + +import fj.data.*; +import org.apache.abdera.*; +import org.apache.abdera.model.*; +import org.apache.abdera.model.Document; +import org.apache.abdera.model.Element; +import org.apache.abdera.parser.*; +import org.dom4j.*; +import org.dom4j.io.*; + +import java.io.*; +import java.util.*; +import java.util.List; +import java.util.regex.*; + +public class GitoriousAtomFeedParser { + public final Parser parser; + public static final STAXEventReader xmlReader = new STAXEventReader(); + + public GitoriousAtomFeedParser() { + Abdera abdera = new Abdera(); + parser = abdera.getParser(); + } + + public List parseStream(InputStream stream, Option lastUpdate, String projectSlug, String name) { + Document document = parser.parse(stream); + + Feed feed = (Feed) document.getRoot(); + + List events = new ArrayList<>(); + + for (Entry entry : feed.getEntries()) { + Date published = entry.getPublished(); + + // Check if it's old + if (published == null || lastUpdate.isSome() && lastUpdate.some().after(published)) { + continue; + } + + GitoriousEvent event = parseEntry(projectSlug, name, entry); + + if (event == null) { + continue; + } + + events.add(event); + } + + return events; + } + + private static Pattern pPatternFixer = Pattern.compile("

$", Pattern.MULTILINE); + private static Pattern branchPattern = Pattern.compile(".*/(.*)$"); + private static Pattern fromToPattern = Pattern.compile(".*/commit/([0-9a-f]*)/diffs/([0-9a-f]*)"); + + private static GitoriousEvent parseEntry(String projectSlug, String name, Entry entry) { + String entryId = entry.getId().toASCIIString(); + Date published = entry.getPublished(); + String title = entry.getTitle(); + + // Validate element + if (entryId == null || published == null || title == null) { + return null; + } + + String text = entry.getContent(); + + text = pPatternFixer.matcher(text).replaceFirst("

"); + + org.dom4j.Element content; + String xml = "

" + text + "

"; + try { + content = xmlReader.readDocument(new StringReader(xml)).getRootElement(); + + List elements = elements(content); + List nodes = nodes(elements.get(0)); + + String who = nodes.get(0).getText(); + + String event = nodes.get(1).getText().trim(); + switch (event) { + case "created repository": + case "created branch": + // This is similar "pushed", but doesn't contain any info on commit IDs or branches + case "started development of": + return null; + case "pushed": + org.dom4j.Element two = (org.dom4j.Element) nodes.get(2); + org.dom4j.Element six = (org.dom4j.Element) nodes.get(6); + + Matcher branchMatcher = branchPattern.matcher(two.attributeValue("href")); + branchMatcher.matches(); + String branch = branchMatcher.group(1); + + String href = six.attributeValue("href"); + Matcher matcher = fromToPattern.matcher(href); + matcher.matches(); + String from = matcher.group(1); + String to = matcher.group(2); + int commitCount = Integer.parseInt(two.getText().replaceFirst("([0-9]*) commit[s]?", "\\1")); + return new GitoriousPush(projectSlug, name, entryId, published, title, text, who, from, to, branch, commitCount); + default: + System.out.println("Unknown event: " + event); + return null; + } + } catch (Exception e) { + System.out.println("Could not process: " + xml); + return null; + } + } + + private static List nodes(org.dom4j.Element element) { + List nodes = new ArrayList<>(element.nodeCount()); + + @SuppressWarnings("unchecked") Iterator iterator = element.nodeIterator(); + while (iterator.hasNext()) { + nodes.add(iterator.next()); + } + return nodes; + } + + private static List elements(org.dom4j.Element content) { + List elements = new ArrayList<>(); + + @SuppressWarnings("unchecked") Iterator iterator = content.elementIterator(); + while (iterator.hasNext()) { + elements.add(iterator.next()); + } + return elements; + } +} + +abstract class GitoriousEvent { + public final String projectSlug; + public final String name; + public final String entryId; + public final Date published; + public final String title; + public final String content; + public final String who; + + protected GitoriousEvent(String projectSlug, String name, String entryId, Date published, String title, String content, String who) { + this.projectSlug = projectSlug; + this.name = name; + this.entryId = entryId; + this.published = published; + this.title = title; + this.content = content; + this.who = who; + } +} + +class GitoriousPush extends GitoriousEvent { + public final String from; + public final String to; + public final String branch; + public final int commitCount; + + GitoriousPush(String projectSlug, String name, String entryId, Date published, String title, String content, String who, String from, String to, String branch, int commitCount) { + super(projectSlug, name, entryId, published, title, content, who); + this.from = from; + this.to = to; + this.branch = branch; + this.commitCount = commitCount; + } +} diff --git a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousClient.java b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousClient.java index a58f1de..892d8d0 100644 --- a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousClient.java +++ b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousClient.java @@ -63,8 +63,8 @@ public class GitoriousClient { return all; } - public URI atomFeed(String slug) { - return URI.create(baseUrl + "/" + slug + ".atom"); + public URI atomFeed(String projectSlug, String repositoryName) { + return URI.create(baseUrl + "/" + projectSlug + "/" + repositoryName + ".atom"); } } @@ -97,7 +97,7 @@ class GitoriousProjectXml implements Comparable { return null; } - List list = (List) mainlines.elements("repository"); + @SuppressWarnings("unchecked") List list = (List) mainlines.elements("repository"); List repositoryList = new ArrayList<>(list.size()); for (Element repository : list) { GitoriousRepositoryXml r = GitoriousRepositoryXml.fromXml(slug, repository); @@ -114,7 +114,8 @@ class GitoriousProjectXml implements Comparable { public static List projectsFromXml(Element root) throws URISyntaxException { List projects = new ArrayList<>(); - for (Element project : (List) root.elements("project")) { + @SuppressWarnings("unchecked") List elements = (List) root.elements("project"); + for (Element project : elements) { GitoriousProjectXml p = GitoriousProjectXml.fromXml(project); if (p == null) { diff --git a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousEventDao.java b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousEventDao.java index 603609e..93f31a5 100644 --- a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousEventDao.java +++ b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousEventDao.java @@ -2,26 +2,44 @@ package io.trygvis.esper.testing.gitorious; import java.sql.*; -public class GitoriousEventDao { - private final PreparedStatement countEntryId; - private final PreparedStatement insertChange; +public class GitoriousEventDao extends Dao { public GitoriousEventDao(Connection c) throws SQLException { - countEntryId = c.prepareStatement("SELECT count(entry_id) FROM gitorious_event WHERE entry_id=?"); - insertChange = c.prepareStatement("INSERT INTO gitorious_event(entry_id, text) VALUES(?, ?)"); + super(c); } + private final PreparedStatement countEntryId = prepareStatement("SELECT count(entry_id) FROM gitorious_event WHERE entry_id=?"); + public int countEntryId(String entryId) throws SQLException { countEntryId.setString(1, entryId); - try(ResultSet rs = countEntryId.executeQuery()) { + try (ResultSet rs = countEntryId.executeQuery()) { rs.next(); return rs.getInt(1); } } - public void insertChange(String entryId, String text) throws SQLException { - insertChange.setString(1, entryId); - insertChange.setString(2, text); - insertChange.executeUpdate(); + private final PreparedStatement insertPush = prepareStatement("INSERT INTO gitorious_event(project_slug, name, entry_id, published, title, content, event_type, who, \"from\", \"to\", branch, commit_count) VALUES(?, ?, ?, ?, ?, ?, 'PUSH', ?, ?, ?, ?, ?)"); + + public void insertEvent(GitoriousEvent event) throws SQLException { + PreparedStatement s; + if (event instanceof GitoriousPush) { + GitoriousPush push = (GitoriousPush) event; + s = insertPush; + s.setString(7, push.who); + s.setString(8, push.from); + s.setString(9, push.to); + s.setString(10, push.branch); + s.setInt(11, push.commitCount); + } else { + throw new SQLException("Unknown event type: " + event.getClass().getName()); + } + + s.setString(1, event.projectSlug); + s.setString(2, event.name); + s.setString(3, event.entryId); + s.setTimestamp(4, dateToTimestamp.f(event.published)); + s.setString(5, event.title); + s.setString(6, event.content); + s.executeUpdate(); } } diff --git a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousImporter.java b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousImporter.java index 4cd0916..4ee6322 100644 --- a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousImporter.java +++ b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousImporter.java @@ -5,14 +5,13 @@ import fj.data.*; import static fj.data.Option.*; import io.trygvis.esper.testing.*; import static java.lang.System.*; -import org.apache.abdera.*; -import org.apache.abdera.model.*; import org.apache.abdera.parser.*; import org.codehaus.httpcache4j.*; import org.codehaus.httpcache4j.cache.*; import org.codehaus.httpcache4j.client.*; import java.io.*; +import java.net.*; import java.sql.*; import java.util.Date; import java.util.*; @@ -21,7 +20,7 @@ import java.util.Set; import java.util.concurrent.*; public class GitoriousImporter { - private final Parser parser; + private final GitoriousAtomFeedParser parser; private final BoneCP boneCp; private final GitoriousClient gitoriousClient; private final HTTPCache httpCache; @@ -32,8 +31,7 @@ public class GitoriousImporter { } public GitoriousImporter(String jdbcUrl, String jdbcUsername, String jdbcPassword) throws Exception { - Abdera abdera = new Abdera(); - parser = abdera.getParser(); + parser = new GitoriousAtomFeedParser(); BoneCPConfig config = new BoneCPConfig(); config.setJdbcUrl(jdbcUrl); @@ -48,22 +46,25 @@ public class GitoriousImporter { gitoriousClient = new GitoriousClient(httpCache, "http://gitorious.org"); - final ScheduledThreadPoolExecutor service = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor service = new ScheduledThreadPoolExecutor(2); + boolean projectsUpdateEnabled = false; int projectsUpdateDelay = 0 * 1000; int projectsUpdateInterval = 60 * 1000; int repositoriesUpdateDelay = 0; int repositoriesUpdateInterval = 60 * 1000; - service.scheduleAtFixedRate(new Runnable() { - public void run() { - try { - discoverProjects(); - } catch (Exception e) { - e.printStackTrace(System.out); + if (projectsUpdateEnabled) { + service.scheduleAtFixedRate(new Runnable() { + public void run() { + try { + discoverProjects(); + } catch (Exception e) { + e.printStackTrace(System.out); + } } - } - }, projectsUpdateDelay, projectsUpdateInterval, TimeUnit.MILLISECONDS); + }, projectsUpdateDelay, projectsUpdateInterval, TimeUnit.MILLISECONDS); + } service.scheduleAtFixedRate(new Runnable() { public void run() { @@ -90,13 +91,15 @@ public class GitoriousImporter { System.out.println("New project: " + project.slug + ", has " + project.repositories.size() + " repositories."); projectDao.insertProject(project.slug); for (GitoriousRepositoryXml repository : project.repositories) { - repoDao.insertRepository(repository.projectSlug, repository.name, gitoriousClient.atomFeed(project.slug)); + URI atomFeed = gitoriousClient.atomFeed(repository.projectSlug, repository.name); + repoDao.insertRepository(repository.projectSlug, repository.name, atomFeed); } } else { for (GitoriousRepositoryXml repository : project.repositories) { if (repoDao.countRepositories(repository.projectSlug, repository.name) == 0) { System.out.println("New repository for project " + repository.projectSlug + ": " + repository.name); - repoDao.insertRepository(repository.projectSlug, repository.name, gitoriousClient.atomFeed(project.slug)); + URI atomFeed = gitoriousClient.atomFeed(repository.projectSlug, repository.name); + repoDao.insertRepository(repository.projectSlug, repository.name, atomFeed); } } @@ -160,7 +163,7 @@ public class GitoriousImporter { GitoriousRepositoryDao repositoryDao = daos.gitoriousRepositoryDao; GitoriousEventDao eventDao = daos.gitoriousEventDao; - Option lastUpdate = repository.lastUpdate; + Option lastUpdate = repository.lastSuccessfulUpdate; System.out.println("Fetching " + repository.atomFeed); @@ -174,9 +177,9 @@ public class GitoriousImporter { System.out.println("responseDate = " + responseDate); - Document document; + List events; try { - document = parser.parse(response.getPayload().getInputStream()); + events = parser.parseStream(response.getPayload().getInputStream(), lastUpdate, repository.projectSlug, repository.name); } catch (ParseException e) { repositoryDao.updateTimestamp(repository.projectSlug, repository.name, new Timestamp(currentTimeMillis()), Option.none()); System.out.println("Error parsing " + repository.atomFeed); @@ -184,28 +187,12 @@ public class GitoriousImporter { return; } - Feed feed = (Feed) document.getRoot(); - - for (Entry entry : feed.getEntries()) { - String entryId = entry.getId().toASCIIString(); - Date published = entry.getPublished(); - String title = entry.getTitle(); - - // Validate element - if (entryId == null || published == null || title == null) { - continue; - } - - if (lastUpdate.isSome() && lastUpdate.some().after(published)) { - System.out.println("Old entry: " + repository.atomFeed + ":" + entryId); - continue; - } - - if (eventDao.countEntryId(entryId) == 0) { - System.out.println("New entry: " + repository.atomFeed + ":" + entryId); - eventDao.insertChange(entryId, title); + for (GitoriousEvent event : events) { + if (eventDao.countEntryId(event.entryId) == 0) { + System.out.println("New entry in " + repository.atomFeed + ": " + event.entryId); + eventDao.insertEvent(event); } else { - System.out.println("Already imported entry: " + entryId); + System.out.println("Already imported entry: " + event.entryId); } } diff --git a/src/main/resources/ddl-core.sql b/src/main/resources/ddl-core.sql new file mode 100644 index 0000000..662ed10 --- /dev/null +++ b/src/main/resources/ddl-core.sql @@ -0,0 +1,20 @@ +BEGIN; + +DROP TABLE IF EXISTS subscription_gitorious_repository; +DROP TABLE IF EXISTS subscriber; + +CREATE TABLE subscriber ( + name VARCHAR(100) PRIMARY KEY +); + +CREATE TABLE subscription_gitorious_repository ( + subscriber_name VARCHAR(100) REFERENCES subscriber (name), + gitorious_repository_project_slug VARCHAR(100), + gitorious_repository_name VARCHAR(100) +-- CONSTRAINT subscription_gitorious_repository_2_gitorious_repository FOREIGN KEY (gitorious_repository_project_slug, gitorious_repository_name) REFERENCES gitorious_repository (project_slug, name) +); + +INSERT INTO subscriber VALUES ('trygvis'); +INSERT INTO subscription_gitorious_repository VALUES ('trygvis','esper-test-project', 'esper-test-project'); + +COMMIT; diff --git a/src/main/resources/ddl-gitorious.sql b/src/main/resources/ddl-gitorious.sql new file mode 100644 index 0000000..929a326 --- /dev/null +++ b/src/main/resources/ddl-gitorious.sql @@ -0,0 +1,43 @@ +BEGIN; + +DROP TABLE IF EXISTS gitorious_event; +DROP TABLE IF EXISTS gitorious_repository; +DROP TABLE IF EXISTS gitorious_project; + +CREATE TABLE gitorious_project ( + slug VARCHAR(1000) PRIMARY KEY +); + +CREATE TABLE gitorious_repository ( + project_slug VARCHAR(1000) NOT NULL, + name VARCHAR(1000) NOT NULL, + atom_feed VARCHAR(1000) NOT NULL, + last_update TIMESTAMP, + last_successful_update TIMESTAMP, + CONSTRAINT gitorious_repository_pk PRIMARY KEY (project_slug, name), + CONSTRAINT gitorious_repository_2_gitorious_project FOREIGN KEY (project_slug) REFERENCES gitorious_project (slug) +); + +CREATE TABLE gitorious_event ( + project_slug VARCHAR(1000) NOT NULL, + name VARCHAR(1000) NOT NULL, + +-- The raw values for debugging + entry_id VARCHAR(1000) PRIMARY KEY, + published TIMESTAMP NOT NULL, + title VARCHAR(1000), + content VARCHAR(1000), + + event_type VARCHAR(20), + who VARCHAR(100), +-- Push + "from" CHAR(40), + "to" CHAR(40), + branch VARCHAR(100), + commit_count INTEGER +); + +INSERT INTO gitorious_project VALUES ('esper-test-project'); +INSERT INTO gitorious_repository VALUES ('esper-test-project', 'esper-test-project', 'https://gitorious.org/esper-test-project/esper-test-project.atom'); + +COMMIT; diff --git a/src/main/resources/ddl.sql b/src/main/resources/ddl.sql deleted file mode 100644 index 4e641cc..0000000 --- a/src/main/resources/ddl.sql +++ /dev/null @@ -1,26 +0,0 @@ -BEGIN; - -DROP TABLE IF EXISTS gitorious_event; -DROP TABLE IF EXISTS gitorious_repository; -DROP TABLE IF EXISTS gitorious_project; - -CREATE TABLE gitorious_project ( - slug VARCHAR(1000) PRIMARY KEY -); - -CREATE TABLE gitorious_repository ( - project_slug VARCHAR(1000) NOT NULL, - name VARCHAR(1000) NOT NULL, - atom_feed VARCHAR(1000) NOT NULL, - last_update TIMESTAMP, - last_successful_update TIMESTAMP, - CONSTRAINT gitorious_repository_pk PRIMARY KEY (project_slug, name), - CONSTRAINT gitorious_repository_2_gitorious_project FOREIGN KEY (project_slug) REFERENCES gitorious_project (slug) -); - -CREATE TABLE gitorious_event ( - entry_id VARCHAR(1000) PRIMARY KEY, - text VARCHAR(1000) -); - -COMMIT; diff --git a/src/test/java/io/trygvis/esper/testing/gitorious/TestXmlParsing.java b/src/test/java/io/trygvis/esper/testing/gitorious/TestXmlParsing.java index 2d5945e..a6ba2f7 100644 --- a/src/test/java/io/trygvis/esper/testing/gitorious/TestXmlParsing.java +++ b/src/test/java/io/trygvis/esper/testing/gitorious/TestXmlParsing.java @@ -1,10 +1,12 @@ package io.trygvis.esper.testing.gitorious; +import fj.data.*; import junit.framework.*; import org.dom4j.*; import java.io.*; import java.util.*; +import java.util.List; public class TestXmlParsing extends TestCase { public void testProjectParsing() throws Exception { @@ -21,4 +23,28 @@ public class TestXmlParsing extends TestCase { assertEquals(2, project.repositories.size()); } } + + public void testEventParsing() throws Exception { + GitoriousAtomFeedParser parser = new GitoriousAtomFeedParser(); + try (InputStream stream = getClass().getResourceAsStream("/gitorious/esper-test-project.atom")) { + + List events = parser.parseStream(stream, Option.none(), "esper-test-project", "esper-test-project"); + + assertEquals(5, events.size()); + + GitoriousPush p0 = (GitoriousPush) events.get(0); + assertEquals("tag:gitorious.org,2005:Event/43390557", p0.entryId); + assertEquals("trygvis", p0.who); + assertEquals("dd6f41a45587f3f4d81ba7c0a874fcaf94e67365", p0.from); + assertEquals("0d3de9c126c6f84e46e3f92244b4d99a4a3a3aa5", p0.to); + assertEquals("my-branch", p0.branch); + + GitoriousPush p3 = (GitoriousPush) events.get(3); + assertEquals("tag:gitorious.org,2005:Event/43390409", p3.entryId); + assertEquals("trygvis", p3.who); + assertEquals("7054468bc18ae6e66aeccecc87896a90b21f2101", p3.from); + assertEquals("4aa8a70c00a9527035e3f9b2fb69bbc4779aa090", p3.to); + assertEquals("master", p3.branch); + } + } } diff --git a/src/test/resources/gitorious/esper-test-project.atom b/src/test/resources/gitorious/esper-test-project.atom new file mode 100644 index 0000000..44d9113 --- /dev/null +++ b/src/test/resources/gitorious/esper-test-project.atom @@ -0,0 +1,120 @@ + + + tag:gitorious.org,2005:/esper-test-project/esper-test-project + + + Gitorious: esper-test-project/esper-test-project activity + 2012-11-09T14:06:33Z + + tag:gitorious.org,2005:Event/43390557 + 2012-11-09T14:06:33Z + 2012-11-09T14:06:33Z + + Trygve Laugstøl pushed 1 commit to esper-test-project/esper-test-project:my-branch. View diff + <p><a href="/~trygvis">trygvis</a> pushed <a href="/esper-test-project/esper-test-project/commits/my-branch" class="commit_event_toggler" gts:id="43390557" gts:url="/events/43390557/commits" id="commits_in_event_43390557_toggler">1 commit</a> to <a href="/esper-test-project/esper-test-project/commits/my-branch">esper-test-project/esper-test-project:my-branch</a>. <a href="/esper-test-project/esper-test-project/commit/dd6f41a45587f3f4d81ba7c0a874fcaf94e67365/diffs/0d3de9c126c6f84e46e3f92244b4d99a4a3a3aa5">View diff</a></p> +<p>my-branch changed from dd6f41a to 0d3de9c<p> +<p></p> + + + Trygve Laugstøl + + + + tag:gitorious.org,2005:Event/43390538 + 2012-11-09T13:58:05Z + 2012-11-09T13:58:05Z + + Trygve Laugstøl created branch my-branch on esper-test-project/esper-test-project + <p><a href="/~trygvis">trygvis</a> created branch <a href="/esper-test-project/esper-test-project/commits/my-branch">my-branch</a> on <a href="/esper-test-project">esper-test-project</a>/<a href="http://gitorious.org/esper-test-project/esper-test-project">esper-test-project</a></p> +<p><p> +<p></p> + + + Trygve Laugstøl + + + + tag:gitorious.org,2005:Event/43390537 + 2012-11-09T13:57:31Z + 2012-11-09T13:57:31Z + + Trygve Laugstøl pushed 1 commit to esper-test-project/esper-test-project:master. View diff + <p><a href="/~trygvis">trygvis</a> pushed <a href="/esper-test-project/esper-test-project/commits/master" class="commit_event_toggler" gts:id="43390537" gts:url="/events/43390537/commits" id="commits_in_event_43390537_toggler">1 commit</a> to <a href="/esper-test-project/esper-test-project/commits/master">esper-test-project/esper-test-project:master</a>. <a href="/esper-test-project/esper-test-project/commit/776cb0a8b1c8f56cb0f2ec919bee87665bfdc3b7/diffs/3f0ef74c1a660e9adc7d9b6668de657bdabe245a">View diff</a></p> +<p>master changed from 776cb0a to 3f0ef74<p> +<p></p> + + + Trygve Laugstøl + + + + tag:gitorious.org,2005:Event/43390416 + 2012-11-09T12:26:09Z + 2012-11-09T12:26:09Z + + Trygve Laugstøl pushed 1 commit to esper-test-project/esper-test-project:master. View diff + <p><a href="/~trygvis">trygvis</a> pushed <a href="/esper-test-project/esper-test-project/commits/master" class="commit_event_toggler" gts:id="43390416" gts:url="/events/43390416/commits" id="commits_in_event_43390416_toggler">1 commit</a> to <a href="/esper-test-project/esper-test-project/commits/master">esper-test-project/esper-test-project:master</a>. <a href="/esper-test-project/esper-test-project/commit/4aa8a70c00a9527035e3f9b2fb69bbc4779aa090/diffs/776cb0a8b1c8f56cb0f2ec919bee87665bfdc3b7">View diff</a></p> +<p>master changed from 4aa8a70 to 776cb0a<p> +<p></p> + + + Trygve Laugstøl + + + + tag:gitorious.org,2005:Event/43390409 + 2012-11-09T12:22:07Z + 2012-11-09T12:22:07Z + + Trygve Laugstøl pushed 3 commits to esper-test-project/esper-test-project:master. View diff + <p><a href="/~trygvis">trygvis</a> pushed <a href="/esper-test-project/esper-test-project/commits/master" class="commit_event_toggler" gts:id="43390409" gts:url="/events/43390409/commits" id="commits_in_event_43390409_toggler">3 commits</a> to <a href="/esper-test-project/esper-test-project/commits/master">esper-test-project/esper-test-project:master</a>. <a href="/esper-test-project/esper-test-project/commit/7054468bc18ae6e66aeccecc87896a90b21f2101/diffs/4aa8a70c00a9527035e3f9b2fb69bbc4779aa090">View diff</a></p> +<p>master changed from 7054468 to 4aa8a70<p> +<p></p> + + + Trygve Laugstøl + + + + tag:gitorious.org,2005:Event/43390405 + 2012-11-09T12:21:29Z + 2012-11-09T12:21:29Z + + Trygve Laugstøl pushed 2 commits to esper-test-project/esper-test-project:master. View diff + <p><a href="/~trygvis">trygvis</a> pushed <a href="/esper-test-project/esper-test-project/commits/master" class="commit_event_toggler" gts:id="43390405" gts:url="/events/43390405/commits" id="commits_in_event_43390405_toggler">2 commits</a> to <a href="/esper-test-project/esper-test-project/commits/master">esper-test-project/esper-test-project:master</a>. <a href="/esper-test-project/esper-test-project/commit/80c5808f3dd2e32abf94a06d27e4eb3a0b6590d1/diffs/7054468bc18ae6e66aeccecc87896a90b21f2101">View diff</a></p> +<p>master changed from 80c5808 to 7054468<p> +<p></p> + + + Trygve Laugstøl + + + + tag:gitorious.org,2005:Event/43390404 + 2012-11-09T12:19:57Z + 2012-11-09T12:19:57Z + + Trygve Laugstøl started development of esper-test-project/esper-test-project + <p><a href="/~trygvis">trygvis</a> started development of <a href="/esper-test-project">esper-test-project</a>/<a href="http://gitorious.org/esper-test-project/esper-test-project">esper-test-project</a></p> +<p><p> +<p></p> + + + Trygve Laugstøl + + + + tag:gitorious.org,2005:Event/43390388 + 2012-11-09T12:05:04Z + 2012-11-09T12:05:04Z + + Trygve Laugstøl created repository esper-test-project in esper-test-project + <p><a href="/~trygvis">trygvis</a> created repository <a href="/esper-test-project/esper-test-project">esper-test-project</a> in <a href="/esper-test-project">esper-test-project</a></p> +<p><p> +<p></p> + + + Trygve Laugstøl + + + -- cgit v1.2.3