GNU LESSER GENERAL PUBLIC LICENSE | |||||
GNU LESSER GENERAL PUBLIC LICENSE | |||||
Version 3, 29 June 2007 | Version 3, 29 June 2007 | ||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
scp -i ~/.ssh/id_rsa-sonar-keypair -C -r docs.tar root@ec2-75-101-133-159.compute-1.amazonaws.com:/tmp | scp -i ~/.ssh/id_rsa-sonar-keypair -C -r docs.tar root@ec2-75-101-133-159.compute-1.amazonaws.com:/tmp | ||||
ssh -i ~/.ssh/id_rsa-sonar-keypair root@ec2-75-101-133-159.compute-1.amazonaws.com 'tar -xf /tmp/docs.tar -C /vol/www/sonar.codehaus.org/docs' | |||||
ssh -i ~/.ssh/id_rsa-sonar-keypair root@ec2-75-101-133-159.compute-1.amazonaws.com 'tar -xf /tmp/docs.tar -C /vol/www/sonar.codehaus.org/docs' |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.plugins.core.sensors; | |||||
import javax.persistence.EntityManager; | |||||
import javax.persistence.EntityTransaction; | |||||
import javax.persistence.Query; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import org.sonar.api.batch.Decorator; | |||||
import org.sonar.api.batch.DecoratorContext; | |||||
import org.sonar.api.batch.DependedUpon; | |||||
import org.sonar.api.batch.DependsUpon; | |||||
import org.sonar.api.database.DatabaseSession; | |||||
import org.sonar.api.database.model.Snapshot; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.batch.index.ResourcePersister; | |||||
/** | |||||
* Decorator that currently only closes a review when its corresponding violation has been fixed. | |||||
*/ | |||||
@DependsUpon("ViolationPersisterDecorator") | |||||
public class ReviewsDecorator implements Decorator { | |||||
private static final Logger LOG = LoggerFactory.getLogger(ReviewsDecorator.class); | |||||
private ResourcePersister resourcePersister; | |||||
private DatabaseSession databaseSession; | |||||
public ReviewsDecorator(ResourcePersister resourcePersister, DatabaseSession databaseSession) { | |||||
this.resourcePersister = resourcePersister; | |||||
this.databaseSession = databaseSession; | |||||
} | |||||
public boolean shouldExecuteOnProject(Project project) { | |||||
return true; | |||||
} | |||||
public void decorate(Resource resource, DecoratorContext context) { | |||||
Snapshot currentSnapshot = resourcePersister.getSnapshot(resource); | |||||
if (currentSnapshot != null) { | |||||
int resourceId = currentSnapshot.getResourceId(); | |||||
int snapshotId = currentSnapshot.getId(); | |||||
Query query = databaseSession.createNativeQuery("UPDATE reviews SET status='closed' " + "WHERE resource_id = " + resourceId | |||||
+ " AND rule_failure_permanent_id NOT IN " + "(SELECT permanent_id FROM rule_failures WHERE snapshot_id = " + snapshotId + ")"); | |||||
int rowUpdated = query.executeUpdate(); | |||||
LOG.debug("- {} reviews set to 'closed' on resource #{}", rowUpdated, resourceId); | |||||
databaseSession.commit(); | |||||
} | |||||
} | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.plugins.core.sensors; | |||||
import javax.persistence.EntityManager; | |||||
import javax.persistence.EntityTransaction; | |||||
import javax.persistence.Query; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import org.sonar.api.batch.Decorator; | |||||
import org.sonar.api.batch.DecoratorContext; | |||||
import org.sonar.api.batch.DependedUpon; | |||||
import org.sonar.api.batch.DependsUpon; | |||||
import org.sonar.api.database.DatabaseSession; | |||||
import org.sonar.api.database.model.Snapshot; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.batch.index.ResourcePersister; | |||||
/** | |||||
* Decorator that currently only closes a review when its corresponding violation has been fixed. | |||||
*/ | |||||
@DependsUpon("ViolationPersisterDecorator") | |||||
public class ReviewsDecorator implements Decorator { | |||||
private static final Logger LOG = LoggerFactory.getLogger(ReviewsDecorator.class); | |||||
private ResourcePersister resourcePersister; | |||||
private DatabaseSession databaseSession; | |||||
public ReviewsDecorator(ResourcePersister resourcePersister, DatabaseSession databaseSession) { | |||||
this.resourcePersister = resourcePersister; | |||||
this.databaseSession = databaseSession; | |||||
} | |||||
public boolean shouldExecuteOnProject(Project project) { | |||||
return true; | |||||
} | |||||
public void decorate(Resource resource, DecoratorContext context) { | |||||
Snapshot currentSnapshot = resourcePersister.getSnapshot(resource); | |||||
if (currentSnapshot != null) { | |||||
int resourceId = currentSnapshot.getResourceId(); | |||||
int snapshotId = currentSnapshot.getId(); | |||||
Query query = databaseSession.createNativeQuery("UPDATE reviews SET status='closed' " + "WHERE resource_id = " + resourceId | |||||
+ " AND rule_failure_permanent_id NOT IN " + "(SELECT permanent_id FROM rule_failures WHERE snapshot_id = " + snapshotId + ")"); | |||||
int rowUpdated = query.executeUpdate(); | |||||
LOG.debug("- {} reviews set to 'closed' on resource #{}", rowUpdated, resourceId); | |||||
databaseSession.commit(); | |||||
} | |||||
} | |||||
} |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.plugins.core.timemachine; | |||||
import com.google.common.collect.LinkedHashMultimap; | |||||
import com.google.common.collect.Lists; | |||||
import com.google.common.collect.Multimap; | |||||
import org.apache.commons.codec.digest.DigestUtils; | |||||
import org.apache.commons.io.IOUtils; | |||||
import org.apache.commons.lang.ObjectUtils; | |||||
import org.apache.commons.lang.StringUtils; | |||||
import org.codehaus.plexus.util.StringInputStream; | |||||
import org.sonar.api.batch.*; | |||||
import org.sonar.api.database.model.RuleFailureModel; | |||||
import org.sonar.api.database.model.SnapshotSource; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.rules.Rule; | |||||
import org.sonar.api.rules.RuleFinder; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.api.utils.SonarException; | |||||
import org.sonar.batch.components.PastViolationsLoader; | |||||
import org.sonar.batch.index.ViolationPersister; | |||||
import java.io.IOException; | |||||
import java.util.Collection; | |||||
import java.util.Collections; | |||||
import java.util.List; | |||||
@DependsUpon(DecoratorBarriers.END_OF_VIOLATIONS_GENERATION) | |||||
@DependedUpon("ViolationPersisterDecorator") /* temporary workaround - see NewViolationsDecorator */ | |||||
public class ViolationPersisterDecorator implements Decorator { | |||||
/** | |||||
* Those chars would be ignored during generation of checksums. | |||||
*/ | |||||
private static final String SPACE_CHARS = "\t\n\r "; | |||||
private RuleFinder ruleFinder; | |||||
private PastViolationsLoader pastViolationsLoader; | |||||
private ViolationPersister violationPersister; | |||||
List<String> checksums = Lists.newArrayList(); | |||||
public ViolationPersisterDecorator(RuleFinder ruleFinder, PastViolationsLoader pastViolationsLoader, ViolationPersister violationPersister) { | |||||
this.ruleFinder = ruleFinder; | |||||
this.pastViolationsLoader = pastViolationsLoader; | |||||
this.violationPersister = violationPersister; | |||||
} | |||||
public boolean shouldExecuteOnProject(Project project) { | |||||
return true; | |||||
} | |||||
public void decorate(Resource resource, DecoratorContext context) { | |||||
if (context.getViolations().isEmpty()) { | |||||
return; | |||||
} | |||||
// Load past violations | |||||
List<RuleFailureModel> pastViolations = pastViolationsLoader.getPastViolations(resource); | |||||
// Load current source and calculate checksums | |||||
checksums = getChecksums(pastViolationsLoader.getSource(resource)); | |||||
// Save violations | |||||
compareWithPastViolations(context, pastViolations); | |||||
// Clear cache | |||||
checksums.clear(); | |||||
} | |||||
private void compareWithPastViolations(DecoratorContext context, List<RuleFailureModel> pastViolations) { | |||||
Multimap<Rule, RuleFailureModel> pastViolationsByRule = LinkedHashMultimap.create(); | |||||
for (RuleFailureModel pastViolation : pastViolations) { | |||||
Rule rule = ruleFinder.findById(pastViolation.getRuleId()); | |||||
pastViolationsByRule.put(rule, pastViolation); | |||||
} | |||||
// for each violation, search equivalent past violation | |||||
for (Violation violation : context.getViolations()) { | |||||
RuleFailureModel pastViolation = selectPastViolation(violation, pastViolationsByRule); | |||||
if (pastViolation != null) { | |||||
// remove violation, since would be updated and shouldn't affect other violations anymore | |||||
pastViolationsByRule.remove(violation.getRule(), pastViolation); | |||||
} | |||||
String checksum = getChecksumForLine(checksums, violation.getLineId()); | |||||
violationPersister.saveViolation(context.getProject(), violation, pastViolation, checksum); | |||||
} | |||||
violationPersister.commit(); | |||||
} | |||||
/** | |||||
* @return checksums, never null | |||||
*/ | |||||
private List<String> getChecksums(SnapshotSource source) { | |||||
return source == null || source.getData() == null ? Collections.<String>emptyList() : getChecksums(source.getData()); | |||||
} | |||||
static List<String> getChecksums(String data) { | |||||
List<String> result = Lists.newArrayList(); | |||||
StringInputStream stream = new StringInputStream(data); | |||||
try { | |||||
List<String> lines = IOUtils.readLines(stream); | |||||
for (String line : lines) { | |||||
result.add(getChecksum(line)); | |||||
} | |||||
} catch (IOException e) { | |||||
throw new SonarException("Unable to calculate checksums", e); | |||||
} finally { | |||||
IOUtils.closeQuietly(stream); | |||||
} | |||||
return result; | |||||
} | |||||
static String getChecksum(String line) { | |||||
String reducedLine = StringUtils.replaceChars(line, SPACE_CHARS, ""); | |||||
return DigestUtils.md5Hex(reducedLine); | |||||
} | |||||
/** | |||||
* @return checksum or null if checksum not exists for line | |||||
*/ | |||||
private String getChecksumForLine(List<String> checksums, Integer line) { | |||||
if (line == null || line < 1 || line > checksums.size()) { | |||||
return null; | |||||
} | |||||
return checksums.get(line - 1); | |||||
} | |||||
/** | |||||
* Search for past violation. | |||||
*/ | |||||
RuleFailureModel selectPastViolation(Violation violation, Multimap<Rule, RuleFailureModel> pastViolationsByRule) { | |||||
Collection<RuleFailureModel> pastViolations = pastViolationsByRule.get(violation.getRule()); | |||||
if (pastViolations==null || pastViolations.isEmpty()) { | |||||
// skip violation, if there is no past violations with same rule | |||||
return null; | |||||
} | |||||
String dbFormattedMessage = RuleFailureModel.abbreviateMessage(violation.getMessage()); | |||||
RuleFailureModel found = selectPastViolationUsingLine(violation, dbFormattedMessage, pastViolations); | |||||
if (found == null) { | |||||
found = selectPastViolationUsingChecksum(violation, dbFormattedMessage, pastViolations); | |||||
} | |||||
return found; | |||||
} | |||||
/** | |||||
* Search for past violation with same message and line. | |||||
*/ | |||||
private RuleFailureModel selectPastViolationUsingLine(Violation violation, String dbFormattedMessage, Collection<RuleFailureModel> pastViolations) { | |||||
for (RuleFailureModel pastViolation : pastViolations) { | |||||
if (ObjectUtils.equals(violation.getLineId(), pastViolation.getLine()) && StringUtils.equals(dbFormattedMessage, pastViolation.getMessage())) { | |||||
return pastViolation; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
/** | |||||
* Search for past violation with same message and checksum. | |||||
*/ | |||||
private RuleFailureModel selectPastViolationUsingChecksum(Violation violation, String dbFormattedMessage, Collection<RuleFailureModel> pastViolations) { | |||||
String checksum = getChecksumForLine(checksums, violation.getLineId()); | |||||
// skip violation, which not attached to line | |||||
if (checksum == null) { | |||||
return null; | |||||
} | |||||
for (RuleFailureModel pastViolation : pastViolations) { | |||||
String pastChecksum = pastViolation.getChecksum(); | |||||
if (StringUtils.equals(checksum, pastChecksum) && StringUtils.equals(dbFormattedMessage, pastViolation.getMessage())) { | |||||
return pastViolation; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return getClass().getSimpleName(); | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.plugins.core.timemachine; | |||||
import com.google.common.collect.LinkedHashMultimap; | |||||
import com.google.common.collect.Lists; | |||||
import com.google.common.collect.Multimap; | |||||
import org.apache.commons.codec.digest.DigestUtils; | |||||
import org.apache.commons.io.IOUtils; | |||||
import org.apache.commons.lang.ObjectUtils; | |||||
import org.apache.commons.lang.StringUtils; | |||||
import org.codehaus.plexus.util.StringInputStream; | |||||
import org.sonar.api.batch.*; | |||||
import org.sonar.api.database.model.RuleFailureModel; | |||||
import org.sonar.api.database.model.SnapshotSource; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.rules.Rule; | |||||
import org.sonar.api.rules.RuleFinder; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.api.utils.SonarException; | |||||
import org.sonar.batch.components.PastViolationsLoader; | |||||
import org.sonar.batch.index.ViolationPersister; | |||||
import java.io.IOException; | |||||
import java.util.Collection; | |||||
import java.util.Collections; | |||||
import java.util.List; | |||||
@DependsUpon(DecoratorBarriers.END_OF_VIOLATIONS_GENERATION) | |||||
@DependedUpon("ViolationPersisterDecorator") /* temporary workaround - see NewViolationsDecorator */ | |||||
public class ViolationPersisterDecorator implements Decorator { | |||||
/** | |||||
* Those chars would be ignored during generation of checksums. | |||||
*/ | |||||
private static final String SPACE_CHARS = "\t\n\r "; | |||||
private RuleFinder ruleFinder; | |||||
private PastViolationsLoader pastViolationsLoader; | |||||
private ViolationPersister violationPersister; | |||||
List<String> checksums = Lists.newArrayList(); | |||||
public ViolationPersisterDecorator(RuleFinder ruleFinder, PastViolationsLoader pastViolationsLoader, ViolationPersister violationPersister) { | |||||
this.ruleFinder = ruleFinder; | |||||
this.pastViolationsLoader = pastViolationsLoader; | |||||
this.violationPersister = violationPersister; | |||||
} | |||||
public boolean shouldExecuteOnProject(Project project) { | |||||
return true; | |||||
} | |||||
public void decorate(Resource resource, DecoratorContext context) { | |||||
if (context.getViolations().isEmpty()) { | |||||
return; | |||||
} | |||||
// Load past violations | |||||
List<RuleFailureModel> pastViolations = pastViolationsLoader.getPastViolations(resource); | |||||
// Load current source and calculate checksums | |||||
checksums = getChecksums(pastViolationsLoader.getSource(resource)); | |||||
// Save violations | |||||
compareWithPastViolations(context, pastViolations); | |||||
// Clear cache | |||||
checksums.clear(); | |||||
} | |||||
private void compareWithPastViolations(DecoratorContext context, List<RuleFailureModel> pastViolations) { | |||||
Multimap<Rule, RuleFailureModel> pastViolationsByRule = LinkedHashMultimap.create(); | |||||
for (RuleFailureModel pastViolation : pastViolations) { | |||||
Rule rule = ruleFinder.findById(pastViolation.getRuleId()); | |||||
pastViolationsByRule.put(rule, pastViolation); | |||||
} | |||||
// for each violation, search equivalent past violation | |||||
for (Violation violation : context.getViolations()) { | |||||
RuleFailureModel pastViolation = selectPastViolation(violation, pastViolationsByRule); | |||||
if (pastViolation != null) { | |||||
// remove violation, since would be updated and shouldn't affect other violations anymore | |||||
pastViolationsByRule.remove(violation.getRule(), pastViolation); | |||||
} | |||||
String checksum = getChecksumForLine(checksums, violation.getLineId()); | |||||
violationPersister.saveViolation(context.getProject(), violation, pastViolation, checksum); | |||||
} | |||||
violationPersister.commit(); | |||||
} | |||||
/** | |||||
* @return checksums, never null | |||||
*/ | |||||
private List<String> getChecksums(SnapshotSource source) { | |||||
return source == null || source.getData() == null ? Collections.<String>emptyList() : getChecksums(source.getData()); | |||||
} | |||||
static List<String> getChecksums(String data) { | |||||
List<String> result = Lists.newArrayList(); | |||||
StringInputStream stream = new StringInputStream(data); | |||||
try { | |||||
List<String> lines = IOUtils.readLines(stream); | |||||
for (String line : lines) { | |||||
result.add(getChecksum(line)); | |||||
} | |||||
} catch (IOException e) { | |||||
throw new SonarException("Unable to calculate checksums", e); | |||||
} finally { | |||||
IOUtils.closeQuietly(stream); | |||||
} | |||||
return result; | |||||
} | |||||
static String getChecksum(String line) { | |||||
String reducedLine = StringUtils.replaceChars(line, SPACE_CHARS, ""); | |||||
return DigestUtils.md5Hex(reducedLine); | |||||
} | |||||
/** | |||||
* @return checksum or null if checksum not exists for line | |||||
*/ | |||||
private String getChecksumForLine(List<String> checksums, Integer line) { | |||||
if (line == null || line < 1 || line > checksums.size()) { | |||||
return null; | |||||
} | |||||
return checksums.get(line - 1); | |||||
} | |||||
/** | |||||
* Search for past violation. | |||||
*/ | |||||
RuleFailureModel selectPastViolation(Violation violation, Multimap<Rule, RuleFailureModel> pastViolationsByRule) { | |||||
Collection<RuleFailureModel> pastViolations = pastViolationsByRule.get(violation.getRule()); | |||||
if (pastViolations==null || pastViolations.isEmpty()) { | |||||
// skip violation, if there is no past violations with same rule | |||||
return null; | |||||
} | |||||
String dbFormattedMessage = RuleFailureModel.abbreviateMessage(violation.getMessage()); | |||||
RuleFailureModel found = selectPastViolationUsingLine(violation, dbFormattedMessage, pastViolations); | |||||
if (found == null) { | |||||
found = selectPastViolationUsingChecksum(violation, dbFormattedMessage, pastViolations); | |||||
} | |||||
return found; | |||||
} | |||||
/** | |||||
* Search for past violation with same message and line. | |||||
*/ | |||||
private RuleFailureModel selectPastViolationUsingLine(Violation violation, String dbFormattedMessage, Collection<RuleFailureModel> pastViolations) { | |||||
for (RuleFailureModel pastViolation : pastViolations) { | |||||
if (ObjectUtils.equals(violation.getLineId(), pastViolation.getLine()) && StringUtils.equals(dbFormattedMessage, pastViolation.getMessage())) { | |||||
return pastViolation; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
/** | |||||
* Search for past violation with same message and checksum. | |||||
*/ | |||||
private RuleFailureModel selectPastViolationUsingChecksum(Violation violation, String dbFormattedMessage, Collection<RuleFailureModel> pastViolations) { | |||||
String checksum = getChecksumForLine(checksums, violation.getLineId()); | |||||
// skip violation, which not attached to line | |||||
if (checksum == null) { | |||||
return null; | |||||
} | |||||
for (RuleFailureModel pastViolation : pastViolations) { | |||||
String pastChecksum = pastViolation.getChecksum(); | |||||
if (StringUtils.equals(checksum, pastChecksum) && StringUtils.equals(dbFormattedMessage, pastViolation.getMessage())) { | |||||
return pastViolation; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return getClass().getSimpleName(); | |||||
} | |||||
} | } |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.plugins.core.sensors; | |||||
import org.junit.Ignore; | |||||
import org.junit.Test; | |||||
import org.sonar.api.database.model.Snapshot; | |||||
import org.sonar.api.resources.File; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.utils.DateUtils; | |||||
import org.sonar.batch.components.PastSnapshot; | |||||
import org.sonar.batch.components.TimeMachineConfiguration; | |||||
import org.sonar.batch.index.ResourcePersister; | |||||
import org.sonar.jpa.test.AbstractDbUnitTestCase; | |||||
import java.text.ParseException; | |||||
import java.util.Arrays; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.when; | |||||
public class ReviewsDecoratorTest extends AbstractDbUnitTestCase { | |||||
@Test | |||||
@Ignore("DBUnit needs Hibernate mapping...") | |||||
public void shouldSaveConfigurationInSnapshotsTable() throws ParseException { | |||||
setupData("fixture"); | |||||
File resource = new File("Foo"); | |||||
Snapshot snapshot = new Snapshot(); | |||||
snapshot.setId(666); | |||||
snapshot.setResourceId(111); | |||||
ResourcePersister persister = mock(ResourcePersister.class); | |||||
when(persister.getSnapshot(resource)).thenReturn(snapshot); | |||||
ReviewsDecorator reviewsDecorator = new ReviewsDecorator(persister, getSession()); | |||||
reviewsDecorator.decorate(resource, null); | |||||
//checkTables("shouldSaveConfigurationInSnapshotsTable", "snapshots"); | |||||
} | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.plugins.core.sensors; | |||||
import org.junit.Ignore; | |||||
import org.junit.Test; | |||||
import org.sonar.api.database.model.Snapshot; | |||||
import org.sonar.api.resources.File; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.utils.DateUtils; | |||||
import org.sonar.batch.components.PastSnapshot; | |||||
import org.sonar.batch.components.TimeMachineConfiguration; | |||||
import org.sonar.batch.index.ResourcePersister; | |||||
import org.sonar.jpa.test.AbstractDbUnitTestCase; | |||||
import java.text.ParseException; | |||||
import java.util.Arrays; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.when; | |||||
public class ReviewsDecoratorTest extends AbstractDbUnitTestCase { | |||||
@Test | |||||
@Ignore("DBUnit needs Hibernate mapping...") | |||||
public void shouldSaveConfigurationInSnapshotsTable() throws ParseException { | |||||
setupData("fixture"); | |||||
File resource = new File("Foo"); | |||||
Snapshot snapshot = new Snapshot(); | |||||
snapshot.setId(666); | |||||
snapshot.setResourceId(111); | |||||
ResourcePersister persister = mock(ResourcePersister.class); | |||||
when(persister.getSnapshot(resource)).thenReturn(snapshot); | |||||
ReviewsDecorator reviewsDecorator = new ReviewsDecorator(persister, getSession()); | |||||
reviewsDecorator.decorate(resource, null); | |||||
//checkTables("shouldSaveConfigurationInSnapshotsTable", "snapshots"); | |||||
} | |||||
} |
<dataset> | |||||
<snapshots | |||||
id="11" | |||||
project_id="555"/> | |||||
<snapshots | |||||
id="111" | |||||
project_id="555"/> | |||||
<snapshots | |||||
id="22" | |||||
project_id="666"/> | |||||
<snapshots | |||||
id="222" | |||||
project_id="666"/> | |||||
<rule_failures | |||||
id="1" | |||||
permament_id="1" | |||||
snapshot_id="11"/> | |||||
<rule_failures | |||||
id="2" | |||||
permament_id="2" | |||||
snapshot_id="22"/> | |||||
<rule_failures | |||||
id="3" | |||||
permament_id="3" | |||||
snapshot_id="22"/> | |||||
<rule_failures | |||||
id="4" | |||||
permament_id="1" | |||||
snapshot_id="111"/> | |||||
<rule_failures | |||||
id="5" | |||||
permament_id="3" | |||||
snapshot_id="222"/> | |||||
<reviews | |||||
id="1" | |||||
status="open" | |||||
rule_failure_permanent_id="1" | |||||
resource_id="555"/> | |||||
<reviews | |||||
id="2" | |||||
status="open" | |||||
rule_failure_permanent_id="2" | |||||
resource_id="666"/> | |||||
<reviews | |||||
id="3" | |||||
status="open" | |||||
rule_failure_permanent_id="3" | |||||
resource_id="666"/> | |||||
<dataset> | |||||
<snapshots | |||||
id="11" | |||||
project_id="555"/> | |||||
<snapshots | |||||
id="111" | |||||
project_id="555"/> | |||||
<snapshots | |||||
id="22" | |||||
project_id="666"/> | |||||
<snapshots | |||||
id="222" | |||||
project_id="666"/> | |||||
<rule_failures | |||||
id="1" | |||||
permament_id="1" | |||||
snapshot_id="11"/> | |||||
<rule_failures | |||||
id="2" | |||||
permament_id="2" | |||||
snapshot_id="22"/> | |||||
<rule_failures | |||||
id="3" | |||||
permament_id="3" | |||||
snapshot_id="22"/> | |||||
<rule_failures | |||||
id="4" | |||||
permament_id="1" | |||||
snapshot_id="111"/> | |||||
<rule_failures | |||||
id="5" | |||||
permament_id="3" | |||||
snapshot_id="222"/> | |||||
<reviews | |||||
id="1" | |||||
status="open" | |||||
rule_failure_permanent_id="1" | |||||
resource_id="555"/> | |||||
<reviews | |||||
id="2" | |||||
status="open" | |||||
rule_failure_permanent_id="2" | |||||
resource_id="666"/> | |||||
<reviews | |||||
id="3" | |||||
status="open" | |||||
rule_failure_permanent_id="3" | |||||
resource_id="666"/> | |||||
</dataset> | </dataset> |
set MAVEN_OPTS=-Xmx768m -XX:MaxPermSize=256m | set MAVEN_OPTS=-Xmx768m -XX:MaxPermSize=256m | ||||
mvn clean install -Dtest=false -DfailIfNoTests=false -Ddev | |||||
mvn clean install -Dtest=false -DfailIfNoTests=false -Ddev |
echo '-------------------------------------------------' | echo '-------------------------------------------------' | ||||
# it is recommended to use maven 3 for faster builds | # it is recommended to use maven 3 for faster builds | ||||
mvn clean install -Dtest=false -DfailIfNoTests=false -Ddev | |||||
mvn clean install -Dtest=false -DfailIfNoTests=false -Ddev |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.batch; | |||||
import java.util.Collection; | |||||
import java.util.Date; | |||||
import java.util.List; | |||||
import java.util.Set; | |||||
import com.google.common.collect.Lists; | |||||
import org.sonar.api.batch.DecoratorContext; | |||||
import org.sonar.api.batch.Event; | |||||
import org.sonar.api.batch.SonarIndex; | |||||
import org.sonar.api.design.Dependency; | |||||
import org.sonar.api.measures.Measure; | |||||
import org.sonar.api.measures.MeasuresFilter; | |||||
import org.sonar.api.measures.MeasuresFilters; | |||||
import org.sonar.api.measures.Metric; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.api.violations.ViolationQuery; | |||||
public class DefaultDecoratorContext implements DecoratorContext { | |||||
private SonarIndex index; | |||||
private Resource resource; | |||||
private boolean readOnly = false; | |||||
private List<DecoratorContext> childrenContexts; | |||||
public DefaultDecoratorContext(Resource resource, | |||||
SonarIndex index, | |||||
List<DecoratorContext> childrenContexts) { | |||||
this.index = index; | |||||
this.resource = resource; | |||||
this.childrenContexts = childrenContexts; | |||||
} | |||||
public DefaultDecoratorContext setReadOnly(boolean b) { | |||||
readOnly = b; | |||||
childrenContexts = null; | |||||
return this; | |||||
} | |||||
public Project getProject() { | |||||
return index.getProject(); | |||||
} | |||||
public List<DecoratorContext> getChildren() { | |||||
checkReadOnly("getModules"); | |||||
return childrenContexts; | |||||
} | |||||
private void checkReadOnly(String methodName) { | |||||
if (readOnly) { | |||||
throw new IllegalStateException("Method DecoratorContext." + methodName + "() can not be executed on children."); | |||||
} | |||||
} | |||||
public <M> M getMeasures(MeasuresFilter<M> filter) { | |||||
return index.getMeasures(resource, filter); | |||||
} | |||||
public Measure getMeasure(Metric metric) { | |||||
return index.getMeasure(resource, metric); | |||||
} | |||||
public Collection<Measure> getChildrenMeasures(MeasuresFilter filter) { | |||||
List<Measure> result = Lists.newArrayList(); | |||||
for (DecoratorContext childContext : childrenContexts) { | |||||
Object childResult = childContext.getMeasures(filter); | |||||
if (childResult != null) { | |||||
if (childResult instanceof Collection) { | |||||
result.addAll((Collection) childResult); | |||||
} else { | |||||
result.add((Measure) childResult); | |||||
} | |||||
} | |||||
} | |||||
return result; | |||||
} | |||||
public Collection<Measure> getChildrenMeasures(Metric metric) { | |||||
return getChildrenMeasures(MeasuresFilters.metric(metric)); | |||||
} | |||||
public Resource getResource() { | |||||
return resource; | |||||
} | |||||
public DecoratorContext saveMeasure(Measure measure) { | |||||
checkReadOnly("saveMeasure"); | |||||
index.addMeasure(resource, measure); | |||||
return this; | |||||
} | |||||
public DecoratorContext saveMeasure(Metric metric, Double value) { | |||||
checkReadOnly("saveMeasure"); | |||||
index.addMeasure(resource, new Measure(metric, value)); | |||||
return this; | |||||
} | |||||
/** | |||||
* {@inheritDoc} | |||||
*/ | |||||
public List<Violation> getViolations(ViolationQuery violationQuery) { | |||||
return index.getViolations(violationQuery); | |||||
} | |||||
/** | |||||
* {@inheritDoc} | |||||
*/ | |||||
public List<Violation> getViolations() { | |||||
return index.getViolations(resource); | |||||
} | |||||
public Dependency saveDependency(Dependency dependency) { | |||||
checkReadOnly("addDependency"); | |||||
return index.addDependency(dependency); | |||||
} | |||||
public Set<Dependency> getDependencies() { | |||||
return index.getDependencies(); | |||||
} | |||||
public Collection<Dependency> getIncomingDependencies() { | |||||
return index.getIncomingEdges(resource); | |||||
} | |||||
public Collection<Dependency> getOutgoingDependencies() { | |||||
return index.getOutgoingEdges(resource); | |||||
} | |||||
public List<Event> getEvents() { | |||||
return index.getEvents(resource); | |||||
} | |||||
public Event createEvent(String name, String description, String category, Date date) { | |||||
return index.addEvent(resource, name, description, category, date); | |||||
} | |||||
public void deleteEvent(Event event) { | |||||
index.deleteEvent(event); | |||||
} | |||||
public DefaultDecoratorContext saveViolation(Violation violation, boolean force) { | |||||
if (violation.getResource() == null) { | |||||
violation.setResource(resource); | |||||
} | |||||
index.addViolation(violation, force); | |||||
return this; | |||||
} | |||||
public DefaultDecoratorContext saveViolation(Violation violation) { | |||||
return saveViolation(violation, false); | |||||
} | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.batch; | |||||
import java.util.Collection; | |||||
import java.util.Date; | |||||
import java.util.List; | |||||
import java.util.Set; | |||||
import com.google.common.collect.Lists; | |||||
import org.sonar.api.batch.DecoratorContext; | |||||
import org.sonar.api.batch.Event; | |||||
import org.sonar.api.batch.SonarIndex; | |||||
import org.sonar.api.design.Dependency; | |||||
import org.sonar.api.measures.Measure; | |||||
import org.sonar.api.measures.MeasuresFilter; | |||||
import org.sonar.api.measures.MeasuresFilters; | |||||
import org.sonar.api.measures.Metric; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.api.violations.ViolationQuery; | |||||
public class DefaultDecoratorContext implements DecoratorContext { | |||||
private SonarIndex index; | |||||
private Resource resource; | |||||
private boolean readOnly = false; | |||||
private List<DecoratorContext> childrenContexts; | |||||
public DefaultDecoratorContext(Resource resource, | |||||
SonarIndex index, | |||||
List<DecoratorContext> childrenContexts) { | |||||
this.index = index; | |||||
this.resource = resource; | |||||
this.childrenContexts = childrenContexts; | |||||
} | |||||
public DefaultDecoratorContext setReadOnly(boolean b) { | |||||
readOnly = b; | |||||
childrenContexts = null; | |||||
return this; | |||||
} | |||||
public Project getProject() { | |||||
return index.getProject(); | |||||
} | |||||
public List<DecoratorContext> getChildren() { | |||||
checkReadOnly("getModules"); | |||||
return childrenContexts; | |||||
} | |||||
private void checkReadOnly(String methodName) { | |||||
if (readOnly) { | |||||
throw new IllegalStateException("Method DecoratorContext." + methodName + "() can not be executed on children."); | |||||
} | |||||
} | |||||
public <M> M getMeasures(MeasuresFilter<M> filter) { | |||||
return index.getMeasures(resource, filter); | |||||
} | |||||
public Measure getMeasure(Metric metric) { | |||||
return index.getMeasure(resource, metric); | |||||
} | |||||
public Collection<Measure> getChildrenMeasures(MeasuresFilter filter) { | |||||
List<Measure> result = Lists.newArrayList(); | |||||
for (DecoratorContext childContext : childrenContexts) { | |||||
Object childResult = childContext.getMeasures(filter); | |||||
if (childResult != null) { | |||||
if (childResult instanceof Collection) { | |||||
result.addAll((Collection) childResult); | |||||
} else { | |||||
result.add((Measure) childResult); | |||||
} | |||||
} | |||||
} | |||||
return result; | |||||
} | |||||
public Collection<Measure> getChildrenMeasures(Metric metric) { | |||||
return getChildrenMeasures(MeasuresFilters.metric(metric)); | |||||
} | |||||
public Resource getResource() { | |||||
return resource; | |||||
} | |||||
public DecoratorContext saveMeasure(Measure measure) { | |||||
checkReadOnly("saveMeasure"); | |||||
index.addMeasure(resource, measure); | |||||
return this; | |||||
} | |||||
public DecoratorContext saveMeasure(Metric metric, Double value) { | |||||
checkReadOnly("saveMeasure"); | |||||
index.addMeasure(resource, new Measure(metric, value)); | |||||
return this; | |||||
} | |||||
/** | |||||
* {@inheritDoc} | |||||
*/ | |||||
public List<Violation> getViolations(ViolationQuery violationQuery) { | |||||
return index.getViolations(violationQuery); | |||||
} | |||||
/** | |||||
* {@inheritDoc} | |||||
*/ | |||||
public List<Violation> getViolations() { | |||||
return index.getViolations(resource); | |||||
} | |||||
public Dependency saveDependency(Dependency dependency) { | |||||
checkReadOnly("addDependency"); | |||||
return index.addDependency(dependency); | |||||
} | |||||
public Set<Dependency> getDependencies() { | |||||
return index.getDependencies(); | |||||
} | |||||
public Collection<Dependency> getIncomingDependencies() { | |||||
return index.getIncomingEdges(resource); | |||||
} | |||||
public Collection<Dependency> getOutgoingDependencies() { | |||||
return index.getOutgoingEdges(resource); | |||||
} | |||||
public List<Event> getEvents() { | |||||
return index.getEvents(resource); | |||||
} | |||||
public Event createEvent(String name, String description, String category, Date date) { | |||||
return index.addEvent(resource, name, description, category, date); | |||||
} | |||||
public void deleteEvent(Event event) { | |||||
index.deleteEvent(event); | |||||
} | |||||
public DefaultDecoratorContext saveViolation(Violation violation, boolean force) { | |||||
if (violation.getResource() == null) { | |||||
violation.setResource(resource); | |||||
} | |||||
index.addViolation(violation, force); | |||||
return this; | |||||
} | |||||
public DefaultDecoratorContext saveViolation(Violation violation) { | |||||
return saveViolation(violation, false); | |||||
} | |||||
} |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.batch.index; | |||||
import org.sonar.api.database.DatabaseSession; | |||||
import org.sonar.api.database.model.RuleFailureModel; | |||||
import org.sonar.api.database.model.Snapshot; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.rules.Rule; | |||||
import org.sonar.api.rules.RuleFinder; | |||||
import org.sonar.api.rules.Violation; | |||||
public final class ViolationPersister { | |||||
private DatabaseSession session; | |||||
private ResourcePersister resourcePersister; | |||||
private RuleFinder ruleFinder; | |||||
public ViolationPersister(DatabaseSession session, ResourcePersister resourcePersister, RuleFinder ruleFinder) { | |||||
this.session = session; | |||||
this.resourcePersister = resourcePersister; | |||||
this.ruleFinder = ruleFinder; | |||||
} | |||||
void saveViolation(Project project, Violation violation) { | |||||
saveViolation(project, violation, null, null); | |||||
} | |||||
public void saveViolation(Project project, Violation violation, RuleFailureModel pastViolation, String checksum) { | |||||
Snapshot snapshot = resourcePersister.saveResource(project, violation.getResource()); | |||||
RuleFailureModel model = createModel(violation); | |||||
if (pastViolation!=null) { | |||||
model.setCreatedAt(pastViolation.getCreatedAt()); | |||||
model.setPermanentId(pastViolation.getPermanentId()); | |||||
model.setSwitchedOff(pastViolation.isSwitchedOff()); | |||||
} else { | |||||
// avoid plugins setting date | |||||
model.setCreatedAt(snapshot.getCreatedAt()); | |||||
} | |||||
model.setSnapshotId(snapshot.getId()); | |||||
model.setChecksum(checksum); | |||||
session.save(model); | |||||
if (model.getPermanentId()==null) { | |||||
model.setPermanentId(model.getId()); | |||||
session.save(model); | |||||
} | |||||
// the following fields can have been changed | |||||
violation.setMessage(model.getMessage());// the message can be changed in the class RuleFailure (truncate + trim) | |||||
violation.setCreatedAt(model.getCreatedAt()); | |||||
violation.setSwitchedOff(model.isSwitchedOff()); | |||||
} | |||||
public void commit() { | |||||
session.commit(); | |||||
} | |||||
private RuleFailureModel createModel(Violation violation) { | |||||
RuleFailureModel model = new RuleFailureModel(); | |||||
Rule rule = ruleFinder.findByKey(violation.getRule().getRepositoryKey(), violation.getRule().getKey()); | |||||
model.setRuleId(rule.getId()); | |||||
model.setPriority(violation.getSeverity()); | |||||
model.setLine(violation.getLineId()); | |||||
model.setMessage(violation.getMessage()); | |||||
model.setCost(violation.getCost()); | |||||
return model; | |||||
} | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.batch.index; | |||||
import org.sonar.api.database.DatabaseSession; | |||||
import org.sonar.api.database.model.RuleFailureModel; | |||||
import org.sonar.api.database.model.Snapshot; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.rules.Rule; | |||||
import org.sonar.api.rules.RuleFinder; | |||||
import org.sonar.api.rules.Violation; | |||||
public final class ViolationPersister { | |||||
private DatabaseSession session; | |||||
private ResourcePersister resourcePersister; | |||||
private RuleFinder ruleFinder; | |||||
public ViolationPersister(DatabaseSession session, ResourcePersister resourcePersister, RuleFinder ruleFinder) { | |||||
this.session = session; | |||||
this.resourcePersister = resourcePersister; | |||||
this.ruleFinder = ruleFinder; | |||||
} | |||||
void saveViolation(Project project, Violation violation) { | |||||
saveViolation(project, violation, null, null); | |||||
} | |||||
public void saveViolation(Project project, Violation violation, RuleFailureModel pastViolation, String checksum) { | |||||
Snapshot snapshot = resourcePersister.saveResource(project, violation.getResource()); | |||||
RuleFailureModel model = createModel(violation); | |||||
if (pastViolation!=null) { | |||||
model.setCreatedAt(pastViolation.getCreatedAt()); | |||||
model.setPermanentId(pastViolation.getPermanentId()); | |||||
model.setSwitchedOff(pastViolation.isSwitchedOff()); | |||||
} else { | |||||
// avoid plugins setting date | |||||
model.setCreatedAt(snapshot.getCreatedAt()); | |||||
} | |||||
model.setSnapshotId(snapshot.getId()); | |||||
model.setChecksum(checksum); | |||||
session.save(model); | |||||
if (model.getPermanentId()==null) { | |||||
model.setPermanentId(model.getId()); | |||||
session.save(model); | |||||
} | |||||
// the following fields can have been changed | |||||
violation.setMessage(model.getMessage());// the message can be changed in the class RuleFailure (truncate + trim) | |||||
violation.setCreatedAt(model.getCreatedAt()); | |||||
violation.setSwitchedOff(model.isSwitchedOff()); | |||||
} | |||||
public void commit() { | |||||
session.commit(); | |||||
} | |||||
private RuleFailureModel createModel(Violation violation) { | |||||
RuleFailureModel model = new RuleFailureModel(); | |||||
Rule rule = ruleFinder.findByKey(violation.getRule().getRepositoryKey(), violation.getRule().getKey()); | |||||
model.setRuleId(rule.getId()); | |||||
model.setPriority(violation.getSeverity()); | |||||
model.setLine(violation.getLineId()); | |||||
model.setMessage(violation.getMessage()); | |||||
model.setCost(violation.getCost()); | |||||
return model; | |||||
} | |||||
} |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.batch.index; | |||||
import static org.hamcrest.Matchers.nullValue; | |||||
import static org.hamcrest.core.Is.is; | |||||
import static org.junit.Assert.assertThat; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.when; | |||||
import org.apache.commons.lang.StringUtils; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import org.sonar.api.batch.ResourceFilter; | |||||
import org.sonar.api.measures.CoreMetrics; | |||||
import org.sonar.api.measures.Measure; | |||||
import org.sonar.api.measures.MeasuresFilters; | |||||
import org.sonar.api.measures.MetricFinder; | |||||
import org.sonar.api.profiles.RulesProfile; | |||||
import org.sonar.api.resources.Directory; | |||||
import org.sonar.api.resources.File; | |||||
import org.sonar.api.resources.Java; | |||||
import org.sonar.api.resources.JavaPackage; | |||||
import org.sonar.api.resources.Language; | |||||
import org.sonar.api.resources.Library; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.Qualifiers; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.rules.Rule; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.api.utils.SonarException; | |||||
import org.sonar.api.violations.ViolationQuery; | |||||
import org.sonar.batch.DefaultResourceCreationLock; | |||||
import org.sonar.batch.ProjectTree; | |||||
import org.sonar.batch.ResourceFilters; | |||||
import org.sonar.batch.ViolationFilters; | |||||
public class DefaultIndexTest { | |||||
private DefaultIndex index = null; | |||||
private DefaultResourceCreationLock lock; | |||||
private Rule rule; | |||||
@Before | |||||
public void createIndex() { | |||||
lock = new DefaultResourceCreationLock(); | |||||
MetricFinder metricFinder = mock(MetricFinder.class); | |||||
when(metricFinder.findByKey("ncloc")).thenReturn(CoreMetrics.NCLOC); | |||||
index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder); | |||||
Project project = new Project("project"); | |||||
ResourceFilter filter = new ResourceFilter() { | |||||
public boolean isIgnored(Resource resource) { | |||||
return StringUtils.containsIgnoreCase(resource.getKey(), "excluded"); | |||||
} | |||||
}; | |||||
RulesProfile rulesProfile = RulesProfile.create(); | |||||
rule = Rule.create("repoKey", "ruleKey", "Rule"); | |||||
rulesProfile.activateRule(rule, null); | |||||
index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[] { filter }), new ViolationFilters(), rulesProfile); | |||||
index.doStart(project); | |||||
} | |||||
@Test | |||||
public void shouldCreateUID() { | |||||
Project project = new Project("my_project"); | |||||
assertThat(DefaultIndex.createUID(project, project), is("my_project")); | |||||
JavaPackage javaPackage = new JavaPackage("org.foo"); | |||||
assertThat(DefaultIndex.createUID(project, javaPackage), is("my_project:org.foo")); | |||||
Library library = new Library("junit:junit", "4.7"); | |||||
assertThat(DefaultIndex.createUID(project, library), is("junit:junit")); | |||||
} | |||||
@Test | |||||
public void shouldIndexParentOfDeprecatedFiles() { | |||||
File file = new File("org/foo/Bar.java"); | |||||
assertThat(index.index(file), is(true)); | |||||
Directory reference = new Directory("org/foo"); | |||||
assertThat(index.getResource(reference).getName(), is("org/foo")); | |||||
assertThat(index.isIndexed(reference, true), is(true)); | |||||
assertThat(index.isExcluded(reference), is(false)); | |||||
assertThat(index.getChildren(reference).size(), is(1)); | |||||
assertThat(index.getParent(reference), is(Project.class)); | |||||
} | |||||
@Test | |||||
public void shouldIndexTreeOfResources() { | |||||
Directory directory = new Directory("org/foo"); | |||||
File file = new File("org/foo/Bar.java"); | |||||
file.setLanguage(Java.INSTANCE); | |||||
assertThat(index.index(directory), is(true)); | |||||
assertThat(index.index(file, directory), is(true)); | |||||
File fileRef = new File("org/foo/Bar.java"); | |||||
assertThat(index.getResource(fileRef).getKey(), is("org/foo/Bar.java")); | |||||
assertThat(index.getResource(fileRef).getLanguage(), is((Language) Java.INSTANCE)); | |||||
assertThat(index.isIndexed(fileRef, true), is(true)); | |||||
assertThat(index.isExcluded(fileRef), is(false)); | |||||
assertThat(index.getChildren(fileRef).size(), is(0)); | |||||
assertThat(index.getParent(fileRef), is(Directory.class)); | |||||
} | |||||
@Test | |||||
public void shouldIndexLibraryOutsideProjectTree() { | |||||
Library lib = new Library("junit", "4.8"); | |||||
assertThat(index.index(lib), is(true)); | |||||
Library reference = new Library("junit", "4.8"); | |||||
assertThat(index.getResource(reference).getQualifier(), is(Qualifiers.LIBRARY)); | |||||
assertThat(index.isIndexed(reference, true), is(true)); | |||||
assertThat(index.isExcluded(reference), is(false)); | |||||
} | |||||
@Test | |||||
public void shouldNotIndexResourceIfParentNotIndexed() { | |||||
Directory directory = new Directory("org/other"); | |||||
File file = new File("org/foo/Bar.java"); | |||||
assertThat(index.index(file, directory), is(false)); | |||||
File fileRef = new File("org/foo/Bar.java"); | |||||
assertThat(index.isIndexed(directory, true), is(false)); | |||||
assertThat(index.isIndexed(fileRef, true), is(false)); | |||||
assertThat(index.isExcluded(fileRef), is(false)); | |||||
assertThat(index.getChildren(fileRef).size(), is(0)); | |||||
assertThat(index.getParent(fileRef), nullValue()); | |||||
} | |||||
/** | |||||
* Only a warning is logged when index is locked. | |||||
*/ | |||||
@Test | |||||
public void shouldIndexEvenIfLocked() { | |||||
lock.lock(); | |||||
Directory dir = new Directory("org/foo"); | |||||
assertThat(index.index(dir), is(true)); | |||||
assertThat(index.isIndexed(dir, true), is(true)); | |||||
} | |||||
@Test(expected = SonarException.class) | |||||
public void shouldFailIfIndexingAndLocked() { | |||||
lock.setFailWhenLocked(true); | |||||
lock.lock(); | |||||
Directory dir = new Directory("org/foo"); | |||||
index.index(dir); | |||||
} | |||||
@Test | |||||
public void shouldBeExcluded() { | |||||
File file = new File("org/foo/ExcludedBar.java"); | |||||
assertThat(index.index(file), is(false)); | |||||
assertThat(index.isIndexed(file, true), is(true)); | |||||
assertThat(index.isIndexed(file, false), is(false)); | |||||
assertThat(index.isExcluded(file), is(true)); | |||||
} | |||||
@Test | |||||
public void shouldIndexResourceWhenAddingMeasure() { | |||||
Resource dir = new Directory("org/foo"); | |||||
index.addMeasure(dir, new Measure("ncloc").setValue(50.0)); | |||||
assertThat(index.isIndexed(dir, true), is(true)); | |||||
assertThat(index.getMeasures(dir, MeasuresFilters.metric("ncloc")).getIntValue(), is(50)); | |||||
} | |||||
/** | |||||
* See http://jira.codehaus.org/browse/SONAR-2107 | |||||
*/ | |||||
@Test | |||||
public void shouldNotFailWhenSavingViolationOnNullRule() { | |||||
File file = new File("org/foo/Bar.java"); | |||||
Violation violation = Violation.create((Rule) null, file); | |||||
index.addViolation(violation); | |||||
assertThat(index.getViolations(file).size(), is(0)); | |||||
} | |||||
@Test | |||||
public void testGetViolations() { | |||||
File file = new File("org/foo/Bar.java"); | |||||
Violation violation1 = Violation.create(rule, file); | |||||
index.addViolation(violation1); | |||||
Violation violation2 = Violation.create(rule, file); | |||||
violation2.setSwitchedOff(true); | |||||
index.addViolation(violation2); | |||||
Violation violation3 = Violation.create(rule, file); | |||||
violation3.setSwitchedOff(true); | |||||
index.addViolation(violation3); | |||||
assertThat(index.getViolations(file).size(), is(1)); | |||||
} | |||||
@Test | |||||
public void testGetViolationsWithQuery() { | |||||
File file = new File("org/foo/Bar.java"); | |||||
Violation violation1 = Violation.create(rule, file); | |||||
index.addViolation(violation1); | |||||
Violation violation2 = Violation.create(rule, file); | |||||
violation2.setSwitchedOff(true); | |||||
index.addViolation(violation2); | |||||
Violation violation3 = Violation.create(rule, file); | |||||
violation3.setSwitchedOff(true); | |||||
index.addViolation(violation3); | |||||
assertThat(index.getViolations(ViolationQuery.create().forResource(file).ignoreSwitchedOff(false)).size(), is(3)); | |||||
} | |||||
@Test(expected = IllegalArgumentException.class) | |||||
public void testGetViolationsWithQueryWithNoResource() { | |||||
index.getViolations(ViolationQuery.create()); | |||||
} | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.batch.index; | |||||
import static org.hamcrest.Matchers.nullValue; | |||||
import static org.hamcrest.core.Is.is; | |||||
import static org.junit.Assert.assertThat; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.when; | |||||
import org.apache.commons.lang.StringUtils; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import org.sonar.api.batch.ResourceFilter; | |||||
import org.sonar.api.measures.CoreMetrics; | |||||
import org.sonar.api.measures.Measure; | |||||
import org.sonar.api.measures.MeasuresFilters; | |||||
import org.sonar.api.measures.MetricFinder; | |||||
import org.sonar.api.profiles.RulesProfile; | |||||
import org.sonar.api.resources.Directory; | |||||
import org.sonar.api.resources.File; | |||||
import org.sonar.api.resources.Java; | |||||
import org.sonar.api.resources.JavaPackage; | |||||
import org.sonar.api.resources.Language; | |||||
import org.sonar.api.resources.Library; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.Qualifiers; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.rules.Rule; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.api.utils.SonarException; | |||||
import org.sonar.api.violations.ViolationQuery; | |||||
import org.sonar.batch.DefaultResourceCreationLock; | |||||
import org.sonar.batch.ProjectTree; | |||||
import org.sonar.batch.ResourceFilters; | |||||
import org.sonar.batch.ViolationFilters; | |||||
public class DefaultIndexTest { | |||||
private DefaultIndex index = null; | |||||
private DefaultResourceCreationLock lock; | |||||
private Rule rule; | |||||
@Before | |||||
public void createIndex() { | |||||
lock = new DefaultResourceCreationLock(); | |||||
MetricFinder metricFinder = mock(MetricFinder.class); | |||||
when(metricFinder.findByKey("ncloc")).thenReturn(CoreMetrics.NCLOC); | |||||
index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder); | |||||
Project project = new Project("project"); | |||||
ResourceFilter filter = new ResourceFilter() { | |||||
public boolean isIgnored(Resource resource) { | |||||
return StringUtils.containsIgnoreCase(resource.getKey(), "excluded"); | |||||
} | |||||
}; | |||||
RulesProfile rulesProfile = RulesProfile.create(); | |||||
rule = Rule.create("repoKey", "ruleKey", "Rule"); | |||||
rulesProfile.activateRule(rule, null); | |||||
index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[] { filter }), new ViolationFilters(), rulesProfile); | |||||
index.doStart(project); | |||||
} | |||||
@Test | |||||
public void shouldCreateUID() { | |||||
Project project = new Project("my_project"); | |||||
assertThat(DefaultIndex.createUID(project, project), is("my_project")); | |||||
JavaPackage javaPackage = new JavaPackage("org.foo"); | |||||
assertThat(DefaultIndex.createUID(project, javaPackage), is("my_project:org.foo")); | |||||
Library library = new Library("junit:junit", "4.7"); | |||||
assertThat(DefaultIndex.createUID(project, library), is("junit:junit")); | |||||
} | |||||
@Test | |||||
public void shouldIndexParentOfDeprecatedFiles() { | |||||
File file = new File("org/foo/Bar.java"); | |||||
assertThat(index.index(file), is(true)); | |||||
Directory reference = new Directory("org/foo"); | |||||
assertThat(index.getResource(reference).getName(), is("org/foo")); | |||||
assertThat(index.isIndexed(reference, true), is(true)); | |||||
assertThat(index.isExcluded(reference), is(false)); | |||||
assertThat(index.getChildren(reference).size(), is(1)); | |||||
assertThat(index.getParent(reference), is(Project.class)); | |||||
} | |||||
@Test | |||||
public void shouldIndexTreeOfResources() { | |||||
Directory directory = new Directory("org/foo"); | |||||
File file = new File("org/foo/Bar.java"); | |||||
file.setLanguage(Java.INSTANCE); | |||||
assertThat(index.index(directory), is(true)); | |||||
assertThat(index.index(file, directory), is(true)); | |||||
File fileRef = new File("org/foo/Bar.java"); | |||||
assertThat(index.getResource(fileRef).getKey(), is("org/foo/Bar.java")); | |||||
assertThat(index.getResource(fileRef).getLanguage(), is((Language) Java.INSTANCE)); | |||||
assertThat(index.isIndexed(fileRef, true), is(true)); | |||||
assertThat(index.isExcluded(fileRef), is(false)); | |||||
assertThat(index.getChildren(fileRef).size(), is(0)); | |||||
assertThat(index.getParent(fileRef), is(Directory.class)); | |||||
} | |||||
@Test | |||||
public void shouldIndexLibraryOutsideProjectTree() { | |||||
Library lib = new Library("junit", "4.8"); | |||||
assertThat(index.index(lib), is(true)); | |||||
Library reference = new Library("junit", "4.8"); | |||||
assertThat(index.getResource(reference).getQualifier(), is(Qualifiers.LIBRARY)); | |||||
assertThat(index.isIndexed(reference, true), is(true)); | |||||
assertThat(index.isExcluded(reference), is(false)); | |||||
} | |||||
@Test | |||||
public void shouldNotIndexResourceIfParentNotIndexed() { | |||||
Directory directory = new Directory("org/other"); | |||||
File file = new File("org/foo/Bar.java"); | |||||
assertThat(index.index(file, directory), is(false)); | |||||
File fileRef = new File("org/foo/Bar.java"); | |||||
assertThat(index.isIndexed(directory, true), is(false)); | |||||
assertThat(index.isIndexed(fileRef, true), is(false)); | |||||
assertThat(index.isExcluded(fileRef), is(false)); | |||||
assertThat(index.getChildren(fileRef).size(), is(0)); | |||||
assertThat(index.getParent(fileRef), nullValue()); | |||||
} | |||||
/** | |||||
* Only a warning is logged when index is locked. | |||||
*/ | |||||
@Test | |||||
public void shouldIndexEvenIfLocked() { | |||||
lock.lock(); | |||||
Directory dir = new Directory("org/foo"); | |||||
assertThat(index.index(dir), is(true)); | |||||
assertThat(index.isIndexed(dir, true), is(true)); | |||||
} | |||||
@Test(expected = SonarException.class) | |||||
public void shouldFailIfIndexingAndLocked() { | |||||
lock.setFailWhenLocked(true); | |||||
lock.lock(); | |||||
Directory dir = new Directory("org/foo"); | |||||
index.index(dir); | |||||
} | |||||
@Test | |||||
public void shouldBeExcluded() { | |||||
File file = new File("org/foo/ExcludedBar.java"); | |||||
assertThat(index.index(file), is(false)); | |||||
assertThat(index.isIndexed(file, true), is(true)); | |||||
assertThat(index.isIndexed(file, false), is(false)); | |||||
assertThat(index.isExcluded(file), is(true)); | |||||
} | |||||
@Test | |||||
public void shouldIndexResourceWhenAddingMeasure() { | |||||
Resource dir = new Directory("org/foo"); | |||||
index.addMeasure(dir, new Measure("ncloc").setValue(50.0)); | |||||
assertThat(index.isIndexed(dir, true), is(true)); | |||||
assertThat(index.getMeasures(dir, MeasuresFilters.metric("ncloc")).getIntValue(), is(50)); | |||||
} | |||||
/** | |||||
* See http://jira.codehaus.org/browse/SONAR-2107 | |||||
*/ | |||||
@Test | |||||
public void shouldNotFailWhenSavingViolationOnNullRule() { | |||||
File file = new File("org/foo/Bar.java"); | |||||
Violation violation = Violation.create((Rule) null, file); | |||||
index.addViolation(violation); | |||||
assertThat(index.getViolations(file).size(), is(0)); | |||||
} | |||||
@Test | |||||
public void testGetViolations() { | |||||
File file = new File("org/foo/Bar.java"); | |||||
Violation violation1 = Violation.create(rule, file); | |||||
index.addViolation(violation1); | |||||
Violation violation2 = Violation.create(rule, file); | |||||
violation2.setSwitchedOff(true); | |||||
index.addViolation(violation2); | |||||
Violation violation3 = Violation.create(rule, file); | |||||
violation3.setSwitchedOff(true); | |||||
index.addViolation(violation3); | |||||
assertThat(index.getViolations(file).size(), is(1)); | |||||
} | |||||
@Test | |||||
public void testGetViolationsWithQuery() { | |||||
File file = new File("org/foo/Bar.java"); | |||||
Violation violation1 = Violation.create(rule, file); | |||||
index.addViolation(violation1); | |||||
Violation violation2 = Violation.create(rule, file); | |||||
violation2.setSwitchedOff(true); | |||||
index.addViolation(violation2); | |||||
Violation violation3 = Violation.create(rule, file); | |||||
violation3.setSwitchedOff(true); | |||||
index.addViolation(violation3); | |||||
assertThat(index.getViolations(ViolationQuery.create().forResource(file).ignoreSwitchedOff(false)).size(), is(3)); | |||||
} | |||||
@Test(expected = IllegalArgumentException.class) | |||||
public void testGetViolationsWithQueryWithNoResource() { | |||||
index.getViolations(ViolationQuery.create()); | |||||
} | |||||
} |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.batch.index; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import org.sonar.api.database.model.RuleFailureModel; | |||||
import org.sonar.api.database.model.Snapshot; | |||||
import org.sonar.api.resources.JavaFile; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.rules.Rule; | |||||
import org.sonar.api.rules.RulePriority; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.core.components.DefaultRuleFinder; | |||||
import org.sonar.jpa.test.AbstractDbUnitTestCase; | |||||
import static org.mockito.Matchers.anyObject; | |||||
import static org.mockito.Matchers.eq; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.when; | |||||
public class ViolationPersisterTest extends AbstractDbUnitTestCase { | |||||
private ViolationPersister violationPersister; | |||||
private Rule rule1 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck", "Check Header"); | |||||
private Rule rule2 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck", "Equals Avoid Null"); | |||||
private JavaFile javaFile = new JavaFile("org.foo.Bar"); | |||||
Project project = new Project("project"); | |||||
@Before | |||||
public void before() { | |||||
setupData("shared"); | |||||
Snapshot snapshot = getSession().getSingleResult(Snapshot.class, "id", 1000); | |||||
ResourcePersister resourcePersister = mock(ResourcePersister.class); | |||||
when(resourcePersister.saveResource((Project) anyObject(), eq(javaFile))).thenReturn(snapshot); | |||||
when(resourcePersister.getSnapshot(javaFile)).thenReturn(snapshot); | |||||
violationPersister = new ViolationPersister(getSession(), resourcePersister, new DefaultRuleFinder(getSessionFactory())); | |||||
} | |||||
@Test | |||||
public void shouldSaveViolations() { | |||||
Violation violation1a = Violation.create(rule1, javaFile) | |||||
.setSeverity(RulePriority.CRITICAL).setLineId(20).setCost(55.6) | |||||
.setMessage("the message"); | |||||
Violation violation1b = Violation.create(rule1, javaFile) | |||||
.setSeverity(RulePriority.CRITICAL).setLineId(50).setCost(80.0); | |||||
Violation violation2 = Violation.create(rule2, javaFile) | |||||
.setSeverity(RulePriority.MINOR); | |||||
violationPersister.saveViolation(project, violation1a); | |||||
violationPersister.saveViolation(project, violation1b); | |||||
violationPersister.saveViolation(project, violation2); | |||||
checkTables("shouldInsertViolations", "rule_failures"); | |||||
} | |||||
@Test | |||||
public void shouldCopyPermanentIdFromPastViolation() { | |||||
RuleFailureModel pastViolation = getSession().getSingleResult(RuleFailureModel.class, "id", 1); | |||||
Violation violation = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); | |||||
violationPersister.saveViolation(project, violation, pastViolation, "line_checksum"); | |||||
checkTables("shouldCopyPermanentIdFromPastViolation", "rule_failures"); | |||||
} | |||||
@Test | |||||
public void shouldCopySwitchedOffFromPastViolation() { | |||||
RuleFailureModel pastViolation1 = getSession().getSingleResult(RuleFailureModel.class, "id", 1); | |||||
Violation violation1 = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); | |||||
violationPersister.saveViolation(project, violation1, pastViolation1, "line_checksum"); | |||||
RuleFailureModel pastViolation2 = getSession().getSingleResult(RuleFailureModel.class, "id", 2); | |||||
Violation violation2 = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); | |||||
violationPersister.saveViolation(project, violation2, pastViolation2, "line_checksum"); | |||||
checkTables("shouldCopySwitchedOffFromPastViolation", "rule_failures"); | |||||
} | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.batch.index; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import org.sonar.api.database.model.RuleFailureModel; | |||||
import org.sonar.api.database.model.Snapshot; | |||||
import org.sonar.api.resources.JavaFile; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.rules.Rule; | |||||
import org.sonar.api.rules.RulePriority; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.core.components.DefaultRuleFinder; | |||||
import org.sonar.jpa.test.AbstractDbUnitTestCase; | |||||
import static org.mockito.Matchers.anyObject; | |||||
import static org.mockito.Matchers.eq; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.when; | |||||
public class ViolationPersisterTest extends AbstractDbUnitTestCase { | |||||
private ViolationPersister violationPersister; | |||||
private Rule rule1 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck", "Check Header"); | |||||
private Rule rule2 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck", "Equals Avoid Null"); | |||||
private JavaFile javaFile = new JavaFile("org.foo.Bar"); | |||||
Project project = new Project("project"); | |||||
@Before | |||||
public void before() { | |||||
setupData("shared"); | |||||
Snapshot snapshot = getSession().getSingleResult(Snapshot.class, "id", 1000); | |||||
ResourcePersister resourcePersister = mock(ResourcePersister.class); | |||||
when(resourcePersister.saveResource((Project) anyObject(), eq(javaFile))).thenReturn(snapshot); | |||||
when(resourcePersister.getSnapshot(javaFile)).thenReturn(snapshot); | |||||
violationPersister = new ViolationPersister(getSession(), resourcePersister, new DefaultRuleFinder(getSessionFactory())); | |||||
} | |||||
@Test | |||||
public void shouldSaveViolations() { | |||||
Violation violation1a = Violation.create(rule1, javaFile) | |||||
.setSeverity(RulePriority.CRITICAL).setLineId(20).setCost(55.6) | |||||
.setMessage("the message"); | |||||
Violation violation1b = Violation.create(rule1, javaFile) | |||||
.setSeverity(RulePriority.CRITICAL).setLineId(50).setCost(80.0); | |||||
Violation violation2 = Violation.create(rule2, javaFile) | |||||
.setSeverity(RulePriority.MINOR); | |||||
violationPersister.saveViolation(project, violation1a); | |||||
violationPersister.saveViolation(project, violation1b); | |||||
violationPersister.saveViolation(project, violation2); | |||||
checkTables("shouldInsertViolations", "rule_failures"); | |||||
} | |||||
@Test | |||||
public void shouldCopyPermanentIdFromPastViolation() { | |||||
RuleFailureModel pastViolation = getSession().getSingleResult(RuleFailureModel.class, "id", 1); | |||||
Violation violation = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); | |||||
violationPersister.saveViolation(project, violation, pastViolation, "line_checksum"); | |||||
checkTables("shouldCopyPermanentIdFromPastViolation", "rule_failures"); | |||||
} | |||||
@Test | |||||
public void shouldCopySwitchedOffFromPastViolation() { | |||||
RuleFailureModel pastViolation1 = getSession().getSingleResult(RuleFailureModel.class, "id", 1); | |||||
Violation violation1 = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); | |||||
violationPersister.saveViolation(project, violation1, pastViolation1, "line_checksum"); | |||||
RuleFailureModel pastViolation2 = getSession().getSingleResult(RuleFailureModel.class, "id", 2); | |||||
Violation violation2 = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message"); | |||||
violationPersister.saveViolation(project, violation2, pastViolation2, "line_checksum"); | |||||
checkTables("shouldCopySwitchedOffFromPastViolation", "rule_failures"); | |||||
} | |||||
} |
<dataset> | |||||
<rules_categories id="1" name="Efficiency" description="[null]"/> | |||||
<rules_categories id="6" name="Usability" description="[null]"/> | |||||
<rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" | |||||
plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" | |||||
plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" | |||||
name="Bar" long_name="org.foo.Bar" description="[null]" | |||||
enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> | |||||
<snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" | |||||
scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" | |||||
status="U" islast="false" depth="3" /> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
</dataset> | |||||
<dataset> | |||||
<rules_categories id="1" name="Efficiency" description="[null]"/> | |||||
<rules_categories id="6" name="Usability" description="[null]"/> | |||||
<rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" | |||||
plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" | |||||
plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" | |||||
name="Bar" long_name="org.foo.Bar" description="[null]" | |||||
enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> | |||||
<snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" | |||||
scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" | |||||
status="U" islast="false" depth="3" /> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
</dataset> |
<dataset> | |||||
<rules_categories id="1" name="Efficiency" description="[null]"/> | |||||
<rules_categories id="6" name="Usability" description="[null]"/> | |||||
<rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" | |||||
plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" | |||||
plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" | |||||
name="Bar" long_name="org.foo.Bar" description="[null]" | |||||
enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> | |||||
<snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" | |||||
scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" | |||||
status="U" islast="false" depth="3" /> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/> | |||||
</dataset> | |||||
<dataset> | |||||
<rules_categories id="1" name="Efficiency" description="[null]"/> | |||||
<rules_categories id="6" name="Usability" description="[null]"/> | |||||
<rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" | |||||
plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" | |||||
plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" | |||||
name="Bar" long_name="org.foo.Bar" description="[null]" | |||||
enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> | |||||
<snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" | |||||
scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" | |||||
status="U" islast="false" depth="3" /> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/> | |||||
</dataset> |
<dataset> | |||||
<rules_categories id="1" name="Efficiency" description="[null]"/> | |||||
<rules_categories id="6" name="Usability" description="[null]"/> | |||||
<rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" | |||||
plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" | |||||
plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" | |||||
name="Bar" long_name="org.foo.Bar" description="[null]" | |||||
enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> | |||||
<snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" | |||||
scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" | |||||
status="U" islast="false" depth="3" /> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/> | |||||
<rule_failures switched_off="true" permanent_id="2" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/> | |||||
</dataset> | |||||
<dataset> | |||||
<rules_categories id="1" name="Efficiency" description="[null]"/> | |||||
<rules_categories id="6" name="Usability" description="[null]"/> | |||||
<rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" | |||||
plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" | |||||
plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" | |||||
name="Bar" long_name="org.foo.Bar" description="[null]" | |||||
enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> | |||||
<snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" | |||||
scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" | |||||
status="U" islast="false" depth="3" /> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/> | |||||
<rule_failures switched_off="true" permanent_id="2" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/> | |||||
</dataset> |
<dataset> | |||||
<rules_categories id="1" name="Efficiency" description="[null]"/> | |||||
<rules_categories id="6" name="Usability" description="[null]"/> | |||||
<rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" | |||||
plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" | |||||
plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" | |||||
name="Bar" long_name="org.foo.Bar" description="[null]" | |||||
enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> | |||||
<snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" | |||||
scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" | |||||
status="U" islast="false" depth="3" /> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="false" permanent_id="3" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="the message" LINE="20" COST="55.6" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="false" permanent_id="4" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="[null]" LINE="50" COST="80" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="false" permanent_id="5" ID="5" SNAPSHOT_ID="1000" RULE_ID="31" FAILURE_LEVEL="1" MESSAGE="[null]" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<dataset> | |||||
<rules_categories id="1" name="Efficiency" description="[null]"/> | |||||
<rules_categories id="6" name="Usability" description="[null]"/> | |||||
<rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" | |||||
plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck" | |||||
plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true" | |||||
cardinality="SINGLE" parent_id="[null]"/> | |||||
<projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]" | |||||
name="Bar" long_name="org.foo.Bar" description="[null]" | |||||
enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/> | |||||
<snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]" | |||||
scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path="" | |||||
status="U" islast="false" depth="3" /> | |||||
<rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="false" permanent_id="3" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="the message" LINE="20" COST="55.6" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="false" permanent_id="4" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="[null]" LINE="50" COST="80" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
<rule_failures switched_off="false" permanent_id="5" ID="5" SNAPSHOT_ID="1000" RULE_ID="31" FAILURE_LEVEL="1" MESSAGE="[null]" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/> | |||||
</dataset> | </dataset> |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.jpa.session; | |||||
import org.apache.commons.lang.StringUtils; | |||||
import org.sonar.api.database.DatabaseSession; | |||||
import java.util.*; | |||||
import javax.persistence.EntityManager; | |||||
import javax.persistence.NonUniqueResultException; | |||||
import javax.persistence.PersistenceException; | |||||
import javax.persistence.Query; | |||||
public class JpaDatabaseSession extends DatabaseSession { | |||||
private final DatabaseConnector connector; | |||||
private EntityManager entityManager = null; | |||||
private int index = 0; | |||||
private boolean inTransaction = false; | |||||
public JpaDatabaseSession(DatabaseConnector connector) { | |||||
this.connector = connector; | |||||
} | |||||
/** | |||||
* Note that usage of this method is discouraged, because it allows to construct and execute queries without additional exception handling, | |||||
* which done in methods of this class. | |||||
*/ | |||||
public EntityManager getEntityManager() { | |||||
return entityManager; | |||||
} | |||||
public void start() { | |||||
entityManager = connector.createEntityManager(); | |||||
index = 0; | |||||
} | |||||
public void stop() { | |||||
commit(); | |||||
if (entityManager != null && entityManager.isOpen()) { | |||||
entityManager.close(); | |||||
entityManager = null; | |||||
} | |||||
} | |||||
public void commit() { | |||||
if (entityManager != null && inTransaction) { | |||||
if (entityManager.isOpen()) { | |||||
if (entityManager.getTransaction().getRollbackOnly()) { | |||||
entityManager.getTransaction().rollback(); | |||||
} else { | |||||
entityManager.getTransaction().commit(); | |||||
} | |||||
entityManager.clear(); | |||||
index = 0; | |||||
} | |||||
inTransaction = false; | |||||
} | |||||
} | |||||
public void rollback() { | |||||
if (entityManager != null && inTransaction) { | |||||
entityManager.getTransaction().rollback(); | |||||
inTransaction = false; | |||||
} | |||||
} | |||||
public <T> T save(T model) { | |||||
startTransaction(); | |||||
internalSave(model, true); | |||||
return model; | |||||
} | |||||
public Object saveWithoutFlush(Object model) { | |||||
startTransaction(); | |||||
internalSave(model, false); | |||||
return model; | |||||
} | |||||
public boolean contains(Object model) { | |||||
startTransaction(); | |||||
return entityManager.contains(model); | |||||
} | |||||
public void save(Object... models) { | |||||
startTransaction(); | |||||
for (Object model : models) { | |||||
save(model); | |||||
} | |||||
} | |||||
private void internalSave(Object model, boolean flushIfNeeded) { | |||||
try { | |||||
entityManager.persist(model); | |||||
} catch (PersistenceException e) { | |||||
/* | |||||
* See http://jira.codehaus.org/browse/SONAR-2234 | |||||
* In some cases Hibernate can throw exceptions without meaningful information about context, so we improve them here. | |||||
*/ | |||||
throw new PersistenceException("Unable to persist : " + model, e); | |||||
} | |||||
if (flushIfNeeded && (++index % BATCH_SIZE == 0)) { | |||||
commit(); | |||||
} | |||||
} | |||||
public Object merge(Object model) { | |||||
startTransaction(); | |||||
return entityManager.merge(model); | |||||
} | |||||
public void remove(Object model) { | |||||
startTransaction(); | |||||
entityManager.remove(model); | |||||
if (++index % BATCH_SIZE == 0) { | |||||
commit(); | |||||
} | |||||
} | |||||
public void removeWithoutFlush(Object model) { | |||||
startTransaction(); | |||||
entityManager.remove(model); | |||||
} | |||||
public <T> T reattach(Class<T> entityClass, Object primaryKey) { | |||||
startTransaction(); | |||||
return entityManager.getReference(entityClass, primaryKey); | |||||
} | |||||
private void startTransaction() { | |||||
if (!inTransaction) { | |||||
entityManager.getTransaction().begin(); | |||||
inTransaction = true; | |||||
} | |||||
} | |||||
/** | |||||
* Note that not recommended to directly execute {@link Query#getSingleResult()}, because it will bypass exception handling, | |||||
* which done in {@link #getSingleResult(Query, Object)}. | |||||
*/ | |||||
public Query createQuery(String hql) { | |||||
startTransaction(); | |||||
return entityManager.createQuery(hql); | |||||
} | |||||
@Override | |||||
public Query createNativeQuery(String sql) { | |||||
startTransaction(); | |||||
return entityManager.createNativeQuery(sql); | |||||
} | |||||
/** | |||||
* @return the result or <code>defaultValue</code>, if not found | |||||
* @throws NonUniqueResultException if more than one result | |||||
*/ | |||||
public <T> T getSingleResult(Query query, T defaultValue) { | |||||
/* | |||||
* See http://jira.codehaus.org/browse/SONAR-2225 | |||||
* By default Hibernate throws NonUniqueResultException without meaningful information about context, | |||||
* so we improve it here by adding all results in error message. | |||||
* Note that in some rare situations we can receive too many results, which may lead to OOME, | |||||
* but actually it will mean that database is corrupted as we don't expect more than one result | |||||
* and in fact org.hibernate.ejb.QueryImpl#getSingleResult() anyway does loading of several results under the hood. | |||||
*/ | |||||
List<T> result = query.getResultList(); | |||||
if (result.size() == 1) { | |||||
return result.get(0); | |||||
} else if (result.isEmpty()) { | |||||
return defaultValue; | |||||
} else { | |||||
Set<T> uniqueResult = new HashSet<T>(result); | |||||
if (uniqueResult.size() > 1) { | |||||
throw new NonUniqueResultException("Expected single result, but got : " + result.toString()); | |||||
} else { | |||||
return uniqueResult.iterator().next(); | |||||
} | |||||
} | |||||
} | |||||
public <T> T getEntity(Class<T> entityClass, Object id) { | |||||
startTransaction(); | |||||
return getEntityManager().find(entityClass, id); | |||||
} | |||||
/** | |||||
* @return the result or <code>null</code>, if not found | |||||
* @throws NonUniqueResultException if more than one result | |||||
*/ | |||||
public <T> T getSingleResult(Class<T> entityClass, Object... criterias) { | |||||
try { | |||||
return getSingleResult(getQueryForCriterias(entityClass, true, criterias), (T) null); | |||||
} catch (NonUniqueResultException ex) { | |||||
NonUniqueResultException e = new NonUniqueResultException("Expected single result for entitiy " + entityClass.getSimpleName() | |||||
+ " with criterias : " + StringUtils.join(criterias, ",")); | |||||
e.initCause(ex); | |||||
throw e; | |||||
} | |||||
} | |||||
public <T> List<T> getResults(Class<T> entityClass, Object... criterias) { | |||||
return getQueryForCriterias(entityClass, true, criterias).getResultList(); | |||||
} | |||||
public <T> List<T> getResults(Class<T> entityClass) { | |||||
return getQueryForCriterias(entityClass, false, null).getResultList(); | |||||
} | |||||
private Query getQueryForCriterias(Class<?> entityClass, boolean raiseError, Object... criterias) { | |||||
if (criterias == null && raiseError) { | |||||
throw new IllegalStateException("criterias parameter must be provided"); | |||||
} | |||||
startTransaction(); | |||||
StringBuilder hql = new StringBuilder("SELECT o FROM ").append(entityClass.getSimpleName()).append(" o"); | |||||
if (criterias != null) { | |||||
hql.append(" WHERE "); | |||||
Map<String, Object> mappedCriterias = new HashMap<String, Object>(); | |||||
for (int i = 0; i < criterias.length; i += 2) { | |||||
mappedCriterias.put((String) criterias[i], criterias[i + 1]); | |||||
} | |||||
buildCriteriasHQL(hql, mappedCriterias); | |||||
Query query = getEntityManager().createQuery(hql.toString()); | |||||
for (Map.Entry<String, Object> entry : mappedCriterias.entrySet()) { | |||||
query.setParameter(entry.getKey(), entry.getValue()); | |||||
} | |||||
return query; | |||||
} | |||||
return getEntityManager().createQuery(hql.toString()); | |||||
} | |||||
private void buildCriteriasHQL(StringBuilder hql, Map<String, Object> mappedCriterias) { | |||||
for (Iterator<String> i = mappedCriterias.keySet().iterator(); i.hasNext();) { | |||||
String criteria = i.next(); | |||||
hql.append("o.").append(criteria).append("=:").append(criteria); | |||||
if (i.hasNext()) { | |||||
hql.append(" AND "); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.jpa.session; | |||||
import org.apache.commons.lang.StringUtils; | |||||
import org.sonar.api.database.DatabaseSession; | |||||
import java.util.*; | |||||
import javax.persistence.EntityManager; | |||||
import javax.persistence.NonUniqueResultException; | |||||
import javax.persistence.PersistenceException; | |||||
import javax.persistence.Query; | |||||
public class JpaDatabaseSession extends DatabaseSession { | |||||
private final DatabaseConnector connector; | |||||
private EntityManager entityManager = null; | |||||
private int index = 0; | |||||
private boolean inTransaction = false; | |||||
public JpaDatabaseSession(DatabaseConnector connector) { | |||||
this.connector = connector; | |||||
} | |||||
/** | |||||
* Note that usage of this method is discouraged, because it allows to construct and execute queries without additional exception handling, | |||||
* which done in methods of this class. | |||||
*/ | |||||
public EntityManager getEntityManager() { | |||||
return entityManager; | |||||
} | |||||
public void start() { | |||||
entityManager = connector.createEntityManager(); | |||||
index = 0; | |||||
} | |||||
public void stop() { | |||||
commit(); | |||||
if (entityManager != null && entityManager.isOpen()) { | |||||
entityManager.close(); | |||||
entityManager = null; | |||||
} | |||||
} | |||||
public void commit() { | |||||
if (entityManager != null && inTransaction) { | |||||
if (entityManager.isOpen()) { | |||||
if (entityManager.getTransaction().getRollbackOnly()) { | |||||
entityManager.getTransaction().rollback(); | |||||
} else { | |||||
entityManager.getTransaction().commit(); | |||||
} | |||||
entityManager.clear(); | |||||
index = 0; | |||||
} | |||||
inTransaction = false; | |||||
} | |||||
} | |||||
public void rollback() { | |||||
if (entityManager != null && inTransaction) { | |||||
entityManager.getTransaction().rollback(); | |||||
inTransaction = false; | |||||
} | |||||
} | |||||
public <T> T save(T model) { | |||||
startTransaction(); | |||||
internalSave(model, true); | |||||
return model; | |||||
} | |||||
public Object saveWithoutFlush(Object model) { | |||||
startTransaction(); | |||||
internalSave(model, false); | |||||
return model; | |||||
} | |||||
public boolean contains(Object model) { | |||||
startTransaction(); | |||||
return entityManager.contains(model); | |||||
} | |||||
public void save(Object... models) { | |||||
startTransaction(); | |||||
for (Object model : models) { | |||||
save(model); | |||||
} | |||||
} | |||||
private void internalSave(Object model, boolean flushIfNeeded) { | |||||
try { | |||||
entityManager.persist(model); | |||||
} catch (PersistenceException e) { | |||||
/* | |||||
* See http://jira.codehaus.org/browse/SONAR-2234 | |||||
* In some cases Hibernate can throw exceptions without meaningful information about context, so we improve them here. | |||||
*/ | |||||
throw new PersistenceException("Unable to persist : " + model, e); | |||||
} | |||||
if (flushIfNeeded && (++index % BATCH_SIZE == 0)) { | |||||
commit(); | |||||
} | |||||
} | |||||
public Object merge(Object model) { | |||||
startTransaction(); | |||||
return entityManager.merge(model); | |||||
} | |||||
public void remove(Object model) { | |||||
startTransaction(); | |||||
entityManager.remove(model); | |||||
if (++index % BATCH_SIZE == 0) { | |||||
commit(); | |||||
} | |||||
} | |||||
public void removeWithoutFlush(Object model) { | |||||
startTransaction(); | |||||
entityManager.remove(model); | |||||
} | |||||
public <T> T reattach(Class<T> entityClass, Object primaryKey) { | |||||
startTransaction(); | |||||
return entityManager.getReference(entityClass, primaryKey); | |||||
} | |||||
private void startTransaction() { | |||||
if (!inTransaction) { | |||||
entityManager.getTransaction().begin(); | |||||
inTransaction = true; | |||||
} | |||||
} | |||||
/** | |||||
* Note that not recommended to directly execute {@link Query#getSingleResult()}, because it will bypass exception handling, | |||||
* which done in {@link #getSingleResult(Query, Object)}. | |||||
*/ | |||||
public Query createQuery(String hql) { | |||||
startTransaction(); | |||||
return entityManager.createQuery(hql); | |||||
} | |||||
@Override | |||||
public Query createNativeQuery(String sql) { | |||||
startTransaction(); | |||||
return entityManager.createNativeQuery(sql); | |||||
} | |||||
/** | |||||
* @return the result or <code>defaultValue</code>, if not found | |||||
* @throws NonUniqueResultException if more than one result | |||||
*/ | |||||
public <T> T getSingleResult(Query query, T defaultValue) { | |||||
/* | |||||
* See http://jira.codehaus.org/browse/SONAR-2225 | |||||
* By default Hibernate throws NonUniqueResultException without meaningful information about context, | |||||
* so we improve it here by adding all results in error message. | |||||
* Note that in some rare situations we can receive too many results, which may lead to OOME, | |||||
* but actually it will mean that database is corrupted as we don't expect more than one result | |||||
* and in fact org.hibernate.ejb.QueryImpl#getSingleResult() anyway does loading of several results under the hood. | |||||
*/ | |||||
List<T> result = query.getResultList(); | |||||
if (result.size() == 1) { | |||||
return result.get(0); | |||||
} else if (result.isEmpty()) { | |||||
return defaultValue; | |||||
} else { | |||||
Set<T> uniqueResult = new HashSet<T>(result); | |||||
if (uniqueResult.size() > 1) { | |||||
throw new NonUniqueResultException("Expected single result, but got : " + result.toString()); | |||||
} else { | |||||
return uniqueResult.iterator().next(); | |||||
} | |||||
} | |||||
} | |||||
public <T> T getEntity(Class<T> entityClass, Object id) { | |||||
startTransaction(); | |||||
return getEntityManager().find(entityClass, id); | |||||
} | |||||
/** | |||||
* @return the result or <code>null</code>, if not found | |||||
* @throws NonUniqueResultException if more than one result | |||||
*/ | |||||
public <T> T getSingleResult(Class<T> entityClass, Object... criterias) { | |||||
try { | |||||
return getSingleResult(getQueryForCriterias(entityClass, true, criterias), (T) null); | |||||
} catch (NonUniqueResultException ex) { | |||||
NonUniqueResultException e = new NonUniqueResultException("Expected single result for entitiy " + entityClass.getSimpleName() | |||||
+ " with criterias : " + StringUtils.join(criterias, ",")); | |||||
e.initCause(ex); | |||||
throw e; | |||||
} | |||||
} | |||||
public <T> List<T> getResults(Class<T> entityClass, Object... criterias) { | |||||
return getQueryForCriterias(entityClass, true, criterias).getResultList(); | |||||
} | |||||
public <T> List<T> getResults(Class<T> entityClass) { | |||||
return getQueryForCriterias(entityClass, false, null).getResultList(); | |||||
} | |||||
private Query getQueryForCriterias(Class<?> entityClass, boolean raiseError, Object... criterias) { | |||||
if (criterias == null && raiseError) { | |||||
throw new IllegalStateException("criterias parameter must be provided"); | |||||
} | |||||
startTransaction(); | |||||
StringBuilder hql = new StringBuilder("SELECT o FROM ").append(entityClass.getSimpleName()).append(" o"); | |||||
if (criterias != null) { | |||||
hql.append(" WHERE "); | |||||
Map<String, Object> mappedCriterias = new HashMap<String, Object>(); | |||||
for (int i = 0; i < criterias.length; i += 2) { | |||||
mappedCriterias.put((String) criterias[i], criterias[i + 1]); | |||||
} | |||||
buildCriteriasHQL(hql, mappedCriterias); | |||||
Query query = getEntityManager().createQuery(hql.toString()); | |||||
for (Map.Entry<String, Object> entry : mappedCriterias.entrySet()) { | |||||
query.setParameter(entry.getKey(), entry.getValue()); | |||||
} | |||||
return query; | |||||
} | |||||
return getEntityManager().createQuery(hql.toString()); | |||||
} | |||||
private void buildCriteriasHQL(StringBuilder hql, Map<String, Object> mappedCriterias) { | |||||
for (Iterator<String> i = mappedCriterias.keySet().iterator(); i.hasNext();) { | |||||
String criteria = i.next(); | |||||
hql.append("o.").append(criteria).append("=:").append(criteria); | |||||
if (i.hasNext()) { | |||||
hql.append(" AND "); | |||||
} | |||||
} | |||||
} | |||||
} |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.api.batch; | |||||
import org.sonar.api.design.Dependency; | |||||
import org.sonar.api.measures.Measure; | |||||
import org.sonar.api.measures.MeasuresFilter; | |||||
import org.sonar.api.measures.Metric; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.api.violations.ViolationQuery; | |||||
import java.util.Collection; | |||||
import java.util.Date; | |||||
import java.util.List; | |||||
import java.util.Set; | |||||
/** | |||||
* @since 1.10 | |||||
*/ | |||||
public interface DecoratorContext { | |||||
/** | |||||
* @return the project in which the decorator is | |||||
*/ | |||||
Project getProject(); | |||||
/** | |||||
* @return the resource that is currently decorated | |||||
*/ | |||||
Resource getResource(); | |||||
/** | |||||
* Child contexts are read only | |||||
*/ | |||||
List<DecoratorContext> getChildren(); | |||||
// MEASURES | |||||
/** | |||||
* Find a measure for the resource | |||||
*/ | |||||
Measure getMeasure(Metric metric); | |||||
/** | |||||
* Never return null. | |||||
*/ | |||||
<M> M getMeasures(MeasuresFilter<M> filter); | |||||
/** | |||||
* Never return null. | |||||
*/ | |||||
Collection<Measure> getChildrenMeasures(MeasuresFilter filter); | |||||
/** | |||||
* @return the resource children measures for the given metric | |||||
*/ | |||||
Collection<Measure> getChildrenMeasures(Metric metric); | |||||
/** | |||||
* Add a measure on the current resource. It can not be executed from children contexts. | |||||
* | |||||
* @return the same context | |||||
*/ | |||||
DecoratorContext saveMeasure(Measure measure); | |||||
/** | |||||
* Add a measure on the current resource. It can not be executed from children contexts. | |||||
* | |||||
* @return the current object | |||||
*/ | |||||
DecoratorContext saveMeasure(Metric metric, Double value); | |||||
// DEPENDENCIES | |||||
Dependency saveDependency(Dependency dependency); | |||||
Set<Dependency> getDependencies(); | |||||
Collection<Dependency> getIncomingDependencies(); | |||||
Collection<Dependency> getOutgoingDependencies(); | |||||
// RULES | |||||
/** | |||||
* Returns the violations that match the {@link ViolationQuery} parameters. | |||||
* | |||||
* @since 2.8 | |||||
* @param violationQuery | |||||
* the request parameters specified as a {@link ViolationQuery} | |||||
* @return the list of violations that match those parameters | |||||
*/ | |||||
public abstract List<Violation> getViolations(ViolationQuery violationQuery); | |||||
/** | |||||
* Returns all the active (= non switched-off) violations found on the current resource. | |||||
* | |||||
* @return the list of violations | |||||
*/ | |||||
List<Violation> getViolations(); | |||||
/** | |||||
* Save a coding rule violation. The decorator which calls this method must be depended upon BatchBarriers.END_OF_VIOLATIONS_GENERATION. | |||||
* | |||||
* @since 2.5 | |||||
* @param force allows to force creation of violation even if it was suppressed by {@link org.sonar.api.rules.ViolationFilter} | |||||
*/ | |||||
DecoratorContext saveViolation(Violation violation, boolean force); | |||||
/** | |||||
* Save a coding rule violation. The decorator which calls this method must be depended upon BatchBarriers.END_OF_VIOLATIONS_GENERATION. | |||||
*/ | |||||
DecoratorContext saveViolation(Violation violation); | |||||
// EVENTS | |||||
/** | |||||
* @return the list of events associated to the current resource | |||||
*/ | |||||
List<Event> getEvents(); | |||||
/** | |||||
* Creates an event for a given date | |||||
* | |||||
* @param name the event name | |||||
* @param description the event description | |||||
* @param category the event category | |||||
* @param date the event date | |||||
* @return the created event | |||||
*/ | |||||
Event createEvent(String name, String description, String category, Date date); | |||||
/** | |||||
* Deletes an event | |||||
* | |||||
* @param event the event to delete | |||||
*/ | |||||
void deleteEvent(Event event); | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.api.batch; | |||||
import org.sonar.api.design.Dependency; | |||||
import org.sonar.api.measures.Measure; | |||||
import org.sonar.api.measures.MeasuresFilter; | |||||
import org.sonar.api.measures.Metric; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.api.violations.ViolationQuery; | |||||
import java.util.Collection; | |||||
import java.util.Date; | |||||
import java.util.List; | |||||
import java.util.Set; | |||||
/** | |||||
* @since 1.10 | |||||
*/ | |||||
public interface DecoratorContext { | |||||
/** | |||||
* @return the project in which the decorator is | |||||
*/ | |||||
Project getProject(); | |||||
/** | |||||
* @return the resource that is currently decorated | |||||
*/ | |||||
Resource getResource(); | |||||
/** | |||||
* Child contexts are read only | |||||
*/ | |||||
List<DecoratorContext> getChildren(); | |||||
// MEASURES | |||||
/** | |||||
* Find a measure for the resource | |||||
*/ | |||||
Measure getMeasure(Metric metric); | |||||
/** | |||||
* Never return null. | |||||
*/ | |||||
<M> M getMeasures(MeasuresFilter<M> filter); | |||||
/** | |||||
* Never return null. | |||||
*/ | |||||
Collection<Measure> getChildrenMeasures(MeasuresFilter filter); | |||||
/** | |||||
* @return the resource children measures for the given metric | |||||
*/ | |||||
Collection<Measure> getChildrenMeasures(Metric metric); | |||||
/** | |||||
* Add a measure on the current resource. It can not be executed from children contexts. | |||||
* | |||||
* @return the same context | |||||
*/ | |||||
DecoratorContext saveMeasure(Measure measure); | |||||
/** | |||||
* Add a measure on the current resource. It can not be executed from children contexts. | |||||
* | |||||
* @return the current object | |||||
*/ | |||||
DecoratorContext saveMeasure(Metric metric, Double value); | |||||
// DEPENDENCIES | |||||
Dependency saveDependency(Dependency dependency); | |||||
Set<Dependency> getDependencies(); | |||||
Collection<Dependency> getIncomingDependencies(); | |||||
Collection<Dependency> getOutgoingDependencies(); | |||||
// RULES | |||||
/** | |||||
* Returns the violations that match the {@link ViolationQuery} parameters. | |||||
* | |||||
* @since 2.8 | |||||
* @param violationQuery | |||||
* the request parameters specified as a {@link ViolationQuery} | |||||
* @return the list of violations that match those parameters | |||||
*/ | |||||
public abstract List<Violation> getViolations(ViolationQuery violationQuery); | |||||
/** | |||||
* Returns all the active (= non switched-off) violations found on the current resource. | |||||
* | |||||
* @return the list of violations | |||||
*/ | |||||
List<Violation> getViolations(); | |||||
/** | |||||
* Save a coding rule violation. The decorator which calls this method must be depended upon BatchBarriers.END_OF_VIOLATIONS_GENERATION. | |||||
* | |||||
* @since 2.5 | |||||
* @param force allows to force creation of violation even if it was suppressed by {@link org.sonar.api.rules.ViolationFilter} | |||||
*/ | |||||
DecoratorContext saveViolation(Violation violation, boolean force); | |||||
/** | |||||
* Save a coding rule violation. The decorator which calls this method must be depended upon BatchBarriers.END_OF_VIOLATIONS_GENERATION. | |||||
*/ | |||||
DecoratorContext saveViolation(Violation violation); | |||||
// EVENTS | |||||
/** | |||||
* @return the list of events associated to the current resource | |||||
*/ | |||||
List<Event> getEvents(); | |||||
/** | |||||
* Creates an event for a given date | |||||
* | |||||
* @param name the event name | |||||
* @param description the event description | |||||
* @param category the event category | |||||
* @param date the event date | |||||
* @return the created event | |||||
*/ | |||||
Event createEvent(String name, String description, String category, Date date); | |||||
/** | |||||
* Deletes an event | |||||
* | |||||
* @param event the event to delete | |||||
*/ | |||||
void deleteEvent(Event event); | |||||
} |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.api.batch; | |||||
import org.sonar.api.design.Dependency; | |||||
import org.sonar.api.measures.Measure; | |||||
import org.sonar.api.measures.MeasuresFilter; | |||||
import org.sonar.api.measures.Metric; | |||||
import org.sonar.api.resources.DuplicatedSourceException; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.ProjectLink; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.api.violations.ViolationQuery; | |||||
import org.sonar.graph.DirectedGraphAccessor; | |||||
import java.util.Collection; | |||||
import java.util.Date; | |||||
import java.util.List; | |||||
import java.util.Set; | |||||
public abstract class SonarIndex implements DirectedGraphAccessor<Resource, Dependency> { | |||||
/** | |||||
* Indexes a resource as a direct child of project. This method does nothing and returns true if the resource already indexed. | |||||
* If the method resource.getParent() does not return null, then this parent will be indexed too. | |||||
* | |||||
* @return false if the resource is excluded | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract boolean index(Resource resource); | |||||
/** | |||||
* Indexes a resource. This method does nothing if the resource is already indexed. | |||||
* | |||||
* @param resource the resource to index. Not nullable | |||||
* @param parentReference a reference to the indexed parent. If null, the resource is indexed as a direct child of project. | |||||
* @return false if the parent is not indexed or if the resource is excluded | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract boolean index(Resource resource, Resource parentReference); | |||||
/** | |||||
* Returns true if the referenced resource is excluded. An excluded resource is not indexed. | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract boolean isExcluded(Resource reference); | |||||
/** | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract boolean isIndexed(Resource reference, boolean acceptExcluded); | |||||
/** | |||||
* Search for an indexed resource. | |||||
* | |||||
* @param reference the resource reference | |||||
* @return the indexed resource, null if it's not indexed | |||||
* @since 1.10. Generic types since 2.6. | |||||
*/ | |||||
public abstract <R extends Resource> R getResource(R reference); | |||||
/** | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract Resource getParent(Resource reference); | |||||
/** | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract Collection<Resource> getChildren(Resource reference); | |||||
/** | |||||
* Save the source code of a file. The file must be have been indexed before. | |||||
* Note: the source stream is not closed. | |||||
* | |||||
* @return false if the resource is excluded or not indexed | |||||
* @throws org.sonar.api.resources.DuplicatedSourceException | |||||
* if the source has already been set on this resource | |||||
*/ | |||||
public abstract void setSource(Resource reference, String source) throws DuplicatedSourceException; | |||||
public abstract Project getProject(); | |||||
public final Collection<Resource> getResources() { | |||||
return getVertices(); | |||||
} | |||||
/** | |||||
* Indexes the resource. | |||||
* @return the indexed resource, even if it's excluded | |||||
* @deprecated since 2.6. Use methods index() | |||||
*/ | |||||
@Deprecated | |||||
public abstract Resource addResource(Resource resource); | |||||
public abstract Measure getMeasure(Resource resource, Metric metric); | |||||
public abstract <M> M getMeasures(Resource resource, MeasuresFilter<M> filter); | |||||
/** | |||||
* Returns the violations that match the {@link ViolationQuery} parameters. | |||||
* | |||||
* @since 2.8 | |||||
* @param violationQuery | |||||
* the request parameters specified as a {@link ViolationQuery} | |||||
* @return the list of violations that match those parameters | |||||
*/ | |||||
public abstract List<Violation> getViolations(ViolationQuery violationQuery); | |||||
/** | |||||
* Returns all the active (= non switched-off) violations found on the given resource. Equivalent to | |||||
* {@link #getViolations(ViolationQuery)} called with <code>ViolationQuery.create().forResource(resource).ignoreSwitchedOff(true)</code> | |||||
* as a parameter. | |||||
* | |||||
* @since 2.7 | |||||
* @param the | |||||
* resource on which violations are searched | |||||
* @return the list of violations | |||||
*/ | |||||
public final List<Violation> getViolations(Resource resource) { | |||||
return getViolations(ViolationQuery.create().forResource(resource).ignoreSwitchedOff(true)); | |||||
} | |||||
/** | |||||
* @since 2.5 | |||||
*/ | |||||
public abstract void addViolation(Violation violation, boolean force); | |||||
public final void addViolation(Violation violation) { | |||||
addViolation(violation, false); | |||||
} | |||||
/** | |||||
* Warning: the resource is automatically indexed for backward-compatibility, but it should be explictly | |||||
* indexed before. Next versions will deactivate this automatic indexation. | |||||
* | |||||
* @throws SonarException if the metric is unknown. | |||||
*/ | |||||
public abstract Measure addMeasure(Resource resource, Measure measure); | |||||
public abstract Dependency addDependency(Dependency dependency); | |||||
public abstract Set<Dependency> getDependencies(); | |||||
public abstract void addLink(ProjectLink link); | |||||
public abstract void deleteLink(String key); | |||||
public abstract List<Event> getEvents(Resource resource); | |||||
public abstract void deleteEvent(Event event); | |||||
public abstract Event addEvent(Resource resource, String name, String description, String category, Date date); | |||||
public final Collection<Dependency> getOutgoingDependencies(Resource from) { | |||||
return getOutgoingEdges(from); | |||||
} | |||||
public final Collection<Dependency> getIncomingDependencies(Resource to) { | |||||
return getIncomingEdges(to); | |||||
} | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.api.batch; | |||||
import org.sonar.api.design.Dependency; | |||||
import org.sonar.api.measures.Measure; | |||||
import org.sonar.api.measures.MeasuresFilter; | |||||
import org.sonar.api.measures.Metric; | |||||
import org.sonar.api.resources.DuplicatedSourceException; | |||||
import org.sonar.api.resources.Project; | |||||
import org.sonar.api.resources.ProjectLink; | |||||
import org.sonar.api.resources.Resource; | |||||
import org.sonar.api.rules.Violation; | |||||
import org.sonar.api.violations.ViolationQuery; | |||||
import org.sonar.graph.DirectedGraphAccessor; | |||||
import java.util.Collection; | |||||
import java.util.Date; | |||||
import java.util.List; | |||||
import java.util.Set; | |||||
public abstract class SonarIndex implements DirectedGraphAccessor<Resource, Dependency> { | |||||
/** | |||||
* Indexes a resource as a direct child of project. This method does nothing and returns true if the resource already indexed. | |||||
* If the method resource.getParent() does not return null, then this parent will be indexed too. | |||||
* | |||||
* @return false if the resource is excluded | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract boolean index(Resource resource); | |||||
/** | |||||
* Indexes a resource. This method does nothing if the resource is already indexed. | |||||
* | |||||
* @param resource the resource to index. Not nullable | |||||
* @param parentReference a reference to the indexed parent. If null, the resource is indexed as a direct child of project. | |||||
* @return false if the parent is not indexed or if the resource is excluded | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract boolean index(Resource resource, Resource parentReference); | |||||
/** | |||||
* Returns true if the referenced resource is excluded. An excluded resource is not indexed. | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract boolean isExcluded(Resource reference); | |||||
/** | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract boolean isIndexed(Resource reference, boolean acceptExcluded); | |||||
/** | |||||
* Search for an indexed resource. | |||||
* | |||||
* @param reference the resource reference | |||||
* @return the indexed resource, null if it's not indexed | |||||
* @since 1.10. Generic types since 2.6. | |||||
*/ | |||||
public abstract <R extends Resource> R getResource(R reference); | |||||
/** | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract Resource getParent(Resource reference); | |||||
/** | |||||
* @since 2.6 | |||||
*/ | |||||
public abstract Collection<Resource> getChildren(Resource reference); | |||||
/** | |||||
* Save the source code of a file. The file must be have been indexed before. | |||||
* Note: the source stream is not closed. | |||||
* | |||||
* @return false if the resource is excluded or not indexed | |||||
* @throws org.sonar.api.resources.DuplicatedSourceException | |||||
* if the source has already been set on this resource | |||||
*/ | |||||
public abstract void setSource(Resource reference, String source) throws DuplicatedSourceException; | |||||
public abstract Project getProject(); | |||||
public final Collection<Resource> getResources() { | |||||
return getVertices(); | |||||
} | |||||
/** | |||||
* Indexes the resource. | |||||
* @return the indexed resource, even if it's excluded | |||||
* @deprecated since 2.6. Use methods index() | |||||
*/ | |||||
@Deprecated | |||||
public abstract Resource addResource(Resource resource); | |||||
public abstract Measure getMeasure(Resource resource, Metric metric); | |||||
public abstract <M> M getMeasures(Resource resource, MeasuresFilter<M> filter); | |||||
/** | |||||
* Returns the violations that match the {@link ViolationQuery} parameters. | |||||
* | |||||
* @since 2.8 | |||||
* @param violationQuery | |||||
* the request parameters specified as a {@link ViolationQuery} | |||||
* @return the list of violations that match those parameters | |||||
*/ | |||||
public abstract List<Violation> getViolations(ViolationQuery violationQuery); | |||||
/** | |||||
* Returns all the active (= non switched-off) violations found on the given resource. Equivalent to | |||||
* {@link #getViolations(ViolationQuery)} called with <code>ViolationQuery.create().forResource(resource).ignoreSwitchedOff(true)</code> | |||||
* as a parameter. | |||||
* | |||||
* @since 2.7 | |||||
* @param the | |||||
* resource on which violations are searched | |||||
* @return the list of violations | |||||
*/ | |||||
public final List<Violation> getViolations(Resource resource) { | |||||
return getViolations(ViolationQuery.create().forResource(resource).ignoreSwitchedOff(true)); | |||||
} | |||||
/** | |||||
* @since 2.5 | |||||
*/ | |||||
public abstract void addViolation(Violation violation, boolean force); | |||||
public final void addViolation(Violation violation) { | |||||
addViolation(violation, false); | |||||
} | |||||
/** | |||||
* Warning: the resource is automatically indexed for backward-compatibility, but it should be explictly | |||||
* indexed before. Next versions will deactivate this automatic indexation. | |||||
* | |||||
* @throws SonarException if the metric is unknown. | |||||
*/ | |||||
public abstract Measure addMeasure(Resource resource, Measure measure); | |||||
public abstract Dependency addDependency(Dependency dependency); | |||||
public abstract Set<Dependency> getDependencies(); | |||||
public abstract void addLink(ProjectLink link); | |||||
public abstract void deleteLink(String key); | |||||
public abstract List<Event> getEvents(Resource resource); | |||||
public abstract void deleteEvent(Event event); | |||||
public abstract Event addEvent(Resource resource, String name, String description, String category, Date date); | |||||
public final Collection<Dependency> getOutgoingDependencies(Resource from) { | |||||
return getOutgoingEdges(from); | |||||
} | |||||
public final Collection<Dependency> getIncomingDependencies(Resource to) { | |||||
return getIncomingEdges(to); | |||||
} | |||||
} |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.api.database; | |||||
import org.sonar.api.BatchComponent; | |||||
import javax.persistence.EntityManager; | |||||
import javax.persistence.Query; | |||||
import java.util.List; | |||||
/** | |||||
* This component should not accessible from plugin API | |||||
* | |||||
* @since 1.10 | |||||
*/ | |||||
public abstract class DatabaseSession implements BatchComponent { | |||||
// IMPORTANT : this value must be the same than the property | |||||
// hibernate.jdbc.batch_size from /META-INF/persistence.xml (module sonar-database) | |||||
public static final int BATCH_SIZE = 30; | |||||
public abstract EntityManager getEntityManager(); | |||||
public abstract void start(); | |||||
public abstract void stop(); | |||||
public abstract void commit(); | |||||
public abstract void rollback(); | |||||
public abstract <T> T save(T entity); | |||||
public abstract Object saveWithoutFlush(Object entity); | |||||
public abstract boolean contains(Object entity); | |||||
public abstract void save(Object... entities); | |||||
public abstract Object merge(Object entity); | |||||
public abstract void remove(Object entity); | |||||
public abstract void removeWithoutFlush(Object entity); | |||||
public abstract <T> T reattach(Class<T> entityClass, Object primaryKey); | |||||
public abstract Query createQuery(String hql); | |||||
public abstract Query createNativeQuery(String sql); | |||||
public abstract <T> T getSingleResult(Query query, T defaultValue); | |||||
public abstract <T> T getEntity(Class<T> entityClass, Object id); | |||||
public abstract <T> T getSingleResult(Class<T> entityClass, Object... criterias); | |||||
public abstract <T> List<T> getResults(Class<T> entityClass, Object... criterias); | |||||
public abstract <T> List<T> getResults(Class<T> entityClass); | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.api.database; | |||||
import org.sonar.api.BatchComponent; | |||||
import javax.persistence.EntityManager; | |||||
import javax.persistence.Query; | |||||
import java.util.List; | |||||
/** | |||||
* This component should not accessible from plugin API | |||||
* | |||||
* @since 1.10 | |||||
*/ | |||||
public abstract class DatabaseSession implements BatchComponent { | |||||
// IMPORTANT : this value must be the same than the property | |||||
// hibernate.jdbc.batch_size from /META-INF/persistence.xml (module sonar-database) | |||||
public static final int BATCH_SIZE = 30; | |||||
public abstract EntityManager getEntityManager(); | |||||
public abstract void start(); | |||||
public abstract void stop(); | |||||
public abstract void commit(); | |||||
public abstract void rollback(); | |||||
public abstract <T> T save(T entity); | |||||
public abstract Object saveWithoutFlush(Object entity); | |||||
public abstract boolean contains(Object entity); | |||||
public abstract void save(Object... entities); | |||||
public abstract Object merge(Object entity); | |||||
public abstract void remove(Object entity); | |||||
public abstract void removeWithoutFlush(Object entity); | |||||
public abstract <T> T reattach(Class<T> entityClass, Object primaryKey); | |||||
public abstract Query createQuery(String hql); | |||||
public abstract Query createNativeQuery(String sql); | |||||
public abstract <T> T getSingleResult(Query query, T defaultValue); | |||||
public abstract <T> T getEntity(Class<T> entityClass, Object id); | |||||
public abstract <T> T getSingleResult(Class<T> entityClass, Object... criterias); | |||||
public abstract <T> List<T> getResults(Class<T> entityClass, Object... criterias); | |||||
public abstract <T> List<T> getResults(Class<T> entityClass); | |||||
} |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.api.rules; | |||||
import org.apache.commons.lang.builder.EqualsBuilder; | |||||
import org.apache.commons.lang.builder.HashCodeBuilder; | |||||
import org.apache.commons.lang.builder.ReflectionToStringBuilder; | |||||
import org.sonar.api.resources.Resource; | |||||
import java.util.Date; | |||||
/** | |||||
* A class that represents a violation. A violation happens when a resource does not respect a defined rule. | |||||
*/ | |||||
public class Violation { | |||||
private Resource resource; | |||||
private Rule rule; | |||||
private String message; | |||||
private RulePriority severity; | |||||
private Integer lineId; | |||||
private Double cost; | |||||
private Date createdAt; | |||||
private boolean switchedOff; | |||||
/** | |||||
* Creates of a violation from a rule. Will need to define the resource later on | |||||
* | |||||
* @deprecated since 2.3. Use the factory method create() | |||||
*/ | |||||
@Deprecated | |||||
public Violation(Rule rule) { | |||||
this.rule = rule; | |||||
} | |||||
/** | |||||
* Creates a fully qualified violation | |||||
* | |||||
* @param rule | |||||
* the rule that has been violated | |||||
* @param resource | |||||
* the resource the violation should be attached to | |||||
* @deprecated since 2.3. Use the factory method create() | |||||
*/ | |||||
@Deprecated | |||||
public Violation(Rule rule, Resource resource) { | |||||
this.resource = resource; | |||||
this.rule = rule; | |||||
} | |||||
public Resource getResource() { | |||||
return resource; | |||||
} | |||||
/** | |||||
* Sets the resource the violation applies to | |||||
* | |||||
* @return the current object | |||||
*/ | |||||
public Violation setResource(Resource resource) { | |||||
this.resource = resource; | |||||
return this; | |||||
} | |||||
public Rule getRule() { | |||||
return rule; | |||||
} | |||||
/** | |||||
* Sets the rule violated | |||||
* | |||||
* @return the current object | |||||
*/ | |||||
public Violation setRule(Rule rule) { | |||||
this.rule = rule; | |||||
return this; | |||||
} | |||||
public String getMessage() { | |||||
return message; | |||||
} | |||||
/** | |||||
* Sets the violation message | |||||
* | |||||
* @return the current object | |||||
*/ | |||||
public Violation setMessage(String message) { | |||||
this.message = message; | |||||
return this; | |||||
} | |||||
/** | |||||
* @see #setLineId(Integer) | |||||
*/ | |||||
public Integer getLineId() { | |||||
return lineId; | |||||
} | |||||
/** | |||||
* Sets the violation line. Note that numbering starts from 1. | |||||
* | |||||
* @return the current object | |||||
*/ | |||||
public Violation setLineId(Integer lineId) { | |||||
this.lineId = lineId; | |||||
return this; | |||||
} | |||||
/** | |||||
* @since 2.5 | |||||
*/ | |||||
public RulePriority getSeverity() { | |||||
return severity; | |||||
} | |||||
/** | |||||
* For internal use only. | |||||
* | |||||
* @since 2.5 | |||||
*/ | |||||
public Violation setSeverity(RulePriority severity) { | |||||
this.severity = severity; | |||||
return this; | |||||
} | |||||
/** | |||||
* @deprecated since 2.5 use {@link #getSeverity()} instead. See http://jira.codehaus.org/browse/SONAR-1829 | |||||
*/ | |||||
@Deprecated | |||||
public RulePriority getPriority() { | |||||
return severity; | |||||
} | |||||
/** | |||||
* For internal use only | |||||
* | |||||
* @deprecated since 2.5 use {@link #setSeverity(RulePriority)} instead. See http://jira.codehaus.org/browse/SONAR-1829 | |||||
*/ | |||||
@Deprecated | |||||
public Violation setPriority(RulePriority priority) { | |||||
this.severity = priority; | |||||
return this; | |||||
} | |||||
/** | |||||
* @see #setCost(Double) | |||||
* @since 2.4 | |||||
*/ | |||||
public Double getCost() { | |||||
return cost; | |||||
} | |||||
/** | |||||
* The cost to fix a violation can't be precisely computed without this information. Let's take the following example : a rule forbids to | |||||
* have methods whose complexity is greater than 10. Without this field "cost", the same violation is created with a method whose | |||||
* complexity is 15 and a method whose complexity is 100. If the cost to fix one point of complexity is 0.05h, then 15mn is necessary to | |||||
* fix the method whose complexity is 15, and 3h5mn is required to fix the method whose complexity is 100. | |||||
* | |||||
* @since 2.4 | |||||
*/ | |||||
public Violation setCost(Double d) { | |||||
this.cost = d; | |||||
return this; | |||||
} | |||||
/** | |||||
* @since 2.5 | |||||
*/ | |||||
public Date getCreatedAt() { | |||||
return createdAt; | |||||
} | |||||
/** | |||||
* For internal use only | |||||
* | |||||
* @since 2.5 | |||||
*/ | |||||
public Violation setCreatedAt(Date createdAt) { | |||||
this.createdAt = createdAt; | |||||
return this; | |||||
} | |||||
/** | |||||
* Switches off the current violation. This is a kind of "mute", which means the violation exists but won't be counted as an active | |||||
* violation (and thus, won't be counted in the total number of violations). | |||||
* | |||||
* @since 2.8 | |||||
* @param switchedOff | |||||
* if true, the violation is considered OFF | |||||
*/ | |||||
public void setSwitchedOff(boolean switchedOff) { | |||||
this.switchedOff = switchedOff; | |||||
} | |||||
/** | |||||
* Tells wether this violation is ON or OFF. | |||||
* | |||||
* @since 2.8 | |||||
* @return true if the violation has been switched off | |||||
*/ | |||||
public boolean isSwitchedOff() { | |||||
return switchedOff; | |||||
} | |||||
@Override | |||||
public boolean equals(Object obj) { | |||||
if ( !(obj instanceof Violation)) { | |||||
return false; | |||||
} | |||||
if (this == obj) { | |||||
return true; | |||||
} | |||||
Violation other = (Violation) obj; | |||||
return new EqualsBuilder().append(rule, other.getRule()).append(resource, other.getResource()).isEquals(); | |||||
} | |||||
@Override | |||||
public int hashCode() { | |||||
return new HashCodeBuilder(17, 37).append(getRule()).append(getResource()).toHashCode(); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return ReflectionToStringBuilder.toString(this); | |||||
} | |||||
public static Violation create(ActiveRule activeRule, Resource resource) { | |||||
return new Violation(activeRule.getRule()).setResource(resource); | |||||
} | |||||
public static Violation create(Rule rule, Resource resource) { | |||||
return new Violation(rule).setResource(resource); | |||||
} | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.api.rules; | |||||
import org.apache.commons.lang.builder.EqualsBuilder; | |||||
import org.apache.commons.lang.builder.HashCodeBuilder; | |||||
import org.apache.commons.lang.builder.ReflectionToStringBuilder; | |||||
import org.sonar.api.resources.Resource; | |||||
import java.util.Date; | |||||
/** | |||||
* A class that represents a violation. A violation happens when a resource does not respect a defined rule. | |||||
*/ | |||||
public class Violation { | |||||
private Resource resource; | |||||
private Rule rule; | |||||
private String message; | |||||
private RulePriority severity; | |||||
private Integer lineId; | |||||
private Double cost; | |||||
private Date createdAt; | |||||
private boolean switchedOff; | |||||
/** | |||||
* Creates of a violation from a rule. Will need to define the resource later on | |||||
* | |||||
* @deprecated since 2.3. Use the factory method create() | |||||
*/ | |||||
@Deprecated | |||||
public Violation(Rule rule) { | |||||
this.rule = rule; | |||||
} | |||||
/** | |||||
* Creates a fully qualified violation | |||||
* | |||||
* @param rule | |||||
* the rule that has been violated | |||||
* @param resource | |||||
* the resource the violation should be attached to | |||||
* @deprecated since 2.3. Use the factory method create() | |||||
*/ | |||||
@Deprecated | |||||
public Violation(Rule rule, Resource resource) { | |||||
this.resource = resource; | |||||
this.rule = rule; | |||||
} | |||||
public Resource getResource() { | |||||
return resource; | |||||
} | |||||
/** | |||||
* Sets the resource the violation applies to | |||||
* | |||||
* @return the current object | |||||
*/ | |||||
public Violation setResource(Resource resource) { | |||||
this.resource = resource; | |||||
return this; | |||||
} | |||||
public Rule getRule() { | |||||
return rule; | |||||
} | |||||
/** | |||||
* Sets the rule violated | |||||
* | |||||
* @return the current object | |||||
*/ | |||||
public Violation setRule(Rule rule) { | |||||
this.rule = rule; | |||||
return this; | |||||
} | |||||
public String getMessage() { | |||||
return message; | |||||
} | |||||
/** | |||||
* Sets the violation message | |||||
* | |||||
* @return the current object | |||||
*/ | |||||
public Violation setMessage(String message) { | |||||
this.message = message; | |||||
return this; | |||||
} | |||||
/** | |||||
* @see #setLineId(Integer) | |||||
*/ | |||||
public Integer getLineId() { | |||||
return lineId; | |||||
} | |||||
/** | |||||
* Sets the violation line. Note that numbering starts from 1. | |||||
* | |||||
* @return the current object | |||||
*/ | |||||
public Violation setLineId(Integer lineId) { | |||||
this.lineId = lineId; | |||||
return this; | |||||
} | |||||
/** | |||||
* @since 2.5 | |||||
*/ | |||||
public RulePriority getSeverity() { | |||||
return severity; | |||||
} | |||||
/** | |||||
* For internal use only. | |||||
* | |||||
* @since 2.5 | |||||
*/ | |||||
public Violation setSeverity(RulePriority severity) { | |||||
this.severity = severity; | |||||
return this; | |||||
} | |||||
/** | |||||
* @deprecated since 2.5 use {@link #getSeverity()} instead. See http://jira.codehaus.org/browse/SONAR-1829 | |||||
*/ | |||||
@Deprecated | |||||
public RulePriority getPriority() { | |||||
return severity; | |||||
} | |||||
/** | |||||
* For internal use only | |||||
* | |||||
* @deprecated since 2.5 use {@link #setSeverity(RulePriority)} instead. See http://jira.codehaus.org/browse/SONAR-1829 | |||||
*/ | |||||
@Deprecated | |||||
public Violation setPriority(RulePriority priority) { | |||||
this.severity = priority; | |||||
return this; | |||||
} | |||||
/** | |||||
* @see #setCost(Double) | |||||
* @since 2.4 | |||||
*/ | |||||
public Double getCost() { | |||||
return cost; | |||||
} | |||||
/** | |||||
* The cost to fix a violation can't be precisely computed without this information. Let's take the following example : a rule forbids to | |||||
* have methods whose complexity is greater than 10. Without this field "cost", the same violation is created with a method whose | |||||
* complexity is 15 and a method whose complexity is 100. If the cost to fix one point of complexity is 0.05h, then 15mn is necessary to | |||||
* fix the method whose complexity is 15, and 3h5mn is required to fix the method whose complexity is 100. | |||||
* | |||||
* @since 2.4 | |||||
*/ | |||||
public Violation setCost(Double d) { | |||||
this.cost = d; | |||||
return this; | |||||
} | |||||
/** | |||||
* @since 2.5 | |||||
*/ | |||||
public Date getCreatedAt() { | |||||
return createdAt; | |||||
} | |||||
/** | |||||
* For internal use only | |||||
* | |||||
* @since 2.5 | |||||
*/ | |||||
public Violation setCreatedAt(Date createdAt) { | |||||
this.createdAt = createdAt; | |||||
return this; | |||||
} | |||||
/** | |||||
* Switches off the current violation. This is a kind of "mute", which means the violation exists but won't be counted as an active | |||||
* violation (and thus, won't be counted in the total number of violations). | |||||
* | |||||
* @since 2.8 | |||||
* @param switchedOff | |||||
* if true, the violation is considered OFF | |||||
*/ | |||||
public void setSwitchedOff(boolean switchedOff) { | |||||
this.switchedOff = switchedOff; | |||||
} | |||||
/** | |||||
* Tells wether this violation is ON or OFF. | |||||
* | |||||
* @since 2.8 | |||||
* @return true if the violation has been switched off | |||||
*/ | |||||
public boolean isSwitchedOff() { | |||||
return switchedOff; | |||||
} | |||||
@Override | |||||
public boolean equals(Object obj) { | |||||
if ( !(obj instanceof Violation)) { | |||||
return false; | |||||
} | |||||
if (this == obj) { | |||||
return true; | |||||
} | |||||
Violation other = (Violation) obj; | |||||
return new EqualsBuilder().append(rule, other.getRule()).append(resource, other.getResource()).isEquals(); | |||||
} | |||||
@Override | |||||
public int hashCode() { | |||||
return new HashCodeBuilder(17, 37).append(getRule()).append(getResource()).toHashCode(); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return ReflectionToStringBuilder.toString(this); | |||||
} | |||||
public static Violation create(ActiveRule activeRule, Resource resource) { | |||||
return new Violation(activeRule.getRule()).setResource(resource); | |||||
} | |||||
public static Violation create(Rule rule, Resource resource) { | |||||
return new Violation(rule).setResource(resource); | |||||
} | |||||
} |
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.api.violations; | |||||
import org.sonar.api.resources.Resource; | |||||
/** | |||||
* Class that allows to query the Sonar index about violations. | |||||
* | |||||
* @since 2.8 | |||||
*/ | |||||
public final class ViolationQuery { | |||||
private boolean ignoreSwitchedOff; | |||||
private Resource resource; | |||||
/** | |||||
* Use the factory method <code>create()</code> | |||||
*/ | |||||
ViolationQuery() { | |||||
} | |||||
/** | |||||
* Creates a new {@link ViolationQuery} object. | |||||
* | |||||
* @return the new query | |||||
*/ | |||||
public static ViolationQuery create() { | |||||
return new ViolationQuery(); | |||||
} | |||||
/** | |||||
* Specifies if the query should returned switched-off violations or not. | |||||
* | |||||
* @param ignore | |||||
* if true, the query will return only active violations. | |||||
* @return the current violation query | |||||
*/ | |||||
public ViolationQuery ignoreSwitchedOff(boolean ignore) { | |||||
this.ignoreSwitchedOff = ignore; | |||||
return this; | |||||
} | |||||
/** | |||||
* Tells if the query should returned switched-off violations or not. | |||||
* | |||||
* @return | |||||
*/ | |||||
public boolean ignoreSwitchedOff() { | |||||
return ignoreSwitchedOff; | |||||
} | |||||
/** | |||||
* Specifies the resource which violations are search from. | |||||
* | |||||
* @param resource | |||||
* the resource | |||||
*/ | |||||
public ViolationQuery forResource(Resource resource) { | |||||
this.resource = resource; | |||||
return this; | |||||
} | |||||
/** | |||||
* Returns the resource which violations are search from. | |||||
* | |||||
* @return the resource | |||||
*/ | |||||
public Resource getResource() { | |||||
return resource; | |||||
} | |||||
} | |||||
/* | |||||
* Sonar, open source software quality management tool. | |||||
* Copyright (C) 2008-2011 SonarSource | |||||
* mailto:contact AT sonarsource DOT com | |||||
* | |||||
* Sonar 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. | |||||
* | |||||
* Sonar 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 Sonar; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
*/ | |||||
package org.sonar.api.violations; | |||||
import org.sonar.api.resources.Resource; | |||||
/** | |||||
* Class that allows to query the Sonar index about violations. | |||||
* | |||||
* @since 2.8 | |||||
*/ | |||||
public final class ViolationQuery { | |||||
private boolean ignoreSwitchedOff; | |||||
private Resource resource; | |||||
/** | |||||
* Use the factory method <code>create()</code> | |||||
*/ | |||||
ViolationQuery() { | |||||
} | |||||
/** | |||||
* Creates a new {@link ViolationQuery} object. | |||||
* | |||||
* @return the new query | |||||
*/ | |||||
public static ViolationQuery create() { | |||||
return new ViolationQuery(); | |||||
} | |||||
/** | |||||
* Specifies if the query should returned switched-off violations or not. | |||||
* | |||||
* @param ignore | |||||
* if true, the query will return only active violations. | |||||
* @return the current violation query | |||||
*/ | |||||
public ViolationQuery ignoreSwitchedOff(boolean ignore) { | |||||
this.ignoreSwitchedOff = ignore; | |||||
return this; | |||||
} | |||||
/** | |||||
* Tells if the query should returned switched-off violations or not. | |||||
* | |||||
* @return | |||||
*/ | |||||
public boolean ignoreSwitchedOff() { | |||||
return ignoreSwitchedOff; | |||||
} | |||||
/** | |||||
* Specifies the resource which violations are search from. | |||||
* | |||||
* @param resource | |||||
* the resource | |||||
*/ | |||||
public ViolationQuery forResource(Resource resource) { | |||||
this.resource = resource; | |||||
return this; | |||||
} | |||||
/** | |||||
* Returns the resource which violations are search from. | |||||
* | |||||
* @return the resource | |||||
*/ | |||||
public Resource getResource() { | |||||
return resource; | |||||
} | |||||
} |
# | |||||
# Sonar, entreprise quality control tool. | |||||
# Copyright (C) 2008-2011 SonarSource | |||||
# mailto:contact AT sonarsource DOT com | |||||
# | |||||
# Sonar 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. | |||||
# | |||||
# Sonar 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 Sonar; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
# | |||||
class ResourceController < ApplicationController | |||||
SECTION=Navigation::SECTION_RESOURCE | |||||
helper DashboardHelper | |||||
def index | |||||
@resource = Project.by_key(params[:id]) | |||||
if (@resource && has_role?(:user, @resource)) | |||||
params[:layout]='false' | |||||
@snapshot=@resource.last_snapshot | |||||
load_extensions() | |||||
if @extension | |||||
if (@extension.getId()=='violations') | |||||
render_violations() | |||||
elsif (@extension.getId()=='coverage') | |||||
render_coverage() | |||||
elsif (@extension.getId()=='source') | |||||
render_source() | |||||
else | |||||
render_extension() | |||||
end | |||||
else | |||||
render_nothing() | |||||
end | |||||
else | |||||
access_denied | |||||
end | |||||
end | |||||
private | |||||
def load_extensions | |||||
@extensions=[] | |||||
java_facade.getResourceTabs(@resource.scope, @resource.qualifier, @resource.language).each do |tab| | |||||
tab.getUserRoles().each do |role| | |||||
if has_role?(role, @resource) | |||||
@extensions<<tab | |||||
break | |||||
end | |||||
end | |||||
end | |||||
if !params[:tab].blank? | |||||
@extension=@extensions.find{|extension| extension.getId()==params[:tab]} | |||||
elsif !params[:metric].blank? | |||||
metric=Metric.by_key(params[:metric]) | |||||
@extension=@extensions.find{|extension| extension.getDefaultTabForMetrics().include?(metric.key)} | |||||
end | |||||
@extension=@extensions.find{|extension| extension.isDefaultTab()} if @extension==nil | |||||
end | |||||
def load_sources | |||||
@period = params[:period].to_i unless params[:period].blank? | |||||
@expanded=(params[:expand]=='true') | |||||
if @snapshot.source | |||||
source_lines=Java::OrgSonarServerUi::JRubyFacade.new.colorizeCode(@snapshot.source.data, @snapshot.project.language).split("\n") | |||||
init_scm() | |||||
@lines=[] | |||||
source_lines.each_with_index do |source, index| | |||||
line=Line.new(source) | |||||
@lines<<line | |||||
line.revision=@revisions_by_line[index+1] | |||||
line.author=@authors_by_line[index+1] | |||||
date_string=@dates_by_line[index+1] | |||||
line.datetime=(date_string ? Java::OrgSonarApiUtils::DateUtils.parseDateTime(date_string): nil) | |||||
end | |||||
end | |||||
end | |||||
def init_scm | |||||
@scm_available=(@snapshot.measure('last_commit_datetimes_by_line')!=nil) | |||||
@authors_by_line=load_distribution('authors_by_line') | |||||
@revisions_by_line=load_distribution('revisions_by_line') | |||||
@dates_by_line=load_distribution('last_commit_datetimes_by_line') | |||||
end | |||||
def load_distribution(metric_key) | |||||
m=@snapshot.measure(metric_key) | |||||
m ? m.data_as_line_distribution() : {} | |||||
end | |||||
def render_coverage | |||||
load_sources() | |||||
@display_coverage=true | |||||
@expandable=(@lines!=nil) | |||||
if @lines | |||||
@hits_by_line=load_distribution('coverage_line_hits_data') | |||||
@conditions_by_line=load_distribution('conditions_by_line') | |||||
@covered_conditions_by_line=load_distribution('covered_conditions_by_line') | |||||
@hits_by_line.each_pair do |line_id,hits| | |||||
line=@lines[line_id-1] | |||||
if line | |||||
line.hits=hits.to_i | |||||
line.conditions=@conditions_by_line[line_id].to_i | |||||
line.covered_conditions=@covered_conditions_by_line[line_id].to_i | |||||
end | |||||
end | |||||
if @snapshot.measure('conditions_by_line').nil? | |||||
# TODO remove this code when branch_coverage_hits_data is fully removed from CoreMetrics | |||||
deprecated_branches_by_line=load_distribution('branch_coverage_hits_data') | |||||
deprecated_branches_by_line.each_pair do |line_id,label| | |||||
line=@lines[line_id-1] | |||||
if line | |||||
line.deprecated_conditions_label=label | |||||
end | |||||
end | |||||
end | |||||
to=(@period ? Java::JavaUtil::Date.new(@snapshot.period_datetime(@period).to_f * 1000) : nil) | |||||
metric=Metric.by_key(params[:coverage_filter]||params[:metric]) | |||||
@coverage_filter=(metric ? metric.key : 'coverage') | |||||
@filtered=true | |||||
if ('lines_to_cover'==@coverage_filter || 'coverage'==@coverage_filter || 'line_coverage'==@coverage_filter || | |||||
'new_lines_to_cover'==@coverage_filter || 'new_coverage'==@coverage_filter || 'new_line_coverage'==@coverage_filter) | |||||
@coverage_filter='lines_to_cover' | |||||
filter_lines{|line| line.hits && line.after(to)} | |||||
elsif 'uncovered_lines'==@coverage_filter || 'new_uncovered_lines'==@coverage_filter | |||||
@coverage_filter='uncovered_lines' | |||||
filter_lines{|line| line.hits && line.hits==0 && line.after(to)} | |||||
elsif 'conditions_to_cover'==@coverage_filter || 'branch_coverage'==@coverage_filter || | |||||
'new_conditions_to_cover'==@coverage_filter || 'new_branch_coverage'==@coverage_filter | |||||
@coverage_filter='conditions_to_cover' | |||||
filter_lines{|line| line.conditions && line.conditions>0 && line.after(to)} | |||||
elsif 'uncovered_conditions'==@coverage_filter || 'new_uncovered_conditions'==@coverage_filter | |||||
@coverage_filter='uncovered_conditions' | |||||
filter_lines{|line| line.conditions && line.covered_conditions && line.covered_conditions<line.conditions && line.after(to)} | |||||
end | |||||
end | |||||
render :action => 'index', :layout => !request.xhr? | |||||
end | |||||
def render_violations | |||||
load_sources() | |||||
@display_violations=true | |||||
@global_violations=[] | |||||
@expandable=(@lines!=nil) | |||||
@filtered=!@expanded | |||||
conditions='switched_off is not true AND snapshot_id=?' | |||||
values=[@snapshot.id] | |||||
unless params[:rule].blank? | |||||
severity=Sonar::RulePriority.id(params[:rule]) | |||||
if severity | |||||
conditions += ' AND failure_level=?' | |||||
values<<severity | |||||
else | |||||
rule=Rule.by_key_or_id(params[:rule]) | |||||
conditions += ' AND rule_id=?' | |||||
values<<(rule ? rule.id : -1) | |||||
end | |||||
end | |||||
if @period | |||||
date=@snapshot.period_datetime(@period) | |||||
if date | |||||
conditions+=' AND created_at>?' | |||||
values<<date.advance(:minutes => 1) | |||||
else | |||||
conditions+=' AND id=-1' | |||||
end | |||||
end | |||||
RuleFailure.find(:all, :include => ['rule', 'reviews' ], :conditions => [conditions] + values, :order => 'failure_level DESC').each do |violation| | |||||
# sorted by severity => from blocker to info | |||||
if violation.line && violation.line>0 && @lines | |||||
@lines[violation.line-1].add_violation(violation) | |||||
else | |||||
@global_violations<<violation | |||||
end | |||||
# if the permanent_id does not exist, set it to the current id | |||||
unless violation.permanent_id | |||||
violation.permanent_id = violation.id | |||||
violation.save | |||||
end | |||||
end | |||||
if !@expanded && @lines | |||||
filter_lines{|line| line.violations?} | |||||
end | |||||
render :action => 'index', :layout => !request.xhr? | |||||
end | |||||
def render_source | |||||
load_sources() | |||||
filter_lines_by_date() | |||||
render :action => 'index', :layout => !request.xhr? | |||||
end | |||||
def filter_lines_by_date | |||||
if @period | |||||
@filtered=true | |||||
to=Java::JavaUtil::Date.new(@snapshot.period_datetime(@period).to_f * 1000) | |||||
if to | |||||
@lines.each do |line| | |||||
line.flag_as_hidden() if !line.after(to) | |||||
end | |||||
end | |||||
end | |||||
end | |||||
def filter_lines(&block) | |||||
@lines.each_with_index do |line,index| | |||||
if yield(line) | |||||
for i in index-4...index | |||||
@lines[i].flag_as_highlight_context() if i>=0 | |||||
end | |||||
line.flag_as_highlighted() | |||||
for i in index+1..index+4 | |||||
@lines[i].flag_as_highlight_context() if i<@lines.size | |||||
end | |||||
else | |||||
line.flag_as_hidden() | |||||
end | |||||
end | |||||
end | |||||
class Line | |||||
attr_accessor :source, :revision, :author, :datetime, :violations, :hits, :conditions, :covered_conditions, :hidden, :highlighted, :deprecated_conditions_label | |||||
def initialize(source) | |||||
@source=source | |||||
end | |||||
def add_violation(violation) | |||||
@violations||=[] | |||||
@violations<<violation | |||||
@visible=true | |||||
end | |||||
def violations? | |||||
@violations && @violations.size>0 | |||||
end | |||||
def violation_severity | |||||
if @violations && @violations.size>0 | |||||
@violations[0].failure_level | |||||
else | |||||
nil | |||||
end | |||||
end | |||||
def after(date) | |||||
if date && @datetime | |||||
@datetime.after(date) | |||||
else | |||||
true | |||||
end | |||||
end | |||||
def flag_as_highlighted | |||||
@highlighted=true | |||||
@hidden=false | |||||
end | |||||
def flag_as_highlight_context | |||||
# do not force if highlighted has already been set to true | |||||
@highlighted=false if @highlighted.nil? | |||||
@hidden=false | |||||
end | |||||
def flag_as_hidden | |||||
# do not force if it has already been flagged as visible | |||||
if @hidden.nil? | |||||
@hidden=true | |||||
@highlighted=false | |||||
end | |||||
end | |||||
def hidden? | |||||
@hidden==true | |||||
end | |||||
def highlighted? | |||||
# highlighted if the @highlighted has not been set or has been set to true | |||||
!hidden? && @highlighted!=false | |||||
end | |||||
def deprecated_conditions_label=(label) | |||||
if label | |||||
@deprecated_conditions_label=label | |||||
if label=='0%' | |||||
@conditions=2 | |||||
@covered_conditions=0 | |||||
elsif label=='100%' | |||||
@conditions=2 | |||||
@covered_conditions=2 | |||||
else | |||||
@conditions=2 | |||||
@covered_conditions=1 | |||||
end | |||||
end | |||||
end | |||||
end | |||||
def render_extension() | |||||
render :action => 'extension', :layout => !request.xhr? | |||||
end | |||||
def render_nothing() | |||||
render :action => 'nothing', :layout => !request.xhr? | |||||
# | |||||
# Sonar, entreprise quality control tool. | |||||
# Copyright (C) 2008-2011 SonarSource | |||||
# mailto:contact AT sonarsource DOT com | |||||
# | |||||
# Sonar 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. | |||||
# | |||||
# Sonar 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 Sonar; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
# | |||||
class ResourceController < ApplicationController | |||||
SECTION=Navigation::SECTION_RESOURCE | |||||
helper DashboardHelper | |||||
def index | |||||
@resource = Project.by_key(params[:id]) | |||||
if (@resource && has_role?(:user, @resource)) | |||||
params[:layout]='false' | |||||
@snapshot=@resource.last_snapshot | |||||
load_extensions() | |||||
if @extension | |||||
if (@extension.getId()=='violations') | |||||
render_violations() | |||||
elsif (@extension.getId()=='coverage') | |||||
render_coverage() | |||||
elsif (@extension.getId()=='source') | |||||
render_source() | |||||
else | |||||
render_extension() | |||||
end | |||||
else | |||||
render_nothing() | |||||
end | |||||
else | |||||
access_denied | |||||
end | |||||
end | |||||
private | |||||
def load_extensions | |||||
@extensions=[] | |||||
java_facade.getResourceTabs(@resource.scope, @resource.qualifier, @resource.language).each do |tab| | |||||
tab.getUserRoles().each do |role| | |||||
if has_role?(role, @resource) | |||||
@extensions<<tab | |||||
break | |||||
end | |||||
end | |||||
end | |||||
if !params[:tab].blank? | |||||
@extension=@extensions.find{|extension| extension.getId()==params[:tab]} | |||||
elsif !params[:metric].blank? | |||||
metric=Metric.by_key(params[:metric]) | |||||
@extension=@extensions.find{|extension| extension.getDefaultTabForMetrics().include?(metric.key)} | |||||
end | |||||
@extension=@extensions.find{|extension| extension.isDefaultTab()} if @extension==nil | |||||
end | |||||
def load_sources | |||||
@period = params[:period].to_i unless params[:period].blank? | |||||
@expanded=(params[:expand]=='true') | |||||
if @snapshot.source | |||||
source_lines=Java::OrgSonarServerUi::JRubyFacade.new.colorizeCode(@snapshot.source.data, @snapshot.project.language).split("\n") | |||||
init_scm() | |||||
@lines=[] | |||||
source_lines.each_with_index do |source, index| | |||||
line=Line.new(source) | |||||
@lines<<line | |||||
line.revision=@revisions_by_line[index+1] | |||||
line.author=@authors_by_line[index+1] | |||||
date_string=@dates_by_line[index+1] | |||||
line.datetime=(date_string ? Java::OrgSonarApiUtils::DateUtils.parseDateTime(date_string): nil) | |||||
end | |||||
end | |||||
end | |||||
def init_scm | |||||
@scm_available=(@snapshot.measure('last_commit_datetimes_by_line')!=nil) | |||||
@authors_by_line=load_distribution('authors_by_line') | |||||
@revisions_by_line=load_distribution('revisions_by_line') | |||||
@dates_by_line=load_distribution('last_commit_datetimes_by_line') | |||||
end | |||||
def load_distribution(metric_key) | |||||
m=@snapshot.measure(metric_key) | |||||
m ? m.data_as_line_distribution() : {} | |||||
end | |||||
def render_coverage | |||||
load_sources() | |||||
@display_coverage=true | |||||
@expandable=(@lines!=nil) | |||||
if @lines | |||||
@hits_by_line=load_distribution('coverage_line_hits_data') | |||||
@conditions_by_line=load_distribution('conditions_by_line') | |||||
@covered_conditions_by_line=load_distribution('covered_conditions_by_line') | |||||
@hits_by_line.each_pair do |line_id,hits| | |||||
line=@lines[line_id-1] | |||||
if line | |||||
line.hits=hits.to_i | |||||
line.conditions=@conditions_by_line[line_id].to_i | |||||
line.covered_conditions=@covered_conditions_by_line[line_id].to_i | |||||
end | |||||
end | |||||
if @snapshot.measure('conditions_by_line').nil? | |||||
# TODO remove this code when branch_coverage_hits_data is fully removed from CoreMetrics | |||||
deprecated_branches_by_line=load_distribution('branch_coverage_hits_data') | |||||
deprecated_branches_by_line.each_pair do |line_id,label| | |||||
line=@lines[line_id-1] | |||||
if line | |||||
line.deprecated_conditions_label=label | |||||
end | |||||
end | |||||
end | |||||
to=(@period ? Java::JavaUtil::Date.new(@snapshot.period_datetime(@period).to_f * 1000) : nil) | |||||
metric=Metric.by_key(params[:coverage_filter]||params[:metric]) | |||||
@coverage_filter=(metric ? metric.key : 'coverage') | |||||
@filtered=true | |||||
if ('lines_to_cover'==@coverage_filter || 'coverage'==@coverage_filter || 'line_coverage'==@coverage_filter || | |||||
'new_lines_to_cover'==@coverage_filter || 'new_coverage'==@coverage_filter || 'new_line_coverage'==@coverage_filter) | |||||
@coverage_filter='lines_to_cover' | |||||
filter_lines{|line| line.hits && line.after(to)} | |||||
elsif 'uncovered_lines'==@coverage_filter || 'new_uncovered_lines'==@coverage_filter | |||||
@coverage_filter='uncovered_lines' | |||||
filter_lines{|line| line.hits && line.hits==0 && line.after(to)} | |||||
elsif 'conditions_to_cover'==@coverage_filter || 'branch_coverage'==@coverage_filter || | |||||
'new_conditions_to_cover'==@coverage_filter || 'new_branch_coverage'==@coverage_filter | |||||
@coverage_filter='conditions_to_cover' | |||||
filter_lines{|line| line.conditions && line.conditions>0 && line.after(to)} | |||||
elsif 'uncovered_conditions'==@coverage_filter || 'new_uncovered_conditions'==@coverage_filter | |||||
@coverage_filter='uncovered_conditions' | |||||
filter_lines{|line| line.conditions && line.covered_conditions && line.covered_conditions<line.conditions && line.after(to)} | |||||
end | |||||
end | |||||
render :action => 'index', :layout => !request.xhr? | |||||
end | |||||
def render_violations | |||||
load_sources() | |||||
@display_violations=true | |||||
@global_violations=[] | |||||
@expandable=(@lines!=nil) | |||||
@filtered=!@expanded | |||||
conditions='switched_off is not true AND snapshot_id=?' | |||||
values=[@snapshot.id] | |||||
unless params[:rule].blank? | |||||
severity=Sonar::RulePriority.id(params[:rule]) | |||||
if severity | |||||
conditions += ' AND failure_level=?' | |||||
values<<severity | |||||
else | |||||
rule=Rule.by_key_or_id(params[:rule]) | |||||
conditions += ' AND rule_id=?' | |||||
values<<(rule ? rule.id : -1) | |||||
end | |||||
end | |||||
if @period | |||||
date=@snapshot.period_datetime(@period) | |||||
if date | |||||
conditions+=' AND created_at>?' | |||||
values<<date.advance(:minutes => 1) | |||||
else | |||||
conditions+=' AND id=-1' | |||||
end | |||||
end | |||||
RuleFailure.find(:all, :include => ['rule', 'reviews' ], :conditions => [conditions] + values, :order => 'failure_level DESC').each do |violation| | |||||
# sorted by severity => from blocker to info | |||||
if violation.line && violation.line>0 && @lines | |||||
@lines[violation.line-1].add_violation(violation) | |||||
else | |||||
@global_violations<<violation | |||||
end | |||||
# if the permanent_id does not exist, set it to the current id | |||||
unless violation.permanent_id | |||||
violation.permanent_id = violation.id | |||||
violation.save | |||||
end | |||||
end | |||||
if !@expanded && @lines | |||||
filter_lines{|line| line.violations?} | |||||
end | |||||
render :action => 'index', :layout => !request.xhr? | |||||
end | |||||
def render_source | |||||
load_sources() | |||||
filter_lines_by_date() | |||||
render :action => 'index', :layout => !request.xhr? | |||||
end | |||||
def filter_lines_by_date | |||||
if @period | |||||
@filtered=true | |||||
to=Java::JavaUtil::Date.new(@snapshot.period_datetime(@period).to_f * 1000) | |||||
if to | |||||
@lines.each do |line| | |||||
line.flag_as_hidden() if !line.after(to) | |||||
end | |||||
end | |||||
end | |||||
end | |||||
def filter_lines(&block) | |||||
@lines.each_with_index do |line,index| | |||||
if yield(line) | |||||
for i in index-4...index | |||||
@lines[i].flag_as_highlight_context() if i>=0 | |||||
end | |||||
line.flag_as_highlighted() | |||||
for i in index+1..index+4 | |||||
@lines[i].flag_as_highlight_context() if i<@lines.size | |||||
end | |||||
else | |||||
line.flag_as_hidden() | |||||
end | |||||
end | |||||
end | |||||
class Line | |||||
attr_accessor :source, :revision, :author, :datetime, :violations, :hits, :conditions, :covered_conditions, :hidden, :highlighted, :deprecated_conditions_label | |||||
def initialize(source) | |||||
@source=source | |||||
end | |||||
def add_violation(violation) | |||||
@violations||=[] | |||||
@violations<<violation | |||||
@visible=true | |||||
end | |||||
def violations? | |||||
@violations && @violations.size>0 | |||||
end | |||||
def violation_severity | |||||
if @violations && @violations.size>0 | |||||
@violations[0].failure_level | |||||
else | |||||
nil | |||||
end | |||||
end | |||||
def after(date) | |||||
if date && @datetime | |||||
@datetime.after(date) | |||||
else | |||||
true | |||||
end | |||||
end | |||||
def flag_as_highlighted | |||||
@highlighted=true | |||||
@hidden=false | |||||
end | |||||
def flag_as_highlight_context | |||||
# do not force if highlighted has already been set to true | |||||
@highlighted=false if @highlighted.nil? | |||||
@hidden=false | |||||
end | |||||
def flag_as_hidden | |||||
# do not force if it has already been flagged as visible | |||||
if @hidden.nil? | |||||
@hidden=true | |||||
@highlighted=false | |||||
end | |||||
end | |||||
def hidden? | |||||
@hidden==true | |||||
end | |||||
def highlighted? | |||||
# highlighted if the @highlighted has not been set or has been set to true | |||||
!hidden? && @highlighted!=false | |||||
end | |||||
def deprecated_conditions_label=(label) | |||||
if label | |||||
@deprecated_conditions_label=label | |||||
if label=='0%' | |||||
@conditions=2 | |||||
@covered_conditions=0 | |||||
elsif label=='100%' | |||||
@conditions=2 | |||||
@covered_conditions=2 | |||||
else | |||||
@conditions=2 | |||||
@covered_conditions=1 | |||||
end | |||||
end | |||||
end | |||||
end | |||||
def render_extension() | |||||
render :action => 'extension', :layout => !request.xhr? | |||||
end | |||||
def render_nothing() | |||||
render :action => 'nothing', :layout => !request.xhr? | |||||
end | end | ||||
end | end |
# | |||||
# Sonar, entreprise quality control tool. | |||||
# Copyright (C) 2008-2011 SonarSource | |||||
# mailto:contact AT sonarsource DOT com | |||||
# | |||||
# Sonar 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. | |||||
# | |||||
# Sonar 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 Sonar; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
# | |||||
class ReviewsController < ApplicationController | |||||
SECTION=Navigation::SECTION_HOME | |||||
verify :method => :post, :only => [ :create, :create_comment ], :redirect_to => { :action => :error_not_post } | |||||
def index | |||||
init_params | |||||
@reviews = [] | |||||
unless params.blank? | |||||
find_reviews_for_user_query | |||||
end | |||||
end | |||||
def list | |||||
reviews = find_reviews_for_rule_failure params[:rule_failure_permanent_id] | |||||
render :partial => "list", :locals => { :reviews => reviews } | |||||
end | |||||
def display_violation | |||||
violation = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id] | |||||
render :partial => "resource/violation", :locals => { :violation => violation } | |||||
end | |||||
def form | |||||
rule_failure = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id] | |||||
@review = Review.new | |||||
@review.rule_failure_permanent_id = rule_failure.permanent_id | |||||
@review_comment = ReviewComment.new | |||||
@review_comment.review_text = "" | |||||
if params[:switch_off] | |||||
@review.review_type = "f-positive" | |||||
else | |||||
@review.review_type = Review.default_type | |||||
end | |||||
render :partial => "form" | |||||
end | |||||
def create | |||||
rule_failure = find_last_rule_failure_with_permanent_id params[:review][:rule_failure_permanent_id] | |||||
unless has_rights_to_create? rule_failure | |||||
render :text => "<b>Cannot create the review</b> : access denied." | |||||
return | |||||
end | |||||
@review = Review.new(params[:review]) | |||||
@review.user = current_user | |||||
if params[:assign_to_me] | |||||
@review.assignee = current_user | |||||
end | |||||
@review.title = rule_failure.message | |||||
@review.status = Review.default_status | |||||
@review.severity = Sonar::RulePriority.to_s rule_failure.failure_level | |||||
@review.resource = RuleFailure.find( @review.rule_failure_permanent_id, :include => ['snapshot'] ).snapshot.project | |||||
@review_comment = ReviewComment.new(params[:review_comment]) | |||||
@review_comment.user = current_user | |||||
@review.review_comments << @review_comment | |||||
if @review.valid? | |||||
if @review.review_type == "f-positive" | |||||
if rule_failure.get_open_review | |||||
current_open_review = rule_failure.get_open_review | |||||
current_open_review.status = "closed" | |||||
current_open_review.save | |||||
end | |||||
rule_failure.switched_off = true | |||||
rule_failure.save | |||||
end | |||||
@review.save | |||||
@violation = rule_failure | |||||
end | |||||
render "create_result" | |||||
end | |||||
def form_comment | |||||
@review_comment = ReviewComment.new | |||||
@review_comment.user = current_user | |||||
@review_comment.review_id = params[:review_id] | |||||
@review_comment.review_text = "" | |||||
@rule_failure_permanent_id = params[:rule_failure_permanent_id] | |||||
if params[:update_comment] | |||||
@update_comment = true | |||||
@review_comment.review_text = params[:review_text] | |||||
end | |||||
render :partial => "form_comment" | |||||
end | |||||
def create_comment | |||||
rule_failure = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id] | |||||
unless has_rights_to_create? rule_failure | |||||
render :text => "<b>Cannot create the comment</b> : access denied." | |||||
return | |||||
end | |||||
@review_comment = ReviewComment.new(params[:review_comment]) | |||||
@review_comment.user = current_user | |||||
@rule_failure_permanent_id = params[:rule_failure_permanent_id] | |||||
if @review_comment.valid? | |||||
@review_comment.save | |||||
# -- TODO : should create a Review#create_comment and put the following logic in it | |||||
review = @review_comment.review | |||||
review.updated_at = @review_comment.created_at | |||||
review.save | |||||
# -- End of TODO code -- | |||||
@violation = rule_failure | |||||
end | |||||
render "create_comment_result" | |||||
end | |||||
def update_comment | |||||
review = Review.find params[:review_comment][:review_id] | |||||
@review_comment = review.review_comments.last | |||||
unless current_user && current_user.id == @review_comment.user_id | |||||
render :text => "<b>Cannot modify the comment</b> : access denied." | |||||
return | |||||
end | |||||
@review_comment.review_text = params[:review_comment][:review_text] | |||||
@review_comment.created_at = DateTime.now | |||||
@rule_failure_permanent_id = params[:rule_failure_permanent_id] | |||||
if @review_comment.valid? | |||||
@review_comment.save | |||||
review.updated_at = @review_comment.updated_at | |||||
review.save | |||||
@violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id | |||||
end | |||||
render "create_comment_result" | |||||
end | |||||
def form_assign | |||||
@user_options = add_all_users [] | |||||
@review_id = params[:review_id] | |||||
@rule_failure_permanent_id = params[:rule_failure_permanent_id] | |||||
render :partial => "form_assign" | |||||
end | |||||
def assign | |||||
review = Review.find params[:review_id] | |||||
unless current_user | |||||
render :text => "<b>Cannot edit the review</b> : access denied." | |||||
return | |||||
end | |||||
review.assignee = User.find params[:assignee_id] | |||||
review.save | |||||
violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id | |||||
render :partial => "resource/violation", :locals => { :violation => violation } | |||||
end | |||||
def close_review | |||||
review = Review.find params[:review_id] | |||||
unless current_user | |||||
render :text => "<b>Cannot edit the review</b> : access denied." | |||||
return | |||||
end | |||||
review.status = "closed" | |||||
review.save | |||||
violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id | |||||
render :partial => "resource/violation", :locals => { :violation => violation } | |||||
end | |||||
## -------------- PRIVATE -------------- ## | |||||
private | |||||
def init_params | |||||
@user_names = [["Any", ""]] | |||||
default_user = [""] | |||||
if current_user | |||||
default_user = [current_user.id] | |||||
end | |||||
add_all_users @user_names | |||||
@review_authors = filter_any(params[:review_authors]) || default_user | |||||
@comment_authors = filter_any(params[:comment_authors]) || default_user | |||||
@severities = filter_any(params[:severities]) || [""] | |||||
@statuses = filter_any(params[:statuses]) || ["open"] | |||||
end | |||||
def add_all_users ( user_options ) | |||||
User.find( :all ).each do |user| | |||||
userName = user.name | |||||
if current_user.id == user.id | |||||
userName = "Me (" + user.name + ")" | |||||
end | |||||
user_options << [userName, user.id.to_s] | |||||
end | |||||
return user_options | |||||
end | |||||
def filter_any(array) | |||||
if array && array.size>1 && array.include?("") | |||||
array=[""] | |||||
end | |||||
array | |||||
end | |||||
def find_reviews_for_user_query | |||||
conditions=[] | |||||
values={} | |||||
unless @statuses == [""] | |||||
conditions << "reviews.status in (:statuses)" | |||||
values[:statuses]=@statuses | |||||
end | |||||
unless @severities == [""] | |||||
conditions << "reviews.severity in (:severities)" | |||||
values[:severities]=@severities | |||||
end | |||||
unless @review_authors == [""] | |||||
conditions << "reviews.user_id in (:review_authors)" | |||||
values[:review_authors]=@review_authors | |||||
end | |||||
unless @comment_authors == [""] | |||||
conditions << "review_comments.user_id in (:comment_authors)" | |||||
values[:comment_authors]=@comment_authors | |||||
end | |||||
@reviews = Review.find( :all, :order => "created_at DESC", :joins => :review_comments, :conditions => [ conditions.join(" AND "), values] ).uniq | |||||
end | |||||
def find_reviews_for_rule_failure ( rule_failure_permanent_id ) | |||||
return Review.find :all, :conditions => ['rule_failure_permanent_id=?', rule_failure_permanent_id] | |||||
end | |||||
def find_last_rule_failure_with_permanent_id ( rule_failure_permanent_id ) | |||||
return RuleFailure.last( :all, :conditions => [ "permanent_id = ?", rule_failure_permanent_id ], :include => ['snapshot'] ) | |||||
end | |||||
def has_rights_to_create? ( rule_failure ) | |||||
return false unless current_user | |||||
project = rule_failure.snapshot.root_project | |||||
unless has_role?(:user, project) | |||||
return false | |||||
end | |||||
return true | |||||
end | |||||
def error_not_post | |||||
render :text => "Create actions must use POST method." | |||||
end | |||||
end | |||||
# | |||||
# Sonar, entreprise quality control tool. | |||||
# Copyright (C) 2008-2011 SonarSource | |||||
# mailto:contact AT sonarsource DOT com | |||||
# | |||||
# Sonar 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. | |||||
# | |||||
# Sonar 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 Sonar; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
# | |||||
class ReviewsController < ApplicationController | |||||
SECTION=Navigation::SECTION_HOME | |||||
verify :method => :post, :only => [ :create, :create_comment ], :redirect_to => { :action => :error_not_post } | |||||
def index | |||||
init_params | |||||
@reviews = [] | |||||
unless params.blank? | |||||
find_reviews_for_user_query | |||||
end | |||||
end | |||||
def list | |||||
reviews = find_reviews_for_rule_failure params[:rule_failure_permanent_id] | |||||
render :partial => "list", :locals => { :reviews => reviews } | |||||
end | |||||
def display_violation | |||||
violation = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id] | |||||
render :partial => "resource/violation", :locals => { :violation => violation } | |||||
end | |||||
def form | |||||
rule_failure = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id] | |||||
@review = Review.new | |||||
@review.rule_failure_permanent_id = rule_failure.permanent_id | |||||
@review_comment = ReviewComment.new | |||||
@review_comment.review_text = "" | |||||
if params[:switch_off] | |||||
@review.review_type = "f-positive" | |||||
else | |||||
@review.review_type = Review.default_type | |||||
end | |||||
render :partial => "form" | |||||
end | |||||
def create | |||||
rule_failure = find_last_rule_failure_with_permanent_id params[:review][:rule_failure_permanent_id] | |||||
unless has_rights_to_create? rule_failure | |||||
render :text => "<b>Cannot create the review</b> : access denied." | |||||
return | |||||
end | |||||
@review = Review.new(params[:review]) | |||||
@review.user = current_user | |||||
if params[:assign_to_me] | |||||
@review.assignee = current_user | |||||
end | |||||
@review.title = rule_failure.message | |||||
@review.status = Review.default_status | |||||
@review.severity = Sonar::RulePriority.to_s rule_failure.failure_level | |||||
@review.resource = RuleFailure.find( @review.rule_failure_permanent_id, :include => ['snapshot'] ).snapshot.project | |||||
@review_comment = ReviewComment.new(params[:review_comment]) | |||||
@review_comment.user = current_user | |||||
@review.review_comments << @review_comment | |||||
if @review.valid? | |||||
if @review.review_type == "f-positive" | |||||
if rule_failure.get_open_review | |||||
current_open_review = rule_failure.get_open_review | |||||
current_open_review.status = "closed" | |||||
current_open_review.save | |||||
end | |||||
rule_failure.switched_off = true | |||||
rule_failure.save | |||||
end | |||||
@review.save | |||||
@violation = rule_failure | |||||
end | |||||
render "create_result" | |||||
end | |||||
def form_comment | |||||
@review_comment = ReviewComment.new | |||||
@review_comment.user = current_user | |||||
@review_comment.review_id = params[:review_id] | |||||
@review_comment.review_text = "" | |||||
@rule_failure_permanent_id = params[:rule_failure_permanent_id] | |||||
if params[:update_comment] | |||||
@update_comment = true | |||||
@review_comment.review_text = params[:review_text] | |||||
end | |||||
render :partial => "form_comment" | |||||
end | |||||
def create_comment | |||||
rule_failure = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id] | |||||
unless has_rights_to_create? rule_failure | |||||
render :text => "<b>Cannot create the comment</b> : access denied." | |||||
return | |||||
end | |||||
@review_comment = ReviewComment.new(params[:review_comment]) | |||||
@review_comment.user = current_user | |||||
@rule_failure_permanent_id = params[:rule_failure_permanent_id] | |||||
if @review_comment.valid? | |||||
@review_comment.save | |||||
# -- TODO : should create a Review#create_comment and put the following logic in it | |||||
review = @review_comment.review | |||||
review.updated_at = @review_comment.created_at | |||||
review.save | |||||
# -- End of TODO code -- | |||||
@violation = rule_failure | |||||
end | |||||
render "create_comment_result" | |||||
end | |||||
def update_comment | |||||
review = Review.find params[:review_comment][:review_id] | |||||
@review_comment = review.review_comments.last | |||||
unless current_user && current_user.id == @review_comment.user_id | |||||
render :text => "<b>Cannot modify the comment</b> : access denied." | |||||
return | |||||
end | |||||
@review_comment.review_text = params[:review_comment][:review_text] | |||||
@review_comment.created_at = DateTime.now | |||||
@rule_failure_permanent_id = params[:rule_failure_permanent_id] | |||||
if @review_comment.valid? | |||||
@review_comment.save | |||||
review.updated_at = @review_comment.updated_at | |||||
review.save | |||||
@violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id | |||||
end | |||||
render "create_comment_result" | |||||
end | |||||
def form_assign | |||||
@user_options = add_all_users [] | |||||
@review_id = params[:review_id] | |||||
@rule_failure_permanent_id = params[:rule_failure_permanent_id] | |||||
render :partial => "form_assign" | |||||
end | |||||
def assign | |||||
review = Review.find params[:review_id] | |||||
unless current_user | |||||
render :text => "<b>Cannot edit the review</b> : access denied." | |||||
return | |||||
end | |||||
review.assignee = User.find params[:assignee_id] | |||||
review.save | |||||
violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id | |||||
render :partial => "resource/violation", :locals => { :violation => violation } | |||||
end | |||||
def close_review | |||||
review = Review.find params[:review_id] | |||||
unless current_user | |||||
render :text => "<b>Cannot edit the review</b> : access denied." | |||||
return | |||||
end | |||||
review.status = "closed" | |||||
review.save | |||||
violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id | |||||
render :partial => "resource/violation", :locals => { :violation => violation } | |||||
end | |||||
## -------------- PRIVATE -------------- ## | |||||
private | |||||
def init_params | |||||
@user_names = [["Any", ""]] | |||||
default_user = [""] | |||||
if current_user | |||||
default_user = [current_user.id] | |||||
end | |||||
add_all_users @user_names | |||||
@review_authors = filter_any(params[:review_authors]) || default_user | |||||
@comment_authors = filter_any(params[:comment_authors]) || default_user | |||||
@severities = filter_any(params[:severities]) || [""] | |||||
@statuses = filter_any(params[:statuses]) || ["open"] | |||||
end | |||||
def add_all_users ( user_options ) | |||||
User.find( :all ).each do |user| | |||||
userName = user.name | |||||
if current_user.id == user.id | |||||
userName = "Me (" + user.name + ")" | |||||
end | |||||
user_options << [userName, user.id.to_s] | |||||
end | |||||
return user_options | |||||
end | |||||
def filter_any(array) | |||||
if array && array.size>1 && array.include?("") | |||||
array=[""] | |||||
end | |||||
array | |||||
end | |||||
def find_reviews_for_user_query | |||||
conditions=[] | |||||
values={} | |||||
unless @statuses == [""] | |||||
conditions << "reviews.status in (:statuses)" | |||||
values[:statuses]=@statuses | |||||
end | |||||
unless @severities == [""] | |||||
conditions << "reviews.severity in (:severities)" | |||||
values[:severities]=@severities | |||||
end | |||||
unless @review_authors == [""] | |||||
conditions << "reviews.user_id in (:review_authors)" | |||||
values[:review_authors]=@review_authors | |||||
end | |||||
unless @comment_authors == [""] | |||||
conditions << "review_comments.user_id in (:comment_authors)" | |||||
values[:comment_authors]=@comment_authors | |||||
end | |||||
@reviews = Review.find( :all, :order => "created_at DESC", :joins => :review_comments, :conditions => [ conditions.join(" AND "), values] ).uniq | |||||
end | |||||
def find_reviews_for_rule_failure ( rule_failure_permanent_id ) | |||||
return Review.find :all, :conditions => ['rule_failure_permanent_id=?', rule_failure_permanent_id] | |||||
end | |||||
def find_last_rule_failure_with_permanent_id ( rule_failure_permanent_id ) | |||||
return RuleFailure.last( :all, :conditions => [ "permanent_id = ?", rule_failure_permanent_id ], :include => ['snapshot'] ) | |||||
end | |||||
def has_rights_to_create? ( rule_failure ) | |||||
return false unless current_user | |||||
project = rule_failure.snapshot.root_project | |||||
unless has_role?(:user, project) | |||||
return false | |||||
end | |||||
return true | |||||
end | |||||
def error_not_post | |||||
render :text => "Create actions must use POST method." | |||||
end | |||||
end |
# | |||||
# Sonar, entreprise quality control tool. | |||||
# Copyright (C) 2008-2011 SonarSource | |||||
# mailto:contact AT sonarsource DOT com | |||||
# | |||||
# Sonar 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. | |||||
# | |||||
# Sonar 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 Sonar; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
# | |||||
class Review < ActiveRecord::Base | |||||
belongs_to :user | |||||
belongs_to :assignee, :class_name => "User", :foreign_key => "assignee_id" | |||||
belongs_to :resource, :class_name => "Project", :foreign_key => "resource_id" | |||||
has_many :review_comments, :order => "created_at", :dependent => :destroy | |||||
validates_presence_of :user, :message => "can't be empty" | |||||
validates_presence_of :title, :message => "can't be empty" | |||||
validates_presence_of :review_type, :message => "can't be empty" | |||||
validates_presence_of :status, :message => "can't be empty" | |||||
SEVERITY_INFO = "INFO" | |||||
SEVERITY_MINOR = "MINOR" | |||||
SEVERITY_MAJOR = "MAJOR" | |||||
SEVERITY_CRITICAL = "CRITICAL" | |||||
SEVERITY_BLOCKER = "BLOCKER" | |||||
TYPE_COMMENTS = "comments" | |||||
TYPE_FALSE_POSITIVE = "f-positive" | |||||
STATUS_OPEN = "open" | |||||
STATUS_CLOSED = "closed" | |||||
def self.default_severity | |||||
return SEVERITY_MAJOR | |||||
end | |||||
def self.default_type | |||||
return TYPE_COMMENTS | |||||
end | |||||
def self.default_status | |||||
return STATUS_OPEN | |||||
end | |||||
def self.severity_options | |||||
severity_ops = [] | |||||
severity_ops << ["Info", SEVERITY_INFO] | |||||
severity_ops << ["Minor", SEVERITY_MINOR] | |||||
severity_ops << ["Major", SEVERITY_MAJOR] | |||||
severity_ops << ["Critical", SEVERITY_CRITICAL] | |||||
severity_ops << ["Blocker", SEVERITY_BLOCKER] | |||||
return severity_ops | |||||
end | |||||
def self.status_options | |||||
status_ops = [] | |||||
status_ops << ["Open", STATUS_OPEN] | |||||
status_ops << ["Closed", STATUS_CLOSED] | |||||
return status_ops | |||||
end | |||||
end | |||||
# | |||||
# Sonar, entreprise quality control tool. | |||||
# Copyright (C) 2008-2011 SonarSource | |||||
# mailto:contact AT sonarsource DOT com | |||||
# | |||||
# Sonar 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. | |||||
# | |||||
# Sonar 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 Sonar; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
# | |||||
class Review < ActiveRecord::Base | |||||
belongs_to :user | |||||
belongs_to :assignee, :class_name => "User", :foreign_key => "assignee_id" | |||||
belongs_to :resource, :class_name => "Project", :foreign_key => "resource_id" | |||||
has_many :review_comments, :order => "created_at", :dependent => :destroy | |||||
validates_presence_of :user, :message => "can't be empty" | |||||
validates_presence_of :title, :message => "can't be empty" | |||||
validates_presence_of :review_type, :message => "can't be empty" | |||||
validates_presence_of :status, :message => "can't be empty" | |||||
SEVERITY_INFO = "INFO" | |||||
SEVERITY_MINOR = "MINOR" | |||||
SEVERITY_MAJOR = "MAJOR" | |||||
SEVERITY_CRITICAL = "CRITICAL" | |||||
SEVERITY_BLOCKER = "BLOCKER" | |||||
TYPE_COMMENTS = "comments" | |||||
TYPE_FALSE_POSITIVE = "f-positive" | |||||
STATUS_OPEN = "open" | |||||
STATUS_CLOSED = "closed" | |||||
def self.default_severity | |||||
return SEVERITY_MAJOR | |||||
end | |||||
def self.default_type | |||||
return TYPE_COMMENTS | |||||
end | |||||
def self.default_status | |||||
return STATUS_OPEN | |||||
end | |||||
def self.severity_options | |||||
severity_ops = [] | |||||
severity_ops << ["Info", SEVERITY_INFO] | |||||
severity_ops << ["Minor", SEVERITY_MINOR] | |||||
severity_ops << ["Major", SEVERITY_MAJOR] | |||||
severity_ops << ["Critical", SEVERITY_CRITICAL] | |||||
severity_ops << ["Blocker", SEVERITY_BLOCKER] | |||||
return severity_ops | |||||
end | |||||
def self.status_options | |||||
status_ops = [] | |||||
status_ops << ["Open", STATUS_OPEN] | |||||
status_ops << ["Closed", STATUS_CLOSED] | |||||
return status_ops | |||||
end | |||||
end |
# | |||||
# Sonar, entreprise quality control tool. | |||||
# Copyright (C) 2008-2011 SonarSource | |||||
# mailto:contact AT sonarsource DOT com | |||||
# | |||||
# Sonar 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. | |||||
# | |||||
# Sonar 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 {library}; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
# | |||||
class RuleFailure < ActiveRecord::Base | |||||
belongs_to :rule | |||||
belongs_to :snapshot | |||||
has_many :reviews, :primary_key => "permanent_id", :foreign_key => "rule_failure_permanent_id", :order => "created_at" | |||||
def get_open_review | |||||
reviews.each do |review| | |||||
if review.status == "open" | |||||
return review | |||||
end | |||||
end | |||||
return nil | |||||
end | |||||
def to_hash_json | |||||
json = {} | |||||
json['message'] = message | |||||
json['line'] = line if line | |||||
json['priority'] = Sonar::RulePriority.to_s(failure_level).upcase | |||||
if created_at | |||||
json['createdAt'] = format_datetime(created_at) | |||||
end | |||||
json['rule'] = { | |||||
:key => rule.key, | |||||
:name => rule.name | |||||
} | |||||
json['resource'] = { | |||||
:key => snapshot.project.key, | |||||
:name => snapshot.project.name, | |||||
:scope => snapshot.project.scope, | |||||
:qualifier => snapshot.project.qualifier, | |||||
:language => snapshot.project.language | |||||
} | |||||
json | |||||
end | |||||
def to_xml(xml=Builder::XmlMarkup.new(:indent => 0)) | |||||
xml.violation do | |||||
xml.message(message) | |||||
xml.line(line) if line | |||||
xml.priority(Sonar::RulePriority.to_s(failure_level)) | |||||
if created_at | |||||
xml.createdAt(format_datetime(created_at)) | |||||
end | |||||
xml.rule do | |||||
xml.key(rule.key) | |||||
xml.name(rule.name) | |||||
end | |||||
xml.resource do | |||||
xml.key(snapshot.project.key) | |||||
xml.name(snapshot.project.name) | |||||
xml.scope(snapshot.project.scope) | |||||
xml.qualifier(snapshot.project.qualifier) | |||||
xml.language(snapshot.project.language) | |||||
end | |||||
end | |||||
end | |||||
def format_datetime(datetime) | |||||
datetime.strftime("%Y-%m-%dT%H:%M:%S%z") | |||||
end | |||||
end | |||||
# | |||||
# Sonar, entreprise quality control tool. | |||||
# Copyright (C) 2008-2011 SonarSource | |||||
# mailto:contact AT sonarsource DOT com | |||||
# | |||||
# Sonar 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. | |||||
# | |||||
# Sonar 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 {library}; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
# | |||||
class RuleFailure < ActiveRecord::Base | |||||
belongs_to :rule | |||||
belongs_to :snapshot | |||||
has_many :reviews, :primary_key => "permanent_id", :foreign_key => "rule_failure_permanent_id", :order => "created_at" | |||||
def get_open_review | |||||
reviews.each do |review| | |||||
if review.status == "open" | |||||
return review | |||||
end | |||||
end | |||||
return nil | |||||
end | |||||
def to_hash_json | |||||
json = {} | |||||
json['message'] = message | |||||
json['line'] = line if line | |||||
json['priority'] = Sonar::RulePriority.to_s(failure_level).upcase | |||||
if created_at | |||||
json['createdAt'] = format_datetime(created_at) | |||||
end | |||||
json['rule'] = { | |||||
:key => rule.key, | |||||
:name => rule.name | |||||
} | |||||
json['resource'] = { | |||||
:key => snapshot.project.key, | |||||
:name => snapshot.project.name, | |||||
:scope => snapshot.project.scope, | |||||
:qualifier => snapshot.project.qualifier, | |||||
:language => snapshot.project.language | |||||
} | |||||
json | |||||
end | |||||
def to_xml(xml=Builder::XmlMarkup.new(:indent => 0)) | |||||
xml.violation do | |||||
xml.message(message) | |||||
xml.line(line) if line | |||||
xml.priority(Sonar::RulePriority.to_s(failure_level)) | |||||
if created_at | |||||
xml.createdAt(format_datetime(created_at)) | |||||
end | |||||
xml.rule do | |||||
xml.key(rule.key) | |||||
xml.name(rule.name) | |||||
end | |||||
xml.resource do | |||||
xml.key(snapshot.project.key) | |||||
xml.name(snapshot.project.name) | |||||
xml.scope(snapshot.project.scope) | |||||
xml.qualifier(snapshot.project.qualifier) | |||||
xml.language(snapshot.project.language) | |||||
end | |||||
end | |||||
end | |||||
def format_datetime(datetime) | |||||
datetime.strftime("%Y-%m-%dT%H:%M:%S%z") | |||||
end | |||||
end |
<% form_for :review, @review do |f| %> | |||||
<%= f.hidden_field :rule_failure_permanent_id -%> | |||||
<%= f.hidden_field :review_type -%> | |||||
<% if @review.review_type == "f-positive" %> | |||||
<b>Reason for flagging this violation as a false-positive:</b> | |||||
<% end %> | |||||
<%= text_area :review_comment, :review_text, | |||||
:id => "reviewText", :rows => 8, | |||||
:style => "width:100%", :onKeyUp => "if (this.value=='') $('submit_btn').disabled='true'; else $('submit_btn').disabled='';" -%> | |||||
<br/> | |||||
<div> | |||||
<% | |||||
if @review.review_type == "comments" | |||||
button_text = "Post review" | |||||
else | |||||
button_text = "Switch-off violation" | |||||
end | |||||
%> | |||||
<%= submit_to_remote "submit_btn", button_text, :url => { :action => 'create' }, :html => { :id => "submit_btn", :disabled => "true" } -%> | |||||
| |||||
<a onclick="$('reviewForm<%= @review.rule_failure_permanent_id.to_s -%>').style.display='none';" href="#">Cancel</a> | |||||
<% if @review.review_type == "comments" %> | |||||
| |||||
<%= check_box_tag "assign_to_me", "me", true -%> Assign to me | |||||
<% end %> | |||||
</div> | |||||
</div class="clear"></div> | |||||
<% form_for :review, @review do |f| %> | |||||
<%= f.hidden_field :rule_failure_permanent_id -%> | |||||
<%= f.hidden_field :review_type -%> | |||||
<% if @review.review_type == "f-positive" %> | |||||
<b>Reason for flagging this violation as a false-positive:</b> | |||||
<% end %> | |||||
<%= text_area :review_comment, :review_text, | |||||
:id => "reviewText", :rows => 8, | |||||
:style => "width:100%", :onKeyUp => "if (this.value=='') $('submit_btn').disabled='true'; else $('submit_btn').disabled='';" -%> | |||||
<br/> | |||||
<div> | |||||
<% | |||||
if @review.review_type == "comments" | |||||
button_text = "Post review" | |||||
else | |||||
button_text = "Switch-off violation" | |||||
end | |||||
%> | |||||
<%= submit_to_remote "submit_btn", button_text, :url => { :action => 'create' }, :html => { :id => "submit_btn", :disabled => "true" } -%> | |||||
| |||||
<a onclick="$('reviewForm<%= @review.rule_failure_permanent_id.to_s -%>').style.display='none';" href="#">Cancel</a> | |||||
<% if @review.review_type == "comments" %> | |||||
| |||||
<%= check_box_tag "assign_to_me", "me", true -%> Assign to me | |||||
<% end %> | |||||
</div> | |||||
</div class="clear"></div> | |||||
<% end %> | <% end %> |
<% form_for :review_comment, @review_comment do |f| %> | |||||
<%= f.hidden_field :review_id %> | |||||
<%= f.text_area :review_text, :rows => 8, | |||||
:id => "commentText" + @rule_failure_permanent_id.to_s, | |||||
:style => "width:100%", | |||||
:onKeyUp => "if (this.value=='') $('submit_btn').disabled='true'; else $('submit_btn').disabled='';" %> | |||||
<br/> | |||||
<% if @update_comment %> | |||||
<%= submit_to_remote 'submit_btn', 'Update comment', | |||||
:url => { :action => 'update_comment', | |||||
:rule_failure_permanent_id => @rule_failure_permanent_id }, | |||||
:html => { :id => "submit_btn" } %> | |||||
| |||||
<%= link_to_remote 'Cancel', | |||||
:url => { :action => 'display_violation', | |||||
:rule_failure_permanent_id => @rule_failure_permanent_id }, | |||||
:update => "vId" + @rule_failure_permanent_id.to_s %> | |||||
<% else %> | |||||
<%= submit_to_remote 'submit_btn', 'Post comment', | |||||
:url => { :action => 'create_comment', | |||||
:rule_failure_permanent_id => @rule_failure_permanent_id }, | |||||
:html => { :id => "submit_btn", :disabled => true } %> | |||||
| |||||
<a onclick="$('reviewForm<%= @rule_failure_permanent_id.to_s -%>').style.display='none'; $('commentAction<%= @rule_failure_permanent_id.to_s -%>').style.display='';" href="#">Cancel</a> | |||||
<% end %> | |||||
<% form_for :review_comment, @review_comment do |f| %> | |||||
<%= f.hidden_field :review_id %> | |||||
<%= f.text_area :review_text, :rows => 8, | |||||
:id => "commentText" + @rule_failure_permanent_id.to_s, | |||||
:style => "width:100%", | |||||
:onKeyUp => "if (this.value=='') $('submit_btn').disabled='true'; else $('submit_btn').disabled='';" %> | |||||
<br/> | |||||
<% if @update_comment %> | |||||
<%= submit_to_remote 'submit_btn', 'Update comment', | |||||
:url => { :action => 'update_comment', | |||||
:rule_failure_permanent_id => @rule_failure_permanent_id }, | |||||
:html => { :id => "submit_btn" } %> | |||||
| |||||
<%= link_to_remote 'Cancel', | |||||
:url => { :action => 'display_violation', | |||||
:rule_failure_permanent_id => @rule_failure_permanent_id }, | |||||
:update => "vId" + @rule_failure_permanent_id.to_s %> | |||||
<% else %> | |||||
<%= submit_to_remote 'submit_btn', 'Post comment', | |||||
:url => { :action => 'create_comment', | |||||
:rule_failure_permanent_id => @rule_failure_permanent_id }, | |||||
:html => { :id => "submit_btn", :disabled => true } %> | |||||
| |||||
<a onclick="$('reviewForm<%= @rule_failure_permanent_id.to_s -%>').style.display='none'; $('commentAction<%= @rule_failure_permanent_id.to_s -%>').style.display='';" href="#">Cancel</a> | |||||
<% end %> | |||||
<% end %> | <% end %> |
<div id="review<%= review.id -%>"> | |||||
<div> | |||||
<b>Review #<%= review.id -%> - <%= h(review.title) -%></b> | |||||
<br/> | |||||
<% if review.assignee %> | |||||
<i>Assigned to <%= h(review.assignee.name) -%></i> | |||||
<% end %> | |||||
</div> | |||||
<div style="margin-top: 10px; margin-left: 20px"> | |||||
<% unless review.review_comments.blank? | |||||
last_comment = review.review_comments.last | |||||
review.review_comments.each do |review_comment| | |||||
%> | |||||
<table style="width:100%; margin-bottom: 3px"> | |||||
<tr style="border: solid 1px grey; background-color: #F7F7F7"> | |||||
<td style="width:180px; vertical-align:top; padding: 2px 2px 2px 10px; font-weight: bold"> | |||||
<%= image_tag("user.png") -%> <b><%= h(review_comment.user.name) -%></b> | |||||
</td> | |||||
<td style="vertical-align: top; padding: 2px 10px 2px 2px; color: grey; text-align: right; font-style: italic"> | |||||
<%= l review_comment.created_at -%> | |||||
</td> | |||||
</tr> | |||||
<tr style="border: solid 1px grey;"> | |||||
<td colspan="2" style="padding: 5px;"> | |||||
<% if review_comment == last_comment %> | |||||
<div id="lastComment<%= review.id -%>"> | |||||
<%= h(review_comment.review_text) -%> | |||||
</div> | |||||
<% else %> | |||||
<%= h(review_comment.review_text) -%> | |||||
<% end %> | |||||
</td> | |||||
</tr> | |||||
</table> | |||||
<% | |||||
end | |||||
end | |||||
%> | |||||
<% if current_user %> | |||||
<div style="text-align: right; padding: 5px"> | |||||
<% if current_user.id == review.review_comments.last.user_id %> | |||||
<%= image_tag("pencil.png") -%> | |||||
<%= link_to_remote "Edit my last comment", | |||||
:url => { :controller => "reviews", :action => "form_comment", | |||||
:review_id => review.id, | |||||
:rule_failure_permanent_id => review.rule_failure_permanent_id, | |||||
:review_text => review.review_comments.last.review_text, | |||||
:update_comment => "true" }, | |||||
:update => "lastComment" + review.id.to_s, | |||||
:complete => "$('commentText" + review.id.to_s + "').focus()" -%> | |||||
| |||||
<% end %> | |||||
<%= image_tag("pencil.png") -%> | |||||
<%= link_to_remote "Add a new comment", | |||||
:url => { :controller => "reviews", :action => "form_comment", :review_id => review.id, :rule_failure_permanent_id => review.rule_failure_permanent_id }, | |||||
:update => "createComment" + review.id.to_s, | |||||
:complete => "$('commentText" + review.id.to_s + "').focus()" -%> | |||||
</div> | |||||
<div id="createComment<%= review.id -%>"></div> | |||||
<% end %> | |||||
</div> | |||||
</div> | |||||
<div id="review<%= review.id -%>"> | |||||
<div> | |||||
<b>Review #<%= review.id -%> - <%= h(review.title) -%></b> | |||||
<br/> | |||||
<% if review.assignee %> | |||||
<i>Assigned to <%= h(review.assignee.name) -%></i> | |||||
<% end %> | |||||
</div> | |||||
<div style="margin-top: 10px; margin-left: 20px"> | |||||
<% unless review.review_comments.blank? | |||||
last_comment = review.review_comments.last | |||||
review.review_comments.each do |review_comment| | |||||
%> | |||||
<table style="width:100%; margin-bottom: 3px"> | |||||
<tr style="border: solid 1px grey; background-color: #F7F7F7"> | |||||
<td style="width:180px; vertical-align:top; padding: 2px 2px 2px 10px; font-weight: bold"> | |||||
<%= image_tag("user.png") -%> <b><%= h(review_comment.user.name) -%></b> | |||||
</td> | |||||
<td style="vertical-align: top; padding: 2px 10px 2px 2px; color: grey; text-align: right; font-style: italic"> | |||||
<%= l review_comment.created_at -%> | |||||
</td> | |||||
</tr> | |||||
<tr style="border: solid 1px grey;"> | |||||
<td colspan="2" style="padding: 5px;"> | |||||
<% if review_comment == last_comment %> | |||||
<div id="lastComment<%= review.id -%>"> | |||||
<%= h(review_comment.review_text) -%> | |||||
</div> | |||||
<% else %> | |||||
<%= h(review_comment.review_text) -%> | |||||
<% end %> | |||||
</td> | |||||
</tr> | |||||
</table> | |||||
<% | |||||
end | |||||
end | |||||
%> | |||||
<% if current_user %> | |||||
<div style="text-align: right; padding: 5px"> | |||||
<% if current_user.id == review.review_comments.last.user_id %> | |||||
<%= image_tag("pencil.png") -%> | |||||
<%= link_to_remote "Edit my last comment", | |||||
:url => { :controller => "reviews", :action => "form_comment", | |||||
:review_id => review.id, | |||||
:rule_failure_permanent_id => review.rule_failure_permanent_id, | |||||
:review_text => review.review_comments.last.review_text, | |||||
:update_comment => "true" }, | |||||
:update => "lastComment" + review.id.to_s, | |||||
:complete => "$('commentText" + review.id.to_s + "').focus()" -%> | |||||
| |||||
<% end %> | |||||
<%= image_tag("pencil.png") -%> | |||||
<%= link_to_remote "Add a new comment", | |||||
:url => { :controller => "reviews", :action => "form_comment", :review_id => review.id, :rule_failure_permanent_id => review.rule_failure_permanent_id }, | |||||
:update => "createComment" + review.id.to_s, | |||||
:complete => "$('commentText" + review.id.to_s + "').focus()" -%> | |||||
</div> | |||||
<div id="createComment<%= review.id -%>"></div> | |||||
<% end %> | |||||
</div> | |||||
</div> |
if @violation | |||||
page.replace "vId" + @violation.permanent_id.to_s, :partial => "resource/violation", :locals => { :violation => @violation } | |||||
else | |||||
page.replace_html "reviewForm" + @rule_failure_permanent_id.to_s, :partial => "form_comment" | |||||
if @violation | |||||
page.replace "vId" + @violation.permanent_id.to_s, :partial => "resource/violation", :locals => { :violation => @violation } | |||||
else | |||||
page.replace_html "reviewForm" + @rule_failure_permanent_id.to_s, :partial => "form_comment" | |||||
end | end |
if @violation | |||||
page.replace "vId" + @violation.permanent_id.to_s, :partial => "resource/violation", :locals => { :violation => @violation } | |||||
else | |||||
page.replace_html "reviewForm" + @review.rule_failure_permanent_id.to_s, :partial => "form" | |||||
if @violation | |||||
page.replace "vId" + @violation.permanent_id.to_s, :partial => "resource/violation", :locals => { :violation => @violation } | |||||
else | |||||
page.replace_html "reviewForm" + @review.rule_failure_permanent_id.to_s, :partial => "form" | |||||
end | end |
# | |||||
# Sonar, entreprise quality control tool. | |||||
# Copyright (C) 2008-2011 SonarSource | |||||
# mailto:contact AT sonarsource DOT com | |||||
# | |||||
# Sonar 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. | |||||
# | |||||
# Sonar 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 Sonar; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
# | |||||
# | |||||
# Sonar 2.8 | |||||
# | |||||
class CreateReview < ActiveRecord::Migration | |||||
def self.up | |||||
create_table 'reviews' do |t| | |||||
t.column 'created_at', :datetime | |||||
t.column 'updated_at', :datetime | |||||
t.column 'user_id', :integer, :null => true | |||||
t.column 'assignee_id', :integer, :null => true | |||||
t.column 'title', :string, :null => true, :limit => 500 | |||||
t.column 'review_type', :string, :null => true, :limit => 10 | |||||
t.column 'status', :string, :null => true, :limit => 10 | |||||
t.column 'severity', :string, :null => true, :limit => 10 | |||||
t.column 'rule_failure_permanent_id', :integer, :null => true | |||||
t.column 'resource_id', :integer, :null => true | |||||
t.column 'resource_line', :integer, :null => true | |||||
end | |||||
create_table 'review_comments' do |t| | |||||
t.column 'created_at', :datetime | |||||
t.column 'updated_at', :datetime | |||||
t.column 'review_id', :integer | |||||
t.column 'user_id', :integer, :null => true | |||||
t.column 'review_text', :text, :null => true | |||||
end | |||||
alter_to_big_primary_key('reviews') | |||||
alter_to_big_primary_key('review_comments') | |||||
end | |||||
end | |||||
# | |||||
# Sonar, entreprise quality control tool. | |||||
# Copyright (C) 2008-2011 SonarSource | |||||
# mailto:contact AT sonarsource DOT com | |||||
# | |||||
# Sonar 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. | |||||
# | |||||
# Sonar 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 Sonar; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||||
# | |||||
# | |||||
# Sonar 2.8 | |||||
# | |||||
class CreateReview < ActiveRecord::Migration | |||||
def self.up | |||||
create_table 'reviews' do |t| | |||||
t.column 'created_at', :datetime | |||||
t.column 'updated_at', :datetime | |||||
t.column 'user_id', :integer, :null => true | |||||
t.column 'assignee_id', :integer, :null => true | |||||
t.column 'title', :string, :null => true, :limit => 500 | |||||
t.column 'review_type', :string, :null => true, :limit => 10 | |||||
t.column 'status', :string, :null => true, :limit => 10 | |||||
t.column 'severity', :string, :null => true, :limit => 10 | |||||
t.column 'rule_failure_permanent_id', :integer, :null => true | |||||
t.column 'resource_id', :integer, :null => true | |||||
t.column 'resource_line', :integer, :null => true | |||||
end | |||||
create_table 'review_comments' do |t| | |||||
t.column 'created_at', :datetime | |||||
t.column 'updated_at', :datetime | |||||
t.column 'review_id', :integer | |||||
t.column 'user_id', :integer, :null => true | |||||
t.column 'review_text', :text, :null => true | |||||
end | |||||
alter_to_big_primary_key('reviews') | |||||
alter_to_big_primary_key('review_comments') | |||||
end | |||||
end |
#!/bin/sh | #!/bin/sh | ||||
# | # | ||||
# NOTE: sonar must be built | # NOTE: sonar must be built | ||||
# | # | ||||
unzip sonar-*.zip | unzip sonar-*.zip | ||||
cd sonar-* | cd sonar-* | ||||
bin/macosx-universal-64/sonar.sh console | bin/macosx-universal-64/sonar.sh console | ||||