Blame pagure/hooks/pagure_ci.py

Pierre-Yves Chibon aabc84
# -*- coding: utf-8 -*-
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
"""
Pierre-Yves Chibon aabc84
 (c) 2016 - Copyright Red Hat Inc
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
 Authors:
Pierre-Yves Chibon aabc84
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
"""
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon 67d1cc
from __future__ import unicode_literals, absolute_import
Aurélien Bompard dcf6f6
Pierre-Yves Chibon b130e5
import flask
Pierre-Yves Chibon aabc84
import sqlalchemy as sa
Pierre-Yves Chibon aabc84
import wtforms
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon 5a5352
try:
Pierre-Yves Chibon 2011e2
    from flask_wtf import FlaskForm
Pierre-Yves Chibon 2011e2
except ImportError:
Pierre-Yves Chibon 5a5352
    from flask_wtf import Form as FlaskForm
Pierre-Yves Chibon aabc84
from sqlalchemy.orm import relation
Pierre-Yves Chibon aabc84
from sqlalchemy.orm import backref
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon 930073
import pagure.lib.login
Pierre-Yves Chibon 43d465
from pagure.hooks import BaseHook, BaseRunner, RequiredIf
Pierre-Yves Chibon e24815
from pagure.lib.model import BASE, Project
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
class PagureCITable(BASE):
Pierre-Yves Chibon aabc84
    """ Stores information about the CI linked to on a project.
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
    Table -- hook_pagure_ci
Pierre-Yves Chibon aabc84
    """
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon 9c2953
    __tablename__ = "hook_pagure_ci"
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
    id = sa.Column(sa.Integer, primary_key=True)
Pierre-Yves Chibon aabc84
    project_id = sa.Column(
Pierre-Yves Chibon aabc84
        sa.Integer,
Pierre-Yves Chibon 9c2953
        sa.ForeignKey("projects.id", onupdate="CASCADE", ondelete="CASCADE"),
Pierre-Yves Chibon aabc84
        nullable=False,
Pierre-Yves Chibon aabc84
        unique=True,
Pierre-Yves Chibon 9c2953
        index=True,
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon 9c2953
    pagure_ci_token = sa.Column(sa.String(32), nullable=True, index=True)
Pierre-Yves Chibon 9c2953
    ci_type = sa.Column(sa.String(255), nullable=True)
Pierre-Yves Chibon 9c2953
    ci_url = sa.Column(sa.String(255), nullable=True, unique=False)
Pierre-Yves Chibon 9c2953
    ci_job = sa.Column(sa.String(255), nullable=True, unique=False)
Pierre-Yves Chibon 9c6dee
    ci_username = sa.Column(sa.String(255), nullable=True, unique=False)
Pierre-Yves Chibon 9c6dee
    ci_password = sa.Column(sa.String(255), nullable=True, unique=False)
Pierre-Yves Chibon aabc84
    active = sa.Column(sa.Boolean, nullable=False, default=False)
Clement Verna 44c44e
    active_commit = sa.Column(sa.Boolean, nullable=False, default=False)
Clement Verna 44c44e
    active_pr = sa.Column(sa.Boolean, nullable=False, default=False)
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
    project = relation(
Pierre-Yves Chibon 9c2953
        "Project",
Pierre-Yves Chibon 9c2953
        remote_side=[Project.id],
Pierre-Yves Chibon aabc84
        backref=backref(
Pierre-Yves Chibon 9c2953
            "ci_hook",
Pierre-Yves Chibon 9c2953
            cascade="delete, delete-orphan",
Pierre-Yves Chibon 9c2953
            single_parent=True,
Pierre-Yves Chibon 9c2953
            uselist=False,
Pierre-Yves Chibon 9c2953
        ),
Pierre-Yves Chibon aabc84
    )
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon e24815
Pierre-Yves Chibon 43d465
class PagureCIRunner(BaseRunner):
Pierre-Yves Chibon 43d465
    """ Runner for the pagure-ci hook, it does nothing as the magic is part
Pierre-Yves Chibon 43d465
    of the CI system itself (to see if there was a commit made and build if
Pierre-Yves Chibon 43d465
    so).
Pierre-Yves Chibon 43d465
    """
Pierre-Yves Chibon 998b35
Pierre-Yves Chibon 43d465
    pass
Pierre-Yves Chibon 43d465
Pierre-Yves Chibon 43d465
Pierre-Yves Chibon e24815
tmpl = """
Pierre-Yves Chibon c99ccd
{% if repo | hasattr('ci_hook') and repo.ci_hook and
Pierre-Yves Chibon 78837b
    repo.ci_hook.pagure_ci_token %}
Pierre-Yves Chibon 005f5d
Pierre-Yves Chibon 005f5d
The token to be used by jenkins to trigger the build is:
Pierre-Yves Chibon 005f5d
Pierre-Yves Chibon 78837b
{{ repo.ci_hook.pagure_ci_token}}
Pierre-Yves Chibon 005f5d
Pierre-Yves Chibon 005f5d
Pierre-Yves Chibon 005f5d
The URL to be used to POST the results of your build is:
Pierre-Yves Chibon e24815
Pierre-Yves Chibon e24815
{{ (config['APP_URL'][:-1] if config['APP_URL'].endswith('/')
Pierre-Yves Chibon e24815
  else config['APP_URL'])
Pierre-Yves Chibon 78837b
  + url_for('api_ns.%s_ci_notification' % repo.ci_hook.ci_type,
Pierre-Yves Chibon 5c0b16
    repo=repo.name, username=username, namespace=repo.namespace,
Pierre-Yves Chibon 78837b
    pagure_ci_token=repo.ci_hook.pagure_ci_token) }}
Pierre-Yves Chibon e24815
Pierre-Yves Chibon e24815
Pierre-Yves Chibon e24815
{% else %}
Clement Verna 524438
You will have access to the token used by the CI service to trigger the job
Pierre-Yves Chibon 2c9f94
and the URL needed to report back the job status in pagure after the plugin
Pierre-Yves Chibon 2c9f94
activation.
Pierre-Yves Chibon e24815
{% endif %}
Pierre-Yves Chibon e24815
"""
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon 5a5352
class PagureCiForm(FlaskForm):
Pierre-Yves Chibon 9c2953
    """ Form to configure the CI hook. """
Pierre-Yves Chibon 9c2953
Pierre-Yves Chibon e24815
    ci_type = wtforms.SelectField(
Pierre-Yves Chibon 9c2953
        "Type of CI service",
Pierre-Yves Chibon 9c2953
        [RequiredIf(["active_commit", "active_pr"])],
Pierre-Yves Chibon 9c2953
        choices=[],
Pierre-Yves Chibon aabc84
    )
Clement Verna 44c44e
Lenka Segura 643d50
    ci_url = wtforms.StringField(
Pierre-Yves Chibon 9c2953
        "URL to the project on the CI service",
Pierre-Yves Chibon 9c2953
        [
Pierre-Yves Chibon 9c2953
            RequiredIf(["active_commit", "active_pr"]),
Pierre-Yves Chibon 9c2953
            wtforms.validators.Length(max=255),
Pierre-Yves Chibon 9c2953
        ],
Pierre-Yves Chibon aabc84
    )
Clement Verna 5434db
Pierre-Yves Chibon 9c6dee
    ci_username = wtforms.StringField(
Pierre-Yves Chibon 9c6dee
        "Username to authenticate with if needed",
Pierre-Yves Chibon 9c6dee
        [wtforms.validators.Optional(), wtforms.validators.Length(max=255)],
Pierre-Yves Chibon 9c6dee
    )
Pierre-Yves Chibon 9c6dee
Pierre-Yves Chibon 9c6dee
    ci_password = wtforms.StringField(
Pierre-Yves Chibon 9c6dee
        "Password to authenticate with if needed",
Pierre-Yves Chibon 9c6dee
        [wtforms.validators.Optional(), wtforms.validators.Length(max=255)],
Pierre-Yves Chibon 9c6dee
    )
Pierre-Yves Chibon 9c6dee
Lenka Segura 643d50
    ci_job = wtforms.StringField(
Pierre-Yves Chibon 9c2953
        "Name of the job to trigger",
Pierre-Yves Chibon 9c2953
        [
Pierre-Yves Chibon 9c2953
            RequiredIf(["active_commit", "active_pr"]),
Pierre-Yves Chibon 9c2953
            wtforms.validators.Length(max=255),
Pierre-Yves Chibon 9c2953
        ],
Clement Verna 5434db
    )
Clement Verna 44c44e
Clement Verna dd6f03
    # The active field is not render in the UI it used
Clement Verna dd6f03
    # to hold the result of a logical OR between active_pr
Clement Verna dd6f03
    # and active_commit.
Clement Verna dd6f03
    # The value of active is set in pagure.ui.plugins.view_plugin
Pierre-Yves Chibon aabc84
    active = wtforms.BooleanField(
Pierre-Yves Chibon 9c2953
        "Activate Pagure CI service", [wtforms.validators.Optional()]
Clement Verna 44c44e
    )
Clement Verna 44c44e
Clement Verna 44c44e
    active_commit = wtforms.BooleanField(
Pierre-Yves Chibon 9c2953
        "Trigger CI job on commits", [wtforms.validators.Optional()]
Clement Verna 44c44e
    )
Clement Verna 44c44e
Clement Verna 44c44e
    active_pr = wtforms.BooleanField(
Pierre-Yves Chibon 9c2953
        "Trigger CI job on pull-requests", [wtforms.validators.Optional()]
Pierre-Yves Chibon aabc84
    )
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
    def __init__(self, *args, **kwargs):
Pierre-Yves Chibon aabc84
        """ Calls the default constructor with the normal argument but
Pierre-Yves Chibon aabc84
        uses the list of collection provided to fill the choices of the
Pierre-Yves Chibon aabc84
        drop-down list.
Pierre-Yves Chibon aabc84
        """
Pierre-Yves Chibon aabc84
        super(PagureCiForm, self).__init__(*args, **kwargs)
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon 9c2953
        types = pagure.config.config.get("PAGURE_CI_SERVICES", [])
Pierre-Yves Chibon 9c2953
        self.ci_type.choices = [(ci_type, ci_type) for ci_type in types]
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
class PagureCi(BaseHook):
Pierre-Yves Chibon 9c2953
    """ Continuous Integration (CI) hooks. """
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon 9c2953
    name = "Pagure CI"
Pierre-Yves Chibon 9c2953
    description = (
Pierre-Yves Chibon 9c2953
        "Integrate continuous integration (CI) services into your "
Pierre-Yves Chibon 9c2953
        "pagure project, providing you notifications for every pull-request "
Pierre-Yves Chibon 9c2953
        "opened in the project."
Pierre-Yves Chibon 9c2953
    )
Pierre-Yves Chibon e24815
    extra_info = tmpl
Pierre-Yves Chibon aabc84
    form = PagureCiForm
Pierre-Yves Chibon aabc84
    db_object = PagureCITable
Pierre-Yves Chibon 9c2953
    backref = "ci_hook"
Pierre-Yves Chibon 9c2953
    form_fields = ["ci_type", "ci_url", "ci_job", "active_commit", "active_pr"]
Pierre-Yves Chibon 43d465
    runner = PagureCIRunner
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
    @classmethod
Pierre-Yves Chibon aabc84
    def set_up(cls, project):
Pierre-Yves Chibon 9c2953
        """ Install the generic post-receive hook that allow us to call
Pierre-Yves Chibon aabc84
        multiple post-receive hooks as set per plugin.
Pierre-Yves Chibon 9c2953
        """
Pierre-Yves Chibon 8bb53a
        pass
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
    @classmethod
Pierre-Yves Chibon aabc84
    def install(cls, project, dbobj):
Pierre-Yves Chibon 9c2953
        """ Method called to install the hook for a project.
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
        :arg project: a ``pagure.model.Project`` object to which the hook
Pierre-Yves Chibon aabc84
            should be installed
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon 9c2953
        """
Pierre-Yves Chibon 8bb53a
        if not dbobj.pagure_ci_token:
Pierre-Yves Chibon 8bb53a
            dbobj.pagure_ci_token = pagure.lib.login.id_generator(32)
Pierre-Yves Chibon b130e5
            flask.g.session.commit()
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
    @classmethod
Pierre-Yves Chibon aabc84
    def remove(cls, project):
Pierre-Yves Chibon 9c2953
        """ Method called to remove the hook of a project.
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon aabc84
        :arg project: a ``pagure.model.Project`` object to which the hook
Pierre-Yves Chibon aabc84
            should be installed
Pierre-Yves Chibon aabc84
Pierre-Yves Chibon 9c2953
        """
Farhaan Bukhsh 322d8d
        if project.ci_hook is not None:
Pierre-Yves Chibon fc5bca
            project.ci_hook.pagure_ci_token = None
Pierre-Yves Chibon b130e5
            flask.g.session.commit()