Blame tests/__init__.py

Pierre-Yves Chibon 33b534
# -*- coding: utf-8 -*-
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
"""
Pierre-Yves Chibon 517d69
 (c) 2015-2018 - Copyright Red Hat Inc
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
 Authors:
Pierre-Yves Chibon 413073
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
"""
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 67d1cc
from __future__ import unicode_literals, absolute_import
Aurélien Bompard 626417
Aurélien Bompard 626417
import imp
Aurélien Bompard f61bb3
import json
Pierre-Yves Chibon 59df6f
import logging
Pierre-Yves Chibon 59e3b9
import os
Pierre-Yves Chibon 59e3b9
import re
Pierre-Yves Chibon 59e3b9
import resource
Pierre-Yves Chibon 59d644
import shutil
Patrick Uiterwijk 55e7e0
import subprocess
Pierre-Yves Chibon 413073
import sys
Pierre-Yves Chibon c27b0d
import tempfile
Patrick Uiterwijk 114ca2
import time
Pierre-Yves Chibon 59e3b9
import unittest
Aurélien Bompard 619e2a
from io import open, StringIO
Pierre-Yves Chibon 73d120
Pierre-Yves Chibon 59df6f
logging.basicConfig(stream=sys.stderr)
Pierre-Yves Chibon 413073
Aurélien Bompard 626417
from bs4 import BeautifulSoup
Pierre-Yves Chibon a324b4
from contextlib import contextmanager
Pierre-Yves Chibon 413073
from datetime import date
Pierre-Yves Chibon 21f499
from datetime import datetime
Pierre-Yves Chibon 413073
from datetime import timedelta
Pierre-Yves Chibon 413073
from functools import wraps
Aurélien Bompard 626417
from six.moves.urllib.parse import urlparse, parse_qs
Pierre-Yves Chibon 413073
Pierre-Yves Chibon a324b4
import mock
Pierre-Yves Chibon 4e9b76
import pygit2
Aurélien Bompard 00115d
import redis
Aurélien Bompard 626417
import six
Pierre-Yves Chibon 4e9b76
Pierre-Yves Chibon 675b89
from bs4 import BeautifulSoup
Aurélien Bompard 00115d
from celery.app.task import EagerResult
Pierre-Yves Chibon 413073
from sqlalchemy import create_engine
Pierre-Yves Chibon 413073
from sqlalchemy.orm import sessionmaker
Pierre-Yves Chibon 413073
from sqlalchemy.orm import scoped_session
Pierre-Yves Chibon 413073
Aurélien Bompard 626417
if six.PY2:
Aurélien Bompard 626417
    # Always enable performance counting for tests
Pierre-Yves Chibon 73d120
    os.environ["PAGURE_PERFREPO"] = "true"
Aurélien Bompard 626417
Pierre-Yves Chibon 73d120
sys.path.insert(
Pierre-Yves Chibon 73d120
    0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
Pierre-Yves Chibon 73d120
)
Pierre-Yves Chibon 413073
Pierre-Yves Chibon fe5017
import pagure
Pierre-Yves Chibon b130e5
import pagure.api
Patrick Uiterwijk 3f97f6
from pagure.api.ci import jenkins
Pierre-Yves Chibon b130e5
import pagure.flask_app
Pierre-Yves Chibon 6fdafd
import pagure.lib.git
Pierre-Yves Chibon fe5017
import pagure.lib.model
Pierre-Yves Chibon 930073
import pagure.lib.query
Patrick Uiterwijk 4012dc
import pagure.lib.tasks_mirror
Patrick Uiterwijk fcd520
import pagure.perfrepo as perfrepo
Aurélien Bompard e78d79
from pagure.config import config as pagure_config, reload_config
Pierre-Yves Chibon b130e5
from pagure.lib.repo import PagureRepo
Pierre-Yves Chibon 413073
Pierre-Yves Chibon f62635
HERE = os.path.join(os.path.dirname(os.path.abspath(__file__)))
Pierre-Yves Chibon b73de8
LOG = logging.getLogger(__name__)
Pierre-Yves Chibon b130e5
LOG.setLevel(logging.INFO)
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 73d120
PAGLOG = logging.getLogger("pagure")
Pierre-Yves Chibon b73de8
PAGLOG.setLevel(logging.CRITICAL)
Pierre-Yves Chibon b73de8
PAGLOG.handlers = []
Pierre-Yves Chibon b73de8
Pierre-Yves Chibon 73d120
if "PYTHONPATH" not in os.environ:
Pierre-Yves Chibon 73d120
    os.environ["PYTHONPATH"] = os.path.normpath(os.path.join(HERE, "../"))
Patrick Uiterwijk b2cb9c
Patrick Uiterwijk 55e7e0
CONFIG_TEMPLATE = """
Patrick Uiterwijk 55e7e0
GIT_FOLDER = '%(path)s/repos'
Aurélien Bompard e78d79
ENABLE_DOCS = %(enable_docs)s
Aurélien Bompard e78d79
ENABLE_TICKETS = %(enable_tickets)s
Patrick Uiterwijk 55e7e0
REMOTE_GIT_FOLDER = '%(path)s/remotes'
Patrick Uiterwijk 55e7e0
DB_URL = '%(dburl)s'
Patrick Uiterwijk 7b9080
ALLOW_PROJECT_DOWAIT = True
Aurélien Bompard e78d79
PAGURE_CI_SERVICES = ['jenkins']
Aurélien Bompard e78d79
EMAIL_SEND = False
Aurélien Bompard e78d79
TESTING = True
Aurélien Bompard e78d79
GIT_FOLDER = '%(path)s/repos'
Aurélien Bompard e78d79
REQUESTS_FOLDER = '%(path)s/repos/requests'
Aurélien Bompard e78d79
TICKETS_FOLDER = %(tickets_folder)r
Aurélien Bompard e78d79
DOCS_FOLDER = %(docs_folder)r
Patrick Uiterwijk 3f97f6
REPOSPANNER_PSEUDO_FOLDER = '%(path)s/repos/pseudo'
Aurélien Bompard e78d79
ATTACHMENTS_FOLDER = '%(path)s/attachments'
Aurélien Bompard e78d79
BROKER_URL = 'redis+socket://%(global_path)s/broker'
Aurélien Bompard 00115d
CELERY_CONFIG = {
Aurélien Bompard 00115d
    "task_always_eager": True,
Aurélien Bompard 626417
    #"task_eager_propagates": True,
Aurélien Bompard 00115d
}
Patrick Uiterwijk b2cb9c
GIT_AUTH_BACKEND = '%(authbackend)s'
Patrick Uiterwijk b2cb9c
TEST_AUTH_STATUS = '%(path)s/testauth_status.json'
Patrick Uiterwijk 8174a4
REPOBRIDGE_BINARY = '%(repobridge_binary)s'
Patrick Uiterwijk 3f97f6
REPOSPANNER_NEW_REPO = %(repospanner_new_repo)s
Patrick Uiterwijk 3f97f6
REPOSPANNER_NEW_REPO_ADMIN_OVERRIDE = %(repospanner_admin_override)s
Patrick Uiterwijk 3f97f6
REPOSPANNER_NEW_FORK = %(repospanner_new_fork)s
Patrick Uiterwijk 3f97f6
REPOSPANNER_ADMIN_MIGRATION = %(repospanner_admin_migration)s
Patrick Uiterwijk 3f97f6
REPOSPANNER_REGIONS = {
Patrick Uiterwijk 9b2de7
    'default': {'url': 'https://repospanner.localhost.localdomain:%(repospanner_gitport)s',
Patrick Uiterwijk 3f97f6
                'repo_prefix': 'pagure/',
Patrick Uiterwijk d29158
                'hook': None,
Patrick Uiterwijk 3f97f6
                'ca': '%(path)s/repospanner/pki/ca.crt',
Patrick Uiterwijk 3f97f6
                'admin_cert': {'cert': '%(path)s/repospanner/pki/admin.crt',
Patrick Uiterwijk 3f97f6
                               'key': '%(path)s/repospanner/pki/admin.key'},
Patrick Uiterwijk 3f97f6
                'push_cert': {'cert': '%(path)s/repospanner/pki/pagure.crt',
Patrick Uiterwijk 3f97f6
                              'key': '%(path)s/repospanner/pki/pagure.key'}}
Patrick Uiterwijk 3f97f6
}
Patrick Uiterwijk 55e7e0
"""
Aurélien Bompard 00115d
# The Celery docs warn against using task_always_eager:
Aurélien Bompard 00115d
# http://docs.celeryproject.org/en/latest/userguide/testing.html
Aurélien Bompard 00115d
# but that warning is only valid when testing the async nature of the task, not
Aurélien Bompard 00115d
# what the task actually does.
Patrick Uiterwijk 55e7e0
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 73d120
LOG.info("BUILD_ID: %s", os.environ.get("BUILD_ID"))
Pierre-Yves Chibon 413073
Patrick Uiterwijk 114ca2
Karsten Hopp b310af
WAIT_REGEX = re.compile(r"""var _url = '(\/wait\/[a-z0-9-]+\??.*)'""")
Pierre-Yves Chibon 73d120
Pierre-Yves Chibon 73d120
Patrick Uiterwijk 114ca2
def get_wait_target(html):
Patrick Uiterwijk 114ca2
    """ This parses the window.location out of the HTML for the wait page. """
Patrick Uiterwijk 114ca2
    found = WAIT_REGEX.findall(html)
Pierre-Yves Chibon f341aa
    if len(found) == 0:
Patrick Uiterwijk 114ca2
        raise Exception("Not able to get wait target in %s" % html)
Pierre-Yves Chibon f341aa
    return found[-1]
Patrick Uiterwijk 114ca2
Patrick Uiterwijk 114ca2
Pierre-Yves Chibon 517d69
def get_post_target(html):
Pierre-Yves Chibon 675b89
    """ This parses the wait page form to get the POST url. """
Pierre-Yves Chibon 73d120
    soup = BeautifulSoup(html, "html.parser")
Pierre-Yves Chibon 73d120
    form = soup.find(id="waitform")
Pierre-Yves Chibon 675b89
    if not form:
Pierre-Yves Chibon 517d69
        raise Exception("Not able to get the POST url in %s" % html)
Pierre-Yves Chibon 73d120
    return form.get("action")
Pierre-Yves Chibon 517d69
Pierre-Yves Chibon 517d69
Pierre-Yves Chibon 517d69
def get_post_args(html):
Pierre-Yves Chibon 675b89
    """ This parses the wait page for the hidden arguments of the form. """
Pierre-Yves Chibon 73d120
    soup = BeautifulSoup(html, "html.parser")
Pierre-Yves Chibon 517d69
    output = {}
Pierre-Yves Chibon 73d120
    inputs = soup.find_all("input")
Pierre-Yves Chibon 675b89
    if not inputs:
Pierre-Yves Chibon 675b89
        raise Exception("Not able to get the POST arguments in %s" % html)
Pierre-Yves Chibon 675b89
    for inp in inputs:
Pierre-Yves Chibon 73d120
        if inp.get("type") == "hidden":
Pierre-Yves Chibon 73d120
            output[inp.get("name")] = inp.get("value")
Pierre-Yves Chibon 517d69
    return output
Pierre-Yves Chibon 517d69
Pierre-Yves Chibon 517d69
Patrick Uiterwijk 114ca2
def create_maybe_waiter(method, getter):
Patrick Uiterwijk 114ca2
    def maybe_waiter(*args, **kwargs):
Patrick Uiterwijk 114ca2
        """ A wrapper for self.app.get()/.post() that will resolve wait's """
Patrick Uiterwijk 114ca2
        result = method(*args, **kwargs)
Pierre-Yves Chibon 517d69
Pierre-Yves Chibon 517d69
        # Handle the POST wait case
Pierre-Yves Chibon 517d69
        form_url = None
Pierre-Yves Chibon 517d69
        form_args = None
Aurélien Bompard 626417
        try:
Aurélien Bompard 626417
            result_text = result.get_data(as_text=True)
Aurélien Bompard 626417
        except UnicodeDecodeError:
Aurélien Bompard 626417
            return result
Aurélien Bompard 626417
        if 'id="waitform"' in result_text:
Aurélien Bompard 626417
            form_url = get_post_target(result_text)
Aurélien Bompard 626417
            form_args = get_post_args(result_text)
Pierre-Yves Chibon 73d120
            form_args["csrf_token"] = result_text.split(
Pierre-Yves Chibon 73d120
                'name="csrf_token" type="hidden" value="'
Pierre-Yves Chibon 73d120
            )[1].split('">')[0]
Pierre-Yves Chibon 517d69
Patrick Uiterwijk 114ca2
        count = 0
Pierre-Yves Chibon 73d120
        while "We are waiting for your task to finish." in result_text:
Patrick Uiterwijk 114ca2
            # Resolve wait page
Aurélien Bompard 626417
            target_url = get_wait_target(result_text)
Patrick Uiterwijk 114ca2
            if count > 10:
Patrick Uiterwijk 114ca2
                time.sleep(0.5)
Patrick Uiterwijk 114ca2
            else:
Patrick Uiterwijk 114ca2
                time.sleep(0.1)
Patrick Uiterwijk 114ca2
            result = getter(target_url, follow_redirects=True)
Aurélien Bompard 626417
            try:
Aurélien Bompard 626417
                result_text = result.get_data(as_text=True)
Aurélien Bompard 626417
            except UnicodeDecodeError:
Aurélien Bompard 626417
                return result
Patrick Uiterwijk 114ca2
            if count > 50:
Pierre-Yves Chibon 73d120
                raise Exception("Had to wait too long")
Patrick Uiterwijk 114ca2
        else:
Pierre-Yves Chibon 517d69
            if form_url and form_args:
Pierre-Yves Chibon 517d69
                return method(form_url, data=form_args, follow_redirects=True)
Patrick Uiterwijk 114ca2
            return result
Pierre-Yves Chibon 73d120
Patrick Uiterwijk 114ca2
    return maybe_waiter
Patrick Uiterwijk 114ca2
Patrick Uiterwijk 114ca2
Pierre-Yves Chibon 413073
@contextmanager
Patrick Uiterwijk 3d2cb5
def user_set(APP, user, keep_get_user=False):
Pierre-Yves Chibon 413073
    """ Set the provided user as fas_user in the provided application."""
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
    # Hack used to remove the before_request function set by
Pierre-Yves Chibon 413073
    # flask.ext.fas_openid.FAS which otherwise kills our effort to set a
Pierre-Yves Chibon 413073
    # flask.g.fas_user.
Pierre-Yves Chibon 413073
    from flask import appcontext_pushed, g
Pierre-Yves Chibon 73d120
Pierre-Yves Chibon 4ad0bb
    keep = []
Pierre-Yves Chibon 4ad0bb
    for meth in APP.before_request_funcs[None]:
Pierre-Yves Chibon 73d120
        if "flask_fas_openid.FAS" in str(meth):
Pierre-Yves Chibon 4ad0bb
            continue
Pierre-Yves Chibon 4ad0bb
        keep.append(meth)
Pierre-Yves Chibon 4ad0bb
    APP.before_request_funcs[None] = keep
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
    def handler(sender, **kwargs):
Pierre-Yves Chibon 413073
        g.fas_user = user
Pierre-Yves Chibon 73d120
        g.fas_session_id = b"123"
Pierre-Yves Chibon 392277
        g.authenticated = True
Pierre-Yves Chibon 73d120
Patrick Uiterwijk 3d2cb5
    old_get_user = pagure.flask_app._get_user
Patrick Uiterwijk 3d2cb5
    if not keep_get_user:
Patrick Uiterwijk 3d2cb5
        pagure.flask_app._get_user = mock.MagicMock(
Pierre-Yves Chibon 73d120
            return_value=pagure.lib.model.User()
Pierre-Yves Chibon 73d120
        )
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
    with appcontext_pushed.connected_to(handler, APP):
Pierre-Yves Chibon 413073
        yield
Pierre-Yves Chibon 413073
Patrick Uiterwijk 3d2cb5
    pagure.flask_app._get_user = old_get_user
Patrick Uiterwijk 3d2cb5
Slavek Kabrda 7713cf
Aurélien Bompard e78d79
tests_state = {
Pierre-Yves Chibon 73d120
    "path": tempfile.mkdtemp(prefix="pagure-tests-"),
Aurélien Bompard e78d79
    "broker": None,
Aurélien Bompard 00115d
    "broker_client": None,
Aurélien Bompard 00115d
    "results": {},
Aurélien Bompard e78d79
}
Slavek Kabrda 7713cf
Slavek Kabrda 7713cf
Aurélien Bompard e78d79
def _populate_db(session):
Slavek Kabrda 7713cf
    # Create a couple of users
Slavek Kabrda 7713cf
    item = pagure.lib.model.User(
Pierre-Yves Chibon 73d120
        user="pingou",
Pierre-Yves Chibon 73d120
        fullname="PY C",
Pierre-Yves Chibon 73d120
        password=b"foo",
Pierre-Yves Chibon 73d120
        default_email="bar@pingou.com",
Slavek Kabrda 7713cf
    )
Slavek Kabrda 7713cf
    session.add(item)
Pierre-Yves Chibon 73d120
    item = pagure.lib.model.UserEmail(user_id=1, email="bar@pingou.com")
Slavek Kabrda 7713cf
    session.add(item)
Pierre-Yves Chibon 73d120
    item = pagure.lib.model.UserEmail(user_id=1, email="foo@pingou.com")
Slavek Kabrda 7713cf
    session.add(item)
Slavek Kabrda 7713cf
Slavek Kabrda 7713cf
    item = pagure.lib.model.User(
Pierre-Yves Chibon 73d120
        user="foo",
Pierre-Yves Chibon 73d120
        fullname="foo bar",
Pierre-Yves Chibon 73d120
        password=b"foo",
Pierre-Yves Chibon 73d120
        default_email="foo@bar.com",
Slavek Kabrda 7713cf
    )
Slavek Kabrda 7713cf
    session.add(item)
Pierre-Yves Chibon 73d120
    item = pagure.lib.model.UserEmail(user_id=2, email="foo@bar.com")
Slavek Kabrda 7713cf
    session.add(item)
Slavek Kabrda 7713cf
Slavek Kabrda 7713cf
    session.commit()
Slavek Kabrda 7713cf
Slavek Kabrda 7713cf
Aurélien Bompard 00115d
def store_eager_results(*args, **kwargs):
Aurélien Bompard 00115d
    """A wrapper for EagerResult that stores the instance."""
Aurélien Bompard 00115d
    result = EagerResult(*args, **kwargs)
Aurélien Bompard 00115d
    tests_state["results"][result.id] = result
Aurélien Bompard 00115d
    return result
Slavek Kabrda 7713cf
Aurélien Bompard e78d79
Aurélien Bompard e78d79
def setUp():
Aurélien Bompard e78d79
    # In order to save time during local test execution, we create sqlite DB
Aurélien Bompard e78d79
    # file only once and then we populate it and empty it for every test case
Aurélien Bompard e78d79
    # (as opposed to creating DB file for every test case).
Aurélien Bompard e78d79
    session = pagure.lib.model.create_tables(
Pierre-Yves Chibon 73d120
        "sqlite:///%s/db.sqlite" % tests_state["path"],
Pierre-Yves Chibon 73d120
        acls=pagure_config.get("ACLS", {}),
Aurélien Bompard e78d79
    )
Aurélien Bompard e78d79
    tests_state["db_session"] = session
Slavek Kabrda 7713cf
Slavek Kabrda 3cb529
    # Create a broker
Pierre-Yves Chibon 73d120
    broker_url = os.path.join(tests_state["path"], "broker")
Aurélien Bompard e78d79
Aurélien Bompard e78d79
    tests_state["broker"] = broker = subprocess.Popen(
Pierre-Yves Chibon 73d120
        [
Pierre-Yves Chibon 73d120
            "/usr/bin/redis-server",
Pierre-Yves Chibon 73d120
            "--unixsocket",
Pierre-Yves Chibon 73d120
            broker_url,
Pierre-Yves Chibon 73d120
            "--port",
Pierre-Yves Chibon 73d120
            "0",
Pierre-Yves Chibon 73d120
            "--loglevel",
Pierre-Yves Chibon 73d120
            "warning",
Pierre-Yves Chibon 73d120
            "--logfile",
Pierre-Yves Chibon 73d120
            "/dev/null",
Pierre-Yves Chibon 73d120
        ],
Pierre-Yves Chibon 73d120
        stdout=None,
Pierre-Yves Chibon 73d120
        stderr=None,
Pierre-Yves Chibon 73d120
    )
Slavek Kabrda 3cb529
    broker.poll()
Slavek Kabrda 3cb529
    if broker.returncode is not None:
Pierre-Yves Chibon 73d120
        raise Exception("Broker failed to start")
Aurélien Bompard 00115d
    tests_state["broker_client"] = redis.Redis(unix_socket_path=broker_url)
Aurélien Bompard 00115d
Aurélien Bompard 00115d
    # Store the EagerResults to be able to retrieve them later
Pierre-Yves Chibon 73d120
    tests_state["eg_patcher"] = mock.patch("celery.app.task.EagerResult")
Aurélien Bompard 00115d
    eg_mock = tests_state["eg_patcher"].start()
Aurélien Bompard 00115d
    eg_mock.side_effect = store_eager_results
Slavek Kabrda 7713cf
Pierre-Yves Chibon 2d5c52
Slavek Kabrda 3cb529
def tearDown():
Aurélien Bompard e78d79
    tests_state["db_session"].close()
Aurélien Bompard 00115d
    tests_state["eg_patcher"].stop()
Aurélien Bompard e78d79
    broker = tests_state["broker"]
Slavek Kabrda 3cb529
    broker.kill()
Slavek Kabrda 3cb529
    broker.wait()
Aurélien Bompard e78d79
    shutil.rmtree(tests_state["path"])
Pierre-Yves Chibon 59e3b9
Pierre-Yves Chibon 59e3b9
Clement Verna 109c4b
class SimplePagureTest(unittest.TestCase):
Clement Verna 109c4b
    """
Clement Verna 109c4b
    Simple Test class that does not set a broker/worker
Clement Verna 109c4b
    """
Pierre-Yves Chibon 413073
Aurélien Bompard e78d79
    populate_db = True
Aurélien Bompard e78d79
    config_values = {}
Aurélien Bompard e78d79
Pierre-Yves Chibon 73d120
    @mock.patch("pagure.lib.notify.fedmsg_publish", mock.MagicMock())
Pierre-Yves Chibon 73d120
    def __init__(self, method_name="runTest"):
Pierre-Yves Chibon 413073
        """ Constructor. """
Pierre-Yves Chibon 413073
        unittest.TestCase.__init__(self, method_name)
Pierre-Yves Chibon 413073
        self.session = None
Jeremy Cline 20109f
        self.path = None
Pierre-Yves Chibon 3a4d42
        self.gitrepo = None
Pierre-Yves Chibon 619b9a
        self.gitrepos = None
Pierre-Yves Chibon 413073
Patrick Uiterwijk fcd520
    def perfMaxWalks(self, max_walks, max_steps):
Patrick Uiterwijk fcd520
        """ Check that we have not performed too many walks/steps. """
Patrick Uiterwijk fcd520
        num_walks = 0
Patrick Uiterwijk fcd520
        num_steps = 0
Patrick Uiterwijk fcd520
        for reqstat in perfrepo.REQUESTS:
Pierre-Yves Chibon 73d120
            for walk in reqstat["walks"].values():
Patrick Uiterwijk fcd520
                num_walks += 1
Pierre-Yves Chibon 73d120
                num_steps += walk["steps"]
Pierre-Yves Chibon 73d120
        self.assertLessEqual(
Pierre-Yves Chibon 73d120
            num_walks,
Pierre-Yves Chibon 73d120
            max_walks,
Pierre-Yves Chibon 73d120
            "%s git repo walks performed, at most %s allowed"
Pierre-Yves Chibon 73d120
            % (num_walks, max_walks),
Pierre-Yves Chibon 73d120
        )
Pierre-Yves Chibon 73d120
        self.assertLessEqual(
Pierre-Yves Chibon 73d120
            num_steps,
Pierre-Yves Chibon 73d120
            max_steps,
Pierre-Yves Chibon 73d120
            "%s git repo steps performed, at most %s allowed"
Pierre-Yves Chibon 73d120
            % (num_steps, max_steps),
Pierre-Yves Chibon 73d120
        )
Patrick Uiterwijk fcd520
Patrick Uiterwijk fcd520
    def perfReset(self):
Patrick Uiterwijk fcd520
        """ Reset perfrepo stats. """
Patrick Uiterwijk fcd520
        perfrepo.reset_stats()
Patrick Uiterwijk fcd520
        perfrepo.REQUESTS = []
Patrick Uiterwijk fcd520
Clement Verna 109c4b
    def setUp(self):
Patrick Uiterwijk 8a2282
        if self.path:
Patrick Uiterwijk 8a2282
            # This prevents test state leakage.
Patrick Uiterwijk 8a2282
            # This should be None if the previous runs' tearDown didn't finish,
Patrick Uiterwijk 8a2282
            # leaving behind a self.path.
Patrick Uiterwijk 8a2282
            # If we continue in this case, not only did the previous worker and
Patrick Uiterwijk 8a2282
            # redis instances not exit, we also might accidentally use the
Patrick Uiterwijk 8a2282
            # old database connection.
Patrick Uiterwijk 8a2282
            # @pingou, don't delete this again... :)
Pierre-Yves Chibon 73d120
            raise Exception("Previous test failed!")
Patrick Uiterwijk 8a2282
Clement Verna 109c4b
        self.perfReset()
Patrick Uiterwijk fcd520
Pierre-Yves Chibon 73d120
        self.path = tempfile.mkdtemp(prefix="pagure-tests-path-")
Pierre-Yves Chibon 8b2c5c
Pierre-Yves Chibon 73d120
        LOG.debug("Testdir: %s", self.path)
Pierre-Yves Chibon 73d120
        for folder in ["repos", "forks", "releases", "remotes", "attachments"]:
Jeremy Cline 20109f
            os.mkdir(os.path.join(self.path, folder))
Pierre-Yves Chibon 58e731
Pierre-Yves Chibon 73d120
        if hasattr(pagure.lib.query, "REDIS") and pagure.lib.query.REDIS:
Pierre-Yves Chibon 930073
            pagure.lib.query.REDIS.connection_pool.disconnect()
Pierre-Yves Chibon 930073
            pagure.lib.query.REDIS = None
Slavek Kabrda afb8f6
Aurélien Bompard e78d79
        # Database
Aurélien Bompard e78d79
        self._prepare_db()
Patrick Uiterwijk 55e7e0
Patrick Uiterwijk 55e7e0
        # Write a config file
Aurélien Bompard e78d79
        config_values = {
Pierre-Yves Chibon 73d120
            "path": self.path,
Pierre-Yves Chibon 73d120
            "dburl": self.dbpath,
Pierre-Yves Chibon 73d120
            "enable_docs": True,
Pierre-Yves Chibon 73d120
            "docs_folder": "%s/repos/docs" % self.path,
Pierre-Yves Chibon 73d120
            "enable_tickets": True,
Pierre-Yves Chibon 73d120
            "tickets_folder": "%s/repos/tickets" % self.path,
Pierre-Yves Chibon 73d120
            "global_path": tests_state["path"],
Pierre-Yves Chibon 73d120
            "authbackend": "gitolite3",
Pierre-Yves Chibon 73d120
            "repobridge_binary": "/usr/libexec/repobridge",
Pierre-Yves Chibon 73d120
            "repospanner_gitport": str(8443 + sys.version_info.major),
Pierre-Yves Chibon 73d120
            "repospanner_new_repo": "None",
Pierre-Yves Chibon 73d120
            "repospanner_admin_override": "False",
Pierre-Yves Chibon 73d120
            "repospanner_new_fork": "True",
Pierre-Yves Chibon 73d120
            "repospanner_admin_migration": "False",
Aurélien Bompard e78d79
        }
Aurélien Bompard e78d79
        config_values.update(self.config_values)
Pierre-Yves Chibon 30c623
        self.config_values = config_values
Pierre-Yves Chibon 73d120
        config_path = os.path.join(self.path, "config")
Pierre-Yves Chibon 8b2c5c
        if not os.path.exists(config_path):
Pierre-Yves Chibon 73d120
            with open(config_path, "w") as f:
Pierre-Yves Chibon 30c623
                f.write(CONFIG_TEMPLATE % self.config_values)
Aurélien Bompard e78d79
        os.environ["PAGURE_CONFIG"] = config_path
Aurélien Bompard e78d79
        pagure_config.update(reload_config())
Patrick Uiterwijk 55e7e0
Aurélien Bompard 626417
        imp.reload(pagure.lib.tasks)
Pierre-Yves Chibon 893d4f
        imp.reload(pagure.lib.tasks_mirror)
Aurélien Bompard 626417
        imp.reload(pagure.lib.tasks_services)
Pierre-Yves Chibon b130e5
Pierre-Yves Chibon 73d120
        self._app = pagure.flask_app.create_app({"DB_URL": self.dbpath})
Pierre-Yves Chibon b130e5
Slavek Kabrda 3675ce
        self.app = self._app.test_client()
Pierre-Yves Chibon 73d120
        self.gr_patcher = mock.patch("pagure.lib.tasks.get_result")
Aurélien Bompard 00115d
        gr_mock = self.gr_patcher.start()
Aurélien Bompard 00115d
        gr_mock.side_effect = lambda tid: tests_state["results"][tid]
Pierre-Yves Chibon 564e63
Pierre-Yves Chibon b3d8b5
        # Refresh the DB session
Pierre-Yves Chibon b3d8b5
        self.session = pagure.lib.query.create_session(self.dbpath)
Pierre-Yves Chibon b3d8b5
Clement Verna 109c4b
    def tearDown(self):
Aurélien Bompard 00115d
        self.gr_patcher.stop()
Aurélien Bompard e78d79
        self.session.rollback()
Aurélien Bompard e78d79
        self._clear_database()
Pierre-Yves Chibon 7cbc4e
Patrick Uiterwijk 55e7e0
        # Remove testdir
Pierre-Yves Chibon e49b79
        try:
Pierre-Yves Chibon e49b79
            shutil.rmtree(self.path)
Pierre-Yves Chibon e49b79
        except:
Pierre-Yves Chibon e49b79
            # Sometimes there is a race condition that makes deleting the folder
Pierre-Yves Chibon e49b79
            # fail during the first attempt. So just try a second time if that's
Pierre-Yves Chibon e49b79
            # the case.
Pierre-Yves Chibon e49b79
            shutil.rmtree(self.path)
Patrick Uiterwijk 55e7e0
        self.path = None
Patrick Uiterwijk 55e7e0
Slavek Kabrda 3675ce
        del self.app
Slavek Kabrda 3675ce
        del self._app
Slavek Kabrda 3675ce
Aurélien Bompard f61bb3
    def shortDescription(self):
Aurélien Bompard 00115d
        doc = self.__str__() + ": " + self._testMethodDoc
Aurélien Bompard 00115d
        return doc or None
Aurélien Bompard f61bb3
Aurélien Bompard e78d79
    def _prepare_db(self):
Pierre-Yves Chibon 73d120
        self.dbpath = "sqlite:///%s" % os.path.join(
Pierre-Yves Chibon 73d120
            tests_state["path"], "db.sqlite"
Pierre-Yves Chibon 73d120
        )
Aurélien Bompard e78d79
        self.session = tests_state["db_session"]
Aurélien Bompard e78d79
        pagure.lib.model.create_default_status(
Pierre-Yves Chibon 73d120
            self.session, acls=pagure_config.get("ACLS", {})
Pierre-Yves Chibon 73d120
        )
Aurélien Bompard e78d79
        if self.populate_db:
Aurélien Bompard e78d79
            _populate_db(self.session)
Aurélien Bompard e78d79
Aurélien Bompard e78d79
    def _clear_database(self):
Pierre-Yves Chibon 930073
        tables = reversed(pagure.lib.model_base.BASE.metadata.sorted_tables)
Pierre-Yves Chibon 73d120
        if self.dbpath.startswith("postgresql"):
Pierre-Yves Chibon 73d120
            self.session.execute(
Pierre-Yves Chibon 73d120
                "TRUNCATE %s CASCADE" % ", ".join([t.name for t in tables])
Pierre-Yves Chibon 73d120
            )
Pierre-Yves Chibon 73d120
        elif self.dbpath.startswith("sqlite"):
Aurélien Bompard e78d79
            for table in tables:
Aurélien Bompard e78d79
                self.session.execute("DELETE FROM %s" % table.name)
Pierre-Yves Chibon 73d120
        elif self.dbpath.startswith("mysql"):
Aurélien Bompard e78d79
            self.session.execute("SET FOREIGN_KEY_CHECKS = 0")
Aurélien Bompard e78d79
            for table in tables:
Aurélien Bompard e78d79
                self.session.execute("TRUNCATE %s" % table.name)
Aurélien Bompard e78d79
            self.session.execute("SET FOREIGN_KEY_CHECKS = 1")
Aurélien Bompard e78d79
        self.session.commit()
Aurélien Bompard e78d79
Patrick Uiterwijk b2cb9c
    def set_auth_status(self, value):
Patrick Uiterwijk b2cb9c
        """ Set the return value for the test auth """
Pierre-Yves Chibon 73d120
        with open(
Pierre-Yves Chibon 73d120
            os.path.join(self.path, "testauth_status.json"), "w"
Pierre-Yves Chibon 73d120
        ) as statusfile:
Patrick Uiterwijk b2cb9c
            statusfile.write(six.u(json.dumps(value)))
Patrick Uiterwijk b2cb9c
Pierre-Yves Chibon 73d120
    def get_csrf(self, url="/new", output=None):
Pierre-Yves Chibon d596a9
        """Retrieve a CSRF token from given URL."""
Pierre-Yves Chibon a754ea
        if output is None:
Pierre-Yves Chibon a754ea
            output = self.app.get(url)
Pierre-Yves Chibon a754ea
            self.assertEqual(output.status_code, 200)
Pierre-Yves Chibon d596a9
Pierre-Yves Chibon 73d120
        return (
Pierre-Yves Chibon 73d120
            output.get_data(as_text=True)
Pierre-Yves Chibon 73d120
            .split('name="csrf_token" type="hidden" value="')[1]
Pierre-Yves Chibon 73d120
            .split('">')[0]
Pierre-Yves Chibon 73d120
        )
Pierre-Yves Chibon d596a9
Pierre-Yves Chibon 3e9b1d
    def get_wtforms_version(self):
Pierre-Yves Chibon 3e9b1d
        """Returns the wtforms version as a tuple."""
Pierre-Yves Chibon 3e9b1d
        import wtforms
Pierre-Yves Chibon 73d120
Pierre-Yves Chibon 73d120
        wtforms_v = wtforms.__version__.split(".")
Pierre-Yves Chibon 3e9b1d
        for idx, val in enumerate(wtforms_v):
Pierre-Yves Chibon 3e9b1d
            try:
Pierre-Yves Chibon 3e9b1d
                val = int(val)
Pierre-Yves Chibon 3e9b1d
            except ValueError:
Pierre-Yves Chibon 3e9b1d
                pass
Pierre-Yves Chibon 3e9b1d
            wtforms_v[idx] = val
Pierre-Yves Chibon 3e9b1d
        return tuple(wtforms_v)
Pierre-Yves Chibon 3e9b1d
Aurélien Bompard f61bb3
    def assertURLEqual(self, url_1, url_2):
Aurélien Bompard f61bb3
        url_parsed_1 = list(urlparse(url_1))
Aurélien Bompard f61bb3
        url_parsed_1[4] = parse_qs(url_parsed_1[4])
Aurélien Bompard f61bb3
        url_parsed_2 = list(urlparse(url_2))
Aurélien Bompard f61bb3
        url_parsed_2[4] = parse_qs(url_parsed_2[4])
Aurélien Bompard f61bb3
        return self.assertListEqual(url_parsed_1, url_parsed_2)
Aurélien Bompard f61bb3
Aurélien Bompard f61bb3
    def assertJSONEqual(self, json_1, json_2):
Aurélien Bompard f61bb3
        return self.assertEqual(json.loads(json_1), json.loads(json_2))
Aurélien Bompard f61bb3
Pierre-Yves Chibon b130e5
Clement Verna 109c4b
class Modeltests(SimplePagureTest):
Clement Verna 109c4b
    """ Model tests. """
Clement Verna 109c4b
Pierre-Yves Chibon 73d120
    def setUp(self):  # pylint: disable=invalid-name
Clement Verna 109c4b
        """ Set up the environnment, ran before every tests. """
Clement Verna 109c4b
        # Clean up test performance info
Clement Verna 109c4b
        super(Modeltests, self).setUp()
Clement Verna 109c4b
        self.app.get = create_maybe_waiter(self.app.get, self.app.get)
Clement Verna 109c4b
        self.app.post = create_maybe_waiter(self.app.post, self.app.get)
Clement Verna 109c4b
Pierre-Yves Chibon 19ab90
        # Refresh the DB session
Pierre-Yves Chibon 19ab90
        self.session = pagure.lib.query.create_session(self.dbpath)
Pierre-Yves Chibon 19ab90
Pierre-Yves Chibon 73d120
    def tearDown(self):  # pylint: disable=invalid-name
Clement Verna 109c4b
        """ Remove the test.db database if there is one. """
Aurélien Bompard 00115d
        tests_state["broker_client"].flushall()
Aurélien Bompard e78d79
        super(Modeltests, self).tearDown()
Clement Verna 109c4b
Patrick Uiterwijk 390193
    def create_project_full(self, projectname, extra=None):
Patrick Uiterwijk b2cb9c
        """ Create a project via the API.
Patrick Uiterwijk b2cb9c
Patrick Uiterwijk b2cb9c
        This makes sure that the repo is fully setup the way a normal new
Patrick Uiterwijk b2cb9c
        project would be, with hooks and all setup.
Patrick Uiterwijk b2cb9c
        """
Patrick Uiterwijk b2cb9c
Pierre-Yves Chibon 73d120
        headers = {"Authorization": "token aaabbbcccddd"}
Pierre-Yves Chibon 73d120
        data = {"name": projectname, "description": "A test repo"}
Patrick Uiterwijk 390193
        if extra:
Patrick Uiterwijk 390193
            data.update(extra)
Patrick Uiterwijk b2cb9c
Patrick Uiterwijk b2cb9c
        # Valid request
Pierre-Yves Chibon 73d120
        output = self.app.post("/api/0/new/", data=data, headers=headers)
Patrick Uiterwijk b2cb9c
        self.assertEqual(output.status_code, 200)
Patrick Uiterwijk b2cb9c
        data = json.loads(output.get_data(as_text=True))
Patrick Uiterwijk b2cb9c
        self.assertDictEqual(
Pierre-Yves Chibon 73d120
            data, {"message": 'Project "%s" created' % projectname}
Patrick Uiterwijk b2cb9c
        )
Patrick Uiterwijk b2cb9c
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 73d120
class FakeGroup(object):  # pylint: disable=too-few-public-methods
Pierre-Yves Chibon 413073
    """ Fake object used to make the FakeUser object closer to the
Pierre-Yves Chibon 413073
    expectations.
Pierre-Yves Chibon 413073
    """
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
    def __init__(self, name):
Pierre-Yves Chibon 413073
        """ Constructor.
Pierre-Yves Chibon 413073
        :arg name: the name given to the name attribute of this object.
Pierre-Yves Chibon 413073
        """
Pierre-Yves Chibon 413073
        self.name = name
Pierre-Yves Chibon 73d120
        self.group_type = "cla"
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 73d120
class FakeUser(object):  # pylint: disable=too-few-public-methods
Pierre-Yves Chibon 413073
    """ Fake user used to test the fedocallib library. """
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 73d120
    def __init__(
Pierre-Yves Chibon 73d120
        self, groups=None, username="username", cla_done=True, id=None
Pierre-Yves Chibon 73d120
    ):
Pierre-Yves Chibon 413073
        """ Constructor.
Pierre-Yves Chibon 413073
        :arg groups: list of the groups in which this fake user is
Pierre-Yves Chibon 413073
            supposed to be.
Pierre-Yves Chibon 413073
        """
Aurélien Bompard 626417
        if isinstance(groups, six.string_types):
Pierre-Yves Chibon 413073
            groups = [groups]
Pierre-Yves Chibon ad2b94
        self.id = id
Pierre-Yves Chibon a71ef5
        self.groups = groups or []
Pierre-Yves Chibon ad2b94
        self.user = username
Pierre-Yves Chibon 413073
        self.username = username
Pierre-Yves Chibon 413073
        self.name = username
Pierre-Yves Chibon 73d120
        self.email = "foo@bar.com"
Pierre-Yves Chibon 73d120
        self.default_email = "foo@bar.com"
Ryan Lerch 5682fd
Pierre-Yves Chibon 413073
        self.approved_memberships = [
Pierre-Yves Chibon 73d120
            FakeGroup("packager"),
Pierre-Yves Chibon 73d120
            FakeGroup("design-team"),
Pierre-Yves Chibon 413073
        ]
Pierre-Yves Chibon 413073
        self.dic = {}
Pierre-Yves Chibon 73d120
        self.dic["timezone"] = "Europe/Paris"
Pierre-Yves Chibon 9fe7c1
        self.login_time = datetime.utcnow()
Pierre-Yves Chibon 413073
        self.cla_done = cla_done
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
    def __getitem__(self, key):
Pierre-Yves Chibon 413073
        return self.dic[key]
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
Patrick Uiterwijk 3f97f6
def create_locks(session, project):
Pierre-Yves Chibon 73d120
    for ltype in ("WORKER", "WORKER_TICKET", "WORKER_REQUEST"):
Patrick Uiterwijk 3f97f6
        lock = pagure.lib.model.ProjectLock(
Pierre-Yves Chibon 73d120
            project_id=project.id, lock_type=ltype
Pierre-Yves Chibon 73d120
        )
Patrick Uiterwijk 3f97f6
        session.add(lock)
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
Pierre-Yves Chibon 73d120
def create_projects(session, is_fork=False, user_id=1, hook_token_suffix=""):
Pierre-Yves Chibon 413073
    """ Create some projects in the database. """
Pierre-Yves Chibon fe5017
    item = pagure.lib.model.Project(
Pierre-Yves Chibon 11d019
        user_id=user_id,  # pingou
Pierre-Yves Chibon 73d120
        name="test",
Pierre-Yves Chibon 11d019
        is_fork=is_fork,
Pierre-Yves Chibon 11d019
        parent_id=1 if is_fork else None,
Pierre-Yves Chibon 73d120
        description="test project #1",
Pierre-Yves Chibon 73d120
        hook_token="aaabbbccc" + hook_token_suffix,
Pierre-Yves Chibon 413073
    )
Pierre-Yves Chibon 73d120
    item.close_status = ["Invalid", "Insufficient data", "Fixed", "Duplicate"]
Pierre-Yves Chibon 413073
    session.add(item)
Patrick Uiterwijk 3f97f6
    session.flush()
Patrick Uiterwijk 3f97f6
    create_locks(session, item)
Pierre-Yves Chibon 413073
Pierre-Yves Chibon fe5017
    item = pagure.lib.model.Project(
Pierre-Yves Chibon 11d019
        user_id=user_id,  # pingou
Pierre-Yves Chibon 73d120
        name="test2",
Pierre-Yves Chibon 11d019
        is_fork=is_fork,
Pierre-Yves Chibon 11d019
        parent_id=2 if is_fork else None,
Pierre-Yves Chibon 73d120
        description="test project #2",
Pierre-Yves Chibon 73d120
        hook_token="aaabbbddd" + hook_token_suffix,
Pierre-Yves Chibon 413073
    )
Pierre-Yves Chibon 73d120
    item.close_status = ["Invalid", "Insufficient data", "Fixed", "Duplicate"]
Pierre-Yves Chibon 413073
    session.add(item)
Pierre-Yves Chibon 930073
    session.flush()
Pierre-Yves Chibon 930073
    create_locks(session, item)
Pierre-Yves Chibon 413073
clime afed57
    item = pagure.lib.model.Project(
Pierre-Yves Chibon 11d019
        user_id=user_id,  # pingou
Pierre-Yves Chibon 73d120
        name="test3",
Pierre-Yves Chibon 11d019
        is_fork=is_fork,
Pierre-Yves Chibon 11d019
        parent_id=3 if is_fork else None,
Pierre-Yves Chibon 73d120
        description="namespaced test project",
Pierre-Yves Chibon 73d120
        hook_token="aaabbbeee" + hook_token_suffix,
Pierre-Yves Chibon 73d120
        namespace="somenamespace",
clime afed57
    )
Pierre-Yves Chibon 73d120
    item.close_status = ["Invalid", "Insufficient data", "Fixed", "Duplicate"]
clime afed57
    session.add(item)
Pierre-Yves Chibon 930073
    session.flush()
Pierre-Yves Chibon 930073
    create_locks(session, item)
Pierre-Yves Chibon 413073
    session.commit()
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 05b648
def create_projects_git(folder, bare=False):
Pierre-Yves Chibon 4e9b76
    """ Create some projects in the database. """
Pierre-Yves Chibon 4e9b76
    repos = []
Pierre-Yves Chibon 73d120
    for project in [
Pierre-Yves Chibon 73d120
        "test.git",
Pierre-Yves Chibon 73d120
        "test2.git",
Pierre-Yves Chibon 73d120
        os.path.join("somenamespace", "test3.git"),
Pierre-Yves Chibon 73d120
    ]:
Pierre-Yves Chibon 4e9b76
        repo_path = os.path.join(folder, project)
Pierre-Yves Chibon 4e9b76
        repos.append(repo_path)
Pierre-Yves Chibon 63d161
        if not os.path.exists(repo_path):
Pierre-Yves Chibon 63d161
            os.makedirs(repo_path)
Pierre-Yves Chibon 05b648
        pygit2.init_repository(repo_path, bare=bare)
Pierre-Yves Chibon 4e9b76
    return repos
Pierre-Yves Chibon 4e9b76
Pierre-Yves Chibon 4e9b76
Pierre-Yves Chibon a14636
def create_tokens(session, user_id=1, project_id=1):
Pierre-Yves Chibon c0b635
    """ Create some tokens for the project in the database. """
Pierre-Yves Chibon c0b635
    item = pagure.lib.model.Token(
Pierre-Yves Chibon 73d120
        id="aaabbbcccddd",
Pierre-Yves Chibon c0b635
        user_id=user_id,
Pierre-Yves Chibon a14636
        project_id=project_id,
Pierre-Yves Chibon 73d120
        expiration=datetime.utcnow() + timedelta(days=30),
Pierre-Yves Chibon c0b635
    )
Pierre-Yves Chibon c0b635
    session.add(item)
Pierre-Yves Chibon c0b635
Pierre-Yves Chibon c0b635
    item = pagure.lib.model.Token(
Pierre-Yves Chibon 73d120
        id="foo_token",
Pierre-Yves Chibon c0b635
        user_id=user_id,
Pierre-Yves Chibon a14636
        project_id=project_id,
Pierre-Yves Chibon 73d120
        expiration=datetime.utcnow() + timedelta(days=30),
Pierre-Yves Chibon c0b635
    )
Pierre-Yves Chibon c0b635
    session.add(item)
Pierre-Yves Chibon c0b635
Pierre-Yves Chibon c0b635
    item = pagure.lib.model.Token(
Pierre-Yves Chibon 73d120
        id="expired_token",
Pierre-Yves Chibon c0b635
        user_id=user_id,
Pierre-Yves Chibon a14636
        project_id=project_id,
Pierre-Yves Chibon 73d120
        expiration=datetime.utcnow() - timedelta(days=1),
Pierre-Yves Chibon c0b635
    )
Pierre-Yves Chibon c0b635
    session.add(item)
Pierre-Yves Chibon c0b635
    session.commit()
Pierre-Yves Chibon c0b635
Pierre-Yves Chibon c0b635
Pierre-Yves Chibon 73d120
def create_tokens_acl(session, token_id="aaabbbcccddd", acl_name=None):
Matt Prahl 30f8b1
    """ Create some ACLs for the token. If acl_name is not set, the token will
Matt Prahl 30f8b1
    have all the ACLs enabled.
Matt Prahl 30f8b1
    """
Matt Prahl 30f8b1
    if acl_name is None:
Pierre-Yves Chibon 73d120
        for aclid in range(len(pagure_config["ACLS"])):
Matt Prahl 30f8b1
            token_acl = pagure.lib.model.TokenAcl(
Pierre-Yves Chibon 73d120
                token_id=token_id, acl_id=aclid + 1
Matt Prahl 30f8b1
            )
Matt Prahl 30f8b1
            session.add(token_acl)
Matt Prahl 30f8b1
    else:
Pierre-Yves Chibon 73d120
        acl = (
Pierre-Yves Chibon 73d120
            session.query(pagure.lib.model.ACL).filter_by(name=acl_name).one()
Pierre-Yves Chibon 955beb
        )
Pierre-Yves Chibon 73d120
        token_acl = pagure.lib.model.TokenAcl(token_id=token_id, acl_id=acl.id)
Matt Prahl 30f8b1
        session.add(token_acl)
Pierre-Yves Chibon 955beb
Pierre-Yves Chibon 955beb
    session.commit()
Pierre-Yves Chibon 955beb
Pierre-Yves Chibon 955beb
Pierre-Yves Chibon 8a76fa
def _clone_and_top_commits(folder, branch, branch_ref=False):
Pierre-Yves Chibon 8a76fa
    """ Clone the repository, checkout the specified branch and return
Pierre-Yves Chibon 8a76fa
    the top commit of that branch if there is one.
Pierre-Yves Chibon 8a76fa
    Returns the repo, the path to the clone and the top commit(s) in a tuple
Pierre-Yves Chibon 8a76fa
    or the repo, the path to the clone and the reference to the branch
Pierre-Yves Chibon 8a76fa
    object if branch_ref is True.
Pierre-Yves Chibon 8a76fa
    """
Pierre-Yves Chibon f0ad75
    if not os.path.exists(folder):
Pierre-Yves Chibon f0ad75
        os.makedirs(folder)
Pierre-Yves Chibon 128dfb
    brepo = pygit2.init_repository(folder, bare=True)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 73d120
    newfolder = tempfile.mkdtemp(prefix="pagure-tests")
Pierre-Yves Chibon 128dfb
    repo = pygit2.clone_repository(folder, newfolder)
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon 6fdafd
    branch_ref_obj = None
Pierre-Yves Chibon 6fdafd
    if "origin/%s" % branch in repo.listall_branches(pygit2.GIT_BRANCH_ALL):
Pierre-Yves Chibon 6fdafd
        branch_ref_obj = pagure.lib.git.get_branch_ref(repo, branch)
Pierre-Yves Chibon 6fdafd
        repo.checkout(branch_ref_obj)
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon 8a76fa
    if branch_ref:
Pierre-Yves Chibon 8a76fa
        return (repo, newfolder, branch_ref_obj)
Pierre-Yves Chibon 8a76fa
Pierre-Yves Chibon a71c8d
    parents = []
Pierre-Yves Chibon a71c8d
    commit = None
Pierre-Yves Chibon a71c8d
    try:
Pierre-Yves Chibon 6fdafd
        if branch_ref_obj:
Pierre-Yves Chibon 29ff0a
            commit = repo[branch_ref_obj.peel().hex]
Pierre-Yves Chibon 6fdafd
        else:
Pierre-Yves Chibon 73d120
            commit = repo.revparse_single("HEAD")
Pierre-Yves Chibon a71c8d
    except KeyError:
Pierre-Yves Chibon a71c8d
        pass
Pierre-Yves Chibon a71c8d
    if commit:
Pierre-Yves Chibon a71c8d
        parents = [commit.oid.hex]
Pierre-Yves Chibon a71c8d
Pierre-Yves Chibon 8a76fa
    return (repo, newfolder, parents)
Pierre-Yves Chibon 8a76fa
Pierre-Yves Chibon 8a76fa
Pierre-Yves Chibon 73d120
def add_content_git_repo(folder, branch="master", append=None):
Pierre-Yves Chibon 8a76fa
    """ Create some content for the specified git repo. """
Pierre-Yves Chibon 8a76fa
    repo, newfolder, parents = _clone_and_top_commits(folder, branch)
Pierre-Yves Chibon 8a76fa
Pierre-Yves Chibon 6fdafd
    # Create a file in that git repo
Pierre-Yves Chibon 73d120
    filename = os.path.join(newfolder, "sources")
Pierre-Yves Chibon 73d120
    content = "foo\n bar"
Pierre-Yves Chibon 6fdafd
    if os.path.exists(filename):
Pierre-Yves Chibon 73d120
        content = "foo\n bar\nbaz"
Pierre-Yves Chibon 6fdafd
    if append:
Pierre-Yves Chibon 6fdafd
        content += append
Pierre-Yves Chibon 73d120
    with open(filename, "w") as stream:
Pierre-Yves Chibon 6fdafd
        stream.write(content)
Pierre-Yves Chibon 73d120
    repo.index.add("sources")
Pierre-Yves Chibon 6fdafd
    repo.index.write()
Pierre-Yves Chibon 6fdafd
Pierre-Yves Chibon f0ad75
    # Commits the files added
Pierre-Yves Chibon f0ad75
    tree = repo.index.write_tree()
Pierre-Yves Chibon 73d120
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 6fdafd
    commit = repo.create_commit(
Pierre-Yves Chibon 73d120
        "refs/heads/%s" % branch,  # the name of the reference to update
Pierre-Yves Chibon f0ad75
        author,
Pierre-Yves Chibon f0ad75
        committer,
Pierre-Yves Chibon 73d120
        "Add sources file for testing",
Pierre-Yves Chibon f0ad75
        # binary string representing the tree object ID
Pierre-Yves Chibon f0ad75
        tree,
Pierre-Yves Chibon f0ad75
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon a71c8d
        parents,
Pierre-Yves Chibon f0ad75
    )
Pierre-Yves Chibon a71c8d
Pierre-Yves Chibon a71c8d
    if commit:
Pierre-Yves Chibon 6fdafd
        parents = [commit.hex]
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon 73d120
    subfolder = os.path.join("folder1", "folder2")
Pierre-Yves Chibon 128dfb
    if not os.path.exists(os.path.join(newfolder, subfolder)):
Pierre-Yves Chibon 128dfb
        os.makedirs(os.path.join(newfolder, subfolder))
Pierre-Yves Chibon f0ad75
    # Create a file in that git repo
Pierre-Yves Chibon 73d120
    with open(os.path.join(newfolder, subfolder, "file"), "w") as stream:
Pierre-Yves Chibon 73d120
        stream.write("foo\n bar\nbaz")
Pierre-Yves Chibon 73d120
    repo.index.add(os.path.join(subfolder, "file"))
Pierre-Yves Chibon 73d120
    with open(os.path.join(newfolder, subfolder, "fileŠ"), "w") as stream:
Pierre-Yves Chibon 73d120
        stream.write("foo\n bar\nbaz")
Pierre-Yves Chibon 73d120
    repo.index.add(os.path.join(subfolder, "fileŠ"))
Pierre-Yves Chibon f0ad75
    repo.index.write()
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon f0ad75
    # Commits the files added
Pierre-Yves Chibon f0ad75
    tree = repo.index.write_tree()
Pierre-Yves Chibon 73d120
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 73d120
    commit = repo.create_commit(
Pierre-Yves Chibon 73d120
        "refs/heads/%s" % branch,  # the name of the reference to update
Pierre-Yves Chibon f0ad75
        author,
Pierre-Yves Chibon f0ad75
        committer,
Pierre-Yves Chibon 73d120
        "Add some directory and a file for more testing",
Pierre-Yves Chibon f0ad75
        # binary string representing the tree object ID
Pierre-Yves Chibon f0ad75
        tree,
Pierre-Yves Chibon f0ad75
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 73d120
        parents,
Pierre-Yves Chibon f0ad75
    )
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon 128dfb
    # Push to origin
Pierre-Yves Chibon 128dfb
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 62e16b
    master_ref = repo.lookup_reference(
Pierre-Yves Chibon 73d120
        "HEAD" if branch == "master" else "refs/heads/%s" % branch
Pierre-Yves Chibon 73d120
    ).resolve()
Pierre-Yves Chibon 73d120
    refname = "%s:%s" % (master_ref.name, master_ref.name)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 27a73d
    PagureRepo.push(ori_remote, refname)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 128dfb
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon 73d120
def add_readme_git_repo(folder, readme_name="README.rst", branch="master"):
Pierre-Yves Chibon 87ffe2
    """ Create a README file for the specified git repo. """
Pierre-Yves Chibon 8a76fa
    repo, newfolder, parents = _clone_and_top_commits(folder, branch)
Pierre-Yves Chibon 6fdafd
Pierre-Yves Chibon 73d120
    if readme_name == "README.rst":
Karsten Hopp 5192eb
        content = """Pagure
Pierre-Yves Chibon 87ffe2
======
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
:Author: Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon fe5017
Pagure is a light-weight git-centered forge based on pygit2.
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon fe5017
Currently, Pagure offers a web-interface for git repositories, a ticket
Pierre-Yves Chibon fe5017
system and possibilities to create new projects, fork existing ones and
Pierre-Yves Chibon fe5017
create/merge pull-requests across or within projects.
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon fe5017
Homepage: https://github.com/pypingou/pagure
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
Dev instance: http://209.132.184.222/ (/!\\ May change unexpectedly, it's a dev instance ;-))
Pierre-Yves Chibon 87ffe2
"""
Karsten Hopp 5192eb
    else:
Pierre-Yves Chibon 73d120
        content = (
Pierre-Yves Chibon 73d120
            """Pagure
Karsten Hopp 5192eb
======
Karsten Hopp 5192eb
Pierre-Yves Chibon 73d120
This is a placeholder """
Pierre-Yves Chibon 73d120
            + readme_name
Pierre-Yves Chibon 73d120
            + """
Karsten Hopp 5192eb
that should never get displayed on the website if there is a README.rst in the repo.
Karsten Hopp 5192eb
"""
Pierre-Yves Chibon 73d120
        )
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
    # Create a file in that git repo
Pierre-Yves Chibon 73d120
    with open(os.path.join(newfolder, readme_name), "w") as stream:
Pierre-Yves Chibon 87ffe2
        stream.write(content)
Karsten Hopp 5192eb
    repo.index.add(readme_name)
Pierre-Yves Chibon 87ffe2
    repo.index.write()
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
    # Commits the files added
Pierre-Yves Chibon 87ffe2
    tree = repo.index.write_tree()
Pierre-Yves Chibon 73d120
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 6fdafd
    branch_ref = "refs/heads/%s" % branch
Pierre-Yves Chibon 87ffe2
    repo.create_commit(
Pierre-Yves Chibon 6fdafd
        branch_ref,  # the name of the reference to update
Pierre-Yves Chibon 87ffe2
        author,
Pierre-Yves Chibon 87ffe2
        committer,
Pierre-Yves Chibon 73d120
        "Add a README file",
Pierre-Yves Chibon 87ffe2
        # binary string representing the tree object ID
Pierre-Yves Chibon 87ffe2
        tree,
Pierre-Yves Chibon 87ffe2
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 73d120
        parents,
Pierre-Yves Chibon 87ffe2
    )
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 128dfb
    # Push to origin
Pierre-Yves Chibon 128dfb
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 73d120
    PagureRepo.push(ori_remote, "%s:%s" % (branch_ref, branch_ref))
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 128dfb
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 73d120
def add_commit_git_repo(
Pierre-Yves Chibon 73d120
    folder, ncommits=10, filename="sources", branch="master", symlink_to=None
Pierre-Yves Chibon 73d120
):
Pierre-Yves Chibon 595b4e
    """ Create some more commits for the specified git repo. """
Pierre-Yves Chibon 8a76fa
    repo, newfolder, branch_ref_obj = _clone_and_top_commits(
Pierre-Yves Chibon 73d120
        folder, branch, branch_ref=True
Pierre-Yves Chibon 73d120
    )
Pierre-Yves Chibon 6fdafd
Pierre-Yves Chibon 595b4e
    for index in range(ncommits):
Pierre-Yves Chibon 595b4e
        # Create a file in that git repo
Slavek Kabrda dade63
        if symlink_to:
Pierre-Yves Chibon 73d120
            os.symlink(symlink_to, os.path.join(newfolder, filename))
Slavek Kabrda dade63
        else:
Pierre-Yves Chibon 73d120
            with open(os.path.join(newfolder, filename), "a") as stream:
Pierre-Yves Chibon 73d120
                stream.write("Row %s\n" % index)
Pierre-Yves Chibon a48463
        repo.index.add(filename)
Pierre-Yves Chibon 595b4e
        repo.index.write()
Pierre-Yves Chibon 595b4e
Pierre-Yves Chibon 595b4e
        parents = []
Pierre-Yves Chibon 595b4e
        commit = None
Pierre-Yves Chibon 595b4e
        try:
Pierre-Yves Chibon 6fdafd
            if branch_ref_obj:
Pierre-Yves Chibon 29ff0a
                commit = repo[branch_ref_obj.peel().hex]
Pierre-Yves Chibon 6fdafd
            else:
Pierre-Yves Chibon 73d120
                commit = repo.revparse_single("HEAD")
Pierre-Yves Chibon 6fdafd
        except (KeyError, AttributeError):
Pierre-Yves Chibon 595b4e
            pass
Pierre-Yves Chibon 595b4e
        if commit:
Pierre-Yves Chibon 595b4e
            parents = [commit.oid.hex]
Pierre-Yves Chibon 595b4e
Pierre-Yves Chibon 595b4e
        # Commits the files added
Pierre-Yves Chibon 595b4e
        tree = repo.index.write_tree()
Pierre-Yves Chibon 73d120
        author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
        committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 6fdafd
        branch_ref = "refs/heads/%s" % branch
Pierre-Yves Chibon 595b4e
        repo.create_commit(
Pierre-Yves Chibon 6fdafd
            branch_ref,
Pierre-Yves Chibon 595b4e
            author,
Pierre-Yves Chibon 595b4e
            committer,
Pierre-Yves Chibon 73d120
            "Add row %s to %s file" % (index, filename),
Pierre-Yves Chibon 595b4e
            # binary string representing the tree object ID
Pierre-Yves Chibon 595b4e
            tree,
Pierre-Yves Chibon 595b4e
            # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 595b4e
            parents,
Pierre-Yves Chibon 595b4e
        )
Pierre-Yves Chibon 6fdafd
        branch_ref_obj = pagure.lib.git.get_branch_ref(repo, branch)
Pierre-Yves Chibon 595b4e
Pierre-Yves Chibon 128dfb
    # Push to origin
Pierre-Yves Chibon 128dfb
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 73d120
    PagureRepo.push(ori_remote, "%s:%s" % (branch_ref, branch_ref))
Pierre-Yves Chibon 1cd41d
Pierre-Yves Chibon 1cd41d
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 1cd41d
Pierre-Yves Chibon 1cd41d
Slavek Kabrda be430b
def add_tag_git_repo(folder, tagname, obj_hash, message):
Slavek Kabrda be430b
    """ Add a tag to the given object of the given repo annotated by given message. """
Slavek Kabrda be430b
    repo, newfolder, branch_ref_obj = _clone_and_top_commits(
Pierre-Yves Chibon 73d120
        folder, "master", branch_ref=True
Pierre-Yves Chibon 73d120
    )
Slavek Kabrda be430b
Slavek Kabrda be430b
    tag_sha = repo.create_tag(
Slavek Kabrda be430b
        tagname,
Slavek Kabrda be430b
        obj_hash,
Slavek Kabrda be430b
        repo.get(obj_hash).type,
Pierre-Yves Chibon 73d120
        pygit2.Signature("Alice Author", "alice@authors.tld"),
Slavek Kabrda be430b
        message,
Slavek Kabrda be430b
    )
Slavek Kabrda be430b
Slavek Kabrda be430b
    # Push to origin
Slavek Kabrda be430b
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 73d120
    PagureRepo.push(
Pierre-Yves Chibon 73d120
        ori_remote, "refs/tags/%s:refs/tags/%s" % (tagname, tagname)
Pierre-Yves Chibon 73d120
    )
Slavek Kabrda be430b
Slavek Kabrda be430b
    shutil.rmtree(newfolder)
Slavek Kabrda be430b
    return tag_sha
Slavek Kabrda be430b
Slavek Kabrda be430b
Pierre-Yves Chibon ec5e38
def add_content_to_git(
Julen Landa Alustiza c95aa4
    folder,
Julen Landa Alustiza c95aa4
    branch="master",
Julen Landa Alustiza c95aa4
    filename="sources",
Julen Landa Alustiza c95aa4
    content="foo",
Julen Landa Alustiza c95aa4
    message=None,
Julen Landa Alustiza c95aa4
    author=("Alice Author", "alice@authors.tld"),
Julen Landa Alustiza c95aa4
    commiter=("Cecil Committer", "cecil@committers.tld"),
Pierre-Yves Chibon 73d120
):
Pierre-Yves Chibon 1cd41d
    """ Create some more commits for the specified git repo. """
Pierre-Yves Chibon ec5e38
    repo, newfolder, branch_ref_obj = _clone_and_top_commits(
Pierre-Yves Chibon 73d120
        folder, branch, branch_ref=True
Pierre-Yves Chibon 73d120
    )
Pierre-Yves Chibon 1cd41d
Pierre-Yves Chibon 1cd41d
    # Create a file in that git repo
Pierre-Yves Chibon 73d120
    with open(
Pierre-Yves Chibon 73d120
        os.path.join(newfolder, filename), "a", encoding="utf-8"
Pierre-Yves Chibon 73d120
    ) as stream:
Pierre-Yves Chibon 73d120
        stream.write("%s\n" % content)
Pierre-Yves Chibon 1cd41d
    repo.index.add(filename)
Pierre-Yves Chibon 1cd41d
    repo.index.write()
Pierre-Yves Chibon 1cd41d
Pierre-Yves Chibon ec5e38
    parents = []
Pierre-Yves Chibon ec5e38
    commit = None
Pierre-Yves Chibon ec5e38
    try:
Pierre-Yves Chibon ec5e38
        if branch_ref_obj:
Pierre-Yves Chibon 29ff0a
            commit = repo[branch_ref_obj.peel().hex]
Pierre-Yves Chibon ec5e38
        else:
Pierre-Yves Chibon 73d120
            commit = repo.revparse_single("HEAD")
Pierre-Yves Chibon ec5e38
    except (KeyError, AttributeError):
Pierre-Yves Chibon ec5e38
        pass
Pierre-Yves Chibon ec5e38
    if commit:
Pierre-Yves Chibon ec5e38
        parents = [commit.oid.hex]
Pierre-Yves Chibon ec5e38
Pierre-Yves Chibon 1cd41d
    # Commits the files added
Pierre-Yves Chibon 1cd41d
    tree = repo.index.write_tree()
Julen Landa Alustiza c95aa4
    author = pygit2.Signature(*author)
Julen Landa Alustiza c95aa4
    committer = pygit2.Signature(*commiter)
Pierre-Yves Chibon ec5e38
    branch_ref = "refs/heads/%s" % branch
Pierre-Yves Chibon 73d120
    message = message or "Add content to file %s" % (filename)
Pierre-Yves Chibon 1cd41d
    repo.create_commit(
Pierre-Yves Chibon ec5e38
        branch_ref,  # the name of the reference to update
Pierre-Yves Chibon 1cd41d
        author,
Pierre-Yves Chibon 1cd41d
        committer,
Pierre-Yves Chibon 722f04
        message,
Pierre-Yves Chibon 1cd41d
        # binary string representing the tree object ID
Pierre-Yves Chibon 1cd41d
        tree,
Pierre-Yves Chibon 1cd41d
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 1cd41d
        parents,
Pierre-Yves Chibon 1cd41d
    )
Pierre-Yves Chibon 1cd41d
Pierre-Yves Chibon 1cd41d
    # Push to origin
Pierre-Yves Chibon 1cd41d
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 73d120
    PagureRepo.push(ori_remote, "%s:%s" % (branch_ref, branch_ref))
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 128dfb
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 595b4e
Pierre-Yves Chibon 6e857b
def add_binary_git_repo(folder, filename):
Pierre-Yves Chibon 6e857b
    """ Create a fake image file for the specified git repo. """
Pierre-Yves Chibon 73d120
    repo, newfolder, parents = _clone_and_top_commits(folder, "master")
Pierre-Yves Chibon 6e857b
Pierre-Yves Chibon 945241
    content = b"""\x00\x00\x01\x00\x01\x00\x18\x18\x00\x00\x01\x00 \x00\x88
Pierre-Yves Chibon 945241
\t\x00\x00\x16\x00\x00\x00(\x00\x00\x00\x18\x00x00\x00\x01\x00 \x00\x00\x00
Pierre-Yves Chibon 945241
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
Pierre-Yves Chibon 945241
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7lM\x01\xa6kM\t\xa6kM\x01
Pierre-Yves Chibon 945241
\xa4fF\x04\xa2dE\x95\xa2cD8\xa1a
Pierre-Yves Chibon 6e857b
"""
Pierre-Yves Chibon 6e857b
Pierre-Yves Chibon 6e857b
    # Create a file in that git repo
Pierre-Yves Chibon 73d120
    with open(os.path.join(newfolder, filename), "wb") as stream:
Pierre-Yves Chibon 6e857b
        stream.write(content)
Pierre-Yves Chibon 6e857b
    repo.index.add(filename)
Pierre-Yves Chibon 6e857b
    repo.index.write()
Pierre-Yves Chibon 6e857b
Pierre-Yves Chibon 6e857b
    # Commits the files added
Pierre-Yves Chibon 6e857b
    tree = repo.index.write_tree()
Pierre-Yves Chibon 73d120
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 6e857b
    repo.create_commit(
Pierre-Yves Chibon 73d120
        "refs/heads/master",  # the name of the reference to update
Pierre-Yves Chibon 6e857b
        author,
Pierre-Yves Chibon 6e857b
        committer,
Pierre-Yves Chibon 73d120
        "Add a fake image file",
Pierre-Yves Chibon 6e857b
        # binary string representing the tree object ID
Pierre-Yves Chibon 6e857b
        tree,
Pierre-Yves Chibon 6e857b
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 73d120
        parents,
Pierre-Yves Chibon 6e857b
    )
Pierre-Yves Chibon 6e857b
Pierre-Yves Chibon 128dfb
    # Push to origin
Pierre-Yves Chibon 128dfb
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 73d120
    master_ref = repo.lookup_reference("HEAD").resolve()
Pierre-Yves Chibon 73d120
    refname = "%s:%s" % (master_ref.name, master_ref.name)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 27a73d
    PagureRepo.push(ori_remote, refname)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 128dfb
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 652aff
Pierre-Yves Chibon 73d120
def remove_file_git_repo(folder, filename, branch="master"):
Pierre-Yves Chibon 3470e1
    """ Delete the specified file on the give git repo and branch. """
Pierre-Yves Chibon 8a76fa
    repo, newfolder, parents = _clone_and_top_commits(folder, branch)
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 3470e1
    # Remove file
Pierre-Yves Chibon 3470e1
    repo.index.remove(filename)
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 3470e1
    # Write the change and commit it
Pierre-Yves Chibon 3470e1
    tree = repo.index.write_tree()
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 73d120
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 3470e1
    branch_ref = "refs/heads/%s" % branch
Pierre-Yves Chibon 3470e1
    repo.create_commit(
Pierre-Yves Chibon 3470e1
        branch_ref,  # the name of the reference to update
Pierre-Yves Chibon 3470e1
        author,
Pierre-Yves Chibon 3470e1
        committer,
Pierre-Yves Chibon 73d120
        "Remove file %s" % filename,
Pierre-Yves Chibon 3470e1
        # binary string representing the tree object ID
Pierre-Yves Chibon 3470e1
        tree,
Pierre-Yves Chibon 3470e1
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 73d120
        parents,
Pierre-Yves Chibon 3470e1
    )
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 3470e1
    # Push to origin
Pierre-Yves Chibon 3470e1
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 73d120
    PagureRepo.push(ori_remote, "%s:%s" % (branch_ref, branch_ref))
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 3470e1
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 3470e1
Aurélien Bompard a29742
@contextmanager
Aurélien Bompard a29742
def capture_output(merge_stderr=True):
Aurélien Bompard a29742
    oldout, olderr = sys.stdout, sys.stderr
Aurélien Bompard a29742
    try:
Aurélien Bompard a29742
        out = StringIO()
Aurélien Bompard a29742
        err = StringIO()
Aurélien Bompard a29742
        if merge_stderr:
Aurélien Bompard a29742
            sys.stdout = sys.stderr = out
Aurélien Bompard a29742
            yield out
Aurélien Bompard a29742
        else:
Aurélien Bompard a29742
            sys.stdout, sys.stderr = out, err
Aurélien Bompard a29742
            yield out, err
Aurélien Bompard a29742
    finally:
Aurélien Bompard a29742
        sys.stdout, sys.stderr = oldout, olderr
Aurélien Bompard a29742
Aurélien Bompard a29742
Aurélien Bompard 626417
def get_alerts(html):
Aurélien Bompard 626417
    soup = BeautifulSoup(html, "html.parser")
Aurélien Bompard 626417
    alerts = []
Aurélien Bompard 626417
    for element in soup.find_all("div", class_="alert"):
Aurélien Bompard 626417
        severity = None
Aurélien Bompard 626417
        for class_ in element["class"]:
Aurélien Bompard 626417
            if not class_.startswith("alert-"):
Aurélien Bompard 626417
                continue
Aurélien Bompard 626417
            if class_ == "alert-dismissible":
Aurélien Bompard 626417
                continue
Pierre-Yves Chibon 73d120
            severity = class_[len("alert-") :]
Aurélien Bompard 626417
            break
Aurélien Bompard 626417
        element.find("button").decompose()  # close button
Pierre-Yves Chibon 73d120
        alerts.append(
Pierre-Yves Chibon 73d120
            dict(severity=severity, text="".join(element.stripped_strings))
Pierre-Yves Chibon 73d120
        )
Aurélien Bompard 626417
    return alerts
Aurélien Bompard 626417
Aurélien Bompard 626417
Patrick Uiterwijk 3f97f6
def definitely_wait(result):
Patrick Uiterwijk 3f97f6
    """ Helper function for definitely waiting in _maybe_wait. """
Patrick Uiterwijk 3f97f6
    result.wait()
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
Pierre-Yves Chibon 73d120
if __name__ == "__main__":
Pierre-Yves Chibon 413073
    SUITE = unittest.TestLoader().loadTestsFromTestCase(Modeltests)
Pierre-Yves Chibon 413073
    unittest.TextTestRunner(verbosity=2).run(SUITE)