Skip to content

fix: improve join command servers handling #2133

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Conversation

RomanHotsiy
Copy link
Member

What/Why/How?

This pull request resolves an issue with the join command where it would incorrectly merge OpenAPI documents with different servers configurations, leading to a semantically invalid result.

The updated logic now handles server merging based on whether the input files share the same server definitions.

Reference

Resolves #2118

Testing

Check yourself

  • Code changed? - Tested with redoc (internal)
  • All new/updated code is covered with tests
  • New package installed? - Tested in different environments (browser/node)

Security

  • Security impact of change has been considered
  • Code follows company security practices and guidelines

@RomanHotsiy RomanHotsiy requested review from a team as code owners June 12, 2025 09:32
Copy link

changeset-bot bot commented Jun 12, 2025

🦋 Changeset detected

Latest commit: b49d76d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@redocly/cli Patch
@redocly/openapi-core Patch
@redocly/respect-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

github-actions bot commented Jun 12, 2025

Command Mean [ms] Min [ms] Max [ms] Relative
redocly lint packages/core/src/benchmark/benches/rebilly.yaml 944.3 ± 17.7 918.5 967.3 1.00
redocly-next lint packages/core/src/benchmark/benches/rebilly.yaml 1022.8 ± 39.6 980.4 1118.0 1.08 ± 0.05

@@ -5,6 +5,6 @@
"outDir": "lib"
},
"references": [{ "path": "../core" }, { "path": "../respect-core" }],
"include": ["src/**/*.ts"],
"include": ["src/**/*.ts", "src/__tests__/fixtures/join/documents.ts1"],
Copy link
Collaborator

Choose a reason for hiding this comment

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

documents.ts1 looks wrong.

@RomanHotsiy RomanHotsiy requested a review from tatomyr June 13, 2025 14:22
@@ -51,6 +61,10 @@ describe('handleJoin', () => {
);
});

afterEach(() => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are you sure you need this? We've configured Vitest to restore all mocks: https://github.com/Redocly/redocly-cli/blob/main/vitest.config.ts#L49. Isn't that enough?

Comment on lines +172 to +183
const firstDocServers = documents[0]?.parsed.servers;
const serversAreTheSame =
firstDocServers &&
documents.slice(1).every((doc) => {
// include only documents with paths
if (Object.keys(doc.parsed.paths || {}).length === 0) {
return true;
}
return doc.parsed.servers?.every((server: Oas3Server) =>
firstDocServers?.find((firstDocServer: Oas3Server) => firstDocServer.url === server.url)
);
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

A little bit easier to read for me (no magic numbers like 0 or 1 🙂):

Suggested change
const firstDocServers = documents[0]?.parsed.servers;
const serversAreTheSame =
firstDocServers &&
documents.slice(1).every((doc) => {
// include only documents with paths
if (Object.keys(doc.parsed.paths || {}).length === 0) {
return true;
}
return doc.parsed.servers?.every((server: Oas3Server) =>
firstDocServers?.find((firstDocServer: Oas3Server) => firstDocServer.url === server.url)
);
});
const [first, ...others] = documents ?? [];
const serversAreTheSame = others.every(({ parsed: { paths, servers } }) => {
// include only documents with paths
if (!paths || isEmptyObject(paths || {})) {
return true;
}
return servers?.every((server: Oas3Server) =>
first.parsed.servers?.find(({ url }: Oas3Server) => url === server.url)
);
})

@@ -335,7 +336,10 @@ describe('E2E', () => {

test.each(testDirNames)('test: %s', async (dir) => {
const testPath = join(__dirname, `join/${dir}`);
const args = getParams(indexEntryPoint, ['join', ...entrypoints]);
let args = getParams(indexEntryPoint, ['join', ...entrypoints]);
if (dir === 'three-files-one-without-servers') {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you move this to a separate describe/test? Or put a FIXME so I'll do that later. I try to avoid conditions in tests so they are easier to debug and maintain.

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.

Join produces valid yaml but invalid semantics
3 participants