assertThat(definition.key()).isEqualTo("anticipated_transitions");
assertThat(definition.description()).isEqualTo("""
Receive a list of anticipated transitions that can be applied to not yet discovered issues on a specific project.<br>
- Requires the following permission: 'Administer' on the specified project.<br><br>
+ Requires the following permission: 'Administer Issues' on the specified project.<br>
+ Only <code>falsepositive</code> and <code>wontfix</code> transitions are supported.<br>
Upon successful execution, the HTTP status code returned is 202 (Accepted).<br><br>
Request example:
- <pre><code>
- [
+ <pre><code>[
{
"ruleKey": "squid:S0001",
"issueMessage": "issueMessage1",
"filePath": "filePath1",
"line": 1,
"lineHash": "lineHash1",
- "transition": "transition1",
+ "transition": "falsepositive",
"comment": "comment1"
},
{
"filePath": "filePath2",
"line": 2,
"lineHash": "lineHash2",
- "transition": "transition2",
+ "transition": "wontfix",
"comment": "comment2"
}
- ]""");
+ ]</code></pre>""");
assertThat(definition.isPost()).isTrue();
assertThat(definition.isInternal()).isTrue();
assertThat(definition.params()).extracting(WebService.Param::key, WebService.Param::isRequired, WebService.Param::description, WebService.Param::since).containsExactlyInAnyOrder(
"filePath": "filePath3",
"line": 3,
"lineHash": "lineHash3",
- "transition": "transition3",
+ "transition": "wontfix",
"comment": "comment3"
}
]""";
import com.google.gson.Gson;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
import org.sonar.api.rule.RuleKey;
import org.sonar.core.issue.AnticipatedTransition;
public class AnticipatedTransitionParser {
private static final Gson GSON = new Gson();
+ private static final String WONTFIX = "wontfix";
+ private static final String FALSEPOSITIVE = "falsepositive";
+ private static final Set<String> ALLOWED_TRANSITIONS = Set.of(WONTFIX, FALSEPOSITIVE);
+ private static final String TRANSITION_NOT_SUPPORTED_ERROR_MESSAGE = "Transition '%s' not supported. Only 'wontfix' and 'falsepositive' are supported.";
public List<AnticipatedTransition> parse(String requestBody, String userUuid, String projectKey) {
+ List<GsonAnticipatedTransition> anticipatedTransitions;
try {
- List<GsonAnticipatedTransition> anticipatedTransitions = Arrays.asList(GSON.fromJson(requestBody, GsonAnticipatedTransition[].class));
- return mapBodyToAnticipatedTransitions(anticipatedTransitions, userUuid, projectKey);
+ anticipatedTransitions = Arrays.asList(GSON.fromJson(requestBody, GsonAnticipatedTransition[].class));
} catch (Exception e) {
throw new IllegalStateException("Unable to parse anticipated transitions from request body.", e);
}
+ validateAnticipatedTransitions(anticipatedTransitions);
+ return mapBodyToAnticipatedTransitions(anticipatedTransitions, userUuid, projectKey);
+ }
+
+ private static void validateAnticipatedTransitions(List<GsonAnticipatedTransition> anticipatedTransitions) {
+ for (GsonAnticipatedTransition anticipatedTransition : anticipatedTransitions) {
+ if (!ALLOWED_TRANSITIONS.contains(anticipatedTransition.transition())) {
+ throw new IllegalArgumentException(String.format(TRANSITION_NOT_SUPPORTED_ERROR_MESSAGE, anticipatedTransition.transition()));
+ }
+ }
}
private static List<AnticipatedTransition> mapBodyToAnticipatedTransitions(List<GsonAnticipatedTransition> anticipatedTransitions, String userUuid, String projectKey) {
public void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction(IssuesWsParameters.ACTION_ANTICIPATED_TRANSITIONS).setDescription("""
Receive a list of anticipated transitions that can be applied to not yet discovered issues on a specific project.<br>
- Requires the following permission: 'Administer' on the specified project.<br><br>
+ Requires the following permission: 'Administer Issues' on the specified project.<br>
+ Only <code>falsepositive</code> and <code>wontfix</code> transitions are supported.<br>
Upon successful execution, the HTTP status code returned is 202 (Accepted).<br><br>
Request example:
- <pre><code>
- [
+ <pre><code>[
{
"ruleKey": "squid:S0001",
"issueMessage": "issueMessage1",
"filePath": "filePath1",
"line": 1,
"lineHash": "lineHash1",
- "transition": "transition1",
+ "transition": "falsepositive",
"comment": "comment1"
},
{
"filePath": "filePath2",
"line": 2,
"lineHash": "lineHash2",
- "transition": "transition2",
+ "transition": "wontfix",
"comment": "comment2"
}
- ]""")
+ ]</code></pre>""")
.setSince("10.2")
.setHandler(this)
.setInternal(true)
.hasMessage("Unable to parse anticipated transitions from request body.");
}
+ @Test
+ public void givenRequestBodyWithInvalidTransition_whenParse_thenExceptionIsThrown() throws IOException {
+ // given
+ String requestBodyWithInvalidTransition = """
+ [
+ {
+ "ruleKey": "squid:S0001",
+ "issueMessage": "issueMessage1",
+ "filePath": "filePath1",
+ "line": 1,
+ "lineHash": "lineHash1",
+ "transition": "invalid-transition",
+ "comment": "comment1"
+ },
+ ]
+ """;
+
+ // when
+ Assertions.assertThatThrownBy(() -> underTest.parse(requestBodyWithInvalidTransition, USER_UUID, PROJECT_KEY))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Transition 'invalid-transition' not supported. Only 'wontfix' and 'falsepositive' are supported.");
+ }
+
// Handwritten Anticipated Transitions that are expected from the request-with-transitions.json file
private List<AnticipatedTransition> transitionsExpectedFromTestFile() {
return List.of(
"filePath1",
1,
"lineHash1",
- "transition1",
+ "wontfix",
"comment1"),
new AnticipatedTransition(
PROJECT_KEY,
"filePath2",
2,
"lineHash2",
- "transition2",
+ "falsepositive",
"comment2"));
}
return Files.readString(Path.of(getClass().getResource(fileName).getPath()));
}
-}
\ No newline at end of file
+}
"filePath": "filePath1",
"line": 1,
"lineHash": "lineHash1",
- "transition": "transition1",
+ "transition": "wontfix",
"comment": "comment1"
},
{
"filePath": "filePath2",
"line": 2,
"lineHash": "lineHash2",
- "transition": "transition2",
+ "transition": "falsepositive",
"comment": "comment2"
}
]
\ No newline at end of file