Skip to content

Commit

Permalink
SONAR-6281 Fix branch and keys of components in compute report
Browse files Browse the repository at this point in the history
  • Loading branch information
henryju committed Jun 1, 2015
1 parent 2b5a21f commit 1b4f976
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 108 deletions.
Expand Up @@ -21,15 +21,15 @@


import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.ObjectUtils;
import org.picocontainer.Startable; import org.picocontainer.Startable;
import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.resources.Project; import org.sonar.api.resources.Project;
import org.sonar.batch.scan.ImmutableProjectReactor; import org.sonar.batch.scan.ImmutableProjectReactor;


import java.util.List;
import java.util.Map;

public class DefaultProjectTree implements Startable { public class DefaultProjectTree implements Startable {


private final ProjectConfigurator configurator; private final ProjectConfigurator configurator;
Expand All @@ -53,7 +53,7 @@ public void stop() {
// Nothing to do // Nothing to do
} }


void doStart(List<ProjectDefinition> definitions) { void doStart(Collection<ProjectDefinition> definitions) {
projects = Lists.newArrayList(); projects = Lists.newArrayList();
projectsByDef = Maps.newHashMap(); projectsByDef = Maps.newHashMap();


Expand Down
Expand Up @@ -19,17 +19,16 @@
*/ */
package org.sonar.batch.index; package org.sonar.batch.index;


import java.util.ArrayList;
import java.util.Collection;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.fs.InputPath; import org.sonar.api.batch.fs.InputPath;
import org.sonar.api.database.model.Snapshot; import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource; import org.sonar.api.resources.Resource;

import org.sonar.api.resources.ResourceUtils;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.ArrayList;
import java.util.Collection;


public class BatchComponent { public class BatchComponent {


Expand Down Expand Up @@ -104,4 +103,8 @@ public BatchComponent setInputPath(InputPath inputPath) {
public InputPath inputPath() { public InputPath inputPath() {
return inputPath; return inputPath;
} }

public boolean isProjectOrModule() {
return ResourceUtils.isProject(r);
}
} }
Expand Up @@ -59,13 +59,12 @@ public BatchComponent add(Resource resource, @Nullable Resource parentResource)
String componentKey = resource.getEffectiveKey(); String componentKey = resource.getEffectiveKey();
Preconditions.checkState(!Strings.isNullOrEmpty(componentKey), "Missing resource effective key"); Preconditions.checkState(!Strings.isNullOrEmpty(componentKey), "Missing resource effective key");
BatchComponent parent = parentResource != null ? get(parentResource.getEffectiveKey()) : null; BatchComponent parent = parentResource != null ? get(parentResource.getEffectiveKey()) : null;
BatchComponent batchResource = new BatchComponent(components.size() + 1, resource, parent); BatchComponent batchComponent = new BatchComponent(components.size() + 1, resource, parent);
// Libraries can have the same effective key than a project so we can't cache by effectiveKey components.put(componentKey, batchComponent);
components.put(componentKey, batchResource);
if (parent == null) { if (parent == null) {
root = batchResource; root = batchComponent;
} }
return batchResource; return batchComponent;
} }


public Collection<BatchComponent> all() { public Collection<BatchComponent> all() {
Expand Down
Expand Up @@ -23,7 +23,6 @@
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties; import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.resources.Language; import org.sonar.api.resources.Language;
import org.sonar.api.resources.Resource; import org.sonar.api.resources.Resource;
Expand All @@ -37,17 +36,18 @@
import org.sonar.batch.protocol.output.BatchReport.ComponentLink; import org.sonar.batch.protocol.output.BatchReport.ComponentLink;
import org.sonar.batch.protocol.output.BatchReport.Event; import org.sonar.batch.protocol.output.BatchReport.Event;
import org.sonar.batch.protocol.output.BatchReportWriter; import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.batch.scan.ImmutableProjectReactor;


/** /**
* Adds components and analysis metadata to output report * Adds components and analysis metadata to output report
*/ */
public class ComponentsPublisher implements ReportPublisherStep { public class ComponentsPublisher implements ReportPublisherStep {


private final BatchComponentCache resourceCache; private final BatchComponentCache resourceCache;
private final ProjectReactor reactor; private final ImmutableProjectReactor reactor;
private final EventCache eventCache; private final EventCache eventCache;


public ComponentsPublisher(ProjectReactor reactor, BatchComponentCache resourceCache, EventCache eventCache) { public ComponentsPublisher(ImmutableProjectReactor reactor, BatchComponentCache resourceCache, EventCache eventCache) {
this.reactor = reactor; this.reactor = reactor;
this.resourceCache = resourceCache; this.resourceCache = resourceCache;
this.eventCache = eventCache; this.eventCache = eventCache;
Expand All @@ -59,28 +59,30 @@ public void publish(BatchReportWriter writer) {
recursiveWriteComponent(rootProject, writer); recursiveWriteComponent(rootProject, writer);
} }


private void recursiveWriteComponent(BatchComponent batchResource, BatchReportWriter writer) { private void recursiveWriteComponent(BatchComponent batchComponent, BatchReportWriter writer) {
Resource r = batchResource.resource(); Resource r = batchComponent.resource();
BatchReport.Component.Builder builder = BatchReport.Component.newBuilder(); BatchReport.Component.Builder builder = BatchReport.Component.newBuilder();


// non-null fields // non-null fields
builder.setRef(batchResource.batchId()); builder.setRef(batchComponent.batchId());
builder.setType(getType(r)); builder.setType(getType(r));


// Don't set key on directories and files to save space since it can be deduced from path // Don't set key on directories and files to save space since it can be deduced from path
if (ResourceUtils.isProject(r)) { if (batchComponent.isProjectOrModule()) {
builder.setKey(r.getKey()); // Here we want key without branch
ProjectDefinition def = reactor.getProjectDefinition(batchComponent.key());
builder.setKey(def.getKey());
} }


// protocol buffers does not accept null values // protocol buffers does not accept null values


Integer sid = batchResource.snapshotId(); Integer sid = batchComponent.snapshotId();
if (sid != null) { if (sid != null) {
builder.setSnapshotId(sid); builder.setSnapshotId(sid);
} }
if (batchResource.isFile()) { if (batchComponent.isFile()) {
builder.setIsTest(ResourceUtils.isUnitTestFile(r)); builder.setIsTest(ResourceUtils.isUnitTestFile(r));
builder.setLines(((InputFile) batchResource.inputPath()).lines()); builder.setLines(((InputFile) batchComponent.inputPath()).lines());
} }
String name = getName(r); String name = getName(r);
if (name != null) { if (name != null) {
Expand All @@ -98,15 +100,15 @@ private void recursiveWriteComponent(BatchComponent batchResource, BatchReportWr
if (lang != null) { if (lang != null) {
builder.setLanguage(lang); builder.setLanguage(lang);
} }
for (BatchComponent child : batchResource.children()) { for (BatchComponent child : batchComponent.children()) {
builder.addChildRef(child.batchId()); builder.addChildRef(child.batchId());
} }
writeLinks(r, builder); writeLinks(batchComponent, builder);
writeVersion(r, builder); writeVersion(batchComponent, builder);
writeEvents(batchResource, builder); writeEvents(batchComponent, builder);
writer.writeComponent(builder.build()); writer.writeComponent(builder.build());


for (BatchComponent child : batchResource.children()) { for (BatchComponent child : batchComponent.children()) {
recursiveWriteComponent(child, writer); recursiveWriteComponent(child, writer);
} }
} }
Expand All @@ -119,9 +121,9 @@ private void writeEvents(BatchComponent batchResource, Builder builder) {
} }
} }


private void writeVersion(Resource r, BatchReport.Component.Builder builder) { private void writeVersion(BatchComponent c, BatchReport.Component.Builder builder) {
if (ResourceUtils.isProject(r)) { if (c.isProjectOrModule()) {
ProjectDefinition def = getProjectDefinition(reactor, r.getKey()); ProjectDefinition def = reactor.getProjectDefinition(c.key());
String version = getVersion(def); String version = getVersion(def);
builder.setVersion(version); builder.setVersion(version);
} }
Expand All @@ -132,9 +134,9 @@ private String getVersion(ProjectDefinition def) {
return StringUtils.isNotBlank(version) ? version : getVersion(def.getParent()); return StringUtils.isNotBlank(version) ? version : getVersion(def.getParent());
} }


private void writeLinks(Resource r, BatchReport.Component.Builder builder) { private void writeLinks(BatchComponent c, BatchReport.Component.Builder builder) {
if (ResourceUtils.isProject(r)) { if (c.isProjectOrModule()) {
ProjectDefinition def = getProjectDefinition(reactor, r.getKey()); ProjectDefinition def = reactor.getProjectDefinition(c.key());
ComponentLink.Builder linkBuilder = ComponentLink.newBuilder(); ComponentLink.Builder linkBuilder = ComponentLink.newBuilder();


writeProjectLink(builder, def, linkBuilder, CoreProperties.LINKS_HOME_PAGE, ComponentLinkType.HOME); writeProjectLink(builder, def, linkBuilder, CoreProperties.LINKS_HOME_PAGE, ComponentLinkType.HOME);
Expand All @@ -145,15 +147,6 @@ private void writeLinks(Resource r, BatchReport.Component.Builder builder) {
} }
} }


private ProjectDefinition getProjectDefinition(ProjectReactor reactor, String keyWithBranch) {
for (ProjectDefinition p : reactor.getProjects()) {
if (keyWithBranch.equals(p.getKeyWithBranch())) {
return p;
}
}
return null;
}

private void writeProjectLink(BatchReport.Component.Builder componentBuilder, ProjectDefinition def, ComponentLink.Builder linkBuilder, String linkProp, private void writeProjectLink(BatchReport.Component.Builder componentBuilder, ProjectDefinition def, ComponentLink.Builder linkBuilder, String linkProp,
ComponentLinkType linkType) { ComponentLinkType linkType) {
String link = def.properties().get(linkProp); String link = def.properties().get(linkProp);
Expand Down
Expand Up @@ -21,7 +21,12 @@


import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import org.sonar.api.batch.bootstrap.ProjectReactor; import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import javax.annotation.Nullable;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.issue.internal.DefaultIssue; import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.FieldDiffs; import org.sonar.api.issue.internal.FieldDiffs;
import org.sonar.api.resources.Project; import org.sonar.api.resources.Project;
Expand All @@ -32,29 +37,24 @@
import org.sonar.batch.protocol.Constants; import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport; import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportWriter; import org.sonar.batch.protocol.output.BatchReportWriter;

import org.sonar.batch.scan.ImmutableProjectReactor;
import javax.annotation.Nullable;

import java.util.Collection;
import java.util.Date;
import java.util.Iterator;


public class IssuesPublisher implements ReportPublisherStep { public class IssuesPublisher implements ReportPublisherStep {


private final BatchComponentCache resourceCache; private final BatchComponentCache componentCache;
private final IssueCache issueCache; private final IssueCache issueCache;
private final ProjectReactor reactor; private final ImmutableProjectReactor reactor;


public IssuesPublisher(ProjectReactor reactor, BatchComponentCache resourceCache, IssueCache issueCache) { public IssuesPublisher(ImmutableProjectReactor reactor, BatchComponentCache componentCache, IssueCache issueCache) {
this.reactor = reactor; this.reactor = reactor;
this.resourceCache = resourceCache; this.componentCache = componentCache;
this.issueCache = issueCache; this.issueCache = issueCache;
} }


@Override @Override
public void publish(BatchReportWriter writer) { public void publish(BatchReportWriter writer) {
Collection<Object> deletedComponentKeys = issueCache.componentKeys(); Collection<Object> deletedComponentKeys = issueCache.componentKeys();
for (BatchComponent resource : resourceCache.all()) { for (BatchComponent resource : componentCache.all()) {
String componentKey = resource.resource().getEffectiveKey(); String componentKey = resource.resource().getEffectiveKey();
Iterable<DefaultIssue> issues = issueCache.byComponent(componentKey); Iterable<DefaultIssue> issues = issueCache.byComponent(componentKey);
writer.writeComponentIssues(resource.batchId(), Iterables.transform(issues, new Function<DefaultIssue, BatchReport.Issue>() { writer.writeComponentIssues(resource.batchId(), Iterables.transform(issues, new Function<DefaultIssue, BatchReport.Issue>() {
Expand All @@ -74,12 +74,18 @@ public BatchReport.Issue apply(DefaultIssue input) {
} }


private void exportMetadata(BatchReportWriter writer, int count) { private void exportMetadata(BatchReportWriter writer, int count) {
BatchComponent rootProject = resourceCache.get(reactor.getRoot().getKeyWithBranch()); ProjectDefinition root = reactor.getRoot();
BatchComponent rootProject = componentCache.getRoot();
BatchReport.Metadata.Builder builder = BatchReport.Metadata.newBuilder() BatchReport.Metadata.Builder builder = BatchReport.Metadata.newBuilder()
.setAnalysisDate(((Project) rootProject.resource()).getAnalysisDate().getTime()) .setAnalysisDate(((Project) rootProject.resource()).getAnalysisDate().getTime())
.setProjectKey(((Project) rootProject.resource()).key()) // Here we want key without branch
.setProjectKey(root.getKey())
.setRootComponentRef(rootProject.batchId()) .setRootComponentRef(rootProject.batchId())
.setDeletedComponentsCount(count); .setDeletedComponentsCount(count);
String branch = root.properties().get(CoreProperties.PROJECT_BRANCH_PROPERTY);
if (branch != null) {
builder.setBranch(branch);
}
Integer sid = rootProject.snapshotId(); Integer sid = rootProject.snapshotId();
if (sid != null) { if (sid != null) {
builder.setSnapshotId(sid); builder.setSnapshotId(sid);
Expand Down
Expand Up @@ -19,52 +19,53 @@
*/ */
package org.sonar.batch.scan; package org.sonar.batch.scan;


import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.CheckForNull;
import org.sonar.api.batch.BatchSide; import org.sonar.api.batch.BatchSide;
import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.bootstrap.ProjectDefinition;


import java.util.ArrayList;
import java.util.List;

/** /**
* Immutable copy of project reactor after all modifications have been applied (see {@link MutableProjectReactorProvider}). * Immutable copy of project reactor after all modifications have been applied (see {@link MutableProjectReactorProvider}).
*/ */
@BatchSide @BatchSide
public class ImmutableProjectReactor { public class ImmutableProjectReactor {


private ProjectDefinition root; private ProjectDefinition root;
private Map<String, ProjectDefinition> byKey = new HashMap<>();


public ImmutableProjectReactor(ProjectDefinition root) { public ImmutableProjectReactor(ProjectDefinition root) {
if (root.getParent() != null) { if (root.getParent() != null) {
throw new IllegalArgumentException("Not a root project: " + root); throw new IllegalArgumentException("Not a root project: " + root);
} }
this.root = root; this.root = root;
collectProjects(root);
} }


public List<ProjectDefinition> getProjects() { public Collection<ProjectDefinition> getProjects() {
return collectProjects(root, new ArrayList<ProjectDefinition>()); return byKey.values();
} }


/** /**
* Populates list of projects from hierarchy. * Populates list of projects from hierarchy.
*/ */
private static List<ProjectDefinition> collectProjects(ProjectDefinition def, List<ProjectDefinition> collected) { private void collectProjects(ProjectDefinition def) {
collected.add(def); if (byKey.containsKey(def.getKeyWithBranch())) {
throw new IllegalStateException("Duplicate module key in reactor: " + def.getKeyWithBranch());
}
byKey.put(def.getKeyWithBranch(), def);
for (ProjectDefinition child : def.getSubProjects()) { for (ProjectDefinition child : def.getSubProjects()) {
collectProjects(child, collected); collectProjects(child);
} }
return collected;
} }


public ProjectDefinition getRoot() { public ProjectDefinition getRoot() {
return root; return root;
} }


public ProjectDefinition getProject(String key) { @CheckForNull
for (ProjectDefinition p : getProjects()) { public ProjectDefinition getProjectDefinition(String keyWithBranch) {
if (key.equals(p.getKey())) { return byKey.get(keyWithBranch);
return p;
}
}
return null;
} }
} }
Expand Up @@ -24,17 +24,21 @@


public class ImmutableProjectReactorProvider extends ProviderAdapter { public class ImmutableProjectReactorProvider extends ProviderAdapter {


public ImmutableProjectReactor provide(ProjectReactor reactor, ProjectBuildersExecutor projectBuildersExecutor, ProjectExclusions exclusions, ProjectReactorValidator validator) { private ImmutableProjectReactor singleton;


// 1 Apply project builders public ImmutableProjectReactor provide(ProjectReactor reactor, ProjectBuildersExecutor projectBuildersExecutor, ProjectExclusions exclusions, ProjectReactorValidator validator) {
projectBuildersExecutor.execute(reactor); if (singleton == null) {
// 1 Apply project builders
projectBuildersExecutor.execute(reactor);


// 2 Apply project exclusions // 2 Apply project exclusions
exclusions.apply(reactor); exclusions.apply(reactor);


// 3 Validate final reactor // 3 Validate final reactor
validator.validate(reactor); validator.validate(reactor);


return new ImmutableProjectReactor(reactor.getRoot()); singleton = new ImmutableProjectReactor(reactor.getRoot());
}
return singleton;
} }
} }

0 comments on commit 1b4f976

Please sign in to comment.