]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10544 Fix tests handling of external rules
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Fri, 13 Apr 2018 07:12:54 +0000 (09:12 +0200)
committerSonarTech <sonartech@sonarsource.com>
Thu, 26 Apr 2018 18:20:50 +0000 (20:20 +0200)
16 files changed:
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRulesAction.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRulesAction.java
server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleQueryFactory.java
server/sonar-server/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java
server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistExternalRulesStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistIssuesStepTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/ExternalRuleCreatorTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/ws/RuleQueryFactoryTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ModuleIssues.java

index 6b132a301871e84eb8506413057783378cb413dd..8818dadff9b720cb5a8ad05b6dce3f0c17b16356 100644 (file)
@@ -35,7 +35,7 @@ import org.sonar.server.user.UserSession;
 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_03;
 import static org.sonar.server.qualityprofile.ws.BulkChangeWsResponse.writeResponse;
 import static org.sonar.server.qualityprofile.ws.QProfileReference.fromKey;
-import static org.sonar.server.rule.ws.SearchAction.defineRuleSearchParameters;
+import static org.sonar.server.rule.ws.SearchAction.defineGenericRuleSearchParameters;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_ACTIVATE_RULES;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_TARGET_KEY;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_TARGET_SEVERITY;
@@ -69,7 +69,7 @@ public class ActivateRulesAction implements QProfileWsAction {
       .setSince("4.4")
       .setHandler(this);
 
-    defineRuleSearchParameters(activate);
+    defineGenericRuleSearchParameters(activate);
 
     activate.createParam(PARAM_TARGET_KEY)
       .setDescription("Quality Profile key on which the rule activation is done. To retrieve a quality profile key please see <code>api/qualityprofiles/search</code>")
index fd779c15d16fce24748fe016bf04472ce298ccbe..1a96919832eb4e16cbf645c7c891b288e3da2c84 100644 (file)
@@ -33,7 +33,7 @@ import org.sonar.server.user.UserSession;
 
 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_04;
 import static org.sonar.server.qualityprofile.ws.BulkChangeWsResponse.writeResponse;
-import static org.sonar.server.rule.ws.SearchAction.defineRuleSearchParameters;
+import static org.sonar.server.rule.ws.SearchAction.defineGenericRuleSearchParameters;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_DEACTIVATE_RULES;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_TARGET_KEY;
 
@@ -67,7 +67,7 @@ public class DeactivateRulesAction implements QProfileWsAction {
       .setSince("4.4")
       .setHandler(this);
 
-    defineRuleSearchParameters(deactivate);
+    defineGenericRuleSearchParameters(deactivate);
 
     deactivate.createParam(PARAM_TARGET_KEY)
       .setDescription("Quality Profile key on which the rule deactivation is done. To retrieve a profile key please see <code>api/qualityprofiles/search</code>")
index a197a0ee8b9729e0f76795e898b20f248eec6dd0..8188955280c6b48a3640e1c7bcbd1698cfb41212 100644 (file)
@@ -66,6 +66,16 @@ public class RuleQueryFactory {
     this.wsSupport = wsSupport;
   }
 
+  /**
+   * Similar to {@link #createRuleQuery(DbSession, Request)} but sets additional fields which are only used
+   * for the rule search WS. 
+   */
+  public RuleQuery createRuleSearchQuery(DbSession dbSession, Request request) {
+    RuleQuery query = createRuleQuery(dbSession, request);
+    query.setIsExternal(request.paramAsBoolean(PARAM_IS_EXTERNAL));
+    return query;
+  }
+
   /**
    * Create a {@link RuleQuery} from a {@link Request}.
    * When a profile key is set, the language of the profile is automatically set in the query
@@ -92,7 +102,6 @@ public class RuleQueryFactory {
     query.setInheritance(request.paramAsStrings(PARAM_INHERITANCE));
     query.setActiveSeverities(request.paramAsStrings(PARAM_ACTIVE_SEVERITIES));
     query.setIsTemplate(request.paramAsBoolean(PARAM_IS_TEMPLATE));
-    query.setIsExternal(request.paramAsBoolean(PARAM_IS_EXTERNAL));
     query.setTemplateKey(request.param(PARAM_TEMPLATE_KEY));
     query.setTypes(toEnums(request.paramAsStrings(PARAM_TYPES), RuleType.class));
     query.setKey(request.param(PARAM_RULE_KEY));
index 06ee60ec50b674bcb7010ed05ed388a6dca5aaa4..50009dc6730f56071e038ad9381761a5b695f3e1 100644 (file)
@@ -96,9 +96,9 @@ public class RulesWsParameters {
   public static final String FIELD_PARAMS = "params";
   public static final String FIELD_ACTIVES = "actives";
 
-  public static final Set<String> OPTIONAL_FIELDS = ImmutableSet.of(FIELD_REPO, FIELD_NAME, FIELD_CREATED_AT, FIELD_SEVERITY, FIELD_STATUS, FIELD_INTERNAL_KEY, FIELD_IS_EXTERNAL, FIELD_IS_TEMPLATE,
-    FIELD_TEMPLATE_KEY, FIELD_TAGS, FIELD_SYSTEM_TAGS, FIELD_LANGUAGE, FIELD_LANGUAGE_NAME, FIELD_HTML_DESCRIPTION, FIELD_MARKDOWN_DESCRIPTION, FIELD_NOTE_LOGIN,
-    FIELD_MARKDOWN_NOTE, FIELD_HTML_NOTE,
+  public static final Set<String> OPTIONAL_FIELDS = ImmutableSet.of(FIELD_REPO, FIELD_NAME, FIELD_CREATED_AT, FIELD_SEVERITY, FIELD_STATUS, FIELD_INTERNAL_KEY,
+    FIELD_IS_EXTERNAL, FIELD_IS_TEMPLATE, FIELD_TEMPLATE_KEY, FIELD_TAGS, FIELD_SYSTEM_TAGS, FIELD_LANGUAGE, FIELD_LANGUAGE_NAME, FIELD_HTML_DESCRIPTION,
+    FIELD_MARKDOWN_DESCRIPTION, FIELD_NOTE_LOGIN, FIELD_MARKDOWN_NOTE, FIELD_HTML_NOTE,
     FIELD_DEFAULT_DEBT_REM_FUNCTION, FIELD_EFFORT_TO_FIX_DESCRIPTION, FIELD_DEBT_OVERLOADED, FIELD_DEBT_REM_FUNCTION,
     FIELD_DEFAULT_REM_FUNCTION, FIELD_GAP_DESCRIPTION, FIELD_REM_FUNCTION_OVERLOADED, FIELD_REM_FUNCTION,
     FIELD_PARAMS, FIELD_ACTIVES, FIELD_SCOPE);
index 273498012301d7d1f7b93d31ddc588924212f9a3..2c9270c2656b07ac9fc3d25f70255e4637af6cee 100644 (file)
@@ -135,7 +135,7 @@ public class SearchAction implements RulesWsAction {
       .setChangelog(new Change("7.1", "The field 'scope' has been added to the response"))
       .setChangelog(new Change("7.1", "The field 'scope' has been added to the 'f' parameter"))
       .setChangelog(new Change("7.2", "The field 'isExternal' has been added to the response"))
-      .setChangelog(new Change("7.2", "The field 'isExternal' has been added to the 'f' parameter"));;
+      .setChangelog(new Change("7.2", "The field 'isExternal' has been added to the 'f' parameter"));
 
     action.createParam(FACETS)
       .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.")
@@ -163,7 +163,7 @@ public class SearchAction implements RulesWsAction {
     try (DbSession dbSession = dbClient.openSession(false)) {
       SearchRequest searchWsRequest = toSearchWsRequest(request);
       SearchOptions context = buildSearchOptions(searchWsRequest);
-      RuleQuery query = ruleQueryFactory.createRuleQuery(dbSession, request);
+      RuleQuery query = ruleQueryFactory.createRuleSearchQuery(dbSession, request);
       SearchResult searchResult = doSearch(dbSession, query, context);
       SearchResponse responseBuilder = buildResponse(dbSession, searchWsRequest, context, searchResult, query);
       writeProtobuf(responseBuilder, request, response);
@@ -202,10 +202,16 @@ public class SearchAction implements RulesWsAction {
       .setHandler(this);
 
     // Rule-specific search parameters
-    defineRuleSearchParameters(action);
+    defineGenericRuleSearchParameters(action);
+    
+    action
+    .createParam(PARAM_IS_EXTERNAL)
+    .setDescription("Filter external engine rules")
+    .setBooleanPossibleValues()
+    .setSince("7.2");
   }
 
-  public static void defineRuleSearchParameters(WebService.NewAction action) {
+  public static void defineGenericRuleSearchParameters(WebService.NewAction action) {
     action
       .createParam(TEXT_QUERY)
       .setMinimumLength(2)
@@ -295,12 +301,6 @@ public class SearchAction implements RulesWsAction {
       .setDescription("Filter template rules")
       .setBooleanPossibleValues();
 
-    action
-      .createParam(PARAM_IS_EXTERNAL)
-      .setDescription("Filter external engine rules")
-      .setBooleanPossibleValues()
-      .setSince("7.2");
-
     action
       .createParam(PARAM_TEMPLATE_KEY)
       .setDescription("Key of the template rule to filter on. Used to search for the custom rules based on this template.")
index 8024f1b121f6abf49563bef92407a7baa25cbe83..2314d14056e588895f7554744c3997e1959f0747 100644 (file)
@@ -24,8 +24,8 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.db.protobuf.DbCommons.TextRange;
@@ -51,14 +51,18 @@ import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 public class IssueCreationDateCalculatorTest {
   private static final String COMPONENT_UUID = "ab12";
 
-  @Rule
+  @org.junit.Rule
   public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
 
+  @org.junit.Rule
+  public ExpectedException exception = ExpectedException.none();
+
   private ScmInfoRepository scmInfoRepository = mock(ScmInfoRepository.class);
   private IssueFieldsSetter issueUpdater = mock(IssueFieldsSetter.class);
   private ActiveRulesHolder activeRulesHolder = mock(ActiveRulesHolder.class);
@@ -71,6 +75,7 @@ public class IssueCreationDateCalculatorTest {
   private Map<String, ScannerPlugin> scannerPlugins = new HashMap<>();
   private RuleRepository ruleRepository = mock(RuleRepository.class);
   private ScmInfo scmInfo;
+  private Rule rule = mock(Rule.class);
 
   @Before
   public void before() {
@@ -79,6 +84,7 @@ public class IssueCreationDateCalculatorTest {
     when(component.getUuid()).thenReturn(COMPONENT_UUID);
     calculator = new IssueCreationDateCalculator(analysisMetadataHolder, scmInfoRepository, issueUpdater, activeRulesHolder, ruleRepository);
 
+    when(ruleRepository.findByKey(ruleKey)).thenReturn(java.util.Optional.of(rule));
     when(activeRulesHolder.get(any(RuleKey.class)))
       .thenReturn(Optional.absent());
     when(activeRulesHolder.get(ruleKey))
@@ -162,6 +168,19 @@ public class IssueCreationDateCalculatorTest {
     assertNoChangeOfCreationDate();
   }
 
+  @Test
+  public void should_fail_if_rule_is_not_found() {
+    previousAnalysisWas(2000L);
+    currentAnalysisIs(3000L);
+
+    when(ruleRepository.findByKey(ruleKey)).thenReturn(java.util.Optional.empty());
+    newIssue();
+
+    exception.expect(IllegalStateException.class);
+    exception.expectMessage("The rule with key 'reop:rule' raised an issue, but no rule with that key was found");
+    run();
+  }
+
   @Test
   public void should_change_date_if_scm_is_available_and_rule_is_new() {
     previousAnalysisWas(2000L);
@@ -222,6 +241,23 @@ public class IssueCreationDateCalculatorTest {
     assertChangeOfCreationDateTo(1200L);
   }
 
+  @Test
+  public void should_backdate_external_issues() {
+    analysisMetadataHolder.setBaseAnalysis(null);
+    currentAnalysisIs(3000L);
+
+    newIssue();
+    when(rule.isExternal()).thenReturn(true);
+    when(issue.getLocations()).thenReturn(DbIssues.Locations.newBuilder().setTextRange(range(2, 3)).build());
+    withScmAt(2, 1200L);
+    withScmAt(3, 1300L);
+
+    run();
+
+    assertChangeOfCreationDateTo(1300L);
+    verifyZeroInteractions(activeRulesHolder);
+  }
+
   @Test
   public void should_use_primary_location_when_backdating() {
     analysisMetadataHolder.setBaseAnalysis(null);
index 219470ccf180bc46108abf9112f9ac651799597c..5ebab963baef0f5d76343dee7f2484cd77d97efb 100644 (file)
@@ -23,7 +23,6 @@ import java.util.Optional;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbClient;
@@ -58,7 +57,7 @@ public class PersistExternalRulesStepTest extends BaseStepTest {
   private RuleRepositoryImpl ruleRepository;
 
   @org.junit.Rule
-  public EsTester es = new EsTester(new RuleIndexDefinition(new MapSettings().asConfig()));
+  public EsTester es =  EsTester.create();
 
   private RuleIndexer indexer = new RuleIndexer(es.client(), dbClient);
   private ExternalRuleCreator externalRuleCreator = new ExternalRuleCreator(dbClient, System2.INSTANCE, indexer);
index 0b4eaa16e1e14cb5f77a70ada93d9e3f44a14ab2..5e6ae3631eb917f5701b805b8376e52cb46c5591 100644 (file)
@@ -27,7 +27,6 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.RuleType;
 import org.sonar.api.utils.System2;
@@ -53,7 +52,6 @@ import org.sonar.server.computation.task.projectanalysis.issue.UpdateConflictRes
 import org.sonar.server.computation.task.step.ComputationStep;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.rule.ExternalRuleCreator;
-import org.sonar.server.rule.index.RuleIndexDefinition;
 import org.sonar.server.util.cache.DiskCache;
 
 import static java.util.Collections.singletonList;
@@ -78,7 +76,7 @@ public class PersistIssuesStepTest extends BaseStepTest {
   public BatchReportReaderRule reportReader = new BatchReportReaderRule();
   @Rule
   public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule()
-    .setOrganizationUuid("org-1","qg-uuid-1");
+    .setOrganizationUuid("org-1", "qg-uuid-1");
 
   private DbSession session = db.getSession();
   private DbClient dbClient = db.getDbClient();
@@ -87,7 +85,7 @@ public class PersistIssuesStepTest extends BaseStepTest {
   private ComputationStep step;
 
   @org.junit.Rule
-  public EsTester es = new EsTester(new RuleIndexDefinition(new MapSettings().asConfig()));
+  public EsTester es = EsTester.create();
 
   private ExternalRuleCreator externalRuleCreator = mock(ExternalRuleCreator.class);
 
index ca23d02eb4a7c34a29fbc9de1d63f12904bd9f94..c338d771a5d5c09f68beeb9f4bee4245c410f332 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.server.rule;
 
 import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbSession;
@@ -28,7 +27,6 @@ import org.sonar.db.DbTester;
 import org.sonar.server.computation.task.projectanalysis.issue.NewExternalRule;
 import org.sonar.server.computation.task.projectanalysis.issue.Rule;
 import org.sonar.server.es.EsTester;
-import org.sonar.server.rule.index.RuleIndexDefinition;
 import org.sonar.server.rule.index.RuleIndexer;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -40,8 +38,8 @@ public class ExternalRuleCreatorTest {
   @org.junit.Rule
   public DbTester dbTester = DbTester.create(System2.INSTANCE);
   @org.junit.Rule
-  public EsTester es = new EsTester(new RuleIndexDefinition(new MapSettings().asConfig()));
-  
+  public EsTester es = EsTester.create();
+
   private RuleIndexer indexer = new RuleIndexer(es.client(), dbTester.getDbClient());
   private ExternalRuleCreator underTest = new ExternalRuleCreator(dbTester.getDbClient(), System2.INSTANCE, indexer);
   private DbSession dbSession = dbTester.getSession();
index 455a9a841932cd129cbe35fb64eb2a11d9ab82bb..5a72e8fb77f3032c75058b45611d79ca0ff87f25 100644 (file)
@@ -397,18 +397,18 @@ public class RuleIndexTest {
     SearchIdResult<Integer> results = underTest.search(query, new SearchOptions());
     assertThat(results.getIds()).hasSize(2);
 
-    // Only template
-    query = new RuleQuery().setIsTemplate(true);
+    // Only external
+    query = new RuleQuery().setIsExternal(true);
     results = underTest.search(query, new SearchOptions());
     assertThat(results.getIds()).containsOnly(ruleIsExternal.getId());
 
-    // Only not template
-    query = new RuleQuery().setIsTemplate(false);
+    // Only not external
+    query = new RuleQuery().setIsExternal(false);
     results = underTest.search(query, new SearchOptions());
     assertThat(results.getIds()).containsOnly(ruleIsNotExternal.getId());
 
     // null => no filter
-    query = new RuleQuery().setIsTemplate(null);
+    query = new RuleQuery().setIsExternal(null);
     results = underTest.search(query, new SearchOptions());
     assertThat(results.getIds()).containsOnly(ruleIsExternal.getId(), ruleIsNotExternal.getId());
   }
index 49edcf2572334ae1eade1854487fc3b392ec71b8..62ba7c6f33a0228b6f556146bbcf6f8b05a5aa71 100644 (file)
@@ -152,7 +152,6 @@ public class RuleQueryFactoryTest {
     assertThat(result.isAscendingSort()).isFalse();
     assertThat(result.getAvailableSinceLong()).isNotNull();
     assertThat(result.getInheritance()).containsOnly(INHERITED, OVERRIDES);
-    assertThat(result.isExternal()).isTrue();
     assertThat(result.isTemplate()).isTrue();
     assertThat(result.getLanguages()).containsOnly(qualityProfile.getLanguage());
     assertThat(result.getQueryText()).isEqualTo("S001");
index 450ee184427b3b92026c0bb5e59161ed76eaf409..82cc8dfb3de7e000c0b08da7297f50ceaa2547c8 100644 (file)
@@ -132,7 +132,7 @@ public class SearchActionTest {
     assertThat(def.since()).isEqualTo("4.4");
     assertThat(def.isInternal()).isFalse();
     assertThat(def.responseExampleAsString()).isNotEmpty();
-    assertThat(def.params()).hasSize(23);
+    assertThat(def.params()).hasSize(24);
 
     WebService.Param compareToProfile = def.param("compareToProfile");
     assertThat(compareToProfile.since()).isEqualTo("6.5");
index 694942984c233bc8f4defcb0cfdd539342f940d2..c845eb1ab7f1102b903a406f0ed7fd189490f453 100644 (file)
@@ -23,6 +23,7 @@ import com.google.common.base.Preconditions;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import javax.annotation.Nullable;
 import org.sonar.api.batch.sensor.internal.DefaultStorable;
 import org.sonar.api.batch.sensor.internal.SensorStorage;
 import org.sonar.api.batch.sensor.issue.IssueLocation;
@@ -43,7 +44,7 @@ public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue>  exte
     super(null);
   }
   
-  public AbstractDefaultIssue(SensorStorage storage) {
+  public AbstractDefaultIssue(@Nullable SensorStorage storage) {
     super(storage);
   }
   
index 6bbf40078e7c07a347dbe178ea2a7759c6b16555..6ffcb5055e8ca6ad48e88320aeda36a2c574e946 100644 (file)
@@ -42,7 +42,7 @@ public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIs
     super(null);
   }
 
-  public DefaultExternalIssue(SensorStorage storage) {
+  public DefaultExternalIssue(@Nullable SensorStorage storage) {
     super(storage);
   }
 
index 30095731169b236e2c7731aa336f78d556bbf8f9..19f53a68af14c5fb50b2527b1de381f35ed267a1 100644 (file)
@@ -39,7 +39,7 @@ public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements
     super(null);
   }
 
-  public DefaultIssue(SensorStorage storage) {
+  public DefaultIssue(@Nullable SensorStorage storage) {
     super(storage);
   }
 
index a6bdaad62f23df0ae844c96f5b7e69a4fffbc0ce..1ff50f8e5b5156c76dd3897b22820a81c5eb57bf 100644 (file)
@@ -111,7 +111,7 @@ public class ModuleIssues {
   }
 
   private static ScannerReport.ExternalIssue createReportExternalIssue(ExternalIssue issue, int componentRef) {
-    String primaryMessage = issue.primaryLocation().message();
+    String primaryMessage = Strings.isNullOrEmpty(issue.primaryLocation().message()) ? issue.ruleTitle() : issue.primaryLocation().message();
     Severity severity = Severity.valueOf(issue.severity().name());
 
     ScannerReport.ExternalIssue.Builder builder = ScannerReport.ExternalIssue.newBuilder();