Skip to content

fix(MergedSpecBuilder): merge path items by HTTP method instead of overwriting on path collision#24100

Draft
Picazsoo wants to merge 20 commits into
OpenAPITools:masterfrom
Picazsoo:feature/merge-specs
Draft

fix(MergedSpecBuilder): merge path items by HTTP method instead of overwriting on path collision#24100
Picazsoo wants to merge 20 commits into
OpenAPITools:masterfrom
Picazsoo:feature/merge-specs

Conversation

@Picazsoo

@Picazsoo Picazsoo commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Summary by cubic

Improves multi-spec merging with a new DEEP mode that merges path items by HTTP method and detects conflicts. Keeps REF mode as the original $ref index merge, and adds explicit ordered file merging across CLI, Gradle, and Maven.

  • Bug Fixes

    • Merge path items by HTTP method on path collisions; duplicate path+method conflicts are detected in DEEP and handled by mergeConflictStrategy (WARN keeps first, FAIL aborts); REF keeps the last definition.
    • Preserve path-level parameters and x- vendor extensions; merge top-level x- extensions (first wins).
    • Dedupe server URLs; add http://localhost:8080 if none.
    • Process only .yaml, .yml, .json in deterministic order; ignore other files; choose JSON if the first valid spec is JSON.
  • New Features

    • Add mergeMode (REF, DEEP) and mergeConflictStrategy (WARN, FAIL) in CLI (--merge-mode, --merge-conflict-strategy), Gradle (mergeMode, mergeConflictStrategy), and Maven (mergeMode, mergeConflictStrategy); invalid values fail fast.
    • Support an explicit ordered list of spec files to merge across CLI (--input-spec-files with --merged-file-output-dir), Gradle (inputSpecFiles, mergedFileOutputDir), and Maven (inputSpecFiles, mergedFileOutputDir); order is respected and overrides directory scanning.
    • Add merged spec Info fields on all three (mergedFileInfoName, mergedFileInfoDescription, mergedFileInfoVersion); Gradle also adds mergedFileName (defaults to merged).

Written for commit 13baea2. Summary will update on new commits.

Review in cubic

@Picazsoo Picazsoo marked this pull request as ready for review June 30, 2026 11:00
@Picazsoo Picazsoo marked this pull request as draft June 30, 2026 11:01

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found and verified against the latest diff

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

@Picazsoo Picazsoo marked this pull request as ready for review June 30, 2026 13:43
@Picazsoo Picazsoo marked this pull request as draft June 30, 2026 13:44

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 17 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/main/java/org/openapitools/codegen/config/MergedSpecBuilder.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/config/MergedSpecBuilder.java:356">
P1: Deep merge path+method conflict detection is unconditional: it treats any duplicate method as a conflict without comparing whether the incoming operation is identical to the existing one. In FAIL mode this throws RuntimeException even for identical operations, which is inconsistent with component merging (where identical duplicates are silently deduplicated via Objects.equals) and contradicts documented intent of only warning on "different definitions".</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

return;
}
incoming.readOperationsMap().forEach((method, operation) -> {
if (existing.readOperationsMap() != null && existing.readOperationsMap().containsKey(method)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Deep merge path+method conflict detection is unconditional: it treats any duplicate method as a conflict without comparing whether the incoming operation is identical to the existing one. In FAIL mode this throws RuntimeException even for identical operations, which is inconsistent with component merging (where identical duplicates are silently deduplicated via Objects.equals) and contradicts documented intent of only warning on "different definitions".

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/java/org/openapitools/codegen/config/MergedSpecBuilder.java, line 356:

<comment>Deep merge path+method conflict detection is unconditional: it treats any duplicate method as a conflict without comparing whether the incoming operation is identical to the existing one. In FAIL mode this throws RuntimeException even for identical operations, which is inconsistent with component merging (where identical duplicates are silently deduplicated via Objects.equals) and contradicts documented intent of only warning on "different definitions".</comment>

<file context>
@@ -99,51 +186,238 @@ public String buildMergedSpec() {
+            return;
+        }
+        incoming.readOperationsMap().forEach((method, operation) -> {
+            if (existing.readOperationsMap() != null && existing.readOperationsMap().containsKey(method)) {
+                String message = String.format(Locale.ROOT,
+                        "Path+method collision during spec merge: %s %s is defined in multiple specs with different definitions. Keeping the first definition.",
</file context>

@Picazsoo Picazsoo Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is on purpose - schema reuse across multiple specs (e.g. sharing from some common-schemas.yaml file is expected and the merging should be able to handle that. Having POST operation defined for the same path in multiple specs is unexpected. But having POST operation for a path and PUT operation for the same path in different specs is expected and handled correctly. The documentation now tries to explain it clearly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant