From 44c44e6c246d20c6a9af88c5ef2ab6b3826624d1 Mon Sep 17 00:00:00 2001 From: Clement Verna Date: Mar 26 2018 06:43:14 +0000 Subject: [PATCH 1/4] Initial support for commit CI trigger This commit adds the support for trigger a CI job on direct commit. Signed-off-by: Clement Verna --- diff --git a/alembic/versions/eab41ce5f92a_add_active_commit_attribute_to_the_hook_.py b/alembic/versions/eab41ce5f92a_add_active_commit_attribute_to_the_hook_.py new file mode 100644 index 0000000..69a970a --- /dev/null +++ b/alembic/versions/eab41ce5f92a_add_active_commit_attribute_to_the_hook_.py @@ -0,0 +1,32 @@ +"""add active_commit attribute to the hook_pagure_ci table + +Revision ID: eab41ce5f92a +Revises: e18d5b78d782 +Create Date: 2018-03-21 13:37:24.117434 + +""" + +# revision identifiers, used by Alembic. +revision = 'eab41ce5f92a' +down_revision = 'e18d5b78d782' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + ''' Add active_commit column to hook_pagure_ci table''' + op.add_column( + 'hook_pagure_ci', + sa.Column('active_commit', sa.Boolean, nullable=True, default=False) + ) + op.add_column( + 'hook_pagure_ci', + sa.Column('active_pr', sa.Boolean, nullable=True, default=False) + ) + + +def downgrade(): + ''' Revert the active_commit column added''' + op.drop_column('hook_pagure_ci', 'active_commit') + op.drop_column('hook_pagure_ci', 'active_pr') \ No newline at end of file diff --git a/pagure/hooks/files/default_hook.py b/pagure/hooks/files/default_hook.py index 984471f..4694560 100644 --- a/pagure/hooks/files/default_hook.py +++ b/pagure/hooks/files/default_hook.py @@ -116,6 +116,17 @@ def send_notifications(session, project, refname, revs, forced): _log.exception( 'Error sending web-hook notifications on commit push') + if _config.get('PAGURE_CI_SERVICES') \ + and project.ci_hook \ + and project.ci_hook.active_commit \ + and not project.private: + pagure.lib.tasks_services.trigger_ci_build.delay( + project_name=project.fullname, + cause=revs[-1], + branch=refname, + ci_type=project.ci_hook.ci_type + ) + def inform_pull_request_urls( session, project, commits, refname, default_branch): diff --git a/pagure/hooks/pagure_ci.py b/pagure/hooks/pagure_ci.py index 1d61e3a..691b1f8 100644 --- a/pagure/hooks/pagure_ci.py +++ b/pagure/hooks/pagure_ci.py @@ -55,6 +55,8 @@ class PagureCITable(BASE): nullable=True, unique=False) active = sa.Column(sa.Boolean, nullable=False, default=False) + active_commit = sa.Column(sa.Boolean, nullable=False, default=False) + active_pr = sa.Column(sa.Boolean, nullable=False, default=False) project = relation( 'Project', remote_side=[Project.id], @@ -97,6 +99,7 @@ class PagureCiForm(FlaskForm): [RequiredIf('active')], choices=[] ) + ci_url = wtforms.TextField( 'URL to the project on the CI service', [RequiredIf('active'), wtforms.validators.Length(max=255)], @@ -106,8 +109,19 @@ class PagureCiForm(FlaskForm): 'Name of the job to trigger', [RequiredIf('active'), wtforms.validators.Length(max=255)], ) + active = wtforms.BooleanField( - 'Active', + 'Activate Pagure CI service', + [wtforms.validators.Optional()] + ) + + active_commit = wtforms.BooleanField( + 'Trigger CI job on commits', + [wtforms.validators.Optional()] + ) + + active_pr = wtforms.BooleanField( + 'Trigger CI job on pull-requests', [wtforms.validators.Optional()] ) @@ -135,7 +149,8 @@ class PagureCi(BaseHook): form = PagureCiForm db_object = PagureCITable backref = 'ci_hook' - form_fields = ['ci_type', 'ci_url', 'ci_job', 'active'] + form_fields = ['ci_type', 'ci_url', 'ci_job', 'active_commit', 'active_pr', + 'active'] @classmethod def set_up(cls, project): diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index f4e0877..382fa29 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -1257,10 +1257,11 @@ def add_pull_request_comment(session, request, commit, tree_id, filename, and request.status == 'Open' \ and pagure_config.get('PAGURE_CI_SERVICES') \ and request.project.ci_hook \ + and request.project.ci_hook.active_pr \ and not request.project.private: pagure.lib.tasks_services.trigger_ci_build.delay( project_name=request.project_from.fullname, - pr_id=request.id, + cause=request.id, branch=request.branch_from, ci_type=request.project.ci_hook.ci_type ) @@ -1278,10 +1279,11 @@ def add_pull_request_comment(session, request, commit, tree_id, filename, if trigger_ci \ and comment.strip().lower() in trigger_ci \ and pagure_config.get('PAGURE_CI_SERVICES') \ - and request.project.ci_hook: + and request.project.ci_hook \ + and request.project.ci_hook.active_pr: pagure.lib.tasks_services.trigger_ci_build.delay( project_name=request.project_from.fullname, - pr_id=request.id, + cause=request.id, branch=request.branch_from, ci_type=request.project.ci_hook.ci_type ) @@ -1757,10 +1759,11 @@ def new_pull_request(session, branch_from, # Send notification to the CI server if pagure_config.get('PAGURE_CI_SERVICES') \ and request.project.ci_hook \ + and request.project.ci_hook.active_pr \ and not request.project.private: pagure.lib.tasks_services.trigger_ci_build.delay( project_name=request.project_from.fullname, - pr_id=request.id, + cause=request.id, branch=request.branch_from, ci_type=request.project.ci_hook.ci_type ) diff --git a/pagure/lib/lib_ci.py b/pagure/lib/lib_ci.py index eda1dc7..32b4688 100644 --- a/pagure/lib/lib_ci.py +++ b/pagure/lib/lib_ci.py @@ -84,7 +84,7 @@ def process_jenkins_build(session, project, build_id, requestfolder): session.commit() -def trigger_jenkins_build(project_path, url, job, token, branch, pr_id): +def trigger_jenkins_build(project_path, url, job, token, branch, cause): """ Trigger a build on a jenkins instance.""" try: import jenkins @@ -100,7 +100,7 @@ def trigger_jenkins_build(project_path, url, job, token, branch, pr_id): project_path) data = { - 'cause': pr_id, + 'cause': cause, 'REPO': repo, 'BRANCH': branch } diff --git a/pagure/lib/tasks_services.py b/pagure/lib/tasks_services.py index 9248661..e666432 100644 --- a/pagure/lib/tasks_services.py +++ b/pagure/lib/tasks_services.py @@ -333,7 +333,7 @@ def load_json_commits_to_db( @conn.task(queue=pagure_config.get('CI_CELERY_QUEUE', None), bind=True) @pagure_task -def trigger_ci_build(self, session, project_name, pr_id, branch, ci_type): +def trigger_ci_build(self, session, project_name, cause, branch, ci_type): ''' Triggers a new run of the CI system on the specified pull-request. @@ -357,8 +357,8 @@ def trigger_ci_build(self, session, project_name, pr_id, branch, ci_type): _log.info('Pagure-CI: project retrieved: %s', project.fullname) _log.info( - "Pagure-CI: Trigger from %s PR #%s branch: %s", - project.fullname, pr_id, branch) + "Pagure-CI: Trigger from %s cause (PR# or commit) %s branch: %s", + project.fullname, cause, branch) if ci_type == 'jenkins': @@ -376,7 +376,7 @@ def trigger_ci_build(self, session, project_name, pr_id, branch, ci_type): job=job, token=token, branch=branch, - pr_id=pr_id) + cause=cause) else: _log.warning('Pagure-CI:Un-supported CI type') From 8e958609c5edee10221c509e577ccf87ffb0176b Mon Sep 17 00:00:00 2001 From: Clement Verna Date: Mar 26 2018 06:43:14 +0000 Subject: [PATCH 2/4] Activate the CI hook with either commit or pr Signed-off-by: Clement Verna --- diff --git a/pagure/hooks/pagure_ci.py b/pagure/hooks/pagure_ci.py index 691b1f8..ecf15de 100644 --- a/pagure/hooks/pagure_ci.py +++ b/pagure/hooks/pagure_ci.py @@ -149,8 +149,7 @@ class PagureCi(BaseHook): form = PagureCiForm db_object = PagureCITable backref = 'ci_hook' - form_fields = ['ci_type', 'ci_url', 'ci_job', 'active_commit', 'active_pr', - 'active'] + form_fields = ['ci_type', 'ci_url', 'ci_job', 'active_commit', 'active_pr'] @classmethod def set_up(cls, project): diff --git a/pagure/ui/plugins.py b/pagure/ui/plugins.py index bc0207a..656e125 100644 --- a/pagure/ui/plugins.py +++ b/pagure/ui/plugins.py @@ -132,6 +132,12 @@ def view_plugin(repo, plugin, username=None, namespace=None, full=True): form=form, fields=fields) + # Compute the ci_hook active value in function + # of the active PR and active commit values. + if form.active_pr and form.active_commit: + if form.active_pr.data or form.active_commit.data: + form.active.data = True + if form.active.data: # Set up the main script if necessary plugin.set_up(repo) From 926cddf95ff84f5ad1177bd4079b8aff2998b913 Mon Sep 17 00:00:00 2001 From: Clement Verna Date: Mar 26 2018 06:43:14 +0000 Subject: [PATCH 3/4] Update the unit tests Signed-off-by: Clement Verna --- diff --git a/pagure/hooks/pagure_ci.py b/pagure/hooks/pagure_ci.py index ecf15de..29d1a2a 100644 --- a/pagure/hooks/pagure_ci.py +++ b/pagure/hooks/pagure_ci.py @@ -102,12 +102,14 @@ class PagureCiForm(FlaskForm): ci_url = wtforms.TextField( 'URL to the project on the CI service', - [RequiredIf('active'), wtforms.validators.Length(max=255)], + [RequiredIf(['active_commit', 'active_pr']), + wtforms.validators.Length(max=255)], ) ci_job = wtforms.TextField( 'Name of the job to trigger', - [RequiredIf('active'), wtforms.validators.Length(max=255)], + [RequiredIf(['active_commit', 'active_pr']), + wtforms.validators.Length(max=255)], ) active = wtforms.BooleanField( diff --git a/tests/test_pagure_flask_ui_plugins_pagure_ci.py b/tests/test_pagure_flask_ui_plugins_pagure_ci.py index c628be1..6314f97 100644 --- a/tests/test_pagure_flask_ui_plugins_pagure_ci.py +++ b/tests/test_pagure_flask_ui_plugins_pagure_ci.py @@ -34,8 +34,11 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest): '', output.data) self.assertIn( - '', output.data) + '', output.data) + self.assertIn( + '', output.data) csrf_token = output.data.split( 'name="csrf_token" type="hidden" value="')[1].split('">')[0] @@ -55,12 +58,15 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest): '', output.data) self.assertIn( - '', output.data) + '', output.data) + self.assertIn( + '', output.data) # Activate hook data = { - 'active': 'y', + 'active_commit': 'y', 'ci_url': 'https://jenkins.fedoraproject.org', 'ci_type': 'jenkins', 'ci_job': 'test/job' @@ -80,8 +86,11 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest): '', output.data) self.assertIn( - '', output.data) + '', output.data) + self.assertIn( + '', output.data) data['csrf_token'] = csrf_token @@ -112,8 +121,8 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest): '', output.data) self.assertIn( - '', output.data) + '', output.data) self.assertIn( '
\nhttps://pagure.org/api/0/ci/jenkins/test/',
                 output.data)
@@ -145,11 +154,11 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest):
                 '', output.data)
             self.assertIn(
-                '', output.data)
+                '', output.data)
 
             # Missing the required ci_url
-            data = {'csrf_token': csrf_token, 'active': 'y'}
+            data = {'csrf_token': csrf_token, 'active_commit': 'y'}
 
             output = self.app.post(
                 '/test/settings/Pagure CI', data=data, follow_redirects=True)
@@ -169,8 +178,8 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest):
                 '\nThis field is required.',
                 output.data)
             self.assertIn(
-                '', output.data)
+                '', output.data)
 
     def test_plugin_pagure_ci_namespaced(self):
         """ Test the pagure ci plugin on/off endpoint. """
@@ -193,7 +202,7 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest):
                 '', output.data)
             self.assertIn(
-                '', output.data)
 
             csrf_token = output.data.split(
@@ -201,7 +210,7 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest):
 
             # Activate hook
             data = {
-                'active': 'y',
+                'active_pr': 'y',
                 'ci_url': 'https://jenkins.fedoraproject.org',
                 'ci_job': 'test/job',
                 'ci_type': 'jenkins',
@@ -235,7 +244,7 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest):
                 '', output.data)
             self.assertTrue(
-                '' in output.data)
             self.assertIn(
                 '
\nhttps://pagure.org/api/0/ci/jenkins/somenamespace/test3/',

From dd6f039b2f02dfba76e793a66ce741c31f8a1c8d Mon Sep 17 00:00:00 2001
From: Clement Verna 
Date: Mar 26 2018 06:43:14 +0000
Subject: [PATCH 4/4] Update documentation and DB update


Use the current value of the active CI hook
to update the active_pr value.
Also add documentation for new PR/Commit activation
option.

Signed-off-by: Clement Verna 

---

diff --git a/alembic/versions/eab41ce5f92a_add_active_commit_attribute_to_the_hook_.py b/alembic/versions/eab41ce5f92a_add_active_commit_attribute_to_the_hook_.py
index 69a970a..373642c 100644
--- a/alembic/versions/eab41ce5f92a_add_active_commit_attribute_to_the_hook_.py
+++ b/alembic/versions/eab41ce5f92a_add_active_commit_attribute_to_the_hook_.py
@@ -24,9 +24,19 @@ def upgrade():
         'hook_pagure_ci',
         sa.Column('active_pr', sa.Boolean, nullable=True, default=False)
     )
+    op.execute('UPDATE hook_pagure_ci SET active_pr=active')
+    op.execute('UPDATE hook_pagure_ci SET active_commit=False')
+    op.alter_column(
+        'hook_pagure_ci', 'active_pr',
+        nullable=False, existing_nullable=True)
+    op.alter_column(
+        'hook_pagure_ci', 'active_commit',
+        nullable=False, existing_nullable=True)
 
 
 def downgrade():
     ''' Revert the active_commit column added'''
+
+    op.execute('UPDATE hook_pagure_ci SET active=active_pr')
     op.drop_column('hook_pagure_ci', 'active_commit')
-    op.drop_column('hook_pagure_ci', 'active_pr')
\ No newline at end of file
+    op.drop_column('hook_pagure_ci', 'active_pr')
diff --git a/doc/usage/pagure_ci_jenkins.rst b/doc/usage/pagure_ci_jenkins.rst
index 3922be8..81680bc 100644
--- a/doc/usage/pagure_ci_jenkins.rst
+++ b/doc/usage/pagure_ci_jenkins.rst
@@ -16,11 +16,12 @@ How to enable Pagure CI
 
 * Select the type of CI service you want
 
-* Enter the URL to the project on the CI service. For example, if your
-  project is running at `http://jenkins.fedoraproject.org` you will need to
-  enter the URL: `http://jenkins.fedoraproject.org/job/`
+* Enter the URL of the CI service. For example `http://jenkins.fedoraproject.org`
 
-* Tick the checkbox activating the hook.
+* Enter the name of the job the CI service will trigger. For example `pagure-ci`
+
+* Tick the checkbox activating the hook. Either trigger on every commits, trigger only
+on pull-requests or both every commits and pull-requests.
 
 
 These steps will activate the hook, after reloading the page or the tab, you
diff --git a/pagure/hooks/pagure_ci.py b/pagure/hooks/pagure_ci.py
index 29d1a2a..0666723 100644
--- a/pagure/hooks/pagure_ci.py
+++ b/pagure/hooks/pagure_ci.py
@@ -112,6 +112,10 @@ class PagureCiForm(FlaskForm):
          wtforms.validators.Length(max=255)],
     )
 
+    # The active field is not render in the UI it used
+    # to hold the result of a logical OR between active_pr
+    # and active_commit.
+    # The value of active is set in pagure.ui.plugins.view_plugin
     active = wtforms.BooleanField(
         'Activate Pagure CI service',
         [wtforms.validators.Optional()]
diff --git a/pagure/ui/plugins.py b/pagure/ui/plugins.py
index 656e125..5f64bc9 100644
--- a/pagure/ui/plugins.py
+++ b/pagure/ui/plugins.py
@@ -134,7 +134,7 @@ def view_plugin(repo, plugin, username=None, namespace=None, full=True):
 
         # Compute the ci_hook active value in function
         # of the active PR and active commit values.
-        if form.active_pr and form.active_commit:
+        if hasattr(form, 'active_pr') and hasattr(form, 'active_commit'):
             if form.active_pr.data or form.active_commit.data:
                 form.active.data = True