From c3e0a06aa8572a7a1e22e6efe4a7cc3d28729a9b Mon Sep 17 00:00:00 2001 From: Joanna Zakrzewska <816004+Silhoue@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:37:39 +0100 Subject: [PATCH 1/3] feat(environment-templates): add latestOnly query param --- .../environment-template-installation.ts | 4 +- lib/common-types.ts | 1 + lib/create-environment-template-api.ts | 2 + lib/plain/common-types.ts | 1 + .../environment-template-integration.test.ts | 50 +++++++++++++------ .../create-environment-template-api.test.ts | 28 +++++++++++ 6 files changed, 68 insertions(+), 18 deletions(-) diff --git a/lib/adapters/REST/endpoints/environment-template-installation.ts b/lib/adapters/REST/endpoints/environment-template-installation.ts index 155ec6387f..c98beb0fbd 100644 --- a/lib/adapters/REST/endpoints/environment-template-installation.ts +++ b/lib/adapters/REST/endpoints/environment-template-installation.ts @@ -7,12 +7,12 @@ const apiPath = (organizationId: string, ...pathSegments: (number | string)[]) = export const getMany: RestEndpoint<'EnvironmentTemplateInstallation', 'getMany'> = ( http, - { organizationId, environmentTemplateId, spaceId, environmentId, ...paginationProps }, + { organizationId, environmentTemplateId, spaceId, environmentId, ...otherProps }, headers?: RawAxiosRequestHeaders, ) => raw.get(http, apiPath(organizationId, environmentTemplateId, 'template_installations'), { params: { - ...paginationProps, + ...otherProps, ...(environmentId && { 'environment.sys.id': environmentId }), ...(spaceId && { 'space.sys.id': spaceId }), }, diff --git a/lib/common-types.ts b/lib/common-types.ts index ec01fd13fc..2f631bef6a 100644 --- a/lib/common-types.ts +++ b/lib/common-types.ts @@ -1600,6 +1600,7 @@ export type MRActions = { environmentTemplateId: string organizationId: string spaceId?: string + latestOnly?: boolean } return: CursorPaginatedCollectionProp } diff --git a/lib/create-environment-template-api.ts b/lib/create-environment-template-api.ts index d192c4395f..07c61b5799 100644 --- a/lib/create-environment-template-api.ts +++ b/lib/create-environment-template-api.ts @@ -138,6 +138,7 @@ export function createEnvironmentTemplateApi(makeRequest: MakeRequest, organizat * Gets a collection of all installations for the environment template * @param [installationParams.spaceId] - Space ID to filter installations by space and environment * @param [installationParams.environmentId] - Environment ID to filter installations by space and environment + * @param [installationParams.latestOnly] - Boolean flag to only return the latest installation per environment * @return Promise for a collection of EnvironmentTemplateInstallations * ```javascript * const contentful = require('contentful-management') @@ -161,6 +162,7 @@ export function createEnvironmentTemplateApi(makeRequest: MakeRequest, organizat }: { spaceId?: string environmentId?: string + latestOnly?: boolean } & BasicCursorPaginationOptions = {}) { const raw = this.toPlainObject() as EnvironmentTemplateProps return makeRequest({ diff --git a/lib/plain/common-types.ts b/lib/plain/common-types.ts index 99ea0ed295..1573e766fb 100644 --- a/lib/plain/common-types.ts +++ b/lib/plain/common-types.ts @@ -220,6 +220,7 @@ export type PlainClientAPI = { environmentTemplateId: string organizationId: string spaceId?: string + latestOnly?: boolean }, headers?: RawAxiosRequestHeaders, ): Promise> diff --git a/test/integration/environment-template-integration.test.ts b/test/integration/environment-template-integration.test.ts index 223ca00f3a..bfc34347cf 100644 --- a/test/integration/environment-template-integration.test.ts +++ b/test/integration/environment-template-integration.test.ts @@ -17,7 +17,7 @@ import type { Space, } from '../../lib/export-types' -type InstallTemplate = () => Promise +type InstallTemplate = (versionsCount?: number) => Promise describe('Environment template API', () => { const client = defaultClient @@ -213,15 +213,15 @@ describe('Environment template API', () => { expect(installation.sys.id).toBe(installations[0].sys.id) }) - it('gets all installations of an environment template for an environment', async () => { - const installation = await installTemplate() + it('gets all installations of an environment template for a given environment', async () => { + const installation = await installTemplate(2) const template = await client.getEnvironmentTemplate({ organizationId: orgId, environmentTemplateId: installation.sys.template.sys.id, }) const { items: installations } = await template.getInstallations() - expect(installations).toHaveLength(1) + expect(installations).toHaveLength(2) expect(installation.sys.id).toBe(installations[0].sys.id) }) @@ -292,23 +292,41 @@ function createInstallTemplate({ environment: Environment createDraftTemplate: () => CreateEnvironmentTemplateProps }): InstallTemplate { - return async () => { - const template = await client.createEnvironmentTemplate(orgId, createDraftTemplate()) - const installation = await template.install({ - spaceId: space.sys.id, - environmentId: environment.sys.id, - installation: { - version: template.sys.version, - }, - }) - - expect(installation.sys.template.sys.id).toBe(template.sys.id) + return async (versionsCount: number = 1) => { + let template = await client.createEnvironmentTemplate(orgId, createDraftTemplate()) + let installation = await installNewTemplateVersion(client, space, environment, template) + + for (let i = 0; i < versionsCount; i++) { + template.name = 'Updated name for version ' + (i + 2) + template = await template.update() + installation = await installNewTemplateVersion(client, space, environment, template) + } - await waitForPendingInstallation(client, environment, template.sys.id) return installation } } +async function installNewTemplateVersion( + client: ClientAPI, + space: Space, + environment: Environment, + template: EnvironmentTemplate, +): Promise { + const installation = await template.install({ + spaceId: space.sys.id, + environmentId: environment.sys.id, + installation: { + version: template.sys.version, + }, + }) + + expect(installation.sys.template.sys.id).toBe(template.sys.id) + + await waitForPendingInstallation(client, environment, template.sys.id) + + return installation +} + async function enableSpace(client: ClientAPI, space: Space): Promise { const previousEnablements = await client.rawRequest({ method: 'get', diff --git a/test/unit/create-environment-template-api.test.ts b/test/unit/create-environment-template-api.test.ts index 735be6f19f..b852e6f8ae 100644 --- a/test/unit/create-environment-template-api.test.ts +++ b/test/unit/create-environment-template-api.test.ts @@ -146,6 +146,34 @@ describe('createEnvironmentTemplateApi', () => { }) }) + test('API call installations with latestOnly', async () => { + const installations = [ + environmentTemplateInstallationMock, + { + sys: { + ...environmentTemplateInstallationMock.sys, + space: makeLink('Space', 'anothermock-space-id'), + }, + }, + ] + + const { api, makeRequest } = setup(Promise.resolve({ items: installations })) + const [installation1, installation2] = (await api.getInstallations({ latestOnly: true })).items + expect(installation1.toPlainObject()).to.eql(installations[0]) + expect(installation2.toPlainObject()).to.eql(installations[1]) + expect(makeRequest).toHaveBeenCalledWith({ + entityType: 'EnvironmentTemplateInstallation', + action: 'getMany', + params: { + organizationId, + environmentTemplateId: environmentTemplateMock.sys.id, + spaceId: undefined, + environmentId: undefined, + query: { latestOnly: true }, + }, + }) + }) + test('API call validate', async () => { const version = 1 const { api, makeRequest } = setup(Promise.resolve(environmentTemplateValidationMock)) From 9b9d5cc1518113e13c73574268326f48734be1b5 Mon Sep 17 00:00:00 2001 From: Joanna Zakrzewska <816004+Silhoue@users.noreply.github.com> Date: Tue, 28 Oct 2025 18:03:32 +0100 Subject: [PATCH 2/3] test: add test --- .../environment-template-integration.test.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test/integration/environment-template-integration.test.ts b/test/integration/environment-template-integration.test.ts index bfc34347cf..4a5ad206f3 100644 --- a/test/integration/environment-template-integration.test.ts +++ b/test/integration/environment-template-integration.test.ts @@ -225,6 +225,18 @@ describe('Environment template API', () => { expect(installation.sys.id).toBe(installations[0].sys.id) }) + it('gets only the latest installation of an environment template for a given environment', async () => { + const installation = await installTemplate(2) + const template = await client.getEnvironmentTemplate({ + organizationId: orgId, + environmentTemplateId: installation.sys.template.sys.id, + }) + + const { items: installations } = await template.getInstallations({ latestOnly: true }) + expect(installations).toHaveLength(1) + expect(installation.sys.id).toBe(installations[0].sys.id) + }) + it('disconnects environment template', async () => { const installation = await installTemplate() const template = await client.getEnvironmentTemplate({ @@ -296,8 +308,8 @@ function createInstallTemplate({ let template = await client.createEnvironmentTemplate(orgId, createDraftTemplate()) let installation = await installNewTemplateVersion(client, space, environment, template) - for (let i = 0; i < versionsCount; i++) { - template.name = 'Updated name for version ' + (i + 2) + for (let version = 2; version <= versionsCount; version++) { + template.name = `Updated name for version ${version}` template = await template.update() installation = await installNewTemplateVersion(client, space, environment, template) } From b14073f05e340ff86352fb217860d3e3cc28dafe Mon Sep 17 00:00:00 2001 From: Joanna Zakrzewska <816004+Silhoue@users.noreply.github.com> Date: Tue, 28 Oct 2025 18:26:34 +0100 Subject: [PATCH 3/3] fix: pass latestOnly separately from query --- lib/create-environment-template-api.ts | 2 ++ test/unit/create-environment-template-api.test.ts | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/create-environment-template-api.ts b/lib/create-environment-template-api.ts index 07c61b5799..9bf39a64e3 100644 --- a/lib/create-environment-template-api.ts +++ b/lib/create-environment-template-api.ts @@ -158,6 +158,7 @@ export function createEnvironmentTemplateApi(makeRequest: MakeRequest, organizat getInstallations: function getEnvironmentTemplateInstallations({ spaceId, environmentId, + latestOnly, ...query }: { spaceId?: string @@ -174,6 +175,7 @@ export function createEnvironmentTemplateApi(makeRequest: MakeRequest, organizat query: { ...createRequestConfig({ query }).params }, spaceId, environmentId, + latestOnly, }, }).then((data) => wrapEnvironmentTemplateInstallationCollection(makeRequest, data)) }, diff --git a/test/unit/create-environment-template-api.test.ts b/test/unit/create-environment-template-api.test.ts index b852e6f8ae..ae3e861ca4 100644 --- a/test/unit/create-environment-template-api.test.ts +++ b/test/unit/create-environment-template-api.test.ts @@ -169,7 +169,8 @@ describe('createEnvironmentTemplateApi', () => { environmentTemplateId: environmentTemplateMock.sys.id, spaceId: undefined, environmentId: undefined, - query: { latestOnly: true }, + latestOnly: true, + query: {}, }, }) })