diff --git a/.changeset/orange-brooms-lick.md b/.changeset/orange-brooms-lick.md new file mode 100644 index 0000000000..8336ef602a --- /dev/null +++ b/.changeset/orange-brooms-lick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-openapi': patch +--- + +Fix resolveUrl for splited openapi definition relative path diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index a6266a8bf3..9ae3692e80 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -49,6 +49,7 @@ "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", + "@backstage/config": "workspace:^", "openapi-types": "^12.0.0" } } diff --git a/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts b/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts index ec77610733..4cf3864aeb 100644 --- a/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts +++ b/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { bundleFileWithRefs } from './bundle'; +import { bundleFileWithRefs, BundlerRead, BundlerResolveUrl } from './bundle'; +import { ScmIntegrations } from '@backstage/integration'; +import { ConfigReader } from '@backstage/config'; const specification = ` openapi: "3.0.0" @@ -178,3 +180,153 @@ channels: expect(result).toEqual(expectedSchema.trimStart()); }); }); + +describe('bundleFileWithRefs - Testing getRelativePath scenarios', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + const scmIntegrations = ScmIntegrations.fromConfig(new ConfigReader({})); + + const resolveUrl: BundlerResolveUrl = jest.fn( + (url: string, base: string): string => { + return scmIntegrations.resolveUrl({ url, base }); + }, + ); + + const read: BundlerRead = jest.fn(async (url: string) => { + return Buffer.from(url); + }); + + const baseUrl = + 'https://dev.azure.com/organization/project/_git/idp-configurations?path=%2Frepo%2Ftest-openapi.yaml&version=GBmaster'; + + it('should handle the relative path when refUrl has the same base as baseUrl', async () => { + const fileWithRefs = ` +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + $ref: "common.yaml" +`; + + const relativePath = 'common.yaml'; + const expectedUrl = + 'https://dev.azure.com/organization/project/_git/idp-configurations?path=%2Frepo%2Fcommon.yaml&version=GBmaster'; + + await bundleFileWithRefs(fileWithRefs, baseUrl, read, resolveUrl); + + expect(resolveUrl).toHaveBeenCalledWith(relativePath, baseUrl); + expect(read).toHaveBeenCalledWith(expectedUrl); + }); + + it('should handle the relative path, with subdir, when refUrl has the same base as baseUrl', async () => { + const fileWithRefs = ` +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + $ref: "commons/common.yaml" +`; + + const relativePath = 'commons/common.yaml'; + const expectedUrl = + 'https://dev.azure.com/organization/project/_git/idp-configurations?path=%2Frepo%2Fcommons%2Fcommon.yaml&version=GBmaster'; + + await bundleFileWithRefs(fileWithRefs, baseUrl, read, resolveUrl); + + expect(resolveUrl).toHaveBeenCalledWith(relativePath, baseUrl); + expect(read).toHaveBeenCalledWith(expectedUrl); + }); + + it('should handle the entire refUrl when there is no common base', async () => { + const fileWithRef = ` +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + $ref: "https://example.com/commons/common.yaml" +`; + + const refUrl = 'https://example.com/commons/common.yaml'; + + await bundleFileWithRefs(fileWithRef, baseUrl, read, resolveUrl); + + expect(resolveUrl).toHaveBeenCalledWith(refUrl, baseUrl); + expect(read).toHaveBeenCalledWith(refUrl); + }); + + it('should handle the relative path when refUrl has a different subdir', async () => { + const fileWithRefs = ` +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + $ref: "../commons/common.yaml" +`; + + const exampleBaseUrl = + 'https://example.com/path/to/definition/test-openapi.yaml.yaml'; + const relativePath = '../commons/common.yaml'; + const expectedUrl = 'https://example.com/path/to/commons/common.yaml'; + + await bundleFileWithRefs(fileWithRefs, exampleBaseUrl, read, resolveUrl); + + expect(resolveUrl).toHaveBeenCalledWith(relativePath, exampleBaseUrl); + expect(read).toHaveBeenCalledWith(expectedUrl); + }); + + it('should handle the relative path when refUrl has a different subdir (azure)', async () => { + const fileWithRefs = ` +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + $ref: "../commons/common.yaml" +`; + + const relativePath = '../commons/common.yaml'; + const expectedUrl = + 'https://dev.azure.com/organization/project/_git/idp-configurations?path=%2Fcommons%2Fcommon.yaml&version=GBmaster'; + + await bundleFileWithRefs(fileWithRefs, baseUrl, read, resolveUrl); + + expect(resolveUrl).toHaveBeenCalledWith(relativePath, baseUrl); + expect(read).toHaveBeenCalledWith(expectedUrl); + }); +}); diff --git a/plugins/catalog-backend-module-openapi/src/lib/bundle.ts b/plugins/catalog-backend-module-openapi/src/lib/bundle.ts index b2b186dff1..32dac30681 100644 --- a/plugins/catalog-backend-module-openapi/src/lib/bundle.ts +++ b/plugins/catalog-backend-module-openapi/src/lib/bundle.ts @@ -69,6 +69,6 @@ export async function bundleFileWithRefs( }, }; const fileObject = parse(fileWithRefs); - const bundledObject = await $RefParser.bundle(baseUrl, fileObject, options); + const bundledObject = await $RefParser.bundle(fileObject, options); return stringify(bundledObject); } diff --git a/yarn.lock b/yarn.lock index f40ec341af..141d30e5e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6150,6 +6150,7 @@ __metadata: "@backstage/backend-test-utils": "workspace:^" "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^"