diff options
author | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2014-11-25 16:18:04 +0100 |
---|---|---|
committer | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2014-11-25 16:30:58 +0100 |
commit | f1199464b99d54b520a4a3534879bfce8af1d91d (patch) | |
tree | e8733056c6369cd2918977d2880a1bbab35a8c8d | |
parent | 59b40f60adfc5bea1fbe0d41356981a666cebdd7 (diff) | |
download | sonarqube-f1199464b99d54b520a4a3534879bfce8af1d91d.tar.gz sonarqube-f1199464b99d54b520a4a3534879bfce8af1d91d.zip |
SONAR-5868 Add WS to fetch line hashes for issue tracking
16 files changed, 256 insertions, 7 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java b/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java index bfb143566b9..2578e6b5126 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java +++ b/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java @@ -28,6 +28,7 @@ import org.sonar.core.persistence.MyBatis; import org.sonar.core.properties.PropertiesDao; import org.sonar.core.qualityprofile.db.QualityProfileDao; import org.sonar.core.resource.ResourceDao; +import org.sonar.core.source.db.FileSourceDao; import org.sonar.core.technicaldebt.db.CharacteristicDao; import org.sonar.core.template.LoadedTemplateDao; import org.sonar.core.user.AuthorizationDao; @@ -83,6 +84,7 @@ public class DbClient implements ServerComponent { private final DashboardDao dashboardDao; private final WidgetDao widgetDao; private final WidgetPropertyDao widgetPropertyDao; + private final FileSourceDao fileSourceDao; public DbClient(Database db, MyBatis myBatis, DaoComponent... daoComponents) { this.db = db; @@ -114,6 +116,7 @@ public class DbClient implements ServerComponent { dashboardDao = getDao(map, DashboardDao.class); widgetDao = getDao(map, WidgetDao.class); widgetPropertyDao = getDao(map, WidgetPropertyDao.class); + fileSourceDao = getDao(map, FileSourceDao.class); } public Database database() { @@ -212,6 +215,10 @@ public class DbClient implements ServerComponent { return widgetPropertyDao; } + public FileSourceDao fileSourceDao() { + return fileSourceDao; + } + private <K> K getDao(Map<Class, DaoComponent> map, Class<K> clazz) { return (K) map.get(clazz); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index 26976280819..5b44f9579bc 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -546,6 +546,7 @@ class ServerComponents { pico.addSingleton(SourcesWs.class); pico.addSingleton(ShowAction.class); pico.addSingleton(LinesAction.class); + pico.addSingleton(HashAction.class); pico.addSingleton(ScmWriter.class); pico.addSingleton(RawAction.class); pico.addSingleton(ScmAction.class); diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/ws/HashAction.java b/server/sonar-server/src/main/java/org/sonar/server/source/ws/HashAction.java new file mode 100644 index 00000000000..c78e8ed7ca5 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/source/ws/HashAction.java @@ -0,0 +1,78 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.source.ws; + +import com.google.common.io.Resources; +import org.apache.commons.io.Charsets; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.RequestHandler; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.core.component.ComponentDto; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.source.db.FileSourceDao; +import org.sonar.server.db.DbClient; +import org.sonar.server.exceptions.NotFoundException; + +import java.io.OutputStream; + +public class HashAction implements RequestHandler { + + private final DbClient dbClient; + private final FileSourceDao fileSourceDao; + + public HashAction(DbClient dbClient, FileSourceDao fileSourceDao) { + this.dbClient = dbClient; + this.fileSourceDao = fileSourceDao; + } + + void define(WebService.NewController controller) { + WebService.NewAction action = controller.createAction("hash") + .setDescription("Show line line hashes for a given file. Require Browse permission on file's project<br/>") + .setSince("5.0") + .setInternal(true) + .setResponseExample(Resources.getResource(getClass(), "example-hash.txt")) + .setHandler(this); + + action + .createParam("key") + .setRequired(true) + .setDescription("File key") + .setExampleValue("org.codehaus.sonar:sonar-server:src/main/java/org/sonar/server/source/SourceService.java"); + } + + @Override + public void handle(Request request, Response response) throws Exception { + DbSession session = dbClient.openSession(false); + try { + String componentKey = request.mandatoryParam("key"); + ComponentDto component = dbClient.componentDao().getByKey(session, componentKey); + if (component == null) { + throw new NotFoundException("Unable to find component with key " + componentKey); + } + String lineHashes = fileSourceDao.selectLineHashes(component.uuid(), session); + OutputStream output = response.stream().setMediaType("text/plain").output(); + output.write(lineHashes.getBytes(Charsets.UTF_8)); + output.close(); + } finally { + session.close(); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/ws/SourcesWs.java b/server/sonar-server/src/main/java/org/sonar/server/source/ws/SourcesWs.java index b571b17aa53..75bc8580d19 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/ws/SourcesWs.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/ws/SourcesWs.java @@ -28,12 +28,14 @@ public class SourcesWs implements WebService { private final LinesAction show2Action; private final RawAction rawAction; private final ScmAction scmAction; + private final HashAction hashAction; - public SourcesWs(ShowAction showAction, RawAction rawAction, ScmAction scmAction, LinesAction show2Action) { + public SourcesWs(ShowAction showAction, RawAction rawAction, ScmAction scmAction, LinesAction show2Action, HashAction hashAction) { this.showAction = showAction; this.show2Action = show2Action; this.rawAction = rawAction; this.scmAction = scmAction; + this.hashAction = hashAction; } @Override @@ -45,6 +47,7 @@ public class SourcesWs implements WebService { show2Action.define(controller); rawAction.define(controller); scmAction.define(controller); + hashAction.define(controller); controller.done(); } } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/source/ws/example-hash.txt b/server/sonar-server/src/main/resources/org/sonar/server/source/ws/example-hash.txt new file mode 100644 index 00000000000..29b3fc4dccc --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/source/ws/example-hash.txt @@ -0,0 +1,21 @@ +523048e7f5ca9550505f2d8ea6d587e7 +9eaee2dcd8fb3d52785ff19ee1bbbb1f +7e6de4de3dfc573b36a28634a05ba370 +6112a40c70ed55453a0753030d5564a4 +3389dae361af79b04c9c8e7057f60cc6 +eac5fc1130394e7268b1cfbc54cd7e4d +c0b153d8c08365f2de343e278d3b54c7 +eb4521cb5d193e1d37ecac25b0ffea43 +9210ed0dec59ed663c744d7fb68f0275 +3389dae361af79b04c9c8e7057f60cc6 +cd0fbdfa49d32525ecbdb8dab19dafe6 +ea12a10f5b7730daa639fe133867e088 +69739b9bc9312dfb1a6b8625a08c652a +ec21e054f7f5748d0161fe27cdad6462 +3389dae361af79b04c9c8e7057f60cc6 +951a83e8074813100da0cba92092b385 +c93caecd79a332773cfb06cd5d3b8895 +5832d52d5fcb22a3350f62c856993f0d +c4c9bdd47ee05028cb84873da0ebf2b5 +16a8a946b55e075ffc7e522b7a244039 +6fb725696638490fd3fbb05b91271803 diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java new file mode 100644 index 00000000000..879893d3706 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java @@ -0,0 +1,96 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.source.ws; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.sonar.core.component.ComponentDto; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.source.db.FileSourceDao; +import org.sonar.server.component.db.ComponentDao; +import org.sonar.server.db.DbClient; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.ws.WsTester; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class HashActionTest { + + @Mock + DbClient dbClient; + + @Mock + ComponentDao componentDao; + + @Mock + FileSourceDao fileSourceDao; + + WsTester tester; + + @Before + public void setUp() throws Exception { + when(dbClient.componentDao()).thenReturn(componentDao); + when(dbClient.openSession(false)).thenReturn(mock(DbSession.class)); + tester = new WsTester( + new SourcesWs( + mock(ShowAction.class), + mock(RawAction.class), + mock(ScmAction.class), + mock(LinesAction.class), + new HashAction(dbClient, fileSourceDao) + ) + ); + } + + @Test + public void show_hashes() throws Exception { + String componentKey = "project:src/File.xoo"; + String uuid = "polop"; + ComponentDto component = new ComponentDto().setUuid(uuid); + String hashes = "polop\n" + + "\n" + + "pilip"; + when(componentDao.getByKey(any(DbSession.class), eq(componentKey))).thenReturn(component); + when(fileSourceDao.selectLineHashes(eq(uuid), any(DbSession.class))).thenReturn(hashes); + WsTester.TestRequest request = tester.newGetRequest("api/sources", "hash").setParam("key", componentKey); + assertThat(request.execute().outputAsString()).isEqualTo(hashes); + } + + @Test + public void fail_to_show_hashes_if_file_does_not_exist() throws Exception { + String componentKey = "project:src/File.xoo"; + try { + WsTester.TestRequest request = tester.newGetRequest("api/sources", "hash").setParam("key", componentKey); + request.execute(); + fail(); + } catch (Exception e) { + assertThat(e).isInstanceOf(NotFoundException.class); + } + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java index c98ecfdebf2..ab942f8f74d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java @@ -61,7 +61,8 @@ public class LinesActionTest { mock(ShowAction.class), mock(RawAction.class), mock(ScmAction.class), - new LinesAction(sourceLineIndex) + new LinesAction(sourceLineIndex), + mock(HashAction.class) ) ); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java index e848850b000..7ba87deb552 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java @@ -64,7 +64,8 @@ public class RawActionTest { public void setUp() throws Exception { when(dbClient.componentDao()).thenReturn(componentDao); when(dbClient.openSession(false)).thenReturn(session); - tester = new WsTester(new SourcesWs(mock(ShowAction.class), new RawAction(dbClient, sourceService), mock(ScmAction.class), mock(LinesAction.class))); + tester = new WsTester(new SourcesWs(mock(ShowAction.class), new RawAction(dbClient, sourceService), mock(ScmAction.class), mock(LinesAction.class), + mock(HashAction.class))); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java index f57ec7389f6..ba91095a920 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java @@ -34,7 +34,8 @@ public class ScmActionTest { SourceService sourceService = mock(SourceService.class); ScmWriter scmWriter = mock(ScmWriter.class); - WsTester tester = new WsTester(new SourcesWs(mock(ShowAction.class), mock(RawAction.class), new ScmAction(sourceService, scmWriter), mock(LinesAction.class))); + WsTester tester = new WsTester(new SourcesWs(mock(ShowAction.class), mock(RawAction.class), new ScmAction(sourceService, scmWriter), mock(LinesAction.class), + mock(HashAction.class))); @Test public void get_scm() throws Exception { diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java index 8ceaae65b47..904fc967df2 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java @@ -43,7 +43,8 @@ public class ShowActionTest { @Before public void setUp() throws Exception { - tester = new WsTester(new SourcesWs(new ShowAction(sourceService), mock(RawAction.class), new ScmAction(sourceService, mock(ScmWriter.class)), mock(LinesAction.class))); + tester = new WsTester(new SourcesWs(new ShowAction(sourceService), mock(RawAction.class), new ScmAction(sourceService, mock(ScmWriter.class)), mock(LinesAction.class), + mock(HashAction.class))); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java index 9d4334eb6d5..72c393d9051 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java @@ -22,6 +22,7 @@ package org.sonar.server.source.ws; import org.junit.Test; import org.sonar.api.server.ws.WebService; +import org.sonar.core.source.db.FileSourceDao; import org.sonar.server.db.DbClient; import org.sonar.server.source.SourceService; import org.sonar.server.source.index.SourceLineIndex; @@ -36,7 +37,8 @@ public class SourcesWsTest { RawAction rawAction = new RawAction(mock(DbClient.class), mock(SourceService.class)); ScmAction scmAction = new ScmAction(mock(SourceService.class), new ScmWriter()); LinesAction linesAction = new LinesAction(mock(SourceLineIndex.class)); - WsTester tester = new WsTester(new SourcesWs(showAction, rawAction, scmAction, linesAction)); + HashAction hashAction = new HashAction(mock(DbClient.class), mock(FileSourceDao.class)); + WsTester tester = new WsTester(new SourcesWs(showAction, rawAction, scmAction, linesAction, hashAction)); @Test public void define_ws() throws Exception { @@ -44,7 +46,7 @@ public class SourcesWsTest { assertThat(controller).isNotNull(); assertThat(controller.since()).isEqualTo("4.2"); assertThat(controller.description()).isNotEmpty(); - assertThat(controller.actions()).hasSize(4); + assertThat(controller.actions()).hasSize(5); WebService.Action show = controller.action("show"); assertThat(show).isNotNull(); @@ -77,5 +79,13 @@ public class SourcesWsTest { assertThat(index.isInternal()).isTrue(); assertThat(index.responseExampleAsString()).isNotEmpty(); assertThat(index.params()).hasSize(3); + + WebService.Action hash = controller.action("hash"); + assertThat(hash).isNotNull(); + assertThat(hash.handler()).isSameAs(hashAction); + assertThat(hash.since()).isEqualTo("5.0"); + assertThat(hash.isInternal()).isTrue(); + assertThat(hash.responseExampleAsString()).isNotEmpty(); + assertThat(hash.params()).hasSize(1); } } diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java b/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java index c097fd6e167..a6dd902d982 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java @@ -36,6 +36,7 @@ import org.sonar.core.resource.ResourceDao; import org.sonar.core.resource.ResourceIndexerDao; import org.sonar.core.resource.ResourceKeyUpdaterDao; import org.sonar.core.rule.RuleDao; +import org.sonar.core.source.db.FileSourceDao; import org.sonar.core.source.db.SnapshotDataDao; import org.sonar.core.source.db.SnapshotSourceDao; import org.sonar.core.technicaldebt.db.CharacteristicDao; @@ -61,6 +62,7 @@ public final class DaoUtils { AuthorizationDao.class, DashboardDao.class, DuplicationDao.class, + FileSourceDao.class, GraphDao.class, GroupMembershipDao.class, IssueDao.class, diff --git a/sonar-core/src/main/java/org/sonar/core/source/db/FileSourceDao.java b/sonar-core/src/main/java/org/sonar/core/source/db/FileSourceDao.java index 63dcf2631d3..c6c6ea16d6a 100644 --- a/sonar-core/src/main/java/org/sonar/core/source/db/FileSourceDao.java +++ b/sonar-core/src/main/java/org/sonar/core/source/db/FileSourceDao.java @@ -66,4 +66,8 @@ public class FileSourceDao implements BatchComponent, ServerComponent { } } + @CheckForNull + public String selectLineHashes(String fileUuid, DbSession session) { + return session.getMapper(FileSourceMapper.class).selectLineHashes(fileUuid); + } } diff --git a/sonar-core/src/main/java/org/sonar/core/source/db/FileSourceMapper.java b/sonar-core/src/main/java/org/sonar/core/source/db/FileSourceMapper.java index 916d662d212..2fd054897eb 100644 --- a/sonar-core/src/main/java/org/sonar/core/source/db/FileSourceMapper.java +++ b/sonar-core/src/main/java/org/sonar/core/source/db/FileSourceMapper.java @@ -34,4 +34,7 @@ public interface FileSourceMapper { void insert(FileSourceDto dto); void update(FileSourceDto dto); + + @CheckForNull + String selectLineHashes(String fileUuid); } diff --git a/sonar-core/src/main/resources/org/sonar/core/source/db/FileSourceMapper.xml b/sonar-core/src/main/resources/org/sonar/core/source/db/FileSourceMapper.xml index d7b65c501ea..3e68f7fdb2d 100644 --- a/sonar-core/src/main/resources/org/sonar/core/source/db/FileSourceMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/source/db/FileSourceMapper.xml @@ -30,5 +30,11 @@ where id = #{id} </update> + <select id="selectLineHashes" parameterType="string" resultType="String"> + SELECT line_hashes + FROM file_sources + WHERE file_uuid = #{fileUuid} + </select> + </mapper> diff --git a/sonar-core/src/test/java/org/sonar/core/source/db/FileSourceDaoTest.java b/sonar-core/src/test/java/org/sonar/core/source/db/FileSourceDaoTest.java index 0487d80b379..8e4e0274048 100644 --- a/sonar-core/src/test/java/org/sonar/core/source/db/FileSourceDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/source/db/FileSourceDaoTest.java @@ -24,6 +24,7 @@ import org.junit.Before; import org.junit.Test; import org.sonar.api.utils.DateUtils; import org.sonar.core.persistence.AbstractDaoTestCase; +import org.sonar.core.persistence.DbSession; import java.util.Date; @@ -52,6 +53,19 @@ public class FileSourceDaoTest extends AbstractDaoTestCase { } @Test + public void selectLineHashes() throws Exception { + DbSession session = getMyBatis().openSession(false); + String lineHashes = null; + try { + lineHashes = dao.selectLineHashes("ab12", session); + } finally { + session.close(); + } + + assertThat(lineHashes).isEqualTo("truc"); + } + + @Test public void insert() throws Exception { dao.insert(new FileSourceDto().setProjectUuid("prj").setFileUuid("file").setData("bla bla") .setDataHash("hash2") |