From e4b6542e5dd6d17f4cd3c748603a25477dd4e72a Mon Sep 17 00:00:00 2001
From: Piotr Zalewa <piotr@zalewa.info>
Date: Thu, 11 May 2017 14:18:56 +0200
Subject: [PATCH] Construct a phabrictator revision (with stub revision data)
 in the staging repo

---
 docker-compose.yml        |  1 +
 docker/Dockerfile-dev     | 17 +++++++
 docker/Dockerfile-prod    |  4 ++
 landoapi/api/revisions.py | 93 +++++++++++++++++++++++++++++++++++++++
 landoapi/spec/swagger.yml | 12 +++++
 5 files changed, 127 insertions(+)

diff --git a/docker-compose.yml b/docker-compose.yml
index abe1312d..0ce3c4ed 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -13,6 +13,7 @@ services:
     environment:
       - PORT=80
       - VERSION_PATH=/version.json
+      - PHABRICATOR_URI=http://phabricator.dev:7788/
   py3-linter:
     build:
       context: ./
diff --git a/docker/Dockerfile-dev b/docker/Dockerfile-dev
index 5d65f579..d266ceb6 100644
--- a/docker/Dockerfile-dev
+++ b/docker/Dockerfile-dev
@@ -4,6 +4,9 @@
 
 FROM python:3.5-alpine
 
+# Runtime dependencies
+RUN apk --no-cache --update add \
+	mercurial
 ADD requirements.txt /requirements.txt
 RUN pip install --no-cache -r /requirements.txt
 ADD dev-requirements.txt /dev-requirements.txt
@@ -18,6 +21,20 @@ RUN echo '{\
     "build": "dev"\
 }' >> /version.json
 
+ENV REPOSITORY_HOME /repos/
+
+# Create a fake repo
+# It will not be a part of PR
+# This is just the simplest way of creating the repo for now
+ENV STUB_REPOSITORY stub-repository
+RUN mkdir -p /repos/stub-repository
+RUN chmod 777 /repos/stub-repository
+RUN cd /repos/stub-repository
+RUN echo foo > foo
+RUN hg init
+RUN hg add foo
+RUN cd /
+
 ADD . /app
 WORKDIR /app
 
diff --git a/docker/Dockerfile-prod b/docker/Dockerfile-prod
index 495266c1..7a1b0f95 100644
--- a/docker/Dockerfile-prod
+++ b/docker/Dockerfile-prod
@@ -7,6 +7,10 @@ FROM python:3.5-alpine
 RUN addgroup -g 1001 app && \
     adduser -D -u 1001 -G app -s /usr/sbin/nologin app
 
+# Runtime dependencies
+RUN apk --no-cache --update add \
+	mercurial
+
 COPY requirements.txt /requirements.txt
 RUN pip install --no-cache -r /requirements.txt
 
diff --git a/landoapi/api/revisions.py b/landoapi/api/revisions.py
index 556c3228..a5228d83 100644
--- a/landoapi/api/revisions.py
+++ b/landoapi/api/revisions.py
@@ -1,7 +1,12 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+import os
+import subprocess
+import sys
+
 from connexion import problem
+from flask import request
 
 
 def search():
@@ -16,3 +21,91 @@ def get(id):
         'The requested revision does not exist',
         type='https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404'
     )
+
+
+REPOSITORY_HOME = os.environ.get('REPOSITORY_HOME', None)
+
+
+def post():
+    """Land a revision from Phabricator"""
+    if not REPOSITORY_HOME:
+        return problem(
+            500,
+            'Not configured',
+            'This method requires REPOSITORY_HOME env to return a string',
+            type='https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500'
+        )
+
+    # get phabricator revision id
+    data = request.form
+    if not data.get('id'):
+        return  problem(
+            400,
+            'No data provided',
+            'Phabricator Revision id is required',
+            type='https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400'
+        )
+
+    # get repository from phabricator
+    repository_name = os.environ.get('STUB_REPOSITORY', None)
+    if not repository_name:
+        return problem(
+            500,
+            'Not configured',
+            'This method requires STUB_REPOSITORY env to return a string',
+            type='https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500'
+        )
+    path = '%s%s' % (REPOSITORY_HOME, repository_name)
+    env = os.environ.copy()
+
+    # pull from the origin
+    env[b'PYTHONPATH'] = (':'.join(sys.path)).encode('utf-8')
+    p = subprocess.Popen('hg pull',
+                         cwd=path,
+                         env=env,
+                         stderr=subprocess.PIPE,
+                         stdout=subprocess.PIPE,
+                         universal_newlines=True,
+                         shell=True,
+                         )
+    try:
+        outs, errs = p.communicate(timeout=15)
+    except TimeoutExpired:
+        p.kill()
+        outs, errs = p.communicate()
+
+    if errs:
+        pass
+        # return problem(
+        #     500,
+        #     'Pull failed',
+        #     errs,
+        #     type='https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500'
+        # )
+
+    # create the commit from the diff
+    message = 'Hello World. Revision %s' % data['id']
+    p = subprocess.Popen('hg commit -m "%s"' % message,
+                         cwd=path,
+                         env=env,
+                         stderr=subprocess.PIPE,
+                         stdout=subprocess.PIPE,
+                         universal_newlines=True,
+                         shell=True,
+                         )
+    try:
+        outs, errs = p.communicate(timeout=2)
+    except TimeoutExpired:
+        p.kill()
+        outs, errs = p.communicate()
+
+    if errs:
+        return problem(
+            500,
+            'Commit failed',
+            errs,
+            type='https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500'
+        )
+
+    return 'YAY'
+
diff --git a/landoapi/spec/swagger.yml b/landoapi/spec/swagger.yml
index 455097ed..d0deb255 100644
--- a/landoapi/spec/swagger.yml
+++ b/landoapi/spec/swagger.yml
@@ -29,6 +29,18 @@ paths:
           schema:
             allOf:
               - $ref: '#/definitions/Error'
+    post:
+      summary: Add Phabricator revision to be landed.
+      description: |
+        TODO
+      responses:
+        200:
+          description: OK
+        default:
+          description: Unexpected error
+          schema:
+            allOf:
+              - $ref: '#/definitions/Error'
   /revisions/{id}:
     get:
       parameters: