[#8463] added basic resp endpoint to store commit statuses
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index ab98ec1..0dae4b4 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -361,6 +361,19 @@
                 }
                 for commit in revisions
             ]}
+    @expose('json:')
+    def commit_status(self, rev=None, **kwargs):
+        if not g.commit_statuses_enabled:
+            return {'status': 'disabled', 'message': 'check your config file'}
+        params = {x : kwargs.get(x, '').strip() for x in
+                                                   ['state', 'target_url', 'description', 'context']}
+        params['commit_id'] = rev
+        status = M.CommitStatus.upsert(**params)
+        response = {'status': 'error'}
+        if status:
+            response['status'] = 'success'
+        return response
+
 
 
 class MergeRequestsController:
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index 4ec2092..65279bb 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -658,6 +658,10 @@
             "image_height": logo['image_height']
         }
 
+    @property
+    def commit_statuses_enabled(self):
+        return asbool(config['scm.commit_statuses'])
+
 class Icon:
 
     def __init__(self, css, title=None):
diff --git a/Allura/allura/model/__init__.py b/Allura/allura/model/__init__.py
index b7b1fdb..ef5adad 100644
--- a/Allura/allura/model/__init__.py
+++ b/Allura/allura/model/__init__.py
@@ -28,7 +28,7 @@
 from .auth import AuditLog, AlluraUserProperty, UserLoginDetails
 from .filesystem import File
 from .notification import Notification, Mailbox, SiteNotification
-from .repository import Repository, RepositoryImplementation
+from .repository import Repository, RepositoryImplementation, CommitStatus
 from .repository import MergeRequest, GitLikeTree
 from .stats import Stats
 from .oauth import OAuthToken, OAuthConsumerToken, OAuthRequestToken, OAuthAccessToken
@@ -55,7 +55,7 @@
     'AwardFile', 'Award', 'AwardGrant', 'VotableArtifact', 'Discussion', 'Thread', 'PostHistory', 'Post',
     'DiscussionAttachment', 'BaseAttachment', 'AuthGlobals', 'User', 'ProjectRole', 'EmailAddress',
     'AuditLog', 'AlluraUserProperty', 'File', 'Notification', 'Mailbox', 'Repository',
-    'RepositoryImplementation', 'MergeRequest', 'GitLikeTree', 'Stats', 'OAuthToken', 'OAuthConsumerToken',
+    'RepositoryImplementation', 'CommitStatus', 'MergeRequest', 'GitLikeTree', 'Stats', 'OAuthToken', 'OAuthConsumerToken',
     'OAuthRequestToken', 'OAuthAccessToken', 'MonQTask', 'Webhook', 'ACE', 'ACL', 'EVERYONE', 'ALL_PERMISSIONS',
     'DENY_ALL', 'MarkdownCache', 'main_doc_session', 'main_orm_session', 'project_doc_session', 'project_orm_session',
     'artifact_orm_session', 'repository_orm_session', 'task_orm_session', 'ArtifactSessionExtension', 'repository',
diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index 7ebbffd..7373890 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -32,7 +32,6 @@
 from threading import Thread
 from six.moves.queue import Queue
 from itertools import chain, islice
-from difflib import SequenceMatcher
 import typing
 
 import tg
@@ -45,9 +44,10 @@
 import six
 
 from ming import schema as S
+from ming.orm import session
 from ming import Field, collection, Index
 from ming.utils import LazyProperty
-from ming.odm import FieldProperty, session, Mapper, mapper, MappedClass
+from ming.odm import FieldProperty, session, Mapper, mapper, MappedClass, RelationProperty
 from ming.base import Object
 
 from allura.lib import helpers as h
@@ -1043,6 +1043,37 @@
     Field('repo_ids', [S.ObjectId()], index=True))
 
 
+class CommitStatus(MappedClass):
+    class __mongometa__:
+        session = repository_orm_session
+        name = 'commit_status'
+        indexes = [('commit_id', 'context'),]
+
+    query: 'Query[CommitStatus]'
+
+    _id = FieldProperty(S.ObjectId)
+    state = FieldProperty(str)
+    target_url = FieldProperty(str)
+    description = FieldProperty(str)
+    context = FieldProperty(str)
+    commit_id = FieldProperty(str)
+    commit = RelationProperty('Commit')
+
+    def __init__(self, **kw):
+        assert 'commit_id' in kw, 'Commit id missing'
+        super().__init__(**kw)
+
+    @classmethod
+    def upsert(cls, **kw):
+        obj = cls.query.find_and_modify(
+            query=dict(commit_id=kw.get('commit_id'), context=kw.get('context')),
+            update={'$set': kw},
+            new=True,
+            upsert=True,
+        )
+        return obj
+
+
 class Commit(MappedClass, RepoObject, ActivityObject):
     # Basic commit information
     # One of these for each commit in the physical repo on disk
@@ -1066,6 +1097,7 @@
     parent_ids = FieldProperty([str])
     child_ids = FieldProperty([str])
     repo_ids = FieldProperty([S.ObjectId()])
+    statuses = RelationProperty('CommitStatus', via="commit_id")
 
     type_s = 'Commit'
     # Ephemeral attrs
diff --git a/Allura/development.ini b/Allura/development.ini
index 4ddbc0c..2a13bae 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -449,6 +449,10 @@
 ; Max size for download a raw file from a repo
 scm.download.max_file_bytes = 30000000
 
+; Commit Status Support
+scm.commit_statuses = false
+
+
 ; bulk_export_enabled = true
 ; If you keep bulk_export_enabled, you should set up your server to securely share bulk_export_path with users somehow
 bulk_export_path = /tmp/bulk_export/{nbhd}/{project}