diff --git a/.changeset/tiny-books-bathe.md b/.changeset/tiny-books-bathe.md new file mode 100644 index 0000000000..24da55e718 --- /dev/null +++ b/.changeset/tiny-books-bathe.md @@ -0,0 +1,7 @@ +--- +"@comet/cms-api": patch +--- + +`BuildsService`: Start all jobs that match the scope exactly + +Previously, the first job that matched the scope exactly would be started, and the rest would be ignored. This has been fixed so that all jobs that match the scope exactly are started. diff --git a/packages/api/cms-api/src/builds/builds.service.spec.ts b/packages/api/cms-api/src/builds/builds.service.spec.ts index 1854424d8a..6fe83e7cdc 100644 --- a/packages/api/cms-api/src/builds/builds.service.spec.ts +++ b/packages/api/cms-api/src/builds/builds.service.spec.ts @@ -27,6 +27,15 @@ const jobMainEnglish = { }, }; +const jobMainEnglish2 = { + metadata: { + name: "main-en-2", + annotations: { + [CONTENT_SCOPE_ANNOTATION]: '{"domain":"main","language":"en"}', + }, + }, +}; + const jobMainGerman = { metadata: { name: "main-de", @@ -62,6 +71,11 @@ describe("BuildsService", () => { await expect(service.getBuilderCronJobsToStart([{ domain: "main", language: "en" }])).resolves.toEqual([jobMainEnglish]); }); + it("should return two jobs if two jobs have the exact same scope", async () => { + mockedBuildTemplatesService.getAllBuilderCronJobs.mockResolvedValueOnce([jobMainEnglish, jobMainEnglish2]); + await expect(service.getBuilderCronJobsToStart([{ domain: "main", language: "en" }])).resolves.toEqual([jobMainEnglish, jobMainEnglish2]); + }); + it("should return multiple jobs for multiple exact matches", async () => { await expect( service.getBuilderCronJobsToStart([ diff --git a/packages/api/cms-api/src/builds/builds.service.ts b/packages/api/cms-api/src/builds/builds.service.ts index 46b1cc4e69..e3ffaefc36 100644 --- a/packages/api/cms-api/src/builds/builds.service.ts +++ b/packages/api/cms-api/src/builds/builds.service.ts @@ -157,7 +157,8 @@ export class BuildsService { const builderCronJobs = await this.buildTemplatesService.getAllBuilderCronJobs(); const getMatchingBuilderCronJobs = (scope: ContentScope) => { - const matchingCronJobs: V1CronJob[] = []; + const partiallyMatchingCronJobs: V1CronJob[] = []; + const exactlyMatchingCronJobs: V1CronJob[] = []; for (const cronJob of builderCronJobs) { const cronJobScope = this.kubernetesService.getContentScope(cronJob); @@ -169,22 +170,22 @@ export class BuildsService { // Exact match between job's scope and the scope with changes. if (Object.entries(cronJobScope).every(([key, value]) => (scope as Record)[key] === value)) { - return [cronJob]; + exactlyMatchingCronJobs.push(cronJob); } // Check if scopes match partially. For instance, a job's scope may be { "domain": "main" }, but the change was in // { "domain": "main", "language": "en" }. Or the job's scope may be { "domain": "main", "language": "en" }, but the change // was in { "domain": "main" }. In both cases, the job should still be started. if (Object.entries(cronJobScope).some(([key, value]) => (scope as Record)[key] === value)) { - matchingCronJobs.push(cronJob); + partiallyMatchingCronJobs.push(cronJob); } } - if (matchingCronJobs.length === 0) { + if (exactlyMatchingCronJobs.length === 0 && partiallyMatchingCronJobs.length === 0) { throw new Error(`Found changes in scope ${JSON.stringify(scope)} but no matching builder cron job!`); } - return matchingCronJobs; + return exactlyMatchingCronJobs.length > 0 ? exactlyMatchingCronJobs : partiallyMatchingCronJobs; }; const uniqueMatchingCronJobs = new Set();