aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorssjenka <ssjenka@ops-slave-centos7-1.internal.sonarsource.com>2016-07-20 14:08:36 +0200
committerssjenka <ssjenka@ops-slave-centos7-1.internal.sonarsource.com>2016-07-20 14:08:36 +0200
commitdf745897a5324ab8e758c41a061c60ef1ebeafa4 (patch)
tree342838623da8c5c11c8976a6fb5636543feeab8a
parent8de259eee63931e09904c924e20d6caa5f6e8a87 (diff)
parentdeb971fda70db26fc00932db6cb0cfdad95d3299 (diff)
downloadsonarqube-df745897a5324ab8e758c41a061c60ef1ebeafa4.tar.gz
sonarqube-df745897a5324ab8e758c41a061c60ef1ebeafa4.zip
Automatic merge from branch-6.0
* origin/branch-6.0: do not display 0 on overview page when no profiles SONAR-7492 display rating tooltips on measures page Improve Authentication ITs SONAR-7761 Restore error in login page when not even privilege [maven-release-plugin] prepare for next development iteration [maven-release-plugin] prepare release 6.0-RC1
-rw-r--r--it/it-tests/src/test/java/it/user/ForceAuthenticationTest.java82
-rw-r--r--it/it-tests/src/test/java/it/user/LocalAuthenticationTest.java32
-rw-r--r--it/it-tests/src/test/resources/user/LocalAuthenticationTest/redirect_to_login_when_not_enough_privilege.html59
-rw-r--r--it/it-tests/src/test/resources/user/LocalAuthenticationTest/should_not_be_unlogged_when_going_to_login_page.html64
-rw-r--r--server/sonar-ce/pom.xml3
-rw-r--r--server/sonar-process/pom.xml3
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/Measure.js19
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/utils.js14
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/enhance.js29
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/Meta.js2
-rw-r--r--server/sonar-web/src/main/js/helpers/measures.js29
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/_form.html.erb11
-rw-r--r--sonar-db/pom.xml3
13 files changed, 250 insertions, 100 deletions
diff --git a/it/it-tests/src/test/java/it/user/ForceAuthenticationTest.java b/it/it-tests/src/test/java/it/user/ForceAuthenticationTest.java
index 58788abf9bf..f0b9c074d4d 100644
--- a/it/it-tests/src/test/java/it/user/ForceAuthenticationTest.java
+++ b/it/it-tests/src/test/java/it/user/ForceAuthenticationTest.java
@@ -21,21 +21,20 @@ package it.user;
import com.sonar.orchestrator.Orchestrator;
import it.Category4Suite;
-import java.io.IOException;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.util.EntityUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.sonar.wsclient.base.HttpException;
-import org.sonar.wsclient.services.PropertyDeleteQuery;
-import org.sonar.wsclient.services.PropertyUpdateQuery;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.WsClient;
+import org.sonarqube.ws.client.WsResponse;
import util.QaOnly;
import static org.assertj.core.api.Assertions.assertThat;
+import static util.ItUtils.newAdminWsClient;
+import static util.ItUtils.newWsClient;
+import static util.ItUtils.setServerProperty;
@Category(QaOnly.class)
public class ForceAuthenticationTest {
@@ -43,48 +42,43 @@ public class ForceAuthenticationTest {
@ClassRule
public static final Orchestrator orchestrator = Category4Suite.ORCHESTRATOR;
- /**
- * SONAR-5542
- */
- @Test
- public void force_authentication_should_be_used_on_java_web_services_but_not_on_batch_index_and_file() throws IOException {
- try {
- orchestrator.getServer().getAdminWsClient().update(new PropertyUpdateQuery("sonar.forceAuthentication", "true"));
+ static WsClient wsClient;
+ static WsClient adminWsClient;
- // /batch/index should never need authentication
- String batchIndex = orchestrator.getServer().wsClient().get("/batch/index");
- assertThat(batchIndex).isNotEmpty();
+ @BeforeClass
+ public static void setUp() throws Exception {
+ setServerProperty(orchestrator, "sonar.forceAuthentication", "true");
+ wsClient = newWsClient(orchestrator);
+ adminWsClient = newAdminWsClient(orchestrator);
+ }
- String jar = batchIndex.split("\\|")[0];
+ @AfterClass
+ public static void tearDown() throws Exception {
+ setServerProperty(orchestrator, "sonar.forceAuthentication", null);
+ }
- // /batch/file should never need authentication
- HttpClient httpclient = new DefaultHttpClient();
- try {
- HttpGet get = new HttpGet(orchestrator.getServer().getUrl() + "/batch/file?name=" + jar);
- HttpResponse response = httpclient.execute(get);
- assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
- EntityUtils.consume(response.getEntity());
+ @Test
+ public void batch_ws_does_not_require_authentication() throws Exception {
+ WsResponse batchIndex = wsClient.wsConnector().call(new GetRequest("/batch/index")).failIfNotSuccessful();
+ String batchIndexContent = batchIndex.content();
- // As Sonar runner is still using /batch/key, we have to also verify it
- get = new HttpGet(orchestrator.getServer().getUrl() + "/batch/" + jar);
- response = httpclient.execute(get);
- assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
- EntityUtils.consume(response.getEntity());
+ assertThat(batchIndexContent).isNotEmpty();
+ String jar = batchIndexContent.split("\\|")[0];
- } finally {
- httpclient.getConnectionManager().shutdown();
- }
+ assertThat(wsClient.wsConnector().call(
+ new GetRequest("/batch/file").setParam("name", jar)).failIfNotSuccessful().contentStream()).isNotNull();
- // but other java web services should need authentication
- try {
- orchestrator.getServer().wsClient().get("/api");
- } catch (HttpException e) {
- assertThat(e.getMessage()).contains("401");
- }
+ // As sonar-runner is still using deprecated /batch/key, we have to also verify it
+ assertThat(wsClient.wsConnector().call(new GetRequest("/batch/" + jar)).failIfNotSuccessful().contentStream()).isNotNull();
+ }
+
+ @Test
+ public void other_ws_require_authentication() throws Exception {
+ assertThat(wsClient.wsConnector().call(new GetRequest("/api/issues/search")).code()).isEqualTo(401);
+ assertThat(adminWsClient.wsConnector().call(new GetRequest("/api/issues/search")).code()).isEqualTo(200);
- } finally {
- orchestrator.getServer().getAdminWsClient().delete(new PropertyDeleteQuery("sonar.forceAuthentication"));
- }
+ assertThat(wsClient.wsConnector().call(new GetRequest("/api/rules/search")).code()).isEqualTo(401);
+ assertThat(adminWsClient.wsConnector().call(new GetRequest("/api/rules/search")).code()).isEqualTo(200);
}
}
diff --git a/it/it-tests/src/test/java/it/user/LocalAuthenticationTest.java b/it/it-tests/src/test/java/it/user/LocalAuthenticationTest.java
index 83019aecd2f..8026250318b 100644
--- a/it/it-tests/src/test/java/it/user/LocalAuthenticationTest.java
+++ b/it/it-tests/src/test/java/it/user/LocalAuthenticationTest.java
@@ -86,6 +86,8 @@ public class LocalAuthenticationTest {
userRule.createUser(LOGIN, "123456");
addUserPermission(LOGIN, "admin");
addUserPermission(LOGIN, "scan");
+
+ userRule.createUser("simple-user", "password");
}
@AfterClass
@@ -204,18 +206,18 @@ public class LocalAuthenticationTest {
new SeleneseTest(Selenese.builder().setHtmlTestsInClasspath("authentication",
"/user/LocalAuthenticationTest/login_successful.html",
"/user/LocalAuthenticationTest/login_wrong_password.html",
+ "/user/LocalAuthenticationTest/should_not_be_unlogged_when_going_to_login_page.html",
+ "/user/LocalAuthenticationTest/redirect_to_login_when_not_enough_privilege.html",
// SONAR-2132
"/user/LocalAuthenticationTest/redirect_to_original_url_after_direct_login.html",
// SONAR-2009
- "/user/LocalAuthenticationTest/redirect_to_original_url_after_indirect_login.html"
- ).build()).runOn(ORCHESTRATOR);
+ "/user/LocalAuthenticationTest/redirect_to_original_url_after_indirect_login.html").build()).runOn(ORCHESTRATOR);
setServerProperty(ORCHESTRATOR, "sonar.forceAuthentication", "true");
new SeleneseTest(Selenese.builder().setHtmlTestsInClasspath("force-authentication",
// SONAR-3473
- "/user/LocalAuthenticationTest/force-authentication.html"
- ).build()).runOn(ORCHESTRATOR);
+ "/user/LocalAuthenticationTest/force-authentication.html").build()).runOn(ORCHESTRATOR);
}
@Test
@@ -238,19 +240,19 @@ public class LocalAuthenticationTest {
*/
@Test
public void authentication_with_any_ws() throws Exception {
- assertThat(checkAuthenticationWithAnyWebService("admin", "admin").code()).isEqualTo(200);
- assertThat(checkAuthenticationWithAnyWebService("wrong", "admin").code()).isEqualTo(401);
- assertThat(checkAuthenticationWithAnyWebService("admin", "wrong").code()).isEqualTo(401);
- assertThat(checkAuthenticationWithAnyWebService("admin", null).code()).isEqualTo(401);
- assertThat(checkAuthenticationWithAnyWebService(null, null).code()).isEqualTo(200);
+ assertThat(checkAuthenticationWithAnyWS("admin", "admin").code()).isEqualTo(200);
+ assertThat(checkAuthenticationWithAnyWS("wrong", "admin").code()).isEqualTo(401);
+ assertThat(checkAuthenticationWithAnyWS("admin", "wrong").code()).isEqualTo(401);
+ assertThat(checkAuthenticationWithAnyWS("admin", null).code()).isEqualTo(401);
+ assertThat(checkAuthenticationWithAnyWS(null, null).code()).isEqualTo(200);
setServerProperty(ORCHESTRATOR, "sonar.forceAuthentication", "true");
- assertThat(checkAuthenticationWithAnyWebService("admin", "admin").code()).isEqualTo(200);
- assertThat(checkAuthenticationWithAnyWebService("wrong", "admin").code()).isEqualTo(401);
- assertThat(checkAuthenticationWithAnyWebService("admin", "wrong").code()).isEqualTo(401);
- assertThat(checkAuthenticationWithAnyWebService("admin", null).code()).isEqualTo(401);
- assertThat(checkAuthenticationWithAnyWebService(null, null).code()).isEqualTo(401);
+ assertThat(checkAuthenticationWithAnyWS("admin", "admin").code()).isEqualTo(200);
+ assertThat(checkAuthenticationWithAnyWS("wrong", "admin").code()).isEqualTo(401);
+ assertThat(checkAuthenticationWithAnyWS("admin", "wrong").code()).isEqualTo(401);
+ assertThat(checkAuthenticationWithAnyWS("admin", null).code()).isEqualTo(401);
+ assertThat(checkAuthenticationWithAnyWS(null, null).code()).isEqualTo(401);
}
private boolean checkAuthenticationWithAuthenticateWebService(String login, String password) {
@@ -258,7 +260,7 @@ public class LocalAuthenticationTest {
return result.contains("{\"valid\":true}");
}
- private WsResponse checkAuthenticationWithAnyWebService(String login, String password) {
+ private WsResponse checkAuthenticationWithAnyWS(String login, String password) {
WsClient wsClient = WsClientFactories.getDefault().newClient(HttpConnector.newBuilder().url(ORCHESTRATOR.getServer().getUrl()).credentials(login, password).build());
// Call any WS
return wsClient.wsConnector().call(new GetRequest("api/rules/search"));
diff --git a/it/it-tests/src/test/resources/user/LocalAuthenticationTest/redirect_to_login_when_not_enough_privilege.html b/it/it-tests/src/test/resources/user/LocalAuthenticationTest/redirect_to_login_when_not_enough_privilege.html
new file mode 100644
index 00000000000..3fbb9ddb8ac
--- /dev/null
+++ b/it/it-tests/src/test/resources/user/LocalAuthenticationTest/redirect_to_login_when_not_enough_privilege.html
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <title>redirect-to-original-url-after-direct-login</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+ <tbody>
+ <tr>
+ <td>open</td>
+ <td>/sessions/new</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>id=login</td>
+ <td>simple-user</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>id=password</td>
+ <td>password</td>
+</tr>
+<tr>
+ <td>clickAndWait</td>
+ <td>commit</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>css=.js-user-authenticated</td>
+ <td></td>
+</tr>
+<tr>
+ <td>open</td>
+ <td>/settings</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>content</td>
+ <td>*You are not authorized to access this page. Please log in with more privileges and try again.*</td>
+</tr>
+</tbody>
+</table>
+</body>
+</html>
diff --git a/it/it-tests/src/test/resources/user/LocalAuthenticationTest/should_not_be_unlogged_when_going_to_login_page.html b/it/it-tests/src/test/resources/user/LocalAuthenticationTest/should_not_be_unlogged_when_going_to_login_page.html
new file mode 100644
index 00000000000..66a0ab89a51
--- /dev/null
+++ b/it/it-tests/src/test/resources/user/LocalAuthenticationTest/should_not_be_unlogged_when_going_to_login_page.html
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <title>redirect-to-original-url-after-direct-login</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+ <tbody>
+ <tr>
+ <td>open</td>
+ <td>/sessions/new</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>id=login</td>
+ <td>simple-user</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>id=password</td>
+ <td>password</td>
+</tr>
+<tr>
+ <td>clickAndWait</td>
+ <td>commit</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>css=.js-user-authenticated</td>
+ <td></td>
+</tr>
+<tr>
+ <td>open</td>
+ <td>/sessions/new</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForText</td>
+ <td>content</td>
+ <td>*Log In to SonarQube*</td>
+</tr>
+<tr>
+ <td>open</td>
+ <td>/</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForText</td>
+ <td>css=.js-user-authenticated</td>
+ <td>*simple-user*</td>
+</tr>
+</tbody>
+</table>
+</body>
+</html>
diff --git a/server/sonar-ce/pom.xml b/server/sonar-ce/pom.xml
index 4f698206011..1f9475d8974 100644
--- a/server/sonar-ce/pom.xml
+++ b/server/sonar-ce/pom.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sonarsource.sonarqube</groupId>
diff --git a/server/sonar-process/pom.xml b/server/sonar-process/pom.xml
index 6856c68f396..a7b919bc341 100644
--- a/server/sonar-process/pom.xml
+++ b/server/sonar-process/pom.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sonarsource.sonarqube</groupId>
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/Measure.js b/server/sonar-web/src/main/js/apps/component-measures/components/Measure.js
index a83267a0242..d8e8253130a 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/Measure.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/Measure.js
@@ -18,17 +18,30 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-
import Rating from '../../../components/ui/Rating';
import Level from '../../../components/ui/Level';
import { formatMeasure } from '../../../helpers/measures';
-import { formatLeak, isDiffMetric } from '../utils';
+import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin';
+import { formatLeak, isDiffMetric, getRatingTooltip } from '../utils';
const Measure = ({ measure, metric }) => {
const finalMetric = metric || measure.metric;
if (finalMetric.type === 'RATING') {
- return <Rating value={measure.value}/>;
+ const tooltip = getRatingTooltip(finalMetric.key, measure.value);
+ const rating = <Rating value={measure.value}/>;
+ if (tooltip) {
+ return (
+ <TooltipsContainer>
+ <span>
+ <span title={tooltip} data-toggle="tooltip">
+ {rating}
+ </span>
+ </span>
+ </TooltipsContainer>
+ );
+ }
+ return rating;
}
if (finalMetric.type === 'LEVEL') {
diff --git a/server/sonar-web/src/main/js/apps/component-measures/utils.js b/server/sonar-web/src/main/js/apps/component-measures/utils.js
index c7bd18ca7e3..076053498ab 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/utils.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/utils.js
@@ -18,7 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import bubbles from './config/bubbles';
-import { formatMeasure, formatMeasureVariation } from '../../helpers/measures';
+import {
+ formatMeasure,
+ formatMeasureVariation,
+ getRatingTooltip as nextGetRatingTooltip
+} from '../../helpers/measures';
export function isDiffMetric (metric) {
return metric.key.indexOf('new_') === 0;
@@ -113,3 +117,11 @@ export function hasTreemap (metric) {
export function filterOutEmptyMeasures (components) {
return components.filter(component => component.value !== null || component.leak !== null);
}
+
+export function getRatingTooltip (metricKey, value) {
+ const KNOWN_RATINGS = ['sqale_rating', 'reliability_rating', 'security_rating'];
+ if (KNOWN_RATINGS.includes(metricKey)) {
+ return nextGetRatingTooltip(metricKey, value);
+ }
+ return null;
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/enhance.js b/server/sonar-web/src/main/js/apps/overview/main/enhance.js
index 91f3b8a37b4..26e57e1afa7 100644
--- a/server/sonar-web/src/main/js/apps/overview/main/enhance.js
+++ b/server/sonar-web/src/main/js/apps/overview/main/enhance.js
@@ -34,7 +34,7 @@ import {
import { translateWithParameters, translate } from '../../../helpers/l10n';
import { getPeriodDate } from '../../../helpers/periods';
import { getComponentIssuesUrl } from '../../../helpers/urls';
-import { getMaintainabilityRatingGrid } from '../../../helpers/measures';
+import { getRatingTooltip } from '../../../helpers/measures';
export default function enhance (ComposedComponent) {
return class extends React.Component {
@@ -132,27 +132,6 @@ export default function enhance (ComposedComponent) {
);
}
- getMaintainabilityRatingTooltip (rating) {
- const maintainabilityGrid = getMaintainabilityRatingGrid();
- const maintainabilityRatingThreshold =
- maintainabilityGrid[Math.floor(rating) - 2];
-
- console.log(maintainabilityGrid[0]);
-
- if (rating < 2) {
- return translateWithParameters(
- 'metric.sqale_rating.tooltip.A',
- `${maintainabilityGrid[0]}%`);
- }
-
- const ratingLetter = formatMeasure(rating, 'RATING');
-
- return translateWithParameters(
- 'metric.sqale_rating.tooltip',
- ratingLetter,
- `${maintainabilityRatingThreshold}%`);
- }
-
renderRating (metricKey) {
const { component, measures } = this.props;
const measure = measures.find(measure => measure.metric.key === metricKey);
@@ -161,11 +140,7 @@ export default function enhance (ComposedComponent) {
return null;
}
- const ratingLetter = formatMeasure(measure.value, 'RATING');
-
- const title = metricKey === 'sqale_rating' ?
- this.getMaintainabilityRatingTooltip(measure.value) :
- translate('metric', metricKey, 'tooltip', ratingLetter);
+ const title = getRatingTooltip(metricKey, measure.value);
return (
<div className="overview-domain-measure-sup"
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/Meta.js b/server/sonar-web/src/main/js/apps/overview/meta/Meta.js
index 70d5a4d6be0..34fd17dc77a 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/Meta.js
+++ b/server/sonar-web/src/main/js/apps/overview/meta/Meta.js
@@ -34,7 +34,7 @@ const Meta = ({ component }) => {
const hasDescription = !!description;
const hasLinks = Array.isArray(links) && !!links.length;
- const hasQualityProfiles = Array.isArray(profiles) && profiles.length;
+ const hasQualityProfiles = Array.isArray(profiles) && profiles.length > 0;
const hasQualityGate = !!gate;
const shouldShowQualityProfiles = !isView && !isDeveloper && hasQualityProfiles;
diff --git a/server/sonar-web/src/main/js/helpers/measures.js b/server/sonar-web/src/main/js/helpers/measures.js
index a3e181e04cb..064c7733cf8 100644
--- a/server/sonar-web/src/main/js/helpers/measures.js
+++ b/server/sonar-web/src/main/js/helpers/measures.js
@@ -370,7 +370,7 @@ function shortDurationVariationFormatter (value) {
let maintainabilityRatingGrid;
-export function getMaintainabilityRatingGrid () {
+function getMaintainabilityRatingGrid () {
if (maintainabilityRatingGrid) {
return maintainabilityRatingGrid;
}
@@ -388,3 +388,30 @@ export function getMaintainabilityRatingGrid () {
return maintainabilityRatingGrid;
}
+
+function getMaintainabilityRatingTooltip (rating) {
+ const maintainabilityGrid = getMaintainabilityRatingGrid();
+ const maintainabilityRatingThreshold =
+ maintainabilityGrid[Math.floor(rating) - 2];
+
+ if (rating < 2) {
+ return translateWithParameters(
+ 'metric.sqale_rating.tooltip.A',
+ `${maintainabilityGrid[0]}%`);
+ }
+
+ const ratingLetter = formatMeasure(rating, 'RATING');
+
+ return translateWithParameters(
+ 'metric.sqale_rating.tooltip',
+ ratingLetter,
+ `${maintainabilityRatingThreshold}%`);
+}
+
+export function getRatingTooltip (metricKey, value) {
+ const ratingLetter = formatMeasure(value, 'RATING');
+
+ return metricKey === 'sqale_rating' ?
+ getMaintainabilityRatingTooltip(value) :
+ translate('metric', metricKey, 'tooltip', ratingLetter);
+}
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/_form.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/_form.html.erb
index 4495fffa997..3cb6a3187e0 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/_form.html.erb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/_form.html.erb
@@ -22,7 +22,13 @@
<form id="login_form" action="<%= ApplicationController.root_context -%>/api/authentication/login" method="post">
<input type="hidden" name="return_to_anchor" value="<%= h @return_to_anchor %>">
- <div class="alert alert-danger hidden"><%= message('session.flash_notice.authentication_failed') %></div>
+ <div class="alert alert-danger alert-authentication-failed hidden"><%= message('session.flash_notice.authentication_failed') %></div>
+ <% if flash[:loginerror] %>
+ <div class="alert alert-danger alert-flash"> <%= flash[:loginerror] %></div>
+ <% end %>
+ <% if flash[:notice] %>
+ <div class="alert alert-info alert-flash"><%= flash[:notice] %></div>
+ <% end %>
<div class="big-spacer-bottom">
<label for="login" class="login-label"><%= message('login') %></label>
@@ -62,7 +68,8 @@
window.location = '<%= h(@return_to) -%>' + $('[name="return_to_anchor"]').val();
},
error: function () {
- $('.alert').removeClass('hidden');
+ $('.alert-flash').addClass('hidden');
+ $('.alert-authentication-failed').removeClass('hidden');
$('button').prop('disabled', false);
},
statusCode: {
diff --git a/sonar-db/pom.xml b/sonar-db/pom.xml
index e1d12fac324..9b3e737b3c3 100644
--- a/sonar-db/pom.xml
+++ b/sonar-db/pom.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>