@sanity/cli 6.0.0-alpha.4 → 6.0.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/dev/startStudioDevServer.js +3 -8
- package/dist/actions/dev/startStudioDevServer.js.map +1 -1
- package/dist/actions/dev/types.d.ts +1 -3
- package/dist/actions/dev/types.js.map +1 -1
- package/dist/actions/documents/validate.d.ts +0 -2
- package/dist/actions/documents/validate.js +21 -1
- package/dist/actions/documents/validate.js.map +1 -1
- package/dist/actions/exec/execScript.js +1 -1
- package/dist/actions/exec/execScript.js.map +1 -1
- package/dist/actions/graphql/__tests__/getGraphQLAPIs.test.js +1 -1
- package/dist/actions/graphql/__tests__/getGraphQLAPIs.test.js.map +1 -1
- package/dist/actions/graphql/getGraphQLAPIs.js +1 -1
- package/dist/actions/graphql/getGraphQLAPIs.js.map +1 -1
- package/dist/actions/manifest/extractManifest.js +1 -4
- package/dist/actions/manifest/extractManifest.js.map +1 -1
- package/dist/actions/schema/deleteSchemaAction.d.ts +13 -5
- package/dist/actions/schema/deleteSchemaAction.js +12 -17
- package/dist/actions/schema/deleteSchemaAction.js.map +1 -1
- package/dist/actions/schema/deploySchemas.d.ts +15 -0
- package/dist/actions/schema/deploySchemas.js +98 -0
- package/dist/actions/schema/deploySchemas.js.map +1 -0
- package/dist/actions/schema/listSchemas.d.ts +12 -0
- package/dist/actions/schema/listSchemas.js +119 -0
- package/dist/actions/schema/listSchemas.js.map +1 -0
- package/dist/actions/schema/schemaStoreTypes.d.ts +0 -11
- package/dist/actions/schema/schemaStoreTypes.js.map +1 -1
- package/dist/actions/schema/utils/debug.d.ts +2 -0
- package/dist/actions/schema/utils/debug.js +5 -0
- package/dist/actions/schema/utils/debug.js.map +1 -0
- package/dist/actions/schema/utils/manifestExtractor.d.ts +3 -8
- package/dist/actions/schema/utils/manifestExtractor.js +12 -17
- package/dist/actions/schema/utils/manifestExtractor.js.map +1 -1
- package/dist/actions/schema/utils/manifestReader.d.ts +2 -9
- package/dist/actions/schema/utils/manifestReader.js +6 -12
- package/dist/actions/schema/utils/manifestReader.js.map +1 -1
- package/dist/actions/schema/utils/schemaStoreOutStrings.d.ts +0 -1
- package/dist/actions/schema/utils/schemaStoreOutStrings.js +1 -1
- package/dist/actions/schema/utils/schemaStoreOutStrings.js.map +1 -1
- package/dist/actions/schema/utils/schemaStoreValidation.d.ts +10 -62
- package/dist/actions/schema/utils/schemaStoreValidation.js +38 -125
- package/dist/actions/schema/utils/schemaStoreValidation.js.map +1 -1
- package/dist/actions/schema/utils/uniqByProjectIdDataset.d.ts +14 -0
- package/dist/actions/schema/utils/uniqByProjectIdDataset.js +9 -0
- package/dist/actions/schema/utils/uniqByProjectIdDataset.js.map +1 -0
- package/dist/actions/users/getMembersForProject.d.ts +1 -3
- package/dist/actions/users/getMembersForProject.js +6 -17
- package/dist/actions/users/getMembersForProject.js.map +1 -1
- package/dist/actions/users/types.d.ts +0 -11
- package/dist/actions/users/types.js.map +1 -1
- package/dist/commands/__tests__/debug.test.js +113 -220
- package/dist/commands/__tests__/debug.test.js.map +1 -1
- package/dist/commands/__tests__/deploy.test.js +325 -293
- package/dist/commands/__tests__/deploy.test.js.map +1 -1
- package/dist/commands/__tests__/dev.test.js +62 -19
- package/dist/commands/__tests__/dev.test.js.map +1 -1
- package/dist/commands/__tests__/init/init.authentication.test.js +40 -27
- package/dist/commands/__tests__/init/init.authentication.test.js.map +1 -1
- package/dist/commands/__tests__/init/init.create-new-project.test.js +84 -85
- package/dist/commands/__tests__/init/init.create-new-project.test.js.map +1 -1
- package/dist/commands/__tests__/init/init.plan.test.js +103 -44
- package/dist/commands/__tests__/init/init.plan.test.js.map +1 -1
- package/dist/commands/__tests__/init/init.setup.test.js +85 -29
- package/dist/commands/__tests__/init/init.setup.test.js.map +1 -1
- package/dist/commands/__tests__/install.test.js +46 -22
- package/dist/commands/__tests__/install.test.js.map +1 -1
- package/dist/commands/__tests__/logout.test.js +8 -5
- package/dist/commands/__tests__/logout.test.js.map +1 -1
- package/dist/commands/__tests__/manage.test.js +29 -24
- package/dist/commands/__tests__/manage.test.js.map +1 -1
- package/dist/commands/__tests__/versions.test.js +22 -14
- package/dist/commands/__tests__/versions.test.js.map +1 -1
- package/dist/commands/backup/__tests__/disable.test.js +72 -75
- package/dist/commands/backup/__tests__/disable.test.js.map +1 -1
- package/dist/commands/backup/__tests__/download.test.js +166 -77
- package/dist/commands/backup/__tests__/download.test.js.map +1 -1
- package/dist/commands/backup/__tests__/enable.test.js +109 -140
- package/dist/commands/backup/__tests__/enable.test.js.map +1 -1
- package/dist/commands/backup/__tests__/list.test.js +84 -75
- package/dist/commands/backup/__tests__/list.test.js.map +1 -1
- package/dist/commands/backup/disable.js +5 -11
- package/dist/commands/backup/disable.js.map +1 -1
- package/dist/commands/backup/enable.js +5 -11
- package/dist/commands/backup/enable.js.map +1 -1
- package/dist/commands/backup/list.js +7 -8
- package/dist/commands/backup/list.js.map +1 -1
- package/dist/commands/cors/__tests__/add.test.js +68 -38
- package/dist/commands/cors/__tests__/add.test.js.map +1 -1
- package/dist/commands/cors/__tests__/delete.test.js +52 -37
- package/dist/commands/cors/__tests__/delete.test.js.map +1 -1
- package/dist/commands/cors/__tests__/list.test.js +80 -57
- package/dist/commands/cors/__tests__/list.test.js.map +1 -1
- package/dist/commands/cors/add.js +5 -13
- package/dist/commands/cors/add.js.map +1 -1
- package/dist/commands/cors/delete.js +7 -15
- package/dist/commands/cors/delete.js.map +1 -1
- package/dist/commands/cors/list.js +2 -10
- package/dist/commands/cors/list.js.map +1 -1
- package/dist/commands/dataset/__tests__/copy.test.js +197 -89
- package/dist/commands/dataset/__tests__/copy.test.js.map +1 -1
- package/dist/commands/dataset/__tests__/create.test.js +147 -117
- package/dist/commands/dataset/__tests__/create.test.js.map +1 -1
- package/dist/commands/dataset/__tests__/delete.test.js +75 -68
- package/dist/commands/dataset/__tests__/delete.test.js.map +1 -1
- package/dist/commands/dataset/__tests__/export.test.js +123 -83
- package/dist/commands/dataset/__tests__/export.test.js.map +1 -1
- package/dist/commands/dataset/__tests__/list.test.js +107 -65
- package/dist/commands/dataset/__tests__/list.test.js.map +1 -1
- package/dist/commands/dataset/alias/__tests__/create.test.js +114 -74
- package/dist/commands/dataset/alias/__tests__/create.test.js.map +1 -1
- package/dist/commands/dataset/alias/__tests__/delete.test.js +40 -29
- package/dist/commands/dataset/alias/__tests__/delete.test.js.map +1 -1
- package/dist/commands/dataset/alias/__tests__/link.test.js +114 -74
- package/dist/commands/dataset/alias/__tests__/link.test.js.map +1 -1
- package/dist/commands/dataset/alias/__tests__/unlink.test.js +44 -29
- package/dist/commands/dataset/alias/__tests__/unlink.test.js.map +1 -1
- package/dist/commands/dataset/export.js +4 -4
- package/dist/commands/dataset/export.js.map +1 -1
- package/dist/commands/dataset/visibility/__tests__/get.test.js +48 -67
- package/dist/commands/dataset/visibility/__tests__/get.test.js.map +1 -1
- package/dist/commands/dataset/visibility/__tests__/set.test.js +76 -123
- package/dist/commands/dataset/visibility/__tests__/set.test.js.map +1 -1
- package/dist/commands/dev.js +0 -1
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/docs/__tests__/search.test.js +8 -7
- package/dist/commands/docs/__tests__/search.test.js.map +1 -1
- package/dist/commands/documents/__tests__/create.test.js +328 -265
- package/dist/commands/documents/__tests__/create.test.js.map +1 -1
- package/dist/commands/documents/__tests__/delete.test.js +119 -87
- package/dist/commands/documents/__tests__/delete.test.js.map +1 -1
- package/dist/commands/documents/__tests__/get.test.js +68 -95
- package/dist/commands/documents/__tests__/get.test.js.map +1 -1
- package/dist/commands/documents/__tests__/query.test.js +84 -189
- package/dist/commands/documents/__tests__/query.test.js.map +1 -1
- package/dist/commands/documents/__tests__/validate.test.js +52 -29
- package/dist/commands/documents/__tests__/validate.test.js.map +1 -1
- package/dist/commands/documents/create.d.ts +1 -0
- package/dist/commands/documents/create.js +10 -9
- package/dist/commands/documents/create.js.map +1 -1
- package/dist/commands/documents/delete.js +2 -3
- package/dist/commands/documents/delete.js.map +1 -1
- package/dist/commands/documents/get.js +2 -3
- package/dist/commands/documents/get.js.map +1 -1
- package/dist/commands/documents/query.js +2 -3
- package/dist/commands/documents/query.js.map +1 -1
- package/dist/commands/documents/validate.js +0 -20
- package/dist/commands/documents/validate.js.map +1 -1
- package/dist/commands/graphql/__tests__/list.test.js +57 -45
- package/dist/commands/graphql/__tests__/list.test.js.map +1 -1
- package/dist/commands/graphql/__tests__/undeploy.test.js +85 -59
- package/dist/commands/graphql/__tests__/undeploy.test.js.map +1 -1
- package/dist/commands/graphql/list.js +2 -2
- package/dist/commands/graphql/list.js.map +1 -1
- package/dist/commands/graphql/undeploy.js +4 -9
- package/dist/commands/graphql/undeploy.js.map +1 -1
- package/dist/commands/hook/__tests__/attempt.test.js +48 -33
- package/dist/commands/hook/__tests__/attempt.test.js.map +1 -1
- package/dist/commands/hook/__tests__/create.test.js +49 -51
- package/dist/commands/hook/__tests__/create.test.js.map +1 -1
- package/dist/commands/hook/__tests__/delete.test.js +43 -30
- package/dist/commands/hook/__tests__/delete.test.js.map +1 -1
- package/dist/commands/hook/__tests__/list.test.js +38 -31
- package/dist/commands/hook/__tests__/list.test.js.map +1 -1
- package/dist/commands/hook/__tests__/logs.test.js +68 -40
- package/dist/commands/hook/__tests__/logs.test.js.map +1 -1
- package/dist/commands/hook/create.js +2 -6
- package/dist/commands/hook/create.js.map +1 -1
- package/dist/commands/hook/delete.js +5 -17
- package/dist/commands/hook/delete.js.map +1 -1
- package/dist/commands/hook/list.js +2 -8
- package/dist/commands/hook/list.js.map +1 -1
- package/dist/commands/manifest/__tests__/extract.test.js +22 -13
- package/dist/commands/manifest/__tests__/extract.test.js.map +1 -1
- package/dist/commands/media/__tests__/create-aspect.test.js +41 -28
- package/dist/commands/media/__tests__/create-aspect.test.js.map +1 -1
- package/dist/commands/media/__tests__/delete-aspect.test.js +44 -35
- package/dist/commands/media/__tests__/delete-aspect.test.js.map +1 -1
- package/dist/commands/media/__tests__/deploy-aspect.test.js +67 -80
- package/dist/commands/media/__tests__/deploy-aspect.test.js.map +1 -1
- package/dist/commands/media/__tests__/export.test.js +365 -66
- package/dist/commands/media/__tests__/export.test.js.map +1 -1
- package/dist/commands/media/__tests__/import.test.js +171 -105
- package/dist/commands/media/__tests__/import.test.js.map +1 -1
- package/dist/commands/media/export.js +2 -2
- package/dist/commands/media/export.js.map +1 -1
- package/dist/commands/media/import.js +2 -2
- package/dist/commands/media/import.js.map +1 -1
- package/dist/commands/projects/__tests__/list.test.js +5 -4
- package/dist/commands/projects/__tests__/list.test.js.map +1 -1
- package/dist/commands/projects/list.js +2 -6
- package/dist/commands/projects/list.js.map +1 -1
- package/dist/commands/schema/__tests__/delete.test.js +396 -151
- package/dist/commands/schema/__tests__/delete.test.js.map +1 -1
- package/dist/commands/schema/__tests__/deploy.test.js +348 -0
- package/dist/commands/schema/__tests__/deploy.test.js.map +1 -0
- package/dist/commands/schema/__tests__/extract.test.js +19 -11
- package/dist/commands/schema/__tests__/extract.test.js.map +1 -1
- package/dist/commands/schema/__tests__/list.test.js +399 -0
- package/dist/commands/schema/__tests__/list.test.js.map +1 -0
- package/dist/commands/schema/__tests__/validate.test.js +27 -10
- package/dist/commands/schema/__tests__/validate.test.js.map +1 -1
- package/dist/commands/schema/delete.d.ts +1 -1
- package/dist/commands/schema/delete.js +20 -23
- package/dist/commands/schema/delete.js.map +1 -1
- package/dist/commands/schema/deploy.d.ts +16 -0
- package/dist/commands/schema/deploy.js +98 -0
- package/dist/commands/schema/deploy.js.map +1 -0
- package/dist/commands/schema/list.d.ts +15 -0
- package/dist/commands/schema/list.js +104 -0
- package/dist/commands/schema/list.js.map +1 -0
- package/dist/commands/telemetry/__tests__/disable.test.js +7 -5
- package/dist/commands/telemetry/__tests__/disable.test.js.map +1 -1
- package/dist/commands/telemetry/__tests__/enable.test.js +7 -5
- package/dist/commands/telemetry/__tests__/enable.test.js.map +1 -1
- package/dist/commands/telemetry/__tests__/status.test.js +7 -5
- package/dist/commands/telemetry/__tests__/status.test.js.map +1 -1
- package/dist/commands/tokens/__tests__/add.test.js +55 -40
- package/dist/commands/tokens/__tests__/add.test.js.map +1 -1
- package/dist/commands/tokens/__tests__/delete.test.js +72 -42
- package/dist/commands/tokens/__tests__/delete.test.js.map +1 -1
- package/dist/commands/tokens/__tests__/list.test.js +87 -60
- package/dist/commands/tokens/__tests__/list.test.js.map +1 -1
- package/dist/commands/tokens/add.js +3 -5
- package/dist/commands/tokens/add.js.map +1 -1
- package/dist/commands/users/__tests__/invite.test.js +100 -79
- package/dist/commands/users/__tests__/invite.test.js.map +1 -1
- package/dist/commands/users/__tests__/list.test.js +186 -180
- package/dist/commands/users/__tests__/list.test.js.map +1 -1
- package/dist/commands/users/invite.js +6 -17
- package/dist/commands/users/invite.js.map +1 -1
- package/dist/commands/users/list.js +4 -7
- package/dist/commands/users/list.js.map +1 -1
- package/dist/config/createCliConfig.d.ts +4 -4
- package/dist/services/backup.d.ts +8 -0
- package/dist/services/backup.js +19 -0
- package/dist/services/backup.js.map +1 -1
- package/dist/services/cors.d.ts +23 -0
- package/dist/services/cors.js +38 -0
- package/dist/services/cors.js.map +1 -0
- package/dist/services/graphql.d.ts +7 -0
- package/dist/services/graphql.js +11 -0
- package/dist/services/graphql.js.map +1 -1
- package/dist/services/hooks.d.ts +2 -0
- package/dist/services/hooks.js +19 -0
- package/dist/services/hooks.js.map +1 -1
- package/dist/services/organizations.d.ts +1 -1
- package/dist/services/organizations.js +1 -1
- package/dist/services/organizations.js.map +1 -1
- package/dist/services/projects.d.ts +11 -0
- package/dist/services/projects.js +41 -0
- package/dist/services/projects.js.map +1 -1
- package/dist/services/schemas.d.ts +4 -0
- package/dist/services/schemas.js +40 -0
- package/dist/services/schemas.js.map +1 -0
- package/dist/services/user.d.ts +8 -0
- package/dist/services/user.js +15 -2
- package/dist/services/user.js.map +1 -1
- package/dist/util/__tests__/getCliVersion.test.js +2 -2
- package/dist/util/__tests__/getCliVersion.test.js.map +1 -1
- package/dist/util/errorMessages.d.ts +1 -0
- package/dist/util/errorMessages.js +1 -0
- package/dist/util/errorMessages.js.map +1 -1
- package/dist/util/getCliVersion.js +1 -1
- package/dist/util/getCliVersion.js.map +1 -1
- package/dist/util/readPackageJson.d.ts +1 -15
- package/dist/util/readPackageJson.js +1 -1
- package/dist/util/readPackageJson.js.map +1 -1
- package/dist/util/uniqBy.d.ts +1 -0
- package/dist/util/uniqBy.js +14 -0
- package/dist/util/uniqBy.js.map +1 -0
- package/oclif.manifest.json +172 -27
- package/package.json +27 -28
- package/dist/actions/cors/constants.d.ts +0 -1
- package/dist/actions/cors/constants.js +0 -3
- package/dist/actions/cors/constants.js.map +0 -1
- package/dist/actions/cors/types.d.ts +0 -9
- package/dist/actions/cors/types.js +0 -3
- package/dist/actions/cors/types.js.map +0 -1
- package/dist/actions/schema/__tests__/deleteSchemaAction.test.js +0 -294
- package/dist/actions/schema/__tests__/deleteSchemaAction.test.js.map +0 -1
- package/dist/actions/schema/schemaStoreConstants.d.ts +0 -1
- package/dist/actions/schema/schemaStoreConstants.js +0 -4
- package/dist/actions/schema/schemaStoreConstants.js.map +0 -1
- package/dist/actions/schema/utils/schemaActionHelpers.d.ts +0 -1
- package/dist/actions/schema/utils/schemaActionHelpers.js +0 -5
- package/dist/actions/schema/utils/schemaActionHelpers.js.map +0 -1
- package/dist/actions/schema/utils/schemaApiClient.d.ts +0 -6
- package/dist/actions/schema/utils/schemaApiClient.js +0 -17
- package/dist/actions/schema/utils/schemaApiClient.js.map +0 -1
- package/dist/actions/users/apiVersion.d.ts +0 -6
- package/dist/actions/users/apiVersion.js +0 -7
- package/dist/actions/users/apiVersion.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/commands/dataset/alias/__tests__/link.test.ts"],"sourcesContent":["import {runCommand} from '@oclif/test'\nimport {getCliConfig} from '@sanity/cli-core'\nimport {mockApi, testCommand} from '@sanity/cli-test'\nimport nock from 'nock'\nimport {afterEach, describe, expect, test, vi} from 'vitest'\n\nimport {DATASET_ALIASES_API_VERSION} from '../../../../services/datasetAliases.js'\nimport {listDatasets} from '../../../../services/datasets.js'\nimport {NO_PROJECT_ID} from '../../../../util/errorMessages.js'\nimport {LinkAliasCommand} from '../link.js'\n\nvi.mock('../../../../../../cli-core/src/config/findProjectRoot.js', () => ({\n findProjectRoot: vi.fn().mockResolvedValue({\n directory: '/test/path',\n root: '/test/path',\n type: 'studio',\n }),\n}))\n\nvi.mock('../../../../../../cli-core/src/config/cli/getCliConfig.js', () => ({\n getCliConfig: vi.fn().mockResolvedValue({\n api: {\n projectId: 'test-project',\n },\n }),\n}))\n\nvi.mock('../../../../../../cli-core/src/services/getCliToken.js', () => ({\n getCliToken: vi.fn().mockResolvedValue('test-token'),\n}))\n\nvi.mock('../../../../services/datasets.js', () => ({\n listDatasets: vi.fn(),\n}))\n\nconst mockListDatasets = vi.mocked(listDatasets)\nconst mockGetCliConfig = vi.mocked(getCliConfig)\n\ndescribe('#dataset:alias:link', () => {\n afterEach(() => {\n vi.clearAllMocks()\n const pending = nock.pendingMocks()\n nock.cleanAll()\n expect(pending, 'pending mocks').toEqual([])\n })\n\n test('help works correctly', async () => {\n const {stdout} = await runCommand(['dataset alias link', '--help'])\n expect(stdout).toMatchInlineSnapshot(`\n \"Link a dataset alias to a dataset within your project\n\n USAGE\n $ sanity dataset alias link [ALIASNAME] [TARGETDATASET] [--force]\n\n ARGUMENTS\n [ALIASNAME] Dataset alias name to link\n [TARGETDATASET] Target dataset name to link the alias to\n\n FLAGS\n --force Skip confirmation prompt when relinking existing alias\n\n DESCRIPTION\n Link a dataset alias to a dataset within your project\n\n EXAMPLES\n Link an alias with interactive prompts\n\n $ sanity dataset alias link\n\n Link alias named \"conference\" with interactive dataset selection\n\n $ sanity dataset alias link conference\n\n Link alias \"conference\" to \"conf-2025\" dataset\n\n $ sanity dataset alias link conference conf-2025\n\n Link alias with explicit ~ prefix\n\n $ sanity dataset alias link ~conference conf-2025\n\n Force link without confirmation (skip relink prompt)\n\n $ sanity dataset alias link conference conf-2025 --force\n\n \"\n `)\n })\n\n test('links alias with valid arguments', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}, {name: 'development'}] as never)\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging',\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n const {stdout} = await testCommand(LinkAliasCommand, ['staging', 'production'])\n\n expect(stdout).toContain('Dataset alias ~staging linked to production successfully')\n })\n\n test('re-links already-linked alias when using force flag', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}, {name: 'development'}] as never)\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [{datasetName: 'development', name: 'staging'}])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging',\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n const {stderr, stdout} = await testCommand(LinkAliasCommand, [\n 'staging',\n 'production',\n '--force',\n ])\n\n expect(stderr).toContain(\"'--force' used: skipping confirmation, linking alias to\")\n expect(stdout).toContain('Dataset alias ~staging linked to production successfully')\n })\n\n test('links unlinked alias without requiring confirmation', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}] as never)\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging',\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n const {stdout} = await testCommand(LinkAliasCommand, ['staging', 'production'])\n\n expect(stdout).toContain('Dataset alias ~staging linked to production successfully')\n expect(stdout).not.toContain('confirmation')\n })\n\n test.each([\n [\n 'invalid-alias-name-that-is-way-too-long-and-exceeds-the-maximum-allowed-length',\n 'production',\n 'Alias name must be at most 64 characters',\n ],\n ['staging', 'Invalid-Dataset', 'Dataset name must be all lowercase characters'],\n ])('fails with invalid input: alias=%s, dataset=%s', async (alias, dataset, expectedError) => {\n const {error} = await testCommand(LinkAliasCommand, [alias, dataset])\n\n expect(error?.message).toContain(expectedError)\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('fails when no project ID', async () => {\n mockGetCliConfig.mockResolvedValueOnce({\n api: {},\n })\n\n const {error} = await testCommand(LinkAliasCommand, ['staging', 'production'])\n\n expect(error?.message).toContain(NO_PROJECT_ID)\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('fails when alias does not exist', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}] as never)\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n const {error} = await testCommand(LinkAliasCommand, ['nonexistent', 'production'])\n\n expect(error?.message).toContain('Dataset alias \"~nonexistent\" does not exist')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('fails when dataset does not exist', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}] as never)\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n const {error} = await testCommand(LinkAliasCommand, ['staging', 'nonexistent'])\n\n expect(error?.message).toContain('Dataset \"nonexistent\" does not exist')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('fails when alias already linked to same dataset', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}] as never)\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [{datasetName: 'production', name: 'staging'}])\n\n const {error} = await testCommand(LinkAliasCommand, ['staging', 'production'])\n\n expect(error?.message).toContain('Dataset alias ~staging already linked to production')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('fails when no datasets available', async () => {\n mockListDatasets.mockResolvedValue([] as never)\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n const {error} = await testCommand(LinkAliasCommand, ['staging'])\n\n expect(error?.message).toContain('No datasets available to link to')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('handles API error gracefully', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}] as never)\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging',\n }).reply(500, {message: 'API Error'})\n\n const {error} = await testCommand(LinkAliasCommand, ['staging', 'production'])\n\n expect(error?.message).toContain('Dataset alias linking failed: API Error')\n expect(error?.oclif?.exit).toBe(1)\n })\n})\n"],"names":["runCommand","getCliConfig","mockApi","testCommand","nock","afterEach","describe","expect","test","vi","DATASET_ALIASES_API_VERSION","listDatasets","NO_PROJECT_ID","LinkAliasCommand","mock","findProjectRoot","fn","mockResolvedValue","directory","root","type","api","projectId","getCliToken","mockListDatasets","mocked","mockGetCliConfig","clearAllMocks","pending","pendingMocks","cleanAll","toEqual","stdout","toMatchInlineSnapshot","name","apiHost","apiVersion","uri","reply","datasetName","method","aliasName","toContain","stderr","not","each","alias","dataset","expectedError","error","message","oclif","exit","toBe","mockResolvedValueOnce"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/commands/dataset/alias/__tests__/link.test.ts"],"sourcesContent":["import {runCommand} from '@oclif/test'\nimport {createTestClient, mockApi, testCommand} from '@sanity/cli-test'\nimport nock from 'nock'\nimport {afterEach, describe, expect, test, vi} from 'vitest'\n\nimport {DATASET_API_VERSION} from '../../../../services/datasets.js'\nimport {NO_PROJECT_ID} from '../../../../util/errorMessages.js'\nimport {LinkAliasCommand} from '../link.js'\n\nconst mockListDatasets = vi.hoisted(() => vi.fn())\nconst testProjectId = vi.hoisted(() => 'test-project')\nconst testToken = vi.hoisted(() => 'test-token')\n\nvi.mock('@sanity/cli-core', async (importOriginal) => {\n const actual = await importOriginal<typeof import('@sanity/cli-core')>()\n const testClient = createTestClient({\n apiVersion: 'v2025-09-16',\n projectId: testProjectId,\n token: testToken,\n })\n\n return {\n ...actual,\n getProjectCliClient: vi.fn().mockResolvedValue({\n datasets: {\n list: mockListDatasets,\n } as never,\n request: testClient.request,\n }),\n }\n})\n\nconst defaultMocks = {\n cliConfig: {api: {projectId: testProjectId}},\n projectRoot: {\n directory: '/test/path',\n path: '/test/path/sanity.config.ts',\n type: 'studio' as const,\n },\n token: testToken,\n}\n\ndescribe('#dataset:alias:link', () => {\n afterEach(() => {\n vi.clearAllMocks()\n const pending = nock.pendingMocks()\n nock.cleanAll()\n expect(pending, 'pending mocks').toEqual([])\n })\n\n test('help works correctly', async () => {\n const {stdout} = await runCommand(['dataset alias link', '--help'])\n expect(stdout).toMatchInlineSnapshot(`\n \"Link a dataset alias to a dataset within your project\n\n USAGE\n $ sanity dataset alias link [ALIASNAME] [TARGETDATASET] [--force]\n\n ARGUMENTS\n [ALIASNAME] Dataset alias name to link\n [TARGETDATASET] Target dataset name to link the alias to\n\n FLAGS\n --force Skip confirmation prompt when relinking existing alias\n\n DESCRIPTION\n Link a dataset alias to a dataset within your project\n\n EXAMPLES\n Link an alias with interactive prompts\n\n $ sanity dataset alias link\n\n Link alias named \"conference\" with interactive dataset selection\n\n $ sanity dataset alias link conference\n\n Link alias \"conference\" to \"conf-2025\" dataset\n\n $ sanity dataset alias link conference conf-2025\n\n Link alias with explicit ~ prefix\n\n $ sanity dataset alias link ~conference conf-2025\n\n Force link without confirmation (skip relink prompt)\n\n $ sanity dataset alias link conference conf-2025 --force\n\n \"\n `)\n })\n\n test('links alias with valid arguments', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}, {name: 'development'}] as never)\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'get',\n uri: `/aliases`,\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'patch',\n uri: `/aliases/staging`,\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n const {stdout} = await testCommand(LinkAliasCommand, ['staging', 'production'], {\n mocks: defaultMocks,\n })\n\n expect(stdout).toContain('Dataset alias ~staging linked to production successfully')\n })\n\n test('re-links already-linked alias when using force flag', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}, {name: 'development'}] as never)\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'get',\n uri: `/aliases`,\n }).reply(200, [{datasetName: 'development', name: 'staging'}])\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'patch',\n uri: `/aliases/staging`,\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n const {stderr, stdout} = await testCommand(\n LinkAliasCommand,\n ['staging', 'production', '--force'],\n {mocks: defaultMocks},\n )\n\n expect(stderr).toContain(\"'--force' used: skipping confirmation, linking alias to\")\n expect(stdout).toContain('Dataset alias ~staging linked to production successfully')\n })\n\n test('links unlinked alias without requiring confirmation', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}] as never)\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'get',\n uri: `/aliases`,\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'patch',\n uri: `/aliases/staging`,\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n const {stdout} = await testCommand(LinkAliasCommand, ['staging', 'production'], {\n mocks: defaultMocks,\n })\n\n expect(stdout).toContain('Dataset alias ~staging linked to production successfully')\n expect(stdout).not.toContain('confirmation')\n })\n\n test.each([\n [\n 'invalid-alias-name-that-is-way-too-long-and-exceeds-the-maximum-allowed-length',\n 'production',\n 'Alias name must be at most 64 characters',\n ],\n ['staging', 'Invalid-Dataset', 'Dataset name must be all lowercase characters'],\n ])('fails with invalid input: alias=%s, dataset=%s', async (alias, dataset, expectedError) => {\n const {error} = await testCommand(LinkAliasCommand, [alias, dataset], {mocks: defaultMocks})\n\n expect(error?.message).toContain(expectedError)\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('fails when no project ID', async () => {\n const {error} = await testCommand(LinkAliasCommand, ['staging', 'production'], {\n mocks: {\n ...defaultMocks,\n cliConfig: {api: {}},\n },\n })\n\n expect(error?.message).toContain(NO_PROJECT_ID)\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('fails when alias does not exist', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}] as never)\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'get',\n uri: `/aliases`,\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n const {error} = await testCommand(LinkAliasCommand, ['nonexistent', 'production'], {\n mocks: defaultMocks,\n })\n\n expect(error?.message).toContain('Dataset alias \"~nonexistent\" does not exist')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('fails when dataset does not exist', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}] as never)\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'get',\n uri: `/aliases`,\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n const {error} = await testCommand(LinkAliasCommand, ['staging', 'nonexistent'], {\n mocks: defaultMocks,\n })\n\n expect(error?.message).toContain('Dataset \"nonexistent\" does not exist')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('fails when alias already linked to same dataset', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}] as never)\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'get',\n uri: `/aliases`,\n }).reply(200, [{datasetName: 'production', name: 'staging'}])\n\n const {error} = await testCommand(LinkAliasCommand, ['staging', 'production'], {\n mocks: defaultMocks,\n })\n\n expect(error?.message).toContain('Dataset alias ~staging already linked to production')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('fails when no datasets available', async () => {\n mockListDatasets.mockResolvedValue([] as never)\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'get',\n uri: `/aliases`,\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n const {error} = await testCommand(LinkAliasCommand, ['staging'], {mocks: defaultMocks})\n\n expect(error?.message).toContain('No datasets available to link to')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('handles API error gracefully', async () => {\n mockListDatasets.mockResolvedValue([{name: 'production'}] as never)\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'get',\n uri: `/aliases`,\n }).reply(200, [{datasetName: null, name: 'staging'}])\n\n mockApi({\n apiHost: `https://${testProjectId}.api.sanity.io`,\n apiVersion: DATASET_API_VERSION,\n method: 'patch',\n uri: `/aliases/staging`,\n }).reply(500, {error: 'API Error', message: 'API Error'})\n\n const {error} = await testCommand(LinkAliasCommand, ['staging', 'production'], {\n mocks: defaultMocks,\n })\n\n expect(error?.message).toContain('Dataset alias linking failed: API Error')\n expect(error?.oclif?.exit).toBe(1)\n })\n})\n"],"names":["runCommand","createTestClient","mockApi","testCommand","nock","afterEach","describe","expect","test","vi","DATASET_API_VERSION","NO_PROJECT_ID","LinkAliasCommand","mockListDatasets","hoisted","fn","testProjectId","testToken","mock","importOriginal","actual","testClient","apiVersion","projectId","token","getProjectCliClient","mockResolvedValue","datasets","list","request","defaultMocks","cliConfig","api","projectRoot","directory","path","type","clearAllMocks","pending","pendingMocks","cleanAll","toEqual","stdout","toMatchInlineSnapshot","name","apiHost","method","uri","reply","datasetName","aliasName","mocks","toContain","stderr","not","each","alias","dataset","expectedError","error","message","oclif","exit","toBe"],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { runCommand } from '@oclif/test';
|
|
2
|
-
import { getCliConfig } from '@sanity/cli-core';
|
|
3
2
|
import { input } from '@sanity/cli-core/ux';
|
|
4
3
|
import { mockApi, testCommand } from '@sanity/cli-test';
|
|
5
4
|
import nock from 'nock';
|
|
@@ -7,23 +6,6 @@ import { afterEach, describe, expect, test, vi } from 'vitest';
|
|
|
7
6
|
import { DATASET_ALIASES_API_VERSION } from '../../../../services/datasetAliases.js';
|
|
8
7
|
import { NO_PROJECT_ID } from '../../../../util/errorMessages.js';
|
|
9
8
|
import { UnlinkAliasCommand } from '../unlink.js';
|
|
10
|
-
vi.mock('../../../../../../cli-core/src/config/findProjectRoot.js', ()=>({
|
|
11
|
-
findProjectRoot: vi.fn().mockResolvedValue({
|
|
12
|
-
directory: '/test/path',
|
|
13
|
-
root: '/test/path',
|
|
14
|
-
type: 'studio'
|
|
15
|
-
})
|
|
16
|
-
}));
|
|
17
|
-
vi.mock('../../../../../../cli-core/src/config/cli/getCliConfig.js', ()=>({
|
|
18
|
-
getCliConfig: vi.fn().mockResolvedValue({
|
|
19
|
-
api: {
|
|
20
|
-
projectId: 'test-project'
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
}));
|
|
24
|
-
vi.mock('../../../../../../cli-core/src/services/getCliToken.js', ()=>({
|
|
25
|
-
getCliToken: vi.fn().mockResolvedValue('test-token')
|
|
26
|
-
}));
|
|
27
9
|
vi.mock('@sanity/cli-core/ux', async ()=>{
|
|
28
10
|
const actual = await vi.importActual('@sanity/cli-core/ux');
|
|
29
11
|
return {
|
|
@@ -31,7 +13,20 @@ vi.mock('@sanity/cli-core/ux', async ()=>{
|
|
|
31
13
|
input: vi.fn()
|
|
32
14
|
};
|
|
33
15
|
});
|
|
34
|
-
const
|
|
16
|
+
const testProjectId = 'test-project';
|
|
17
|
+
const defaultMocks = {
|
|
18
|
+
cliConfig: {
|
|
19
|
+
api: {
|
|
20
|
+
projectId: testProjectId
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
projectRoot: {
|
|
24
|
+
directory: '/test/path',
|
|
25
|
+
path: '/test/path/sanity.config.ts',
|
|
26
|
+
type: 'studio'
|
|
27
|
+
},
|
|
28
|
+
token: 'test-token'
|
|
29
|
+
};
|
|
35
30
|
const mockInput = vi.mocked(input);
|
|
36
31
|
describe('#dataset:alias:unlink', ()=>{
|
|
37
32
|
afterEach(()=>{
|
|
@@ -116,7 +111,9 @@ describe('#dataset:alias:unlink', ()=>{
|
|
|
116
111
|
mockInput.mockResolvedValueOnce('yes');
|
|
117
112
|
const { stdout } = await testCommand(UnlinkAliasCommand, [
|
|
118
113
|
aliasInput
|
|
119
|
-
]
|
|
114
|
+
], {
|
|
115
|
+
mocks: defaultMocks
|
|
116
|
+
});
|
|
120
117
|
expect(stdout).toContain('Dataset alias ~staging unlinked from production successfully');
|
|
121
118
|
expect(mockInput).toHaveBeenCalledWith({
|
|
122
119
|
message: expect.stringContaining('Are you ABSOLUTELY sure you want to unlink this alias from the "production" dataset?'),
|
|
@@ -150,7 +147,9 @@ describe('#dataset:alias:unlink', ()=>{
|
|
|
150
147
|
const { stderr, stdout } = await testCommand(UnlinkAliasCommand, [
|
|
151
148
|
'staging',
|
|
152
149
|
'--force'
|
|
153
|
-
]
|
|
150
|
+
], {
|
|
151
|
+
mocks: defaultMocks
|
|
152
|
+
});
|
|
154
153
|
expect(stdout).toContain('Dataset alias ~staging unlinked from production successfully');
|
|
155
154
|
expect(stderr).toContain('\'--force\' used: skipping confirmation, unlinking alias "~staging"');
|
|
156
155
|
expect(mockInput).not.toHaveBeenCalled();
|
|
@@ -181,7 +180,9 @@ describe('#dataset:alias:unlink', ()=>{
|
|
|
181
180
|
});
|
|
182
181
|
mockInput.mockResolvedValueOnce('staging') // alias name prompt
|
|
183
182
|
.mockResolvedValueOnce('yes'); // confirmation prompt
|
|
184
|
-
const { stdout } = await testCommand(UnlinkAliasCommand, []
|
|
183
|
+
const { stdout } = await testCommand(UnlinkAliasCommand, [], {
|
|
184
|
+
mocks: defaultMocks
|
|
185
|
+
});
|
|
185
186
|
expect(stdout).toContain('Dataset alias ~staging unlinked from production successfully');
|
|
186
187
|
expect(mockInput).toHaveBeenCalledWith({
|
|
187
188
|
message: 'Alias name:',
|
|
@@ -206,22 +207,30 @@ describe('#dataset:alias:unlink', ()=>{
|
|
|
206
207
|
mockInput.mockRejectedValueOnce(new Error('User cancelled'));
|
|
207
208
|
const { error } = await testCommand(UnlinkAliasCommand, [
|
|
208
209
|
'staging'
|
|
209
|
-
]
|
|
210
|
+
], {
|
|
211
|
+
mocks: defaultMocks
|
|
212
|
+
});
|
|
210
213
|
expect(error?.message).toContain('Dataset alias unlink failed: User cancelled');
|
|
211
214
|
expect(error?.oclif?.exit).toBe(1);
|
|
212
215
|
});
|
|
213
216
|
test('shows error when no project ID available', async ()=>{
|
|
214
|
-
mockGetCliConfig.mockResolvedValueOnce({});
|
|
215
217
|
const { error } = await testCommand(UnlinkAliasCommand, [
|
|
216
218
|
'staging'
|
|
217
|
-
]
|
|
219
|
+
], {
|
|
220
|
+
mocks: {
|
|
221
|
+
...defaultMocks,
|
|
222
|
+
cliConfig: {}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
218
225
|
expect(error?.message).toContain(NO_PROJECT_ID);
|
|
219
226
|
expect(error?.oclif?.exit).toBe(1);
|
|
220
227
|
});
|
|
221
228
|
test('shows error when alias name is invalid', async ()=>{
|
|
222
229
|
const { error } = await testCommand(UnlinkAliasCommand, [
|
|
223
230
|
'invalid-alias!'
|
|
224
|
-
]
|
|
231
|
+
], {
|
|
232
|
+
mocks: defaultMocks
|
|
233
|
+
});
|
|
225
234
|
expect(error?.message).toContain('Alias name must only contain letters, numbers, dashes and underscores');
|
|
226
235
|
expect(error?.oclif?.exit).toBe(1);
|
|
227
236
|
});
|
|
@@ -242,7 +251,9 @@ describe('#dataset:alias:unlink', ()=>{
|
|
|
242
251
|
]);
|
|
243
252
|
const { error } = await testCommand(UnlinkAliasCommand, [
|
|
244
253
|
'nonexistent'
|
|
245
|
-
]
|
|
254
|
+
], {
|
|
255
|
+
mocks: defaultMocks
|
|
256
|
+
});
|
|
246
257
|
expect(error?.message).toContain('Dataset alias "~nonexistent" does not exist');
|
|
247
258
|
expect(error?.oclif?.exit).toBe(1);
|
|
248
259
|
});
|
|
@@ -263,7 +274,9 @@ describe('#dataset:alias:unlink', ()=>{
|
|
|
263
274
|
]);
|
|
264
275
|
const { error } = await testCommand(UnlinkAliasCommand, [
|
|
265
276
|
'unlinked'
|
|
266
|
-
]
|
|
277
|
+
], {
|
|
278
|
+
mocks: defaultMocks
|
|
279
|
+
});
|
|
267
280
|
expect(error?.message).toContain('Dataset alias "~unlinked" is not linked to a dataset');
|
|
268
281
|
expect(error?.oclif?.exit).toBe(1);
|
|
269
282
|
});
|
|
@@ -289,7 +302,9 @@ describe('#dataset:alias:unlink', ()=>{
|
|
|
289
302
|
mockInput.mockResolvedValueOnce('yes');
|
|
290
303
|
const { error } = await testCommand(UnlinkAliasCommand, [
|
|
291
304
|
'staging'
|
|
292
|
-
]
|
|
305
|
+
], {
|
|
306
|
+
mocks: defaultMocks
|
|
307
|
+
});
|
|
293
308
|
expect(error?.message).toContain('Dataset alias unlink failed: API Error');
|
|
294
309
|
expect(error?.oclif?.exit).toBe(1);
|
|
295
310
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/commands/dataset/alias/__tests__/unlink.test.ts"],"sourcesContent":["import {runCommand} from '@oclif/test'\nimport {getCliConfig} from '@sanity/cli-core'\nimport {input} from '@sanity/cli-core/ux'\nimport {mockApi, testCommand} from '@sanity/cli-test'\nimport nock from 'nock'\nimport {afterEach, describe, expect, test, vi} from 'vitest'\n\nimport {DATASET_ALIASES_API_VERSION} from '../../../../services/datasetAliases.js'\nimport {NO_PROJECT_ID} from '../../../../util/errorMessages.js'\nimport {UnlinkAliasCommand} from '../unlink.js'\n\nvi.mock('../../../../../../cli-core/src/config/findProjectRoot.js', () => ({\n findProjectRoot: vi.fn().mockResolvedValue({\n directory: '/test/path',\n root: '/test/path',\n type: 'studio',\n }),\n}))\n\nvi.mock('../../../../../../cli-core/src/config/cli/getCliConfig.js', () => ({\n getCliConfig: vi.fn().mockResolvedValue({\n api: {\n projectId: 'test-project',\n },\n }),\n}))\n\nvi.mock('../../../../../../cli-core/src/services/getCliToken.js', () => ({\n getCliToken: vi.fn().mockResolvedValue('test-token'),\n}))\n\nvi.mock('@sanity/cli-core/ux', async () => {\n const actual = await vi.importActual<typeof import('@sanity/cli-core/ux')>('@sanity/cli-core/ux')\n return {\n ...actual,\n input: vi.fn(),\n }\n})\n\nconst mockGetCliConfig = vi.mocked(getCliConfig)\nconst mockInput = vi.mocked(input)\n\ndescribe('#dataset:alias:unlink', () => {\n afterEach(() => {\n vi.clearAllMocks()\n const pending = nock.pendingMocks()\n nock.cleanAll()\n expect(pending, 'pending mocks').toEqual([])\n })\n\n test('help works correctly', async () => {\n const {stdout} = await runCommand(['dataset alias unlink', '--help'])\n expect(stdout).toMatchInlineSnapshot(`\n \"Unlink a dataset alias from its dataset within your project\n\n USAGE\n $ sanity dataset alias unlink [ALIASNAME] [--force]\n\n ARGUMENTS\n [ALIASNAME] Dataset alias name to unlink\n\n FLAGS\n --force Skip confirmation prompt and unlink immediately\n\n DESCRIPTION\n Unlink a dataset alias from its dataset within your project\n\n EXAMPLES\n Unlink an alias with interactive selection\n\n $ sanity dataset alias unlink\n\n Unlink alias \"conference\" with confirmation prompt\n\n $ sanity dataset alias unlink conference\n\n Unlink alias with explicit ~ prefix\n\n $ sanity dataset alias unlink ~conference\n\n Unlink alias \"conference\" without confirmation prompt\n\n $ sanity dataset alias unlink conference --force\n\n \"\n `)\n })\n\n test.each([\n ['staging', 'without ~ prefix'],\n ['~staging', 'with ~ prefix'],\n ])('unlinks alias with confirmation: %s (%s)', async (aliasInput) => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging/unlink',\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n mockInput.mockResolvedValueOnce('yes')\n\n const {stdout} = await testCommand(UnlinkAliasCommand, [aliasInput])\n\n expect(stdout).toContain('Dataset alias ~staging unlinked from production successfully')\n expect(mockInput).toHaveBeenCalledWith({\n message: expect.stringContaining(\n 'Are you ABSOLUTELY sure you want to unlink this alias from the \"production\" dataset?',\n ),\n validate: expect.any(Function),\n })\n })\n\n test('unlinks alias with force flag (skips confirmation)', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging/unlink',\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n const {stderr, stdout} = await testCommand(UnlinkAliasCommand, ['staging', '--force'])\n\n expect(stdout).toContain('Dataset alias ~staging unlinked from production successfully')\n expect(stderr).toContain('\\'--force\\' used: skipping confirmation, unlinking alias \"~staging\"')\n expect(mockInput).not.toHaveBeenCalled()\n })\n\n test('prompts for alias name when no alias provided', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging/unlink',\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n mockInput\n .mockResolvedValueOnce('staging') // alias name prompt\n .mockResolvedValueOnce('yes') // confirmation prompt\n\n const {stdout} = await testCommand(UnlinkAliasCommand, [])\n\n expect(stdout).toContain('Dataset alias ~staging unlinked from production successfully')\n expect(mockInput).toHaveBeenCalledWith({\n message: 'Alias name:',\n validate: expect.any(Function),\n })\n })\n\n test('handles user cancellation during confirmation', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n mockInput.mockRejectedValueOnce(new Error('User cancelled'))\n\n const {error} = await testCommand(UnlinkAliasCommand, ['staging'])\n\n expect(error?.message).toContain('Dataset alias unlink failed: User cancelled')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('shows error when no project ID available', async () => {\n mockGetCliConfig.mockResolvedValueOnce({})\n\n const {error} = await testCommand(UnlinkAliasCommand, ['staging'])\n\n expect(error?.message).toContain(NO_PROJECT_ID)\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('shows error when alias name is invalid', async () => {\n const {error} = await testCommand(UnlinkAliasCommand, ['invalid-alias!'])\n\n expect(error?.message).toContain(\n 'Alias name must only contain letters, numbers, dashes and underscores',\n )\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('shows error when alias does not exist', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n const {error} = await testCommand(UnlinkAliasCommand, ['nonexistent'])\n\n expect(error?.message).toContain('Dataset alias \"~nonexistent\" does not exist')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('shows error when alias exists but is not linked', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n const {error} = await testCommand(UnlinkAliasCommand, ['unlinked'])\n\n expect(error?.message).toContain('Dataset alias \"~unlinked\" is not linked to a dataset')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('handles API error during unlink', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [{datasetName: 'production', name: 'staging'}])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging/unlink',\n }).reply(500, {message: 'API Error'})\n\n mockInput.mockResolvedValueOnce('yes')\n\n const {error} = await testCommand(UnlinkAliasCommand, ['staging'])\n\n expect(error?.message).toContain('Dataset alias unlink failed: API Error')\n expect(error?.oclif?.exit).toBe(1)\n })\n})\n"],"names":["runCommand","getCliConfig","input","mockApi","testCommand","nock","afterEach","describe","expect","test","vi","DATASET_ALIASES_API_VERSION","NO_PROJECT_ID","UnlinkAliasCommand","mock","findProjectRoot","fn","mockResolvedValue","directory","root","type","api","projectId","getCliToken","actual","importActual","mockGetCliConfig","mocked","mockInput","clearAllMocks","pending","pendingMocks","cleanAll","toEqual","stdout","toMatchInlineSnapshot","each","aliasInput","apiHost","apiVersion","uri","reply","datasetName","name","method","aliasName","mockResolvedValueOnce","toContain","toHaveBeenCalledWith","message","stringContaining","validate","any","Function","stderr","not","toHaveBeenCalled","mockRejectedValueOnce","Error","error","oclif","exit","toBe"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/commands/dataset/alias/__tests__/unlink.test.ts"],"sourcesContent":["import {runCommand} from '@oclif/test'\nimport {input} from '@sanity/cli-core/ux'\nimport {mockApi, testCommand} from '@sanity/cli-test'\nimport nock from 'nock'\nimport {afterEach, describe, expect, test, vi} from 'vitest'\n\nimport {DATASET_ALIASES_API_VERSION} from '../../../../services/datasetAliases.js'\nimport {NO_PROJECT_ID} from '../../../../util/errorMessages.js'\nimport {UnlinkAliasCommand} from '../unlink.js'\n\nvi.mock('@sanity/cli-core/ux', async () => {\n const actual = await vi.importActual<typeof import('@sanity/cli-core/ux')>('@sanity/cli-core/ux')\n return {\n ...actual,\n input: vi.fn(),\n }\n})\n\nconst testProjectId = 'test-project'\n\nconst defaultMocks = {\n cliConfig: {api: {projectId: testProjectId}},\n projectRoot: {\n directory: '/test/path',\n path: '/test/path/sanity.config.ts',\n type: 'studio' as const,\n },\n token: 'test-token',\n}\n\nconst mockInput = vi.mocked(input)\n\ndescribe('#dataset:alias:unlink', () => {\n afterEach(() => {\n vi.clearAllMocks()\n const pending = nock.pendingMocks()\n nock.cleanAll()\n expect(pending, 'pending mocks').toEqual([])\n })\n\n test('help works correctly', async () => {\n const {stdout} = await runCommand(['dataset alias unlink', '--help'])\n expect(stdout).toMatchInlineSnapshot(`\n \"Unlink a dataset alias from its dataset within your project\n\n USAGE\n $ sanity dataset alias unlink [ALIASNAME] [--force]\n\n ARGUMENTS\n [ALIASNAME] Dataset alias name to unlink\n\n FLAGS\n --force Skip confirmation prompt and unlink immediately\n\n DESCRIPTION\n Unlink a dataset alias from its dataset within your project\n\n EXAMPLES\n Unlink an alias with interactive selection\n\n $ sanity dataset alias unlink\n\n Unlink alias \"conference\" with confirmation prompt\n\n $ sanity dataset alias unlink conference\n\n Unlink alias with explicit ~ prefix\n\n $ sanity dataset alias unlink ~conference\n\n Unlink alias \"conference\" without confirmation prompt\n\n $ sanity dataset alias unlink conference --force\n\n \"\n `)\n })\n\n test.each([\n ['staging', 'without ~ prefix'],\n ['~staging', 'with ~ prefix'],\n ])('unlinks alias with confirmation: %s (%s)', async (aliasInput) => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging/unlink',\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n mockInput.mockResolvedValueOnce('yes')\n\n const {stdout} = await testCommand(UnlinkAliasCommand, [aliasInput], {mocks: defaultMocks})\n\n expect(stdout).toContain('Dataset alias ~staging unlinked from production successfully')\n expect(mockInput).toHaveBeenCalledWith({\n message: expect.stringContaining(\n 'Are you ABSOLUTELY sure you want to unlink this alias from the \"production\" dataset?',\n ),\n validate: expect.any(Function),\n })\n })\n\n test('unlinks alias with force flag (skips confirmation)', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging/unlink',\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n const {stderr, stdout} = await testCommand(UnlinkAliasCommand, ['staging', '--force'], {\n mocks: defaultMocks,\n })\n\n expect(stdout).toContain('Dataset alias ~staging unlinked from production successfully')\n expect(stderr).toContain('\\'--force\\' used: skipping confirmation, unlinking alias \"~staging\"')\n expect(mockInput).not.toHaveBeenCalled()\n })\n\n test('prompts for alias name when no alias provided', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging/unlink',\n }).reply(200, {aliasName: 'staging', datasetName: 'production'})\n\n mockInput\n .mockResolvedValueOnce('staging') // alias name prompt\n .mockResolvedValueOnce('yes') // confirmation prompt\n\n const {stdout} = await testCommand(UnlinkAliasCommand, [], {mocks: defaultMocks})\n\n expect(stdout).toContain('Dataset alias ~staging unlinked from production successfully')\n expect(mockInput).toHaveBeenCalledWith({\n message: 'Alias name:',\n validate: expect.any(Function),\n })\n })\n\n test('handles user cancellation during confirmation', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n mockInput.mockRejectedValueOnce(new Error('User cancelled'))\n\n const {error} = await testCommand(UnlinkAliasCommand, ['staging'], {mocks: defaultMocks})\n\n expect(error?.message).toContain('Dataset alias unlink failed: User cancelled')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('shows error when no project ID available', async () => {\n const {error} = await testCommand(UnlinkAliasCommand, ['staging'], {\n mocks: {\n ...defaultMocks,\n cliConfig: {},\n },\n })\n\n expect(error?.message).toContain(NO_PROJECT_ID)\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('shows error when alias name is invalid', async () => {\n const {error} = await testCommand(UnlinkAliasCommand, ['invalid-alias!'], {mocks: defaultMocks})\n\n expect(error?.message).toContain(\n 'Alias name must only contain letters, numbers, dashes and underscores',\n )\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('shows error when alias does not exist', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n const {error} = await testCommand(UnlinkAliasCommand, ['nonexistent'], {mocks: defaultMocks})\n\n expect(error?.message).toContain('Dataset alias \"~nonexistent\" does not exist')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('shows error when alias exists but is not linked', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [\n {datasetName: 'production', name: 'staging'},\n {datasetName: null, name: 'unlinked'},\n ])\n\n const {error} = await testCommand(UnlinkAliasCommand, ['unlinked'], {mocks: defaultMocks})\n\n expect(error?.message).toContain('Dataset alias \"~unlinked\" is not linked to a dataset')\n expect(error?.oclif?.exit).toBe(1)\n })\n\n test('handles API error during unlink', async () => {\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n uri: '/aliases',\n }).reply(200, [{datasetName: 'production', name: 'staging'}])\n\n mockApi({\n apiHost: 'https://test-project.api.sanity.io',\n apiVersion: DATASET_ALIASES_API_VERSION,\n method: 'patch',\n uri: '/aliases/staging/unlink',\n }).reply(500, {message: 'API Error'})\n\n mockInput.mockResolvedValueOnce('yes')\n\n const {error} = await testCommand(UnlinkAliasCommand, ['staging'], {mocks: defaultMocks})\n\n expect(error?.message).toContain('Dataset alias unlink failed: API Error')\n expect(error?.oclif?.exit).toBe(1)\n })\n})\n"],"names":["runCommand","input","mockApi","testCommand","nock","afterEach","describe","expect","test","vi","DATASET_ALIASES_API_VERSION","NO_PROJECT_ID","UnlinkAliasCommand","mock","actual","importActual","fn","testProjectId","defaultMocks","cliConfig","api","projectId","projectRoot","directory","path","type","token","mockInput","mocked","clearAllMocks","pending","pendingMocks","cleanAll","toEqual","stdout","toMatchInlineSnapshot","each","aliasInput","apiHost","apiVersion","uri","reply","datasetName","name","method","aliasName","mockResolvedValueOnce","mocks","toContain","toHaveBeenCalledWith","message","stringContaining","validate","any","Function","stderr","not","toHaveBeenCalled","mockRejectedValueOnce","Error","error","oclif","exit","toBe"],"mappings":"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"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { Args, Flags } from '@oclif/core';
|
|
4
|
-
import { SanityCommand, subdebug } from '@sanity/cli-core';
|
|
4
|
+
import { getProjectCliClient, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
5
5
|
import { input, spinner } from '@sanity/cli-core/ux';
|
|
6
6
|
import { exportDataset } from '@sanity/export';
|
|
7
7
|
import boxen from 'boxen';
|
|
8
8
|
import prettyMs from 'pretty-ms';
|
|
9
9
|
import { validateDatasetName } from '../../actions/dataset/validateDatasetName.js';
|
|
10
10
|
import { promptForDataset } from '../../prompts/promptForDataset.js';
|
|
11
|
+
import { listDatasets } from '../../services/datasets.js';
|
|
11
12
|
import { absolutify } from '../../util/absolutify.js';
|
|
12
13
|
import { NO_PROJECT_ID } from '../../util/errorMessages.js';
|
|
13
14
|
const noop = ()=>null;
|
|
@@ -90,15 +91,14 @@ export class DatasetExportCommand extends SanityCommand {
|
|
|
90
91
|
exit: 1
|
|
91
92
|
});
|
|
92
93
|
}
|
|
93
|
-
|
|
94
|
-
const projectClient = await this.getProjectApiClient({
|
|
94
|
+
const projectClient = await getProjectCliClient({
|
|
95
95
|
apiVersion: '2023-05-26',
|
|
96
96
|
projectId,
|
|
97
97
|
requireUser: true
|
|
98
98
|
});
|
|
99
99
|
let datasets;
|
|
100
100
|
try {
|
|
101
|
-
datasets = await
|
|
101
|
+
datasets = await listDatasets(projectId);
|
|
102
102
|
} catch (error) {
|
|
103
103
|
exportDebug('Error listing datasets', error);
|
|
104
104
|
this.error(`Failed to list datasets:\n${error instanceof Error ? error.message : error}`, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/dataset/export.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport {type Writable} from 'node:stream'\n\nimport {Args, Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {input, spinner} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\nimport {exportDataset, type ExportOptions, type ExportProgress} from '@sanity/export'\nimport boxen from 'boxen'\nimport prettyMs from 'pretty-ms'\n\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {absolutify} from '../../util/absolutify.js'\nimport {NO_PROJECT_ID} from '../../util/errorMessages.js'\n\nconst noop = () => null\nconst exportDebug = subdebug('dataset:export')\n\nexport class DatasetExportCommand extends SanityCommand<typeof DatasetExportCommand> {\n static override args = {\n name: Args.string({\n description: 'Name of the dataset to export',\n }),\n // Args are order dependent\n // eslint-disable-next-line perfectionist/sort-objects\n destination: Args.string({\n description: 'Output destination file path',\n }),\n }\n\n static override description =\n 'Export dataset to local filesystem as a gzipped tarball. Assets failing with HTTP status codes 401, 403 and 404 upon download are ignored and excluded from export.'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> moviedb localPath.tar.gz',\n description: 'Export dataset \"moviedb\" to localPath.tar.gz',\n },\n {\n command: '<%= config.bin %> <%= command.id %> moviedb assetless.tar.gz --no-assets',\n description: 'Export dataset without assets',\n },\n {\n command: '<%= config.bin %> <%= command.id %> staging staging.tar.gz --raw',\n description: 'Export raw documents without asset reference rewriting',\n },\n {\n command: '<%= config.bin %> <%= command.id %> staging staging.tar.gz --types products,shops',\n description: 'Export specific document types',\n },\n ]\n\n static override flags = {\n 'asset-concurrency': Flags.integer({\n default: 8,\n description: 'Concurrent number of asset downloads',\n }),\n mode: Flags.string({\n default: 'stream',\n description:\n 'Mode to export documents with `cursor` might be more performant for larger datasets, but might not be as accurate if the dataset is being modified during export',\n options: ['stream', 'cursor'],\n }),\n 'no-assets': Flags.boolean({\n default: false,\n description: 'Export only non-asset documents and remove references to image assets',\n }),\n 'no-compress': Flags.boolean({\n default: false,\n description: 'Skips compressing tarball entries (still generates a gzip file)',\n }),\n 'no-drafts': Flags.boolean({\n default: false,\n description: 'Export only published versions of documents',\n }),\n overwrite: Flags.boolean({\n default: false,\n description: 'Overwrite any file with the same name',\n }),\n raw: Flags.boolean({\n default: false,\n description: 'Extract only documents, without rewriting asset references',\n }),\n types: Flags.string({\n description: 'Defines which document types to export (comma-separated)',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(DatasetExportCommand)\n const {destination: targetDestination, name: targetDataset} = args\n\n // Get project configuration\n const cliConfig = await this.getCliConfig()\n const projectId = await this.getProjectId()\n\n if (!projectId) {\n this.error(NO_PROJECT_ID, {\n exit: 1,\n })\n }\n\n // Get the project API client\n const projectClient = await this.getProjectApiClient({\n apiVersion: '2023-05-26',\n projectId,\n requireUser: true,\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await projectClient.datasets.list()\n } catch (error) {\n exportDebug('Error listing datasets', error)\n this.error(`Failed to list datasets:\\n${error instanceof Error ? error.message : error}`, {\n exit: 1,\n })\n }\n\n // Determine dataset name\n let dataset = targetDataset\n try {\n if (!dataset) {\n // Get default dataset from config\n const defaultDataset = cliConfig.api?.dataset\n if (defaultDataset) {\n dataset = defaultDataset\n this.log(`Using default dataset: ${dataset}`)\n } else {\n dataset = await promptForDataset({allowCreation: false, datasets})\n }\n }\n } catch (error) {\n exportDebug('Error selecting dataset', error)\n this.error(`Failed to select dataset:\\n${error instanceof Error ? error.message : error}`, {\n exit: 1,\n })\n }\n\n // Validate dataset name\n const dsError = validateDatasetName(dataset)\n if (dsError) {\n this.error(dsError, {exit: 1})\n }\n\n // Verify existence of dataset before trying to export from it\n if (!datasets.some((set) => set.name === dataset)) {\n this.error(`Dataset with name \"${dataset}\" not found`, {exit: 1})\n }\n\n this.log(\n boxen(\n `Exporting from:\nprojectId: ${projectId.padEnd(44)}\ndataset: ${dataset.padEnd(46)}`,\n {\n borderColor: 'yellow',\n borderStyle: 'round',\n },\n ),\n )\n\n // Determine output path\n let destinationPath = targetDestination\n if (!destinationPath) {\n destinationPath = await this.promptForDestination({dataset})\n }\n\n const outputPath = await this.getOutputPath(destinationPath, dataset, flags)\n if (!outputPath) {\n this.error('Cancelled', {exit: 1})\n }\n\n // Prepare export options\n const {fail, onProgress, succeed} = this.createProgressHandler()\n const exportOptions: ExportOptions = {\n assetConcurrency: flags['asset-concurrency'],\n assets: !flags['no-assets'],\n client: projectClient,\n compress: !flags['no-compress'],\n dataset,\n drafts: !flags['no-drafts'],\n mode: flags.mode === 'cursor' || flags.mode === 'stream' ? flags.mode : undefined,\n onProgress,\n outputPath,\n raw: flags.raw,\n types: flags.types ? flags.types.split(',') : undefined,\n }\n\n const start = Date.now()\n try {\n await exportDataset(exportOptions)\n succeed()\n this.log(`Export finished (${prettyMs(Date.now() - start)})`)\n } catch (error) {\n fail()\n const err = error instanceof Error ? error : new Error(String(error))\n exportDebug('Export failed', err)\n this.error(`Export failed: ${err.message}`, {exit: 1})\n }\n }\n\n private createProgressHandler() {\n let currentSpinner: ReturnType<typeof spinner> | null = null\n let currentStep = ''\n\n const onProgress = (progress: ExportProgress) => {\n if (progress.step !== currentStep) {\n // Complete previous step\n succeed()\n\n // Start new step\n currentStep = progress.step\n currentSpinner = spinner(progress.step).start()\n } else if (progress.step === currentStep && progress.update && currentSpinner) {\n // Update current step with progress info\n currentSpinner.text = `${progress.step} (${progress.current}/${progress.total})`\n }\n }\n\n const succeed = () => {\n currentSpinner?.succeed()\n }\n\n const fail = () => {\n currentSpinner?.fail()\n }\n\n return {fail, onProgress, succeed}\n }\n\n private async getOutputPath(\n destination: string,\n dataset: string,\n flags: {overwrite?: boolean},\n ): Promise<string | Writable> {\n if (destination === '-') {\n return process.stdout\n }\n\n const dstPath = path.isAbsolute(destination)\n ? destination\n : path.resolve(process.cwd(), destination)\n\n const dstStats = await fs.stat(dstPath).catch(noop)\n const looksLikeFile = dstStats ? dstStats.isFile() : path.basename(dstPath).includes('.')\n\n if (!dstStats) {\n const createPath = looksLikeFile ? path.dirname(dstPath) : dstPath\n try {\n await fs.mkdir(createPath, {recursive: true})\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n const errorWithCode = err as Error & {code?: string}\n if (errorWithCode.code === 'EACCES') {\n this.error(\n `Permission denied: Cannot create directory \"${createPath}\". Please check write permissions.`,\n {\n exit: 1,\n },\n )\n } else {\n this.error(`Failed to create directory \"${createPath}\": ${err.message}`, {\n exit: 1,\n })\n }\n }\n }\n\n const finalPath = looksLikeFile ? dstPath : path.join(dstPath, `${dataset}.tar.gz`)\n const finalPathStats = await fs.stat(finalPath).catch(noop)\n\n if (!flags.overwrite && finalPathStats && finalPathStats.isFile()) {\n this.error(`File \"${finalPath}\" already exists. Use --overwrite flag to overwrite it.`, {\n exit: 1,\n })\n }\n\n return finalPath\n }\n\n private promptForDestination(options: {dataset: string; workDir?: string}): Promise<string> {\n const {dataset, workDir = process.cwd()} = options\n\n const defaultPath = path.join(workDir, `${dataset}.tar.gz`)\n\n return input({\n default: defaultPath,\n message: 'Output path:',\n transformer: (value: string) => absolutify(value.trim()),\n validate: (value: string) => {\n const trimmed = value.trim()\n if (!trimmed) {\n return 'Please provide a valid output path'\n }\n return true\n },\n })\n }\n}\n"],"names":["fs","path","Args","Flags","SanityCommand","subdebug","input","spinner","exportDataset","boxen","prettyMs","validateDatasetName","promptForDataset","absolutify","NO_PROJECT_ID","noop","exportDebug","DatasetExportCommand","args","name","string","description","destination","examples","command","flags","integer","default","mode","options","boolean","overwrite","raw","types","run","parse","targetDestination","targetDataset","cliConfig","getCliConfig","projectId","getProjectId","error","exit","projectClient","getProjectApiClient","apiVersion","requireUser","datasets","list","Error","message","dataset","defaultDataset","api","log","allowCreation","dsError","some","set","padEnd","borderColor","borderStyle","destinationPath","promptForDestination","outputPath","getOutputPath","fail","onProgress","succeed","createProgressHandler","exportOptions","assetConcurrency","assets","client","compress","drafts","undefined","split","start","Date","now","err","String","currentSpinner","currentStep","progress","step","update","text","current","total","process","stdout","dstPath","isAbsolute","resolve","cwd","dstStats","stat","catch","looksLikeFile","isFile","basename","includes","createPath","dirname","mkdir","recursive","errorWithCode","code","finalPath","join","finalPathStats","workDir","defaultPath","transformer","value","trim","validate","trimmed"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/dataset/export.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport {type Writable} from 'node:stream'\n\nimport {Args, Flags} from '@oclif/core'\nimport {getProjectCliClient, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {input, spinner} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\nimport {exportDataset, type ExportOptions, type ExportProgress} from '@sanity/export'\nimport boxen from 'boxen'\nimport prettyMs from 'pretty-ms'\n\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {absolutify} from '../../util/absolutify.js'\nimport {NO_PROJECT_ID} from '../../util/errorMessages.js'\n\nconst noop = () => null\nconst exportDebug = subdebug('dataset:export')\n\nexport class DatasetExportCommand extends SanityCommand<typeof DatasetExportCommand> {\n static override args = {\n name: Args.string({\n description: 'Name of the dataset to export',\n }),\n // Args are order dependent\n // eslint-disable-next-line perfectionist/sort-objects\n destination: Args.string({\n description: 'Output destination file path',\n }),\n }\n\n static override description =\n 'Export dataset to local filesystem as a gzipped tarball. Assets failing with HTTP status codes 401, 403 and 404 upon download are ignored and excluded from export.'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> moviedb localPath.tar.gz',\n description: 'Export dataset \"moviedb\" to localPath.tar.gz',\n },\n {\n command: '<%= config.bin %> <%= command.id %> moviedb assetless.tar.gz --no-assets',\n description: 'Export dataset without assets',\n },\n {\n command: '<%= config.bin %> <%= command.id %> staging staging.tar.gz --raw',\n description: 'Export raw documents without asset reference rewriting',\n },\n {\n command: '<%= config.bin %> <%= command.id %> staging staging.tar.gz --types products,shops',\n description: 'Export specific document types',\n },\n ]\n\n static override flags = {\n 'asset-concurrency': Flags.integer({\n default: 8,\n description: 'Concurrent number of asset downloads',\n }),\n mode: Flags.string({\n default: 'stream',\n description:\n 'Mode to export documents with `cursor` might be more performant for larger datasets, but might not be as accurate if the dataset is being modified during export',\n options: ['stream', 'cursor'],\n }),\n 'no-assets': Flags.boolean({\n default: false,\n description: 'Export only non-asset documents and remove references to image assets',\n }),\n 'no-compress': Flags.boolean({\n default: false,\n description: 'Skips compressing tarball entries (still generates a gzip file)',\n }),\n 'no-drafts': Flags.boolean({\n default: false,\n description: 'Export only published versions of documents',\n }),\n overwrite: Flags.boolean({\n default: false,\n description: 'Overwrite any file with the same name',\n }),\n raw: Flags.boolean({\n default: false,\n description: 'Extract only documents, without rewriting asset references',\n }),\n types: Flags.string({\n description: 'Defines which document types to export (comma-separated)',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(DatasetExportCommand)\n const {destination: targetDestination, name: targetDataset} = args\n\n // Get project configuration\n const cliConfig = await this.getCliConfig()\n const projectId = await this.getProjectId()\n\n if (!projectId) {\n this.error(NO_PROJECT_ID, {\n exit: 1,\n })\n }\n\n const projectClient = await getProjectCliClient({\n apiVersion: '2023-05-26',\n projectId,\n requireUser: true,\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n exportDebug('Error listing datasets', error)\n this.error(`Failed to list datasets:\\n${error instanceof Error ? error.message : error}`, {\n exit: 1,\n })\n }\n\n // Determine dataset name\n let dataset = targetDataset\n try {\n if (!dataset) {\n // Get default dataset from config\n const defaultDataset = cliConfig.api?.dataset\n if (defaultDataset) {\n dataset = defaultDataset\n this.log(`Using default dataset: ${dataset}`)\n } else {\n dataset = await promptForDataset({allowCreation: false, datasets})\n }\n }\n } catch (error) {\n exportDebug('Error selecting dataset', error)\n this.error(`Failed to select dataset:\\n${error instanceof Error ? error.message : error}`, {\n exit: 1,\n })\n }\n\n // Validate dataset name\n const dsError = validateDatasetName(dataset)\n if (dsError) {\n this.error(dsError, {exit: 1})\n }\n\n // Verify existence of dataset before trying to export from it\n if (!datasets.some((set) => set.name === dataset)) {\n this.error(`Dataset with name \"${dataset}\" not found`, {exit: 1})\n }\n\n this.log(\n boxen(\n `Exporting from:\nprojectId: ${projectId.padEnd(44)}\ndataset: ${dataset.padEnd(46)}`,\n {\n borderColor: 'yellow',\n borderStyle: 'round',\n },\n ),\n )\n\n // Determine output path\n let destinationPath = targetDestination\n if (!destinationPath) {\n destinationPath = await this.promptForDestination({dataset})\n }\n\n const outputPath = await this.getOutputPath(destinationPath, dataset, flags)\n if (!outputPath) {\n this.error('Cancelled', {exit: 1})\n }\n\n // Prepare export options\n const {fail, onProgress, succeed} = this.createProgressHandler()\n const exportOptions: ExportOptions = {\n assetConcurrency: flags['asset-concurrency'],\n assets: !flags['no-assets'],\n client: projectClient,\n compress: !flags['no-compress'],\n dataset,\n drafts: !flags['no-drafts'],\n mode: flags.mode === 'cursor' || flags.mode === 'stream' ? flags.mode : undefined,\n onProgress,\n outputPath,\n raw: flags.raw,\n types: flags.types ? flags.types.split(',') : undefined,\n }\n\n const start = Date.now()\n try {\n await exportDataset(exportOptions)\n succeed()\n this.log(`Export finished (${prettyMs(Date.now() - start)})`)\n } catch (error) {\n fail()\n const err = error instanceof Error ? error : new Error(String(error))\n exportDebug('Export failed', err)\n this.error(`Export failed: ${err.message}`, {exit: 1})\n }\n }\n\n private createProgressHandler() {\n let currentSpinner: ReturnType<typeof spinner> | null = null\n let currentStep = ''\n\n const onProgress = (progress: ExportProgress) => {\n if (progress.step !== currentStep) {\n // Complete previous step\n succeed()\n\n // Start new step\n currentStep = progress.step\n currentSpinner = spinner(progress.step).start()\n } else if (progress.step === currentStep && progress.update && currentSpinner) {\n // Update current step with progress info\n currentSpinner.text = `${progress.step} (${progress.current}/${progress.total})`\n }\n }\n\n const succeed = () => {\n currentSpinner?.succeed()\n }\n\n const fail = () => {\n currentSpinner?.fail()\n }\n\n return {fail, onProgress, succeed}\n }\n\n private async getOutputPath(\n destination: string,\n dataset: string,\n flags: {overwrite?: boolean},\n ): Promise<string | Writable> {\n if (destination === '-') {\n return process.stdout\n }\n\n const dstPath = path.isAbsolute(destination)\n ? destination\n : path.resolve(process.cwd(), destination)\n\n const dstStats = await fs.stat(dstPath).catch(noop)\n const looksLikeFile = dstStats ? dstStats.isFile() : path.basename(dstPath).includes('.')\n\n if (!dstStats) {\n const createPath = looksLikeFile ? path.dirname(dstPath) : dstPath\n try {\n await fs.mkdir(createPath, {recursive: true})\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n const errorWithCode = err as Error & {code?: string}\n if (errorWithCode.code === 'EACCES') {\n this.error(\n `Permission denied: Cannot create directory \"${createPath}\". Please check write permissions.`,\n {\n exit: 1,\n },\n )\n } else {\n this.error(`Failed to create directory \"${createPath}\": ${err.message}`, {\n exit: 1,\n })\n }\n }\n }\n\n const finalPath = looksLikeFile ? dstPath : path.join(dstPath, `${dataset}.tar.gz`)\n const finalPathStats = await fs.stat(finalPath).catch(noop)\n\n if (!flags.overwrite && finalPathStats && finalPathStats.isFile()) {\n this.error(`File \"${finalPath}\" already exists. Use --overwrite flag to overwrite it.`, {\n exit: 1,\n })\n }\n\n return finalPath\n }\n\n private promptForDestination(options: {dataset: string; workDir?: string}): Promise<string> {\n const {dataset, workDir = process.cwd()} = options\n\n const defaultPath = path.join(workDir, `${dataset}.tar.gz`)\n\n return input({\n default: defaultPath,\n message: 'Output path:',\n transformer: (value: string) => absolutify(value.trim()),\n validate: (value: string) => {\n const trimmed = value.trim()\n if (!trimmed) {\n return 'Please provide a valid output path'\n }\n return true\n },\n })\n }\n}\n"],"names":["fs","path","Args","Flags","getProjectCliClient","SanityCommand","subdebug","input","spinner","exportDataset","boxen","prettyMs","validateDatasetName","promptForDataset","listDatasets","absolutify","NO_PROJECT_ID","noop","exportDebug","DatasetExportCommand","args","name","string","description","destination","examples","command","flags","integer","default","mode","options","boolean","overwrite","raw","types","run","parse","targetDestination","targetDataset","cliConfig","getCliConfig","projectId","getProjectId","error","exit","projectClient","apiVersion","requireUser","datasets","Error","message","dataset","defaultDataset","api","log","allowCreation","dsError","some","set","padEnd","borderColor","borderStyle","destinationPath","promptForDestination","outputPath","getOutputPath","fail","onProgress","succeed","createProgressHandler","exportOptions","assetConcurrency","assets","client","compress","drafts","undefined","split","start","Date","now","err","String","currentSpinner","currentStep","progress","step","update","text","current","total","process","stdout","dstPath","isAbsolute","resolve","cwd","dstStats","stat","catch","looksLikeFile","isFile","basename","includes","createPath","dirname","mkdir","recursive","errorWithCode","code","finalPath","join","finalPathStats","workDir","defaultPath","transformer","value","trim","validate","trimmed"],"mappings":"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"}
|
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
import { runCommand } from '@oclif/test';
|
|
2
|
-
import { getCliConfig, getProjectCliClient } from '@sanity/cli-core';
|
|
3
2
|
import { testCommand } from '@sanity/cli-test';
|
|
4
3
|
import { afterEach, describe, expect, test, vi } from 'vitest';
|
|
5
4
|
import { NO_PROJECT_ID } from '../../../../util/errorMessages.js';
|
|
6
5
|
import { DatasetVisibilityGetCommand } from '../get.js';
|
|
7
|
-
vi.
|
|
8
|
-
|
|
9
|
-
directory: '/test/path',
|
|
10
|
-
root: '/test/path',
|
|
11
|
-
type: 'studio'
|
|
12
|
-
})
|
|
13
|
-
}));
|
|
14
|
-
vi.mock('../../../../../../cli-core/src/config/cli/getCliConfig.js', ()=>({
|
|
15
|
-
getCliConfig: vi.fn()
|
|
16
|
-
}));
|
|
17
|
-
vi.mock('../../../../../../cli-core/src/services/getCliToken.js', ()=>({
|
|
18
|
-
getCliToken: vi.fn().mockResolvedValue('test-token')
|
|
19
|
-
}));
|
|
20
|
-
vi.mock(import('../../../../../../cli-core/src/services/apiClient.js'), async (importOriginal)=>{
|
|
6
|
+
const mockListDatasets = vi.hoisted(()=>vi.fn());
|
|
7
|
+
vi.mock('@sanity/cli-core', async (importOriginal)=>{
|
|
21
8
|
const actual = await importOriginal();
|
|
22
9
|
return {
|
|
23
10
|
...actual,
|
|
24
|
-
getProjectCliClient: vi.fn()
|
|
11
|
+
getProjectCliClient: vi.fn().mockResolvedValue({
|
|
12
|
+
datasets: {
|
|
13
|
+
list: mockListDatasets
|
|
14
|
+
}
|
|
15
|
+
})
|
|
25
16
|
};
|
|
26
17
|
});
|
|
27
|
-
const
|
|
28
|
-
const
|
|
18
|
+
const testProjectId = 'test-project';
|
|
19
|
+
const defaultMocks = {
|
|
20
|
+
cliConfig: {
|
|
21
|
+
api: {
|
|
22
|
+
projectId: testProjectId
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
projectRoot: {
|
|
26
|
+
directory: '/test/path',
|
|
27
|
+
path: '/test/path/sanity.config.ts',
|
|
28
|
+
type: 'studio'
|
|
29
|
+
},
|
|
30
|
+
token: 'test-token'
|
|
31
|
+
};
|
|
29
32
|
describe('#dataset:visibility:get', ()=>{
|
|
30
33
|
afterEach(()=>{
|
|
31
34
|
vi.clearAllMocks();
|
|
@@ -56,89 +59,67 @@ describe('#dataset:visibility:get', ()=>{
|
|
|
56
59
|
`);
|
|
57
60
|
});
|
|
58
61
|
test('gets dataset visibility successfully', async ()=>{
|
|
59
|
-
|
|
62
|
+
mockListDatasets.mockResolvedValue([
|
|
60
63
|
{
|
|
61
64
|
aclMode: 'private',
|
|
62
65
|
name: 'my-dataset'
|
|
63
66
|
}
|
|
64
|
-
];
|
|
65
|
-
mockGetCliConfig.mockResolvedValue({
|
|
66
|
-
api: {
|
|
67
|
-
projectId: 'test-project'
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
mockGetProjectCliClient.mockResolvedValue({
|
|
71
|
-
datasets: {
|
|
72
|
-
list: vi.fn().mockResolvedValue(mockDatasets)
|
|
73
|
-
}
|
|
74
|
-
});
|
|
67
|
+
]);
|
|
75
68
|
const { stdout } = await testCommand(DatasetVisibilityGetCommand, [
|
|
76
69
|
'my-dataset'
|
|
77
|
-
]
|
|
70
|
+
], {
|
|
71
|
+
mocks: defaultMocks
|
|
72
|
+
});
|
|
78
73
|
expect(stdout).toContain('private');
|
|
79
74
|
});
|
|
80
75
|
test('shows error when dataset is not found', async ()=>{
|
|
81
|
-
|
|
76
|
+
mockListDatasets.mockResolvedValue([
|
|
82
77
|
{
|
|
83
78
|
aclMode: 'public',
|
|
84
79
|
name: 'other-dataset'
|
|
85
80
|
}
|
|
86
|
-
];
|
|
87
|
-
mockGetCliConfig.mockResolvedValue({
|
|
88
|
-
api: {
|
|
89
|
-
projectId: 'test-project'
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
mockGetProjectCliClient.mockResolvedValue({
|
|
93
|
-
datasets: {
|
|
94
|
-
list: vi.fn().mockResolvedValue(mockDatasets)
|
|
95
|
-
}
|
|
96
|
-
});
|
|
81
|
+
]);
|
|
97
82
|
const { error } = await testCommand(DatasetVisibilityGetCommand, [
|
|
98
83
|
'not-found'
|
|
99
|
-
]
|
|
84
|
+
], {
|
|
85
|
+
mocks: defaultMocks
|
|
86
|
+
});
|
|
100
87
|
expect(error?.message).toContain('Dataset not found: not-found');
|
|
101
88
|
expect(error?.oclif?.exit).toBe(1);
|
|
102
89
|
});
|
|
103
90
|
test('shows error for invalid dataset name', async ()=>{
|
|
104
91
|
const invalidDatasetName = 'invalid-dataset-name!';
|
|
105
|
-
mockGetCliConfig.mockResolvedValue({
|
|
106
|
-
api: {
|
|
107
|
-
projectId: 'test-project'
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
92
|
const { error } = await testCommand(DatasetVisibilityGetCommand, [
|
|
111
93
|
invalidDatasetName
|
|
112
|
-
]
|
|
94
|
+
], {
|
|
95
|
+
mocks: defaultMocks
|
|
96
|
+
});
|
|
113
97
|
expect(error?.message).toContain('Dataset name must only contain');
|
|
114
98
|
expect(error?.oclif?.exit).toBe(1);
|
|
115
99
|
});
|
|
116
100
|
test('shows error when no project ID is available', async ()=>{
|
|
117
|
-
mockGetCliConfig.mockResolvedValue({
|
|
118
|
-
api: {
|
|
119
|
-
projectId: undefined
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
101
|
const { error } = await testCommand(DatasetVisibilityGetCommand, [
|
|
123
102
|
'my-dataset'
|
|
124
|
-
]
|
|
103
|
+
], {
|
|
104
|
+
mocks: {
|
|
105
|
+
...defaultMocks,
|
|
106
|
+
cliConfig: {
|
|
107
|
+
api: {
|
|
108
|
+
projectId: undefined
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
125
113
|
expect(error?.message).toContain(NO_PROJECT_ID);
|
|
126
114
|
expect(error?.oclif?.exit).toBe(1);
|
|
127
115
|
});
|
|
128
116
|
test('handles error when listing datasets', async ()=>{
|
|
129
|
-
|
|
130
|
-
api: {
|
|
131
|
-
projectId: 'test-project'
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
mockGetProjectCliClient.mockResolvedValue({
|
|
135
|
-
datasets: {
|
|
136
|
-
list: vi.fn().mockRejectedValue(new Error('Network error'))
|
|
137
|
-
}
|
|
138
|
-
});
|
|
117
|
+
mockListDatasets.mockRejectedValue(new Error('Network error'));
|
|
139
118
|
const { error } = await testCommand(DatasetVisibilityGetCommand, [
|
|
140
119
|
'my-dataset'
|
|
141
|
-
]
|
|
120
|
+
], {
|
|
121
|
+
mocks: defaultMocks
|
|
122
|
+
});
|
|
142
123
|
expect(error?.message).toContain('Failed to list datasets');
|
|
143
124
|
expect(error?.oclif?.exit).toBe(1);
|
|
144
125
|
});
|