diff --git a/.github/actions/e2e-clean/action.yml b/.github/actions/e2e-clean/action.yml index 5df42e3701..53c3e09990 100644 --- a/.github/actions/e2e-clean/action.yml +++ b/.github/actions/e2e-clean/action.yml @@ -33,3 +33,7 @@ runs: shell: bash if: cancelled() || failure() || success() run: node ./scripts/cleaning/delete-api-keys.js + - name: Delete test NGSPs + shell: bash + if: cancelled() || failure() || success() + run: node ./scripts/cleaning/delete-ngsp.js diff --git a/.github/workflows/delete-resources.yml b/.github/workflows/delete-resources.yml index c4ac820679..7b1e6c8fe3 100644 --- a/.github/workflows/delete-resources.yml +++ b/.github/workflows/delete-resources.yml @@ -31,6 +31,10 @@ jobs: timeout-minutes: 30 if: cancelled() || failure() || success() run: node ./scripts/cleaning/delete-api-keys.js --olderThan 1d + - name: Delete test NGSP + timeout-minutes: 30 + if: cancelled() || failure() || success() + run: node ./scripts/cleaning/delete-api-ngsp.js --olderThan 1d - name: Delete test orgs timeout-minutes: 30 if: cancelled() || failure() || success() diff --git a/package-lock.json b/package-lock.json index 8a5594e875..e1e5a3b8e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2674,31 +2674,25 @@ "link": true }, "node_modules/@coveo/push-api-client": { - "version": "3.1.15", - "resolved": "https://registry.npmjs.org/@coveo/push-api-client/-/push-api-client-3.1.15.tgz", - "integrity": "sha512-kMiYZZItt5+pQo9QkMxBgyBJCOOO4wSq7P9gzslQKl6XZUt4eXaNbncKsjfkyeC6pH6S94vlbrDNAgH55Vavkg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@coveo/push-api-client/-/push-api-client-4.0.1.tgz", + "integrity": "sha512-qYZ73UjpE7+XKMZyOXM+AvhEz8verHK8I6HKYHqUxHSww2bo9mkPp9ZydS5VVRdTqCVpcxEoDC2PrQ/ypkl7ZA==", "dependencies": { - "@coveo/bueno": "^0.43.0", - "@coveo/platform-client": "44.1.0", + "@coveo/bueno": "^0.45.0", + "@coveo/platform-client": "^52.1.0", "dayjs": "^1.10.4", "exponential-backoff": "^3.1.0", - "fetch-undici-polyfill": "1.2.1", - "ts-dedent": "2.2.0", + "ts-dedent": "^2.2.0", "zod": "^3.20.2" }, "engines": { - "node": ">=16.x" + "node": "^18.12.0 || ^20.10.0" } }, - "node_modules/@coveo/push-api-client/node_modules/@coveo/platform-client": { - "version": "44.1.0", - "resolved": "https://registry.npmjs.org/@coveo/platform-client/-/platform-client-44.1.0.tgz", - "integrity": "sha512-bOiY+IG/3RSMQrXMRShRkNBW4bHnMXlLL30z5K5GOnLwH43mK7jxCtuU6JFCDze8zyoAY/1kYSd2W1uSTG1Izw==", - "dependencies": { - "exponential-backoff": "^3.1.0", - "query-string-cjs": "npm:query-string@^7.0.0", - "query-string-esm": "npm:query-string@^8.0.0" - } + "node_modules/@coveo/push-api-client/node_modules/@coveo/bueno": { + "version": "0.45.6", + "resolved": "https://registry.npmjs.org/@coveo/bueno/-/bueno-0.45.6.tgz", + "integrity": "sha512-OPYN3pqw6ON7X1EYbCxRWcGBt9gjeOHDj9VVnL8YtD/nzozphTw2nYV9yf7OxfgUOYCiV2IvSXLHSA+tftQW2Q==" }, "node_modules/@coveo/search-token-server": { "resolved": "packages/ui/search-token-server", @@ -30781,7 +30775,7 @@ "dependencies": { "@coveo/cli-commons": "2.7.15", "@coveo/platform-client": "52.1.0", - "@coveo/push-api-client": "3.1.15", + "@coveo/push-api-client": "4.0.1", "@oclif/core": "1.24.0", "@oclif/plugin-help": "5.1.23", "@oclif/plugin-plugins": "2.1.12", diff --git a/packages/cli-e2e/__tests__/atomic.specs.ts b/packages/cli-e2e/__tests__/atomic.specs.ts index 17f43166ad..d4466ac711 100644 --- a/packages/cli-e2e/__tests__/atomic.specs.ts +++ b/packages/cli-e2e/__tests__/atomic.specs.ts @@ -1,7 +1,7 @@ -import type {Browser, Page, HTTPResponse} from 'puppeteer'; +import type {Browser, Page, HTTPResponse, Platform} from 'puppeteer'; import {captureScreenshots, getNewBrowser, openNewPage} from '../utils/browser'; import {answerPrompt, getProjectPath, setupUIProject} from '../utils/cli'; -import {isSuccessfulSearchResponse} from '../utils/platform'; +import {getPlatformClient, isSuccessfulSearchResponse} from '../utils/platform'; import {ProcessManager} from '../utils/processManager'; import {Terminal} from '../utils/terminal/terminal'; import {BrowserConsoleInterceptor} from '../utils/browserConsoleInterceptor'; @@ -10,6 +10,7 @@ import {EOL} from 'os'; import {join, resolve} from 'path'; import {hashElement} from 'folder-hash'; import {existsSync, symlinkSync, unlinkSync} from 'fs'; +import PlatformClient from '@coveo/platform-client'; interface BuildAppOptions { id: string; @@ -120,6 +121,16 @@ describe('ui:create:atomic', () => { ), ]); + await Promise.allSettled( + streams.map((stream) => + buildTerminal + .when(/\(y\)/) + .on(stream) + .do(answerPrompt(`n${EOL}`)) + .once() + ) + ); + await Promise.allSettled( streams.map((stream) => buildTerminal @@ -150,6 +161,23 @@ describe('ui:create:atomic', () => { `${debugName}-${options.id}` ); }; + let freshNgspId: string; + let platformClient: PlatformClient; + beforeAll(async () => { + platformClient = getPlatformClient( + process.env.ORG_ID!, + process.env.PLATFORM_API_KEY! + ); + freshNgspId = ( + await platformClient.nextGenSearchPages.create({ + name: getProjectName('from-platform'), + }) + ).id; + }); + + afterAll(async () => { + await platformClient.nextGenSearchPages.delete(freshNgspId); + }); describe.each([ { @@ -161,6 +189,21 @@ describe('ui:create:atomic', () => { }, skipBrowser: false, }, + { + describeName: 'when using a fresh ngsp (--pageId flag specified)', + buildAppOptions: Object.defineProperties( + { + id: 'fresh-ngsp', + skipInstall: false, + }, + { + pageId: { + get: () => freshNgspId, + }, + } + ), + skipBrowser: false, + }, { describeName: 'when using the default page config (pageId not specified)', buildAppOptions: {id: 'without-page-id', skipInstall: true}, diff --git a/packages/cli/core/src/commands/org/search/dump.ts b/packages/cli/core/src/commands/org/search/dump.ts index cd3a6882ab..0f646a278f 100644 --- a/packages/cli/core/src/commands/org/search/dump.ts +++ b/packages/cli/core/src/commands/org/search/dump.ts @@ -269,7 +269,7 @@ export default class Dump extends CLICommand { }), ...(params.pipeline && {pipeline: params.pipeline}), ...(indexToken !== '' && {indexToken: indexToken}), - })) as SearchResponse; + })) as unknown as SearchResponse; return results; } catch (error) { if (this.isResponseExceededMaximumSizeError(error)) { diff --git a/packages/cli/core/src/commands/ui/create/shared.ts b/packages/cli/core/src/commands/ui/create/shared.ts index acdc1cc3dc..2c1f29dd1e 100644 --- a/packages/cli/core/src/commands/ui/create/shared.ts +++ b/packages/cli/core/src/commands/ui/create/shared.ts @@ -7,7 +7,7 @@ const manuallyEnterSearchHub = () => export async function promptForSearchHub(client: PlatformClient) { const createSearchHub = await confirm( - 'An API key will be created against your organization. We strongly recommends that you associate this API key with a search hub. Would you like to do so now ? y/n', + 'An API key will be created against your organization. We strongly recommends that you associate this API key with a search hub. Would you like to do so now ? (y/n)', false ); if (!createSearchHub) { diff --git a/packages/cli/source/package.json b/packages/cli/source/package.json index bfa51ee986..f9b01a5745 100644 --- a/packages/cli/source/package.json +++ b/packages/cli/source/package.json @@ -16,7 +16,7 @@ "dependencies": { "@coveo/cli-commons": "2.7.15", "@coveo/platform-client": "52.1.0", - "@coveo/push-api-client": "3.1.15", + "@coveo/push-api-client": "4.0.1", "@oclif/core": "1.24.0", "@oclif/plugin-help": "5.1.23", "@oclif/plugin-plugins": "2.1.12", diff --git a/packages/ui/atomic/create-atomic/src/fetch-page.ts b/packages/ui/atomic/create-atomic/src/fetch-page.ts index 6fe38815a4..e441883226 100644 --- a/packages/ui/atomic/create-atomic/src/fetch-page.ts +++ b/packages/ui/atomic/create-atomic/src/fetch-page.ts @@ -7,7 +7,7 @@ import { /** * @coveo/platform-client's IManifestResponse with simplified configuration */ -export interface IManifest extends Omit { +export interface IManifest extends Omit, 'config'> { config: Pick; } @@ -20,28 +20,22 @@ export async function fetchPageManifest( platformUrl: string ) { let manifestGetters = []; - // if (type !== 'next-gen') { - // manifestGetters.push(getLegacyManifest); - // } + if (type !== 'next-gen') { + manifestGetters.push(getLegacyManifest); + } if (type !== 'legacy') { manifestGetters.push(getNextGenManifest); } for (const manifestGetter of manifestGetters) { let manifest: IManifest; try { - manifest = await manifestGetter( - client, - pageId, - apiKey, - orgId, - platformUrl - ); + manifest = await manifestGetter(client, pageId); } catch (error) { continue; } return replaceResultsPlaceholder(manifest); } - throw 'PANIC'; + throw new Error('Could not fetch the page manifest'); } function replaceResultsPlaceholder(manifestResponse: IManifest) { @@ -69,26 +63,11 @@ async function getLegacyManifest( async function getNextGenManifest( client: PlatformClient, - pageId: string, - apiKey: string, - orgId: string, - platformUrl: string + pageId: string ): Promise { - return ( - await fetch( - `http://localhost:8222/rest/organizations/${orgId}/searchpage/v1/interfaces/${pageId}/manifest`, - { - headers: { - Authorization: `Bearer ${apiKey}`, - }, - body: { - //@ts-ignore shush, it works. - pagePlaceholders: { - results: '--results--', - }, - }, - method: 'POST', - } - ) - ).json() as Promise; + return await client.nextGenSearchPages.manifest(pageId, { + pagePlaceholders: { + results: '--results--', + }, + }); } diff --git a/scripts/cleaning/delete-ngsp.js b/scripts/cleaning/delete-ngsp.js new file mode 100644 index 0000000000..4786118fbe --- /dev/null +++ b/scripts/cleaning/delete-ngsp.js @@ -0,0 +1,40 @@ +const {homedir} = require('os'); +const {join} = require('path'); +const {config} = require('dotenv'); +const {getClient, yargGenerator, wasCreatedBefore} = require('./utils'); +config({path: join(homedir(), '.env')}); + +async function deleteNgsp(platform, idsToDelete) { + for (const id of idsToDelete) { + console.log(`Deleting ${id}`); + await platform.nextGenSearchPages.delete(id); + } + console.log(`\nDeleted ${idsToDelete.length} API keys`); +} + +async function main(amount, unit) { + const { + ORG_ID: testOrgId, + TEST_RUN_ID: testRunId, + PLATFORM_API_KEY: accessToken, + PLATFORM_ENV: env, + } = process.env; + const platform = getClient(accessToken, env, testOrgId); + try { + const pages = await platform.nextGenSearchPages.list({filter: 'cli-id'}); + + const cliApiKeys = pages + .filter(page=>page.name.includes(testRunId)) + .filter(wasCreatedBefore(amount, unit)); + + await deleteNgsp(platform, cliApiKeys); + } catch (error) { + console.log(error); + process.exit(1); + } +} + +const argv = yargGenerator('NGSP'); + +const {amount, unit} = argv.olderThan; +main(amount, unit); diff --git a/scripts/cleaning/utils.js b/scripts/cleaning/utils.js index 310491798e..0224f01aed 100644 --- a/scripts/cleaning/utils.js +++ b/scripts/cleaning/utils.js @@ -19,9 +19,13 @@ function getClient(accessToken, env, organizationId) { } function wasCreatedBefore(amount, unit) { - return (key) => { + return (resource) => { const limit = moment().subtract(amount, unit); - return moment(key.createdDate).isBefore(limit); + for (const createField of ['createdDate', 'created']) { + if (resource[createField]) { + return moment(resource[createField]).isBefore(limit); + } + } }; }