From 7fa04fc7f56236f7e6cb31ae2e88a8fb8fdfc1d1 Mon Sep 17 00:00:00 2001 From: Pascal B Date: Wed, 6 Aug 2025 10:01:09 -0400 Subject: [PATCH] feat(cli): allow relative package queries (#14107) --- packages/cli/package.json | 2 +- packages/cli/src/api/client.ts | 14 +++-- .../cli/src/api/find-previous-version.test.ts | 61 ------------------- packages/cli/src/api/find-previous-version.ts | 41 ------------- packages/cli/src/package-ref.test.ts | 4 +- packages/cli/src/package-ref.ts | 2 +- 6 files changed, 13 insertions(+), 111 deletions(-) delete mode 100644 packages/cli/src/api/find-previous-version.test.ts delete mode 100644 packages/cli/src/api/find-previous-version.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index 73dc1283533..770c2d32092 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@botpress/cli", - "version": "4.14.6", + "version": "4.15.0", "description": "Botpress CLI", "scripts": { "build": "pnpm run bundle && pnpm run template:gen", diff --git a/packages/cli/src/api/client.ts b/packages/cli/src/api/client.ts index e10625a674a..36925d4d02e 100644 --- a/packages/cli/src/api/client.ts +++ b/packages/cli/src/api/client.ts @@ -1,9 +1,10 @@ import * as client from '@botpress/client' +import semver from 'semver' import yn from 'yn' +import * as errors from '../errors' import type { Logger } from '../logger' import { formatPackageRef, ApiPackageRef, NamePackageRef } from '../package-ref' import * as utils from '../utils' -import { findPreviousIntegrationVersion } from './find-previous-version' import * as paging from './paging' import * as retry from './retry' @@ -279,11 +280,14 @@ export class ApiClient { public listAllPages = paging.listAllPages public async findPreviousIntegrationVersion(ref: NamePackageRef): Promise { - const previous = await findPreviousIntegrationVersion(this.client, ref) - if (!previous) { - return + const isValidSemverVersion = semver.valid(ref.version) + + // Sanity check (this should never happen): + if (!isValidSemverVersion) { + throw new errors.BotpressCLIError(`Invalid version "${ref.version}" for integration "${ref.name}"`) } - return this.findPublicOrPrivateIntegration({ type: 'id', id: previous.id }) + + return this.findPublicOrPrivateIntegration({ ...ref, version: `<${ref.version}` }) } public async findBotByName(name: string): Promise { diff --git a/packages/cli/src/api/find-previous-version.test.ts b/packages/cli/src/api/find-previous-version.test.ts deleted file mode 100644 index 4e34233ede1..00000000000 --- a/packages/cli/src/api/find-previous-version.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import * as uuid from 'uuid' -import * as client from '@botpress/client' -import { test, expect } from 'vitest' -import { findPreviousIntegrationVersion } from './find-previous-version' -import { IntegrationSummary } from './types' - -class IntegrationFixtureCreator { - private t0 = Date.now() - - public constructor(private name: string) {} - - public create = (version: string): IntegrationSummary => { - return { - id: uuid.v4(), - name: this.name, - version, - public: true, - visibility: 'public', - createdAt: new Date(this.t0++).toISOString(), - updatedAt: new Date(this.t0++).toISOString(), - description: 'description', - title: 'title', - iconUrl: 'iconUrl', - verificationStatus: 'approved', - } - } -} - -test('find previous integration version', async () => { - const client: Partial = { - listIntegrations: async ({ name }: { name?: string; version?: string }) => { - const creator = new IntegrationFixtureCreator(name!) - - const integrations: IntegrationSummary[] = [ - creator.create('9.2.0'), - creator.create('9.2.1'), - creator.create('9.3.0'), - creator.create('9.2.2'), - creator.create('10.0.0'), - ].reverse() // reverse creation order just like the real API - - return { integrations, meta: {} } - }, - } - - const getPrevious = async (version: string) => { - const integration = await findPreviousIntegrationVersion(client as client.Client, { - type: 'name', - name: 'slack', - version, - }) - return integration?.version - } - - expect(await getPrevious('10.0.1')).toEqual('10.0.0') - expect(await getPrevious('10.0.0')).toEqual('9.3.0') - expect(await getPrevious('9.3.0')).toEqual('9.2.2') - expect(await getPrevious('9.2.2')).toEqual('9.2.1') - expect(await getPrevious('9.2.1')).toEqual('9.2.0') - expect(await getPrevious('9.2.0')).toEqual(undefined) -}) diff --git a/packages/cli/src/api/find-previous-version.ts b/packages/cli/src/api/find-previous-version.ts deleted file mode 100644 index e423f8f8b86..00000000000 --- a/packages/cli/src/api/find-previous-version.ts +++ /dev/null @@ -1,41 +0,0 @@ -import * as client from '@botpress/client' -import semver from 'semver' -import { NamePackageRef } from '../package-ref' -import * as paging from './paging' -import { IntegrationSummary } from './types' - -export const findPreviousIntegrationVersion = async ( - client: client.Client, - ref: NamePackageRef -): Promise => { - const { name, version: targetVersion } = ref - const allVersions = await paging.listAllPages( - async ({ nextToken }) => client.listIntegrations({ name, nextToken }), - (r) => r.integrations - ) - - const orderedVersions = allVersions.sort((a, b) => semver.compare(b.version, a.version)) - const latestVersion = orderedVersions[0] - if (!latestVersion) { - return - } - - type VersionIdx = [number, IntegrationSummary] - - let current: VersionIdx = [0, latestVersion] - while (semver.gte(current[1].version, targetVersion)) { - const nextIdx = current[0] + 1 - const nextIntegration = orderedVersions[nextIdx] - if (!nextIntegration) { - break - } - current = [nextIdx, nextIntegration] - } - - const previous = current[1] - if (semver.gte(previous.version, targetVersion)) { - return - } - - return previous -} diff --git a/packages/cli/src/package-ref.test.ts b/packages/cli/src/package-ref.test.ts index 84732a56722..d20d2d03687 100644 --- a/packages/cli/src/package-ref.test.ts +++ b/packages/cli/src/package-ref.test.ts @@ -19,8 +19,8 @@ describe('parsePackageRef', () => { test('parse with invalid version should return undefined', () => { // arrange const ref0 = `${name}@lol` - const ref1 = `${name}@1` - const ref2 = `${name}@1.0` + const ref1 = `${name}@>>1` + const ref2 = `${name}@1.0.b` // act const result0 = parsePackageRef(ref0) const result1 = parsePackageRef(ref1) diff --git a/packages/cli/src/package-ref.ts b/packages/cli/src/package-ref.ts index d8a3c7f7a5c..f65854d5206 100644 --- a/packages/cli/src/package-ref.ts +++ b/packages/cli/src/package-ref.ts @@ -90,7 +90,7 @@ const parseNamePackageRef = (ref: string): NamePackageRef | undefined => { return } - const cleanedVersion = version === LATEST_TAG ? version : semver.clean(version) + const cleanedVersion = version === LATEST_TAG ? version : semver.validRange(version) if (!cleanedVersion) { return }