CREATE TABLE "PROJECT_LINKS" (
- "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
- "COMPONENT_UUID" VARCHAR(50),
- "LINK_TYPE" VARCHAR(20),
+ "UUID" VARCHAR(40) NOT NULL,
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ "LINK_TYPE" VARCHAR(20) NOT NULL,
"NAME" VARCHAR(128),
- "HREF" VARCHAR(2048) NOT NULL
+ "HREF" VARCHAR(2048) NOT NULL,
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT
);
+CREATE INDEX "PROJECT_LINKS_PROJECT" ON "PROJECT_LINKS" ("PROJECT_UUID");
+
CREATE TABLE "DUPLICATIONS_INDEX" (
"ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
import org.sonar.db.component.BranchDao;
import org.sonar.db.component.ComponentDao;
import org.sonar.db.component.ComponentKeyUpdaterDao;
-import org.sonar.db.component.ComponentLinkDao;
+import org.sonar.db.component.ProjectLinkDao;
import org.sonar.db.component.SnapshotDao;
import org.sonar.db.duplication.DuplicationDao;
import org.sonar.db.es.EsQueueDao;
CeTaskInputDao.class,
ComponentDao.class,
ComponentKeyUpdaterDao.class,
- ComponentLinkDao.class,
+ ProjectLinkDao.class,
LiveMeasureDao.class,
CustomMeasureDao.class,
DefaultQProfileDao.class,
import org.sonar.db.component.BranchDao;
import org.sonar.db.component.ComponentDao;
import org.sonar.db.component.ComponentKeyUpdaterDao;
-import org.sonar.db.component.ComponentLinkDao;
+import org.sonar.db.component.ProjectLinkDao;
import org.sonar.db.component.SnapshotDao;
import org.sonar.db.duplication.DuplicationDao;
import org.sonar.db.es.EsQueueDao;
private final CeTaskCharacteristicDao ceTaskCharacteristicsDao;
private final CeScannerContextDao ceScannerContextDao;
private final FileSourceDao fileSourceDao;
- private final ComponentLinkDao componentLinkDao;
+ private final ProjectLinkDao projectLinkDao;
private final EventDao eventDao;
private final PurgeDao purgeDao;
private final QualityGateDao qualityGateDao;
ceTaskCharacteristicsDao = getDao(map, CeTaskCharacteristicDao.class);
ceScannerContextDao = getDao(map, CeScannerContextDao.class);
fileSourceDao = getDao(map, FileSourceDao.class);
- componentLinkDao = getDao(map, ComponentLinkDao.class);
+ projectLinkDao = getDao(map, ProjectLinkDao.class);
eventDao = getDao(map, EventDao.class);
purgeDao = getDao(map, PurgeDao.class);
qualityGateDao = getDao(map, QualityGateDao.class);
return fileSourceDao;
}
- public ComponentLinkDao componentLinkDao() {
- return componentLinkDao;
+ public ProjectLinkDao projectLinkDao() {
+ return projectLinkDao;
}
public EventDao eventDao() {
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentDtoWithSnapshotId;
import org.sonar.db.component.ComponentKeyUpdaterMapper;
-import org.sonar.db.component.ComponentLinkDto;
-import org.sonar.db.component.ComponentLinkMapper;
import org.sonar.db.component.ComponentMapper;
import org.sonar.db.component.FilePathWithHashDto;
import org.sonar.db.component.KeyWithUuidDto;
+import org.sonar.db.component.ProjectLinkMapper;
import org.sonar.db.component.ResourceDto;
import org.sonar.db.component.ScrapAnalysisPropertyDto;
import org.sonar.db.component.SnapshotDto;
confBuilder.loadAlias("ActiveRuleParam", ActiveRuleParamDto.class);
confBuilder.loadAlias("CeTaskCharacteristic", CeTaskCharacteristicDto.class);
confBuilder.loadAlias("Component", ComponentDto.class);
- confBuilder.loadAlias("ComponentLink", ComponentLinkDto.class);
confBuilder.loadAlias("ComponentWithSnapshot", ComponentDtoWithSnapshotId.class);
confBuilder.loadAlias("CustomMeasure", CustomMeasureDto.class);
confBuilder.loadAlias("DuplicationUnit", DuplicationUnitDto.class);
CeTaskInputMapper.class,
CeTaskCharacteristicMapper.class,
ComponentKeyUpdaterMapper.class,
- ComponentLinkMapper.class,
+ ProjectLinkMapper.class,
ComponentMapper.class,
LiveMeasureMapper.class,
CustomMeasureMapper.class,
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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.db.component;
-
-import java.util.List;
-import javax.annotation.CheckForNull;
-import org.sonar.db.Dao;
-import org.sonar.db.DbSession;
-
-import static java.util.Collections.emptyList;
-
-public class ComponentLinkDao implements Dao {
-
- public List<ComponentLinkDto> selectByComponentUuid(DbSession session, String componentUuid) {
- return session.getMapper(ComponentLinkMapper.class).selectByComponentUuid(componentUuid);
- }
-
- public List<ComponentLinkDto> selectByComponentUuids(DbSession dbSession, List<String> componentUuids) {
- return componentUuids.isEmpty() ? emptyList() : mapper(dbSession).selectByComponentUuids(componentUuids);
- }
-
- @CheckForNull
- public ComponentLinkDto selectById(DbSession session, long id) {
- return session.getMapper(ComponentLinkMapper.class).selectById(id);
- }
-
- public ComponentLinkDto insert(DbSession session, ComponentLinkDto dto) {
- session.getMapper(ComponentLinkMapper.class).insert(dto);
- return dto;
- }
-
- public void update(DbSession session, ComponentLinkDto dto) {
- session.getMapper(ComponentLinkMapper.class).update(dto);
- }
-
- public void delete(DbSession session, long id) {
- session.getMapper(ComponentLinkMapper.class).delete(id);
- }
-
- private static ComponentLinkMapper mapper(DbSession dbSession) {
- return dbSession.getMapper(ComponentLinkMapper.class);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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.db.component;
-
-import com.google.common.collect.ImmutableList;
-import java.util.List;
-
-/**
- * Component links should be merge in a 'links' column (using protobuf for instance) of the projects table.
- * But to do this we'll have to wait for the measure filters page (where links are displayed) to be rewritten in JS/WS (because it's in Rails for the moment).
- */
-public class ComponentLinkDto {
-
- public static final String TYPE_HOME_PAGE = "homepage";
- public static final String TYPE_CI = "ci";
- public static final String TYPE_ISSUE_TRACKER = "issue";
- public static final String TYPE_SOURCES = "scm";
- public static final String TYPE_SOURCES_DEV = "scm_dev";
-
- public static final List<String> PROVIDED_TYPES = ImmutableList.of(TYPE_HOME_PAGE, TYPE_CI, TYPE_ISSUE_TRACKER, TYPE_SOURCES, TYPE_SOURCES_DEV);
-
- private Long id;
- private String componentUuid;
- private String type;
- private String name;
- private String href;
-
- public String getName() {
- return name;
- }
-
- public ComponentLinkDto setName(String name) {
- this.name = name;
- return this;
- }
-
- public String getComponentUuid() {
- return componentUuid;
- }
-
- public ComponentLinkDto setComponentUuid(String componentUuid) {
- this.componentUuid = componentUuid;
- return this;
- }
-
- public String getHref() {
- return href;
- }
-
- public ComponentLinkDto setHref(String href) {
- this.href = href;
- return this;
- }
-
- public Long getId() {
- return id;
- }
-
- public String getIdAsString() {
- return String.valueOf(id);
- }
-
- public ComponentLinkDto setId(Long id) {
- this.id = id;
- return this;
- }
-
- public String getType() {
- return type;
- }
-
- public ComponentLinkDto setType(String type) {
- this.type = type;
- return this;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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.db.component;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-
-public interface ComponentLinkMapper {
-
- List<ComponentLinkDto> selectByComponentUuid(String componentUuid);
-
- List<ComponentLinkDto> selectByComponentUuids(@Param("componentUuids") List<String> componentUuids);
-
- ComponentLinkDto selectById(@Param("id") long id);
-
- void insert(ComponentLinkDto dto);
-
- void update(ComponentLinkDto dto);
-
- void delete(long id);
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.component;
+
+import java.util.List;
+import javax.annotation.CheckForNull;
+import org.sonar.api.utils.System2;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+import static org.sonar.db.DatabaseUtils.executeLargeInputs;
+
+public class ProjectLinkDao implements Dao {
+
+ private final System2 system2;
+
+ public ProjectLinkDao(System2 system2) {
+ this.system2 = system2;
+ }
+
+ public List<ProjectLinkDto> selectByProjectUuid(DbSession session, String projectUuid) {
+ return session.getMapper(ProjectLinkMapper.class).selectByProjectUuid(projectUuid);
+ }
+
+ public List<ProjectLinkDto> selectByProjectUuids(DbSession dbSession, List<String> projectUuids) {
+ return executeLargeInputs(projectUuids, mapper(dbSession)::selectByProjectUuids);
+ }
+
+ @CheckForNull
+ public ProjectLinkDto selectByUuid(DbSession session, String uuid) {
+ return session.getMapper(ProjectLinkMapper.class).selectByUuid(uuid);
+ }
+
+ public ProjectLinkDto insert(DbSession session, ProjectLinkDto dto) {
+ long now = system2.now();
+ session.getMapper(ProjectLinkMapper.class).insert(dto.setCreatedAt(now).setUpdatedAt(now));
+ return dto;
+ }
+
+ public void update(DbSession session, ProjectLinkDto dto) {
+ session.getMapper(ProjectLinkMapper.class).update(dto.setUpdatedAt(system2.now()));
+ }
+
+ public void delete(DbSession session, String uuid) {
+ session.getMapper(ProjectLinkMapper.class).delete(uuid);
+ }
+
+ private static ProjectLinkMapper mapper(DbSession dbSession) {
+ return dbSession.getMapper(ProjectLinkMapper.class);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.component;
+
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+public class ProjectLinkDto {
+
+ public static final String TYPE_HOME_PAGE = "homepage";
+ public static final String TYPE_CI = "ci";
+ public static final String TYPE_ISSUE_TRACKER = "issue";
+ public static final String TYPE_SOURCES = "scm";
+
+ public static final String TYPE_SOURCES_DEV = "scm_dev";
+
+ public static final List<String> PROVIDED_TYPES = ImmutableList.of(TYPE_HOME_PAGE, TYPE_CI, TYPE_ISSUE_TRACKER, TYPE_SOURCES, TYPE_SOURCES_DEV);
+
+ private String uuid;
+ private String projectUuid;
+ private String type;
+ private String name;
+ private String href;
+ private long createdAt;
+ private long updatedAt;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public ProjectLinkDto setUuid(String uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+
+ @CheckForNull
+ public String getName() {
+ return name;
+ }
+
+ public ProjectLinkDto setName(@Nullable String name) {
+ this.name = name;
+ return this;
+ }
+
+ public String getProjectUuid() {
+ return projectUuid;
+ }
+
+ public ProjectLinkDto setProjectUuid(String projectUuid) {
+ this.projectUuid = projectUuid;
+ return this;
+ }
+
+ public String getHref() {
+ return href;
+ }
+
+ public ProjectLinkDto setHref(String href) {
+ this.href = href;
+ return this;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public ProjectLinkDto setType(String type) {
+ this.type = type;
+ return this;
+ }
+
+ public long getCreatedAt() {
+ return createdAt;
+ }
+
+ public ProjectLinkDto setCreatedAt(long createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ public long getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public ProjectLinkDto setUpdatedAt(long updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.component;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+
+public interface ProjectLinkMapper {
+
+ List<ProjectLinkDto> selectByProjectUuid(String projectUuid);
+
+ List<ProjectLinkDto> selectByProjectUuids(@Param("projectUuids") List<String> projectUuids);
+
+ ProjectLinkDto selectByUuid(@Param("uuid") String uuid);
+
+ void insert(ProjectLinkDto dto);
+
+ void update(ProjectLinkDto dto);
+
+ void delete(String uuid);
+}
void deleteLinks(String rootUuid) {
profiler.start("deleteLinks (project_links)");
- purgeMapper.deleteProjectLinksByComponentUuid(rootUuid);
+ purgeMapper.deleteProjectLinksByProjectUuid(rootUuid);
session.commit();
profiler.stop();
}
void resolveComponentIssuesNotAlreadyResolved(@Param("componentUuids") List<String> componentUuids, @Param("dateAsLong") Long dateAsLong);
- void deleteProjectLinksByComponentUuid(@Param("rootUuid") String rootUuid);
+ void deleteProjectLinksByProjectUuid(@Param("rootUuid") String rootUuid);
void deletePropertiesByComponentIds(@Param("componentIds") List<Long> componentIds);
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
-<mapper namespace="org.sonar.db.component.ComponentLinkMapper">
-
- <sql id="componentLinkColumns">
- p.id,
- p.component_uuid as "componentUuid",
- p.link_type as "type",
- p.name as name,
- p.href as href
- </sql>
-
- <select id="selectByComponentUuid" parameterType="String" resultType="ComponentLink">
- SELECT
- <include refid="componentLinkColumns"/>
- FROM project_links p
- where p.component_uuid=#{uuid,jdbcType=VARCHAR}
- ORDER BY p.id
- </select>
-
- <select id="selectByComponentUuids" parameterType="String" resultType="ComponentLink">
- SELECT
- <include refid="componentLinkColumns"/>
- FROM project_links p
- where
- p.component_uuid in
- <foreach collection="componentUuids" open="(" close=")" item="uuid" separator=",">
- #{uuid,jdbcType=VARCHAR}
- </foreach>
- order by p.id
- </select>
-
- <select id="selectById" parameterType="long" resultType="ComponentLink">
- SELECT
- <include refid="componentLinkColumns"/>
- FROM project_links p
- where p.id=#{id,jdbcType=BIGINT}
- </select>
-
- <insert id="insert" parameterType="ComponentLink" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
- INSERT INTO project_links (component_uuid, link_type, name, href)
- VALUES (#{componentUuid,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
- #{href,jdbcType=VARCHAR})
- </insert>
-
- <insert id="update" parameterType="ComponentLink" useGeneratedKeys="false">
- UPDATE project_links SET component_uuid=#{componentUuid,jdbcType=VARCHAR}, link_type=#{type,jdbcType=VARCHAR},
- name=#{name,jdbcType=VARCHAR}, href=#{href,jdbcType=VARCHAR}
- WHERE id=#{id,jdbcType=BIGINT}
- </insert>
-
- <delete id="delete">
- DELETE FROM project_links WHERE id=#{id,jdbcType=BIGINT}
- </delete>
-
-</mapper>
-
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
+<mapper namespace="org.sonar.db.component.ProjectLinkMapper">
+
+ <sql id="columns">
+ p.uuid,
+ p.project_uuid as "projectUuid",
+ p.link_type as "type",
+ p.name as name,
+ p.href as href,
+ p.created_at as "createdAt",
+ p.updated_at as "updatedAt"
+ </sql>
+
+ <select id="selectByProjectUuid" parameterType="String" resultType="org.sonar.db.component.ProjectLinkDto">
+ SELECT
+ <include refid="columns"/>
+ FROM project_links p
+ where p.project_uuid=#{uuid,jdbcType=VARCHAR}
+ ORDER BY p.uuid
+ </select>
+
+ <select id="selectByProjectUuids" parameterType="String" resultType="org.sonar.db.component.ProjectLinkDto">
+ SELECT
+ <include refid="columns"/>
+ FROM project_links p
+ where
+ p.project_uuid in
+ <foreach collection="projectUuids" open="(" close=")" item="uuid" separator=",">
+ #{uuid,jdbcType=VARCHAR}
+ </foreach>
+ order by p.uuid
+ </select>
+
+ <select id="selectByUuid" parameterType="String" resultType="org.sonar.db.component.ProjectLinkDto">
+ SELECT
+ <include refid="columns"/>
+ FROM project_links p
+ where p.uuid=#{uuid,jdbcType=VARCHAR}
+ </select>
+
+ <insert id="insert" parameterType="org.sonar.db.component.ProjectLinkDto" useGeneratedKeys="false">
+ INSERT INTO project_links (uuid, project_uuid, link_type, name, href, created_at, updated_at)
+ VALUES (
+ #{uuid,jdbcType=VARCHAR},
+ #{projectUuid,jdbcType=VARCHAR},
+ #{type,jdbcType=VARCHAR},
+ #{name,jdbcType=VARCHAR},
+ #{href,jdbcType=VARCHAR},
+ #{createdAt,jdbcType=BIGINT},
+ #{updatedAt,jdbcType=BIGINT})
+ </insert>
+
+ <insert id="update" parameterType="org.sonar.db.component.ProjectLinkDto" useGeneratedKeys="false">
+ UPDATE project_links SET
+ project_uuid=#{projectUuid,jdbcType=VARCHAR},
+ link_type=#{type,jdbcType=VARCHAR},
+ name=#{name,jdbcType=VARCHAR},
+ href=#{href,jdbcType=VARCHAR},
+ updated_at=#{updatedAt,jdbcType=BIGINT}
+ WHERE uuid=#{uuid,jdbcType=VARCHAR}
+ </insert>
+
+ <delete id="delete">
+ DELETE FROM project_links WHERE uuid=#{uuid,jdbcType=VARCHAR}
+ </delete>
+
+</mapper>
+
and resolution is null
</update>
- <delete id="deleteProjectLinksByComponentUuid" parameterType="map">
+ <delete id="deleteProjectLinksByProjectUuid" parameterType="map">
delete from project_links
where
- component_uuid = #{rootUuid,jdbcType=VARCHAR}
+ project_uuid = #{rootUuid,jdbcType=VARCHAR}
</delete>
<delete id="deletePropertiesByComponentIds" parameterType="map">
import org.sonar.api.utils.System2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.component.ComponentDbTester;
+import org.sonar.db.component.ProjectLinkDbTester;
import org.sonar.db.event.EventDbTester;
import org.sonar.db.favorite.FavoriteDbTester;
import org.sonar.db.issue.IssueDbTester;
import org.sonar.db.plugin.PluginDbTester;
import org.sonar.db.property.PropertyDbTester;
import org.sonar.db.qualitygate.QualityGateDbTester;
-import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.db.qualityprofile.QualityProfileDbTester;
import org.sonar.db.rule.RuleDbTester;
import org.sonar.db.source.FileSourceTester;
private boolean started = false;
private String defaultOrganizationUuid = randomAlphanumeric(40);
private OrganizationDto defaultOrganization;
- private QualityGateDto builtInQualityGate;
private final UserDbTester userTester;
private final ComponentDbTester componentTester;
+ private final ProjectLinkDbTester componentLinkTester;
private final FavoriteDbTester favoriteTester;
private final EventDbTester eventTester;
private final OrganizationDbTester organizationTester;
initDbClient();
this.userTester = new UserDbTester(this);
this.componentTester = new ComponentDbTester(this);
+ this.componentLinkTester = new ProjectLinkDbTester(this);
this.favoriteTester = new FavoriteDbTester(this);
this.eventTester = new EventDbTester(this);
this.organizationTester = new OrganizationDbTester(this);
return componentTester;
}
+ public ProjectLinkDbTester componentLinks() {
+ return componentLinkTester;
+ }
+
public FavoriteDbTester favorites() {
return favoriteTester;
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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.db.component;
-
-import java.util.List;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.DbTester;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static java.util.Collections.emptyList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.db.component.ComponentLinkDto.TYPE_HOME_PAGE;
-import static org.sonar.db.component.ComponentLinkDto.TYPE_SOURCES;
-import static org.sonar.db.component.ComponentLinkTesting.newComponentLinkDto;
-
-
-public class ComponentLinkDaoTest {
-
- @Rule
- public DbTester db = DbTester.create(System2.INSTANCE);
- private DbClient dbClient = db.getDbClient();
- private DbSession dbSession = db.getSession();
-
- private ComponentLinkDao underTest = db.getDbClient().componentLinkDao();
-
- @Test
- public void select_by_component_uuid() {
- db.prepareDbUnit(getClass(), "shared.xml");
-
- List<ComponentLinkDto> links = underTest.selectByComponentUuid(db.getSession(), "ABCD");
- assertThat(links).hasSize(2);
-
- links = underTest.selectByComponentUuid(db.getSession(), "BCDE");
- assertThat(links).hasSize(1);
-
- ComponentLinkDto link = links.get(0);
- assertThat(link.getId()).isEqualTo(3L);
- assertThat(link.getComponentUuid()).isEqualTo("BCDE");
- assertThat(link.getType()).isEqualTo("homepage");
- assertThat(link.getName()).isEqualTo("Home");
- assertThat(link.getHref()).isEqualTo("http://www.struts.org");
- }
-
- @Test
- public void select_by_component_uuids() {
- String firstUuid = "COMPONENT_UUID_1";
- String secondUuid = "COMPONENT_UUID_2";
- dbClient.componentLinkDao().insert(dbSession, newComponentLinkDto().setComponentUuid(firstUuid).setType(TYPE_HOME_PAGE));
- dbClient.componentLinkDao().insert(dbSession, newComponentLinkDto().setComponentUuid(firstUuid).setType(TYPE_SOURCES));
- dbClient.componentLinkDao().insert(dbSession, newComponentLinkDto().setComponentUuid(secondUuid).setType(TYPE_HOME_PAGE));
- dbClient.componentLinkDao().insert(dbSession, newComponentLinkDto().setComponentUuid("ANOTHER_COMPONENT_UUID").setType(TYPE_HOME_PAGE));
- db.commit();
-
- List<ComponentLinkDto> result = underTest.selectByComponentUuids(dbSession, newArrayList(firstUuid, secondUuid));
-
- assertThat(result).hasSize(3).extracting(ComponentLinkDto::getComponentUuid).containsOnly(firstUuid, secondUuid);
- }
-
- @Test
- public void select_by_component_uuids_with_empty_list() {
- List<ComponentLinkDto> result = underTest.selectByComponentUuids(dbSession, emptyList());
-
- assertThat(result).isEmpty();
- }
-
- @Test
- public void select_by_id() {
- ComponentLinkDto link = underTest.insert(dbSession, newComponentLinkDto());
- db.commit();
-
- ComponentLinkDto candidate = underTest.selectById(dbSession, link.getId());
- assertThat(candidate.getId()).isNotNull();
- }
-
- @Test
- public void insert() {
- db.prepareDbUnit(getClass(), "empty.xml");
-
- underTest.insert(db.getSession(), new ComponentLinkDto()
- .setComponentUuid("ABCD")
- .setType("homepage")
- .setName("Home")
- .setHref("http://www.sonarqube.org")
- );
- db.getSession().commit();
-
- db.assertDbUnit(getClass(), "insert-result.xml", new String[] {"id"}, "project_links");
- }
-
- @Test
- public void update() {
- db.prepareDbUnit(getClass(), "update.xml");
-
- underTest.update(db.getSession(), new ComponentLinkDto()
- .setId(1L)
- .setComponentUuid("ABCD")
- .setType("homepage")
- .setName("Home")
- .setHref("http://www.sonarqube.org")
- );
- db.getSession().commit();
-
- db.assertDbUnit(getClass(), "update-result.xml", "project_links");
- }
-
- @Test
- public void delete() {
- db.prepareDbUnit(getClass(), "delete.xml");
-
- underTest.delete(db.getSession(), 1L);
- db.getSession().commit();
-
- assertThat(db.countRowsOfTable("project_links")).isEqualTo(0);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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.db.component;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ComponentLinkDtoTest {
-
- @Test
- public void test_getters_and_setters() {
- ComponentLinkDto dto = new ComponentLinkDto()
- .setId(1L)
- .setComponentUuid("ABCD")
- .setType("homepage")
- .setName("Home")
- .setHref("http://www.sonarqube.org");
-
- assertThat(dto.getId()).isEqualTo(1L);
- assertThat(dto.getComponentUuid()).isEqualTo("ABCD");
- assertThat(dto.getType()).isEqualTo("homepage");
- assertThat(dto.getName()).isEqualTo("Home");
- assertThat(dto.getHref()).isEqualTo("http://www.sonarqube.org");
- }
-
- @Test
- public void test_provided_types() {
- assertThat(ComponentLinkDto.PROVIDED_TYPES).hasSize(5);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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.db.component;
-
-import org.sonar.core.util.Uuids;
-
-import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
-import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
-
-public class ComponentLinkTesting {
- public static ComponentLinkDto newComponentLinkDto() {
- return new ComponentLinkDto()
- .setComponentUuid(Uuids.createFast())
- .setHref(randomAlphanumeric(128))
- .setName(randomAlphabetic(128))
- .setType(ComponentLinkDto.TYPE_SOURCES);
- }
-
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.component;
+
+import java.util.Collections;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.db.DbTester;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProjectLinkDaoTest {
+
+ private final static long PAST = 5_000_000_000L;
+ private final static long NOW = 10_000_000_000L;
+
+ private System2 system2 = new TestSystem2().setNow(NOW);
+
+ @Rule
+ public DbTester db = DbTester.create(system2);
+
+ private ProjectLinkDao underTest = db.getDbClient().projectLinkDao();
+
+ @Test
+ public void select_by_id() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertProvidedLink(project, c -> c
+ .setUuid("ABCD")
+ .setName("Home")
+ .setType("homepage")
+ .setHref("http://www.struts.org"));
+
+ ProjectLinkDto reloaded = underTest.selectByUuid(db.getSession(), link.getUuid());
+
+ assertThat(reloaded.getUuid()).isEqualTo("ABCD");
+ assertThat(reloaded.getProjectUuid()).isEqualTo(project.uuid());
+ assertThat(reloaded.getType()).isEqualTo("homepage");
+ assertThat(reloaded.getName()).isEqualTo("Home");
+ assertThat(reloaded.getHref()).isEqualTo("http://www.struts.org");
+ assertThat(reloaded.getCreatedAt()).isEqualTo(NOW);
+ assertThat(reloaded.getUpdatedAt()).isEqualTo(NOW);
+ }
+
+ @Test
+ public void select_by_project_uuid() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link1 = db.componentLinks().insertProvidedLink(project);
+ ProjectLinkDto link2 = db.componentLinks().insertProvidedLink(project);
+ ProjectLinkDto link3 = db.componentLinks().insertProvidedLink(project);
+ ComponentDto otherProject = db.components().insertPrivateProject();
+ ProjectLinkDto otherLink = db.componentLinks().insertProvidedLink(otherProject);
+
+ assertThat(underTest.selectByProjectUuid(db.getSession(), project.uuid()))
+ .extracting(ProjectLinkDto::getUuid)
+ .containsExactlyInAnyOrder(link1.getUuid(), link2.getUuid(), link3.getUuid());
+ assertThat(underTest.selectByProjectUuid(db.getSession(), otherProject.uuid()))
+ .extracting(ProjectLinkDto::getUuid)
+ .containsExactlyInAnyOrder(otherLink.getUuid());
+ assertThat(underTest.selectByProjectUuid(db.getSession(), "UNKNOWN")).isEmpty();
+ }
+
+ @Test
+ public void select_by_project_uuids() {
+ ComponentDto project1 = db.components().insertPrivateProject();
+ ProjectLinkDto link1 = db.componentLinks().insertProvidedLink(project1);
+ ProjectLinkDto link2 = db.componentLinks().insertProvidedLink(project1);
+ ComponentDto project2 = db.components().insertPrivateProject();
+ ProjectLinkDto link3 = db.componentLinks().insertProvidedLink(project2);
+
+ assertThat(underTest.selectByProjectUuids(db.getSession(), asList(project1.uuid(), project2.uuid())))
+ .extracting(ProjectLinkDto::getUuid)
+ .containsOnly(link1.getUuid(), link2.getUuid(), link3.getUuid());
+ assertThat(underTest.selectByProjectUuids(db.getSession(), singletonList(project1.uuid())))
+ .extracting(ProjectLinkDto::getUuid)
+ .containsOnly(link1.getUuid(), link2.getUuid());
+ assertThat(underTest.selectByProjectUuids(db.getSession(), Collections.emptyList())).isEmpty();
+ }
+
+ @Test
+ public void insert() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = ProjectLinkTesting.newProvidedLinkDto()
+ .setUuid("ABCD")
+ .setProjectUuid(project.uuid())
+ .setName("Home")
+ .setType("homepage")
+ .setHref("http://www.struts.org")
+ // These fields will be set by the DAO
+ .setCreatedAt(0L)
+ .setUpdatedAt(0L);
+
+ underTest.insert(db.getSession(), link);
+ db.getSession().commit();
+
+ ProjectLinkDto reloaded = underTest.selectByUuid(db.getSession(), link.getUuid());
+ assertThat(reloaded.getUuid()).isEqualTo("ABCD");
+ assertThat(reloaded.getProjectUuid()).isEqualTo(project.uuid());
+ assertThat(reloaded.getType()).isEqualTo("homepage");
+ assertThat(reloaded.getName()).isEqualTo("Home");
+ assertThat(reloaded.getHref()).isEqualTo("http://www.struts.org");
+ assertThat(reloaded.getCreatedAt()).isEqualTo(NOW);
+ assertThat(reloaded.getUpdatedAt()).isEqualTo(NOW);
+ }
+
+ @Test
+ public void update() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertProvidedLink(project, c -> c
+ .setUuid("ABCD")
+ .setType("ci")
+ .setName("Gihub")
+ .setHref("http://www.github.org"));
+ // Force dates to be in the past
+ db.executeUpdateSql("UPDATE project_links SET created_at=" + PAST + " ,updated_at=" + PAST);
+
+ ComponentDto project2 = db.components().insertPrivateProject();
+ underTest.update(db.getSession(), link
+ .setProjectUuid(project2.uuid())
+ .setType("homepage")
+ .setName("Home")
+ .setHref("http://www.sonarqube.org"));
+ db.getSession().commit();
+
+ ProjectLinkDto reloaded = underTest.selectByUuid(db.getSession(), link.getUuid());
+ assertThat(reloaded.getUuid()).isEqualTo("ABCD");
+ assertThat(reloaded.getProjectUuid()).isEqualTo(project2.uuid());
+ assertThat(reloaded.getType()).isEqualTo("homepage");
+ assertThat(reloaded.getName()).isEqualTo("Home");
+ assertThat(reloaded.getHref()).isEqualTo("http://www.sonarqube.org");
+ assertThat(reloaded.getCreatedAt()).isEqualTo(PAST);
+ assertThat(reloaded.getUpdatedAt()).isEqualTo(NOW);
+ }
+
+ @Test
+ public void delete() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertProvidedLink(project);
+
+ underTest.delete(db.getSession(), link.getUuid());
+ db.getSession().commit();
+
+ assertThat(db.countRowsOfTable("project_links")).isEqualTo(0);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.component;
+
+import java.util.Arrays;
+import java.util.function.Consumer;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+
+import static org.sonar.db.component.ProjectLinkTesting.newCustomLinkDto;
+import static org.sonar.db.component.ProjectLinkTesting.newProvidedLinkDto;
+
+public class ProjectLinkDbTester {
+ private final DbTester db;
+ private final DbClient dbClient;
+ private final DbSession dbSession;
+
+ public ProjectLinkDbTester(DbTester db) {
+ this.db = db;
+ this.dbClient = db.getDbClient();
+ this.dbSession = db.getSession();
+ }
+
+ @SafeVarargs
+ public final ProjectLinkDto insertProvidedLink(ComponentDto project, Consumer<ProjectLinkDto>... dtoPopulators) {
+ return insertLink(project, newProvidedLinkDto(), dtoPopulators);
+ }
+
+ @SafeVarargs
+ public final ProjectLinkDto insertCustomLink(ComponentDto project, Consumer<ProjectLinkDto>... dtoPopulators) {
+ return insertLink(project, newCustomLinkDto(), dtoPopulators);
+ }
+
+ @SafeVarargs
+ private final ProjectLinkDto insertLink(ComponentDto project, ProjectLinkDto componentLink, Consumer<ProjectLinkDto>... dtoPopulators) {
+ Arrays.stream(dtoPopulators).forEach(dtoPopulator -> dtoPopulator.accept(componentLink));
+ dbClient.projectLinkDao().insert(dbSession, componentLink.setProjectUuid(project.uuid()));
+ db.commit();
+ return componentLink;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.component;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProjectLinkDtoTest {
+
+ @Test
+ public void test_getters_and_setters() {
+ ProjectLinkDto dto = new ProjectLinkDto()
+ .setUuid("ABCD")
+ .setProjectUuid("EFGH")
+ .setType("homepage")
+ .setName("Home")
+ .setHref("http://www.sonarqube.org")
+ .setCreatedAt(1_000_000_000L)
+ .setUpdatedAt(5_000_000_000L);
+
+ assertThat(dto.getUuid()).isEqualTo("ABCD");
+ assertThat(dto.getProjectUuid()).isEqualTo("EFGH");
+ assertThat(dto.getType()).isEqualTo("homepage");
+ assertThat(dto.getName()).isEqualTo("Home");
+ assertThat(dto.getHref()).isEqualTo("http://www.sonarqube.org");
+ assertThat(dto.getCreatedAt()).isEqualTo(1_000_000_000L);
+ assertThat(dto.getUpdatedAt()).isEqualTo(5_000_000_000L);
+ }
+
+ @Test
+ public void test_provided_types() {
+ assertThat(ProjectLinkDto.PROVIDED_TYPES).hasSize(5);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.db.component;
+
+import org.apache.commons.lang.math.RandomUtils;
+import org.sonar.core.util.Uuids;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+
+public class ProjectLinkTesting {
+
+ public static ProjectLinkDto newProvidedLinkDto() {
+ return newCommonLinkDto()
+ .setName(null)
+ .setType(ProjectLinkDto.PROVIDED_TYPES.get(RandomUtils.nextInt(ProjectLinkDto.PROVIDED_TYPES.size() - 1)));
+ }
+
+ public static ProjectLinkDto newCustomLinkDto() {
+ String nameAndType = randomAlphabetic(20);
+ return newCommonLinkDto()
+ .setName(nameAndType)
+ .setType(nameAndType);
+ }
+
+ private static ProjectLinkDto newCommonLinkDto() {
+ return new ProjectLinkDto()
+ .setUuid(Uuids.createFast())
+ .setProjectUuid(Uuids.createFast())
+ .setHref(randomAlphanumeric(128))
+ .setCreatedAt(System.currentTimeMillis())
+ .setUpdatedAt(System.currentTimeMillis());
+ }
+
+}
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="ABCD" link_type="homepage" name="Home" href="http://www.sonarqube.org"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="ABCD" link_type="homepage" name="Home" href="http://www.sonarqube.org"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="ABCD" link_type="homepage" name="Home" href="http://www.sonarqube.org"/>
- <project_links id="2" component_uuid="ABCD" link_type="scm" name="Sources" href="https://github.com/SonarSource/sonar"/>
- <project_links id="3" component_uuid="BCDE" link_type="homepage" name="Home" href="http://www.struts.org"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="ABCD" link_type="homepage" name="Home" href="http://www.sonarqube.org"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="BCDE" link_type="ci" name="CI" href="github"/>
-
-</dataset>
*/
package org.sonar.server.platform.db.migration.sql;
-import java.util.Arrays;
import java.util.List;
import org.sonar.db.dialect.Dialect;
import org.sonar.db.dialect.H2;
import org.sonar.db.dialect.PostgreSql;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.sonar.server.platform.db.migration.def.Validations.validateTableName;
-/**
- * Limitation: only tables with auto-generated ID column can
- * be renamed as the Oracle implementation assumes that
- * the sequence and trigger related to ID column exist.
- */
public class RenameTableBuilder {
private final Dialect dialect;
private String name;
private String newName;
+ private boolean autoGeneratedId = true;
public RenameTableBuilder(Dialect dialect) {
this.dialect = dialect;
return this;
}
+ /**
+ * When a table has no auto generated id, this parameter has to be set to false.
+ * On Oracle, it will allow to not try to drop and recreate the trigger.
+ * On other databases, this method is useless.
+ *
+ * Default value is true.
+ */
+ public RenameTableBuilder setAutoGeneratedId(boolean autoGeneratedId) {
+ this.autoGeneratedId = autoGeneratedId;
+ return this;
+ }
+
public List<String> build() {
validateTableName(name);
validateTableName(newName);
case MsSql.ID:
return singletonList("EXEC sp_rename '" + name + "', '" + newName + "'");
case Oracle.ID:
- return Arrays.asList(
+ String renameSqlCommand = "RENAME " + name + " TO " + newName;
+ return autoGeneratedId ? asList(
"DROP TRIGGER " + name + "_idt",
- "RENAME " + name + " TO " + newName,
+ renameSqlCommand,
"RENAME " + name + "_seq TO " + newName + "_seq",
- CreateTableBuilder.createOracleTriggerForTable(newName));
+ CreateTableBuilder.createOracleTriggerForTable(newName))
+ : singletonList(renameSqlCommand);
default:
throw new IllegalArgumentException("Unsupported dialect id " + dialect.getId());
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration.version.v71;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.CreateTableBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.BigIntegerColumnDef.newBigIntegerColumnDefBuilder;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
+
+public class CreateTableProjectLinks2 extends DdlChange {
+
+ private static final String TABLE_NAME = "project_links2";
+
+ public CreateTableProjectLinks2(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME)
+ .addPkColumn(newVarcharColumnDefBuilder()
+ .setColumnName("uuid")
+ .setLimit(UUID_SIZE)
+ .setIsNullable(false)
+ .build())
+ .addColumn(newVarcharColumnDefBuilder()
+ .setColumnName("project_uuid")
+ .setLimit(UUID_SIZE)
+ .setIsNullable(false)
+ .build())
+ .addColumn(newVarcharColumnDefBuilder()
+ .setColumnName("link_type")
+ .setLimit(20)
+ .setIsNullable(false)
+ .build())
+ .addColumn(newVarcharColumnDefBuilder()
+ .setColumnName("name")
+ .setLimit(128)
+ .setIsNullable(true)
+ .build())
+ .addColumn(newVarcharColumnDefBuilder()
+ .setColumnName("href")
+ .setLimit(2048)
+ .setIsNullable(false)
+ .build())
+ .addColumn(newBigIntegerColumnDefBuilder()
+ .setColumnName("created_at")
+ .setIsNullable(false)
+ .build())
+ .addColumn(newBigIntegerColumnDefBuilder()
+ .setColumnName("updated_at")
+ .setIsNullable(false)
+ .build())
+ .build());
+ }
+}
.add(2005, "Create table DEPRECATED_RULE_KEYS", CreateDeprecatedRuleKeysTable.class)
.add(2006, "Clean orphans in Compute Engine child tables", CleanCeChildTablesOrphans.class)
.add(2007, "Update PERMISSION_TEMPLATES.KEYS ", UpdatePermissionTooLongTemplateKeys.class)
+ .add(2008, "Make scope not nullable in rules", MakeScopeNotNullableInRules.class)
+ .add(2009, "Create table PROJECT_LINKS2", CreateTableProjectLinks2.class)
+ .add(2010, "Populate table PROJECT_LINKS2", PopulateTableProjectLinks2.class)
+ .add(2011, "Drop table PROJECT_LINKS", DropTableProjectLinks.class)
+ .add(2012, "Rename table PROJECT_LINKS2 to PROJECT_LINKS", RenameTableProjectLinks2ToProjectLinks.class)
;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration.version.v71;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.DropTableBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class DropTableProjectLinks extends DdlChange {
+
+ private static final String TABLE_NAME = "project_links";
+
+ public DropTableProjectLinks(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(new DropTableBuilder(getDialect(), TABLE_NAME).build());
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration.version.v71;
+
+import com.google.common.collect.ImmutableList;
+import java.sql.SQLException;
+import java.util.List;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+
+/**
+ * Populate PROJECT_LINK2 data from PROJECT_LINK table and take the opportunity to do some cleanup :
+ * - Ignore link that are not set on project (only take component with qualifier TRK and scope PRJ)
+ * - Do not set a name on provided links (SONAR-10411)
+ * - Do not copy link on Developer Connection (SONAR-10299)
+ */
+public class PopulateTableProjectLinks2 extends DataChange {
+
+ private static final String TYPE_HOME_PAGE = "homepage";
+ private static final String TYPE_CI = "ci";
+ private static final String TYPE_ISSUE_TRACKER = "issue";
+ private static final String TYPE_SOURCES = "scm";
+ private static final String TYPE_SOURCES_DEV = "scm_dev";
+ private static final List<String> PROVIDED_TYPES = ImmutableList.of(TYPE_HOME_PAGE, TYPE_CI, TYPE_ISSUE_TRACKER, TYPE_SOURCES);
+
+ private static final String SCOPE_PROJECT = "PRJ";
+ private static final String QUALIFIER_PROJECT = "TRK";
+
+ private final UuidFactory uuidFactory;
+ private final System2 system2;
+
+ public PopulateTableProjectLinks2(Database db, UuidFactory uuidFactory, System2 system2) {
+ super(db);
+ this.uuidFactory = uuidFactory;
+ this.system2 = system2;
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ long now = system2.now();
+ MassUpdate massUpdate = context.prepareMassUpdate();
+ massUpdate.select("SELECT" +
+ " p.component_uuid, p.link_type, p.name, p.href" +
+ " from project_links p" +
+ // Join on projects in order to sanitize orphans (if any)
+ " inner join projects prj on prj.uuid=p.component_uuid and prj.scope=? and prj.qualifier=? " +
+ " left outer join project_links2 p2" +
+ " on p2.project_uuid=p.component_uuid " +
+ " and p2.href=p.href" +
+ " and p2.link_type=p.link_type" +
+ " and (p2.name=p.name or (p2.name is null and p.link_type in (?, ?, ?, ?)))" +
+ " where" +
+ " p2.uuid is null" +
+ " order by p.id")
+ .setString(1, SCOPE_PROJECT)
+ .setString(2, QUALIFIER_PROJECT)
+ .setString(3, TYPE_HOME_PAGE)
+ .setString(4, TYPE_CI)
+ .setString(5, TYPE_ISSUE_TRACKER)
+ .setString(6, TYPE_SOURCES);
+ massUpdate.update("insert into project_links2" +
+ " (uuid, project_uuid, link_type, name, href, created_at, updated_at)" +
+ " values " +
+ " (?, ?, ?, ?, ?, ?, ?)");
+ massUpdate.rowPluralName("project links");
+ massUpdate.execute((row, update) -> {
+ String componentUuid = row.getString(1);
+ String linkType = row.getString(2);
+ String name = row.getString(3);
+ String href = row.getString(4);
+
+ // project link "developer connection" are removed
+ if (linkType.equals(TYPE_SOURCES_DEV)) {
+ return false;
+ }
+
+ update.setString(1, uuidFactory.create());
+ update.setString(2, componentUuid);
+ update.setString(3, linkType);
+ // provided type don't need anymore a name, the UI will display it by getting the i18 bundle of the link_type value
+ if (PROVIDED_TYPES.contains(linkType)) {
+ update.setString(4, null);
+ } else {
+ update.setString(4, name);
+ }
+ update.setString(5, href);
+ update.setLong(6, now);
+ update.setLong(7, now);
+ return true;
+ });
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration.version.v71;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder;
+import org.sonar.server.platform.db.migration.sql.RenameTableBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
+
+public class RenameTableProjectLinks2ToProjectLinks extends DdlChange {
+
+ public RenameTableProjectLinks2ToProjectLinks(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(new RenameTableBuilder(getDialect())
+ .setName("project_links2")
+ .setNewName("project_links")
+ .setAutoGeneratedId(false)
+ .build());
+
+ context.execute(new CreateIndexBuilder(getDialect())
+ .setTable("project_links")
+ .setName("project_links_project")
+ .addColumn(newVarcharColumnDefBuilder()
+ .setColumnName("project_uuid")
+ .setLimit(UUID_SIZE)
+ .setIsNullable(false)
+ .build())
+ .build());
+ }
+
+}
"CREATE OR REPLACE TRIGGER bar_idt BEFORE INSERT ON bar FOR EACH ROW BEGIN IF :new.id IS null THEN SELECT bar_seq.nextval INTO :new.id FROM dual; END IF; END;");
}
+ @Test
+ public void rename_table_on_oracle_when_auto_generated_id_is_false() {
+ verifySqlWhenAutoGeneratedIdIsFalse(new Oracle(), "RENAME foo TO bar");
+ }
+
@Test
public void rename_table_on_postgresql() {
verifySql(new PostgreSql(), "ALTER TABLE foo RENAME TO bar");
.build();
assertThat(actual).containsExactly(expectedSql);
}
+
+ private static void verifySqlWhenAutoGeneratedIdIsFalse(Dialect dialect, String... expectedSql) {
+ List<String> actual = new RenameTableBuilder(dialect)
+ .setName("foo")
+ .setNewName("bar")
+ .setAutoGeneratedId(false)
+ .build();
+ assertThat(actual).containsExactly(expectedSql);
+ }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration.version.v71;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CreateTableProjectLinks2Test {
+
+ private static final String TABLE_NAME = "project_links2";
+
+ @Rule
+ public final CoreDbTester dbTester = CoreDbTester.createForSchema(CreateTableProjectLinks2Test.class, "empty.sql");
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private CreateTableProjectLinks2 underTest = new CreateTableProjectLinks2(dbTester.database());
+
+ @Test
+ public void creates_table_on_empty_db() throws SQLException {
+ underTest.execute();
+
+ assertThat(dbTester.countRowsOfTable(TABLE_NAME)).isEqualTo(0);
+
+ dbTester.assertColumnDefinition(TABLE_NAME, "uuid", Types.VARCHAR, 40, false);
+ dbTester.assertColumnDefinition(TABLE_NAME, "project_uuid", Types.VARCHAR, 40, false);
+ dbTester.assertColumnDefinition(TABLE_NAME, "link_type", Types.VARCHAR, 20, false);
+ dbTester.assertColumnDefinition(TABLE_NAME, "name", Types.VARCHAR, 128, true);
+ dbTester.assertColumnDefinition(TABLE_NAME, "href", Types.VARCHAR, 2048, false);
+ dbTester.assertColumnDefinition(TABLE_NAME, "created_at", Types.BIGINT, null, false);
+ dbTester.assertColumnDefinition(TABLE_NAME, "updated_at", Types.BIGINT, null, false);
+ }
+
+ @Test
+ public void migration_is_not_reentrant() throws SQLException {
+ underTest.execute();
+
+ expectedException.expect(IllegalStateException.class);
+
+ underTest.execute();
+ }
+
+}
\ No newline at end of file
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 8);
+ verifyMigrationCount(underTest, 13);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration.version.v71;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+public class DropTableProjectLinksTest {
+
+ @Rule
+ public final CoreDbTester dbTester = CoreDbTester.createForSchema(DropTableProjectLinksTest.class, "project_links.sql");
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private DropTableProjectLinks underTest = new DropTableProjectLinks(dbTester.database());
+
+ @Test
+ public void creates_table_on_empty_db() throws SQLException {
+ underTest.execute();
+
+ dbTester.assertTableDoesNotExist("project_links");
+ }
+
+ @Test
+ public void migration_is_not_reentrant() throws SQLException {
+ underTest.execute();
+
+ expectedException.expect(IllegalStateException.class);
+
+ underTest.execute();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration.version.v71;
+
+import java.sql.SQLException;
+import java.util.stream.Collectors;
+import org.assertj.core.groups.Tuple;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.core.util.SequenceUuidFactory;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.CoreDbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.groups.Tuple.tuple;
+
+public class PopulateTableProjectLinks2Test {
+
+ private static final long PAST = 5_000_000_000L;
+ private static final long NOW = 10_000_000_000L;
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(PopulateTableProjectLinks2Test.class, "project_links2.sql");
+
+ private System2 system2 = new TestSystem2().setNow(NOW);
+ private UuidFactory uuidFactory = new SequenceUuidFactory();
+
+ private PopulateTableProjectLinks2 underTest = new PopulateTableProjectLinks2(db.database(), uuidFactory, system2);
+
+ @Test
+ public void copy_custom_links() throws SQLException {
+ String project = insertProject();
+ insertProjectLink("Name1", "custom1", "http://link1", project);
+ insertProjectLink("Name2", "custom2", "http://link2", project);
+
+ underTest.execute();
+
+ assertProjectLinks2(
+ tuple("Name1", "custom1", "http://link1", project, NOW, NOW),
+ tuple("Name2", "custom2", "http://link2", project, NOW, NOW));
+ }
+
+ @Test
+ public void remove_name_of_provided_links() throws SQLException {
+ String project = insertProject();
+ insertProjectLink("Home", "homepage", "http://homepage", project);
+ insertProjectLink("CI", "ci", "http://ci", project);
+ insertProjectLink("Jira", "issue", "http://issue", project);
+ insertProjectLink("SCM", "scm", "http://scm", project);
+
+ underTest.execute();
+
+ assertProjectLinks2(
+ tuple(null, "homepage", "http://homepage", project, NOW, NOW),
+ tuple(null, "ci", "http://ci", project, NOW, NOW),
+ tuple(null, "issue", "http://issue", project, NOW, NOW),
+ tuple(null, "scm", "http://scm", project, NOW, NOW));
+ }
+
+ @Test
+ public void copy_links_from_different_projects() throws SQLException {
+ String project1 = insertProject();
+ insertProjectLink("Name", "custom", "http://link1", project1);
+ String project2 = insertProject();
+ insertProjectLink("Name", "custom", "http://link2", project2);
+
+ underTest.execute();
+
+ assertProjectLinks2(
+ tuple("Name", "custom", "http://link1", project1, NOW, NOW),
+ tuple("Name", "custom", "http://link2", project2, NOW, NOW));
+ }
+
+ @Test
+ public void do_not_copy_links_from_developer_connection_link() throws SQLException {
+ insertProjectLink("Dev", "scm_dev", "http://link1", insertProject());
+
+ underTest.execute();
+
+ assertNoProjectLinks2();
+ }
+
+ @Test
+ public void do_not_copy_links_from_components_that_are_not_projects() throws SQLException {
+ insertProjectLink("Name", "custom", "http://link1", insertComponent("PRJ", "BRC"));
+ insertProjectLink("Name", "custom", "http://link2", insertComponent("PRJ", "VW"));
+ insertProjectLink("Name", "custom", "http://link1", insertComponent("DIR", "DIR"));
+ insertProjectLink("Name", "custom", "http://link1", "UNKNOWN");
+
+ underTest.execute();
+
+ assertNoProjectLinks2();
+ }
+
+ @Test
+ public void do_not_copy_already_copied_data() throws SQLException {
+ String project = insertProject();
+ insertProjectLink("Name", "custom", "http://link", project);
+ insertProjectLink("Home", "homepage", "http://homepage", project);
+ insertProjectLink2("UUID1", "Name", "custom", "http://link", project, PAST);
+ insertProjectLink2("UUID2", null, "homepage", "http://homepage", project, PAST);
+
+ underTest.execute();
+
+ assertThat(db.select("SELECT UUID, NAME, LINK_TYPE, HREF, PROJECT_UUID, CREATED_AT FROM PROJECT_LINKS2")
+ .stream()
+ .map(map -> new Tuple(map.get("UUID"), map.get("NAME"), map.get("LINK_TYPE"), map.get("HREF"), map.get("PROJECT_UUID"), map.get("CREATED_AT")))
+ .collect(Collectors.toList()))
+ .containsExactlyInAnyOrder(
+ tuple("UUID1", "Name", "custom", "http://link", project, PAST),
+ tuple("UUID2", null, "homepage", "http://homepage", project, PAST));
+ }
+
+ @Test
+ public void migration_is_reentrant() throws SQLException {
+ String project = insertProject();
+ insertProjectLink("Name", "custom", "http://link", project);
+
+ underTest.execute();
+ underTest.execute();
+
+ assertProjectLinks2(tuple("Name", "custom", "http://link", project, NOW, NOW));
+ }
+
+ @Test
+ public void has_no_effect_if_table_is_empty() throws SQLException {
+ underTest.execute();
+
+ assertThat(db.countRowsOfTable("project_links2")).isZero();
+ }
+
+ private void assertNoProjectLinks2() {
+ assertProjectLinks2();
+ }
+
+ private void assertProjectLinks2(Tuple... expectedTuples) {
+ assertThat(db.select("SELECT NAME, LINK_TYPE, HREF, PROJECT_UUID, CREATED_AT, UPDATED_AT FROM PROJECT_LINKS2")
+ .stream()
+ .map(map -> new Tuple(map.get("NAME"), map.get("LINK_TYPE"), map.get("HREF"), map.get("PROJECT_UUID"), map.get("CREATED_AT"), map.get("UPDATED_AT")))
+ .collect(Collectors.toList()))
+ .containsExactlyInAnyOrder(expectedTuples);
+ }
+
+ private void insertProjectLink(String name, String linkType, String href, String componentUuid) {
+ db.executeInsert(
+ "PROJECT_LINKS",
+ "COMPONENT_UUID", componentUuid,
+ "NAME", name,
+ "LINK_TYPE", linkType,
+ "HREF", href);
+ }
+
+ private void insertProjectLink2(String uuid, String name, String linkType, String href, String componentUuid, Long createdAt) {
+ db.executeInsert(
+ "PROJECT_LINKS2",
+ "UUID", uuid,
+ "PROJECT_UUID", componentUuid,
+ "NAME", name,
+ "LINK_TYPE", linkType,
+ "HREF", href,
+ "CREATED_AT", createdAt,
+ "UPDATED_AT", createdAt);
+ }
+
+ private String insertProject() {
+ return insertComponent("PRJ", "TRK");
+ }
+
+ private String insertComponent(String scope, String qualifier) {
+ String uuid = uuidFactory.create();
+ db.executeInsert("PROJECTS",
+ "ORGANIZATION_UUID", "O1",
+ "KEE", uuid,
+ "UUID", uuid,
+ "PROJECT_UUID", uuid,
+ "MAIN_BRANCH_PROJECT_UUID", uuid,
+ "UUID_PATH", ".",
+ "ROOT_UUID", uuid,
+ "PRIVATE", "true",
+ "QUALIFIER", qualifier,
+ "SCOPE", scope);
+ return uuid;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration.version.v71;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RenameTableProjectLinks2ToProjectLinksTest {
+
+ @Rule
+ public final CoreDbTester dbTester = CoreDbTester.createForSchema(RenameTableProjectLinks2ToProjectLinksTest.class, "project_links2.sql");
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private RenameTableProjectLinks2ToProjectLinks underTest = new RenameTableProjectLinks2ToProjectLinks(dbTester.database());
+
+ @Test
+ public void creates_table_on_empty_db() throws SQLException {
+ underTest.execute();
+
+ dbTester.assertTableDoesNotExist("project_links2");
+ assertThat(dbTester.countRowsOfTable("project_links")).isZero();
+ dbTester.assertIndex("project_links", "project_links_project", "project_uuid");
+ }
+
+ @Test
+ public void migration_is_not_reentrant() throws SQLException {
+ underTest.execute();
+
+ expectedException.expect(IllegalStateException.class);
+
+ underTest.execute();
+ }
+
+}
--- /dev/null
+CREATE TABLE "PROJECT_LINKS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "COMPONENT_UUID" VARCHAR(50),
+ "LINK_TYPE" VARCHAR(20),
+ "NAME" VARCHAR(128),
+ "HREF" VARCHAR(2048) NOT NULL
+);
--- /dev/null
+CREATE TABLE "PROJECT_LINKS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "COMPONENT_UUID" VARCHAR(50),
+ "LINK_TYPE" VARCHAR(20),
+ "NAME" VARCHAR(128),
+ "HREF" VARCHAR(2048) NOT NULL
+);
+
+CREATE TABLE "PROJECT_LINKS2" (
+ "UUID" VARCHAR(40) NOT NULL PRIMARY KEY,
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ "LINK_TYPE" VARCHAR(20) NOT NULL,
+ "NAME" VARCHAR(128),
+ "HREF" VARCHAR(2048) NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL
+);
+
+CREATE TABLE "PROJECTS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
+ "KEE" VARCHAR(400),
+ "UUID" VARCHAR(50) NOT NULL,
+ "UUID_PATH" VARCHAR(1500) NOT NULL,
+ "ROOT_UUID" VARCHAR(50) NOT NULL,
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ "MODULE_UUID" VARCHAR(50),
+ "MODULE_UUID_PATH" VARCHAR(1500),
+ "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50),
+ "NAME" VARCHAR(2000),
+ "DESCRIPTION" VARCHAR(2000),
+ "PRIVATE" BOOLEAN NOT NULL,
+ "TAGS" VARCHAR(500),
+ "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE,
+ "SCOPE" VARCHAR(3),
+ "QUALIFIER" VARCHAR(10),
+ "DEPRECATED_KEE" VARCHAR(400),
+ "PATH" VARCHAR(2000),
+ "LANGUAGE" VARCHAR(20),
+ "COPY_COMPONENT_UUID" VARCHAR(50),
+ "LONG_NAME" VARCHAR(2000),
+ "DEVELOPER_UUID" VARCHAR(50),
+ "CREATED_AT" TIMESTAMP,
+ "AUTHORIZATION_UPDATED_AT" BIGINT,
+ "B_CHANGED" BOOLEAN,
+ "B_COPY_COMPONENT_UUID" VARCHAR(50),
+ "B_DESCRIPTION" VARCHAR(2000),
+ "B_ENABLED" BOOLEAN,
+ "B_UUID_PATH" VARCHAR(1500),
+ "B_LANGUAGE" VARCHAR(20),
+ "B_LONG_NAME" VARCHAR(500),
+ "B_MODULE_UUID" VARCHAR(50),
+ "B_MODULE_UUID_PATH" VARCHAR(1500),
+ "B_NAME" VARCHAR(500),
+ "B_PATH" VARCHAR(2000),
+ "B_QUALIFIER" VARCHAR(10)
+);
+CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID");
+CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE");
+CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID");
+CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID");
+CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID");
+CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID");
+CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER");
\ No newline at end of file
--- /dev/null
+CREATE TABLE "PROJECT_LINKS2" (
+ "UUID" VARCHAR(40) NOT NULL PRIMARY KEY,
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ "LINK_TYPE" VARCHAR(20) NOT NULL,
+ "NAME" VARCHAR(128),
+ "HREF" VARCHAR(2048) NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL
+);
}
public ElementsCollection getLinks() {
- return Selenide.$$("#project-links tr[data-name]");
+ return Selenide.$$("#project-links tbody tr");
}
public List<ProjectLinkItem> getLinksAsItems() {
import com.google.common.collect.ImmutableMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import org.sonar.api.i18n.I18n;
+import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
-import org.sonar.db.component.ComponentLinkDto;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.ComponentLink.ComponentLinkType;
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader;
import org.sonar.server.computation.task.projectanalysis.component.Component;
-import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit;
-import org.sonar.server.computation.task.projectanalysis.component.DepthTraversalTypeAwareCrawler;
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder;
-import org.sonar.server.computation.task.projectanalysis.component.TypeAwareVisitorAdapter;
import org.sonar.server.computation.task.step.ComputationStep;
-import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER;
+import static com.google.common.base.Preconditions.checkArgument;
-/**
- * Persist project and module links
- */
public class PersistProjectLinksStep implements ComputationStep {
private final DbClient dbClient;
- private final I18n i18n;
private final TreeRootHolder treeRootHolder;
private final BatchReportReader reportReader;
+ private final UuidFactory uuidFactory;
private static final Map<ComponentLinkType, String> typesConverter = ImmutableMap.of(
- ComponentLinkType.HOME, ComponentLinkDto.TYPE_HOME_PAGE,
- ComponentLinkType.SCM, ComponentLinkDto.TYPE_SOURCES,
- ComponentLinkType.SCM_DEV, ComponentLinkDto.TYPE_SOURCES_DEV,
- ComponentLinkType.CI, ComponentLinkDto.TYPE_CI,
- ComponentLinkType.ISSUE, ComponentLinkDto.TYPE_ISSUE_TRACKER);
+ ComponentLinkType.HOME, ProjectLinkDto.TYPE_HOME_PAGE,
+ ComponentLinkType.SCM, ProjectLinkDto.TYPE_SOURCES,
+ ComponentLinkType.SCM_DEV, ProjectLinkDto.TYPE_SOURCES_DEV,
+ ComponentLinkType.CI, ProjectLinkDto.TYPE_CI,
+ ComponentLinkType.ISSUE, ProjectLinkDto.TYPE_ISSUE_TRACKER);
- public PersistProjectLinksStep(DbClient dbClient, I18n i18n, TreeRootHolder treeRootHolder, BatchReportReader reportReader) {
+ public PersistProjectLinksStep(DbClient dbClient, TreeRootHolder treeRootHolder, BatchReportReader reportReader, UuidFactory uuidFactory) {
this.dbClient = dbClient;
- this.i18n = i18n;
this.treeRootHolder = treeRootHolder;
this.reportReader = reportReader;
+ this.uuidFactory = uuidFactory;
}
@Override
public void execute() {
try (DbSession session = dbClient.openSession(false)) {
- new DepthTraversalTypeAwareCrawler(new ProjectLinkVisitor(session))
- .visit(treeRootHolder.getRoot());
+ Component project = treeRootHolder.getRoot();
+ ScannerReport.Component batchComponent = reportReader.readComponent(project.getReportAttributes().getRef());
+ List<ProjectLinkDto> previousLinks = dbClient.projectLinkDao().selectByProjectUuid(session, project.getUuid());
+ mergeLinks(session, project.getUuid(), batchComponent.getLinkList(), previousLinks);
session.commit();
}
}
- private class ProjectLinkVisitor extends TypeAwareVisitorAdapter {
-
- private final DbSession session;
-
- private ProjectLinkVisitor(DbSession session) {
- super(CrawlerDepthLimit.FILE, PRE_ORDER);
- this.session = session;
- }
-
- @Override
- public void visitProject(Component project) {
- processComponent(project);
- }
-
- @Override
- public void visitModule(Component module) {
- processComponent(module);
- }
-
- private void processComponent(Component component) {
- ScannerReport.Component batchComponent = reportReader.readComponent(component.getReportAttributes().getRef());
- processLinks(component.getUuid(), batchComponent.getLinkList());
- }
-
- private void processLinks(String componentUuid, List<ScannerReport.ComponentLink> links) {
- List<ComponentLinkDto> previousLinks = dbClient.componentLinkDao().selectByComponentUuid(session, componentUuid);
- mergeLinks(session, componentUuid, links, previousLinks);
- }
-
- private void mergeLinks(DbSession session, String componentUuid, List<ScannerReport.ComponentLink> links, List<ComponentLinkDto> previousLinks) {
- Set<String> linkType = new HashSet<>();
- for (final ScannerReport.ComponentLink link : links) {
+ private void mergeLinks(DbSession session, String componentUuid, List<ScannerReport.ComponentLink> links, List<ProjectLinkDto> previousLinks) {
+ Set<String> linkType = new HashSet<>();
+ links.forEach(
+ link -> {
String type = convertType(link.getType());
- if (!linkType.contains(type)) {
- linkType.add(type);
- } else {
- throw new IllegalArgumentException(String.format("Link of type '%s' has already been declared on component '%s'", type, componentUuid));
- }
+ checkArgument(!linkType.contains(type), "Link of type '%s' has already been declared on component '%s'", type, componentUuid);
+ linkType.add(type);
- Optional<ComponentLinkDto> previousLink = previousLinks.stream()
+ Optional<ProjectLinkDto> previousLink = previousLinks.stream()
.filter(input -> input != null && input.getType().equals(convertType(link.getType())))
.findFirst();
if (previousLink.isPresent()) {
previousLink.get().setHref(link.getHref());
- dbClient.componentLinkDao().update(session, previousLink.get());
+ dbClient.projectLinkDao().update(session, previousLink.get());
} else {
- dbClient.componentLinkDao().insert(session,
- new ComponentLinkDto()
- .setComponentUuid(componentUuid)
+ dbClient.projectLinkDao().insert(session,
+ new ProjectLinkDto()
+ .setUuid(uuidFactory.create())
+ .setProjectUuid(componentUuid)
.setType(type)
- .setName(i18n.message(Locale.ENGLISH, "project_links." + type, null))
.setHref(link.getHref()));
}
- }
+ });
- for (ComponentLinkDto dto : previousLinks) {
- if (!linkType.contains(dto.getType()) && ComponentLinkDto.PROVIDED_TYPES.contains(dto.getType())) {
- dbClient.componentLinkDao().delete(session, dto.getId());
- }
- }
- }
+ previousLinks.stream()
+ .filter(dto -> !linkType.contains(dto.getType()))
+ .filter(dto -> ProjectLinkDto.PROVIDED_TYPES.contains(dto.getType()))
+ .forEach(dto -> dbClient.projectLinkDao().delete(session, dto.getUuid()));
+ }
- private String convertType(ComponentLinkType reportType) {
- String type = typesConverter.get(reportType);
- if (type != null) {
- return type;
- } else {
- throw new IllegalArgumentException(String.format("Unsupported type %s", reportType.name()));
- }
- }
+ private static String convertType(ComponentLinkType reportType) {
+ String type = typesConverter.get(reportType);
+ checkArgument(type != null, "Unsupported type %s", reportType.name());
+ return type;
}
@Override
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentLinkDto;
import org.sonar.db.component.ComponentQuery;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.measure.LiveMeasureDto;
import org.sonar.server.user.UserSession;
}
}
- private enum ProjectLinkDtoToWs implements Function<ComponentLinkDto, Link> {
+ private enum ProjectLinkDtoToWs implements Function<ProjectLinkDto, Link> {
INSTANCE;
@Override
- public Link apply(ComponentLinkDto dto) {
+ public Link apply(ProjectLinkDto dto) {
Link.Builder link = Link.newBuilder();
link.setHref(dto.getHref());
ProjectsResult searchResult = searchProjects(dbSession, request);
List<ComponentDto> projects = searchResult.projects;
List<String> projectUuids = Lists.transform(projects, ComponentDto::projectUuid);
- List<ComponentLinkDto> projectLinks = dbClient.componentLinkDao().selectByComponentUuids(dbSession, projectUuids);
+ List<ProjectLinkDto> projectLinks = dbClient.projectLinkDao().selectByProjectUuids(dbSession, projectUuids);
List<SnapshotDto> snapshots = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, projectUuids);
List<LiveMeasureDto> qualityGates = dbClient.liveMeasureDao()
.selectByComponentUuidsAndMetricKeys(dbSession, projectUuids, singletonList(CoreMetrics.ALERT_STATUS_KEY));
import java.util.Optional;
import java.util.stream.Collectors;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentLinkDto;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.measure.LiveMeasureDto;
class SearchMyProjectsData {
private final List<ComponentDto> projects;
- private final ListMultimap<String, ComponentLinkDto> projectLinksByProjectUuid;
+ private final ListMultimap<String, ProjectLinkDto> projectLinksByProjectUuid;
private final Map<String, String> lastAnalysisDates;
private final Map<String, String> qualityGateStatuses;
private final int totalNbOfProject;
return projects;
}
- List<ComponentLinkDto> projectLinksFor(String projectUuid) {
+ List<ProjectLinkDto> projectLinksFor(String projectUuid) {
return projectLinksByProjectUuid.get(projectUuid);
}
return totalNbOfProject;
}
- private static ListMultimap<String, ComponentLinkDto> buildProjectLinks(List<ComponentLinkDto> dtos) {
- ImmutableListMultimap.Builder<String, ComponentLinkDto> projectLinks = ImmutableListMultimap.builder();
- dtos.forEach(projectLink -> projectLinks.put(projectLink.getComponentUuid(), projectLink));
+ private static ListMultimap<String, ProjectLinkDto> buildProjectLinks(List<ProjectLinkDto> dtos) {
+ ImmutableListMultimap.Builder<String, ProjectLinkDto> projectLinks = ImmutableListMultimap.builder();
+ dtos.forEach(projectLink -> projectLinks.put(projectLink.getProjectUuid(), projectLink));
return projectLinks.build();
}
static class Builder {
private List<ComponentDto> projects;
- private List<ComponentLinkDto> projectLinks;
+ private List<ProjectLinkDto> projectLinks;
private List<SnapshotDto> snapshots;
private List<LiveMeasureDto> qualityGates;
private Integer totalNbOfProjects;
return this;
}
- public Builder setProjectLinks(List<ComponentLinkDto> projectLinks) {
+ public Builder setProjectLinks(List<ProjectLinkDto> projectLinks) {
this.projectLinks = projectLinks;
return this;
}
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.web.UserRole;
+import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentLinkDto;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.ProjectLinks;
import static org.sonar.core.util.Slug.slugify;
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
-import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
-import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonar.server.projectlink.ws.ProjectLinksWs.checkProject;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.ACTION_CREATE;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_NAME;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_PROJECT_ID;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_PROJECT_KEY;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_URL;
+import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
public class CreateAction implements ProjectLinksWsAction {
private final DbClient dbClient;
private final UserSession userSession;
private final ComponentFinder componentFinder;
+ private final UuidFactory uuidFactory;
private static final int LINK_NAME_MAX_LENGTH = 128;
private static final int LINK_URL_MAX_LENGTH = 2048;
private static final int LINK_TYPE_MAX_LENGTH = 20;
- public CreateAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder) {
+ public CreateAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder, UuidFactory uuidFactory) {
this.dbClient = dbClient;
this.userSession = userSession;
this.componentFinder = componentFinder;
+ this.uuidFactory = uuidFactory;
}
@Override
String url = createWsRequest.getUrl();
try (DbSession dbSession = dbClient.openSession(false)) {
- ComponentDto component = getComponentByUuidOrKey(dbSession, createWsRequest);
+ ComponentDto component = checkProject(getComponentByUuidOrKey(dbSession, createWsRequest));
userSession.checkComponentPermission(UserRole.ADMIN, component);
- ComponentLinkDto link = new ComponentLinkDto()
- .setComponentUuid(component.uuid())
+ ProjectLinkDto link = new ProjectLinkDto()
+ .setUuid(uuidFactory.create())
+ .setProjectUuid(component.uuid())
.setName(name)
.setHref(url)
.setType(nameToType(name));
- dbClient.componentLinkDao().insert(dbSession, link);
+ dbClient.projectLinkDao().insert(dbSession, link);
dbSession.commit();
return buildResponse(link);
}
}
- private static CreateWsResponse buildResponse(ComponentLinkDto link) {
+ private static CreateWsResponse buildResponse(ProjectLinkDto link) {
return CreateWsResponse.newBuilder().setLink(ProjectLinks.Link.newBuilder()
- .setId(String.valueOf(link.getId()))
+ .setId(String.valueOf(link.getUuid()))
.setName(link.getName())
.setType(link.getType())
.setUrl(link.getHref()))
}
private ComponentDto getComponentByUuidOrKey(DbSession dbSession, CreateRequest request) {
- return componentFinder.getRootComponentByUuidOrKey(
+ return componentFinder.getByUuidOrKey(
dbSession,
request.getProjectId(),
request.getProjectKey(),
import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
-import org.sonar.db.component.ComponentLinkDto;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.server.user.UserSession;
import org.sonar.server.ws.WsUtils;
-import static org.sonar.db.component.ComponentLinkDto.PROVIDED_TYPES;
+import static org.sonar.db.component.ProjectLinkDto.PROVIDED_TYPES;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.ACTION_DELETE;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_ID;
response.noContent();
}
- private void doHandle(String idParam) {
+ private void doHandle(String id) {
try (DbSession dbSession = dbClient.openSession(false)) {
- long id = Long.parseLong(idParam);
- ComponentLinkDto link = dbClient.componentLinkDao().selectById(dbSession, id);
+ ProjectLinkDto link = dbClient.projectLinkDao().selectByUuid(dbSession, id);
link = WsUtils.checkFound(link, "Link with id '%s' not found", id);
checkProjectAdminPermission(link);
checkNotProvided(link);
- dbClient.componentLinkDao().delete(dbSession, link.getId());
+ dbClient.projectLinkDao().delete(dbSession, link.getUuid());
dbSession.commit();
}
}
- private static void checkNotProvided(ComponentLinkDto link) {
+ private static void checkNotProvided(ProjectLinkDto link) {
String type = link.getType();
boolean isProvided = type != null && PROVIDED_TYPES.contains(type);
WsUtils.checkRequest(!isProvided, "Provided link cannot be deleted.");
}
- private void checkProjectAdminPermission(ComponentLinkDto link) {
- userSession.checkComponentUuidPermission(UserRole.ADMIN, link.getComponentUuid());
+ private void checkProjectAdminPermission(ProjectLinkDto link) {
+ userSession.checkComponentUuidPermission(UserRole.ADMIN, link.getProjectUuid());
}
}
*/
package org.sonar.server.projectlink.ws;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Scopes;
import org.sonar.api.server.ws.WebService;
+import org.sonar.db.component.ComponentDto;
+
+import static java.lang.String.format;
+import static org.sonar.server.ws.WsUtils.checkRequest;
public class ProjectLinksWs implements WebService {
controller.done();
}
+ static ComponentDto checkProject(ComponentDto component) {
+ checkRequest(component.scope().equals(Scopes.PROJECT) && component.qualifier().equals(Qualifiers.PROJECT),
+ format("Component '%s' must be a project.", component.getKey()));
+ return component;
+ }
+
}
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentLinkDto;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.ProjectLinks.Link;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
-import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
-import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
-import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonar.server.projectlink.ws.ProjectLinksWs.checkProject;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.ACTION_SEARCH;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_PROJECT_ID;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_PROJECT_KEY;
+import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
+import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
public class SearchAction implements ProjectLinksWsAction {
private final DbClient dbClient;
"</ul>",
PARAM_PROJECT_ID, PARAM_PROJECT_KEY)
.setHandler(this)
- .setResponseExample(getClass().getResource("list-example.json"))
+ .setResponseExample(getClass().getResource("search-example.json"))
.setSince("6.1");
action.createParam(PARAM_PROJECT_ID)
private SearchWsResponse doHandle(SearchRequest searchWsRequest) {
try (DbSession dbSession = dbClient.openSession(false)) {
ComponentDto component = getComponentByUuidOrKey(dbSession, searchWsRequest);
- List<ComponentLinkDto> links = dbClient.componentLinkDao()
- .selectByComponentUuid(dbSession, component.uuid());
+ List<ProjectLinkDto> links = dbClient.projectLinkDao()
+ .selectByProjectUuid(dbSession, component.uuid());
return buildResponse(links);
}
}
- private static SearchWsResponse buildResponse(List<ComponentLinkDto> links) {
+ private static SearchWsResponse buildResponse(List<ProjectLinkDto> links) {
return SearchWsResponse.newBuilder()
.addAllLinks(links.stream()
.map(SearchAction::buildLink)
.build();
}
- private static Link buildLink(ComponentLinkDto link) {
+ private static Link buildLink(ProjectLinkDto link) {
Link.Builder builder = Link.newBuilder()
- .setId(String.valueOf(link.getId()))
+ .setId(String.valueOf(link.getUuid()))
+ .setType(link.getType())
.setUrl(link.getHref());
setNullable(link.getName(), builder::setName);
- setNullable(link.getType(), builder::setType);
return builder.build();
}
private ComponentDto getComponentByUuidOrKey(DbSession dbSession, SearchRequest request) {
- ComponentDto component = componentFinder.getRootComponentByUuidOrKey(
+ ComponentDto component = componentFinder.getByUuidOrKey(
dbSession,
request.getProjectId(),
request.getProjectKey(),
ComponentFinder.ParamNames.PROJECT_ID_AND_KEY);
-
if (!userSession.hasComponentPermission(UserRole.ADMIN, component) &&
!userSession.hasComponentPermission(UserRole.USER, component)) {
throw insufficientPrivilegesException();
}
-
- return component;
+ return checkProject(component);
}
private static SearchRequest toSearchWsRequest(Request request) {
+++ /dev/null
-{
- "links": [
- {
- "id": "1",
- "name": "Homepage",
- "type": "homepage",
- "url": "http://example.org"
- },
- {
- "id": "2",
- "name": "Custom",
- "url": "http://example.org/custom"
- }
- ]
-}
\ No newline at end of file
--- /dev/null
+{
+ "links": [
+ {
+ "id": "1",
+ "name": "Homepage",
+ "type": "homepage",
+ "url": "http://example.org"
+ },
+ {
+ "id": "2",
+ "name": "Custom",
+ "type": "custom",
+ "url": "http://example.org/custom"
+ }
+ ]
+}
\ No newline at end of file
*/
package org.sonar.server.computation.task.projectanalysis.step;
-import java.util.Locale;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.i18n.I18n;
+import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType;
-import org.sonar.scanner.protocol.output.ScannerReport.ComponentLink.ComponentLinkType;
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule;
-import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
import org.sonar.server.computation.task.projectanalysis.component.Component;
import org.sonar.server.computation.task.projectanalysis.component.ReportComponent;
-import org.sonar.server.computation.task.projectanalysis.component.VisitException;
+import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
import org.sonar.server.computation.task.step.ComputationStep;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.sonar.scanner.protocol.output.ScannerReport.ComponentLink.ComponentLinkType.CI;
+import static org.sonar.scanner.protocol.output.ScannerReport.ComponentLink.ComponentLinkType.HOME;
+import static org.sonar.scanner.protocol.output.ScannerReport.ComponentLink.ComponentLinkType.ISSUE;
+import static org.sonar.scanner.protocol.output.ScannerReport.ComponentLink.ComponentLinkType.SCM;
+import static org.sonar.scanner.protocol.output.ScannerReport.ComponentLink.ComponentLinkType.SCM_DEV;
public class PersistProjectLinksStepTest extends BaseStepTest {
@Rule
- public DbTester dbTester = DbTester.create(System2.INSTANCE);
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Rule
+ public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
- PersistProjectLinksStep step;
-
- @Before
- public void setup() {
- I18n i18n = mock(I18n.class);
- when(i18n.message(Locale.ENGLISH, "project_links.homepage", null)).thenReturn("Home");
- when(i18n.message(Locale.ENGLISH, "project_links.scm", null)).thenReturn("Sources");
- when(i18n.message(Locale.ENGLISH, "project_links.scm_dev", null)).thenReturn("Developer connection");
- when(i18n.message(Locale.ENGLISH, "project_links.ci", null)).thenReturn("Continuous integration");
- when(i18n.message(Locale.ENGLISH, "project_links.issue", null)).thenReturn("Issues");
-
- step = new PersistProjectLinksStep(dbTester.getDbClient(), i18n, treeRootHolder, reportReader);
- }
+ PersistProjectLinksStep step = new PersistProjectLinksStep(db.getDbClient(), treeRootHolder, reportReader, UuidFactoryFast.getInstance());
@Override
protected ComputationStep step() {
}
@Test
- public void add_links_on_project_and_module() {
- dbTester.prepareDbUnit(getClass(), "empty.xml");
-
+ public void add_links_on_project() {
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").addChildren(
ReportComponent.builder(Component.Type.MODULE, 2).setUuid("BCDE").build())
.build());
- // project and 1 module
+ // project
reportReader.putComponent(ScannerReport.Component.newBuilder()
.setRef(1)
.setType(ComponentType.PROJECT)
.addChildRef(2)
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.HOME).setHref("http://www.sonarqube.org").build())
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.SCM).setHref("https://github.com/SonarSource/sonar").build())
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.SCM_DEV).setHref("scm:git:git@github.com:SonarSource/sonar.git/sonar").build())
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.ISSUE).setHref("http://jira.sonarsource.com/").build())
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.CI).setHref("http://bamboo.ci.codehaus.org/browse/SONAR").build())
- .build());
- reportReader.putComponent(ScannerReport.Component.newBuilder()
- .setRef(2)
- .setType(ComponentType.MODULE)
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.SCM).setHref("https://github.com/SonarSource/sonar/server").build())
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(HOME).setHref("http://www.sonarqube.org").build())
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(SCM).setHref("https://github.com/SonarSource/sonar").build())
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(SCM_DEV).setHref("scm:git:git@github.com:SonarSource/sonar.git/sonar").build())
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(ISSUE).setHref("http://jira.sonarsource.com/").build())
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(CI).setHref("http://bamboo.ci.codehaus.org/browse/SONAR").build())
.build());
step.execute();
- dbTester.assertDbUnit(getClass(), "add_links_on_project_and_module-result.xml", "project_links");
+ assertThat(db.getDbClient().projectLinkDao().selectByProjectUuid(db.getSession(), "ABCD"))
+ .extracting(ProjectLinkDto::getType, ProjectLinkDto::getHref, ProjectLinkDto::getName)
+ .containsExactlyInAnyOrder(
+ tuple("homepage", "http://www.sonarqube.org", null),
+ tuple("scm", "https://github.com/SonarSource/sonar", null),
+ tuple("scm_dev", "scm:git:git@github.com:SonarSource/sonar.git/sonar", null),
+ tuple("issue", "http://jira.sonarsource.com/", null),
+ tuple("ci", "http://bamboo.ci.codehaus.org/browse/SONAR", null));
}
@Test
public void nothing_to_do_when_link_already_exists() {
- dbTester.prepareDbUnit(getClass(), "nothing_to_do_when_link_already_exists.xml");
+ ComponentDto project = db.components().insertPrivateProject(p -> p.setUuid("ABCD"));
+ db.componentLinks().insertProvidedLink(project, l -> l.setType("homepage").setName("Home").setHref("http://www.sonarqube.org"));
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build());
reportReader.putComponent(ScannerReport.Component.newBuilder()
.setRef(1)
.setType(ComponentType.PROJECT)
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.HOME).setHref("http://www.sonarqube.org").build())
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(HOME).setHref("http://www.sonarqube.org").build())
.build());
step.execute();
- dbTester.assertDbUnit(getClass(), "nothing_to_do_when_link_already_exists.xml", "project_links");
+ assertThat(db.getDbClient().projectLinkDao().selectByProjectUuid(db.getSession(), "ABCD"))
+ .extracting(ProjectLinkDto::getType, ProjectLinkDto::getHref)
+ .containsExactlyInAnyOrder(tuple("homepage", "http://www.sonarqube.org"));
}
@Test
- public void do_not_add_links_on_file() {
- dbTester.prepareDbUnit(getClass(), "empty.xml");
+ public void do_not_add_links_on_module() {
+ treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").addChildren(
+ ReportComponent.builder(Component.Type.MODULE, 2).setUuid("BCDE").build())
+ .build());
+ reportReader.putComponent(ScannerReport.Component.newBuilder()
+ .setRef(1)
+ .setType(ComponentType.PROJECT)
+ .addChildRef(2)
+ .build());
+ reportReader.putComponent(ScannerReport.Component.newBuilder()
+ .setRef(2)
+ .setType(ComponentType.MODULE)
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(HOME).setHref("http://www.sonarqube.org").build())
+ .build());
+ step.execute();
+
+ assertThat(db.countRowsOfTable("project_links")).isZero();
+ }
+
+ @Test
+ public void do_not_add_links_on_file() {
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").addChildren(
ReportComponent.builder(Component.Type.FILE, 2).setUuid("BCDE").build())
.build());
reportReader.putComponent(ScannerReport.Component.newBuilder()
.setRef(2)
.setType(ComponentType.FILE)
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.HOME).setHref("http://www.sonarqube.org").build())
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(HOME).setHref("http://www.sonarqube.org").build())
.build());
step.execute();
- assertThat(dbTester.countRowsOfTable("project_links")).isEqualTo(0);
+ assertThat(db.countRowsOfTable("project_links")).isZero();
}
@Test
public void update_link() {
- dbTester.prepareDbUnit(getClass(), "update_link.xml");
+ ComponentDto project = db.components().insertPrivateProject(p -> p.setUuid("ABCD"));
+ db.componentLinks().insertProvidedLink(project, l -> l.setType("homepage").setName("Home").setHref("http://www.sonar.org"));
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build());
reportReader.putComponent(ScannerReport.Component.newBuilder()
.setRef(1)
.setType(ComponentType.PROJECT)
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.HOME).setHref("http://www.sonarqube.org").build())
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(HOME).setHref("http://www.sonarqube.org").build())
.build());
step.execute();
- dbTester.assertDbUnit(getClass(), "update_link-result.xml", "project_links");
+ assertThat(db.getDbClient().projectLinkDao().selectByProjectUuid(db.getSession(), "ABCD"))
+ .extracting(ProjectLinkDto::getType, ProjectLinkDto::getHref)
+ .containsExactlyInAnyOrder(tuple("homepage", "http://www.sonarqube.org"));
}
@Test
public void delete_link() {
- dbTester.prepareDbUnit(getClass(), "delete_link.xml");
+ ComponentDto project = db.components().insertPrivateProject(p -> p.setUuid("ABCD"));
+ db.componentLinks().insertProvidedLink(project, l -> l.setType("homepage").setName("Home").setHref("http://www.sonar.org"));
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build());
step.execute();
- assertThat(dbTester.countRowsOfTable("project_links")).isEqualTo(0);
+ assertThat(db.countRowsOfTable("project_links")).isZero();
}
@Test
public void not_delete_custom_link() {
- dbTester.prepareDbUnit(getClass(), "not_delete_custom_link.xml");
+ ComponentDto project = db.components().insertPrivateProject(p -> p.setUuid("ABCD"));
+ db.componentLinks().insertCustomLink(project);
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build());
step.execute();
- dbTester.assertDbUnit(getClass(), "not_delete_custom_link.xml", "project_links");
+ assertThat(db.countRowsOfTable("project_links")).isEqualTo(1);
}
@Test
public void fail_when_trying_to_add_same_link_type_multiple_times() {
- dbTester.prepareDbUnit(getClass(), "empty.xml");
-
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build());
reportReader.putComponent(ScannerReport.Component.newBuilder()
.setRef(1)
.setType(ComponentType.PROJECT)
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.HOME).setHref("http://www.sonarqube.org").build())
- .addLink(ScannerReport.ComponentLink.newBuilder().setType(ComponentLinkType.HOME).setHref("http://www.sonarqube.org").build())
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(HOME).setHref("http://www.sonarqube.org").build())
+ .addLink(ScannerReport.ComponentLink.newBuilder().setType(HOME).setHref("http://www.sonarqube.org").build())
.build());
- try {
- step.execute();
- failBecauseExceptionWasNotThrown(VisitException.class);
- } catch (VisitException e) {
- assertThat(e.getCause()).isInstanceOf(IllegalArgumentException.class);
- assertThat(e.getCause()).hasMessage("Link of type 'homepage' has already been declared on component 'ABCD'");
- }
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Link of type 'homepage' has already been declared on component 'ABCD'");
+
+ step.execute();
}
}
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentLinkDto;
import org.sonar.db.component.ComponentTesting;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.metric.MetricDto;
import org.sonar.db.organization.OrganizationDto;
OrganizationDto organizationDto = db.organizations().insert();
ComponentDto jdk7 = insertJdk7(organizationDto);
ComponentDto cLang = insertClang(organizationDto);
- dbClient.componentLinkDao().insert(dbSession,
- new ComponentLinkDto().setComponentUuid(jdk7.uuid()).setHref("http://www.oracle.com").setType(ComponentLinkDto.TYPE_HOME_PAGE).setName("Home"));
- dbClient.componentLinkDao().insert(dbSession,
- new ComponentLinkDto().setComponentUuid(jdk7.uuid()).setHref("http://download.java.net/openjdk/jdk8/").setType(ComponentLinkDto.TYPE_SOURCES).setName("Sources"));
+ db.componentLinks().insertProvidedLink(jdk7, l -> l.setHref("http://www.oracle.com").setType(ProjectLinkDto.TYPE_HOME_PAGE).setName("Home"));
+ db.componentLinks().insertProvidedLink(jdk7, l -> l.setHref("http://download.java.net/openjdk/jdk8/").setType(ProjectLinkDto.TYPE_SOURCES).setName("Sources"));
long oneTime = DateUtils.parseDateTime("2016-06-10T13:17:53+0000").getTime();
long anotherTime = DateUtils.parseDateTime("2016-06-11T14:25:53+0000").getTime();
SnapshotDto jdk7Snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(jdk7).setCreatedAt(oneTime));
*/
package org.sonar.server.projectlink.ws;
-import java.io.IOException;
import java.util.Random;
import org.apache.commons.lang.StringUtils;
-import org.junit.Before;
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.util.UuidFactoryFast;
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.ComponentLinkDto;
import org.sonar.db.component.ComponentTesting;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.db.organization.OrganizationDto;
-import org.sonar.server.component.ComponentFinder;
import org.sonar.server.component.TestComponentFinder;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
-import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
-import static org.sonar.test.JsonAssert.assertJson;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_NAME;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_PROJECT_ID;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_PROJECT_KEY;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_URL;
+import static org.sonar.test.JsonAssert.assertJson;
public class CreateActionTest {
- private final String PROJECT_KEY = KEY_PROJECT_EXAMPLE_001;
- private final String PROJECT_UUID = UUID_EXAMPLE_01;
-
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
private DbClient dbClient = db.getDbClient();
private DbSession dbSession = db.getSession();
- private WsActionTester ws;
-
- private CreateAction underTest;
-
- @Before
- public void setUp() {
- ComponentFinder componentFinder = TestComponentFinder.from(db);
- underTest = new CreateAction(dbClient, userSession, componentFinder);
- ws = new WsActionTester(underTest);
- }
+ private WsActionTester ws = new WsActionTester(new CreateAction(dbClient, userSession, TestComponentFinder.from(db), UuidFactoryFast.getInstance()));
@Test
public void example_with_key() {
- ComponentDto project = insertProject();
+ ComponentDto project = db.components().insertPrivateProject();
logInAsProjectAdministrator(project);
String result = ws.newRequest()
@Test
public void example_with_id() {
- ComponentDto project = insertProject();
+ ComponentDto project = db.components().insertPrivateProject();
logInAsProjectAdministrator(project);
String result = ws.newRequest()
}
@Test
- public void require_project_admin() throws IOException {
- ComponentDto project = insertProject();
+ public void require_project_admin() {
+ ComponentDto project = db.components().insertPrivateProject();
logInAsProjectAdministrator(project);
+
createAndTest(project);
}
@Test
- public void with_long_name() throws IOException {
- ComponentDto project = insertProject();
+ public void with_long_name() {
+ ComponentDto project = db.components().insertPrivateProject();
logInAsProjectAdministrator(project);
-
String longName = StringUtils.leftPad("", 60, "a");
String expectedType = StringUtils.leftPad("", 20, "a");
+
createAndTest(project, longName, "http://example.org", expectedType);
}
@Test
public void fail_if_anonymous() {
userSession.anonymous();
- insertProject();
+ ComponentDto project = db.components().insertPublicProject();
+ userSession.registerComponents(project);
expectedException.expect(ForbiddenException.class);
+
ws.newRequest()
- .setParam(PARAM_PROJECT_KEY, PROJECT_KEY)
+ .setParam(PARAM_PROJECT_KEY, project.getKey())
.setParam(PARAM_NAME, "Custom")
.setParam(PARAM_URL, "http://example.org")
.execute();
@Test
public void fail_if_not_project_admin() {
userSession.logIn();
- insertProject();
+ ComponentDto project = db.components().insertPrivateProject();
expectedException.expect(ForbiddenException.class);
+
ws.newRequest()
- .setParam(PARAM_PROJECT_KEY, PROJECT_KEY)
+ .setParam(PARAM_PROJECT_KEY, project.getKey())
.setParam(PARAM_NAME, "Custom")
.setParam(PARAM_URL, "http://example.org")
.execute();
}
@Test
- public void fail_if_subview() {
+ public void fail_if_view() {
ComponentDto view = db.components().insertView();
- ComponentDto subview = db.components().insertComponent(ComponentTesting.newSubView(view));
- failIfNotAProject(view, subview);
+ failIfNotAProject(view, view);
}
@Test
ComponentDto branch = db.components().insertProjectBranch(project);
expectedException.expect(NotFoundException.class);
- expectedException.expectMessage(format("Project key '%s' not found", branch.getDbKey()));
+ expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey()));
ws.newRequest()
.setParam(PARAM_PROJECT_KEY, branch.getDbKey())
ComponentDto branch = db.components().insertProjectBranch(project);
expectedException.expect(NotFoundException.class);
- expectedException.expectMessage(format("Project id '%s' not found", branch.uuid()));
+ expectedException.expectMessage(format("Component id '%s' not found", branch.uuid()));
ws.newRequest()
.setParam(PARAM_PROJECT_ID, branch.uuid())
.execute();
}
+ @Test
+ public void define_create_action() {
+ WebService.Action action = ws.getDef();
+ assertThat(action).isNotNull();
+ assertThat(action.isPost()).isTrue();
+ assertThat(action.handler()).isNotNull();
+ assertThat(action.responseExampleAsString()).isNotEmpty();
+ assertThat(action.params()).hasSize(4);
+ }
+
private void failIfNotAProject(ComponentDto root, ComponentDto component) {
userSession.logIn().addProjectPermission(UserRole.ADMIN, root);
expectedException.expect(BadRequestException.class);
- expectedException.expectMessage("Component '" + component.getDbKey() + "' (id: " + component.uuid() + ") must be a project");
+ expectedException.expectMessage("Component '" + component.getDbKey() + "' must be a project");
TestRequest testRequest = ws.newRequest();
if (new Random().nextBoolean()) {
.execute();
}
- private ComponentDto insertProject() {
- OrganizationDto org = db.organizations().insert();
- return db.components().insertComponent(
- ComponentTesting.newPrivateProjectDto(org, PROJECT_UUID).setDbKey(PROJECT_KEY));
- }
-
private void createAndTest(ComponentDto project, String name, String url, String type) {
ProjectLinks.CreateWsResponse response = ws.newRequest()
.setMethod("POST")
.setParam(PARAM_URL, url)
.executeProtobuf(ProjectLinks.CreateWsResponse.class);
- long newId = Long.valueOf(response.getLink().getId());
+ String newId = response.getLink().getId();
- ComponentLinkDto link = dbClient.componentLinkDao().selectById(dbSession, newId);
+ ProjectLinkDto link = dbClient.projectLinkDao().selectByUuid(dbSession, newId);
assertThat(link.getName()).isEqualTo(name);
assertThat(link.getHref()).isEqualTo(url);
assertThat(link.getType()).isEqualTo(type);
}
- private void createAndTest(ComponentDto project) throws IOException {
+ private void createAndTest(ComponentDto project) {
createAndTest(project, "Custom", "http://example.org", "custom");
}
*/
package org.sonar.server.projectlink.ws;
-import org.junit.Before;
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.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentLinkDto;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.ws.WsActionTester;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
-import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+import static org.sonar.api.web.UserRole.ADMIN;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_ID;
public class DeleteActionTest {
- private static final String PROJECT_KEY = KEY_PROJECT_EXAMPLE_001;
- private static final String PROJECT_UUID = UUID_EXAMPLE_01;
-
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
private DbClient dbClient = db.getDbClient();
private DbSession dbSession = db.getSession();
- private ComponentDbTester componentDb = new ComponentDbTester(db);
-
- private WsActionTester ws;
-
- private DeleteAction underTest;
- @Before
- public void setUp() {
- underTest = new DeleteAction(dbClient, userSession);
- ws = new WsActionTester(underTest);
- }
+ private WsActionTester ws = new WsActionTester(new DeleteAction(dbClient, userSession));
@Test
public void no_response() {
- ComponentDto project = insertProject();
- ComponentLinkDto link = insertCustomLink(project.uuid());
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertCustomLink(project);
logInAsProjectAdministrator(project);
- TestResponse response = deleteLink(link.getId());
+ TestResponse response = deleteLink(link);
assertThat(response.getStatus()).isEqualTo(204);
assertThat(response.getInput()).isEmpty();
}
@Test
- public void actual_removal() {
- ComponentDto project = insertProject();
- ComponentLinkDto link = insertCustomLink(project.uuid());
- long id = link.getId();
+ public void remove_custom_link() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertCustomLink(project);
logInAsProjectAdministrator(project);
- deleteLink(id);
- assertLinkIsDeleted(id);
+ deleteLink(link);
+
+ assertLinkIsDeleted(link.getUuid());
}
@Test
public void keep_links_of_another_project() {
- ComponentDto project1 = insertProject();
- ComponentDto project2 = insertProject("another", "abcd");
- ComponentLinkDto customLink1 = insertCustomLink(project1.uuid());
- ComponentLinkDto customLink2 = insertCustomLink(project2.uuid());
- Long id1 = customLink1.getId();
- Long id2 = customLink2.getId();
- userSession.logIn().addProjectPermission(UserRole.ADMIN, project1, project2);
-
- deleteLink(id1);
- assertLinkIsDeleted(id1);
- assertLinkIsNotDeleted(id2);
+ ComponentDto project1 = db.components().insertPrivateProject();
+ ComponentDto project2 = db.components().insertPrivateProject();
+ ProjectLinkDto customLink1 = db.componentLinks().insertCustomLink(project1);
+ ProjectLinkDto customLink2 = db.componentLinks().insertCustomLink(project2);
+ userSession.logIn().addProjectPermission(ADMIN, project1, project2);
+
+ deleteLink(customLink1);
+
+ assertLinkIsDeleted(customLink1.getUuid());
+ assertLinkIsNotDeleted(customLink2.getUuid());
}
@Test
public void fail_when_delete_provided_link() {
- ComponentDto project = insertProject();
- ComponentLinkDto link = insertHomepageLink(project.uuid());
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertProvidedLink(project);
logInAsProjectAdministrator(project);
expectedException.expect(BadRequestException.class);
+ expectedException.expectMessage("Provided link cannot be deleted");
- deleteLink(link.getId());
+ deleteLink(link);
}
@Test
- public void fail_when_no_link() {
+ public void fail_on_unknown_link() {
expectedException.expect(NotFoundException.class);
- deleteLink("175");
+ ws.newRequest()
+ .setMethod("POST")
+ .setParam(PARAM_ID, "UNKNOWN")
+ .execute();
}
@Test
public void fail_if_anonymous() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertCustomLink(project);
userSession.anonymous();
- ComponentDto project = insertProject();
- ComponentLinkDto link = insertCustomLink(project.uuid());
-
expectedException.expect(ForbiddenException.class);
- deleteLink(link.getId());
+ deleteLink(link);
}
@Test
public void fail_if_not_project_admin() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertCustomLink(project);
userSession.logIn();
- ComponentDto project = insertProject();
- ComponentLinkDto link = insertCustomLink(project.uuid());
-
expectedException.expect(ForbiddenException.class);
- deleteLink(link.getId());
+ deleteLink(link);
}
- private ComponentDto insertProject(String projectKey, String projectUuid) {
- return componentDb.insertComponent(new ComponentDto()
- .setOrganizationUuid("org1")
- .setUuid(projectUuid)
- .setDbKey(projectKey)
- .setUuidPath("")
- .setRootUuid("")
- .setProjectUuid(""));
- }
-
- private ComponentDto insertProject() {
- return insertProject(PROJECT_KEY, PROJECT_UUID);
- }
-
- private void insertLink(ComponentLinkDto linkDto) {
- dbClient.componentLinkDao().insert(dbSession, linkDto);
- dbSession.commit();
- }
-
- private ComponentLinkDto insertHomepageLink(String projectUuid) {
- ComponentLinkDto link = new ComponentLinkDto()
- .setComponentUuid(projectUuid)
- .setName("Homepage")
- .setType("homepage")
- .setHref("http://example.org");
- insertLink(link);
- return link;
- }
-
- private ComponentLinkDto insertCustomLink(String projectUuid) {
- ComponentLinkDto link = new ComponentLinkDto()
- .setComponentUuid(projectUuid)
- .setName("Custom")
- .setHref("http://example.org/custom");
- insertLink(link);
- return link;
+ @Test
+ public void define_delete_action() {
+ WebService.Action action = ws.getDef();
+ assertThat(action).isNotNull();
+ assertThat(action.isPost()).isTrue();
+ assertThat(action.handler()).isNotNull();
+ assertThat(action.responseExample()).isNull();
+ assertThat(action.params()).hasSize(1);
}
- private TestResponse deleteLink(String id) {
+ private TestResponse deleteLink(ProjectLinkDto link) {
return ws.newRequest()
.setMethod("POST")
- .setParam(PARAM_ID, id)
+ .setParam(PARAM_ID, link.getUuid())
.execute();
}
- private TestResponse deleteLink(Long id) {
- return deleteLink(String.valueOf(id));
- }
-
- private void assertLinkIsDeleted(Long id) {
- assertThat(dbClient.componentLinkDao().selectById(dbSession, id)).isNull();
+ private void assertLinkIsDeleted(String uuid) {
+ assertThat(dbClient.projectLinkDao().selectByUuid(dbSession, uuid)).isNull();
}
- private void assertLinkIsNotDeleted(Long id) {
- assertThat(dbClient.componentLinkDao().selectById(dbSession, id)).isNotNull();
+ private void assertLinkIsNotDeleted(String uuid) {
+ assertThat(dbClient.projectLinkDao().selectByUuid(dbSession, uuid)).isNotNull();
}
private void logInAsProjectAdministrator(ComponentDto project) {
- userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
+ userSession.logIn().addProjectPermission(ADMIN, project);
}
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info 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.projectlink.ws;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.db.DbClient;
-import org.sonar.server.component.ComponentFinder;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.WsTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class ProjectLinksWsTest {
-
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
-
- WebService.Controller controller;
-
- @Before
- public void setUp() {
- WsTester tester = new WsTester(new ProjectLinksWs(
- new SearchAction(mock(DbClient.class), userSessionRule, mock(ComponentFinder.class)),
- new CreateAction(mock(DbClient.class), userSessionRule, mock(ComponentFinder.class)),
- new DeleteAction(mock(DbClient.class), userSessionRule)
- ));
- controller = tester.controller("api/project_links");
- }
-
- @Test
- public void define_controller() {
- assertThat(controller).isNotNull();
- assertThat(controller.description()).isNotEmpty();
- assertThat(controller.since()).isEqualTo("6.1");
- assertThat(controller.actions()).hasSize(3);
- }
-
- @Test
- public void define_search_action() {
- WebService.Action action = controller.action("search");
- assertThat(action).isNotNull();
- assertThat(action.isPost()).isFalse();
- assertThat(action.handler()).isNotNull();
- assertThat(action.responseExampleAsString()).isNotEmpty();
- assertThat(action.params()).hasSize(2);
- }
-
- @Test
- public void define_create_action() {
- WebService.Action action = controller.action("create");
- assertThat(action).isNotNull();
- assertThat(action.isPost()).isTrue();
- assertThat(action.handler()).isNotNull();
- assertThat(action.responseExampleAsString()).isNotEmpty();
- assertThat(action.params()).hasSize(4);
- }
-
- @Test
- public void define_delete_action() {
- WebService.Action action = controller.action("delete");
- assertThat(action).isNotNull();
- assertThat(action.isPost()).isTrue();
- assertThat(action.handler()).isNotNull();
- assertThat(action.responseExample()).isNull();
- assertThat(action.params()).hasSize(1);
- }
-}
*/
package org.sonar.server.projectlink.ws;
-import java.io.IOException;
import java.util.Random;
-import org.junit.Before;
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.db.DbClient;
-import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentLinkDto;
import org.sonar.db.component.ComponentTesting;
+import org.sonar.db.component.ProjectLinkDto;
import org.sonar.db.organization.OrganizationDto;
-import org.sonar.server.component.ComponentFinder;
import org.sonar.server.component.TestComponentFinder;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
-import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
-import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
-import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
-import static org.sonar.test.JsonAssert.assertJson;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_PROJECT_ID;
import static org.sonar.server.projectlink.ws.ProjectLinksWsParameters.PARAM_PROJECT_KEY;
+import static org.sonar.test.JsonAssert.assertJson;
public class SearchActionTest {
- private final String PROJECT_KEY = KEY_PROJECT_EXAMPLE_001;
- private final String PROJECT_UUID = UUID_EXAMPLE_01;
-
@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 ComponentDbTester componentDb = new ComponentDbTester(db);
-
- private SearchAction underTest;
- private WsActionTester ws;
- @Before
- public void setUp() {
- ComponentFinder componentFinder = TestComponentFinder.from(db);
- underTest = new SearchAction(dbClient, userSession, componentFinder);
- ws = new WsActionTester(underTest);
- }
+ private WsActionTester ws = new WsActionTester(new SearchAction(dbClient, userSession, TestComponentFinder.from(db)));
@Test
public void example() {
- ComponentDto project = insertProject();
- insertHomepageLink(project.uuid());
- insertCustomLink(project.uuid());
+ ComponentDto project = db.components().insertPrivateProject();
+ db.componentLinks().insertProvidedLink(project, l -> l.setUuid("1").setType("homepage").setName("Homepage").setHref("http://example.org"));
+ db.componentLinks().insertCustomLink(project, l -> l.setUuid("2").setType("custom").setName("Custom").setHref("http://example.org/custom"));
logInAsProjectAdministrator(project);
String result = ws.newRequest()
- .setParam(PARAM_PROJECT_KEY, PROJECT_KEY)
+ .setParam(PARAM_PROJECT_KEY, project.getKey())
.execute().getInput();
- assertJson(result).ignoreFields("id").isSimilarTo(getClass().getResource("list-example.json"));
+ assertJson(result).isSimilarTo(getClass().getResource("search-example.json"));
}
@Test
- public void request_by_project_id() throws IOException {
- ComponentDto project = insertProject();
- insertHomepageLink(project.uuid());
+ public void request_by_project_id() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertCustomLink(project);
logInAsProjectAdministrator(project);
SearchWsResponse response = callByUuid(project.uuid());
- assertThat(response.getLinksCount()).isEqualTo(1);
- assertThat(response.getLinks(0).getName()).isEqualTo("Homepage");
+ assertThat(response.getLinksList())
+ .extracting(Link::getId, Link::getName)
+ .containsExactlyInAnyOrder(tuple(link.getUuid(), link.getName()));
}
@Test
- public void request_by_project_key() throws IOException {
- ComponentDto project = insertProject();
- insertHomepageLink(project.uuid());
+ public void request_by_project_key() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertCustomLink(project);
logInAsProjectAdministrator(project);
- SearchWsResponse response = callByKey(project.getDbKey());
+ SearchWsResponse response = callByKey(project.getKey());
- assertThat(response.getLinksCount()).isEqualTo(1);
- assertThat(response.getLinks(0).getName()).isEqualTo("Homepage");
+ assertThat(response.getLinksList())
+ .extracting(Link::getId, Link::getName)
+ .containsExactlyInAnyOrder(tuple(link.getUuid(), link.getName()));
}
@Test
- public void response_fields() throws IOException {
- ComponentDto project = insertProject();
- ComponentLinkDto homepageLink = insertHomepageLink(project.uuid());
- ComponentLinkDto customLink = insertCustomLink(project.uuid());
+ public void response_fields() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto homepageLink = db.componentLinks().insertProvidedLink(project);
+ ProjectLinkDto customLink = db.componentLinks().insertCustomLink(project);
logInAsProjectAdministrator(project);
- SearchWsResponse response = callByKey(project.getDbKey());
+ SearchWsResponse response = callByKey(project.getKey());
- assertThat(response.getLinksCount()).isEqualTo(2);
assertThat(response.getLinksList()).extracting(Link::getId, Link::getName, Link::getType, Link::getUrl)
- .containsOnlyOnce(
- tuple(homepageLink.getIdAsString(), homepageLink.getName(), homepageLink.getType(), homepageLink.getHref()),
- tuple(customLink.getIdAsString(), customLink.getName(), customLink.getType(), customLink.getHref()));
+ .containsExactlyInAnyOrder(
+ tuple(homepageLink.getUuid(), "", homepageLink.getType(), homepageLink.getHref()),
+ tuple(customLink.getUuid(), customLink.getName(), customLink.getType(), customLink.getHref()));
}
@Test
- public void several_projects() throws IOException {
- ComponentDto project1 = insertProject();
- ComponentDto project2 = insertProject("another", "abcd");
- ComponentLinkDto customLink1 = insertCustomLink(project1.uuid());
- insertCustomLink(project2.uuid());
+ public void several_projects() {
+ ComponentDto project1 = db.components().insertPrivateProject();
+ ComponentDto project2 = db.components().insertPrivateProject();
+ ProjectLinkDto link1 = db.componentLinks().insertCustomLink(project1);
+ ProjectLinkDto link2 = db.componentLinks().insertCustomLink(project2);
userSession.logIn().setRoot();
- SearchWsResponse response = callByKey(project1.getDbKey());
+ SearchWsResponse response = callByKey(project1.getKey());
- assertThat(response.getLinksCount()).isEqualTo(1);
- assertThat(response.getLinks(0).getId()).isEqualTo(customLink1.getIdAsString());
+ assertThat(response.getLinksList())
+ .extracting(Link::getId, Link::getName)
+ .containsExactlyInAnyOrder(tuple(link1.getUuid(), link1.getName()));
}
@Test
- public void request_does_not_fail_when_link_has_no_name() throws IOException {
+ public void request_does_not_fail_when_link_has_no_name() {
ComponentDto project = db.components().insertPrivateProject();
- ComponentLinkDto foo = new ComponentLinkDto().setComponentUuid(project.uuid()).setHref("foo").setType("type");
- insertLink(foo);
+ ProjectLinkDto link = db.componentLinks().insertProvidedLink(project);
logInAsProjectAdministrator(project);
- callByKey(project.getDbKey());
- }
-
- @Test
- public void request_does_not_fail_when_link_has_no_type() throws IOException {
- ComponentDto project = db.components().insertPrivateProject();
- ComponentLinkDto foo = new ComponentLinkDto().setComponentUuid(project.uuid()).setHref("foo").setName("name");
- insertLink(foo);
- logInAsProjectAdministrator(project);
+ SearchWsResponse response = callByKey(project.getKey());
- callByKey(project.getDbKey());
+ assertThat(response.getLinksList())
+ .extracting(Link::getId, Link::hasName)
+ .containsExactlyInAnyOrder(tuple(link.getUuid(), false));
}
@Test
- public void project_administrator_can_search_for_links() throws IOException {
- ComponentDto project = insertProject();
+ public void project_administrator_can_search_for_links() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertCustomLink(project);
userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
- checkItWorks(project);
+ SearchWsResponse response = callByKey(project.getKey());
+
+ assertThat(response.getLinksList())
+ .extracting(Link::getId, Link::getName)
+ .containsExactlyInAnyOrder(tuple(link.getUuid(), link.getName()));
}
@Test
- public void project_user_can_search_for_links() throws IOException {
- ComponentDto project = insertProject();
+ public void project_user_can_search_for_links() {
+ ComponentDto project = db.components().insertPrivateProject();
+ ProjectLinkDto link = db.componentLinks().insertCustomLink(project);
userSession.logIn().addProjectPermission(UserRole.USER, project);
- checkItWorks(project);
+ SearchWsResponse response = callByKey(project.getKey());
+
+ assertThat(response.getLinksList())
+ .extracting(Link::getId, Link::getName)
+ .containsExactlyInAnyOrder(tuple(link.getUuid(), link.getName()));
}
@Test
- public void fail_when_no_project() throws IOException {
+ public void fail_when_no_project() {
expectedException.expect(NotFoundException.class);
callByKey("unknown");
}
}
@Test
- public void fail_if_subview() {
+ public void fail_if_view() {
ComponentDto view = db.components().insertView();
- ComponentDto subview = db.components().insertComponent(ComponentTesting.newSubView(view));
- failIfNotAProject(view, subview);
- }
-
- private void failIfNotAProject(ComponentDto root, ComponentDto component) {
- userSession.logIn().addProjectPermission(UserRole.ADMIN, root);
-
- expectedException.expect(BadRequestException.class);
- expectedException.expectMessage("Component '" + component.getDbKey() + "' (id: " + component.uuid() + ") must be a project");
-
- TestRequest testRequest = ws.newRequest();
- if (new Random().nextBoolean()) {
- testRequest.setParam(PARAM_PROJECT_KEY, component.getDbKey());
- } else {
- testRequest.setParam(PARAM_PROJECT_ID, component.uuid());
- }
- testRequest.execute();
+ failIfNotAProject(view, view);
}
@Test
- public void fail_if_insufficient_privileges() throws IOException {
+ public void fail_if_insufficient_privileges() {
userSession.anonymous();
- insertProject();
+ ComponentDto project = db.components().insertPrivateProject();
expectedException.expect(ForbiddenException.class);
- callByKey(PROJECT_KEY);
+
+ callByKey(project.getKey());
}
@Test
public void fail_when_both_id_and_key_are_provided() {
- ComponentDto project = insertProject();
+ ComponentDto project = db.components().insertPrivateProject();
logInAsProjectAdministrator(project);
expectedException.expect(IllegalArgumentException.class);
ws.newRequest()
- .setParam(PARAM_PROJECT_KEY, project.getDbKey())
+ .setParam(PARAM_PROJECT_KEY, project.getKey())
.setParam(PARAM_PROJECT_ID, project.uuid())
.execute();
}
@Test
public void fail_when_no_id_nor_key_are_provided() {
- insertProject();
+ ComponentDto project = db.components().insertPrivateProject();
expectedException.expect(IllegalArgumentException.class);
ws.newRequest()
- .setParam(PARAM_PROJECT_KEY, PROJECT_KEY)
- .setParam(PARAM_PROJECT_ID, PROJECT_UUID)
+ .setParam(PARAM_PROJECT_KEY, project.getKey())
+ .setParam(PARAM_PROJECT_ID, project.uuid())
.execute();
}
ComponentDto branch = db.components().insertProjectBranch(project);
expectedException.expect(NotFoundException.class);
- expectedException.expectMessage(format("Project key '%s' not found", branch.getDbKey()));
+ expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey()));
ws.newRequest()
.setParam(PARAM_PROJECT_KEY, branch.getDbKey())
ComponentDto branch = db.components().insertProjectBranch(project);
expectedException.expect(NotFoundException.class);
- expectedException.expectMessage(format("Project id '%s' not found", branch.uuid()));
+ expectedException.expectMessage(format("Component id '%s' not found", branch.uuid()));
ws.newRequest()
.setParam(PARAM_PROJECT_ID, branch.uuid())
.execute();
}
- private ComponentDto insertProject(String projectKey, String projectUuid) {
- return componentDb.insertComponent(newPrivateProjectDto(db.organizations().insert(), projectUuid).setDbKey(projectKey));
- }
-
- private ComponentDto insertProject() {
- return insertProject(PROJECT_KEY, PROJECT_UUID);
- }
-
- private void insertLink(ComponentLinkDto linkDto) {
- dbClient.componentLinkDao().insert(dbSession, linkDto);
- dbSession.commit();
- }
-
- private ComponentLinkDto insertHomepageLink(String projectUuid) {
- ComponentLinkDto link = new ComponentLinkDto()
- .setComponentUuid(projectUuid)
- .setName("Homepage")
- .setType("homepage")
- .setHref("http://example.org");
- insertLink(link);
- return link;
- }
-
- private ComponentLinkDto insertCustomLink(String projectUuid) {
- ComponentLinkDto link = new ComponentLinkDto()
- .setComponentUuid(projectUuid)
- .setName("Custom")
- .setType("Custom")
- .setHref("http://example.org/custom");
- insertLink(link);
- return link;
+ @Test
+ public void define_search_action() {
+ WebService.Action action = ws.getDef();
+ assertThat(action).isNotNull();
+ assertThat(action.isPost()).isFalse();
+ assertThat(action.handler()).isNotNull();
+ assertThat(action.responseExampleAsString()).isNotEmpty();
+ assertThat(action.params()).hasSize(2);
}
private SearchWsResponse callByKey(String projectKey) {
.executeProtobuf(SearchWsResponse.class);
}
- private void checkItWorks(ComponentDto project) throws IOException {
- insertHomepageLink(project.uuid());
- SearchWsResponse response = callByKey(project.getDbKey());
- assertThat(response.getLinksCount()).isEqualTo(1);
- assertThat(response.getLinks(0).getName()).isEqualTo("Homepage");
- }
-
private void logInAsProjectAdministrator(ComponentDto project) {
userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
}
+
+ private void failIfNotAProject(ComponentDto root, ComponentDto component) {
+ userSession.logIn().addProjectPermission(UserRole.ADMIN, root);
+
+ expectedException.expect(BadRequestException.class);
+ expectedException.expectMessage("Component '" + component.getKey() + "' must be a project");
+
+ TestRequest testRequest = ws.newRequest();
+ if (new Random().nextBoolean()) {
+ testRequest.setParam(PARAM_PROJECT_KEY, component.getDbKey());
+ } else {
+ testRequest.setParam(PARAM_PROJECT_ID, component.uuid());
+ }
+ testRequest.execute();
+ }
}
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="ABCD" link_type="homepage" name="Home" href="http://www.sonarqube.org"/>
- <project_links id="2" component_uuid="ABCD" link_type="scm" name="Sources" href="https://github.com/SonarSource/sonar"/>
- <project_links id="3" component_uuid="ABCD" link_type="scm_dev" name="Developer connection" href="scm:git:git@github.com:SonarSource/sonar.git/sonar"/>
- <project_links id="4" component_uuid="ABCD" link_type="issue" name="Issues" href="http://jira.sonarsource.com/"/>
- <project_links id="5" component_uuid="ABCD" link_type="ci" name="Continuous integration" href="http://bamboo.ci.codehaus.org/browse/SONAR"/>
-
- <project_links id="6" component_uuid="BCDE" link_type="scm" name="Sources" href="https://github.com/SonarSource/sonar/server"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="ABCD" link_type="homepage" name="Home" href="http://www.sonarqube.org"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="ABCD" link_type="custom" name="custom" href="http://www.custom.org"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="ABCD" link_type="homepage" name="Home" href="http://www.sonarqube.org"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="ABCD" link_type="homepage" name="Home" href="http://www.sonarqube.org"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <project_links id="1" component_uuid="ABCD" link_type="homepage" name="Home" href="http://www.sonar.org"/>
-
-</dataset>
@ClassRule
public static RuleChain ruleChain = RuleChain.outerRule(orchestrator).around(tester);
- private long customLinkId;
+ private String customLinkId;
private String adminUser;
@BeforeClass
@Before
public void prepare() {
- customLinkId = Long.parseLong(createCustomLink().getLink().getId());
+ customLinkId = createCustomLink().getLink().getId();
adminUser = tester.users().generateAdministratorOnDefaultOrganization().getLogin();
}
.setUrl("http://example.org/custom"));
}
- private void deleteLink(long id) {
+ private void deleteLink(String id) {
try {
- tester.wsClient().projectLinks().delete(new DeleteRequest().setId("" + id));
+ tester.wsClient().projectLinks().delete(new DeleteRequest().setId(id));
} catch (Exception e) {
// fail silently
}