<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>io.github.a-simeshin</groupId>
    <artifactId>spring-ai-mcp-inspector-parent</artifactId>
    <version>2.0.0</version>
    <packaging>pom</packaging>

    <name>spring-ai-mcp-inspector-parent</name>
    <description>Parent POM for Spring AI MCP Inspector — embeddable inspector UI for Spring AI MCP servers.</description>
    <url>https://github.com/a-simeshin/spring-ai-mcp-inspector</url>

    <licenses>
        <license>
            <name>Apache License, Version 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
            <distribution>repo</distribution>
        </license>
    </licenses>

    <developers>
        <developer>
            <id>a-simeshin</id>
            <name>Artem Simeshin</name>
            <url>https://github.com/a-simeshin</url>
        </developer>
    </developers>

    <scm>
        <connection>scm:git:https://github.com/a-simeshin/spring-ai-mcp-inspector.git</connection>
        <developerConnection>scm:git:ssh://git@github.com/a-simeshin/spring-ai-mcp-inspector.git</developerConnection>
        <url>https://github.com/a-simeshin/spring-ai-mcp-inspector</url>
        <tag>HEAD</tag>
    </scm>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <maven.compiler.release>17</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <spring-boot.version>4.1.0</spring-boot.version>
        <spring-ai.version>2.0.0</spring-ai.version>
        <!-- MCP Java SDK is BOM-managed by spring-ai-bom 2.0.0 (mcp 2.0.0). Do NOT pin it
             here: an explicit override would drag the SDK two majors behind the BOM and
             silently reintroduce 0.18 APIs. -->
        <!-- mcp-sdk.version intentionally removed; managed by spring-ai-bom -->


        <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
        <maven-surefire-plugin.version>3.5.0</maven-surefire-plugin.version>
        <maven-failsafe-plugin.version>3.5.0</maven-failsafe-plugin.version>
        <spring-javaformat-maven-plugin.version>0.0.47</spring-javaformat-maven-plugin.version>
        <jacoco-maven-plugin.version>0.8.15</jacoco-maven-plugin.version>

        <!-- Maven Central release tooling (activated by the `release` profile).
             Versions kept in lockstep with the sibling spring-ai-ragas release setup. -->
        <maven-source-plugin.version>3.4.0</maven-source-plugin.version>
        <maven-javadoc-plugin.version>3.12.0</maven-javadoc-plugin.version>
        <maven-gpg-plugin.version>3.2.8</maven-gpg-plugin.version>
        <central-publishing-maven-plugin.version>0.9.0</central-publishing-maven-plugin.version>

        <!-- Checkstyle: the classic Spring ruleset (io.spring.javaformat.checkstyle.SpringChecks)
             plus FinalLocalVariable, gated at the validate phase. checkstyle.version must match
             what spring-javaformat-checkstyle 0.0.47 was built against (Checkstyle 10.x). -->
        <maven-checkstyle-plugin.version>3.6.0</maven-checkstyle-plugin.version>
        <checkstyle.version>10.21.4</checkstyle.version>

        <!-- SpotBugs static analysis: effort=Max / threshold=Medium, gated at the
             verify phase (needs compiled bytecode). spotbugs.version pins the core
             engine to the same train as the plugin wrapper. demo/ui opt out via
             <spotbugs.skip>true</spotbugs.skip>. -->
        <spotbugs-maven-plugin.version>4.9.3.0</spotbugs-maven-plugin.version>
        <spotbugs.version>4.9.3</spotbugs.version>
        <spotbugs.skip>false</spotbugs.skip>

        <!-- Allure test reporting. allure.version: latest stable Allure 2.x (known-good
             recent release). aspectj.version MUST match the aspectjweaver version managed
             by spring-boot-dependencies (3.5.15 → 1.9.25.1) so the -javaagent jar path on
             surefire/failsafe argLine resolves to a real jar in the local repository. -->
        <allure.version>2.29.1</allure.version>
        <aspectj.version>1.9.25.1</aspectj.version>
        <allure-maven-plugin.version>2.15.2</allure-maven-plugin.version>

        <!-- JaCoCo coverage gate (Surefire only — IT/E2E run under Failsafe
             and do not contribute). Override per-module to relax or skip. -->
        <jacoco.line.minimum>0.80</jacoco.line.minimum>
        <jacoco.branch.minimum>0.80</jacoco.branch.minimum>
        <jacoco.instruction.minimum>0.80</jacoco.instruction.minimum>
        <jacoco.skip>false</jacoco.skip>
    </properties>

    <modules>
        <module>spring-ai-mcp-inspector-core</module>
        <module>spring-ai-mcp-inspector-ui</module>
        <module>spring-ai-mcp-inspector-starter-webmvc</module>
        <module>spring-ai-mcp-inspector-starter-webflux</module>
        <module>spring-ai-mcp-inspector-demo</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- MCP Java SDK BOM. spring-ai-bom does NOT manage the raw SDK
                 (io.modelcontextprotocol.sdk:mcp-core / mcp-json-*), only the Spring
                 transports, so we import the SDK BOM to version mcp-core + the Jackson2
                 binding directly. The SDK version tracks Spring AI's train (2.0.0). -->
            <dependency>
                <groupId>io.modelcontextprotocol.sdk</groupId>
                <artifactId>mcp-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Allure BOM: aligns allure-junit5 (and any other allure-*) versions
                 so module poms can omit explicit versions. -->
            <dependency>
                <groupId>io.qameta.allure</groupId>
                <artifactId>allure-bom</artifactId>
                <version>${allure.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>${maven-compiler-plugin.version}</version>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                        <release>${maven.compiler.release}</release>
                        <!-- Required for Spring AI MCP annotations (mcp-annotations 0.9.0)
                             to bind JSON-RPC `arguments.X` to method parameters by name.
                             Without this, every @McpToolParam parameter arrives as null
                             because reflection sees arg0/arg1 instead of declared names. -->
                        <parameters>true</parameters>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>${maven-surefire-plugin.version}</version>
                    <configuration>
                        <!-- `@{surefireArgLine}` (set by jacoco prepare-agent-unit) MUST stay
                             first so the JaCoCo agent records unit coverage; the aspectjweaver
                             javaagent for Allure @Step is appended after it. -->
                        <argLine>@{surefireArgLine} -XX:+EnableDynamicAgentLoading -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"</argLine>
                        <includes>
                            <include>**/*Tests.java</include>
                        </includes>
                        <excludes>
                            <exclude>**/*IT.java</exclude>
                            <exclude>**/*E2ETest.java</exclude>
                        </excludes>
                        <systemPropertyVariables>
                            <allure.results.directory>${project.build.directory}/allure-results</allure.results.directory>
                        </systemPropertyVariables>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-failsafe-plugin</artifactId>
                    <version>${maven-failsafe-plugin.version}</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>integration-test</goal>
                                <goal>verify</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <!-- `@{failsafeArgLine}` (set by jacoco prepare-agent-it) MUST stay
                             first so the JaCoCo agent records IT coverage; the aspectjweaver
                             javaagent for Allure @Step is appended after it. -->
                        <argLine>@{failsafeArgLine} -XX:+EnableDynamicAgentLoading -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"</argLine>
                        <includes>
                            <include>**/*IT.java</include>
                            <include>**/*E2ETest.java</include>
                        </includes>
                        <systemPropertyVariables>
                            <allure.results.directory>${project.build.directory}/allure-results</allure.results.directory>
                        </systemPropertyVariables>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.jacoco</groupId>
                    <artifactId>jacoco-maven-plugin</artifactId>
                    <version>${jacoco-maven-plugin.version}</version>
                    <configuration>
                        <skip>${jacoco.skip}</skip>
                        <!-- Coverage gate applies to production logic only.
                             Excluded: framework glue (autoconfig, config props),
                             pure data carriers (records/POJOs in dto/oauth/bootstrap
                             leaves) and exception types. -->
                        <excludes>
                            <exclude>**/*AutoConfiguration*</exclude>
                            <exclude>io/inspector/mcp/**/config/**</exclude>
                            <exclude>io/inspector/mcp/**/dto/**</exclude>
                            <exclude>io/inspector/mcp/**/oauth/OAuth*Request*</exclude>
                            <exclude>io/inspector/mcp/**/oauth/OAuth*Response*</exclude>
                            <exclude>io/inspector/mcp/**/transport/DetectedTransport*</exclude>
                            <exclude>io/inspector/mcp/**/bootstrap/CustomHeader*</exclude>
                            <exclude>io/inspector/mcp/**/bootstrap/ServerEntry*</exclude>
                            <exclude>io/inspector/mcp/**/bootstrap/InspectorBootstrap.class</exclude>
                            <exclude>io/inspector/mcp/**/bootstrap/InspectorBootstrap$*.class</exclude>
                            <exclude>**/exception/**</exclude>
                            <exclude>**/*Exception.class</exclude>
                        </excludes>
                    </configuration>
                    <executions>
                        <!-- Surefire agent → target/jacoco-unit.exec.
                             Coverage gate reads this file only. -->
                        <execution>
                            <id>prepare-agent-unit</id>
                            <goals>
                                <goal>prepare-agent</goal>
                            </goals>
                            <configuration>
                                <destFile>${project.build.directory}/jacoco-unit.exec</destFile>
                                <propertyName>surefireArgLine</propertyName>
                            </configuration>
                        </execution>
                        <!-- Failsafe agent → target/jacoco-it.exec.
                             Recorded for diagnostics; NOT considered by the gate. -->
                        <execution>
                            <id>prepare-agent-it</id>
                            <goals>
                                <goal>prepare-agent-integration</goal>
                            </goals>
                            <configuration>
                                <destFile>${project.build.directory}/jacoco-it.exec</destFile>
                                <propertyName>failsafeArgLine</propertyName>
                            </configuration>
                        </execution>
                        <!-- Unit-only HTML/XML report after Surefire. -->
                        <execution>
                            <id>report-unit</id>
                            <phase>test</phase>
                            <goals>
                                <goal>report</goal>
                            </goals>
                            <configuration>
                                <dataFile>${project.build.directory}/jacoco-unit.exec</dataFile>
                                <outputDirectory>${project.build.directory}/site/jacoco</outputDirectory>
                            </configuration>
                        </execution>
                        <!-- Hard coverage gate, Surefire only. -->
                        <execution>
                            <id>check</id>
                            <phase>verify</phase>
                            <goals>
                                <goal>check</goal>
                            </goals>
                            <configuration>
                                <dataFile>${project.build.directory}/jacoco-unit.exec</dataFile>
                                <rules>
                                    <rule>
                                        <element>BUNDLE</element>
                                        <limits>
                                            <limit>
                                                <counter>LINE</counter>
                                                <value>COVEREDRATIO</value>
                                                <minimum>${jacoco.line.minimum}</minimum>
                                            </limit>
                                            <limit>
                                                <counter>BRANCH</counter>
                                                <value>COVEREDRATIO</value>
                                                <minimum>${jacoco.branch.minimum}</minimum>
                                            </limit>
                                            <limit>
                                                <counter>INSTRUCTION</counter>
                                                <value>COVEREDRATIO</value>
                                                <minimum>${jacoco.instruction.minimum}</minimum>
                                            </limit>
                                        </limits>
                                    </rule>
                                </rules>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>io.spring.javaformat</groupId>
                    <artifactId>spring-javaformat-maven-plugin</artifactId>
                    <version>${spring-javaformat-maven-plugin.version}</version>
                    <executions>
                        <execution>
                            <phase>validate</phase>
                            <inherited>true</inherited>
                            <goals>
                                <goal>validate</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <!-- Checkstyle: classic Spring ruleset (SpringChecks) + FinalLocalVariable.
                     Config in config/checkstyle/. Bound to validate in the active <plugins>
                     below; demo/ui opt out via <checkstyle.skip>true</checkstyle.skip>. -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-checkstyle-plugin</artifactId>
                    <version>${maven-checkstyle-plugin.version}</version>
                    <dependencies>
                        <dependency>
                            <groupId>com.puppycrawl.tools</groupId>
                            <artifactId>checkstyle</artifactId>
                            <version>${checkstyle.version}</version>
                        </dependency>
                        <dependency>
                            <groupId>io.spring.javaformat</groupId>
                            <artifactId>spring-javaformat-checkstyle</artifactId>
                            <version>${spring-javaformat-maven-plugin.version}</version>
                        </dependency>
                    </dependencies>
                    <configuration>
                        <configLocation>${maven.multiModuleProjectDirectory}/config/checkstyle/checkstyle.xml</configLocation>
                        <suppressionsLocation>${maven.multiModuleProjectDirectory}/config/checkstyle/checkstyle-suppressions.xml</suppressionsLocation>
                        <includeTestSourceDirectory>true</includeTestSourceDirectory>
                        <propertyExpansion>config_loc=${maven.multiModuleProjectDirectory}/config/checkstyle</propertyExpansion>
                        <failOnViolation>true</failOnViolation>
                        <violationSeverity>warning</violationSeverity>
                        <consoleOutput>true</consoleOutput>
                    </configuration>
                    <executions>
                        <execution>
                            <id>checkstyle-validation</id>
                            <phase>validate</phase>
                            <inherited>true</inherited>
                            <goals>
                                <goal>check</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <!-- SpotBugs: bytecode static analysis. Bound to verify (after
                     compile) in the active <plugins> below; demo/ui opt out via
                     <spotbugs.skip>true</spotbugs.skip>. Filter in config/spotbugs/. -->
                <plugin>
                    <groupId>com.github.spotbugs</groupId>
                    <artifactId>spotbugs-maven-plugin</artifactId>
                    <version>${spotbugs-maven-plugin.version}</version>
                    <dependencies>
                        <dependency>
                            <groupId>com.github.spotbugs</groupId>
                            <artifactId>spotbugs</artifactId>
                            <version>${spotbugs.version}</version>
                        </dependency>
                    </dependencies>
                    <configuration>
                        <skip>${spotbugs.skip}</skip>
                        <!-- Max effort, Medium confidence: the Spring-convention
                             balance — catches real defects without low-confidence noise. -->
                        <effort>Max</effort>
                        <threshold>Medium</threshold>
                        <failOnError>true</failOnError>
                        <!-- Production code only; tests use reflection/mocks that
                             trip many false positives. -->
                        <includeTests>false</includeTests>
                        <excludeFilterFile>${maven.multiModuleProjectDirectory}/config/spotbugs/spotbugs-exclude.xml</excludeFilterFile>
                        <xmlOutput>true</xmlOutput>
                    </configuration>
                    <executions>
                        <execution>
                            <id>spotbugs-check</id>
                            <phase>verify</phase>
                            <inherited>true</inherited>
                            <goals>
                                <goal>check</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <!-- Allure: generates the HTML report from target/allure-results
                     (produced by surefire/failsafe via the allure-junit5 listener). -->
                <plugin>
                    <groupId>io.qameta.allure</groupId>
                    <artifactId>allure-maven</artifactId>
                    <version>${allure-maven-plugin.version}</version>
                    <configuration>
                        <reportVersion>${allure.version}</reportVersion>
                        <resultsDirectory>${project.build.directory}/allure-results</resultsDirectory>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <!-- Failsafe is declared at the parent level so every module's `verify`
                 phase runs **/*IT.java tests. Configuration lives in pluginManagement above. -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
            </plugin>
            <!-- Spring Java Format runs at validate phase across every module.
                 Matches the convention used by spring-ai-community siblings
                 (spring-ai-a2a, mcp-annotations, mcp-security). -->
            <plugin>
                <groupId>io.spring.javaformat</groupId>
                <artifactId>spring-javaformat-maven-plugin</artifactId>
            </plugin>
            <!-- Checkstyle gate at validate phase (after javaformat). Classic Spring
                 ruleset + mandatory `final` on non-reassigned locals/parameters.
                 Configuration lives in pluginManagement above. -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-checkstyle-plugin</artifactId>
            </plugin>
            <!-- JaCoCo: agent on Surefire, report on `test`, hard gate on `verify`.
                 Demo and UI modules opt out via `<jacoco.skip>true` in their poms. -->
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
            </plugin>
            <!-- SpotBugs gate at the verify phase. effort=Max / threshold=Medium.
                 Demo and UI modules opt out via `<spotbugs.skip>true` in their poms.
                 Configuration lives in pluginManagement above. -->
            <plugin>
                <groupId>com.github.spotbugs</groupId>
                <artifactId>spotbugs-maven-plugin</artifactId>
            </plugin>
            <!-- Allure report generation (`mvn allure:report` / `allure:serve`).
                 Configuration lives in pluginManagement above. -->
            <plugin>
                <groupId>io.qameta.allure</groupId>
                <artifactId>allure-maven</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>central</id>
            <name>Maven Central</name>
            <url>https://repo.maven.apache.org/maven2</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <profiles>
        <!-- Maven Central release profile. Activate with `-Prelease` (the GitHub
             Actions release workflow does this). Adds the sources + javadoc jars,
             GPG signing of every artifact, and the Sonatype Central Portal deploy.
             Kept out of the default build so day-to-day `mvn verify` needs no GPG key. -->
        <profile>
            <id>release</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-source-plugin</artifactId>
                        <version>${maven-source-plugin.version}</version>
                        <executions>
                            <execution>
                                <id>attach-sources</id>
                                <goals>
                                    <goal>jar-no-fork</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-javadoc-plugin</artifactId>
                        <version>${maven-javadoc-plugin.version}</version>
                        <configuration>
                            <!-- Central requires the jar to exist; do not fail the
                                 release on Java 17 doclint warnings. -->
                            <doclint>none</doclint>
                            <quiet>true</quiet>
                        </configuration>
                        <executions>
                            <execution>
                                <id>attach-javadocs</id>
                                <goals>
                                    <goal>jar</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-gpg-plugin</artifactId>
                        <version>${maven-gpg-plugin.version}</version>
                        <executions>
                            <execution>
                                <id>sign-artifacts</id>
                                <phase>verify</phase>
                                <goals>
                                    <goal>sign</goal>
                                </goals>
                                <configuration>
                                    <!-- Loopback lets the passphrase come from
                                         settings.xml / env without an interactive pinentry. -->
                                    <gpgArguments>
                                        <arg>--pinentry-mode</arg>
                                        <arg>loopback</arg>
                                    </gpgArguments>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>org.sonatype.central</groupId>
                        <artifactId>central-publishing-maven-plugin</artifactId>
                        <version>${central-publishing-maven-plugin.version}</version>
                        <extensions>true</extensions>
                        <configuration>
                            <!-- `central` is the <server> id holding the Central Portal
                                 token in settings.xml. -->
                            <publishingServerId>central</publishingServerId>
                            <autoPublish>true</autoPublish>
                            <waitUntil>published</waitUntil>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

</project>
