diff --git a/.changeset/lovely-pants-battle.md b/.changeset/lovely-pants-battle.md new file mode 100644 index 0000000000..f0d8f7e002 --- /dev/null +++ b/.changeset/lovely-pants-battle.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-fossa': patch +--- + +Request a sorted response list to select the project with the correct title. The FOSSA API +matches title searches with "starts with" so previously it used the response for `my-project-part` +if you searched for `my-project`. diff --git a/plugins/fossa/src/api/FossaClient.test.ts b/plugins/fossa/src/api/FossaClient.test.ts index c01dd09327..dd0fdeff5e 100644 --- a/plugins/fossa/src/api/FossaClient.test.ts +++ b/plugins/fossa/src/api/FossaClient.test.ts @@ -37,12 +37,13 @@ describe('FossaClient', () => { server.use( rest.get(`${mockBaseUrl}/fossa/projects`, (req, res, ctx) => { expect(req.url.searchParams.toString()).toBe( - 'count=1&title=our-service&organizationId=8736', + 'count=1&sort=title+&title=our-service&organizationId=8736', ); return res( ctx.json([ { locator: 'custom+8736/our-service', + title: 'our-service', default_branch: 'develop', revisions: [ { @@ -73,12 +74,13 @@ describe('FossaClient', () => { server.use( rest.get(`${mockBaseUrl}/fossa/projects`, (req, res, ctx) => { expect(req.url.searchParams.toString()).toBe( - 'count=1&title=our-service&organizationId=8736', + 'count=1&sort=title+&title=our-service&organizationId=8736', ); return res( ctx.json([ { locator: 'custom+8736/our-service', + title: 'our-service', default_branch: 'refs/master', revisions: [ { @@ -104,13 +106,43 @@ describe('FossaClient', () => { } as FindingSummary); }); + it('should handle empty result', async () => { + server.use( + rest.get(`${mockBaseUrl}/fossa/projects`, (req, res, ctx) => { + expect(req.url.searchParams.toString()).toBe( + 'count=1&sort=title+&title=our-service&organizationId=8736', + ); + return res(ctx.json([])); + }), + ); + + const summary = await client.getFindingSummary('our-service'); + + expect(summary).toBeUndefined(); + }); + + it('should ignore result with invalid title', async () => { + server.use( + rest.get(`${mockBaseUrl}/fossa/projects`, (req, res, ctx) => { + expect(req.url.searchParams.toString()).toBe( + 'count=1&sort=title+&title=our-service&organizationId=8736', + ); + return res(ctx.json([{ title: 'our-service-2' }])); + }), + ); + + const summary = await client.getFindingSummary('our-service'); + + expect(summary).toBeUndefined(); + }); + it('should skip organizationId', async () => { client = new FossaClient({ discoveryApi }); server.use( rest.get(`${mockBaseUrl}/fossa/projects`, (req, res, ctx) => { expect(req.url.searchParams.toString()).toBe( - 'count=1&title=our-service', + 'count=1&sort=title+&title=our-service', ); return res(ctx.status(404)); }), @@ -125,7 +157,7 @@ describe('FossaClient', () => { server.use( rest.get(`${mockBaseUrl}/fossa/projects`, (req, res, ctx) => { expect(req.url.searchParams.toString()).toBe( - 'count=1&title=our-service&organizationId=8736', + 'count=1&sort=title+&title=our-service&organizationId=8736', ); return res(ctx.status(404)); }), diff --git a/plugins/fossa/src/api/FossaClient.ts b/plugins/fossa/src/api/FossaClient.ts index 10f688393b..05a889177a 100644 --- a/plugins/fossa/src/api/FossaClient.ts +++ b/plugins/fossa/src/api/FossaClient.ts @@ -46,11 +46,12 @@ export class FossaClient implements FossaApi { projectTitle: string, ): Promise { const project = await this.callApi( - `projects?count=1&title=${projectTitle}${ + `projects?count=1&sort=title+&title=${projectTitle}${ this.organizationId ? `&organizationId=${this.organizationId}` : '' }`, ); - if (!project) { + + if (!project || project.length === 0 || project[0].title !== projectTitle) { return undefined; }