Browse Source

SONAR-7847 Add a way to see scanner context in the background page

tags/6.1-RC1
Stas Vilchik 7 years ago
parent
commit
87c95bc05d

+ 23
- 3
it/it-tests/src/test/java/it/projectAdministration/BackgroundTasksTest.java View File

@@ -23,8 +23,12 @@ import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.build.SonarScanner;
import com.sonar.orchestrator.selenium.Selenese;
import it.Category1Suite;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import pageobjects.BackgroundTaskItem;
import pageobjects.BackgroundTasksPage;
import pageobjects.Navigation;
import util.selenium.SeleneseTest;

import static util.ItUtils.projectDir;
@@ -34,18 +38,34 @@ public class BackgroundTasksTest {
@ClassRule
public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR;

@Test
public void should_not_display_failing_and_search_and_filter_elements_on_project_level_page() throws Exception {
@BeforeClass
public static void beforeClass() {
executeBuild("test-project", "Test Project");
executeBuild("test-project-2", "Another Test Project");
}

@Test
public void should_not_display_failing_and_search_and_filter_elements_on_project_level_page() throws Exception {
Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("should_not_display_failing_and_search_and_filter_elements_on_project_level_page",
"/projectAdministration/BackgroundTasksTest/should_not_display_failing_and_search_and_filter_elements_on_project_level_page.html"
).build();
new SeleneseTest(selenese).runOn(orchestrator);
}

private void executeBuild(String projectKey, String projectName) {
@Test
public void display_scanner_context() {
Navigation nav = Navigation.get(orchestrator);
nav.openHomepage().logIn().submitCredentials("admin", "admin");
BackgroundTasksPage page = nav.openBackgroundTasksPage();

BackgroundTaskItem task = page.getTasksAsItems().get(0);
task.openActions()
.openScannerContext()
.assertScannerContextContains("SonarQube plugins:")
.assertScannerContextContains("Global properties:");
}

private static void executeBuild(String projectKey, String projectName) {
orchestrator.executeBuild(
SonarScanner.create(projectDir("shared/xoo-sample"))
.setProjectKey(projectKey)

+ 56
- 0
it/it-tests/src/test/java/pageobjects/BackgroundTaskItem.java View File

@@ -0,0 +1,56 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package pageobjects;

import com.codeborne.selenide.SelenideElement;

import static com.codeborne.selenide.Condition.hasText;
import static com.codeborne.selenide.Condition.visible;
import static com.codeborne.selenide.Selenide.$;

public class BackgroundTaskItem {

private final SelenideElement elt;

public BackgroundTaskItem(SelenideElement elt) {
this.elt = elt;
}

public SelenideElement getComponent() {
return elt.$("td:nth-child(2)");
}

public BackgroundTaskItem openActions() {
elt.$(".js-task-action > .dropdown-toggle").click();
elt.$(".js-task-action > .dropdown-menu").shouldBe(visible);
return this;
}

public BackgroundTaskItem openScannerContext () {
elt.$(".js-task-show-scanner-context").click();
$(".js-task-scanner-context").shouldBe(visible);
return this;
}

public BackgroundTaskItem assertScannerContextContains(String text) {
$(".js-task-scanner-context").should(hasText(text));
return this;
}
}

+ 47
- 0
it/it-tests/src/test/java/pageobjects/BackgroundTasksPage.java View File

@@ -0,0 +1,47 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package pageobjects;

import com.codeborne.selenide.ElementsCollection;
import java.util.List;
import java.util.stream.Collectors;
import org.openqa.selenium.By;

import static com.codeborne.selenide.Condition.exist;
import static com.codeborne.selenide.Selenide.$;
import static com.codeborne.selenide.Selenide.$$;

public class BackgroundTasksPage {

public BackgroundTasksPage() {
$(By.cssSelector(".background-tasks")).should(exist);
}

public ElementsCollection getTasks() {
return $$(".background-tasks > tbody > tr");
}

public List<BackgroundTaskItem> getTasksAsItems() {
return getTasks()
.stream()
.map(BackgroundTaskItem::new)
.collect(Collectors.toList());
}
}

+ 4
- 0
it/it-tests/src/test/java/pageobjects/Navigation.java View File

@@ -80,6 +80,10 @@ public class Navigation extends ExternalResource {
return open(url, ProjectKeyPage.class);
}

public BackgroundTasksPage openBackgroundTasksPage() {
return open("/background_tasks", BackgroundTasksPage.class);
}

public void open(String relativeUrl) {
Selenide.open(relativeUrl);
}

+ 2
- 2
server/sonar-web/src/main/js/api/ce.js View File

@@ -39,9 +39,9 @@ export function getStatus (componentId) {
return getJSON(url, data);
}

export function getTask (id) {
export function getTask (id, additionalFields) {
const url = '/api/ce/task';
return getJSON(url, { id }).then(r => r.task);
return getJSON(url, { id, additionalFields }).then(r => r.task);
}

export function cancelTask (id) {

+ 7
- 23
server/sonar-web/src/main/js/apps/background-tasks/components/Task.js View File

@@ -19,15 +19,13 @@
*/
import React from 'react';
import shallowCompare from 'react-addons-shallow-compare';

import TaskStatus from './TaskStatus';
import TaskComponent from './TaskComponent';
import TaskId from './TaskId';
import TaskDay from './TaskDay';
import TaskDate from './TaskDate';
import TaskExecutionTime from './TaskExecutionTime';
import TaskCancelButton from './TaskCancelButton';
import { STATUSES } from './../constants';
import TaskActions from './TaskActions';

export default class Task extends React.Component {
static propTypes = {
@@ -44,13 +42,8 @@ export default class Task extends React.Component {
return shallowCompare(this, nextProps, nextState);
}

handleFilterTask (task, e) {
e.preventDefault();
this.props.onFilterTask(task);
}

render () {
const { task, index, tasks, component, types, onCancelTask } = this.props;
const { task, index, tasks, component, types, onCancelTask, onFilterTask } = this.props;

const prevTask = index > 0 ? tasks[index - 1] : null;

@@ -64,20 +57,11 @@ export default class Task extends React.Component {
<TaskDate date={task.startedAt} baseDate={task.submittedAt} format="LTS"/>
<TaskDate date={task.executedAt} baseDate={task.submittedAt} format="LTS"/>
<TaskExecutionTime task={task}/>

<td className="thin nowrap">
{!component && (
<a
onClick={this.handleFilterTask.bind(this, task)}
className="icon-filter icon-half-transparent spacer-left"
href="#"
title={`Show only "${task.componentName}" tasks`}
data-toggle="tooltip"/>
)}
{task.status === STATUSES.PENDING && (
<TaskCancelButton task={task} onCancelTask={onCancelTask}/>
)}
</td>
<TaskActions
component={component}
task={task}
onFilterTask={onFilterTask}
onCancelTask={onCancelTask}/>
</tr>
);
}

+ 86
- 0
server/sonar-web/src/main/js/apps/background-tasks/components/TaskActions.js View File

@@ -0,0 +1,86 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
import shallowCompare from 'react-addons-shallow-compare';
import ScannerContextView from '../views/ScannerContextView';
import { STATUSES } from './../constants';
import { translate } from '../../../helpers/l10n';

export default class TaskActions extends React.Component {
shouldComponentUpdate (nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}

handleFilterClick (e) {
e.preventDefault();
this.props.onFilterTask(this.props.task);
}

handleCancelClick (e) {
e.preventDefault();
this.props.onCancelTask(this.props.task);
}

handleShowScannerContextClick (e) {
e.preventDefault();
new ScannerContextView({ task: this.props.task }).render();
}

render () {
const { component, task } = this.props;

return (
<td className="thin nowrap">
<div className="dropdown js-task-action">
<button className="dropdown-toggle" data-toggle="dropdown">
<i className="icon-dropdown"/>
</button>
<ul className="dropdown-menu dropdown-menu-right">
{!component && (
<li>
<a className="js-task-filter" href="#" onClick={this.handleFilterClick.bind(this)}>
<i className="spacer-right icon-filter icon-half-transparent"/>
Show only {task.componentName} tasks
</a>
</li>
)}
{task.status === STATUSES.PENDING && (
<li>
<a className="js-task-cancel" href="#" onClick={this.handleCancelClick.bind(this)}>
<i className="spacer-right icon-delete"/>
{translate('background_tasks.cancel_task')}
</a>
</li>
)}
{task.hasScannerContext && (
<li>
<a className="js-task-show-scanner-context"
href="#"
onClick={this.handleShowScannerContextClick.bind(this)}>
{translate('background_tasks.show_scanner_context')}
</a>
</li>
)}
</ul>
</div>
</td>
);
}
}

+ 17
- 0
server/sonar-web/src/main/js/apps/background-tasks/views/ScannerContextView.hbs View File

@@ -0,0 +1,17 @@
<form id="deactivate-user-form" autocomplete="off">
<div class="modal-head">
<h2>{{t 'background_tasks.scanner_context'}}: {{task.componentName}} [{{t 'background_task.type' task.type}}]</h2>
</div>
<div class="modal-body modal-container">
<div class="js-modal-messages"></div>

{{#if scannerContext}}
<pre class="js-task-scanner-context">{{scannerContext}}</pre>
{{else}}
<i class="spinner"></i>
{{/if}}
</div>
<div class="modal-foot">
<a href="#" class="js-modal-close">{{t 'close'}}</a>
</div>
</form>

server/sonar-web/src/main/js/apps/background-tasks/components/TaskCancelButton.js → server/sonar-web/src/main/js/apps/background-tasks/views/ScannerContextView.js View File

@@ -17,23 +17,31 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
import { translate } from '../../../helpers/l10n';
import Modal from '../../../components/common/modals';
import Template from './ScannerContextView.hbs';
import { getTask } from '../../../api/ce';

const TaskCancelButton = ({ task, onCancelTask }) => {
function handleClick (e) {
e.preventDefault();
onCancelTask(task);
}
export default Modal.extend({
template: Template,
className: 'modal modal-large',

initialize () {
this.scannerContext = null;
this.loadScannerContext();
},

return (
<a
onClick={handleClick}
className="spacer-left icon-delete"
title={translate('background_tasks.cancel_task')}
data-toggle="tooltip"
href="#"/>
);
};
loadScannerContext() {
getTask(this.options.task.id, ['scannerContext']).then(task => {
this.scannerContext = task.scannerContext;
this.render();
});
},

serializeData() {
return {
task: this.options.task,
scannerContext: this.scannerContext
};
}
});

export default TaskCancelButton;

+ 2
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -2974,6 +2974,8 @@ background_tasks.table.duration=Duration
background_tasks.logs=Logs
background_tasks.cancel_task=Cancel Task
background_tasks.cancel_all_tasks=Cancel All Pending Tasks
background_tasks.scanner_context=Scanner Context
background_tasks.show_scanner_context=Show Scanner Context
background_tasks.pending=pending
background_tasks.failures=still failing
background_tasks.in_progress_duration=Duration of the current task in progress.

Loading…
Cancel
Save