Start refactoring of the trigger system:

- Move each trigger handler into its own file
- Add dictionary helper classes for easier reading and writing of dict-based data
- Extract the web hook payload -> internal representation building for each trigger system
- Add tests for this transformation
- Remove support for Github archived-based building
This commit is contained in:
Joseph Schorr 2015-09-11 17:40:32 -04:00
parent 2ff77df946
commit 49b575afb6
25 changed files with 2449 additions and 1602 deletions

View file

@ -12,8 +12,8 @@ from playhouse.test_utils import assert_query_count
from endpoints.api import api_bp, api
from endpoints.building import PreparedBuild
from endpoints.webhooks import webhooks
from endpoints.trigger import BuildTriggerHandler
from app import app
from buildtrigger.basehandler import BuildTriggerHandler
from initdb import setup_database_for_testing, finished_database_for_testing
from data import database, model
from data.database import RepositoryActionCount

View file

@ -0,0 +1,194 @@
import unittest
import json
from jsonschema import validate, ValidationError
from buildtrigger.basehandler import METADATA_SCHEMA
from buildtrigger.bitbuckethandler import get_transformed_webhook_payload as bb_webhook
from buildtrigger.bitbuckethandler import get_transformed_commit_info as bb_commit
from buildtrigger.githubhandler import get_transformed_webhook_payload as gh_webhook
from buildtrigger.gitlabhandler import get_transformed_webhook_payload as gl_webhook
class TestPrepareTrigger(unittest.TestCase):
def test_bitbucket_commit(self):
with open('test/triggerjson/bitbucket_commit.json') as f:
commit = json.loads(f.read())
ref = 'refs/heads/somebranch'
default_branch = 'somebranch'
repository_name = 'foo/bar'
def lookup_author(_):
return {
'user': {
'username': 'cooluser',
'avatar': 'http://some/avatar/url'
}
}
expected = {
"commit": u"abdeaf1b2b4a6b9ddf742c1e1754236380435a62",
"ref": u"refs/heads/somebranch",
"git_url": u"git@bitbucket.org:foo/bar.git",
"default_branch": u"somebranch",
"commit_info": {
"url": u"https://bitbucket.org/foo/bar/commits/abdeaf1b2b4a6b9ddf742c1e1754236380435a62",
"date": u"2012-07-24 00:26:36",
"message": u"making some changes\n",
"author": {
"url": u"https://bitbucket.org/cooluser/",
"avatar_url": u"http://some/avatar/url",
"username": u"cooluser",
}
}
}
created = bb_commit(commit, ref, default_branch, repository_name, lookup_author)
self.assertEquals(expected, created)
validate(created, METADATA_SCHEMA)
def test_bitbucket_webhook_payload(self):
with open('test/triggerjson/bitbucket_webhook.json') as f:
payload = json.loads(f.read())
expected = {
"commit": u"af64ae7188685f8424040b4735ad12941b980d75",
"ref": u"refs/heads/master",
"git_url": u"git@bitbucket.org:jscoreos/another-repo.git",
"commit_info": {
"url": u"https://bitbucket.org/jscoreos/another-repo/commits/af64ae7188685f8424040b4735ad12941b980d75",
"date": u"2015-09-10T20:40:54+00:00",
"message": u"Dockerfile edited online with Bitbucket",
"author": {
"username": u"jscoreos",
"url": u"https://bitbucket.org/jscoreos/",
"avatar_url": u"https://bitbucket.org/account/jscoreos/avatar/32/",
},
"committer": {
"username": u"jscoreos",
"url": u"https://bitbucket.org/jscoreos/",
"avatar_url": u"https://bitbucket.org/account/jscoreos/avatar/32/",
},
},
}
created = bb_webhook(payload)
self.assertEquals(expected, created)
validate(created, METADATA_SCHEMA)
def test_github_webhook_payload(self):
with open('test/triggerjson/github_webhook.json') as f:
payload = json.loads(f.read())
expected = {
'commit': u'410f4cdf8ff09b87f245b13845e8497f90b90a4c',
'ref': u'refs/heads/master',
'git_url': u'git@github.com:josephschorr/anothertest.git',
'commit_info': {
'url': u'https://github.com/josephschorr/anothertest/commit/410f4cdf8ff09b87f245b13845e8497f90b90a4c',
'date': u'2015-09-11T14:26:16-04:00',
'message': u'Update Dockerfile',
'committer': {
'username': u'josephschorr',
},
'author': {
'username': u'josephschorr',
},
},
}
created = gh_webhook(payload)
self.assertEquals(expected, created)
validate(created, METADATA_SCHEMA)
def test_github_webhook_payload_with_lookup(self):
with open('test/triggerjson/github_webhook.json') as f:
payload = json.loads(f.read())
expected = {
'commit': u'410f4cdf8ff09b87f245b13845e8497f90b90a4c',
'ref': u'refs/heads/master',
'git_url': u'git@github.com:josephschorr/anothertest.git',
'commit_info': {
'url': u'https://github.com/josephschorr/anothertest/commit/410f4cdf8ff09b87f245b13845e8497f90b90a4c',
'date': u'2015-09-11T14:26:16-04:00',
'message': u'Update Dockerfile',
'committer': {
'username': u'josephschorr',
'url': u'http://github.com/josephschorr',
'avatar_url': u'http://some/avatar/url',
},
'author': {
'username': u'josephschorr',
'url': u'http://github.com/josephschorr',
'avatar_url': u'http://some/avatar/url',
},
},
}
def lookup_user(_):
return {
'html_url': 'http://github.com/josephschorr',
'avatar_url': 'http://some/avatar/url'
}
created = gh_webhook(payload, lookup_user=lookup_user)
self.assertEquals(expected, created)
validate(created, METADATA_SCHEMA)
def test_gitlab_webhook_payload(self):
with open('test/triggerjson/gitlab_webhook.json') as f:
payload = json.loads(f.read())
expected = {
'commit': u'fb88379ee45de28a0a4590fddcbd8eff8b36026e',
'ref': u'refs/heads/master',
'git_url': u'git@gitlab.com:jzelinskie/www-gitlab-com.git',
'commit_info': {
'url': u'https://gitlab.com/jzelinskie/www-gitlab-com/commit/fb88379ee45de28a0a4590fddcbd8eff8b36026e',
'date': u'2015-08-13T19:33:18+00:00',
'message': u'Fix link\n',
},
}
created = gl_webhook(payload)
self.assertEquals(expected, created)
validate(created, METADATA_SCHEMA)
def test_gitlab_webhook_payload_with_lookup(self):
with open('test/triggerjson/gitlab_webhook.json') as f:
payload = json.loads(f.read())
expected = {
'commit': u'fb88379ee45de28a0a4590fddcbd8eff8b36026e',
'ref': u'refs/heads/master',
'git_url': u'git@gitlab.com:jzelinskie/www-gitlab-com.git',
'commit_info': {
'url': u'https://gitlab.com/jzelinskie/www-gitlab-com/commit/fb88379ee45de28a0a4590fddcbd8eff8b36026e',
'date': u'2015-08-13T19:33:18+00:00',
'message': u'Fix link\n',
'author': {
'username': 'jzelinskie',
'url': 'http://gitlab.com/jzelinskie',
'avatar_url': 'http://some/avatar/url',
},
},
}
def lookup_user(_):
return {
'username': 'jzelinskie',
'html_url': 'http://gitlab.com/jzelinskie',
'avatar_url': 'http://some/avatar/url',
}
created = gl_webhook(payload, lookup_user=lookup_user)
self.assertEquals(expected, created)
validate(created, METADATA_SCHEMA)
if __name__ == '__main__':
unittest.main()

View file

@ -1,7 +1,7 @@
import unittest
import re
from endpoints.trigger import matches_ref
from buildtrigger.triggerutil import matches_ref
class TestRegex(unittest.TestCase):
def assertDoesNotMatch(self, ref, filt):

View file

@ -0,0 +1,24 @@
{
"files": [
{
"type": "added",
"file": "AnotherFile.txt"
},
{
"type": "modified",
"file": "Readme"
}
],
"raw_author": "Mary Anthony <manthony@172-28-13-105.staff.sf.atlassian.com>",
"utctimestamp": "2012-07-23 22:26:36+00:00",
"author": "Mary Anthony",
"timestamp": "2012-07-24 00:26:36",
"node": "abdeaf1b2b4a6b9ddf742c1e1754236380435a62",
"parents": [
"86432202a2d5"
],
"branch": "master",
"message": "making some changes\n",
"revision": null,
"size": -1
}

View file

@ -0,0 +1,237 @@
{
"push": {
"changes": [
{
"links": {
"commits": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/commits?include=af64ae7188685f8424040b4735ad12941b980d75&exclude=1784139225279a587e0afb151bed1f9ba3dd509e"
},
"diff": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/diff/af64ae7188685f8424040b4735ad12941b980d75..1784139225279a587e0afb151bed1f9ba3dd509e"
},
"html": {
"href": "https://bitbucket.org/jscoreos/another-repo/branches/compare/af64ae7188685f8424040b4735ad12941b980d75..1784139225279a587e0afb151bed1f9ba3dd509e"
}
},
"old": {
"name": "master",
"links": {
"commits": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/commits/master"
},
"html": {
"href": "https://bitbucket.org/jscoreos/another-repo/branch/master"
},
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/refs/branches/master"
}
},
"type": "branch",
"target": {
"links": {
"html": {
"href": "https://bitbucket.org/jscoreos/another-repo/commits/1784139225279a587e0afb151bed1f9ba3dd509e"
},
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/commit/1784139225279a587e0afb151bed1f9ba3dd509e"
}
},
"author": {
"user": {
"links": {
"avatar": {
"href": "https://bitbucket.org/account/jscoreos/avatar/32/"
},
"html": {
"href": "https://bitbucket.org/jscoreos/"
},
"self": {
"href": "https://api.bitbucket.org/2.0/users/jscoreos"
}
},
"uuid": "{2fa27577-f361-45bb-999a-f4450c546b73}",
"type": "user",
"display_name": "Joseph Schorr",
"username": "jscoreos"
},
"raw": "Joseph Schorr <joseph.schorr@coreos.com>"
},
"date": "2015-09-10T20:37:54+00:00",
"parents": [
{
"links": {
"html": {
"href": "https://bitbucket.org/jscoreos/another-repo/commits/5329daa0961ec968de9ef36f30024bfa0da73103"
},
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/commit/5329daa0961ec968de9ef36f30024bfa0da73103"
}
},
"type": "commit",
"hash": "5329daa0961ec968de9ef36f30024bfa0da73103"
}
],
"type": "commit",
"message": "Dockerfile edited online with Bitbucket",
"hash": "1784139225279a587e0afb151bed1f9ba3dd509e"
}
},
"forced": false,
"truncated": false,
"commits": [
{
"author": {
"user": {
"links": {
"avatar": {
"href": "https://bitbucket.org/account/jscoreos/avatar/32/"
},
"html": {
"href": "https://bitbucket.org/jscoreos/"
},
"self": {
"href": "https://api.bitbucket.org/2.0/users/jscoreos"
}
},
"uuid": "{2fa27577-f361-45bb-999a-f4450c546b73}",
"type": "user",
"display_name": "Joseph Schorr",
"username": "jscoreos"
},
"raw": "Joseph Schorr <joseph.schorr@coreos.com>"
},
"links": {
"html": {
"href": "https://bitbucket.org/jscoreos/another-repo/commits/af64ae7188685f8424040b4735ad12941b980d75"
},
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/commit/af64ae7188685f8424040b4735ad12941b980d75"
}
},
"message": "Dockerfile edited online with Bitbucket",
"type": "commit",
"hash": "af64ae7188685f8424040b4735ad12941b980d75"
}
],
"new": {
"name": "master",
"links": {
"commits": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/commits/master"
},
"html": {
"href": "https://bitbucket.org/jscoreos/another-repo/branch/master"
},
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/refs/branches/master"
}
},
"type": "branch",
"target": {
"links": {
"html": {
"href": "https://bitbucket.org/jscoreos/another-repo/commits/af64ae7188685f8424040b4735ad12941b980d75"
},
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/commit/af64ae7188685f8424040b4735ad12941b980d75"
}
},
"author": {
"user": {
"links": {
"avatar": {
"href": "https://bitbucket.org/account/jscoreos/avatar/32/"
},
"html": {
"href": "https://bitbucket.org/jscoreos/"
},
"self": {
"href": "https://api.bitbucket.org/2.0/users/jscoreos"
}
},
"uuid": "{2fa27577-f361-45bb-999a-f4450c546b73}",
"type": "user",
"display_name": "Joseph Schorr",
"username": "jscoreos"
},
"raw": "Joseph Schorr <joseph.schorr@coreos.com>"
},
"date": "2015-09-10T20:40:54+00:00",
"parents": [
{
"links": {
"html": {
"href": "https://bitbucket.org/jscoreos/another-repo/commits/1784139225279a587e0afb151bed1f9ba3dd509e"
},
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo/commit/1784139225279a587e0afb151bed1f9ba3dd509e"
}
},
"type": "commit",
"hash": "1784139225279a587e0afb151bed1f9ba3dd509e"
}
],
"type": "commit",
"message": "Dockerfile edited online with Bitbucket",
"hash": "af64ae7188685f8424040b4735ad12941b980d75"
}
},
"closed": false,
"created": false
}
]
},
"repository": {
"links": {
"avatar": {
"href": "https://bitbucket.org/jscoreos/another-repo/avatar/16/"
},
"html": {
"href": "https://bitbucket.org/jscoreos/another-repo"
},
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/jscoreos/another-repo"
}
},
"full_name": "jscoreos/another-repo",
"uuid": "{b3459203-3e58-497b-8059-ad087b6b01de}",
"type": "repository",
"is_private": true,
"name": "Another Repo",
"owner": {
"links": {
"avatar": {
"href": "https://bitbucket.org/account/jscoreos/avatar/32/"
},
"html": {
"href": "https://bitbucket.org/jscoreos/"
},
"self": {
"href": "https://api.bitbucket.org/2.0/users/jscoreos"
}
},
"uuid": "{2fa27577-f361-45bb-999a-f4450c546b73}",
"type": "user",
"display_name": "Joseph Schorr",
"username": "jscoreos"
},
"scm": "git"
},
"actor": {
"links": {
"avatar": {
"href": "https://bitbucket.org/account/jscoreos/avatar/32/"
},
"html": {
"href": "https://bitbucket.org/jscoreos/"
},
"self": {
"href": "https://api.bitbucket.org/2.0/users/jscoreos"
}
},
"uuid": "{2fa27577-f361-45bb-999a-f4450c546b73}",
"type": "user",
"display_name": "Joseph Schorr",
"username": "jscoreos"
}
}

View file

@ -0,0 +1,153 @@
{
"ref": "refs/heads/master",
"before": "9ea43cab474709d4a61afb7e3340de1ffc405b41",
"after": "410f4cdf8ff09b87f245b13845e8497f90b90a4c",
"created": false,
"deleted": false,
"forced": false,
"base_ref": null,
"compare": "https://github.com/josephschorr/anothertest/compare/9ea43cab4747...410f4cdf8ff0",
"commits": [
{
"id": "410f4cdf8ff09b87f245b13845e8497f90b90a4c",
"distinct": true,
"message": "Update Dockerfile",
"timestamp": "2015-09-11T14:26:16-04:00",
"url": "https://github.com/josephschorr/anothertest/commit/410f4cdf8ff09b87f245b13845e8497f90b90a4c",
"author": {
"name": "josephschorr",
"email": "josephschorr@users.noreply.github.com",
"username": "josephschorr"
},
"committer": {
"name": "josephschorr",
"email": "josephschorr@users.noreply.github.com",
"username": "josephschorr"
},
"added": [],
"removed": [],
"modified": [
"Dockerfile"
]
}
],
"head_commit": {
"id": "410f4cdf8ff09b87f245b13845e8497f90b90a4c",
"distinct": true,
"message": "Update Dockerfile",
"timestamp": "2015-09-11T14:26:16-04:00",
"url": "https://github.com/josephschorr/anothertest/commit/410f4cdf8ff09b87f245b13845e8497f90b90a4c",
"author": {
"name": "josephschorr",
"email": "josephschorr@users.noreply.github.com",
"username": "josephschorr"
},
"committer": {
"name": "josephschorr",
"email": "josephschorr@users.noreply.github.com",
"username": "josephschorr"
},
"added": [],
"removed": [],
"modified": [
"Dockerfile"
]
},
"repository": {
"id": 34876107,
"name": "anothertest",
"full_name": "josephschorr/anothertest",
"owner": {
"name": "josephschorr",
"email": "josephschorr@users.noreply.github.com"
},
"private": false,
"html_url": "https://github.com/josephschorr/anothertest",
"description": "",
"fork": false,
"url": "https://github.com/josephschorr/anothertest",
"forks_url": "https://api.github.com/repos/josephschorr/anothertest/forks",
"keys_url": "https://api.github.com/repos/josephschorr/anothertest/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/josephschorr/anothertest/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/josephschorr/anothertest/teams",
"hooks_url": "https://api.github.com/repos/josephschorr/anothertest/hooks",
"issue_events_url": "https://api.github.com/repos/josephschorr/anothertest/issues/events{/number}",
"events_url": "https://api.github.com/repos/josephschorr/anothertest/events",
"assignees_url": "https://api.github.com/repos/josephschorr/anothertest/assignees{/user}",
"branches_url": "https://api.github.com/repos/josephschorr/anothertest/branches{/branch}",
"tags_url": "https://api.github.com/repos/josephschorr/anothertest/tags",
"blobs_url": "https://api.github.com/repos/josephschorr/anothertest/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/josephschorr/anothertest/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/josephschorr/anothertest/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/josephschorr/anothertest/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/josephschorr/anothertest/statuses/{sha}",
"languages_url": "https://api.github.com/repos/josephschorr/anothertest/languages",
"stargazers_url": "https://api.github.com/repos/josephschorr/anothertest/stargazers",
"contributors_url": "https://api.github.com/repos/josephschorr/anothertest/contributors",
"subscribers_url": "https://api.github.com/repos/josephschorr/anothertest/subscribers",
"subscription_url": "https://api.github.com/repos/josephschorr/anothertest/subscription",
"commits_url": "https://api.github.com/repos/josephschorr/anothertest/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/josephschorr/anothertest/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/josephschorr/anothertest/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/josephschorr/anothertest/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/josephschorr/anothertest/contents/{+path}",
"compare_url": "https://api.github.com/repos/josephschorr/anothertest/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/josephschorr/anothertest/merges",
"archive_url": "https://api.github.com/repos/josephschorr/anothertest/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/josephschorr/anothertest/downloads",
"issues_url": "https://api.github.com/repos/josephschorr/anothertest/issues{/number}",
"pulls_url": "https://api.github.com/repos/josephschorr/anothertest/pulls{/number}",
"milestones_url": "https://api.github.com/repos/josephschorr/anothertest/milestones{/number}",
"notifications_url": "https://api.github.com/repos/josephschorr/anothertest/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/josephschorr/anothertest/labels{/name}",
"releases_url": "https://api.github.com/repos/josephschorr/anothertest/releases{/id}",
"created_at": 1430426945,
"updated_at": "2015-04-30T20:49:05Z",
"pushed_at": 1441995976,
"git_url": "git://github.com/josephschorr/anothertest.git",
"ssh_url": "git@github.com:josephschorr/anothertest.git",
"clone_url": "https://github.com/josephschorr/anothertest.git",
"svn_url": "https://github.com/josephschorr/anothertest",
"homepage": null,
"size": 144,
"stargazers_count": 0,
"watchers_count": 0,
"language": null,
"has_issues": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": false,
"forks_count": 0,
"mirror_url": null,
"open_issues_count": 0,
"forks": 0,
"open_issues": 0,
"watchers": 0,
"default_branch": "master",
"stargazers": 0,
"master_branch": "master"
},
"pusher": {
"name": "josephschorr",
"email": "josephschorr@users.noreply.github.com"
},
"sender": {
"login": "josephschorr",
"id": 4073002,
"avatar_url": "https://avatars.githubusercontent.com/u/4073002?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/josephschorr",
"html_url": "https://github.com/josephschorr",
"followers_url": "https://api.github.com/users/josephschorr/followers",
"following_url": "https://api.github.com/users/josephschorr/following{/other_user}",
"gists_url": "https://api.github.com/users/josephschorr/gists{/gist_id}",
"starred_url": "https://api.github.com/users/josephschorr/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/josephschorr/subscriptions",
"organizations_url": "https://api.github.com/users/josephschorr/orgs",
"repos_url": "https://api.github.com/users/josephschorr/repos",
"events_url": "https://api.github.com/users/josephschorr/events{/privacy}",
"received_events_url": "https://api.github.com/users/josephschorr/received_events",
"type": "User",
"site_admin": false
}
}

View file

@ -0,0 +1,54 @@
{
"object_kind": "push",
"before": "11fcaca195e8b17ca7e3dc47d9608d5b6b892f45",
"after": "fb88379ee45de28a0a4590fddcbd8eff8b36026e",
"ref": "refs/heads/master",
"checkout_sha": "fb88379ee45de28a0a4590fddcbd8eff8b36026e",
"message": null,
"user_id": 95973,
"user_name": "Jimmy Zelinskie",
"user_email": "jimmyzelinskie@gmail.com",
"project_id": 406414,
"repository": {
"name": "www-gitlab-com",
"url": "git@gitlab.com:jzelinskie/www-gitlab-com.git",
"description": "",
"homepage": "https://gitlab.com/jzelinskie/www-gitlab-com",
"git_http_url": "https://gitlab.com/jzelinskie/www-gitlab-com.git",
"git_ssh_url": "git@gitlab.com:jzelinskie/www-gitlab-com.git",
"visibility_level": 20
},
"commits": [
{
"id": "fb88379ee45de28a0a4590fddcbd8eff8b36026e",
"message": "Fix link\n",
"timestamp": "2015-08-13T19:33:18+00:00",
"url": "https://gitlab.com/jzelinskie/www-gitlab-com/commit/fb88379ee45de28a0a4590fddcbd8eff8b36026e",
"author": {
"name": "Sytse Sijbrandij",
"email": "sytse@gitlab.com"
}
},
{
"id": "4ca166bc0b511f21fa331873f260f1a7cb38d723",
"message": "Merge branch 'git-lfs' into 'master'\n\nGit lfs\n\n@JobV @dzaporozhets @DouweM please review the tone of this\n\nSee merge request !899\n",
"timestamp": "2015-08-13T15:52:15+00:00",
"url": "https://gitlab.com/jzelinskie/www-gitlab-com/commit/4ca166bc0b511f21fa331873f260f1a7cb38d723",
"author": {
"name": "Sytse Sijbrandij",
"email": "sytse@gitlab.com"
}
},
{
"id": "11fcaca195e8b17ca7e3dc47d9608d5b6b892f45",
"message": "Merge branch 'release-7-3-5' into 'master'\n\n7-13-5 Release post.\n\nSee merge request !900\n",
"timestamp": "2015-08-13T09:31:47+00:00",
"url": "https://gitlab.com/jzelinskie/www-gitlab-com/commit/11fcaca195e8b17ca7e3dc47d9608d5b6b892f45",
"author": {
"name": "Valery Sizov",
"email": "valery@gitlab.com"
}
}
],
"total_commits_count": 3
}