import org.sonar.server.projectanalysis.ws.CreateEventAction;
import org.sonar.server.projectanalysis.ws.DeleteEventAction;
import org.sonar.server.projectanalysis.ws.ProjectAnalysesWs;
+import org.sonar.server.projectanalysis.ws.UpdateEventAction;
public class ProjectAnalysisModule extends Module {
ProjectAnalysesWs.class,
// actions
CreateEventAction.class,
+ UpdateEventAction.class,
DeleteEventAction.class);
}
};
case OTHER:
return dbEvent -> {
- throw new IllegalArgumentException(format("An 'other' event with the same name already exists on analysis '%s'", request.getAnalysis()));
+ throw new IllegalArgumentException(format("An '%s' event with the same name already exists on analysis '%s'", OTHER.getLabel(), request.getAnalysis()));
};
default:
throw new IllegalStateException("Event category not handled: " + request.getCategory());
package org.sonar.server.projectanalysis.ws;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import java.util.Set;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
-import static org.sonarqube.ws.client.projectanalysis.EventCategory.OTHER;
+import static org.sonar.server.projectanalysis.ws.EventValidator.checkModifiable;
import static org.sonarqube.ws.client.projectanalysis.EventCategory.VERSION;
import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_EVENT;
public class DeleteEventAction implements ProjectAnalysesWsAction {
- private static final Set<String> AUTHORIZED_CATEGORIES = ImmutableSet.of(VERSION.getLabel(), OTHER.getLabel());
- private static final String AUTHORIZED_CATEGORIES_INLINED = Joiner.on(", ").join(AUTHORIZED_CATEGORIES);
-
private final DbClient dbClient;
private final UserSession userSession;
EventDto dbEvent = dbClient.eventDao().selectByUuid(dbSession, request.getEvent())
.orElseThrow(() -> new NotFoundException(format("Event '%s' not found", request.getEvent())));
checkPermissions(dbEvent);
- checkArgument(AUTHORIZED_CATEGORIES.contains(dbEvent.getCategory()), "Event of category '%s' cannot be deleted. Authorized categories: %s", dbEvent.getCategory(),
- AUTHORIZED_CATEGORIES_INLINED);
+ checkModifiable().accept(dbEvent);
deleteEvent(dbSession, dbEvent);
}
--- /dev/null
+/*
+ * 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 org.sonar.server.projectanalysis.ws;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import java.util.function.Consumer;
+import org.sonar.db.event.EventDto;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+class EventValidator {
+ private static final Set<String> AUTHORIZED_CATEGORIES = ImmutableSet.of("Version", "Other");
+ private static final String AUTHORIZED_CATEGORIES_INLINED = Joiner.on(", ").join(AUTHORIZED_CATEGORIES);
+
+ static Consumer<EventDto> checkModifiable() {
+ return event -> checkArgument(AUTHORIZED_CATEGORIES.contains(event.getCategory()),
+ "Event of category '%s' cannot be modified. Authorized categories: %s",
+ event.getCategory(), AUTHORIZED_CATEGORIES_INLINED);
+ }
+}
--- /dev/null
+/*
+ * 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 org.sonar.server.projectanalysis.ws;
+
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.web.UserRole;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.event.EventDto;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.ProjectAnalyses.Event;
+import org.sonarqube.ws.ProjectAnalyses.UpdateEventResponse;
+import org.sonarqube.ws.client.projectanalysis.UpdateEventRequest;
+
+import static java.lang.String.format;
+import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.server.projectanalysis.ws.EventValidator.checkModifiable;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.projectanalysis.EventCategory.VERSION;
+import static org.sonarqube.ws.client.projectanalysis.EventCategory.fromLabel;
+import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_DESCRIPTION;
+import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_EVENT;
+import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_NAME;
+
+public class UpdateEventAction implements ProjectAnalysesWsAction {
+ private final DbClient dbClient;
+ private final UserSession userSession;
+
+ public UpdateEventAction(DbClient dbClient, UserSession userSession) {
+ this.dbClient = dbClient;
+ this.userSession = userSession;
+ }
+
+ @Override
+ public void define(WebService.NewController context) {
+ WebService.NewAction action = context.createAction("update_event")
+ .setDescription("Update a project analysis event.<br>" +
+ "Requires one of the following permissions:" +
+ "<ul>" +
+ " <li>'Administer System'</li>" +
+ " <li>'Administer' rights on the specified project</li>" +
+ "</ul>")
+ .setSince("6.3")
+ .setPost(true)
+ .setResponseExample(getClass().getResource("update_event-example.json"))
+ .setHandler(this);
+
+ action.createParam(PARAM_EVENT)
+ .setDescription("Event key")
+ .setRequired(true);
+
+ action.createParam(PARAM_NAME)
+ .setDescription("New name")
+ .setExampleValue("5.6");
+
+ action.createParam(PARAM_DESCRIPTION)
+ .setDescription("New description")
+ .setExampleValue("Version released");
+ }
+
+ @Override
+ public void handle(Request httpRequest, Response httpResponse) throws Exception {
+ Stream.of(httpRequest)
+ .map(toUpdateEventRequest())
+ .map(this::doHandle)
+ .forEach(wsResponse -> writeProtobuf(wsResponse, httpRequest, httpResponse));
+ }
+
+ private UpdateEventResponse doHandle(UpdateEventRequest request) {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ return Stream
+ .of(getDbEvent(dbSession, request))
+ .peek(checkPermissions())
+ .peek(checkModifiable())
+ .map(updateNameAndDescription(request))
+ .peek(checkNonConflictingOtherEvents(dbSession))
+ .peek(updateInDb(dbSession))
+ .map(toWsResponse())
+ .findAny()
+ .orElseThrow(() -> new IllegalStateException("Event not found"));
+ }
+ }
+
+ private Consumer<EventDto> updateInDb(DbSession dbSession) {
+ return event -> {
+ dbClient.eventDao().update(dbSession, event.getUuid(), event.getName(), event.getDescription());
+ if (VERSION.getLabel().equals(event.getCategory())) {
+ SnapshotDto analysis = getAnalysis(dbSession, event);
+ dbClient.snapshotDao().updateVersion(dbSession, analysis.getUuid(), event.getName());
+ }
+ dbSession.commit();
+ };
+ }
+
+ private EventDto getDbEvent(DbSession dbSession, UpdateEventRequest request) {
+ return dbClient.eventDao().selectByUuid(dbSession, request.getEvent())
+ .orElseThrow(() -> new NotFoundException(format("Event '%s' not found", request.getEvent())));
+ }
+
+ private Consumer<EventDto> checkPermissions() {
+ return event -> userSession.checkComponentUuidPermission(UserRole.ADMIN, event.getComponentUuid());
+ }
+
+ private Consumer<EventDto> checkNonConflictingOtherEvents(DbSession dbSession) {
+ return candidateEvent -> {
+ List<EventDto> dbEvents = dbClient.eventDao().selectByAnalysisUuid(dbSession, candidateEvent.getAnalysisUuid());
+ Predicate<EventDto> otherEventWithSameName = otherEvent -> !candidateEvent.getUuid().equals(otherEvent.getUuid()) && otherEvent.getName().equals(candidateEvent.getName());
+ dbEvents.stream()
+ .filter(otherEventWithSameName)
+ .findAny()
+ .ifPresent(event -> {
+ throw new IllegalArgumentException(format("An '%s' event with the same name already exists on analysis '%s'",
+ candidateEvent.getCategory(),
+ candidateEvent.getAnalysisUuid()));
+ });
+ };
+ }
+
+ private SnapshotDto getAnalysis(DbSession dbSession, EventDto event) {
+ return dbClient.snapshotDao().selectByUuid(dbSession, event.getAnalysisUuid())
+ .orElseThrow(() -> new IllegalStateException(format("Analysis '%s' is not found", event.getAnalysisUuid())));
+ }
+
+ private static Function<EventDto, EventDto> updateNameAndDescription(UpdateEventRequest request) {
+ return event -> {
+ setNullable(request.getName(), event::setName);
+ setNullable(request.getDescription(), event::setDescription);
+ return event;
+ };
+ }
+
+ private static Function<EventDto, UpdateEventResponse> toWsResponse() {
+ return dbEvent -> {
+ Event.Builder wsEvent = Event.newBuilder()
+ .setKey(dbEvent.getUuid())
+ .setCategory(fromLabel(dbEvent.getCategory()).name())
+ .setAnalysis(dbEvent.getAnalysisUuid());
+ setNullable(dbEvent.getName(), wsEvent::setName);
+ setNullable(dbEvent.getDescription(), wsEvent::setDescription);
+
+ return UpdateEventResponse.newBuilder().setEvent(wsEvent).build();
+ };
+ }
+
+ private static Function<Request, UpdateEventRequest> toUpdateEventRequest() {
+ return request -> new UpdateEventRequest(
+ request.mandatoryParam(PARAM_EVENT),
+ request.param(PARAM_NAME),
+ request.param(PARAM_DESCRIPTION));
+ }
+}
--- /dev/null
+{
+ "event": {
+ "analysis": "A2",
+ "key": "E1",
+ "category": "OTHER",
+ "name": "My Custom Event",
+ "description": "event description"
+ }
+}
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new ProjectAnalysisModule().configure(container);
- assertThat(container.size()).isEqualTo(2 + 3);
+ assertThat(container.size()).isEqualTo(2 + 4);
}
}
call(request);
expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("An 'other' event with the same name already exists on analysis '" + analysis.getUuid() + "'");
+ expectedException.expectMessage("An 'Other' event with the same name already exists on analysis '" + analysis.getUuid() + "'");
call(request.setName("Project Import"));
}
db.events().insertEvent(newEvent(analysis).setUuid("E1").setCategory("Profile"));
expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Event of category 'Profile' cannot be deleted. Authorized categories: Version, Other");
+ expectedException.expectMessage("Event of category 'Profile' cannot be modified. Authorized categories: Version, Other");
call("E1");
}
--- /dev/null
+/*
+ * 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 org.sonar.server.projectanalysis.ws;
+
+import com.google.common.base.Throwables;
+import java.io.IOException;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.event.EventDto;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.ProjectAnalyses;
+import org.sonarqube.ws.ProjectAnalyses.UpdateEventResponse;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.db.component.SnapshotTesting.newAnalysis;
+import static org.sonar.db.event.EventTesting.newEvent;
+import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.client.WsRequest.Method.POST;
+import static org.sonarqube.ws.client.projectanalysis.EventCategory.OTHER;
+import static org.sonarqube.ws.client.projectanalysis.EventCategory.VERSION;
+import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_DESCRIPTION;
+import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_EVENT;
+import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_NAME;
+
+public class UpdateEventActionTest {
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public DbTester db = DbTester.create(System2.INSTANCE);
+ private DbClient dbClient = db.getDbClient();
+ private DbSession dbSession = db.getSession();
+
+ private WsActionTester ws = new WsActionTester(new UpdateEventAction(dbClient, userSession));
+
+ @Test
+ public void json_example() {
+ ComponentDto project = db.components().insertProject();
+ SnapshotDto analysis = db.components().insertSnapshot(newAnalysis(project).setUuid("A2"));
+ db.events().insertEvent(newEvent(analysis)
+ .setUuid("E1")
+ .setCategory(OTHER.getLabel())
+ .setName("Original Name")
+ .setDescription("Original Description"));
+
+ String result = ws.newRequest()
+ .setParam(PARAM_EVENT, "E1")
+ .setParam(PARAM_NAME, "My Custom Event")
+ .setParam(PARAM_DESCRIPTION, "event description")
+ .execute().getInput();
+
+ assertJson(result).isSimilarTo(getClass().getResource("update_event-example.json"));
+ }
+
+ @Test
+ public void update_name_and_description_in_db() {
+ SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto());
+ EventDto originalEvent = db.events().insertEvent(newEvent(analysis).setUuid("E1").setName("Original Name").setDescription("Original Description"));
+
+ call("E1", "name", "description");
+
+ EventDto newEvent = dbClient.eventDao().selectByUuid(dbSession, "E1").get();
+ assertThat(newEvent.getName()).isEqualTo("name");
+ assertThat(newEvent.getDescription()).isEqualTo("description");
+ assertThat(newEvent.getCategory()).isEqualTo(originalEvent.getCategory());
+ assertThat(newEvent.getDate()).isEqualTo(originalEvent.getDate());
+ assertThat(newEvent.getCreatedAt()).isEqualTo(originalEvent.getCreatedAt());
+ }
+
+ @Test
+ public void ws_response_with_updated_name_and_description() {
+ SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto());
+ EventDto originalEvent = db.events().insertEvent(newEvent(analysis).setUuid("E1").setName("Original Name").setDescription("Original Description"));
+
+ ProjectAnalyses.Event result = call("E1", "name", "description").getEvent();
+
+ assertThat(result.getName()).isEqualTo("name");
+ assertThat(result.getDescription()).isEqualTo("description");
+ assertThat(result.getCategory()).isEqualTo(OTHER.name());
+ assertThat(result.getAnalysis()).isEqualTo(originalEvent.getAnalysisUuid());
+ assertThat(result.getKey()).isEqualTo("E1");
+ }
+
+ @Test
+ public void update_VERSION_event_update_analysis_version() {
+ ComponentDto project = db.components().insertProject();
+ SnapshotDto analysis = db.components().insertSnapshot(newAnalysis(project).setVersion("5.6"));
+ db.events().insertEvent(newEvent(analysis).setUuid("E1").setCategory(VERSION.getLabel()));
+
+ call("E1", "6.3", null);
+
+ SnapshotDto updatedAnalysis = dbClient.snapshotDao().selectByUuid(dbSession, analysis.getUuid()).get();
+ assertThat(updatedAnalysis.getVersion()).isEqualTo("6.3");
+ }
+
+ @Test
+ public void update_OTHER_event_does_not_update_analysis_version() {
+ ComponentDto project = db.components().insertProject();
+ SnapshotDto analysis = db.components().insertSnapshot(newAnalysis(project).setVersion("5.6"));
+ db.events().insertEvent(newEvent(analysis).setUuid("E1").setCategory(OTHER.getLabel()));
+
+ call("E1", "6.3", null);
+
+ SnapshotDto updatedAnalysis = dbClient.snapshotDao().selectByUuid(dbSession, analysis.getUuid()).get();
+ assertThat(updatedAnalysis.getVersion()).isEqualTo("5.6");
+ }
+
+ @Test
+ public void update_name_only_in_db() {
+ SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto());
+ EventDto originalEvent = db.events().insertEvent(newEvent(analysis).setUuid("E1").setName("Original Name").setDescription("Original Description"));
+
+ call("E1", "name", null);
+
+ EventDto newEvent = dbClient.eventDao().selectByUuid(dbSession, "E1").get();
+ assertThat(newEvent.getName()).isEqualTo("name");
+ assertThat(newEvent.getDescription()).isEqualTo(originalEvent.getDescription());
+ }
+
+ @Test
+ public void update_as_project_admin() {
+ SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto("P1"));
+ db.events().insertEvent(newEvent(analysis).setUuid("E1").setName("Original Name").setDescription("Original Description"));
+ userSession.anonymous().addProjectUuidPermissions(UserRole.ADMIN, "P1");
+
+ call("E1", "name", "description");
+
+ EventDto newEvent = dbClient.eventDao().selectByUuid(dbSession, "E1").get();
+ assertThat(newEvent.getName()).isEqualTo("name");
+ assertThat(newEvent.getDescription()).isEqualTo("description");
+ }
+
+ @Test
+ public void update_description_only_in_db() {
+ SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto());
+ EventDto originalEvent = db.events().insertEvent(newEvent(analysis).setUuid("E1").setName("Original Name").setDescription("Original Description"));
+
+ call("E1", null, "description");
+
+ EventDto newEvent = dbClient.eventDao().selectByUuid(dbSession, "E1").get();
+ assertThat(newEvent.getName()).isEqualTo(originalEvent.getName());
+ assertThat(newEvent.getDescription()).isEqualTo("description");
+ }
+
+ @Test
+ public void ws_definition() {
+ WebService.Action definition = ws.getDef();
+
+ assertThat(definition.key()).isEqualTo("update_event");
+ assertThat(definition.responseExampleAsString()).isNotEmpty();
+ assertThat(definition.isPost()).isTrue();
+ assertThat(definition.since()).isEqualTo("6.3");
+ assertThat(definition.param(PARAM_EVENT).isRequired()).isTrue();
+ }
+
+ @Test
+ public void fail_if_insufficient_permissions() {
+ SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto());
+ db.events().insertEvent(newEvent(analysis).setUuid("E1"));
+ userSession.anonymous();
+
+ expectedException.expect(ForbiddenException.class);
+
+ call("E1", "name", "description");
+ }
+
+ @Test
+ public void fail_if_event_is_not_found() {
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("Event 'E42' not found");
+
+ call("E42", "name", "description");
+ }
+
+ @Test
+ public void fail_if_no_name_nor_description() {
+ SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto());
+ db.events().insertEvent(newEvent(analysis).setUuid("E1"));
+
+ expectedException.expect(IllegalArgumentException.class);
+
+ call("E1", null, null);
+ }
+
+ @Test
+ public void fail_if_category_other_than_other_or_version() {
+ SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto());
+ db.events().insertEvent(newEvent(analysis).setUuid("E1").setCategory("Profile"));
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Event of category 'Profile' cannot be modified. Authorized categories: Version, Other");
+
+ call("E1", "name", "description");
+ }
+
+ @Test
+ public void fail_if_other_event_with_same_name_on_same_analysis() {
+ SnapshotDto analysis = db.components().insertProjectAndSnapshot(newProjectDto());
+ db.events().insertEvent(newEvent(analysis).setUuid("E1").setCategory(OTHER.getLabel()).setName("E1 name"));
+ db.events().insertEvent(newEvent(analysis).setUuid("E2").setCategory(OTHER.getLabel()).setName("E2 name"));
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("An 'Other' event with the same name already exists on analysis '" + analysis.getUuid() + "'");
+
+ call("E2", "E1 name", "description");
+ }
+
+ private UpdateEventResponse call(@Nullable String eventUuid, @Nullable String name, @Nullable String description) {
+ TestRequest request = ws.newRequest()
+ .setMethod(POST.name())
+ .setMediaType(MediaTypes.PROTOBUF);
+ setNullable(eventUuid, e -> request.setParam(PARAM_EVENT, e));
+ setNullable(name, n -> request.setParam(PARAM_NAME, n));
+ setNullable(description, d -> request.setParam(PARAM_DESCRIPTION, d));
+
+ try {
+ return UpdateEventResponse.parseFrom(request.execute().getInputStream());
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+}
import java.util.List;
import java.util.Optional;
+import javax.annotation.Nullable;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
return dto;
}
+ public void update(DbSession dbSession, String uuid, @Nullable String name, @Nullable String description) {
+ mapper(dbSession).update(uuid, name, description);
+ }
+
public void delete(DbSession session, Long id) {
mapper(session).deleteById(id);
}
package org.sonar.db.event;
import java.util.List;
+import javax.annotation.Nullable;
+import org.apache.ibatis.annotations.Param;
public interface EventMapper {
void insert(EventDto dto);
+ void update(@Param("uuid") String uuid, @Param("name") @Nullable String name, @Param("description") @Nullable String description);
+
void deleteById(long id);
void deleteByUuid(String uuid);
import static com.google.common.base.Preconditions.checkArgument;
-public class EventValidator {
+class EventValidator {
private static final int MAX_NAME_LENGTH = 400;
private static final int MAX_CATEGORY_LENGTH = 50;
private static final int MAX_DESCRIPTION_LENGTH = 4000;
}
@CheckForNull
- public static String checkEventName(@Nullable String name) {
+ static String checkEventName(@Nullable String name) {
if (name == null) {
return null;
}
}
@CheckForNull
- public static String checkEventCategory(@Nullable String category) {
+ static String checkEventCategory(@Nullable String category) {
if (category == null) {
return null;
}
}
@CheckForNull
- public static String checkEventDescription(@Nullable String description) {
+ static String checkEventDescription(@Nullable String description) {
if (description == null) {
return null;
}
description.length(), MAX_DESCRIPTION_LENGTH, description);
return description;
}
-
}
#{createdAt, jdbcType=BIGINT})
</insert>
+ <update id="update" parameterType="map">
+ update events
+ set name = #{name, jdbcType=VARCHAR},
+ description = #{description, jdbcType=VARCHAR}
+ where uuid = #{uuid}
+ </update>
+
<delete id="deleteById" parameterType="Long">
DELETE FROM events WHERE id=#{id}
</delete>
dbTester.assertDbUnit(getClass(), "insert-result.xml", new String[] {"id"}, "events");
}
+ @Test
+ public void update_name_and_description() {
+ SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(newProjectDto());
+ dbTester.events().insertEvent(newEvent(analysis).setUuid("E1"));
+
+ underTest.update(dbSession, "E1", "New Name", "New Description");
+
+ EventDto result = dbClient.eventDao().selectByUuid(dbSession, "E1").get();
+ assertThat(result.getName()).isEqualTo("New Name");
+ assertThat(result.getDescription()).isEqualTo("New Description");
+ }
+
@Test
public void delete_by_id() {
dbTester.prepareDbUnit(getClass(), "delete.xml");
--- /dev/null
+/*
+ * 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 org.sonarqube.ws.client.projectanalysis;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+public class UpdateEventRequest {
+ private final String event;
+ private final String name;
+ private final String description;
+
+ public UpdateEventRequest(String event, @Nullable String name, @Nullable String description) {
+ checkArgument(name != null || description != null, "Name or description is required");
+ this.event = requireNonNull(event, "Event key is required");
+ this.name = name;
+ this.description = description;
+ }
+
+ public String getEvent() {
+ return event;
+ }
+
+ @CheckForNull
+ public String getName() {
+ return name;
+ }
+
+ @CheckForNull
+ public String getDescription() {
+ return description;
+ }
+}
optional Event event = 1;
}
+// WS api/project_analyses/update_event
+message UpdateEventResponse {
+ optional Event event = 1;
+}
+
message Event {
optional string key = 1;
optional string analysis = 2;
--- /dev/null
+/*
+ * 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 org.sonarqube.ws.client.projectanalysis;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class UpdateEventRequestTest {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private UpdateEventRequest underTest;
+
+ @Test
+ public void request_with_name_only() {
+ underTest = new UpdateEventRequest("E1", "name", null);
+
+ assertThat(underTest.getEvent()).isEqualTo("E1");
+ assertThat(underTest.getName()).isEqualTo("name");
+ assertThat(underTest.getDescription()).isNull();
+ }
+
+ @Test
+ public void request_with_description_only() {
+ underTest = new UpdateEventRequest("E1", null , "description");
+
+ assertThat(underTest.getEvent()).isEqualTo("E1");
+ assertThat(underTest.getName()).isNull();
+ assertThat(underTest.getDescription()).isEqualTo("description");
+ }
+
+ @Test
+ public void request_with_all_parameters() {
+ underTest = new UpdateEventRequest("E1", "name", "description");
+
+ assertThat(underTest.getEvent()).isEqualTo("E1");
+ assertThat(underTest.getName()).isEqualTo("name");
+ assertThat(underTest.getDescription()).isEqualTo("description");
+ }
+
+ @Test
+ public void fail_if_null_event() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("Event key is required");
+
+ new UpdateEventRequest(null, "name", "description");
+ }
+
+ @Test
+ public void fail_if_name_and_description_not_provided() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Name or description is required");
+
+ new UpdateEventRequest("E1", null, null);
+ }
+}