Browse Source

SONAR-21372 Deprecate old issue type project badges

tags/10.4.0.87286
Wouter Admiraal 6 months ago
parent
commit
77f502f4a7

+ 28
- 14
server/sonar-web/src/main/js/apps/projectInformation/badges/ProjectBadges.tsx View File

@@ -33,8 +33,10 @@ import { isEmpty } from 'lodash';
import * as React from 'react';
import { useState } from 'react';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { translate } from '../../../helpers/l10n';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { localizeMetric } from '../../../helpers/measures';
import {
DEPRECATED_METRIC_KEYS,
useBadgeMetricsQuery,
useBadgeTokenQuery,
useRenewBagdeTokenMutation,
@@ -130,19 +132,31 @@ export default function ProjectBadges(props: ProjectBadgesProps) {
</Spinner>

{BadgeType.measure === selectedType && (
<FormField htmlFor="badge-param-customize" label={translate('overview.badges.metric')}>
<InputSelect
className="sw-w-abs-300"
inputId="badge-param-customize"
options={metricOptions}
onChange={(option) => {
if (option) {
setSelectedMetric(option.value);
}
}}
value={metricOptions.find((m) => m.value === selectedMetric)}
/>
</FormField>
<>
<FormField htmlFor="badge-param-customize" label={translate('overview.badges.metric')}>
<InputSelect
className="sw-w-abs-300"
inputId="badge-param-customize"
options={metricOptions}
onChange={(option) => {
if (option) {
setSelectedMetric(option.value);
}
}}
value={metricOptions.find((m) => m.value === selectedMetric)}
/>
</FormField>

{DEPRECATED_METRIC_KEYS.includes(selectedMetric) && (
<FlagMessage className="sw-mb-4" variant="warning">
{translateWithParameters(
'overview.badges.deprecated_badge_x_y',
localizeMetric(selectedMetric),
translate('qualifier', qualifier),
)}
</FlagMessage>
)}
</>
)}

<BasicSeparator className="sw-mb-4" />

+ 43
- 2
server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-test.tsx View File

@@ -26,6 +26,7 @@ import { mockBranch } from '../../../../helpers/mocks/branch-like';
import { mockComponent } from '../../../../helpers/mocks/component';
import { renderComponent } from '../../../../helpers/testReactTestingUtils';
import { Location } from '../../../../helpers/urls';
import { ComponentQualifier } from '../../../../types/component';
import { MetricKey } from '../../../../types/metrics';
import ProjectBadges, { ProjectBadgesProps } from '../ProjectBadges';
import { BadgeType } from '../utils';
@@ -49,7 +50,7 @@ jest.mock('../../../../api/web-api', () => ({
{
key: 'measure',
// eslint-disable-next-line local-rules/use-metrickey-enum
params: [{ key: 'metric', possibleValues: ['alert_status', 'coverage'] }],
params: [{ key: 'metric', possibleValues: ['alert_status', 'coverage', 'bugs'] }],
},
],
},
@@ -108,13 +109,53 @@ it('should update params', async () => {
await act(async () => {
await selectEvent.openMenu(screen.getByLabelText('overview.badges.metric'));
});
fireEvent.click(screen.getByText(MetricKey.coverage));
fireEvent.click(screen.getByText(`metric.${MetricKey.coverage}.name`));

expect(
screen.getByText(
`host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=${MetricKey.coverage}&token=foo`,
),
).toBeInTheDocument();

fireEvent.click(
screen.getByRole('button', {
name: `overview.badges.${BadgeType.qualityGate}.alt overview.badges.${BadgeType.qualityGate}.description.${ComponentQualifier.Project}`,
}),
);

expect(
screen.getByText(
`host/api/project_badges/quality_gate?branch=branch-6.7&project=my-project&token=foo`,
),
).toBeInTheDocument();

fireEvent.click(
screen.getByRole('button', {
name: `overview.badges.${BadgeType.measure}.alt overview.badges.${BadgeType.measure}.description.${ComponentQualifier.Project}`,
}),
);

expect(
screen.getByText(
`host/api/project_badges/measure?branch=branch-6.7&project=my-project&metric=${MetricKey.coverage}&token=foo`,
),
).toBeInTheDocument();
});

it('should warn about deprecated metrics', async () => {
renderProjectBadges();
await appLoaded();

await act(async () => {
await selectEvent.openMenu(screen.getByLabelText('overview.badges.metric'));
});
fireEvent.click(screen.getByText(`metric.${MetricKey.bugs}.name (deprecated)`));

expect(
screen.getByText(
`overview.badges.deprecated_badge_x_y.metric.${MetricKey.bugs}.name.qualifier.${ComponentQualifier.Project}`,
),
).toBeInTheDocument();
});

async function appLoaded() {

+ 16
- 8
server/sonar-web/src/main/js/queries/badges.ts View File

@@ -19,10 +19,9 @@
*/

import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useContext } from 'react';
import { getProjectBadgesToken, renewProjectBadgesToken } from '../api/project-badges';
import { MetricsContext } from '../app/components/metrics/MetricsContext';
import { getLocalizedMetricName } from '../helpers/l10n';
import { translate } from '../helpers/l10n';
import { localizeMetric } from '../helpers/measures';
import { MetricKey } from '../types/metrics';
import { useWebApiQuery } from './web-api';

@@ -38,8 +37,15 @@ export function useRenewBagdeTokenMutation() {
});
}

// The same list of deprecated metric keys is maintained on the backend at org.sonar.server.badge.ws.MeasureAction.
export const DEPRECATED_METRIC_KEYS = [
MetricKey.bugs,
MetricKey.code_smells,
MetricKey.security_hotspots,
MetricKey.vulnerabilities,
];

export function useBadgeMetricsQuery() {
const metrics = useContext(MetricsContext);
const { data: webservices = [], ...rest } = useWebApiQuery();
const domain = webservices.find((d) => d.path === 'api/project_badges');
const ws = domain?.actions.find((w) => w.key === 'measure');
@@ -47,11 +53,13 @@ export function useBadgeMetricsQuery() {
if (param?.possibleValues) {
return {
...rest,
data: param.possibleValues.map((key) => {
const metric = metrics[key];
data: param.possibleValues.map((key: MetricKey) => {
const label = localizeMetric(key);
return {
value: key as MetricKey,
label: metric ? getLocalizedMetricName(metric) : key,
value: key,
label: DEPRECATED_METRIC_KEYS.includes(key)
? `${label} (${translate('deprecated')})`
: label,
};
}),
};

+ 4
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/badge/ws/MeasureAction.java View File

@@ -28,6 +28,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
@@ -94,6 +95,8 @@ public class MeasureAction implements ProjectBadgesWsAction {
.put(VULNERABILITIES_KEY, "vulnerabilities")
.build();

private static final String[] DEPRECATED_METRIC_KEYS = {BUGS_KEY, CODE_SMELLS_KEY, SECURITY_HOTSPOTS_KEY, VULNERABILITIES_KEY};

private static final Map<Level, String> QUALITY_GATE_MESSAGE_BY_STATUS = new EnumMap<>(Map.of(
OK, "passed",
ERROR, "failed"));
@@ -126,6 +129,7 @@ public class MeasureAction implements ProjectBadgesWsAction {
.setDescription("Generate badge for project's measure as an SVG.<br/>" +
"Requires 'Browse' permission on the specified project.")
.setSince("7.1")
.setChangelog(new Change("10.4", String.format("The following metric keys are now deprecated: %s", String.join(", ", DEPRECATED_METRIC_KEYS))))
.setResponseExample(Resources.getResource(getClass(), "measure-example.svg"));
support.addProjectAndBranchParams(action);
action.createParam(PARAM_METRIC)

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

@@ -4001,6 +4001,7 @@ overview.badges.quality_gate.description.VW=Displays the current quality gate st
overview.badges.leak_warning=Project badges can expose your security rating and other measures. Only use project badges in trusted environments.
overview.badges.renew=Renew Token
overview.badges.renew.description=If your project badge security token has leaked to an unsafe environment, you can renew it:
overview.badges.deprecated_badge_x_y=Badges displaying {0} are deprecated and will be removed in a future version. Please choose another badge for your {1}.

overview.quality_profiles_update_after_sq_upgrade.message=Upgrade to SonarQube {sqVersion} has updated your Quality Profiles. Issues on your project may have been affected. {link}
overview.quality_profiles_update_after_sq_upgrade.link=See more details

Loading…
Cancel
Save