Commit b0972239 authored by Jérome Perrin's avatar Jérome Perrin

Connector to annotate commits with test results status on gitlab

This adds a new field on Test Suite Repository to configure a "gitlab connector".

If this is set, then the commit from this repository will be annotated with the test status (failed or success). Gitlab uses these annotations to show that status on the merge request.

At the same time, fix a few minor problems on `erp5_test_result`.

/reviewed-on !924
parents 9a1cb966 38e2d655
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>View</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/GitlabRESTConnector_view</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2019 Nexedi SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from urllib import quote_plus
from urlparse import urlparse
from urlparse import urljoin
import logging
from AccessControl import ClassSecurityInfo
import requests
from Products.ERP5Type import Permissions
from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type.XMLObject import XMLObject
class GitlabRESTConnector(XMLObject):
"""Connects to gitlab v4 REST API.
"""
logger = logging.getLogger(__name__)
security = ClassSecurityInfo()
def _getRepositoryIdFromRepositoryUrl(self, repository_url):
# repository_url will be https://lab.nexedi.com/user/project.git
# convert this to user%2fproject
username_repo = urlparse(repository_url).path[1:] # remove leading /
if username_repo.endswith('/'):
username_repo = username_repo[:-1]
if username_repo.endswith('.git'):
username_repo = username_repo[:-4]
return quote_plus(username_repo)
security.declareProtected(
Permissions.AccessContentsInformation,
'postCommitStatus')
def postCommitStatus(self, repository_url, commit_sha, state, target_url, name):
"""Post the build status of a commit.
https://docs.gitlab.com/ce/api/commits.html#post-the-build-status-to-a-commit
"""
url = urljoin(
self.getUrlString(),
"projects/{id}/statuses/{sha}".format(
id=self._getRepositoryIdFromRepositoryUrl(repository_url),
sha=commit_sha
)
)
self.logger.info("posting commit status to %s", url)
response = requests.post(
url,
headers={"PRIVATE-TOKEN": self.getToken()},
json={
"state": state,
"target_url": target_url,
"name": name
},
timeout=5)
response.raise_for_status()
InitializeClass(GitlabRESTConnector)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Document Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>GitlabRESTConnector</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>document.erp5.GitlabRESTConnector</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Document Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
</ZopeData>
......@@ -33,4 +33,7 @@
<item>SlapOS Agent Test Suite</item>
<item>Test Suite</item>
</portal_type>
<portal_type id="Web Service Tool">
<item>Gitlab REST Connector</item>
</portal_type>
</allowed_content_type_list>
\ No newline at end of file
......@@ -13,6 +13,11 @@
<portal_type id="ERP5 Scalability Distributor">
<item>ScalabilityDistributor</item>
</portal_type>
<portal_type id="Gitlab REST Connector">
<item>GitlabRESTConnector</item>
<item>Reference</item>
<item>Url</item>
</portal_type>
<portal_type id="Scalability Test Suite">
<item>Arrow</item>
<item>ScalabilityTestSuite</item>
......@@ -58,6 +63,7 @@
<item>TestSuiteConstraint</item>
</portal_type>
<portal_type id="Test Suite Repository">
<item>Arrow</item>
<item>TestSuiteRepository</item>
<item>TestSuiteRepositoryConstraint</item>
</portal_type>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Base Type" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>content_icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Gitlab REST Connector</string> </value>
</item>
<item>
<key> <string>init_script</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>permission</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Base Type</string> </value>
</item>
<item>
<key> <string>type_class</string> </key>
<value> <string>GitlabRESTConnector</string> </value>
</item>
<item>
<key> <string>type_interface</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>type_mixin</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -19,6 +19,10 @@
<type>ERP5 Scalability Distributor</type>
<workflow>edit_workflow, validation_workflow</workflow>
</chain>
<chain>
<type>Gitlab REST Connector</type>
<workflow>edit_workflow, validation_workflow</workflow>
</chain>
<chain>
<type>Scalability Test Suite</type>
<workflow>edit_workflow, test_suite_workflow</workflow>
......@@ -37,7 +41,7 @@
</chain>
<chain>
<type>Test Result</type>
<workflow>edit_workflow, test_result_workflow</workflow>
<workflow>edit_workflow, test_result_gitlab_interaction_workflow, test_result_workflow</workflow>
</chain>
<chain>
<type>Test Result Line</type>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Property Sheet" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>GitlabRESTConnector</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Property Sheet</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Personal access token\n
\n
https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>token_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>read_permission</string> </key>
<value> <string>Manage properties</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>computer_guid_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>computer_guid</string> </value>
</item>
</dictionary>
</pickle>
</record>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/string</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>computer_guid_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>computer_guid</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5 Form" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>Base_edit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string>multipart/form-data</string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<dictionary>
<item>
<key> <string>bottom</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list>
<string>my_description</string>
</list>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list>
<string>my_reference</string>
<string>my_url_string</string>
</list>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list>
<string>my_token</string>
<string>my_translated_validation_state_title</string>
</list>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>GitlabRESTConnector_view</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>GitlabRESTConnector_view</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_view</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Gitlab REST Connector</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>update_action_title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_description</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_description</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_reference</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_reference</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_token</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list>
<tuple>
<string>FTP</string>
<string>ftp</string>
</tuple>
<tuple>
<string>SFTP</string>
<string>sftp</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Token</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_translated_validation_state_title</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_translated_workflow_state_title</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_url_string</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>URL</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
"""Annotate a commit with state of the test (running, canceled, success, failed)
"""
portal = context.getPortalObject()
portal_absolute_url = portal.ERP5Site_getAbsoluteUrl()
test_suite_data = context.TestResult_getTestSuiteData()
if test_suite_data:
for repository_info in test_suite_data['repository_dict'].values():
connector_url = repository_info['connector_relative_url']
if connector_url:
portal.restrictedTraverse(connector_url).postCommitStatus(
repository_info['repository_url'],
repository_info['revision'],
state,
'%s/%s' % ( portal_absolute_url, context.getRelativeUrl() ),
context.getTitle()
)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>TestResult_annotateCommit</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
"Jump to gitlab or gitweb web interface to view commit"
portal = context.getPortalObject()
test_suite_list = portal.portal_catalog(
portal_type='Test Suite',
validation_state=('validated', 'invalidated'),
title={'query': context.getTitle(), 'key': 'ExactMatch'})
if not test_suite_list:
return []
test_suite = sorted(
[test_suite.getObject() for test_suite in test_suite_list],
key=lambda test_suite: test_suite.getValidationState() == 'validated')[0]
# TODO: make this jump test suite
# decode the reference ( ${buildout_section_id}=${number of commits}-${hash},${buildout_section_id}=${number of commits}-${hash}, ... )
repository_dict = {}
for repository_string in context.getReference().split(','):
repository_code, revision = repository_string.split('-')
repository_dict[repository_code.split('=')[0]] = revision
from Products.PythonScripts.standard import Object
test_suite_data = context.TestResult_getTestSuiteData()
result_list = []
from Products.PythonScripts.standard import Object
def makeVCSLink(repository_url, revision):
# https://user:pass@lab.nexedi.cn/user/repo.git -> https://user:pass@lab.nexedi.cn/user/repo/commit/hash
if 'lab.nexedi.cn' in repository_url and repository_url.endswith('.git'):
if 'lab.nexedi' in repository_url and repository_url.endswith('.git'):
repository_url = repository_url[:-len('.git')]
if '@' in repository_url: # remove credentials
scheme = repository_url.split(':')[0]
......@@ -49,11 +29,11 @@ def makeVCSLink(repository_url, revision):
repository=repository_url,
revision=revision)
for repository in test_suite.contentValues(portal_type='Test Suite Repository'):
for repository in test_suite_data['repository_dict'].values():
result_list.append(
makeVCSLink(
repository.getProperty('git_url'),
repository_dict[repository.getProperty('buildout_section_id')]))
repository['repository_url'],
repository['revision']))
if len(result_list) == 1:
from zExceptions import Redirect
......
"""Returns info about a test result, a mapping containing:
test_suite_relative_url: relative url of test suite
repository_dict: for each test suite repository, keyed by buildout section id:
revision: commit sha
repository_url: git url of the repository
commits_count: number of commits
returns None if test suite cannot be found.
"""
portal = context.getPortalObject()
test_suite_list = portal.portal_catalog(
portal_type='Test Suite',
validation_state=('validated', 'invalidated'),
title={'query': context.getTitle(), 'key': 'ExactMatch'})
if not test_suite_list:
return None
test_suite = sorted(
[test_suite.getObject() for test_suite in test_suite_list],
key=lambda test_suite: test_suite.getValidationState() == 'validated')[-1]
# decode the reference ( ${buildout_section_id}=${number of commits}-${hash},${buildout_section_id}=${number of commits}-${hash} )
repository_dict = {}
if context.getReference() and '-' in context.getReference(): # tolerate invalid references, especially for tests
for repository_string in context.getReference().split(','):
buildout_section_id_and_commits_count, revision = repository_string.split('-')
buildout_section_id, commits_count = buildout_section_id_and_commits_count.split('=')
repository_dict[buildout_section_id] = {
'revision': revision,
'commits_count': int(commits_count),
}
# add information about test suite repositories
for test_result_repository in test_suite.contentValues(portal_type='Test Suite Repository'):
repository_data = repository_dict.setdefault(test_result_repository.getBuildoutSectionId(), {})
repository_data['repository_url'] = test_result_repository.getGitUrl()
repository_data['connector_relative_url'] = test_result_repository.getDestination()
if REQUEST:
REQUEST.RESPONSE.setHeader('content-type', 'application/json; charset=utf-8')
return {
'test_suite_relative_url': test_suite.getRelativeUrl(),
'repository_dict': repository_dict,
}
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>TestResult_getTestSuiteData</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -103,7 +103,9 @@
<item>
<key> <string>right</string> </key>
<value>
<list/>
<list>
<string>my_destination_title</string>
</list>
</value>
</item>
</dictionary>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>columns</string>
<string>description</string>
<string>portal_type</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_destination_title</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>title</string>
<string>Gitlab REST Connector</string>
</tuple>
<tuple>
<string>url_string</string>
<string>URL</string>
</tuple>
<tuple>
<string>translated_validation_state_title</string>
<string>State</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Connector to gitlab API to annotate commits from this repository with test result status.</string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_relation_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value>
<list>
<tuple>
<string>Gitlab REST Connector</string>
<string>Gitlab REST Connector</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Gitlab Connector</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -98,6 +98,10 @@
<string>branch</string>
<string>Branch</string>
</tuple>
<tuple>
<string>destination_title</string>
<string>Gitlab Connector</string>
</tuple>
</list>
</value>
</item>
......
......@@ -3,6 +3,9 @@ from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
import json
from time import sleep
from DateTime import DateTime
import responses
import httplib
class TestTaskDistribution(ERP5TypeTestCase):
def afterSetUp(self):
......@@ -152,7 +155,7 @@ class TestTaskDistribution(ERP5TypeTestCase):
self.scalability_distributor.getRelativeUrl())
def test_02b_checkConsistencyOnTestSuite(self):
test_suite, = self._createTestSuite()
test_suite, = self._createTestSuite() # pylint: disable=unbalanced-tuple-unpacking
self.tic()
test_suite_repository, = test_suite.objectValues(portal_type="Test Suite Repository")
self.checkPropertyConstraint(test_suite, 'title', 'ERP5-MASTER')
......@@ -169,7 +172,7 @@ class TestTaskDistribution(ERP5TypeTestCase):
Make sure validation of test suite generate a reference, and revalidating
a test suite should not change reference
"""
test_suite, = self._createTestSuite()
test_suite, = self._createTestSuite() # pylint: disable=unbalanced-tuple-unpacking
self.assertTrue(test_suite.getReference() != None)
self.tic()
test_suite.invalidate()
......@@ -187,7 +190,7 @@ class TestTaskDistribution(ERP5TypeTestCase):
"""
Check the constraint avoiding duplicates of test suites
"""
test_suite, = self._createTestSuite()
test_suite, = self._createTestSuite() # pylint: disable=unbalanced-tuple-unpacking
self.tic()
test_suite_clone = test_suite.Base_createCloneDocument(batch_mode=1)
self.assertRaises(ValidationFailed, self.portal.portal_workflow.doActionFor, test_suite_clone, 'validate_action')
......@@ -360,10 +363,9 @@ class TestTaskDistribution(ERP5TypeTestCase):
while a test suite with high priority is waiting for more nodes to speed up.
"""
for x in range(10):
config_list = json.loads(self.distributor.startTestSuite(
title="COMP%s-Node1" % x))
json.loads(self.distributor.startTestSuite(title="COMP%s-Node1" % x))
test_suite_list = self._createTestSuite(quantity=3)
test_suite_1, test_suite_2, test_suite_3 = test_suite_list
test_suite_1, test_suite_2, test_suite_3 = test_suite_list # pylint: disable=unbalanced-tuple-unpacking
test_suite_list[0].setIntIndex(1) # test suite 1, up to 1 testnode
test_suite_list[1].setIntIndex(5) # test suite 2, up to 5 testnodes
test_suite_list[2].setIntIndex(8) # test suite 3, up to 10 testnodes
......@@ -869,7 +871,7 @@ class TestTaskDistribution(ERP5TypeTestCase):
It shall be possible on a test suite to define configuration we would like
to use to create slapos instance.
"""
test_suite, = self._createTestSuite(cluster_configuration=None)
test_suite, = self._createTestSuite(cluster_configuration=None) # pylint: disable=unbalanced-tuple-unpacking
self.tic()
self.assertEquals('{"configuration_list": [{}]}', self.distributor.generateConfiguration(test_suite.getTitle()))
test_suite.setClusterConfiguration("{'foo': 3}")
......@@ -896,7 +898,7 @@ class TestTaskDistribution(ERP5TypeTestCase):
When we have two test suites and we have two test nodes, we should have
one test suite distributed per test node
"""
test_node_one, test_node_two = self._createTestNode(quantity=2)
test_node_one, test_node_two = self._createTestNode(quantity=2) # pylint: disable=unbalanced-tuple-unpacking
test_suite_one = self._createTestSuite(reference_correction=+0,
title='one')[0]
self._createTestSuite(reference_correction=+1,
......@@ -989,23 +991,23 @@ class TestTaskDistribution(ERP5TypeTestCase):
[test_node_two, ["one", "seven", "height" , "six"]])
# Check that additional test node would get work for missing assignments
# No move a test suite is done since in average we miss slots
test_node_three, = self._createTestNode(reference_correction=2)
test_node_three, = self._createTestNode(reference_correction=2) # pylint: disable=unbalanced-tuple-unpacking
check([test_node_zero, ["three", "four", "height", "six"]],
[test_node_one, ["two", "four", "seven" , "six"]],
[test_node_two, ["one", "seven", "height" , "six"]],
[test_node_three, ["seven", "height"]])
# With even more test node, check that we move some work to less
# busy test nodes
test_node_four, = self._createTestNode(reference_correction=3)
test_node_five, = self._createTestNode(reference_correction=4)
test_node_four, = self._createTestNode(reference_correction=3) # pylint: disable=unbalanced-tuple-unpacking
test_node_five, = self._createTestNode(reference_correction=4) # pylint: disable=unbalanced-tuple-unpacking
check([test_node_zero, ["three", "six", "height"]],
[test_node_one, ["two", "six", "seven"]],
[test_node_two, ["one", "seven", "height"]],
[test_node_three, ["four", "seven", "height"]],
[test_node_four, ["four", "seven", "height"]],
[test_node_five, ["six", "seven", "height"]])
test_node_six, = self._createTestNode(reference_correction=5)
test_node_seven, = self._createTestNode(reference_correction=6)
test_node_six, = self._createTestNode(reference_correction=5) # pylint: disable=unbalanced-tuple-unpacking
test_node_seven, = self._createTestNode(reference_correction=6) # pylint: disable=unbalanced-tuple-unpacking
check([test_node_zero, ["three", "height"]],
[test_node_one, ["two", "seven"]],
[test_node_two, ["one", "height"]],
......@@ -1020,7 +1022,7 @@ class TestTaskDistribution(ERP5TypeTestCase):
Check that the property max_test_suite on the distributor could
be used to customize the quantity of test suite affected per test node
"""
test_node, = self._createTestNode(quantity=1)
test_node, = self._createTestNode(quantity=1) # pylint: disable=unbalanced-tuple-unpacking
test_suite_list = self._createTestSuite(quantity=5)
self.tool.TestTaskDistribution.setMaxTestSuite(None)
self.tic()
......@@ -1040,8 +1042,9 @@ class TestTaskDistribution(ERP5TypeTestCase):
When we have two test suites and we have two test nodes, we should have
one test suite distributed per test node
"""
test_node_one, test_node_two = self._createTestNode(quantity=2,
specialise_value=self.performance_distributor)
test_node_one, test_node_two = self._createTestNode( # pylint: disable=unbalanced-tuple-unpacking
quantity=2,
specialise_value=self.performance_distributor)
test_suite_one = self._createTestSuite(
title='one', specialise_value=self.performance_distributor)[0]
self._createTestSuite(title='two', reference_correction=+1,
......@@ -1103,7 +1106,6 @@ class TestTaskDistribution(ERP5TypeTestCase):
self.assertEqual(set(['test suite 1|COMP32-Node1',
'test suite 2|COMP32-Node1']),
set([x['test_suite_title'] for x in config_list]))
revision = 'a=a,b=b,c=c'
result = self._createTestResult(test_title='test suite 1|COMP32-Node1',
distributor=self.performance_distributor)
self.tic()
......@@ -1410,4 +1412,133 @@ class TestTaskDistribution(ERP5TypeTestCase):
self.tic()
self._createTestResult(test_title='Periodicity Disabled Test Suite')
self.assertEqual(None, test_suite.getAlarmDate())
\ No newline at end of file
self.assertEqual(None, test_suite.getAlarmDate())
class TestGitlabRESTConnectorInterface(ERP5TypeTestCase):
"""Tests for Gitlab commits annotations.
"""
def afterSetUp(self):
connector = self.portal.portal_web_services.newContent(
portal_type='Gitlab REST Connector',
reference='lab.example.com',
url_string='https://lab.example.com/api/v4/',
token='123456'
)
connector.validate()
self.project = self.portal.project_module.newContent(
portal_type='Project',
title=self.id()
)
self.test_suite = self.portal.test_suite_module.newContent(
portal_type='Test Suite',
title=self.id(),
source_project_value=self.project,
)
self.test_suite.newContent(
portal_type='Test Suite Repository',
branch='master',
git_url='https://lab.example.com/nexedi/test.git',
buildout_section_id='test',
destination_value=connector,
)
# another unrelated repository, without connector, this
# should not cause any API call.
self.test_suite.newContent(
portal_type='Test Suite Repository',
branch='master',
git_url='https://lab.nexedi.com/nexedi/erp5.git',
buildout_section_id='erp5',
profile_path='software-release/software.cfg'
)
self.test_suite.validate()
self.test_result = self.portal.test_result_module.newContent(
portal_type='Test Result',
source_project_value=self.project,
title=self.id(),
reference='erp5=1-dc7b6e2e85e9434a97694a698884b057b7d30286,test=10-cc4c79c003f7cfe0bfcbc7b302eac988110c96ae'
)
self.post_commit_status_url = \
'https://lab.example.com/api/v4/projects/nexedi%2Ftest/statuses/cc4c79c003f7cfe0bfcbc7b302eac988110c96ae'
self.tic()
def beforeTearDown(self):
self.test_suite.invalidate()
self.tic()
def _response_callback(self, state):
"""Callback for responses, checking that request was correct to mark commit as `state`
"""
def _callback(request):
self.assertEqual(
'123456',
request.headers['PRIVATE-TOKEN'])
body = json.loads(request.body)
self.assertEqual(
state,
body['state'])
self.assertIn(
self.test_result.getRelativeUrl(),
body['target_url'])
self.assertEqual(
self.id(),
body['name'])
return (httplib.CREATED, {'content-type': 'application/json'}, '{}')
return _callback
def test_start_test(self):
with responses.RequestsMock() as rsps:
rsps.add_callback(
responses.POST,
self.post_commit_status_url,
self._response_callback('running'))
self.test_result.start()
self.tic()
def _start_test_result(self):
with responses.RequestsMock() as rsps:
rsps.add(
responses.POST,
self.post_commit_status_url,
{})
self.test_result.start()
self.tic()
def test_cancel_test(self):
self._start_test_result()
with responses.RequestsMock() as rsps:
rsps.add_callback(
responses.POST,
self.post_commit_status_url,
self._response_callback('canceled'))
self.test_result.cancel()
self.tic()
def test_stop_test_success(self):
self._start_test_result()
self.test_result.newContent(
portal_type='Test Result Line',
all_tests=1
)
self.test_result.setStringIndex('PASS')
with responses.RequestsMock() as rsps:
rsps.add_callback(
responses.POST,
self.post_commit_status_url,
self._response_callback('success'))
self.test_result.stop()
self.tic()
def test_stop_test_failure(self):
self._start_test_result()
self.test_result.setStringIndex('FAILED')
with responses.RequestsMock() as rsps:
rsps.add_callback(
responses.POST,
self.post_commit_status_url,
self._response_callback('failed'))
self.test_result.stop()
self.tic()
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionWorkflowDefinition" module="Products.ERP5.InteractionWorkflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>creation_guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Update gitlab status of commits after test results</string> </value>
</item>
<item>
<key> <string>groups</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test_result_gitlab_interaction_workflow</string> </value>
</item>
<item>
<key> <string>manager_bypass</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Interaction Workflow Definition</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Interaction" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>interactions</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionDefinition" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>activate_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>TestResult_afterCancel</string>
</list>
</value>
</item>
<item>
<key> <string>before_commit_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>cancel</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
<value>
<list>
<string>cancel</string>
</list>
</value>
</item>
<item>
<key> <string>once_per_transaction</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type_group_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>temporary_document_disallowed</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionDefinition" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>activate_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>TestResult_afterStart</string>
</list>
</value>
</item>
<item>
<key> <string>before_commit_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>start</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
<value>
<list>
<string>start</string>
</list>
</value>
</item>
<item>
<key> <string>once_per_transaction</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type_group_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>temporary_document_disallowed</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionDefinition" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>activate_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>TestResult_afterStop</string>
</list>
</value>
</item>
<item>
<key> <string>before_commit_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>stop</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
<value>
<list>
<string>stop</string>
</list>
</value>
</item>
<item>
<key> <string>once_per_transaction</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type_group_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>temporary_document_disallowed</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Scripts" module="Products.DCWorkflow.Scripts"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>scripts</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>sci</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>TestResult_afterCancel</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>sci</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>TestResult_afterStart</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
test_result = sci['object']
state = 'failed'
if test_result.getStringIndex() == 'PASS' and test_result.getProperty('all_tests', 0) > 0:
state = 'success'
test_result.activate(activity='SQLQueue').TestResult_annotateCommit(state)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>sci</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>TestResult_afterStop</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Variables" module="Products.DCWorkflow.Variables"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variables</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Worklists" module="Products.DCWorkflow.Worklists"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_mapping</string> </key>
<value>
<dictionary/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>worklists</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
erp5_project
\ No newline at end of file
erp5_project
erp5_web_service
\ No newline at end of file
......@@ -3,6 +3,7 @@ Benchmark Result | view
Cloud Performance Unit Test Distributor | view
ERP5 Project Unit Test Distributor | view
ERP5 Scalability Distributor | view
Gitlab REST Connector | view
Scalability Test Suite | vcs_repository
Scalability Test Suite | view
SlapOS Agent Distributor | view
......
......@@ -2,4 +2,5 @@ document.erp5.TestNode
document.erp5.TestSuite
document.erp5.TestSuiteRepository
document.erp5.ERP5ScalabilityDistributor
document.erp5.SlapOSAgentDistributor
\ No newline at end of file
document.erp5.SlapOSAgentDistributor
document.erp5.GitlabRESTConnector
\ No newline at end of file
......@@ -13,4 +13,5 @@ Test Result | Test Result Node
Test Suite Module | Scalability Test Suite
Test Suite Module | SlapOS Agent Test Suite
Test Suite Module | Test Suite
Test Suite | Test Suite Repository
\ No newline at end of file
Test Suite | Test Suite Repository
Web Service Tool | Gitlab REST Connector
\ No newline at end of file
......@@ -3,6 +3,7 @@ Benchmark Result Line
Cloud Performance Unit Test Distributor
ERP5 Project Unit Test Distributor
ERP5 Scalability Distributor
Gitlab REST Connector
Scalability Test Suite
SlapOS Agent Distributor
SlapOS Agent Test Suite
......
......@@ -4,6 +4,9 @@ Benchmark Result | SortIndex
Benchmark Result | Task
ERP5 Project Unit Test Distributor | UnitTestDistributor
ERP5 Scalability Distributor | ScalabilityDistributor
Gitlab REST Connector | GitlabRESTConnector
Gitlab REST Connector | Reference
Gitlab REST Connector | Url
Scalability Test Suite | Arrow
Scalability Test Suite | ScalabilityTestSuite
Scalability Test Suite | TestSuite
......@@ -23,6 +26,7 @@ Test Result Node | Task
Test Result | Comment
Test Result | SortIndex
Test Result | Task
Test Suite Repository | Arrow
Test Suite Repository | TestSuiteRepository
Test Suite Repository | TestSuiteRepositoryConstraint
Test Suite | Arrow
......
......@@ -8,6 +8,8 @@ ERP5 Project Unit Test Distributor | edit_workflow
ERP5 Project Unit Test Distributor | validation_workflow
ERP5 Scalability Distributor | edit_workflow
ERP5 Scalability Distributor | validation_workflow
Gitlab REST Connector | edit_workflow
Gitlab REST Connector | validation_workflow
Scalability Test Suite | edit_workflow
Scalability Test Suite | test_suite_workflow
SlapOS Agent Distributor | edit_workflow
......@@ -21,6 +23,7 @@ Test Result Line | test_result_workflow
Test Result Node | edit_workflow
Test Result Node | test_result_workflow
Test Result | edit_workflow
Test Result | test_result_gitlab_interaction_workflow
Test Result | test_result_workflow
Test Suite | edit_workflow
Test Suite | test_suite_workflow
\ No newline at end of file
TestSuite
GitlabRESTConnector
CommandLineResult
TestSuiteRepository
TestSuiteRepositoryConstraint
......
test_node_workflow
test_result_gitlab_interaction_workflow
test_result_workflow
test_suite_workflow
\ No newline at end of file
......@@ -443,6 +443,7 @@ class TestXHTML(TestXHTMLMixin):
'erp5_email_reader',
'erp5_commerce',
'erp5_credential',
'erp5_web_service',
'erp5_test_result',
'erp5_forge',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment