Introduction to Codacy
Codacy is an automated code review and quality analysis tool that helps developers identify issues, track code quality, and enforce coding standards across multiple programming languages, including Java. It integrates with your workflow to provide continuous code quality monitoring.
System Architecture Overview
Codacy Quality Pipeline ├── Code Repository │ ├ - GitHub/GitLab/Bitbucket │ ├ - Pull/Merge Requests │ └ - Branch Protection ├── Codacy Analysis │ ├ - Static Code Analysis │ ├ - Code Complexity │ ├ - Security Vulnerabilities │ ├ - Code Duplication │ └ - Code Coverage ├── Quality Gates │ ├ - Quality Thresholds │ ├ - Security Checks │ ├ - Coverage Requirements │ └ - PR Comments └── Reporting & Monitoring ├ - Quality Dashboard ├ - Trend Analysis ├ - Team Metrics └ - Security Reports
Core Implementation
1. Project Setup & Configuration
codacy.yml Configuration File
# .codacy.yml exclude_paths: - "**/generated/**" - "**/target/**" - "**/build/**" - "**/test/**" - "**/src/test/**" - "**/node_modules/**" - "**/*.min.js" - "**/vendor/**" engines: checkstyle: enabled: true exclude_paths: - "**/test/**" config: file: "checkstyle.xml" pmd: enabled: true exclude_paths: - "**/test/**" config: rulesets: - "category/java/bestpractices.xml" - "category/java/codestyle.xml" - "category/java/design.xml" - "category/java/documentation.xml" - "category/java/errorprone.xml" - "category/java/performance.xml" - "category/java/security.xml" findbugs: enabled: true exclude_paths: - "**/test/**" jacoco: enabled: true exclude_paths: - "**/test/**" config: min_coverage: 80 duplication: enabled: true exclude_paths: - "**/test/**" config: min_token_count: 70 sonarjava: enabled: true exclude_paths: - "**/test/**" quality: # Code Quality Gates code_patterns: min_grade: B max_issues: 50 # Security Requirements security: max_issues: 5 block_severity: high # Coverage Requirements coverage: min_coverage: 80 max_decrease: 5 # Complexity Limits complexity: max_method_complexity: 15 max_file_complexity: 200 # Duplication Limits duplication: max_duplication: 5% notifications: status: commit: true pull_request: true patterns: - pattern: "security" channel: "security-team" - pattern: "critical" channel: "engineering-leads"
codacy-coverage.xml for Coverage Reporting
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE codacy-coverage PUBLIC "-//Codacy//DTD Coverage 1.0//EN" "http://www.codacy.com/dtd/coverage-1.0.dtd"> <codacy-coverage> <tool>jacoco</tool> <version>0.8.8</version> <files> <file path="src/main/java/com/example/OrderService.java"> <line number="10" hits="15" /> <line number="11" hits="15" /> <line number="15" hits="12" /> <line number="20" hits="8" /> </file> <file path="src/main/java/com/example/OrderRepository.java"> <line number="5" hits="20" /> <line number="10" hits="18" /> <line number="15" hits="15" /> </file> </files> </codacy-coverage>
2. Maven Integration
pom.xml Configuration
<properties>
<codacy.project.token>${env.CODACY_PROJECT_TOKEN}</codacy.project.token>
<codacy.api.base.url>https://api.codacy.com</codacy.api.base.url>
<jacoco.version>0.8.8</jacoco.version>
<checkstyle.version>10.12.1</checkstyle.version>
<pmd.version>6.55.0</pmd.version>
<spotbugs.version>4.7.3</spotbugs.version>
</properties>
<build>
<plugins>
<!-- JaCoCo for Code Coverage -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>INSTRUCTION</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<!-- Checkstyle Configuration -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<configLocation>checkstyle.xml</configLocation>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<linkXRef>false</linkXRef>
</configuration>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- PMD Configuration -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.20.0</version>
<configuration>
<rulesets>
<ruleset>category/java/bestpractices.xml</ruleset>
<ruleset>category/java/codestyle.xml</ruleset>
<ruleset>category/java/design.xml</ruleset>
<ruleset>category/java/documentation.xml</ruleset>
<ruleset>category/java/errorprone.xml</ruleset>
<ruleset>category/java/performance.xml</ruleset>
<ruleset>category/java/security.xml</ruleset>
</rulesets>
<failOnViolation>true</failOnViolation>
<printFailingErrors>true</printFailingErrors>
</configuration>
<executions>
<execution>
<id>pmd-check</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- SpotBugs Configuration -->
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>${spotbugs.version}</version>
<configuration>
<effort>Max</effort>
<threshold>Low</threshold>
<failOnError>true</failOnError>
<excludeFilterFile>spotbugs-exclude.xml</excludeFilterFile>
</configuration>
<executions>
<execution>
<id>spotbugs-check</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>codacy-coverage</id>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.codacy</groupId>
<artifactId>codacy-coverage-reporter</artifactId>
<version>7.1.0</version>
<configuration>
<projectToken>${codacy.project.token}</projectToken>
<apiBaseUrl>${codacy.api.base.url}</apiBaseUrl>
<coverageReportFile>target/site/jacoco/jacoco.xml</coverageReportFile>
</configuration>
<executions>
<execution>
<id>report-coverage</id>
<phase>post-integration-test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
3. Gradle Integration
build.gradle Configuration
plugins {
id 'java'
id 'checkstyle'
id 'pmd'
id 'jacoco'
id 'com.github.spotbugs' version '5.0.14'
}
// Checkstyle Configuration
checkstyle {
toolVersion = '10.12.1'
configFile = file("config/checkstyle/checkstyle.xml")
ignoreFailures = false
maxWarnings = 0
}
tasks.withType(Checkstyle) {
reports {
xml.required = true
html.required = true
}
}
// PMD Configuration
pmd {
toolVersion = '6.55.0'
ruleSets = []
ruleSetFiles = files("config/pmd/ruleset.xml")
ignoreFailures = false
}
pmdMain {
ruleSets = [
'category/java/bestpractices.xml',
'category/java/codestyle.xml',
'category/java/design.xml',
'category/java/documentation.xml',
'category/java/errorprone.xml',
'category/java/performance.xml',
'category/java/security.xml'
]
}
// SpotBugs Configuration
spotbugs {
toolVersion = '4.7.3'
ignoreFailures = false
effort = 'max'
reportLevel = 'low'
excludeFilter = file('config/spotbugs/exclude.xml')
}
spotbugsMain {
reports {
xml.required = true
html.required = true
}
}
// JaCoCo Configuration
jacoco {
toolVersion = "0.8.8"
}
jacocoTestReport {
reports {
xml.required = true
html.required = true
csv.required = false
}
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: [
'**/test/**',
'**/generated/**',
'**/config/**'
])
}))
}
}
jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = 0.80
}
}
rule {
element = 'CLASS'
includes = ['com.example.service.*']
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.85
}
}
}
}
// Codacy Coverage Reporter Task
task codacyCoverage(type: Exec) {
dependsOn jacocoTestReport
commandLine 'bash', '-c',
'bash <(curl -Ls https://coverage.codacy.com/get.sh) report -r build/reports/jacoco/test/jacocoTestReport.xml'
}
// Quality Gate Task
task qualityGate {
dependsOn checkstyleMain, pmdMain, spotbugsMain, jacocoTestCoverageVerification
doLast {
println "All quality checks passed!"
}
}
// Test configuration
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
}
finalizedBy jacocoTestReport
}
4. GitHub Actions Integration
.github/workflows/codacy-analysis.yml
name: Codacy Analysis
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
codacy-analysis:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: 'maven'
- name: Build and run tests with coverage
run: |
mvn clean verify
mvn jacoco:report
- name: Run Codacy analysis
uses: codacy/codacy-analysis-cli-action@v4
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
max-allowed-issues: 50
gh-code-scanning-compat: true
- name: Upload coverage to Codacy
uses: codacy/codacy-coverage-reporter-action@v1
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: target/site/jacoco/jacoco.xml
- name: Check quality gate
run: |
# Check if quality thresholds are met
# This could be a custom script that checks various metrics
echo "Quality gate checks completed"
GitHub Actions with Multiple Quality Checks
name: Java CI with Codacy
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
quality:
name: Code Quality Analysis
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: 'maven'
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Run Checkstyle
run: mvn checkstyle:checkstyle
- name: Run PMD
run: mvn pmd:check
- name: Run SpotBugs
run: mvn spotbugs:check
- name: Run tests with coverage
run: mvn clean test jacoco:report
- name: Upload coverage to Codacy
uses: codacy/codacy-coverage-reporter-action@v1
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: target/site/jacoco/jacoco.xml
- name: Run Codacy Analysis
uses: codacy/codacy-analysis-cli-action@v4
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
max-allowed-issues: 25
fail-on-duplication: true
fail-on-coverage-decrease: true
- name: Upload quality reports
uses: actions/upload-artifact@v3
with:
name: quality-reports
path: |
target/checkstyle-result.xml
target/pmd.xml
target/spotbugs.xml
target/site/jacoco/
retention-days: 30
5. GitLab CI Integration
.gitlab-ci.yml
stages: - test - quality - security - deploy variables: MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository" cache: paths: - .m2/repository/ - target/ test: stage: test image: maven:3.8.6-openjdk-17 script: - mvn clean test jacoco:report artifacts: paths: - target/site/jacoco/ expire_in: 1 week only: - merge_requests - develop - main codacy-analysis: stage: quality image: maven:3.8.6-openjdk-17 dependencies: - test script: - | mvn com.codacy:codacy-coverage-reporter:report \ -DcoverageReportFile=target/site/jacoco/jacoco.xml \ -DprojectToken=$CODACY_PROJECT_TOKEN \ -DapiToken=$CODACY_API_TOKEN - | mvn com.codacy:codacy-analysis-cli:analysis \ -DprojectToken=$CODACY_PROJECT_TOKEN \ -DcommitUuid=$CI_COMMIT_SHA \ -DmaxAllowedIssues=50 only: - merge_requests - develop - main quality-gate: stage: quality image: maven:3.8.6-openjdk-17 script: - mvn checkstyle:checkstyle pmd:check spotbugs:check - mvn jacoco:check allow_failure: false only: - merge_requests - develop - main security-scan: stage: security image: maven:3.8.6-openjdk-17 script: - mvn org.owasp:dependency-check-maven:check - mvn com.github.spotbugs:spotbugs-maven-plugin:spotbugs artifacts: reports: dependency_scanning: target/dependency-check-report.json sast: target/spotbugs.xml only: - merge_requests - develop - main
6. Custom Quality Configuration
Custom PMD Ruleset
<?xml version="1.0"?> <ruleset name="Custom Java Rules" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> <description>Custom PMD rules for our Java project</description> <!-- Import standard rule sets --> <rule ref="category/java/bestpractices.xml"> <exclude name="AbstractClassWithoutAbstractMethod"/> <exclude name="JUnitAssertionsShouldIncludeMessage"/> </rule> <rule ref="category/java/codestyle.xml"> <exclude name="AtLeastOneConstructor"/> <exclude name="ShortVariable"/> </rule> <rule ref="category/java/design.xml"> <exclude name="LawOfDemeter"/> <exclude name="DataClass"/> </rule> <rule ref="category/java/errorprone.xml"> <exclude name="BeanMembersShouldSerialize"/> </rule> <rule ref="category/java/performance.xml"> <exclude name="AvoidInstantiatingObjectsInLoops"/> </rule> <rule ref="category/java/security.xml"/> <!-- Custom rules --> <rule ref="category/java/codestyle.xml/ShortClassName"> <properties> <property name="minimum" value="3"/> </properties> </rule> <rule ref="category/java/design.xml/ExcessiveMethodLength"> <properties> <property name="minimum" value="50.0"/> </properties> </rule> <rule ref="category/java/design.xml/CyclomaticComplexity"> <properties> <property name="classReportLevel" value="50"/> <property name="methodReportLevel" value="15"/> </properties> </rule> </ruleset>
SpotBugs Exclusion Configuration
<!-- spotbugs-exclude.xml --> <FindBugsFilter> <!-- Exclude generated code --> <Match> <Class name="~.*\.generated\..*"/> </Match> <!-- Exclude test classes --> <Match> <Class name="~.*Test.*"/> </Match> <!-- Exclude specific false positives --> <Match> <Class name="com.example.service.OrderService"/> <Method name="processOrder"/> <Bug pattern="REC_CATCH_EXCEPTION"/> </Match> <!-- Exclude serialization issues in models --> <Match> <Class name="~.*\.model\..*"/> <Bug pattern="SE_NO_SERIALVERSIONID"/> </Match> <!-- Exclude specific security warnings --> <Match> <Class name="com.example.config.SecurityConfig"/> <Bug pattern="HARD_CODE_PASSWORD"/> </Match> </FindBugsFilter>
7. Quality Dashboard Configuration
Quality Thresholds File
# quality-thresholds.yml quality_gates: code_quality: min_grade: B max_issues: 25 max_new_issues: 5 security: max_issues: 3 max_critical_issues: 0 max_high_issues: 1 coverage: min_overall_coverage: 80 min_new_coverage: 70 max_decrease: 5 complexity: max_method_complexity: 15 max_file_complexity: 200 max_cyclomatic_complexity: 10 duplication: max_duplicated_lines: 5% max_duplicated_blocks: 10 documentation: min_documentation_rate: 70 performance: max_issues: 10 file_patterns: critical_files: - "**/service/**/*.java" - "**/controller/**/*.java" - "**/security/**/*.java" test_files: - "**/test/**/*.java" - "**/*Test.java" - "**/*IT.java" excluded_files: - "**/generated/**/*.java" - "**/target/**/*.java" - "**/build/**/*.java" rules: mandatory: - "security" - "unused_code" - "error_prone" recommended: - "code_style" - "best_practices" - "documentation" optional: - "performance" - "design"
8. Sample High-Quality Java Code
/**
* Order Service implementation with comprehensive quality measures.
*
* @author Quality Team
* @version 1.0
* @since 2024
*/
package com.example.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
* Service for managing order operations with quality enforcement.
*/
@Service
@Transactional
public class OrderServiceImpl implements OrderService {
private static final Logger LOGGER = LoggerFactory.getLogger(OrderServiceImpl.class);
private static final int MAX_RETRY_ATTEMPTS = 3;
private static final long RETRY_DELAY_MS = 1000L;
private final OrderRepository orderRepository;
private final InventoryService inventoryService;
private final PaymentService paymentService;
/**
* Constructor with dependency injection.
*
* @param orderRepository the order repository
* @param inventoryService the inventory service
* @param paymentService the payment service
*/
public OrderServiceImpl(final OrderRepository orderRepository,
final InventoryService inventoryService,
final PaymentService paymentService) {
this.orderRepository = orderRepository;
this.inventoryService = inventoryService;
this.paymentService = paymentService;
}
/**
* {@inheritDoc}
*/
@Override
public OrderResult processOrder(@NotNull @Valid final Order order)
throws OrderProcessingException {
validateOrder(order);
LOGGER.info("Processing order: {}", order.getId());
final long startTime = System.currentTimeMillis();
try {
final OrderResult result = processOrderWithRetry(order);
final long processingTime = System.currentTimeMillis() - startTime;
LOGGER.info("Order {} processed successfully in {} ms",
order.getId(), processingTime);
return result;
} catch (final OrderProcessingException e) {
LOGGER.error("Failed to process order: {}", order.getId(), e);
throw e;
}
}
/**
* Process order with retry logic for transient failures.
*
* @param order the order to process
* @return order processing result
* @throws OrderProcessingException if processing fails after retries
*/
private OrderResult processOrderWithRetry(final Order order)
throws OrderProcessingException {
int attempt = 0;
OrderProcessingException lastException = null;
while (attempt < MAX_RETRY_ATTEMPTS) {
try {
attempt++;
LOGGER.debug("Order processing attempt {} for order: {}",
attempt, order.getId());
return executeOrderProcessing(order);
} catch (final TemporaryFailureException e) {
lastException = new OrderProcessingException(
"Temporary failure in order processing", e);
LOGGER.warn("Temporary failure processing order {} (attempt {}/{}): {}",
order.getId(), attempt, MAX_RETRY_ATTEMPTS, e.getMessage());
if (attempt < MAX_RETRY_ATTEMPTS) {
waitBeforeRetry(attempt);
}
}
}
throw lastException != null ? lastException
: new OrderProcessingException("Unexpected error in order processing");
}
/**
* Execute the core order processing logic.
*
* @param order the order to process
* @return order processing result
* @throws TemporaryFailureException for retryable failures
* @throws OrderProcessingException for permanent failures
*/
private OrderResult executeOrderProcessing(final Order order)
throws TemporaryFailureException, OrderProcessingException {
try {
// Step 1: Validate inventory
validateInventory(order.getItems());
// Step 2: Process payment
final PaymentResult paymentResult = processPayment(order);
// Step 3: Create order record
final Order savedOrder = saveOrder(order);
// Step 4: Update inventory
updateInventory(order.getItems());
return new OrderResult(true, "Order processed successfully",
savedOrder.getId(), paymentResult.getTransactionId());
} catch (final InventoryException e) {
throw new OrderProcessingException("Inventory validation failed", e);
} catch (final PaymentException e) {
throw new TemporaryFailureException("Payment processing failed", e);
} catch (final DatabaseException e) {
throw new TemporaryFailureException("Database operation failed", e);
}
}
/**
* Validate order before processing.
*
* @param order the order to validate
* @throws IllegalArgumentException if order is invalid
*/
private void validateOrder(final Order order) {
if (order == null) {
throw new IllegalArgumentException("Order cannot be null");
}
if (order.getItems() == null || order.getItems().isEmpty()) {
throw new IllegalArgumentException("Order must contain items");
}
if (order.getTotalAmount() == null || order.getTotalAmount().compareTo(java.math.BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Order amount must be positive");
}
if (order.getCustomerId() == null || order.getCustomerId().trim().isEmpty()) {
throw new IllegalArgumentException("Customer ID is required");
}
}
/**
* Validate inventory for all order items.
*
* @param items the order items to validate
* @throws InventoryException if any item is unavailable
*/
private void validateInventory(final List<OrderItem> items) throws InventoryException {
for (final OrderItem item : items) {
if (!inventoryService.isItemAvailable(item.getProductId(), item.getQuantity())) {
throw new InventoryException(
String.format("Product %s is not available in quantity %d",
item.getProductId(), item.getQuantity()));
}
}
}
/**
* Process payment for the order.
*
* @param order the order to process payment for
* @return payment result
* @throws PaymentException if payment processing fails
*/
private PaymentResult processPayment(final Order order) throws PaymentException {
try {
return paymentService.processPayment(
order.getCustomerId(),
order.getTotalAmount(),
order.getCurrency());
} catch (final PaymentException e) {
LOGGER.error("Payment failed for order {}: {}", order.getId(), e.getMessage());
throw e;
}
}
/**
* Save order to database.
*
* @param order the order to save
* @return saved order
* @throws DatabaseException if database operation fails
*/
private Order saveOrder(final Order order) throws DatabaseException {
try {
order.setStatus(OrderStatus.PROCESSING);
order.setCreatedAt(LocalDateTime.now());
return orderRepository.save(order);
} catch (final Exception e) {
throw new DatabaseException("Failed to save order", e);
}
}
/**
* Update inventory after successful order processing.
*
* @param items the items to update inventory for
*/
private void updateInventory(final List<OrderItem> items) {
items.forEach(item ->
inventoryService.reserveItem(item.getProductId(), item.getQuantity()));
}
/**
* Wait before retry with exponential backoff.
*
* @param attempt the current attempt number
*/
private void waitBeforeRetry(final int attempt) {
try {
final long waitTime = RETRY_DELAY_MS * (long) Math.pow(2, attempt - 1);
Thread.sleep(waitTime);
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
throw new OrderProcessingException("Order processing interrupted", e);
}
}
/**
* {@inheritDoc}
*/
@Override
@Transactional(readOnly = true)
public List<Order> findOrdersByCustomer(final String customerId,
final int page,
final int size) {
validatePaginationParameters(page, size);
return orderRepository.findByCustomerId(customerId)
.stream()
.skip((long) page * size)
.limit(size)
.collect(Collectors.toList());
}
/**
* Validate pagination parameters.
*
* @param page the page number
* @param size the page size
* @throws IllegalArgumentException if parameters are invalid
*/
private void validatePaginationParameters(final int page, final int size) {
if (page < 0) {
throw new IllegalArgumentException("Page must be non-negative");
}
if (size <= 0 || size > 100) {
throw new IllegalArgumentException("Size must be between 1 and 100");
}
}
/**
* {@inheritDoc}
*/
@Override
@Transactional(readOnly = true)
public OrderStatistics getOrderStatistics() {
final List<Order> allOrders = orderRepository.findAll();
final long totalOrders = allOrders.size();
final double totalRevenue = allOrders.stream()
.mapToDouble(order -> order.getTotalAmount().doubleValue())
.sum();
final long pendingOrders = allOrders.stream()
.filter(order -> order.getStatus() == OrderStatus.PENDING)
.count();
return new OrderStatistics(totalOrders, totalRevenue, pendingOrders);
}
}
9. Monitoring and Reporting
Quality Metrics Dashboard
/**
* Service for monitoring code quality metrics.
*/
@Service
public class QualityMetricsService {
private final CodacyClient codacyClient;
private final ProjectRepository projectRepository;
/**
* Get current quality metrics for the project.
*
* @return quality metrics
*/
public QualityMetrics getCurrentMetrics() {
final CodacyProjectMetrics codacyMetrics = codacyClient.getProjectMetrics();
return QualityMetrics.builder()
.codeQualityGrade(codacyMetrics.getGrade())
.totalIssues(codacyMetrics.getTotalIssues())
.newIssues(codacyMetrics.getNewIssues())
.coveragePercentage(codacyMetrics.getCoverage())
.complexity(codacyMetrics.getComplexity())
.duplicationPercentage(codacyMetrics.getDuplication())
.securityIssues(codacyMetrics.getSecurityIssues())
.build();
}
/**
* Check if quality gates are passing.
*
* @return quality gate status
*/
public QualityGateStatus checkQualityGates() {
final QualityMetrics metrics = getCurrentMetrics();
final QualityThresholds thresholds = getQualityThresholds();
return QualityGateStatus.builder()
.codeQualityPassed(metrics.getCodeQualityGrade()
.compareTo(thresholds.getMinGrade()) >= 0)
.coveragePassed(metrics.getCoveragePercentage() >= thresholds.getMinCoverage())
.securityPassed(metrics.getSecurityIssues() <= thresholds.getMaxSecurityIssues())
.complexityPassed(metrics.getComplexity() <= thresholds.getMaxComplexity())
.build();
}
}
10. Team Quality Standards
Team Quality Guidelines
# Team Quality Standards ## Code Quality Requirements - Minimum Code Quality Grade: B - Maximum New Issues per PR: 5 - Maximum Security Issues: 3 (0 critical) - Minimum Test Coverage: 80% ## Security Requirements - No critical security vulnerabilities - High security issues must be fixed within 24 hours - Regular dependency vulnerability scanning ## Performance Requirements - Method complexity < 15 - File complexity < 200 - Cyclomatic complexity < 10 ## Documentation Requirements - All public methods must be documented - Minimum documentation rate: 70% - README files for all modules ## Review Process 1. All PRs must pass quality gates 2. Security review for sensitive changes 3. Performance review for critical paths 4. Documentation review for public APIs
Best Practices
1. Incremental Quality Improvement
# Start with basic thresholds and gradually improve quality_evolution: phase_1: min_grade: C min_coverage: 70 max_issues: 100 phase_2: min_grade: B min_coverage: 75 max_issues: 50 phase_3: min_grade: A min_coverage: 80 max_issues: 25
2. Team-Specific Configurations
team_configurations: backend_team: focus_areas: - "performance" - "security" - "database" rules: - "sql_injection" - "performance_optimization" frontend_team: focus_areas: - "ui_ux" - "accessibility" - "browser_compatibility" mobile_team: focus_areas: - "memory_management" - "battery_optimization" - "network_efficiency"
3. Quality Metrics Tracking
public class QualityMetricsTracker {
public void trackQualityTrends() {
// Track quality metrics over time
// Alert on degradation
// Report on improvement areas
}
}
Conclusion
This comprehensive Codacy configuration provides:
- Automated code quality analysis with multiple tools
- Continuous quality monitoring integrated into CI/CD
- Security vulnerability detection with actionable insights
- Test coverage tracking with enforcement thresholds
- Team quality standards with clear guidelines
- Quality gates for pull request validation
Key benefits:
- Consistent code quality across the organization
- Early issue detection before production
- Security compliance through automated scanning
- Team productivity with automated code reviews
- Quality metrics for continuous improvement
The setup enables organizations to maintain high code quality standards while scaling development teams and codebases efficiently.