Title: [291766] trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy
Revision
291766
Author
zhifei_f...@apple.com
Date
2022-03-23 14:21:59 -0700 (Wed, 23 Mar 2022)

Log Message

[results.webkit.org] Add file bugzilla button
https://bugs.webkit.org/show_bug.cgi?id=237802

Reviewed by Jonathan Bedard.

* Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/__init__.py: Added.
* Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/bug_description.py: Added.
(translate_selected_dots_to_bug_title_and_description):
* Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/bugzilla.py: Added.
(Bugzilla):
(Bugzilla.__init__):
(Bugzilla.create_bug):
* Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/api_routes.py:
(APIRoutes.__init__):
* Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/static/js/timeline.js:
(TimelineFromEndpoint.prototype._renderSelectedDotsButtonGroup):
(TimelineFromEndpoint):

Canonical link: https://commits.webkit.org/248796@main

Modified Paths

Added Paths

Diff

Added: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/__init__.py (0 => 291766)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/__init__.py	                        (rev 0)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/__init__.py	2022-03-23 21:21:59 UTC (rev 291766)
@@ -0,0 +1 @@
+# DO NOTHING

Added: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/bug_description.py (0 => 291766)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/bug_description.py	                        (rev 0)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/bug_description.py	2022-03-23 21:21:59 UTC (rev 291766)
@@ -0,0 +1,88 @@
+# Copyright (C) 2022 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from functools import reduce
+
+from resultsdbpy.model.test_context import Expectations
+from resultsdbpy.controller.configuration import Configuration
+
+
+def translate_selected_dots_to_bug_title_and_description(commit_context, selected_rows, test, suite, repositories, will_filter_expected):
+
+    failed_scopes = []
+    for selected_row in selected_rows:
+        config = selected_row['config']
+        results = selected_row['results']
+        init_failure_type, init_failure_number = Expectations.get_test_result_status(results[0], will_filter_expected)
+        if not init_failure_type:
+            continue
+        sucess_results = list(filter(lambda result: not Expectations.get_test_result_status(result, will_filter_expected)[0], results))
+        if len(sucess_results):
+            last_sucess = sucess_results[0]
+        else:
+            last_sucess = None
+        failed_scopes.append((results[0], init_failure_type, init_failure_number, last_sucess, config))
+
+    if len(failed_scopes) == 0:
+        raise ValueError('No failures dectected')
+
+    title_components = set()
+    description_components = []
+
+    for failed_scope in failed_scopes:
+        result, init_failure_type, init_failure_number, last_sucess, config = failed_scope
+        version_name = config['version_name'] if 'version_name' in config else Configuration.integer_to_version(config['version'])
+        title_components.add('{} on {}({})'.format(init_failure_type, version_name, config['model']))
+        if init_failure_number is not None:
+            description_components.append('{} {}'.format(init_failure_number, init_failure_type))
+        description_components.append('Hardware:     \t{}'.format(config['model']))
+        description_components.append('Architecture: \t{}'.format(config['architecture']))
+        description_components.append('OS:           \t{}'.format(version_name))
+        description_components.append('Style:        \t{}'.format(config['style']))
+        if suite == 'layout-tests':
+            description_components.append('Flavor        \t{}'.format(config['flavor']))
+        if 'sdk' in config:
+            description_components.append('SDK:          \t{}'.format(config['sdk']))
+        description_components.append('-----------------------------')
+        failure_commits = reduce(
+            lambda a, b: a + b,
+            map(lambda repo: commit_context.find_commits_by_uuid(repo, 'main', result['uuid']),
+                repositories)
+        )
+        description_components.append('Most recent failures:')
+        description_components += list(
+            map(lambda commit: '{}: {}'.format(commit.identifier, commit_context.url(commit)),
+                failure_commits)
+        )
+        description_components.append('-----------------------------')
+        if last_sucess:
+            description_components.append('Last success:')
+            last_sucess_commits = reduce(
+                lambda a, b: a + b,
+                map(lambda repo: commit_context.find_commits_by_uuid(repo, 'main', last_sucess['uuid']),
+                    repositories)
+            )
+            description_components += list(
+                map(lambda commit: '{}: {}'.format(commit.identifier, commit_context.url(commit)),
+                    last_sucess_commits)
+            )
+        return title_components, description_components

Added: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/bugzilla.py (0 => 291766)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/bugzilla.py	                        (rev 0)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/bug_trackers/bugzilla.py	2022-03-23 21:21:59 UTC (rev 291766)
@@ -0,0 +1,172 @@
+# Copyright (C) 2022 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from ast import keyword
+from urllib.parse import quote
+from resultsdbpy.bug_trackers.bug_description import translate_selected_dots_to_bug_title_and_description
+from resultsdbpy.controller.bug_tracker_controller import BugTrackerConfig
+
+
+class WebKitBugzilla(BugTrackerConfig):
+
+    COMPONENTS_LAYOUT_TEST_MAPPING = {
+        'Accessibility': {'lower': True},
+        'ANGLE': {'skip': True},
+        'Animations': {'lower': True},
+        'Bindings': {'lower': True},
+        'bmalloc': {'skip': True},
+        'Canvas': {'lower': True},
+        'CMake': {'skip': True},
+        'Compositing': {'lower': True},
+        'CSS': {'keywords': [
+            'css', 'css1', 'css2.1', 'css3', 'cssom', 'css-custom-properties-api',
+            'css-dark-mode', 'css-typedom', 'backgrounds', 'borders', 'box-decoration-break',
+            'box-shadow', 'box-sizing', 'flexbox', 'gradients', 'inline', 'inline-block',
+            'line-grid', 'multicol', 'overflow', 'transforms']},
+        'DOM': {'keywords': ['dom', 'shadow-dom']},
+        'Evangelism': {'skip': True},
+        'Forms': {'lower': True},
+        'Frames': {'lower': True},
+        'History': {'lower': True},
+        'HTML Editing': {'keywords': ['editing']},
+        'Images': {'lower': True},
+        '_javascript_Core': {'keywords': ['js', 'jquery', 'regex']},
+        'Layout and Rendering': {'keywords': ['rendering', 'layers']},
+        'MathML': {'lower': True},
+        'Media': {'keywords': ['media', 'mediacapturefromelement', 'mediasession', 'mediastream']},
+        'New Bugs': {'keywords': ['imported']},
+        'Page Loading': {'skip': True},
+        'PDF': {'skip': True},
+        'Platform': {'skip': True},
+        'Plug-ins': {'skip': True},
+        'Printing': {'lower': True},
+        'Scrolling': {'keywords': ['scrolling', 'fast-moblie-scrolling']},
+        'Service Workers': {'keywords': ['workers']},
+        'SVG': {'lower': True},
+        'Tables': {'lower': True},
+        'Text': {'lower': True},
+        'Tools / Tests': {'skip': True},
+        'UI Events': {'keywords': ['events', 'eventloop']},
+        'WebAssembly': {'keywords': ['wasm']},
+        'Web Audio': {'keywords': ['webaudio']},
+        'WebCore _javascript_': {'skip': True},  # FIXME maybe need move some keywords from _javascript_Core
+        'WebCore Misc.': {'keywords': ['misc']},
+        'WebDriver': {'skip': True},
+        'WebGL': {'lower': True},
+        'WebGPU': {'keywords': ['gpu-process']},
+        'Web Inspector': {'keywords': ['inspector']},
+        'WebKit2': {'skip': True},
+        'WebKit API': {'skip': True},
+        'WebKitGTK': {'skip': True},
+        'WebKit Misc.': {'keywords': ['misc']},
+        'WebKit Process Model': {'skip': True},
+        'WebKit Website': {'skip': True},
+        'WebRTC': {'lower': True},
+        'Website Storage': {'keywords': ['storage']},
+        'Web Template Framework'
+        'WebXR': {'lower': True},
+        'WPE WebKit': {'skip': True},
+        'XML': {'lower': True},
+    }
+
+    def __init__(self):
+        super().__init__('bugzilla')
+
+    def create_bug(self, content):
+        """
+            content formats:
+            {
+                "selectedRows": [{
+                    "config": {
+                        "model":  ...,
+                        "architecture": ...,
+                        "style": ...,
+                        "flavor": ...,
+                        "sdk": ...,
+                        "version_name": ...,
+                        "suite": ...
+                    },
+                    "results": [
+                        {
+                            "uuid": ...,
+                            "actual": ...,
+                            "expected": ...,
+                            "start_time": ...,
+                            "time": ...
+                        }
+                    ]
+                }],
+                "willFilterExpected": ...,
+                "repositories": [],
+                "suite": ...,
+                "test": ...
+            }
+        """
+
+        selected_rows = content['selectedRows']
+        will_filter_expected = content['willFilterExpected']
+        repositories = content['repositories']
+        suite = content['suite']
+        test = content['test']
+
+        title_components, description_components = translate_selected_dots_to_bug_title_and_description(self.commit_context, selected_rows, test, suite, repositories, will_filter_expected)
+
+        component = 'New Bugs'
+        version = 'WebKit Nightly Build'
+        if suite == 'api-tests':
+            component = 'WebKit API'
+        if suite == 'webkitpy-tests':
+            component = 'Tools / Tests'
+        if suite == 'internal-media-tests':
+            component = 'Media'
+        if suite == '_javascript_core-tests':
+            component = '_javascript_Core'
+        if test and any([suite == 'layout-tests', suite == 'internal-security-tests']):
+            test_name_parts = test.split('/')
+            for k, v in self.COMPONENTS_LAYOUT_TEST_MAPPING:
+                if 'skip' in v and v['skip']:
+                    continue
+                if 'lower' in v and v['lower']:
+                    if k.lower() in test_name_parts:
+                        component = k
+                        break
+                if 'keywords' in v and len(v['keywords']):
+                    if any(map(lambda keyword: keyword in test_name_parts, v['keywords'])):
+                        component = k
+                        break
+
+        bugzilla_url_components = [
+            'component={}'.format(quote(component)),
+            'version={}'.format(quote(version)),
+            'short_desc={} {}'.format(
+                quote(test if test else suite),
+                quote(' and '.join(list(title_components)))
+            ),
+            'comment={}'.format(
+                quote('\n'.join(list(description_components)))
+            )
+        ]
+
+        return {
+            'url': 'https://bugs.webkit.org/enter_bug.cgi?product=WebKit&{}'.format('&'.join(bugzilla_url_components)),
+            'newWindow': True
+        }

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/api_routes.py (291765 => 291766)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/api_routes.py	2022-03-23 20:26:40 UTC (rev 291765)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/api_routes.py	2022-03-23 21:21:59 UTC (rev 291766)
@@ -32,6 +32,7 @@
 from resultsdbpy.controller.test_controller import TestController
 from resultsdbpy.controller.upload_controller import UploadController
 from resultsdbpy.controller.bug_tracker_controller import BugTrackerController
+from resultsdbpy.bug_trackers.bugzilla import WebKitBugzilla
 from webkitflaskpy import AuthedBlueprint
 from werkzeug.exceptions import HTTPException
 
@@ -50,7 +51,8 @@
         self.ci_controller = CIController(ci_context=model.ci_context, upload_context=model.upload_context)
         self.archive_controller = ArchiveController(commit_controller=self.commit_controller, archive_context=model.archive_context, upload_context=model.upload_context)
 
-        self.bug_tracker_controller = BugTrackerController(bug_tracker_configs=bug_tracker_configs, commit_context=model.commit_context)
+        self.bug_tracker_configs = [WebKitBugzilla()] if not len(bug_tracker_configs) else bug_tracker_configs
+        self.bug_tracker_controller = BugTrackerController(bug_tracker_configs=self.bug_tracker_configs, commit_context=model.commit_context)
 
         for code in [400, 404, 405]:
             self.register_error_handler(code, self.error_response)
@@ -81,9 +83,8 @@
         self.add_url_rule('/urls/queue', 'queue-urls', self.ci_controller.urls_for_queue_endpoint, methods=('GET',))
         self.add_url_rule('/urls', 'build-urls', self.ci_controller.urls_for_builds_endpoint, methods=('GET',))
 
-        if bug_tracker_configs:
-            self.add_url_rule('/bug-trackers', 'bug-trackers', self.bug_tracker_controller.list_trackers, methods=('GET',))
-            self.add_url_rule('/bug-trackers/<path:tracker>/create-bug', 'create-bug', self.bug_tracker_controller.create_bug, methods=('PUT',))
+        self.add_url_rule('/bug-trackers', 'bug-trackers', self.bug_tracker_controller.list_trackers, methods=('GET',))
+        self.add_url_rule('/bug-trackers/<path:tracker>/create-bug', 'create-bug', self.bug_tracker_controller.create_bug, methods=('PUT',))
 
     def error_response(self, error):
         response = jsonify(status='error', error=error.name, description=error.description)

Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/static/js/timeline.js (291765 => 291766)


--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/static/js/timeline.js	2022-03-23 20:26:40 UTC (rev 291765)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/static/js/timeline.js	2022-03-23 21:21:59 UTC (rev 291766)
@@ -37,6 +37,11 @@
 let willFilterExpected = false;
 let showTestTimes = false;
 
+const BUG_TRACKER_COLORS = {
+    radar: 'var(--purple)',
+    bugzilla: 'var(--blue)'
+} 
+
 function minimumUuidForResults(results, limit) {
     const now = Math.floor(Date.now() / 10);
     let minDisplayedUuid = now;
@@ -550,66 +555,69 @@
     }
 
     _renderSelectedDotsButtonGroup(element) {
-        DOM.inject(element, this.bugTrackers.map(bugTracker => {
-            const buttonText = `${bugTracker}`;
-            const buttonRef = REF.createRef({
-                state: {
-                    loading: false
-                },
-                onStateUpdate: (element, stateDiff) => {
-                    if (stateDiff.loading)
-                        element.innerText = 'Waiting...';
-                    else
-                        element.innerText = buttonText;
-                }
-            });
-
-            buttonRef.fromEvent('click').action(e => {
-                const requestPayload = {
-                    selectedRows: [],
-                    willFilterExpected: InvestigateDrawer.willFilterExpected,
-                    repositories: this.repositories,
-                    suite: this.suite,
-                    test: this.test
-                };
-                Array.from(this.selectedDots.keys()).forEach(config => {
-                    const dots = this.selectedDots.get(config);
-                    requestPayload.selectedRows.push({
-                        config,
-                        results: dots
+        DOM.inject(element, 
+            `<div class="row">
+                ${this.bugTrackers.map(bugTracker => {
+                    const buttonText = `${bugTracker[0].toUpperCase()}${bugTracker.substring(1)}`;
+                    const buttonRef = REF.createRef({
+                        state: {
+                            loading: false
+                        },
+                        onStateUpdate: (element, stateDiff) => {
+                            if (stateDiff.loading)
+                                element.innerText = 'Waiting...';
+                            else
+                                element.innerText = buttonText;
+                        }
                     });
-                });
-                buttonRef.setState({loading: true});
-                fetch(`api/bug-trackers/${bugTracker}/create-bug`, {
-                    method: 'PUT',
-                    headers: {
-                        'Content-Type': 'application/json'
-                    },
-                    body: JSON.stringify(requestPayload)
-                }).then(res => {
-                    if (res.ok)
-                        return res.json()
-                    return res.json().then((data) => {
-                        throw new Error(data.description);
+        
+                    buttonRef.fromEvent('click').action(e => {
+                        const requestPayload = {
+                            selectedRows: [],
+                            willFilterExpected: InvestigateDrawer.willFilterExpected,
+                            repositories: this.repositories,
+                            suite: this.suite,
+                            test: this.test
+                        };
+                        Array.from(this.selectedDots.keys()).forEach(config => {
+                            const dots = this.selectedDots.get(config);
+                            requestPayload.selectedRows.push({
+                                config,
+                                results: dots
+                            });
+                        });
+                        buttonRef.setState({loading: true});
+                        fetch(`api/bug-trackers/${bugTracker}/create-bug`, {
+                            method: 'PUT',
+                            headers: {
+                                'Content-Type': 'application/json'
+                            },
+                            body: JSON.stringify(requestPayload)
+                        }).then(res => {
+                            if (res.ok)
+                                return res.json()
+                            return res.json().then((data) => {
+                                throw new Error(data.description);
+                            });
+                        }).then(data ="" {
+                            const bugLinkElement = document.createElement('a');
+                            if (data['newWindow'])
+                                bugLinkElement.setAttribute('target', '_blank');
+                            bugLinkElement.setAttribute('href', data['url']);
+                            bugLinkElement.click();
+                        }).catch(e => {
+                            alert(e);
+                        }).finally(() => {
+                            buttonRef.setState({loading: false});
+                        });
+                        
                     });
-                }).then(data ="" {
-                    const bugLinkElement = document.createElement('a');
-                    bugLinkElement.setAttribute('href', data['url']);
-                    bugLinkElement.click();
-                }).catch(e => {
-                    alert(e);
-                }).finally(() => {
-                    buttonRef.setState({loading: false});
-                });
-                
-            });
-
-            return `<div>
-                <button class="button tiny" style="position:absolute; background: var(--purple); color: var(--white)" ref="${buttonRef}">
-                    ${buttonText}
-                </button>
-            </div>`;
-        }).join(''));
+                    return `
+                        <button class="button tiny" style="background: ${BUG_TRACKER_COLORS[bugTracker]}; color: var(--white)" ref="${buttonRef}">
+                            ${buttonText}
+                        </button>`;
+                }).join('')}
+            </div>`);
     }
 
     render(limit) {
@@ -994,7 +1002,7 @@
             self.notifyRerender = notifyRerender;
         }));
         return Timeline.CanvasContainer({
-            customizedLayer: `<div class="row" style="position:absolute" ref="${this.selectedDotsButtonGroupRef}"></div>`,
+            customizedLayer: `<div style="position:absolute" ref="${this.selectedDotsButtonGroupRef}"></div>`,
             onSelecting: (e) => {
                 this.selectedDotsButtonGroupRef.setState({show: false});
             },
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to