Blame pagure/api/fork.py

Pierre-Yves Chibon 1e1949
# -*- coding: utf-8 -*-
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 1e1949
"""
Pierre-Yves Chibon b130e5
 (c) 2015-2017 - Copyright Red Hat Inc
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 1e1949
 Authors:
Pierre-Yves Chibon 1e1949
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 1e1949
"""
Pierre-Yves Chibon 1e1949
Aurélien Bompard 831553
from __future__ import unicode_literals
Aurélien Bompard 831553
Pierre-Yves Chibon b130e5
import logging
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 9811e6
import flask
Pierre-Yves Chibon 9811e6
import pygit2
Pierre-Yves Chibon 1e1949
from sqlalchemy.exc import SQLAlchemyError
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 1e1949
import pagure
Pierre-Yves Chibon 1e1949
import pagure.exceptions
Pierre-Yves Chibon 930073
import pagure.lib.query
Patrick Uiterwijk e6f1fd
import pagure.lib.tasks
Pierre-Yves Chibon 9c2953
from pagure.api import (
Pierre-Yves Chibon 9c2953
    API,
Pierre-Yves Chibon 9c2953
    api_method,
Pierre-Yves Chibon 9c2953
    api_login_required,
Pierre-Yves Chibon 9c2953
    APIERROR,
Pierre-Yves Chibon 9c2953
    get_authorized_api_project,
Pierre-Yves Chibon 9c2953
    get_request_data,
Pierre-Yves Chibon 9c2953
    get_page,
Pierre-Yves Chibon 9c2953
    get_per_page,
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
from pagure.config import config as pagure_config
Pierre-Yves Chibon 9c2953
from pagure.utils import (
Pierre-Yves Chibon 9c2953
    authenticated,
Pierre-Yves Chibon 9c2953
    is_repo_committer,
Pierre-Yves Chibon 9c2953
    is_true,
Pierre-Yves Chibon 9c2953
    api_authenticated,
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon b130e5
Pierre-Yves Chibon b130e5
Pierre-Yves Chibon b130e5
_log = logging.getLogger(__name__)
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 9c2953
@API.route("/<repo>/pull-requests")</repo>
Pierre-Yves Chibon 9c2953
@API.route("/<namespace>/<repo>/pull-requests")</repo></namespace>
Pierre-Yves Chibon 9c2953
@API.route("/fork/<username>/<repo>/pull-requests")</repo></username>
Pierre-Yves Chibon 9c2953
@API.route("/fork/<username>/<namespace>/<repo>/pull-requests")</repo></namespace></username>
Pierre-Yves Chibon c0cf15
@api_method
Pierre-Yves Chibon 34ece4
def api_pull_request_views(repo, username=None, namespace=None):
Pierre-Yves Chibon c0cf15
    """
Pierre-Yves Chibon c0cf15
    List project's Pull-Requests
Pierre-Yves Chibon c0cf15
    ----------------------------
Lei Yang 566c51
    Retrieve pull requests of a project.
Pierre-Yves Chibon c0cf15
Pierre-Yves Chibon c0cf15
    ::
Pierre-Yves Chibon c0cf15
Lei Yang 566c51
        GET /api/0/<repo>/pull-requests</repo>
Pierre-Yves Chibon 34ece4
        GET /api/0/<namespace>/<repo>/pull-requests</repo></namespace>
Pierre-Yves Chibon c0cf15
Lei Yang 566c51
    ::
Lei Yang 566c51
Lei Yang 566c51
        GET /api/0/fork/<username>/<repo>/pull-requests</repo></username>
Pierre-Yves Chibon 34ece4
        GET /api/0/fork/<username>/<namespace>/<repo>/pull-requests</repo></namespace></username>
Pierre-Yves Chibon c0cf15
Lei Yang 566c51
    Parameters
Lei Yang 566c51
    ^^^^^^^^^^
Pierre-Yves Chibon c0cf15
Pierre-Yves Chibon e1497f
    +---------------+----------+--------------+----------------------------+
Pierre-Yves Chibon e1497f
    | Key           | Type     | Optionality  | Description                |
Pierre-Yves Chibon e1497f
    +===============+==========+==============+============================+
Pierre-Yves Chibon e68983
    | ``status``    | string   | Optional     | | Filter the status of     |
Pierre-Yves Chibon e1497f
    |               |          |              |   pull requests. Default:  |
Pierre-Yves Chibon e1497f
    |               |          |              |   ``True`` (opened pull    |
Pierre-Yves Chibon e68983
    |               |          |              |   requests), can be ``0``  |
Pierre-Yves Chibon e68983
    |               |          |              |   or ``closed`` for closed |
Pierre-Yves Chibon e68983
    |               |          |              |   requests or ``Merged``   |
Pierre-Yves Chibon e68983
    |               |          |              |   for merged requests.     |
Eric Barbour 395fd2
    |               |          |              |   ``All`` returns closed,  |
Eric Barbour 395fd2
    |               |          |              |   merged and open requests.|
Pierre-Yves Chibon e1497f
    +---------------+----------+--------------+----------------------------+
Pierre-Yves Chibon e1497f
    | ``assignee``  | string   | Optional     | | Filter the assignee of   |
Pierre-Yves Chibon e1497f
    |               |          |              |   pull requests            |
Pierre-Yves Chibon e1497f
    +---------------+----------+--------------+----------------------------+
Pierre-Yves Chibon e1497f
    | ``author``    | string   | Optional     | | Filter the author of     |
Pierre-Yves Chibon e1497f
    |               |          |              |   pull requests            |
Pierre-Yves Chibon e1497f
    +---------------+----------+--------------+----------------------------+
Pierre-Yves Chibon c0cf15
Lei Yang 566c51
    Sample response
Lei Yang 566c51
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon c0cf15
Pierre-Yves Chibon c0cf15
    ::
Pierre-Yves Chibon c0cf15
Pierre-Yves Chibon c0cf15
        {
Pierre-Yves Chibon f3385b
          "args": {
Pierre-Yves Chibon f3385b
            "assignee": null,
Pierre-Yves Chibon f3385b
            "author": null,
Pierre-Yves Chibon f3385b
            "status": true
Pierre-Yves Chibon f3385b
          },
Pierre-Yves Chibon 7a734f
          "total_requests": 1,
Pierre-Yves Chibon f11edf
          "requests": [
Pierre-Yves Chibon f11edf
            {
Pierre-Yves Chibon f11edf
              "assignee": null,
Pierre-Yves Chibon f11edf
              "branch": "master",
Pierre-Yves Chibon f11edf
              "branch_from": "master",
Pierre-Yves Chibon 15c503
              "closed_at": null,
Pierre-Yves Chibon 15c503
              "closed_by": null,
Pierre-Yves Chibon f11edf
              "comments": [],
Pierre-Yves Chibon f11edf
              "commit_start": null,
Pierre-Yves Chibon f11edf
              "commit_stop": null,
Pierre-Yves Chibon f11edf
              "date_created": "1431414800",
Pierre-Yves Chibon f11edf
              "id": 1,
Pierre-Yves Chibon f11edf
              "project": {
Pierre-Yves Chibon f11edf
                "date_created": "1431414800",
Pierre-Yves Chibon f11edf
                "description": "test project #1",
Pierre-Yves Chibon f11edf
                "id": 1,
Pierre-Yves Chibon f11edf
                "name": "test",
Pierre-Yves Chibon f11edf
                "parent": null,
Pierre-Yves Chibon f11edf
                "user": {
Pierre-Yves Chibon f11edf
                  "fullname": "PY C",
Pierre-Yves Chibon f11edf
                  "name": "pingou"
Pierre-Yves Chibon f11edf
                }
Pierre-Yves Chibon f11edf
              },
Pierre-Yves Chibon f11edf
              "repo_from": {
Pierre-Yves Chibon f11edf
                "date_created": "1431414800",
Pierre-Yves Chibon f11edf
                "description": "test project #1",
Pierre-Yves Chibon f11edf
                "id": 1,
Pierre-Yves Chibon f11edf
                "name": "test",
Pierre-Yves Chibon f11edf
                "parent": null,
Pierre-Yves Chibon f11edf
                "user": {
Pierre-Yves Chibon f11edf
                  "fullname": "PY C",
Pierre-Yves Chibon f11edf
                  "name": "pingou"
Pierre-Yves Chibon f11edf
                }
Pierre-Yves Chibon f11edf
              },
Pierre-Yves Chibon 9e2f39
              "status": "Open",
Pierre-Yves Chibon f11edf
              "title": "test pull-request",
Pierre-Yves Chibon f11edf
              "uid": "1431414800",
Pierre-Yves Chibon e68983
              "updated_on": "1431414800",
Pierre-Yves Chibon f11edf
              "user": {
Pierre-Yves Chibon f11edf
                "fullname": "PY C",
Pierre-Yves Chibon f11edf
                "name": "pingou"
Pierre-Yves Chibon f11edf
              }
Pierre-Yves Chibon c0cf15
            }
Pierre-Yves Chibon f3385b
          ]
Pierre-Yves Chibon c0cf15
        }
Pierre-Yves Chibon c0cf15
Pierre-Yves Chibon c0cf15
    """
Pierre-Yves Chibon c0cf15
Patrick Uiterwijk eabc8e
    repo = get_authorized_api_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, repo, user=username, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon c0cf15
Pierre-Yves Chibon c0cf15
    if repo is None:
Pierre-Yves Chibon c0cf15
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT)
Pierre-Yves Chibon c0cf15
Pierre-Yves Chibon 9c2953
    if not repo.settings.get("pull_requests", True):
Pierre-Yves Chibon 5ce0d9
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon c0cf15
Pierre-Yves Chibon 9c2953
    status = flask.request.args.get("status", True)
Pierre-Yves Chibon 9c2953
    assignee = flask.request.args.get("assignee", None)
Pierre-Yves Chibon 9c2953
    author = flask.request.args.get("author", None)
Pierre-Yves Chibon c0cf15
Aurélien Bompard 619e2a
    status_text = ("%s" % status).lower()
Pierre-Yves Chibon c0cf15
    requests = []
Pierre-Yves Chibon 9c2953
    if status_text in ["0", "false", "closed"]:
Pierre-Yves Chibon 930073
        requests = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon b130e5
            flask.g.session,
Pierre-Yves Chibon c0cf15
            project_id=repo.id,
Pierre-Yves Chibon c0cf15
            status=False,
Pierre-Yves Chibon c0cf15
            assignee=assignee,
Pierre-Yves Chibon 9c2953
            author=author,
Pierre-Yves Chibon 9c2953
        )
Eric Barbour 395fd2
Pierre-Yves Chibon 9c2953
    elif status_text == "all":
Pierre-Yves Chibon 930073
        requests = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon b130e5
            flask.g.session,
Eric Barbour 395fd2
            project_id=repo.id,
Eric Barbour 395fd2
            status=None,
Eric Barbour 395fd2
            assignee=assignee,
Pierre-Yves Chibon 9c2953
            author=author,
Pierre-Yves Chibon 9c2953
        )
Eric Barbour 395fd2
Pierre-Yves Chibon c0cf15
    else:
Pierre-Yves Chibon 930073
        requests = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon b130e5
            flask.g.session,
Pierre-Yves Chibon c0cf15
            project_id=repo.id,
Pierre-Yves Chibon c0cf15
            assignee=assignee,
Pierre-Yves Chibon c0cf15
            author=author,
Pierre-Yves Chibon 9c2953
            status=status,
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon c0cf15
Karsten Hopp 566852
    page = get_page()
Karsten Hopp 566852
    per_page = get_per_page()
Karsten Hopp 566852
Pierre-Yves Chibon 930073
    pagination_metadata = pagure.lib.query.get_pagination_metadata(
Pierre-Yves Chibon 9c2953
        flask.request, page, per_page, len(requests)
Pierre-Yves Chibon 9c2953
    )
Karsten Hopp 566852
    start = (page - 1) * per_page
Karsten Hopp 566852
    if start + per_page > len(requests):
Karsten Hopp 566852
        requests_page = requests[start:]
Karsten Hopp 566852
    else:
Pierre-Yves Chibon 9c2953
        requests_page = requests[start : (start + per_page)]
Karsten Hopp 566852
Karsten Hopp 566852
    jsonout = {
Pierre-Yves Chibon 9c2953
        "total_requests": len(requests),
Pierre-Yves Chibon 9c2953
        "requests": [
Pierre-Yves Chibon 9c2953
            request.to_json(public=True, api=True) for request in requests_page
Pierre-Yves Chibon 9c2953
        ],
Pierre-Yves Chibon 9c2953
        "args": {"status": status, "assignee": assignee, "author": author},
Karsten Hopp 566852
    }
Karsten Hopp 566852
    if pagination_metadata:
Pierre-Yves Chibon 9c2953
        jsonout["args"]["page"] = page
Pierre-Yves Chibon 9c2953
        jsonout["args"]["per_page"] = per_page
Pierre-Yves Chibon 9c2953
        jsonout["pagination"] = pagination_metadata
Karsten Hopp 566852
    return flask.jsonify(jsonout)
Pierre-Yves Chibon c0cf15
Pierre-Yves Chibon c0cf15
Slavek Kabrda 1a6e21
@API.route("/pull-requests/<uid>")</uid>
Slavek Kabrda 1a6e21
@api_method
Slavek Kabrda 1a6e21
def api_pull_request_by_uid_view(uid):
Slavek Kabrda 1a6e21
    """
Slavek Kabrda 1a6e21
    Pull-request by UID information
Slavek Kabrda 1a6e21
    -------------------------------
Slavek Kabrda 1a6e21
    Retrieve information of a pull request specified by uid.
Slavek Kabrda 1a6e21
Slavek Kabrda 1a6e21
    ::
Slavek Kabrda 1a6e21
Slavek Kabrda 1a6e21
        GET /api/0/pull-requests/<uid></uid>
Slavek Kabrda 1a6e21
Slavek Kabrda 1a6e21
    Sample response
Slavek Kabrda 1a6e21
    ^^^^^^^^^^^^^^^
Slavek Kabrda 1a6e21
Slavek Kabrda 1a6e21
    ::
Slavek Kabrda 1a6e21
Slavek Kabrda 1a6e21
        {
Slavek Kabrda 1a6e21
          "assignee": null,
Slavek Kabrda 1a6e21
          "branch": "master",
Slavek Kabrda 1a6e21
          "branch_from": "master",
Slavek Kabrda 1a6e21
          "closed_at": null,
Slavek Kabrda 1a6e21
          "closed_by": null,
Slavek Kabrda 1a6e21
          "comments": [],
Slavek Kabrda 1a6e21
          "commit_start": null,
Slavek Kabrda 1a6e21
          "commit_stop": null,
Slavek Kabrda 1a6e21
          "date_created": "1431414800",
Slavek Kabrda 1a6e21
          "id": 1,
Slavek Kabrda 1a6e21
          "project": {
Slavek Kabrda 1a6e21
            "close_status": [],
Slavek Kabrda 1a6e21
            "custom_keys": [],
Slavek Kabrda 1a6e21
            "date_created": "1431414800",
Slavek Kabrda 1a6e21
            "description": "test project #1",
Slavek Kabrda 1a6e21
            "id": 1,
Slavek Kabrda 1a6e21
            "name": "test",
Slavek Kabrda 1a6e21
            "parent": null,
Slavek Kabrda 1a6e21
            "user": {
Slavek Kabrda 1a6e21
              "fullname": "PY C",
Slavek Kabrda 1a6e21
              "name": "pingou"
Slavek Kabrda 1a6e21
            }
Slavek Kabrda 1a6e21
          },
Slavek Kabrda 1a6e21
          "repo_from": {
Slavek Kabrda 1a6e21
            "date_created": "1431414800",
Slavek Kabrda 1a6e21
            "description": "test project #1",
Slavek Kabrda 1a6e21
            "id": 1,
Slavek Kabrda 1a6e21
            "name": "test",
Slavek Kabrda 1a6e21
            "parent": null,
Slavek Kabrda 1a6e21
            "user": {
Slavek Kabrda 1a6e21
              "fullname": "PY C",
Slavek Kabrda 1a6e21
              "name": "pingou"
Slavek Kabrda 1a6e21
            }
Slavek Kabrda 1a6e21
          },
Slavek Kabrda 1a6e21
          "status": "Open",
Slavek Kabrda 1a6e21
          "title": "test pull-request",
Slavek Kabrda 1a6e21
          "uid": "1431414800",
Slavek Kabrda 1a6e21
          "updated_on": "1431414800",
Slavek Kabrda 1a6e21
          "user": {
Slavek Kabrda 1a6e21
            "fullname": "PY C",
Slavek Kabrda 1a6e21
            "name": "pingou"
Slavek Kabrda 1a6e21
          }
Slavek Kabrda 1a6e21
        }
Slavek Kabrda 1a6e21
Slavek Kabrda 1a6e21
    """
Pierre-Yves Chibon 930073
    request = pagure.lib.query.get_request_by_uid(flask.g.session, uid)
Slavek Kabrda 1a6e21
    if not request:
Slavek Kabrda 1a6e21
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)
Slavek Kabrda 1a6e21
Slavek Kabrda 1a6e21
    # we don't really need the repo, but we need to make sure
Slavek Kabrda 1a6e21
    # that we're allowed to access it
Slavek Kabrda 1a6e21
    username = request.project.user.user if request.project.is_fork else None
Slavek Kabrda 1a6e21
    repo = get_authorized_api_project(
Patrick Uiterwijk 3f97f6
        flask.g.session,
Patrick Uiterwijk 3f97f6
        request.project.name,
Patrick Uiterwijk 3f97f6
        user=username,
Patrick Uiterwijk 3f97f6
        namespace=request.project.namespace,
Patrick Uiterwijk 3f97f6
    )
Slavek Kabrda 1a6e21
    if repo is None:
Slavek Kabrda 1a6e21
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)
Slavek Kabrda 1a6e21
Slavek Kabrda 1a6e21
    if not repo.settings.get("pull_requests", True):
Slavek Kabrda 1a6e21
        raise pagure.exceptions.APIError(
Slavek Kabrda 1a6e21
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
Slavek Kabrda 1a6e21
        )
Slavek Kabrda 1a6e21
Slavek Kabrda 1a6e21
    jsonout = flask.jsonify(request.to_json(public=True, api=True))
Slavek Kabrda 1a6e21
    return jsonout
Slavek Kabrda 1a6e21
Slavek Kabrda 1a6e21
Pierre-Yves Chibon 9c2953
@API.route("/<repo>/pull-request/<int:requestid>")</int:requestid></repo>
Pierre-Yves Chibon 9c2953
@API.route("/<namespace>/<repo>/pull-request/<int:requestid>")</int:requestid></repo></namespace>
Pierre-Yves Chibon 9c2953
@API.route("/fork/<username>/<repo>/pull-request/<int:requestid>")</int:requestid></repo></username>
Pierre-Yves Chibon 9c2953
@API.route("/fork/<username>/<namespace>/<repo>/pull-request/<int:requestid>")</int:requestid></repo></namespace></username>
Pierre-Yves Chibon bea7bd
@api_method
Pierre-Yves Chibon 34ece4
def api_pull_request_view(repo, requestid, username=None, namespace=None):
Pierre-Yves Chibon a6225b
    """
Pierre-Yves Chibon 1140cc
    Pull-request information
Pierre-Yves Chibon 1140cc
    ------------------------
Lei Yang 566c51
    Retrieve information of a specific pull request.
Pierre-Yves Chibon a6225b
Pierre-Yves Chibon a6225b
    ::
Pierre-Yves Chibon a6225b
Lei Yang 566c51
        GET /api/0/<repo>/pull-request/<request id=""></request></repo>
Pierre-Yves Chibon 34ece4
        GET /api/0/<namespace>/<repo>/pull-request/<request id=""></request></repo></namespace>
Pierre-Yves Chibon a6225b
Lei Yang 566c51
    ::
Pierre-Yves Chibon a6225b
Lei Yang 566c51
        GET /api/0/fork/<username>/<repo>/pull-request/<request id=""></request></repo></username>
Pierre-Yves Chibon 34ece4
        GET /api/0/fork/<username>/<namespace>/<repo>/pull-request/<request id=""></request></repo></namespace></username>
Pierre-Yves Chibon a6225b
Lei Yang 566c51
    Sample response
Lei Yang 566c51
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon a6225b
Pierre-Yves Chibon a6225b
    ::
Pierre-Yves Chibon a6225b
Pierre-Yves Chibon a6225b
        {
Pierre-Yves Chibon a6225b
          "assignee": null,
Pierre-Yves Chibon a6225b
          "branch": "master",
Pierre-Yves Chibon a6225b
          "branch_from": "master",
Pierre-Yves Chibon 15c503
          "closed_at": null,
Pierre-Yves Chibon 15c503
          "closed_by": null,
Pierre-Yves Chibon a6225b
          "comments": [],
Pierre-Yves Chibon a6225b
          "commit_start": null,
Pierre-Yves Chibon a6225b
          "commit_stop": null,
Pierre-Yves Chibon a6225b
          "date_created": "1431414800",
Pierre-Yves Chibon a6225b
          "id": 1,
Pierre-Yves Chibon a6225b
          "project": {
Farhaan Bukhsh ed34e5
            "close_status": [],
Farhaan Bukhsh ed34e5
            "custom_keys": [],
Pierre-Yves Chibon a6225b
            "date_created": "1431414800",
Pierre-Yves Chibon a6225b
            "description": "test project #1",
Pierre-Yves Chibon a6225b
            "id": 1,
Pierre-Yves Chibon a6225b
            "name": "test",
Pierre-Yves Chibon a6225b
            "parent": null,
Pierre-Yves Chibon a6225b
            "user": {
Pierre-Yves Chibon a6225b
              "fullname": "PY C",
Pierre-Yves Chibon a6225b
              "name": "pingou"
Pierre-Yves Chibon a6225b
            }
Pierre-Yves Chibon a6225b
          },
Pierre-Yves Chibon a6225b
          "repo_from": {
Pierre-Yves Chibon a6225b
            "date_created": "1431414800",
Pierre-Yves Chibon a6225b
            "description": "test project #1",
Pierre-Yves Chibon a6225b
            "id": 1,
Pierre-Yves Chibon a6225b
            "name": "test",
Pierre-Yves Chibon a6225b
            "parent": null,
Pierre-Yves Chibon a6225b
            "user": {
Pierre-Yves Chibon a6225b
              "fullname": "PY C",
Pierre-Yves Chibon a6225b
              "name": "pingou"
Pierre-Yves Chibon a6225b
            }
Pierre-Yves Chibon a6225b
          },
Pierre-Yves Chibon 9e2f39
          "status": "Open",
Pierre-Yves Chibon a6225b
          "title": "test pull-request",
Pierre-Yves Chibon a6225b
          "uid": "1431414800",
Pierre-Yves Chibon e68983
          "updated_on": "1431414800",
Pierre-Yves Chibon a6225b
          "user": {
Pierre-Yves Chibon a6225b
            "fullname": "PY C",
Pierre-Yves Chibon a6225b
            "name": "pingou"
Pierre-Yves Chibon a6225b
          }
Pierre-Yves Chibon a6225b
        }
Pierre-Yves Chibon a6225b
Pierre-Yves Chibon bea7bd
    """
Pierre-Yves Chibon bea7bd
Patrick Uiterwijk eabc8e
    repo = get_authorized_api_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, repo, user=username, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon bea7bd
Pierre-Yves Chibon bea7bd
    if repo is None:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT)
Pierre-Yves Chibon bea7bd
Pierre-Yves Chibon 9c2953
    if not repo.settings.get("pull_requests", True):
Pierre-Yves Chibon 5ce0d9
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon bea7bd
Pierre-Yves Chibon 930073
    request = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon 9c2953
        flask.g.session, project_id=repo.id, requestid=requestid
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon bea7bd
Pierre-Yves Chibon bea7bd
    if not request:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)
Pierre-Yves Chibon bea7bd
Pierre-Yves Chibon 87d805
    jsonout = flask.jsonify(request.to_json(public=True, api=True))
Pierre-Yves Chibon bea7bd
    return jsonout
Pierre-Yves Chibon bea7bd
Pierre-Yves Chibon bea7bd
Pierre-Yves Chibon 9c2953
@API.route("/<repo>/pull-request/<int:requestid>/merge", methods=["POST"])</int:requestid></repo>
Pierre-Yves Chibon 34ece4
@API.route(
Pierre-Yves Chibon 9c2953
    "/<namespace>/<repo>/pull-request/<int:requestid>/merge", methods=["POST"]</int:requestid></repo></namespace>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 34ece4
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/pull-request/<int:requestid>/merge",</int:requestid></repo></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/pull-request/<int:requestid>/merge",</int:requestid></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@api_login_required(acls=["pull_request_merge"])
Pierre-Yves Chibon 807fce
@api_method
Pierre-Yves Chibon 34ece4
def api_pull_request_merge(repo, requestid, username=None, namespace=None):
Pierre-Yves Chibon be094c
    """
Pierre-Yves Chibon be094c
    Merge a pull-request
Pierre-Yves Chibon be094c
    --------------------
Lubomír Sedlář f02111
    Instruct Pagure to merge a pull request.
Pierre-Yves Chibon be094c
Patrick Uiterwijk e6f1fd
    This is an asynchronous call.
Patrick Uiterwijk e6f1fd
Pierre-Yves Chibon be094c
    ::
Pierre-Yves Chibon be094c
Lei Yang 566c51
        POST /api/0/<repo>/pull-request/<request id="">/merge</request></repo>
Pierre-Yves Chibon 34ece4
        POST /api/0/<namespace>/<repo>/pull-request/<request id="">/merge</request></repo></namespace>
Pierre-Yves Chibon be094c
Lei Yang 566c51
    ::
Pierre-Yves Chibon be094c
Lei Yang 566c51
        POST /api/0/fork/<username>/<repo>/pull-request/<request id="">/merge</request></repo></username>
Pierre-Yves Chibon 34ece4
        POST /api/0/fork/<username>/<namespace>/<repo>/pull-request/<request id="">/merge</request></repo></namespace></username>
Pierre-Yves Chibon be094c
Lei Yang 566c51
    Sample response
Lei Yang 566c51
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon be094c
Pierre-Yves Chibon be094c
    ::
Pierre-Yves Chibon be094c
Patrick Uiterwijk 0281ff
        wait=False:
Pierre-Yves Chibon be094c
        {
Patrick Uiterwijk e6f1fd
          "message": "Merging queued",
Patrick Uiterwijk e6f1fd
          "taskid": "123-abcd"
Pierre-Yves Chibon be094c
        }
Pierre-Yves Chibon be094c
Patrick Uiterwijk 0281ff
        wait=True:
Patrick Uiterwijk 0281ff
        {
Patrick Uiterwijk 0281ff
          "message": "Changes merged!"
Patrick Uiterwijk 0281ff
        }
Patrick Uiterwijk 0281ff
Pierre-Yves Chibon 4768f2
    """  # noqa
Pierre-Yves Chibon 807fce
    output = {}
Pierre-Yves Chibon 807fce
Patrick Uiterwijk eabc8e
    repo = get_authorized_api_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, repo, user=username, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 807fce
    if repo is None:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT)
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 9c2953
    if not repo.settings.get("pull_requests", True):
Pierre-Yves Chibon 5ce0d9
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon dea6ca
    if flask.g.token.project and repo != flask.g.token.project:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 930073
    request = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon 9c2953
        flask.g.session, project_id=repo.id, requestid=requestid
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 807fce
    if not request:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)
Pierre-Yves Chibon 807fce
Vivek Anand 967335
    if not is_repo_committer(repo):
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(403, error_code=APIERROR.ENOPRCLOSE)
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 9c2953
    if repo.settings.get("Only_assignee_can_merge_pull-request", False):
Pierre-Yves Chibon 807fce
        if not request.assignee:
Pierre-Yves Chibon 53433f
            raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
                403, error_code=APIERROR.ENOTASSIGNED
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 807fce
        if request.assignee.username != flask.g.fas_user.username:
Pierre-Yves Chibon 704030
            raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
                403, error_code=APIERROR.ENOTASSIGNEE
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 9c2953
    threshold = repo.settings.get("Minimum_score_to_merge_pull-request", -1)
Pierre-Yves Chibon 807fce
    if threshold > 0 and int(request.score) < int(threshold):
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(403, error_code=APIERROR.EPRSCORE)
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 1b3ac8
    task = pagure.lib.tasks.merge_pull_request.delay(
Pierre-Yves Chibon 9c2953
        repo.name, namespace, username, requestid, flask.g.fas_user.username
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    output = {"message": "Merging queued", "taskid": task.id}
Pierre-Yves Chibon 1b3ac8
Pierre-Yves Chibon 9c2953
    if get_request_data().get("wait", True):
Pierre-Yves Chibon 1b3ac8
        task.get()
Pierre-Yves Chibon 9c2953
        output = {"message": "Changes merged!"}
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 807fce
    jsonout = flask.jsonify(output)
Pierre-Yves Chibon 807fce
    return jsonout
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 807fce
Pierre-Yves Chibon 9c2953
@API.route("/<repo>/pull-request/<int:requestid>/close", methods=["POST"])</int:requestid></repo>
Pierre-Yves Chibon 34ece4
@API.route(
Pierre-Yves Chibon 9c2953
    "/<namespace>/<repo>/pull-request/<int:requestid>/close", methods=["POST"]</int:requestid></repo></namespace>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 34ece4
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/pull-request/<int:requestid>/close",</int:requestid></repo></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/pull-request/<int:requestid>/close",</int:requestid></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@api_login_required(acls=["pull_request_close"])
Pierre-Yves Chibon 291626
@api_method
Pierre-Yves Chibon 34ece4
def api_pull_request_close(repo, requestid, username=None, namespace=None):
Pierre-Yves Chibon 2da4df
    """
Pierre-Yves Chibon 2da4df
    Close a pull-request
Pierre-Yves Chibon 2da4df
    --------------------
Lei Yang 566c51
    Instruct Pagure to close a pull request.
Pierre-Yves Chibon 2da4df
Pierre-Yves Chibon 2da4df
    ::
Pierre-Yves Chibon 2da4df
Lei Yang 566c51
        POST /api/0/<repo>/pull-request/<request id="">/close</request></repo>
Pierre-Yves Chibon 34ece4
        POST /api/0/<namespace>/<repo>/pull-request/<request id="">/close</request></repo></namespace>
Pierre-Yves Chibon 2da4df
Lei Yang 566c51
    ::
Pierre-Yves Chibon 2da4df
Lei Yang 566c51
        POST /api/0/fork/<username>/<repo>/pull-request/<request id="">/close</request></repo></username>
Pierre-Yves Chibon 34ece4
        POST /api/0/fork/<username>/<namespace>/<repo>/pull-request/<request id="">/close</request></repo></namespace></username>
Pierre-Yves Chibon 2da4df
Lei Yang 566c51
    Sample response
Lei Yang 566c51
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon 2da4df
Pierre-Yves Chibon 2da4df
    ::
Pierre-Yves Chibon 2da4df
Pierre-Yves Chibon 2da4df
        {
Pierre-Yves Chibon 369fd6
          "message": "Pull-request closed!"
Pierre-Yves Chibon 2da4df
        }
Pierre-Yves Chibon 2da4df
Pierre-Yves Chibon 4768f2
    """  # noqa
Pierre-Yves Chibon 291626
    output = {}
Pierre-Yves Chibon 291626
Patrick Uiterwijk eabc8e
    repo = get_authorized_api_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, repo, user=username, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 291626
Pierre-Yves Chibon 291626
    if repo is None:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT)
Pierre-Yves Chibon 291626
Pierre-Yves Chibon 9c2953
    if not repo.settings.get("pull_requests", True):
Pierre-Yves Chibon 5ce0d9
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 291626
Pierre-Yves Chibon 291626
    if repo != flask.g.token.project:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)
Pierre-Yves Chibon 291626
Pierre-Yves Chibon 930073
    request = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon 9c2953
        flask.g.session, project_id=repo.id, requestid=requestid
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 291626
Pierre-Yves Chibon 291626
    if not request:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)
Pierre-Yves Chibon 291626
Vivek Anand 967335
    if not is_repo_committer(repo):
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(403, error_code=APIERROR.ENOPRCLOSE)
Pierre-Yves Chibon 291626
Pierre-Yves Chibon 291626
    try:
Pierre-Yves Chibon 930073
        pagure.lib.query.close_pull_request(
Patrick Uiterwijk 3f97f6
            flask.g.session, request, flask.g.fas_user.username, merged=False
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon b130e5
        flask.g.session.commit()
Pierre-Yves Chibon 9c2953
        output["message"] = "Pull-request closed!"
Pierre-Yves Chibon 291626
    except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
        flask.g.session.rollback()
Pierre-Yves Chibon b130e5
        _log.exception(err)
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)
Pierre-Yves Chibon 291626
Pierre-Yves Chibon 291626
    jsonout = flask.jsonify(output)
Pierre-Yves Chibon 291626
    return jsonout
Pierre-Yves Chibon 291626
Pierre-Yves Chibon 291626
Pierre-Yves Chibon 9c2953
@API.route("/<repo>/pull-request/<int:requestid>/comment", methods=["POST"])</int:requestid></repo>
Pierre-Yves Chibon 9c2953
@API.route(
Pierre-Yves Chibon 9c2953
    "/<namespace>/<repo>/pull-request/<int:requestid>/comment",</int:requestid></repo></namespace>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/pull-request/<int:requestid>/comment",</int:requestid></repo></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 34ece4
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/pull-request/<int:requestid>/comment",</int:requestid></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@api_login_required(acls=["pull_request_comment"])
Pierre-Yves Chibon 1e1949
@api_method
Pierre-Yves Chibon 34ece4
def api_pull_request_add_comment(
Pierre-Yves Chibon 9c2953
    repo, requestid, username=None, namespace=None
Pierre-Yves Chibon 9c2953
):
Pierre-Yves Chibon e91c31
    """
Pierre-Yves Chibon e91c31
    Comment on a pull-request
Pierre-Yves Chibon 47edc6
    -------------------------
Lei Yang 566c51
    Add comment to a pull request.
Pierre-Yves Chibon e91c31
Pierre-Yves Chibon e91c31
    ::
Pierre-Yves Chibon e91c31
Lei Yang 566c51
        POST /api/0/<repo>/pull-request/<request id="">/comment</request></repo>
Pierre-Yves Chibon 34ece4
        POST /api/0/<namespace>/<repo>/pull-request/<request id="">/comment</request></repo></namespace>
Lei Yang 566c51
Lei Yang 566c51
    ::
Pierre-Yves Chibon e91c31
Lei Yang 566c51
        POST /api/0/fork/<username>/<repo>/pull-request/<request id="">/comment</request></repo></username>
Pierre-Yves Chibon 34ece4
        POST /api/0/fork/<username>/<namespace>/<repo>/pull-request/<request id="">/comment</request></repo></namespace></username>
Pierre-Yves Chibon e91c31
Lei Yang 566c51
    Input
Lei Yang 566c51
    ^^^^^
Pierre-Yves Chibon e91c31
Pierre-Yves Chibon e1497f
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon e1497f
    | Key           | Type    | Optionality  | Description                 |
Pierre-Yves Chibon e1497f
    +===============+=========+==============+=============================+
Pierre-Yves Chibon e1497f
    | ``comment``   | string  | Mandatory    | | The comment to add        |
Pierre-Yves Chibon e1497f
    |               |         |              |   to the pull request       |
Pierre-Yves Chibon e1497f
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon e1497f
    | ``commit``    | string  | Optional     | | The hash of the specific  |
Pierre-Yves Chibon e1497f
    |               |         |              |   commit you wish to        |
Pierre-Yves Chibon e1497f
    |               |         |              |   comment on                |
Pierre-Yves Chibon e1497f
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon e1497f
    | ``filename``  | string  | Optional     | | The filename of the       |
Pierre-Yves Chibon e1497f
    |               |         |              |   specific file you wish    |
Pierre-Yves Chibon e1497f
    |               |         |              |   to comment on             |
Pierre-Yves Chibon e1497f
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon e1497f
    | ``row``       | int     | Optional     | | Used in combination       |
Pierre-Yves Chibon e1497f
    |               |         |              |   with filename to comment  |
Pierre-Yves Chibon e1497f
    |               |         |              |   on a specific row         |
Pierre-Yves Chibon e1497f
    |               |         |              |   of a file                 |
Pierre-Yves Chibon e1497f
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon 626dba
    | ``tree_id``   | string  | Optional     | | The identifier of the     |
Pierre-Yves Chibon 626dba
    |               |         |              |   git tree as it was when   |
Pierre-Yves Chibon 626dba
    |               |         |              |   the comment was added     |
Pierre-Yves Chibon 626dba
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon e91c31
Lei Yang 566c51
    Sample response
Lei Yang 566c51
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon e91c31
Pierre-Yves Chibon e91c31
    ::
Pierre-Yves Chibon e91c31
Pierre-Yves Chibon e91c31
        {
Pierre-Yves Chibon e91c31
          "message": "Comment added"
Pierre-Yves Chibon e91c31
        }
Pierre-Yves Chibon e91c31
Pierre-Yves Chibon 4768f2
    """  # noqa
Patrick Uiterwijk eabc8e
    repo = get_authorized_api_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, repo, user=username, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
farhaanbukhsh 44a97a
Pierre-Yves Chibon 1e1949
    output = {}
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 1e1949
    if repo is None:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT)
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 9c2953
    if not repo.settings.get("pull_requests", True):
Pierre-Yves Chibon 5ce0d9
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 1dfd94
    if flask.g.token.project and repo != flask.g.token.project:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 930073
    request = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon 9c2953
        flask.g.session, project_id=repo.id, requestid=requestid
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 1e1949
    if not request:
Pierre-Yves Chibon 23d3ff
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 5c561c
    form = pagure.forms.AddPullRequestCommentForm(csrf_enabled=False)
Pierre-Yves Chibon 1e1949
    if form.validate_on_submit():
Pierre-Yves Chibon 1e1949
        comment = form.comment.data
Pierre-Yves Chibon 551952
        commit = form.commit.data or None
Pierre-Yves Chibon 551952
        filename = form.filename.data or None
Pierre-Yves Chibon 626dba
        tree_id = form.tree_id.data or None
Pierre-Yves Chibon 551952
        row = form.row.data or None
Pierre-Yves Chibon 1e1949
        try:
Pierre-Yves Chibon 1e1949
            # New comment
Pierre-Yves Chibon 930073
            message = pagure.lib.query.add_pull_request_comment(
Pierre-Yves Chibon b130e5
                flask.g.session,
Pierre-Yves Chibon 1e1949
                request=request,
Pierre-Yves Chibon 1e1949
                commit=commit,
Pierre-Yves Chibon 626dba
                tree_id=tree_id,
Pierre-Yves Chibon 1e1949
                filename=filename,
Pierre-Yves Chibon 1e1949
                row=row,
Pierre-Yves Chibon 1e1949
                comment=comment,
Pierre-Yves Chibon 1e1949
                user=flask.g.fas_user.username,
Pierre-Yves Chibon 1e1949
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 9c2953
            output["message"] = message
Pierre-Yves Chibon d47179
        except pagure.exceptions.PagureException as err:
Pierre-Yves Chibon d47179
            raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
                400, error_code=APIERROR.ENOCODE, error=str(err)
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon fa97f7
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            _log.exception(err)
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon 23d3ff
            raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 1e1949
    else:
Pierre-Yves Chibon f7fcaa
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            400, error_code=APIERROR.EINVALIDREQ, errors=form.errors
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 1e1949
Pierre-Yves Chibon 1e1949
    jsonout = flask.jsonify(output)
Pierre-Yves Chibon 1e1949
    return jsonout
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon 9c2953
@API.route("/<repo>/pull-request/<int:requestid>/flag", methods=["POST"])</int:requestid></repo>
Pierre-Yves Chibon 34ece4
@API.route(
Pierre-Yves Chibon 9c2953
    "/<namespace>/<repo>/pull-request/<int:requestid>/flag", methods=["POST"]</int:requestid></repo></namespace>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/pull-request/<int:requestid>/flag",</int:requestid></repo></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/pull-request/<int:requestid>/flag",</int:requestid></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@api_login_required(acls=["pull_request_flag"])
Pierre-Yves Chibon e39f18
@api_method
Pierre-Yves Chibon 34ece4
def api_pull_request_add_flag(repo, requestid, username=None, namespace=None):
Pierre-Yves Chibon e39f18
    """
Pierre-Yves Chibon e39f18
    Flag a pull-request
Pierre-Yves Chibon e39f18
    -------------------
Lei Yang 566c51
    Add or edit flags on a pull-request.
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon e39f18
    ::
Pierre-Yves Chibon e39f18
Lei Yang 566c51
        POST /api/0/<repo>/pull-request/<request id="">/flag</request></repo>
Pierre-Yves Chibon 34ece4
        POST /api/0/<namespace>/<repo>/pull-request/<request id="">/flag</request></repo></namespace>
Lei Yang 566c51
Lei Yang 566c51
    ::
Lei Yang 566c51
Lei Yang 566c51
        POST /api/0/fork/<username>/<repo>/pull-request/<request id="">/flag</request></repo></username>
Pierre-Yves Chibon 34ece4
        POST /api/0/fork/<username>/<namespace>/<repo>/pull-request/<request id="">/flag</request></repo></namespace></username>
Lei Yang 566c51
Lei Yang 566c51
    Input
Lei Yang 566c51
    ^^^^^
Lei Yang 566c51
Pierre-Yves Chibon e1497f
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon e1497f
    | Key           | Type    | Optionality  | Description                 |
Pierre-Yves Chibon e1497f
    +===============+=========+==============+=============================+
Pierre-Yves Chibon e1497f
    | ``username``  | string  | Mandatory    | | The name of the           |
Pierre-Yves Chibon e1497f
    |               |         |              |   application to be         |
Pierre-Yves Chibon e1497f
    |               |         |              |   presented to users        |
Pierre-Yves Chibon e1497f
    |               |         |              |   on the pull request page  |
Pierre-Yves Chibon e1497f
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon e1497f
    | ``comment``   | string  | Mandatory    | | A short message           |
Pierre-Yves Chibon e1497f
    |               |         |              |   summarizing the           |
Pierre-Yves Chibon e1497f
    |               |         |              |   presented results         |
Pierre-Yves Chibon e1497f
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon e1497f
    | ``url``       | string  | Mandatory    | | A URL to the result       |
Pierre-Yves Chibon e1497f
    |               |         |              |   of this flag              |
Pierre-Yves Chibon e1497f
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon abcbf7
    | ``status``    | string  | Optional     | | The status of the task,   |
Slavek Kabrda 45252f
    |               |         |              |   can be any of:            |
Slavek Kabrda 45252f
    |               |         |              |   $$FLAG_STATUSES_COMMAS$$  |
Slavek Kabrda 45252f
    |               |         |              |   If not provided it will   |
Slavek Kabrda 45252f
    |               |         |              |   be set to                 |
Slavek Kabrda 45252f
    |               |         |              |   ``$$FLAG_SUCCESS$$`` if   |
Slavek Kabrda 45252f
    |               |         |              |   percent is higher than 0  |
Slavek Kabrda 45252f
    |               |         |              |   ``$$FLAG_FAILURE$$`` if   |
Slavek Kabrda 45252f
    |               |         |              |   it is 0 and               |
Slavek Kabrda 45252f
    |               |         |              |   ``$$FLAG_PENDING$$``      |
Slavek Kabrda 45252f
    |               |         |              |   if percent is not         |
Slavek Kabrda 45252f
    |               |         |              |   specified                 |
Pierre-Yves Chibon abcbf7
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon abcbf7
    | ``percent``   | int     | Optional     | | A percentage of           |
Pierre-Yves Chibon abcbf7
    |               |         |              |   completion compared to    |
Pierre-Yves Chibon abcbf7
    |               |         |              |   the goal. The percentage  |
Pierre-Yves Chibon abcbf7
    |               |         |              |   also determine the        |
Pierre-Yves Chibon abcbf7
    |               |         |              |   background color of the   |
Pierre-Yves Chibon abcbf7
    |               |         |              |   flag on the pull-request  |
Pierre-Yves Chibon abcbf7
    |               |         |              |   page                      |
Pierre-Yves Chibon abcbf7
    +---------------+---------+--------------+-----------------------------+
Pierre-Yves Chibon e1497f
    | ``uid``       | string  | Optional     | | A unique identifier used  |
Pierre-Yves Chibon e1497f
    |               |         |              |   to identify a flag on a   |
Pierre-Yves Chibon e1497f
    |               |         |              |   pull-request. If the      |
Pierre-Yves Chibon e1497f
    |               |         |              |   provided UID matches an   |
Pierre-Yves Chibon e1497f
    |               |         |              |   existing one, then the    |
Pierre-Yves Chibon e1497f
    |               |         |              |   API call will update the  |
Pierre-Yves Chibon e1497f
    |               |         |              |   existing one rather than  |
Pierre-Yves Chibon e1497f
    |               |         |              |   create a new one.         |
Pierre-Yves Chibon e1497f
    |               |         |              |   Maximum Length: 32        |
Pierre-Yves Chibon e1497f
    |               |         |              |   characters. Default: an   |
Pierre-Yves Chibon e1497f
    |               |         |              |   auto generated UID        |
Pierre-Yves Chibon e1497f
    +---------------+---------+--------------+-----------------------------+
Lei Yang 566c51
Lei Yang 566c51
    Sample response
Lei Yang 566c51
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon e39f18
    ::
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon e39f18
        {
Pierre-Yves Chibon c27d61
          "flag": {
Pierre-Yves Chibon c27d61
            "comment": "Tests failed",
Pierre-Yves Chibon c27d61
            "date_created": "1510742565",
Pierre-Yves Chibon c27d61
            "percent": 0,
Pierre-Yves Chibon c27d61
            "pull_request_uid": "62b49f00d489452994de5010565fab81",
Pierre-Yves Chibon abcbf7
            "status": "error",
Pierre-Yves Chibon c27d61
            "url": "http://jenkins.cloud.fedoraproject.org/",
Pierre-Yves Chibon c27d61
            "user": {
Pierre-Yves Chibon c27d61
              "default_email": "bar@pingou.com",
Pierre-Yves Chibon c27d61
              "emails": ["bar@pingou.com", "foo@pingou.com"],
Pierre-Yves Chibon c27d61
              "fullname": "PY C",
Pierre-Yves Chibon c27d61
              "name": "pingou"},
Pierre-Yves Chibon c27d61
            "username": "Jenkins"},
Pierre-Yves Chibon c27d61
          "message": u"Flag added",
Pierre-Yves Chibon c27d61
          "uid": u"jenkins_build_pagure_100+seed"
Pierre-Yves Chibon e39f18
        }
Pierre-Yves Chibon e39f18
Lei Yang 566c51
    ::
Lei Yang 566c51
Lei Yang 566c51
        {
Pierre-Yves Chibon c27d61
          "flag": {
Pierre-Yves Chibon c27d61
            "comment": "Tests failed",
Pierre-Yves Chibon c27d61
            "date_created": "1510742565",
Pierre-Yves Chibon c27d61
            "percent": 0,
Pierre-Yves Chibon c27d61
            "pull_request_uid": "62b49f00d489452994de5010565fab81",
Pierre-Yves Chibon abcbf7
            "status": "error",
Pierre-Yves Chibon c27d61
            "url": "http://jenkins.cloud.fedoraproject.org/",
Pierre-Yves Chibon c27d61
            "user": {
Pierre-Yves Chibon c27d61
              "default_email": "bar@pingou.com",
Pierre-Yves Chibon c27d61
              "emails": ["bar@pingou.com", "foo@pingou.com"],
Pierre-Yves Chibon c27d61
              "fullname": "PY C",
Pierre-Yves Chibon c27d61
              "name": "pingou"},
Pierre-Yves Chibon c27d61
            "username": "Jenkins"},
Pierre-Yves Chibon c27d61
          "message": u"Flag updated",
Pierre-Yves Chibon c27d61
          "uid": u"jenkins_build_pagure_100+seed"
Lei Yang 566c51
        }
Lei Yang 566c51
Pierre-Yves Chibon 4768f2
    """  # noqa
Patrick Uiterwijk eabc8e
    repo = get_authorized_api_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, repo, user=username, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
farhaanbukhsh 44a97a
Pierre-Yves Chibon e39f18
    output = {}
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon e39f18
    if repo is None:
Pierre-Yves Chibon 9c2953
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT)
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon 9c2953
    if not repo.settings.get("pull_requests", True):
Pierre-Yves Chibon e39f18
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon 1dfd94
    if flask.g.token.project and repo != flask.g.token.project:
Pierre-Yves Chibon 9c2953
        raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon 930073
    request = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon 9c2953
        flask.g.session, project_id=repo.id, requestid=requestid
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon e39f18
    if not request:
Pierre-Yves Chibon e39f18
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon 9c2953
    if "status" in get_request_data():
Pierre-Yves Chibon 5c561c
        form = pagure.forms.AddPullRequestFlagForm(csrf_enabled=False)
Pierre-Yves Chibon abcbf7
    else:
Pierre-Yves Chibon 5c561c
        form = pagure.forms.AddPullRequestFlagFormV1(csrf_enabled=False)
Pierre-Yves Chibon e39f18
    if form.validate_on_submit():
Pierre-Yves Chibon e39f18
        username = form.username.data
Pierre-Yves Chibon abcbf7
        percent = form.percent.data.strip() or None
Pierre-Yves Chibon e39f18
        comment = form.comment.data.strip()
Pierre-Yves Chibon e39f18
        url = form.url.data.strip()
Pierre-Yves Chibon e39f18
        uid = form.uid.data.strip() if form.uid.data else None
Pierre-Yves Chibon 9c2953
        if "status" in get_request_data():
Pierre-Yves Chibon abcbf7
            status = form.status.data.strip()
Pierre-Yves Chibon abcbf7
        else:
Pierre-Yves Chibon abcbf7
            if percent is None:
Pierre-Yves Chibon 9c2953
                status = pagure_config["FLAG_PENDING"]
Pierre-Yves Chibon abcbf7
            else:
Pierre-Yves Chibon 9c2953
                status = (
Pierre-Yves Chibon 9c2953
                    pagure_config["FLAG_SUCCESS"]
Pierre-Yves Chibon 9c2953
                    if percent != "0"
Pierre-Yves Chibon 9c2953
                    else pagure_config["FLAG_FAILURE"]
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon e39f18
        try:
Pierre-Yves Chibon e39f18
            # New Flag
Pierre-Yves Chibon 930073
            message, uid = pagure.lib.query.add_pull_request_flag(
Pierre-Yves Chibon b130e5
                flask.g.session,
Pierre-Yves Chibon e39f18
                request=request,
Pierre-Yves Chibon e39f18
                username=username,
Pierre-Yves Chibon abcbf7
                status=status,
Pierre-Yves Chibon e39f18
                percent=percent,
Pierre-Yves Chibon e39f18
                comment=comment,
Pierre-Yves Chibon e39f18
                url=url,
Pierre-Yves Chibon e39f18
                uid=uid,
Pierre-Yves Chibon e39f18
                user=flask.g.fas_user.username,
Pierre-Yves Chibon ba2b1c
                token=flask.g.token.id,
Pierre-Yves Chibon e39f18
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 930073
            pr_flag = pagure.lib.query.get_pull_request_flag_by_uid(
Pierre-Yves Chibon 9c2953
                flask.g.session, request, uid
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 9c2953
            output["message"] = message
Pierre-Yves Chibon 9c2953
            output["uid"] = uid
Pierre-Yves Chibon 9c2953
            output["flag"] = pr_flag.to_json()
Pierre-Yves Chibon e39f18
        except pagure.exceptions.PagureException as err:
Pierre-Yves Chibon e39f18
            raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
                400, error_code=APIERROR.ENOCODE, error=str(err)
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon fa97f7
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            _log.exception(err)
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon e39f18
            raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon e39f18
    else:
Pierre-Yves Chibon f7fcaa
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            400, error_code=APIERROR.EINVALIDREQ, errors=form.errors
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon e39f18
Pierre-Yves Chibon 930073
    output["avatar_url"] = pagure.lib.query.avatar_url_from_email(
Pierre-Yves Chibon 9c2953
        flask.g.fas_user.default_email, size=30
Pierre-Yves Chibon 9c2953
    )
Ryan Lerch ccb2e0
Pierre-Yves Chibon 9c2953
    output["user"] = flask.g.fas_user.username
Ryan Lerch ccb2e0
Pierre-Yves Chibon e39f18
    jsonout = flask.jsonify(output)
Pierre-Yves Chibon e39f18
    return jsonout
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 9c2953
@API.route("/<repo>/pull-request/<int:requestid>/subscribe", methods=["POST"])</int:requestid></repo>
Pierre-Yves Chibon 4f5301
@API.route(
Pierre-Yves Chibon 9c2953
    "/<namespace>/<repo>/pull-request/<int:requestid>/subscribe",</int:requestid></repo></namespace>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 4f5301
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<repo>/pull-request/<int:requestid>/subscribe",</int:requestid></repo></username>
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 4f5301
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/pull-request/<int:requestid>"</int:requestid></repo></namespace></username>
Pierre-Yves Chibon 9c2953
    "/subscribe",
Pierre-Yves Chibon 9c2953
    methods=["POST"],
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@api_login_required(acls=["pull_request_subscribe"])
Pierre-Yves Chibon 4f5301
@api_method
Pierre-Yves Chibon 9c2953
def api_subscribe_pull_request(repo, requestid, username=None, namespace=None):
Pierre-Yves Chibon 4f5301
    """
Pierre-Yves Chibon 4f5301
    Subscribe to an pull-request
Pierre-Yves Chibon 4f5301
    ----------------------------
Pierre-Yves Chibon 4f5301
    Allows someone to subscribe to or unsubscribe from the notifications
Pierre-Yves Chibon 4f5301
    related to a pull-request.
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    ::
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
        POST /api/0/<repo>/pull-request/<request id="">/subscribe</request></repo>
Pierre-Yves Chibon 4f5301
        POST /api/0/<namespace>/<repo>/pull-request/<request id="">/subscribe</request></repo></namespace>
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    ::
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
        POST /api/0/fork/<username>/<repo>/pull-request/<request id="">/subscribe</request></repo></username>
Pierre-Yves Chibon 4f5301
        POST /api/0/fork/<username>/<namespace>/<repo>/pull-request/<request id="">/subscribe</request></repo></namespace></username>
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    Input
Pierre-Yves Chibon 4f5301
    ^^^^^
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    +--------------+----------+---------------+---------------------------+
Pierre-Yves Chibon 4f5301
    | Key          | Type     | Optionality   | Description               |
Pierre-Yves Chibon 4f5301
    +==============+==========+===============+===========================+
Pierre-Yves Chibon 4f5301
    | ``status``   | boolean  | Mandatory     | The intended subscription |
Pierre-Yves Chibon 4f5301
    |              |          |               | status. ``true`` for      |
Pierre-Yves Chibon 4f5301
    |              |          |               | subscribing, ``false``    |
Pierre-Yves Chibon 4f5301
    |              |          |               | for unsubscribing.        |
Pierre-Yves Chibon 4f5301
    +--------------+----------+---------------+---------------------------+
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    Sample response
Pierre-Yves Chibon 4f5301
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    ::
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
        {
Ryan Lerch ccb2e0
          "message": "User subscribed",
Ryan Lerch ccb2e0
          "avatar_url": "https://image.png",
Ryan Lerch ccb2e0
          "user": "pingou"
Pierre-Yves Chibon 4f5301
        }
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    """  # noqa
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    repo = get_authorized_api_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, repo, user=username, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    output = {}
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    if repo is None:
Pierre-Yves Chibon 9c2953
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT)
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 9c2953
    if not repo.settings.get("pull_requests", True):
Pierre-Yves Chibon e99858
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 9c2953
    if (
Pierre-Yves Chibon 9c2953
        api_authenticated()
Pierre-Yves Chibon 9c2953
        and flask.g.token
Pierre-Yves Chibon 9c2953
        and flask.g.token.project
Pierre-Yves Chibon 9c2953
        and repo != flask.g.token.project
Pierre-Yves Chibon 9c2953
    ) or not authenticated():
Pierre-Yves Chibon 9c2953
        raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 930073
    request = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon 9c2953
        flask.g.session, project_id=repo.id, requestid=requestid
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    if not request:
Pierre-Yves Chibon 4f5301
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 5c561c
    form = pagure.forms.SubscribtionForm(csrf_enabled=False)
Pierre-Yves Chibon 4f5301
    if form.validate_on_submit():
Aurélien Bompard 619e2a
        status = is_true(form.status.data)
Pierre-Yves Chibon 4f5301
        try:
Pierre-Yves Chibon 4f5301
            # Toggle subscribtion
Pierre-Yves Chibon 930073
            message = pagure.lib.query.set_watch_obj(
Pierre-Yves Chibon b130e5
                flask.g.session,
Pierre-Yves Chibon 4f5301
                user=flask.g.fas_user.username,
Pierre-Yves Chibon 4f5301
                obj=request,
Pierre-Yves Chibon 9c2953
                watch_status=status,
Pierre-Yves Chibon 4f5301
            )
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon 9c2953
            output["message"] = message
Pierre-Yves Chibon 930073
            user_obj = pagure.lib.query.get_user(
Pierre-Yves Chibon 9c2953
                flask.g.session, flask.g.fas_user.username
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 930073
            output["avatar_url"] = pagure.lib.query.avatar_url_from_email(
Pierre-Yves Chibon 9c2953
                user_obj.default_email, size=30
Pierre-Yves Chibon 9c2953
            )
Pierre-Yves Chibon 9c2953
            output["user"] = flask.g.fas_user.username
Pierre-Yves Chibon 4f5301
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon b130e5
            flask.g.session.rollback()
Pierre-Yves Chibon b130e5
            _log.logger.exception(err)
Pierre-Yves Chibon 4f5301
            raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)
Pierre-Yves Chibon 4f5301
Pierre-Yves Chibon 4f5301
    jsonout = flask.jsonify(output)
Pierre-Yves Chibon 4f5301
    return jsonout
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9c2953
@API.route("/<repo>/pull-request/new", methods=["POST"])</repo>
Pierre-Yves Chibon 9c2953
@API.route("/<namespace>/<repo>/pull-request/new", methods=["POST"])</repo></namespace>
Pierre-Yves Chibon 9c2953
@API.route("/fork/<username>/<repo>/pull-request/new", methods=["POST"])</repo></username>
Pierre-Yves Chibon 9c2953
@API.route(
Pierre-Yves Chibon 9c2953
    "/fork/<username>/<namespace>/<repo>/pull-request/new", methods=["POST"]</repo></namespace></username>
Pierre-Yves Chibon 9c2953
)
Pierre-Yves Chibon 9c2953
@api_login_required(acls=["pull_request_create"])
Pierre-Yves Chibon 9811e6
@api_method
Pierre-Yves Chibon 9811e6
def api_pull_request_create(repo, username=None, namespace=None):
Pierre-Yves Chibon 9811e6
    """
Pierre-Yves Chibon 9811e6
    Create pull-request
Pierre-Yves Chibon 9811e6
    -------------------
Pierre-Yves Chibon 9811e6
    Open a new pull-request from this project to itself or its parent (if
Pierre-Yves Chibon 9811e6
    this project is a fork).
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    ::
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
        POST /api/0/<repo>/pull-request/new</repo>
Pierre-Yves Chibon 9811e6
        POST /api/0/<namespace>/<repo>/pull-request/new</repo></namespace>
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    ::
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
        POST /api/0/fork/<username>/<repo>/pull-request/new</repo></username>
Pierre-Yves Chibon 9811e6
        POST /api/0/fork/<username>/<namespace>/<repo>/pull-request/new</repo></namespace></username>
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    Input
Pierre-Yves Chibon 9811e6
    ^^^^^
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    +--------------------+----------+---------------+----------------------+
Pierre-Yves Chibon 9811e6
    | Key                | Type     | Optionality   | Description          |
Pierre-Yves Chibon 9811e6
    +====================+==========+===============+======================+
Pierre-Yves Chibon 9811e6
    | ``title``          | string   | Mandatory     | The title to give to |
Pierre-Yves Chibon 9811e6
    |                    |          |               | this pull-request    |
Pierre-Yves Chibon 9811e6
    +--------------------+----------+---------------+----------------------+
Pierre-Yves Chibon 9811e6
    | ``branch_to``      | string   | Mandatory     | The name of the      |
Pierre-Yves Chibon 9811e6
    |                    |          |               | branch the submitted |
Pierre-Yves Chibon 9811e6
    |                    |          |               | changes should be    |
Pierre-Yves Chibon 9811e6
    |                    |          |               | merged into.         |
Pierre-Yves Chibon 9811e6
    +--------------------+----------+---------------+----------------------+
Pierre-Yves Chibon 9811e6
    | ``branch_from``    | string   | Mandatory     | The name of the      |
Pierre-Yves Chibon 9811e6
    |                    |          |               | branch containing    |
Pierre-Yves Chibon 9811e6
    |                    |          |               | the changes to merge |
Pierre-Yves Chibon 9811e6
    +--------------------+----------+---------------+----------------------+
Pierre-Yves Chibon 9811e6
    | ``initial_comment``| string   | Optional      | The intial comment   |
Pierre-Yves Chibon 9811e6
    |                    |          |               | describing what these|
Pierre-Yves Chibon 9811e6
    |                    |          |               | changes are about.   |
Pierre-Yves Chibon 9811e6
    +--------------------+----------+---------------+----------------------+
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    Sample response
Pierre-Yves Chibon 9811e6
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    ::
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
        {
Pierre-Yves Chibon 9811e6
          "assignee": null,
Pierre-Yves Chibon 9811e6
          "branch": "master",
Pierre-Yves Chibon 9811e6
          "branch_from": "master",
Pierre-Yves Chibon 9811e6
          "closed_at": null,
Pierre-Yves Chibon 9811e6
          "closed_by": null,
Pierre-Yves Chibon 9811e6
          "comments": [],
Pierre-Yves Chibon 9811e6
          "commit_start": null,
Pierre-Yves Chibon 9811e6
          "commit_stop": null,
Pierre-Yves Chibon 9811e6
          "date_created": "1431414800",
Pierre-Yves Chibon 9811e6
          "id": 1,
Pierre-Yves Chibon 9811e6
          "project": {
Pierre-Yves Chibon 9811e6
            "close_status": [],
Pierre-Yves Chibon 9811e6
            "custom_keys": [],
Pierre-Yves Chibon 9811e6
            "date_created": "1431414800",
Pierre-Yves Chibon 9811e6
            "description": "test project #1",
Pierre-Yves Chibon 9811e6
            "id": 1,
Pierre-Yves Chibon 9811e6
            "name": "test",
Pierre-Yves Chibon 9811e6
            "parent": null,
Pierre-Yves Chibon 9811e6
            "user": {
Pierre-Yves Chibon 9811e6
              "fullname": "PY C",
Pierre-Yves Chibon 9811e6
              "name": "pingou"
Pierre-Yves Chibon 9811e6
            }
Pierre-Yves Chibon 9811e6
          },
Pierre-Yves Chibon 9811e6
          "repo_from": {
Pierre-Yves Chibon 9811e6
            "date_created": "1431414800",
Pierre-Yves Chibon 9811e6
            "description": "test project #1",
Pierre-Yves Chibon 9811e6
            "id": 1,
Pierre-Yves Chibon 9811e6
            "name": "test",
Pierre-Yves Chibon 9811e6
            "parent": null,
Pierre-Yves Chibon 9811e6
            "user": {
Pierre-Yves Chibon 9811e6
              "fullname": "PY C",
Pierre-Yves Chibon 9811e6
              "name": "pingou"
Pierre-Yves Chibon 9811e6
            }
Pierre-Yves Chibon 9811e6
          },
Pierre-Yves Chibon 9811e6
          "status": "Open",
Pierre-Yves Chibon 9811e6
          "title": "test pull-request",
Pierre-Yves Chibon 9811e6
          "uid": "1431414800",
Pierre-Yves Chibon 9811e6
          "updated_on": "1431414800",
Pierre-Yves Chibon 9811e6
          "user": {
Pierre-Yves Chibon 9811e6
            "fullname": "PY C",
Pierre-Yves Chibon 9811e6
            "name": "pingou"
Pierre-Yves Chibon 9811e6
          }
Pierre-Yves Chibon 9811e6
        }
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    """
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    repo = get_authorized_api_project(
Pierre-Yves Chibon 9c2953
        flask.g.session, repo, user=username, namespace=namespace
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    if repo is None:
Pierre-Yves Chibon 9811e6
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT)
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon e99858
    if flask.g.token.project and repo != flask.g.token.project:
Pierre-Yves Chibon 9c2953
        raise pagure.exceptions.APIError(401, error_code=APIERROR.EINVALIDTOK)
Pierre-Yves Chibon e99858
Pierre-Yves Chibon 5c561c
    form = pagure.forms.RequestPullForm(csrf_enabled=False)
Pierre-Yves Chibon 9811e6
    if not form.validate_on_submit():
Pierre-Yves Chibon 9811e6
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            400, error_code=APIERROR.EINVALIDREQ, errors=form.errors
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
    branch_to = get_request_data().get("branch_to")
Pierre-Yves Chibon 9811e6
    if not branch_to:
Pierre-Yves Chibon 9811e6
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            400,
Pierre-Yves Chibon 9c2953
            error_code=APIERROR.EINVALIDREQ,
Pierre-Yves Chibon 9c2953
            errors={"branch_to": ["This field is required."]},
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9c2953
    branch_from = get_request_data().get("branch_from")
Pierre-Yves Chibon 9811e6
    if not branch_from:
Pierre-Yves Chibon 9811e6
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            400,
Pierre-Yves Chibon 9c2953
            error_code=APIERROR.EINVALIDREQ,
Pierre-Yves Chibon 9c2953
            errors={"branch_from": ["This field is required."]},
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    parent = repo
Pierre-Yves Chibon 9811e6
    if repo.parent:
Pierre-Yves Chibon 9811e6
        parent = repo.parent
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9c2953
    if not parent.settings.get("pull_requests", True):
Pierre-Yves Chibon 9811e6
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    repo_committer = pagure.utils.is_repo_committer(repo)
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    if not repo_committer:
Pierre-Yves Chibon 9811e6
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            401, error_code=APIERROR.ENOTHIGHENOUGH
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9811e6
Patrick Uiterwijk 3f97f6
    repo_obj = pygit2.Repository(repo.repopath("main"))
Patrick Uiterwijk 3f97f6
    orig_repo = pygit2.Repository(parent.repopath("main"))
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    try:
Pierre-Yves Chibon 9811e6
        diff, diff_commits, orig_commit = pagure.lib.git.get_diff_info(
Pierre-Yves Chibon 9c2953
            repo_obj, orig_repo, branch_from, branch_to
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9811e6
    except pagure.exceptions.PagureException as err:
Pierre-Yves Chibon 9811e6
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
            400, error_code=APIERROR.EINVALIDREQ, errors=str(err)
Pierre-Yves Chibon 9c2953
        )
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    if parent.settings.get(
Pierre-Yves Chibon 9c2953
        "Enforce_signed-off_commits_in_pull-request", False
Pierre-Yves Chibon 9c2953
    ):
Pierre-Yves Chibon 9811e6
        for commit in diff_commits:
Pierre-Yves Chibon 9c2953
            if "signed-off-by" not in commit.message.lower():
Pierre-Yves Chibon 9811e6
                raise pagure.exceptions.APIError(
Pierre-Yves Chibon 9c2953
                    400, error_code=APIERROR.ENOSIGNEDOFF
Pierre-Yves Chibon 9c2953
                )
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    if orig_commit:
Pierre-Yves Chibon 9811e6
        orig_commit = orig_commit.oid.hex
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    initial_comment = form.initial_comment.data.strip() or None
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    commit_start = commit_stop = None
Pierre-Yves Chibon 9811e6
    if diff_commits:
Pierre-Yves Chibon 9811e6
        commit_stop = diff_commits[0].oid.hex
Pierre-Yves Chibon 9811e6
        commit_start = diff_commits[-1].oid.hex
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 930073
    request = pagure.lib.query.new_pull_request(
Pierre-Yves Chibon 9811e6
        flask.g.session,
Pierre-Yves Chibon 9811e6
        repo_to=parent,
Pierre-Yves Chibon 9811e6
        branch_to=branch_to,
Pierre-Yves Chibon 9811e6
        branch_from=branch_from,
Pierre-Yves Chibon 9811e6
        repo_from=repo,
Pierre-Yves Chibon 9811e6
        title=form.title.data,
Pierre-Yves Chibon 9811e6
        initial_comment=initial_comment,
Pierre-Yves Chibon 9811e6
        user=flask.g.fas_user.username,
Pierre-Yves Chibon 9811e6
        commit_start=commit_start,
Pierre-Yves Chibon 9811e6
        commit_stop=commit_stop,
Pierre-Yves Chibon 9811e6
    )
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    try:
Pierre-Yves Chibon 9811e6
        flask.g.session.commit()
Pierre-Yves Chibon 9811e6
    except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon 9811e6
        flask.g.session.rollback()
Pierre-Yves Chibon 9811e6
        _log.logger.exception(err)
Pierre-Yves Chibon 9811e6
        raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)
Pierre-Yves Chibon 9811e6
Pierre-Yves Chibon 9811e6
    jsonout = flask.jsonify(request.to_json(public=True, api=True))
Pierre-Yves Chibon 9811e6
    return jsonout
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
@API.route("/<repo>/pull-request/<int:requestid>/diffstats")</int:requestid></repo>
Pierre-Yves Chibon c67f41
@API.route("/<namespace>/<repo>/pull-request/<int:requestid>/diffstats")</int:requestid></repo></namespace>
Pierre-Yves Chibon c67f41
@API.route("/fork/<username>/<repo>/pull-request/<int:requestid>/diffstats")</int:requestid></repo></username>
Pierre-Yves Chibon c67f41
@API.route(
Pierre-Yves Chibon c67f41
    "/fork/<username>/<namespace>/<repo>/pull-request/<int:requestid>/"</int:requestid></repo></namespace></username>
Pierre-Yves Chibon c67f41
    "diffstats"
Pierre-Yves Chibon c67f41
)
Pierre-Yves Chibon c67f41
@api_method
Pierre-Yves Chibon c67f41
def api_pull_request_diffstats(repo, requestid, username=None, namespace=None):
Pierre-Yves Chibon c67f41
    """
Pierre-Yves Chibon c67f41
    Pull-request diff statistics
Pierre-Yves Chibon c67f41
    ----------------------------
Pierre-Yves Chibon c67f41
    Retrieve the statistics about the diff of a specific pull request.
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    ::
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
        GET /api/0/<repo>/pull-request/<request id="">/diffstats</request></repo>
Pierre-Yves Chibon c67f41
        GET /api/0/<namespace>/<repo>/pull-request/<request id="">/diffstats</request></repo></namespace>
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    ::
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
        GET /api/0/fork/<username>/<repo>/pull-request/<request id="">/diffstats</request></repo></username>
Pierre-Yves Chibon c67f41
        GET /api/0/fork/<username>/<namespace>/<repo>/pull-request/<request id="">/diffstats</request></repo></namespace></username>
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    Sample response
Pierre-Yves Chibon c67f41
    ^^^^^^^^^^^^^^^
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    ::
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
        {
Pierre-Yves Chibon c67f41
          "README.rst": {
Pierre-Yves Chibon c67f41
            "lines_added": 1,
Pierre-Yves Chibon c67f41
            "lines_removed": 1,
Pierre-Yves Chibon c67f41
            "old_path": "README.rst",
Pierre-Yves Chibon c67f41
            "status": "M"
Pierre-Yves Chibon c67f41
          },
Pierre-Yves Chibon c67f41
          "blame_file.txt": {
Pierre-Yves Chibon c67f41
            "lines_added": 0,
Pierre-Yves Chibon c67f41
            "lines_removed": 0,
Pierre-Yves Chibon c67f41
            "old_path": "blame_file",
Pierre-Yves Chibon c67f41
            "status": "R"
Pierre-Yves Chibon c67f41
          },
Pierre-Yves Chibon c67f41
          "test": {
Pierre-Yves Chibon c67f41
            "lines_added": 0,
Pierre-Yves Chibon c67f41
            "lines_removed": 8,
Pierre-Yves Chibon c67f41
            "old_path": "test",
Pierre-Yves Chibon c67f41
            "status": "D"
Pierre-Yves Chibon c67f41
          },
Pierre-Yves Chibon c67f41
          "test3": {
Pierre-Yves Chibon c67f41
            "lines_added": 3,
Pierre-Yves Chibon c67f41
            "lines_removed": 0,
Pierre-Yves Chibon c67f41
            "old_path": "test3",
Pierre-Yves Chibon c67f41
            "status": "A"
Pierre-Yves Chibon c67f41
          }
Pierre-Yves Chibon c67f41
        }
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    """  # noqa
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    repo = get_authorized_api_project(
Pierre-Yves Chibon c67f41
        flask.g.session, repo, user=username, namespace=namespace
Pierre-Yves Chibon c67f41
    )
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    if repo is None:
Pierre-Yves Chibon c67f41
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOPROJECT)
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    if not repo.settings.get("pull_requests", True):
Pierre-Yves Chibon c67f41
        raise pagure.exceptions.APIError(
Pierre-Yves Chibon c67f41
            404, error_code=APIERROR.EPULLREQUESTSDISABLED
Pierre-Yves Chibon c67f41
        )
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon 930073
    request = pagure.lib.query.search_pull_requests(
Pierre-Yves Chibon c67f41
        flask.g.session, project_id=repo.id, requestid=requestid
Pierre-Yves Chibon c67f41
    )
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    if not request:
Pierre-Yves Chibon c67f41
        raise pagure.exceptions.APIError(404, error_code=APIERROR.ENOREQ)
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    if request.remote:
Pierre-Yves Chibon c67f41
        repopath = pagure.utils.get_remote_repo_path(
Pierre-Yves Chibon c67f41
            request.remote_git, request.branch_from
Pierre-Yves Chibon c67f41
        )
Pierre-Yves Chibon c67f41
        parentpath = pagure.utils.get_repo_path(request.project)
Pierre-Yves Chibon c67f41
    else:
Pierre-Yves Chibon c67f41
        repo_from = request.project_from
Pierre-Yves Chibon c67f41
        parentpath = pagure.utils.get_repo_path(request.project)
Pierre-Yves Chibon c67f41
        repopath = parentpath
Pierre-Yves Chibon c67f41
        if repo_from:
Pierre-Yves Chibon c67f41
            repopath = pagure.utils.get_repo_path(repo_from)
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    repo_obj = pygit2.Repository(repopath)
Pierre-Yves Chibon c67f41
    orig_repo = pygit2.Repository(parentpath)
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    diff_commits = []
Pierre-Yves Chibon c67f41
    diff = None
Pierre-Yves Chibon c67f41
    # Closed pull-request
Pierre-Yves Chibon c67f41
    if request.status != "Open":
Pierre-Yves Chibon c67f41
        commitid = request.commit_stop
Pierre-Yves Chibon c67f41
        try:
Pierre-Yves Chibon c67f41
            for commit in repo_obj.walk(commitid, pygit2.GIT_SORT_NONE):
Pierre-Yves Chibon c67f41
                diff_commits.append(commit)
Pierre-Yves Chibon c67f41
                if commit.oid.hex == request.commit_start:
Pierre-Yves Chibon c67f41
                    break
Pierre-Yves Chibon c67f41
        except KeyError:
Pierre-Yves Chibon c67f41
            # This happens when repo.walk() cannot find commitid
Pierre-Yves Chibon c67f41
            pass
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
        if diff_commits:
Pierre-Yves Chibon c67f41
            # Ensure the first commit in the PR as a parent, otherwise
Pierre-Yves Chibon c67f41
            # point to it
Pierre-Yves Chibon c67f41
            start = diff_commits[-1].oid.hex
Pierre-Yves Chibon c67f41
            if diff_commits[-1].parents:
Pierre-Yves Chibon c67f41
                start = diff_commits[-1].parents[0].oid.hex
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
            # If the start and the end commits are the same, it means we are,
Pierre-Yves Chibon c67f41
            # dealing with one commit that has no parent, so just diff that
Pierre-Yves Chibon c67f41
            # one commit
Pierre-Yves Chibon c67f41
            if start == diff_commits[0].oid.hex:
Pierre-Yves Chibon c67f41
                diff = diff_commits[0].tree.diff_to_tree(swap=True)
Pierre-Yves Chibon c67f41
            else:
Pierre-Yves Chibon c67f41
                diff = repo_obj.diff(
Pierre-Yves Chibon c67f41
                    repo_obj.revparse_single(start),
Pierre-Yves Chibon c67f41
                    repo_obj.revparse_single(diff_commits[0].oid.hex),
Pierre-Yves Chibon c67f41
                )
Pierre-Yves Chibon c67f41
    else:
Pierre-Yves Chibon c67f41
        try:
Pierre-Yves Chibon c67f41
            diff_commits, diff = pagure.lib.git.diff_pull_request(
Pierre-Yves Chibon c67f41
                flask.g.session, request, repo_obj, orig_repo
Pierre-Yves Chibon c67f41
            )
Pierre-Yves Chibon c67f41
        except pagure.exceptions.PagureException as err:
Pierre-Yves Chibon c67f41
            flask.flash("%s" % err, "error")
Pierre-Yves Chibon c67f41
        except SQLAlchemyError as err:  # pragma: no cover
Pierre-Yves Chibon c67f41
            flask.g.session.rollback()
Pierre-Yves Chibon c67f41
            _log.exception(err)
Pierre-Yves Chibon c67f41
            flask.flash(
Pierre-Yves Chibon c67f41
                "Could not update this pull-request in the database", "error"
Pierre-Yves Chibon c67f41
            )
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    if diff:
Pierre-Yves Chibon c67f41
        diff.find_similar()
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    output = {}
Pierre-Yves Chibon c67f41
    if diff:
Pierre-Yves Chibon c67f41
        for patch in diff:
Pierre-Yves Chibon c67f41
            linesadded = patch.line_stats[1]
Pierre-Yves Chibon c67f41
            linesremoved = patch.line_stats[2]
Pierre-Yves Chibon c67f41
            if hasattr(patch, "new_file_path"):
Pierre-Yves Chibon c67f41
                # Older pygit2
Pierre-Yves Chibon c67f41
                status = patch.status
Pierre-Yves Chibon c67f41
                if patch.new_file_path != patch.old_file_path:
Pierre-Yves Chibon c67f41
                    status = "R"
Pierre-Yves Chibon c67f41
                output[patch.new_file_path] = {
Pierre-Yves Chibon c67f41
                    "status": patch.status,
Pierre-Yves Chibon c67f41
                    "old_path": patch.old_file_path,
Pierre-Yves Chibon c67f41
                    "lines_added": linesadded,
Pierre-Yves Chibon c67f41
                    "lines_removed": linesremoved,
Pierre-Yves Chibon c67f41
                }
Pierre-Yves Chibon c67f41
            elif hasattr(patch, "delta"):
Pierre-Yves Chibon c67f41
                # Newer pygit2
Pierre-Yves Chibon c67f41
                if (
Pierre-Yves Chibon c67f41
                    patch.delta.new_file.mode == 0
Pierre-Yves Chibon c67f41
                    and patch.delta.old_file.mode in [33188, 33261]
Pierre-Yves Chibon c67f41
                ):
Pierre-Yves Chibon c67f41
                    status = "D"
Pierre-Yves Chibon c67f41
                elif (
Pierre-Yves Chibon c67f41
                    patch.delta.new_file.mode in [33188, 33261]
Pierre-Yves Chibon c67f41
                    and patch.delta.old_file.mode == 0
Pierre-Yves Chibon c67f41
                ):
Pierre-Yves Chibon c67f41
                    status = "A"
Pierre-Yves Chibon c67f41
                elif patch.delta.new_file.mode in [
Pierre-Yves Chibon c67f41
                    33188,
Pierre-Yves Chibon c67f41
                    33261,
Pierre-Yves Chibon c67f41
                ] and patch.delta.old_file.mode in [33188, 33261]:
Pierre-Yves Chibon c67f41
                    status = "M"
Pierre-Yves Chibon c67f41
                if patch.delta.new_file.path != patch.delta.old_file.path:
Pierre-Yves Chibon c67f41
                    status = "R"
Pierre-Yves Chibon c67f41
                output[patch.delta.new_file.path] = {
Pierre-Yves Chibon c67f41
                    "status": status,
Pierre-Yves Chibon c67f41
                    "old_path": patch.delta.old_file.path,
Pierre-Yves Chibon c67f41
                    "lines_added": linesadded,
Pierre-Yves Chibon c67f41
                    "lines_removed": linesremoved,
Pierre-Yves Chibon c67f41
                }
Pierre-Yves Chibon c67f41
    else:
Pierre-Yves Chibon c67f41
        raise pagure.exceptions.APIError(400, error_code=APIERROR.ENOPRSTATS)
Pierre-Yves Chibon c67f41
Pierre-Yves Chibon c67f41
    jsonout = flask.jsonify(output)
Pierre-Yves Chibon c67f41
    return jsonout