https GET api.github.com None /repos/edx/edx-platform/commits/74e70119a23fa3ffb3db19d4590eccfebd72b659 {'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} None 200 [('content-length', '18854'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding'), ('x-served-by', '593010132f82159af0ded24b4932e109'), ('x-oauth-scopes', 'notifications, public_repo, read:org, read:public_key, read:repo_hook, repo:status, repo_deployment'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('x-accepted-oauth-scopes', ''), ('etag', '"8e937a4cbcbaef182ddf483ee99a599f"'), ('access-control-allow-credentials', 'true'), ('status', '200 OK'), ('x-ratelimit-remaining', '4993'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'), ('x-github-request-id', '12B0076B:2073:5CF629E:56A6A81E'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('last-modified', 'Mon, 14 Dec 2015 12:42:38 GMT'), ('date', 'Mon, 25 Jan 2016 22:56:31 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1453765330')] {"sha":"74e70119a23fa3ffb3db19d4590eccfebd72b659","commit":{"author":{"name":"John Eskew","email":"jeskew@edx.org","date":"2015-12-04T22:39:27Z"},"committer":{"name":"John Eskew","email":"jeskew@edx.org","date":"2015-12-14T12:42:38Z"},"message":"Use a common MongoDB connection function.\nAdd some missing @autoretry_read() decorators.\nChange to PyMongo 3.x-compatible syntax.","tree":{"sha":"7712c0f7c0c21f706bcbed393f3de71d854d59df","url":"https://api.github.com/repos/edx/edx-platform/git/trees/7712c0f7c0c21f706bcbed393f3de71d854d59df"},"url":"https://api.github.com/repos/edx/edx-platform/git/commits/74e70119a23fa3ffb3db19d4590eccfebd72b659","comment_count":0},"url":"https://api.github.com/repos/edx/edx-platform/commits/74e70119a23fa3ffb3db19d4590eccfebd72b659","html_url":"https://github.com/edx/edx-platform/commit/74e70119a23fa3ffb3db19d4590eccfebd72b659","comments_url":"https://api.github.com/repos/edx/edx-platform/commits/74e70119a23fa3ffb3db19d4590eccfebd72b659/comments","author":{"login":"doctoryes","id":7285237,"avatar_url":"https://avatars.githubusercontent.com/u/7285237?v=3","gravatar_id":"","url":"https://api.github.com/users/doctoryes","html_url":"https://github.com/doctoryes","followers_url":"https://api.github.com/users/doctoryes/followers","following_url":"https://api.github.com/users/doctoryes/following{/other_user}","gists_url":"https://api.github.com/users/doctoryes/gists{/gist_id}","starred_url":"https://api.github.com/users/doctoryes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/doctoryes/subscriptions","organizations_url":"https://api.github.com/users/doctoryes/orgs","repos_url":"https://api.github.com/users/doctoryes/repos","events_url":"https://api.github.com/users/doctoryes/events{/privacy}","received_events_url":"https://api.github.com/users/doctoryes/received_events","type":"User","site_admin":false},"committer":{"login":"doctoryes","id":7285237,"avatar_url":"https://avatars.githubusercontent.com/u/7285237?v=3","gravatar_id":"","url":"https://api.github.com/users/doctoryes","html_url":"https://github.com/doctoryes","followers_url":"https://api.github.com/users/doctoryes/followers","following_url":"https://api.github.com/users/doctoryes/following{/other_user}","gists_url":"https://api.github.com/users/doctoryes/gists{/gist_id}","starred_url":"https://api.github.com/users/doctoryes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/doctoryes/subscriptions","organizations_url":"https://api.github.com/users/doctoryes/orgs","repos_url":"https://api.github.com/users/doctoryes/repos","events_url":"https://api.github.com/users/doctoryes/events{/privacy}","received_events_url":"https://api.github.com/users/doctoryes/received_events","type":"User","site_admin":false},"parents":[{"sha":"86227e7711c011490f1db6fdfcc17401511e5ee5","url":"https://api.github.com/repos/edx/edx-platform/commits/86227e7711c011490f1db6fdfcc17401511e5ee5","html_url":"https://github.com/edx/edx-platform/commit/86227e7711c011490f1db6fdfcc17401511e5ee5"}],"stats":{"total":192,"additions":112,"deletions":80},"files":[{"sha":"56ccd039ccff39e297523966c340f1be74876af8","filename":"common/lib/xmodule/xmodule/contentstore/mongo.py","status":"modified","additions":34,"deletions":30,"changes":64,"blob_url":"https://github.com/edx/edx-platform/blob/74e70119a23fa3ffb3db19d4590eccfebd72b659/common/lib/xmodule/xmodule/contentstore/mongo.py","raw_url":"https://github.com/edx/edx-platform/raw/74e70119a23fa3ffb3db19d4590eccfebd72b659/common/lib/xmodule/xmodule/contentstore/mongo.py","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/common/lib/xmodule/xmodule/contentstore/mongo.py?ref=74e70119a23fa3ffb3db19d4590eccfebd72b659","patch":"@@ -1,52 +1,50 @@\n+\"\"\"\n+MongoDB/GridFS-level code for the contentstore.\n+\"\"\"\n+import os\n+import json\n import pymongo\n import gridfs\n from gridfs.errors import NoFile\n-\n-from xmodule.contentstore.content import XASSET_LOCATION_TAG\n-\n-import logging\n-\n-from .content import StaticContent, ContentStore, StaticContentStream\n-from xmodule.exceptions import NotFoundError\n from fs.osfs import OSFS\n-import os\n-import json\n from bson.son import SON\n+\n+from mongodb_proxy import autoretry_read\n from opaque_keys.edx.keys import AssetKey\n+from xmodule.contentstore.content import XASSET_LOCATION_TAG\n+from xmodule.exceptions import NotFoundError\n from xmodule.modulestore.django import ASSET_IGNORE_REGEX\n from xmodule.util.misc import escape_invalid_characters\n+from xmodule.mongo_connection import connect_to_mongodb\n+from .content import StaticContent, ContentStore, StaticContentStream\n \n \n class MongoContentStore(ContentStore):\n-\n- # pylint: disable=unused-argument\n- def __init__(self, host, db, port=27017, user=None, password=None, bucket='fs', collection=None, **kwargs):\n+ \"\"\"\n+ MongoDB-backed ContentStore.\n+ \"\"\"\n+ # pylint: disable=unused-argument, bad-continuation\n+ def __init__(\n+ self, host, db,\n+ port=27017, tz_aware=True, user=None, password=None, bucket='fs', collection=None, **kwargs\n+ ):\n \"\"\"\n Establish the connection with the mongo backend and connect to the collections\n \n :param collection: ignores but provided for consistency w/ other doc_store_config patterns\n \"\"\"\n- logging.debug('Using MongoDB for static content serving at host={0} port={1} db={2}'.format(host, port, db))\n-\n- # Remove the replicaSet parameter.\n- kwargs.pop('replicaSet', None)\n-\n- _db = pymongo.database.Database(\n- pymongo.MongoClient(\n- host=host,\n- port=port,\n- document_class=dict,\n- **kwargs\n- ),\n- db\n+ # GridFS will throw an exception if the Database is wrapped in a MongoProxy. So don't wrap it.\n+ # The appropriate methods below are marked as autoretry_read - those methods will handle\n+ # the AutoReconnect errors.\n+ proxy = False\n+ mongo_db = connect_to_mongodb(\n+ db, host,\n+ port=port, tz_aware=tz_aware, user=user, password=password, proxy=proxy, **kwargs\n )\n \n- if user is not None and password is not None:\n- _db.authenticate(user, password)\n-\n- self.fs = gridfs.GridFS(_db, bucket)\n+ self.fs = gridfs.GridFS(mongo_db, bucket) # pylint: disable=invalid-name\n \n- self.fs_files = _db[bucket + \".files\"] # the underlying collection GridFS uses\n+ self.fs_files = mongo_db[bucket + \".files\"] # the underlying collection GridFS uses\n \n def close_connections(self):\n \"\"\"\n@@ -86,11 +84,15 @@ def save(self, content):\n return content\n \n def delete(self, location_or_id):\n+ \"\"\"\n+ Delete an asset.\n+ \"\"\"\n if isinstance(location_or_id, AssetKey):\n location_or_id, _ = self.asset_db_key(location_or_id)\n # Deletes of non-existent files are considered successful\n self.fs.delete(location_or_id)\n \n+ @autoretry_read()\n def find(self, location, throw_on_not_found=True, as_stream=False):\n content_id, __ = self.asset_db_key(location)\n \n@@ -206,6 +208,7 @@ def remove_redundant_content_for_courses(self):\n self.fs_files.remove(query)\n return assets_to_delete\n \n+ @autoretry_read()\n def _get_all_content_for_course(self,\n course_key,\n get_thumbnails=False,\n@@ -288,6 +291,7 @@ def set_attrs(self, location, attr_dict):\n if not result.get('updatedExisting', True):\n raise NotFoundError(asset_db_key)\n \n+ @autoretry_read()\n def get_attrs(self, location):\n \"\"\"\n Gets all of the attributes associated with the given asset. Note, returns even built in attrs"},{"sha":"4bcdfa15a878dc6b413ab093f5edc685096c1dfa","filename":"common/lib/xmodule/xmodule/modulestore/mongo/base.py","status":"modified","additions":15,"deletions":24,"changes":39,"blob_url":"https://github.com/edx/edx-platform/blob/74e70119a23fa3ffb3db19d4590eccfebd72b659/common/lib/xmodule/xmodule/modulestore/mongo/base.py","raw_url":"https://github.com/edx/edx-platform/raw/74e70119a23fa3ffb3db19d4590eccfebd72b659/common/lib/xmodule/xmodule/modulestore/mongo/base.py","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/common/lib/xmodule/xmodule/modulestore/mongo/base.py?ref=74e70119a23fa3ffb3db19d4590eccfebd72b659","patch":"@@ -22,7 +22,7 @@\n from bson.son import SON\n from datetime import datetime\n from fs.osfs import OSFS\n-from mongodb_proxy import MongoProxy, autoretry_read\n+from mongodb_proxy import autoretry_read\n from path import Path as path\n from pytz import UTC\n from contracts import contract, new_contract\n@@ -43,6 +43,7 @@\n from xmodule.errortracker import null_error_tracker, exc_info_to_str\n from xmodule.exceptions import HeartbeatFailure\n from xmodule.mako_module import MakoDescriptorSystem\n+from xmodule.mongo_connection import connect_to_mongodb\n from xmodule.modulestore import ModuleStoreWriteBase, ModuleStoreEnum, BulkOperationsMixin, BulkOpsRecord\n from xmodule.modulestore.draft_and_published import ModuleStoreDraftAndPublished, DIRECT_ONLY_CATEGORIES\n from xmodule.modulestore.edit_info import EditInfoRuntimeMixin\n@@ -558,22 +559,16 @@ def do_connection(\n \"\"\"\n Create & open the connection, authenticate, and provide pointers to the collection\n \"\"\"\n- # Remove the replicaSet parameter.\n- kwargs.pop('replicaSet', None)\n-\n- self.database = MongoProxy(\n- pymongo.database.Database(\n- pymongo.MongoClient(\n- host=host,\n- port=port,\n- tz_aware=tz_aware,\n- document_class=dict,\n- **kwargs\n- ),\n- db\n- ),\n- wait_time=retry_wait_time\n+ # Set a write concern of 1, which makes writes complete successfully to the primary\n+ # only before returning. Also makes pymongo report write errors.\n+ kwargs['w'] = 1\n+\n+ self.database = connect_to_mongodb(\n+ db, host,\n+ port=port, tz_aware=tz_aware, user=user, password=password,\n+ retry_wait_time=retry_wait_time, **kwargs\n )\n+\n self.collection = self.database[collection]\n \n # Collection which stores asset metadata.\n@@ -581,14 +576,8 @@ def do_connection(\n asset_collection = self.DEFAULT_ASSET_COLLECTION_NAME\n self.asset_collection = self.database[asset_collection]\n \n- if user is not None and password is not None:\n- self.database.authenticate(user, password)\n-\n do_connection(**doc_store_config)\n \n- # Force mongo to report errors, at the expense of performance\n- self.collection.write_concern = {'w': 1}\n-\n if default_class is not None:\n module_path, _, class_name = default_class.rpartition('.')\n class_ = getattr(import_module(module_path), class_name)\n@@ -1012,6 +1001,7 @@ def get_courses(self, **kwargs):\n )\n return [course for course in base_list if not isinstance(course, ErrorDescriptor)]\n \n+ @autoretry_read()\n def _find_one(self, location):\n '''Look for a given location in the collection. If the item is not present, raise\n ItemNotFoundError.\n@@ -1052,6 +1042,7 @@ def get_course(self, course_key, depth=0, **kwargs):\n except ItemNotFoundError:\n return None\n \n+ @autoretry_read()\n def has_course(self, course_key, ignore_case=False, **kwargs):\n \"\"\"\n Returns the course_id of the course if it was found, else None\n@@ -1073,7 +1064,7 @@ def has_course(self, course_key, ignore_case=False, **kwargs):\n course_query[key] = re.compile(r\"(?i)^{}$\".format(course_query[key]))\n else:\n course_query = {'_id': location.to_deprecated_son()}\n- course = self.collection.find_one(course_query, fields={'_id': True})\n+ course = self.collection.find_one(course_query, projection={'_id': True})\n if course:\n return SlashSeparatedCourseKey(course['_id']['org'], course['_id']['course'], course['_id']['name'])\n else:\n@@ -1234,7 +1225,7 @@ def create_course(self, org, course, run, user_id, fields=None, **kwargs):\n ('_id.course', re.compile(u'^{}$'.format(course_id.course), re.IGNORECASE)),\n ('_id.category', 'course'),\n ])\n- courses = self.collection.find(course_search_location, fields=('_id'))\n+ courses = self.collection.find(course_search_location, projection={'_id': True})\n if courses.count() > 0:\n raise DuplicateCourseError(course_id, courses[0]['_id'])\n "},{"sha":"1352ee95cd39a611a21a2e17dbc70da9b31af433","filename":"common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py","status":"modified","additions":10,"deletions":26,"changes":36,"blob_url":"https://github.com/edx/edx-platform/blob/74e70119a23fa3ffb3db19d4590eccfebd72b659/common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py","raw_url":"https://github.com/edx/edx-platform/raw/74e70119a23fa3ffb3db19d4590eccfebd72b659/common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py?ref=74e70119a23fa3ffb3db19d4590eccfebd72b659","patch":"@@ -23,10 +23,11 @@\n import dogstats_wrapper as dog_stats_api\n \n from contracts import check, new_contract\n-from mongodb_proxy import autoretry_read, MongoProxy\n+from mongodb_proxy import autoretry_read\n from xmodule.exceptions import HeartbeatFailure\n from xmodule.modulestore import BlockData\n from xmodule.modulestore.split_mongo import BlockKey\n+from xmodule.mongo_connection import connect_to_mongodb\n \n \n new_contract('BlockData', BlockData)\n@@ -287,37 +288,20 @@ def __init__(\n \"\"\"\n Create & open the connection, authenticate, and provide pointers to the collections\n \"\"\"\n- if kwargs.get('replicaSet') is None:\n- kwargs.pop('replicaSet', None)\n- mongo_class = pymongo.MongoClient\n- else:\n- mongo_class = pymongo.MongoReplicaSetClient\n- _client = mongo_class(\n- host=host,\n- port=port,\n- tz_aware=tz_aware,\n- **kwargs\n- )\n- self.database = MongoProxy(\n- pymongo.database.Database(_client, db),\n- wait_time=retry_wait_time\n- )\n+ # Set a write concern of 1, which makes writes complete successfully to the primary\n+ # only before returning. Also makes pymongo report write errors.\n+ kwargs['w'] = 1\n \n- if user is not None and password is not None:\n- self.database.authenticate(user, password)\n+ self.database = connect_to_mongodb(\n+ db, host,\n+ port=port, tz_aware=tz_aware, user=user, password=password,\n+ retry_wait_time=retry_wait_time, **kwargs\n+ )\n \n self.course_index = self.database[collection + '.active_versions']\n self.structures = self.database[collection + '.structures']\n self.definitions = self.database[collection + '.definitions']\n \n- # every app has write access to the db (v having a flag to indicate r/o v write)\n- # Force mongo to report errors, at the expense of performance\n- # pymongo docs suck but explanation:\n- # http://api.mongodb.org/java/2.10.1/com/mongodb/WriteConcern.html\n- self.course_index.write_concern = {'w': 1}\n- self.structures.write_concern = {'w': 1}\n- self.definitions.write_concern = {'w': 1}\n-\n def heartbeat(self):\n \"\"\"\n Check that the db is reachable."},{"sha":"ea353a60b6af9226ce7676495d9572831d99fbd9","filename":"common/lib/xmodule/xmodule/mongo_connection.py","status":"added","additions":53,"deletions":0,"changes":53,"blob_url":"https://github.com/edx/edx-platform/blob/74e70119a23fa3ffb3db19d4590eccfebd72b659/common/lib/xmodule/xmodule/mongo_connection.py","raw_url":"https://github.com/edx/edx-platform/raw/74e70119a23fa3ffb3db19d4590eccfebd72b659/common/lib/xmodule/xmodule/mongo_connection.py","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/common/lib/xmodule/xmodule/mongo_connection.py?ref=74e70119a23fa3ffb3db19d4590eccfebd72b659","patch":"@@ -0,0 +1,53 @@\n+\"\"\"\n+Common MongoDB connection functions.\n+\"\"\"\n+import pymongo\n+from mongodb_proxy import MongoProxy\n+\n+\n+# pylint: disable=bad-continuation\n+def connect_to_mongodb(\n+ db, host,\n+ port=27017, tz_aware=True, user=None, password=None,\n+ retry_wait_time=0.1, proxy=True, **kwargs\n+):\n+ \"\"\"\n+ Returns a MongoDB Database connection, optionally wrapped in a proxy. The proxy\n+ handles AutoReconnect errors by retrying read operations, since these exceptions\n+ typically indicate a temporary step-down condition for MongoDB.\n+ \"\"\"\n+ # The MongoReplicaSetClient class is deprecated in Mongo 3.x, in favor of using\n+ # the MongoClient class for all connections. Update/simplify this code when using\n+ # PyMongo 3.x.\n+ if kwargs.get('replicaSet'):\n+ # Enable reading from secondary nodes in the MongoDB replicaset by using the\n+ # MongoReplicaSetClient class.\n+ # The 'replicaSet' parameter in kwargs is required for secondary reads.\n+ # The read_preference should be set to a proper value, like SECONDARY_PREFERRED.\n+ mongo_client_class = pymongo.MongoReplicaSetClient\n+ else:\n+ # No 'replicaSet' in kwargs - so no secondary reads.\n+ mongo_client_class = pymongo.MongoClient\n+\n+ mongo_conn = pymongo.database.Database(\n+ mongo_client_class(\n+ host=host,\n+ port=port,\n+ tz_aware=tz_aware,\n+ document_class=dict,\n+ **kwargs\n+ ),\n+ db\n+ )\n+\n+ if proxy:\n+ mongo_conn = MongoProxy(\n+ mongo_conn,\n+ wait_time=retry_wait_time\n+ )\n+\n+ # If credentials were provided, authenticate the user.\n+ if user is not None and password is not None:\n+ mongo_conn.authenticate(user, password)\n+\n+ return mongo_conn"}]} https GET api.github.com None /repos/edx/edx-platform/commits/74e70119a23fa3ffb3db19d4590eccfebd72b659/status {'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} None 200 [('content-length', '6365'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding'), ('x-served-by', '3e3b9690823fb031da84658eb58aa83b'), ('x-oauth-scopes', 'notifications, public_repo, read:org, read:public_key, read:repo_hook, repo:status, repo_deployment'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('x-accepted-oauth-scopes', 'repo, repo:status'), ('etag', '"bfa38f9cceb7ccc231038178037a2013"'), ('access-control-allow-credentials', 'true'), ('status', '200 OK'), ('x-ratelimit-remaining', '4992'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'), ('x-github-request-id', '12B0076B:2074:768909A:56A6A81F'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Mon, 25 Jan 2016 22:56:31 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1453765330')] {"state":"success","statuses":[{"url":"https://api.github.com/repos/edx/edx-platform/statuses/74e70119a23fa3ffb3db19d4590eccfebd72b659","id":390601376,"state":"success","description":"Build finished.","target_url":"https://build.testeng.edx.org/job/edx-platform-js-pr/10357/","context":"jenkins/js","created_at":"2015-12-14T12:54:25Z","updated_at":"2015-12-14T12:54:25Z"},{"url":"https://api.github.com/repos/edx/edx-platform/statuses/74e70119a23fa3ffb3db19d4590eccfebd72b659","id":390603044,"state":"success","description":"Build finished.","target_url":"https://build.testeng.edx.org/job/edx-platform-accessibility-pr/10173/","context":"jenkins/a11y","created_at":"2015-12-14T12:56:21Z","updated_at":"2015-12-14T12:56:21Z"},{"url":"https://api.github.com/repos/edx/edx-platform/statuses/74e70119a23fa3ffb3db19d4590eccfebd72b659","id":390615529,"state":"success","description":"Build finished.","target_url":"https://build.testeng.edx.org/job/edx-platform-quality-pr/10214/","context":"jenkins/quality","created_at":"2015-12-14T13:10:22Z","updated_at":"2015-12-14T13:10:22Z"},{"url":"https://api.github.com/repos/edx/edx-platform/statuses/74e70119a23fa3ffb3db19d4590eccfebd72b659","id":390627281,"state":"success","description":"Build finished.","target_url":"https://build.testeng.edx.org/job/edx-platform-bok-choy-pr/10918/","context":"jenkins/bokchoy","created_at":"2015-12-14T13:23:35Z","updated_at":"2015-12-14T13:23:35Z"},{"url":"https://api.github.com/repos/edx/edx-platform/statuses/74e70119a23fa3ffb3db19d4590eccfebd72b659","id":390627989,"state":"success","description":"Build finished.","target_url":"https://build.testeng.edx.org/job/edx-platform-python-unittests-pr/10504/","context":"jenkins/python","created_at":"2015-12-14T13:24:18Z","updated_at":"2015-12-14T13:24:18Z"},{"url":"https://api.github.com/repos/edx/edx-platform/statuses/74e70119a23fa3ffb3db19d4590eccfebd72b659","id":390680150,"state":"success","description":"Build finished.","target_url":"https://build.testeng.edx.org/job/edx-platform-lettuce-pr/10545/","context":"jenkins/lettuce","created_at":"2015-12-14T14:15:40Z","updated_at":"2015-12-14T14:15:40Z"}],"sha":"74e70119a23fa3ffb3db19d4590eccfebd72b659","total_count":6,"repository":{"id":10391073,"name":"edx-platform","full_name":"edx/edx-platform","owner":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/edx/edx-platform","description":"The Open edX platform, the software that powers edX!","fork":false,"url":"https://api.github.com/repos/edx/edx-platform","forks_url":"https://api.github.com/repos/edx/edx-platform/forks","keys_url":"https://api.github.com/repos/edx/edx-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/edx/edx-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/edx/edx-platform/teams","hooks_url":"https://api.github.com/repos/edx/edx-platform/hooks","issue_events_url":"https://api.github.com/repos/edx/edx-platform/issues/events{/number}","events_url":"https://api.github.com/repos/edx/edx-platform/events","assignees_url":"https://api.github.com/repos/edx/edx-platform/assignees{/user}","branches_url":"https://api.github.com/repos/edx/edx-platform/branches{/branch}","tags_url":"https://api.github.com/repos/edx/edx-platform/tags","blobs_url":"https://api.github.com/repos/edx/edx-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/edx/edx-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/edx/edx-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/edx/edx-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/edx/edx-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/edx/edx-platform/languages","stargazers_url":"https://api.github.com/repos/edx/edx-platform/stargazers","contributors_url":"https://api.github.com/repos/edx/edx-platform/contributors","subscribers_url":"https://api.github.com/repos/edx/edx-platform/subscribers","subscription_url":"https://api.github.com/repos/edx/edx-platform/subscription","commits_url":"https://api.github.com/repos/edx/edx-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/edx/edx-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/edx/edx-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/edx/edx-platform/issues/comments{/number}","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/{+path}","compare_url":"https://api.github.com/repos/edx/edx-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/edx/edx-platform/merges","archive_url":"https://api.github.com/repos/edx/edx-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/edx/edx-platform/downloads","issues_url":"https://api.github.com/repos/edx/edx-platform/issues{/number}","pulls_url":"https://api.github.com/repos/edx/edx-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/edx/edx-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/edx/edx-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/edx/edx-platform/labels{/name}","releases_url":"https://api.github.com/repos/edx/edx-platform/releases{/id}","deployments_url":"https://api.github.com/repos/edx/edx-platform/deployments"},"commit_url":"https://api.github.com/repos/edx/edx-platform/commits/74e70119a23fa3ffb3db19d4590eccfebd72b659","url":"https://api.github.com/repos/edx/edx-platform/commits/74e70119a23fa3ffb3db19d4590eccfebd72b659/status"}