@sanity/cli 6.0.0-alpha.3 → 6.0.0-alpha.4

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.
Files changed (110) hide show
  1. package/dist/actions/auth/login/{index.js → login.js} +1 -1
  2. package/dist/actions/auth/login/{index.js.map → login.js.map} +1 -1
  3. package/dist/actions/organizations/getOrganizationChoices.d.ts +6 -0
  4. package/dist/actions/organizations/getOrganizationChoices.js +23 -0
  5. package/dist/actions/organizations/getOrganizationChoices.js.map +1 -0
  6. package/dist/actions/organizations/getOrganizationsWithAttachGrantInfo.d.ts +2 -0
  7. package/dist/actions/organizations/getOrganizationsWithAttachGrantInfo.js +9 -0
  8. package/dist/actions/organizations/getOrganizationsWithAttachGrantInfo.js.map +1 -0
  9. package/dist/actions/organizations/hasProjectAttachGrant.d.ts +1 -0
  10. package/dist/actions/organizations/hasProjectAttachGrant.js +24 -0
  11. package/dist/actions/organizations/hasProjectAttachGrant.js.map +1 -0
  12. package/dist/actions/schema/utils/schemaStoreValidation.js +2 -2
  13. package/dist/actions/schema/utils/schemaStoreValidation.js.map +1 -1
  14. package/dist/commands/__tests__/init/init.authentication.test.js +60 -0
  15. package/dist/commands/__tests__/init/init.authentication.test.js.map +1 -0
  16. package/dist/commands/__tests__/init/init.create-new-project.test.js +196 -0
  17. package/dist/commands/__tests__/init/init.create-new-project.test.js.map +1 -0
  18. package/dist/commands/__tests__/init/init.plan.test.js +220 -0
  19. package/dist/commands/__tests__/init/init.plan.test.js.map +1 -0
  20. package/dist/commands/__tests__/init/init.setup.test.js +279 -0
  21. package/dist/commands/__tests__/init/init.setup.test.js.map +1 -0
  22. package/dist/commands/__tests__/migration.test.js +119 -0
  23. package/dist/commands/__tests__/migration.test.js.map +1 -0
  24. package/dist/commands/backup/__tests__/download.test.js +3 -3
  25. package/dist/commands/backup/__tests__/download.test.js.map +1 -1
  26. package/dist/commands/dataset/__tests__/import.test.js +2 -2
  27. package/dist/commands/dataset/__tests__/import.test.js.map +1 -1
  28. package/dist/commands/documents/__tests__/query.test.js +3 -3
  29. package/dist/commands/documents/__tests__/query.test.js.map +1 -1
  30. package/dist/commands/init.d.ts +4 -0
  31. package/dist/commands/init.js +151 -18
  32. package/dist/commands/init.js.map +1 -1
  33. package/dist/commands/login.js +1 -1
  34. package/dist/commands/login.js.map +1 -1
  35. package/dist/services/organizations.d.ts +40 -0
  36. package/dist/services/organizations.js +41 -0
  37. package/dist/services/organizations.js.map +1 -0
  38. package/dist/services/projects.d.ts +20 -0
  39. package/dist/services/projects.js +30 -1
  40. package/dist/services/projects.js.map +1 -1
  41. package/dist/services/user.d.ts +2 -0
  42. package/dist/services/user.js +11 -0
  43. package/dist/services/user.js.map +1 -0
  44. package/oclif.config.js +6 -1
  45. package/oclif.manifest.json +33 -184
  46. package/package.json +7 -7
  47. package/dist/actions/migration/getMigrationRootDirectory.d.ts +0 -2
  48. package/dist/actions/migration/getMigrationRootDirectory.js +0 -14
  49. package/dist/actions/migration/getMigrationRootDirectory.js.map +0 -1
  50. package/dist/actions/migration/resolveMigrations.d.ts +0 -19
  51. package/dist/actions/migration/resolveMigrations.js +0 -43
  52. package/dist/actions/migration/resolveMigrations.js.map +0 -1
  53. package/dist/actions/migration/templates/__tests__/minimalAdvanced.test.js +0 -65
  54. package/dist/actions/migration/templates/__tests__/minimalAdvanced.test.js.map +0 -1
  55. package/dist/actions/migration/templates/__tests__/minimalSimple.test.js +0 -145
  56. package/dist/actions/migration/templates/__tests__/minimalSimple.test.js.map +0 -1
  57. package/dist/actions/migration/templates/__tests__/renameField.test.js +0 -63
  58. package/dist/actions/migration/templates/__tests__/renameField.test.js.map +0 -1
  59. package/dist/actions/migration/templates/__tests__/renameType.test.js +0 -61
  60. package/dist/actions/migration/templates/__tests__/renameType.test.js.map +0 -1
  61. package/dist/actions/migration/templates/__tests__/stringToPTE.test.js +0 -87
  62. package/dist/actions/migration/templates/__tests__/stringToPTE.test.js.map +0 -1
  63. package/dist/actions/migration/templates/index.d.ts +0 -5
  64. package/dist/actions/migration/templates/index.js +0 -7
  65. package/dist/actions/migration/templates/index.js.map +0 -1
  66. package/dist/actions/migration/templates/minimalAdvanced.d.ts +0 -4
  67. package/dist/actions/migration/templates/minimalAdvanced.js +0 -21
  68. package/dist/actions/migration/templates/minimalAdvanced.js.map +0 -1
  69. package/dist/actions/migration/templates/minimalSimple.d.ts +0 -4
  70. package/dist/actions/migration/templates/minimalSimple.js +0 -61
  71. package/dist/actions/migration/templates/minimalSimple.js.map +0 -1
  72. package/dist/actions/migration/templates/renameField.d.ts +0 -4
  73. package/dist/actions/migration/templates/renameField.js +0 -20
  74. package/dist/actions/migration/templates/renameField.js.map +0 -1
  75. package/dist/actions/migration/templates/renameType.d.ts +0 -4
  76. package/dist/actions/migration/templates/renameType.js +0 -19
  77. package/dist/actions/migration/templates/renameType.js.map +0 -1
  78. package/dist/actions/migration/templates/stringToPTE.d.ts +0 -4
  79. package/dist/actions/migration/templates/stringToPTE.js +0 -32
  80. package/dist/actions/migration/templates/stringToPTE.js.map +0 -1
  81. package/dist/commands/__tests__/init.test.js +0 -411
  82. package/dist/commands/__tests__/init.test.js.map +0 -1
  83. package/dist/commands/migration/__tests__/create.test.js +0 -296
  84. package/dist/commands/migration/__tests__/create.test.js.map +0 -1
  85. package/dist/commands/migration/__tests__/list.test.js +0 -166
  86. package/dist/commands/migration/__tests__/list.test.js.map +0 -1
  87. package/dist/commands/migration/__tests__/run.test.js +0 -481
  88. package/dist/commands/migration/__tests__/run.test.js.map +0 -1
  89. package/dist/commands/migration/create.d.ts +0 -17
  90. package/dist/commands/migration/create.js +0 -143
  91. package/dist/commands/migration/create.js.map +0 -1
  92. package/dist/commands/migration/list.d.ts +0 -9
  93. package/dist/commands/migration/list.js +0 -61
  94. package/dist/commands/migration/list.js.map +0 -1
  95. package/dist/commands/migration/run.d.ts +0 -26
  96. package/dist/commands/migration/run.js +0 -271
  97. package/dist/commands/migration/run.js.map +0 -1
  98. package/dist/util/migration/constants.d.ts +0 -3
  99. package/dist/util/migration/constants.js +0 -10
  100. package/dist/util/migration/constants.js.map +0 -1
  101. package/dist/util/migration/ensureApiVersionFormat.d.ts +0 -9
  102. package/dist/util/migration/ensureApiVersionFormat.js +0 -16
  103. package/dist/util/migration/ensureApiVersionFormat.js.map +0 -1
  104. package/dist/util/migration/prettyMutationFormatter.d.ts +0 -8
  105. package/dist/util/migration/prettyMutationFormatter.js +0 -141
  106. package/dist/util/migration/prettyMutationFormatter.js.map +0 -1
  107. package/dist/utils/migration/resolveMigrationScript.d.ts +0 -44
  108. package/dist/utils/migration/resolveMigrationScript.js +0 -74
  109. package/dist/utils/migration/resolveMigrationScript.js.map +0 -1
  110. /package/dist/actions/auth/login/{index.d.ts → login.d.ts} +0 -0
@@ -1,296 +0,0 @@
1
- import { access, mkdir, writeFile } from 'node:fs/promises';
2
- import { runCommand } from '@oclif/test';
3
- import { testCommand } from '@sanity/cli-test';
4
- import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
5
- import { CreateMigrationCommand } from '../create.js';
6
- const mocks = vi.hoisted(()=>({
7
- confirm: vi.fn(),
8
- findProjectRoot: vi.fn(),
9
- input: vi.fn(),
10
- select: vi.fn()
11
- }));
12
- const mockTemplates = vi.hoisted(()=>({
13
- minimalAdvanced: vi.fn(),
14
- minimalSimple: vi.fn(),
15
- renameField: vi.fn(),
16
- renameType: vi.fn(),
17
- stringToPTE: vi.fn()
18
- }));
19
- vi.mock('node:fs');
20
- vi.mock('node:fs/promises', ()=>({
21
- access: vi.fn(),
22
- mkdir: vi.fn(),
23
- writeFile: vi.fn()
24
- }));
25
- vi.mock('@sanity/cli-core/ux', async ()=>{
26
- const actual = await vi.importActual('@sanity/cli-core/ux');
27
- return {
28
- ...actual,
29
- confirm: mocks.confirm,
30
- input: mocks.input,
31
- select: mocks.select
32
- };
33
- });
34
- vi.mock('../../../../../cli-core/src/config/findProjectRoot.js', ()=>({
35
- findProjectRoot: mocks.findProjectRoot
36
- }));
37
- vi.mock('../../../actions/migration/templates/index.js', ()=>mockTemplates);
38
- const mockConfirm = mocks.confirm;
39
- const mockFindProjectRoot = mocks.findProjectRoot;
40
- const mockInput = mocks.input;
41
- const mockSelect = mocks.select;
42
- const mockAccess = vi.mocked(access);
43
- const mockMkdir = vi.mocked(mkdir);
44
- const mockWriteFile = vi.mocked(writeFile);
45
- describe('#migration:create', ()=>{
46
- beforeEach(()=>{
47
- mockFindProjectRoot.mockResolvedValue({
48
- directory: '/test/path',
49
- root: '/test/path',
50
- type: 'studio'
51
- });
52
- });
53
- afterEach(()=>{
54
- vi.clearAllMocks();
55
- });
56
- test('--help works', async ()=>{
57
- const { stdout } = await runCommand([
58
- 'migration create',
59
- '--help'
60
- ]);
61
- expect(stdout).toMatchInlineSnapshot(`
62
- "Create a new migration within your project
63
-
64
- USAGE
65
- $ sanity migration create [TITLE]
66
-
67
- ARGUMENTS
68
- [TITLE] Title of migration
69
-
70
- DESCRIPTION
71
- Create a new migration within your project
72
-
73
- EXAMPLES
74
- Create a new migration, prompting for title and options
75
-
76
- $ sanity migration create
77
-
78
- Create a new migration with the provided title, prompting for options
79
-
80
- $ sanity migration create "Rename field from location to address"
81
-
82
- "
83
- `);
84
- });
85
- test('prompts user to enter title when no title argument is provided', async ()=>{
86
- await testCommand(CreateMigrationCommand);
87
- expect(mockInput).toHaveBeenCalledWith({
88
- message: 'Title of migration (e.g. "Rename field from location to address")',
89
- validate: expect.any(Function)
90
- });
91
- });
92
- test('skips title prompt when title is provided', async ()=>{
93
- await testCommand(CreateMigrationCommand, [
94
- 'Migration Title'
95
- ]);
96
- expect(mockInput).toHaveBeenCalledWith({
97
- message: 'Type of documents to migrate. You can add multiple types separated by comma (optional)'
98
- });
99
- });
100
- test('errors gracefully if findProjectRoot fails', async ()=>{
101
- mockFindProjectRoot.mockRejectedValue(new Error('No project root found'));
102
- const { error } = await testCommand(CreateMigrationCommand, [
103
- 'Migration Title'
104
- ]);
105
- expect(error?.message).toContain('No project root found');
106
- });
107
- test('prompts user for type of documents for migration after a valid migration name has been entered', async ()=>{
108
- mockInput.mockResolvedValueOnce('Migration Title');
109
- await testCommand(CreateMigrationCommand);
110
- expect(mockInput.mock.calls[1][0]).toStrictEqual({
111
- message: 'Type of documents to migrate. You can add multiple types separated by comma (optional)'
112
- });
113
- });
114
- test('prompts user for template selection after migration name and optional document types', async ()=>{
115
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
116
- await testCommand(CreateMigrationCommand, [
117
- 'Migration Title'
118
- ]);
119
- expect(mockSelect).toHaveBeenCalledWith({
120
- choices: [
121
- {
122
- name: 'Minimalistic migration to get you started',
123
- value: 'Minimalistic migration to get you started'
124
- },
125
- {
126
- name: 'Rename an object type',
127
- value: 'Rename an object type'
128
- },
129
- {
130
- name: 'Rename a field',
131
- value: 'Rename a field'
132
- },
133
- {
134
- name: 'Convert string field to Portable Text',
135
- value: 'Convert string field to Portable Text'
136
- },
137
- {
138
- name: 'Advanced template using async iterators providing more fine grained control',
139
- value: 'Advanced template using async iterators providing more fine grained control'
140
- }
141
- ],
142
- message: 'Select a template'
143
- });
144
- });
145
- test('creates directory when it does not exist', async ()=>{
146
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
147
- mockSelect.mockResolvedValue('Rename a field');
148
- mockAccess.mockRejectedValue(new Error('ENOENT: no such file or directory'));
149
- await testCommand(CreateMigrationCommand, [
150
- 'Migration Title'
151
- ]);
152
- expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining('/test/path/migrations/migration-title'), {
153
- recursive: true
154
- });
155
- expect(mockConfirm).not.toHaveBeenCalled();
156
- });
157
- test('prompts the user to overwrite when directory already exists', async ()=>{
158
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
159
- mockSelect.mockResolvedValue('Rename a field');
160
- mockAccess.mockResolvedValue();
161
- mockConfirm.mockResolvedValue(true);
162
- await testCommand(CreateMigrationCommand, [
163
- 'My Migration'
164
- ]);
165
- expect(mockConfirm).toHaveBeenCalledWith({
166
- default: false,
167
- message: expect.stringContaining('Migration directory /test/path/migrations/my-migration already exists. Overwrite?')
168
- });
169
- expect(mockMkdir).toHaveBeenCalled();
170
- });
171
- test('does not create directory when user declines overwrite', async ()=>{
172
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
173
- mockSelect.mockResolvedValue('Rename a field');
174
- mockAccess.mockResolvedValue();
175
- mockConfirm.mockResolvedValue(false);
176
- await testCommand(CreateMigrationCommand, [
177
- 'My Migration'
178
- ]);
179
- expect(mockConfirm).toHaveBeenCalled();
180
- expect(mockMkdir).not.toHaveBeenCalled();
181
- });
182
- test('creates directory after user confirms overwrite', async ()=>{
183
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
184
- mockSelect.mockResolvedValue('Rename a field');
185
- mockAccess.mockResolvedValue();
186
- mockConfirm.mockResolvedValue(true);
187
- await testCommand(CreateMigrationCommand, [
188
- 'My Migration'
189
- ]);
190
- expect(mockConfirm).toHaveBeenCalled();
191
- expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining('test/path/migrations/my-migration'), {
192
- recursive: true
193
- });
194
- });
195
- test('exits gracefully when directory creation fails', async ()=>{
196
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
197
- mockSelect.mockResolvedValue('Rename a field');
198
- mockAccess.mockResolvedValue();
199
- mockMkdir.mockRejectedValue(new Error('Permission denied'));
200
- const { error } = await testCommand(CreateMigrationCommand, [
201
- 'My Migration'
202
- ]);
203
- expect(error).toBeDefined();
204
- expect(error?.message).toContain('Failed to create migration directory: Permission denied');
205
- expect(mockWriteFile).not.toHaveBeenCalled();
206
- });
207
- test('output migration instructions after migrations folder has been created', async ()=>{
208
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
209
- mockSelect.mockResolvedValue('Rename a field');
210
- mockAccess.mockResolvedValue();
211
- mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
212
- const { stdout } = await testCommand(CreateMigrationCommand, [
213
- 'My Migration'
214
- ]);
215
- expect(mockWriteFile).toHaveBeenCalled();
216
- expect(stdout).toMatchInlineSnapshot(`
217
- "
218
- ✓ Migration created!
219
-
220
- Next steps:
221
- Open /test/path/migrations/my-migration/index.ts in your code editor and write the code for your migration.
222
- Dry run the migration with:
223
- \`sanity migration run my-migration --project=<projectId> --dataset <dataset> \`
224
- Run the migration against a dataset with:
225
- \`sanity migration run my-migration --project=<projectId> --dataset <dataset> --no-dry-run\`
226
-
227
- 👉 Learn more about schema and content migrations at https://www.sanity.io/docs/schema-and-content-migrations
228
- "
229
- `);
230
- });
231
- test('creates minimalSimple template in migration folder when user selects it', async ()=>{
232
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
233
- mockSelect.mockResolvedValue('Minimalistic migration to get you started');
234
- mockAccess.mockResolvedValue();
235
- mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
236
- await testCommand(CreateMigrationCommand, [
237
- 'My Migration'
238
- ]);
239
- expect(mockTemplates.minimalSimple).toHaveBeenCalled();
240
- });
241
- test('creates renameType template in migration folder when user selects it', async ()=>{
242
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
243
- mockSelect.mockResolvedValue('Rename an object type');
244
- mockAccess.mockResolvedValue();
245
- mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
246
- await testCommand(CreateMigrationCommand, [
247
- 'My Migration'
248
- ]);
249
- expect(mockTemplates.renameType).toHaveBeenCalled();
250
- });
251
- test('creates renameField template in migration folder when user selects it', async ()=>{
252
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
253
- mockSelect.mockResolvedValue('Rename a field');
254
- mockAccess.mockResolvedValue();
255
- mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
256
- await testCommand(CreateMigrationCommand, [
257
- 'My Migration'
258
- ]);
259
- expect(mockTemplates.renameField).toHaveBeenCalled();
260
- });
261
- test('creates stringToPTE template in migration folder when user selects it', async ()=>{
262
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
263
- mockSelect.mockResolvedValue('Convert string field to Portable Text');
264
- mockAccess.mockResolvedValue();
265
- mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
266
- await testCommand(CreateMigrationCommand, [
267
- 'My Migration'
268
- ]);
269
- expect(mockTemplates.stringToPTE).toHaveBeenCalled();
270
- });
271
- test('creates minimalAdvanced template in migration folder when user selects it', async ()=>{
272
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
273
- mockSelect.mockResolvedValue('Advanced template using async iterators providing more fine grained control');
274
- mockAccess.mockResolvedValue();
275
- mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
276
- await testCommand(CreateMigrationCommand, [
277
- 'My Migration'
278
- ]);
279
- expect(mockTemplates.minimalAdvanced).toHaveBeenCalled();
280
- });
281
- test('exits gracefully when writing the template to the directory fails', async ()=>{
282
- mockInput.mockResolvedValueOnce('document-1, document-2, document-3');
283
- mockSelect.mockResolvedValue('Advanced template using async iterators providing more fine grained control');
284
- mockAccess.mockResolvedValue();
285
- mockMkdir.mockResolvedValue('test/path/migrations/my-migration');
286
- mockWriteFile.mockRejectedValue(new Error('Permission denied'));
287
- const { error, stdout } = await testCommand(CreateMigrationCommand, [
288
- 'My Migration'
289
- ]);
290
- expect(error).toBeDefined();
291
- expect(error?.message).toContain('Failed to create migration file: Permission denied');
292
- expect(stdout).toBe('');
293
- });
294
- });
295
-
296
- //# sourceMappingURL=create.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/commands/migration/__tests__/create.test.ts"],"sourcesContent":["import {access, mkdir, writeFile} from 'node:fs/promises'\n\nimport {runCommand} from '@oclif/test'\nimport {testCommand} from '@sanity/cli-test'\nimport {afterEach, beforeEach, describe, expect, test, vi} from 'vitest'\n\nimport {CreateMigrationCommand} from '../create.js'\n\nconst mocks = vi.hoisted(() => ({\n confirm: vi.fn(),\n findProjectRoot: vi.fn(),\n input: vi.fn(),\n select: vi.fn(),\n}))\n\nconst mockTemplates = vi.hoisted(() => ({\n minimalAdvanced: vi.fn(),\n minimalSimple: vi.fn(),\n renameField: vi.fn(),\n renameType: vi.fn(),\n stringToPTE: vi.fn(),\n}))\n\nvi.mock('node:fs')\n\nvi.mock('node:fs/promises', () => ({\n access: vi.fn(),\n mkdir: vi.fn(),\n writeFile: vi.fn(),\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 confirm: mocks.confirm,\n input: mocks.input,\n select: mocks.select,\n }\n})\n\nvi.mock('../../../../../cli-core/src/config/findProjectRoot.js', () => ({\n findProjectRoot: mocks.findProjectRoot,\n}))\n\nvi.mock('../../../actions/migration/templates/index.js', () => mockTemplates)\n\nconst mockConfirm = mocks.confirm\nconst mockFindProjectRoot = mocks.findProjectRoot\nconst mockInput = mocks.input\nconst mockSelect = mocks.select\nconst mockAccess = vi.mocked(access)\nconst mockMkdir = vi.mocked(mkdir)\nconst mockWriteFile = vi.mocked(writeFile)\n\ndescribe('#migration:create', () => {\n beforeEach(() => {\n mockFindProjectRoot.mockResolvedValue({\n directory: '/test/path',\n root: '/test/path',\n type: 'studio',\n })\n })\n afterEach(() => {\n vi.clearAllMocks()\n })\n\n test('--help works', async () => {\n const {stdout} = await runCommand(['migration create', '--help'])\n\n expect(stdout).toMatchInlineSnapshot(`\n \"Create a new migration within your project\n\n USAGE\n $ sanity migration create [TITLE]\n\n ARGUMENTS\n [TITLE] Title of migration\n\n DESCRIPTION\n Create a new migration within your project\n\n EXAMPLES\n Create a new migration, prompting for title and options\n\n $ sanity migration create\n\n Create a new migration with the provided title, prompting for options\n\n $ sanity migration create \"Rename field from location to address\"\n\n \"\n `)\n })\n\n test('prompts user to enter title when no title argument is provided', async () => {\n await testCommand(CreateMigrationCommand)\n\n expect(mockInput).toHaveBeenCalledWith({\n message: 'Title of migration (e.g. \"Rename field from location to address\")',\n validate: expect.any(Function),\n })\n })\n\n test('skips title prompt when title is provided', async () => {\n await testCommand(CreateMigrationCommand, ['Migration Title'])\n\n expect(mockInput).toHaveBeenCalledWith({\n message:\n 'Type of documents to migrate. You can add multiple types separated by comma (optional)',\n })\n })\n\n test('errors gracefully if findProjectRoot fails', async () => {\n mockFindProjectRoot.mockRejectedValue(new Error('No project root found'))\n\n const {error} = await testCommand(CreateMigrationCommand, ['Migration Title'])\n\n expect(error?.message).toContain('No project root found')\n })\n\n test('prompts user for type of documents for migration after a valid migration name has been entered', async () => {\n mockInput.mockResolvedValueOnce('Migration Title')\n\n await testCommand(CreateMigrationCommand)\n\n expect(mockInput.mock.calls[1][0]).toStrictEqual({\n message:\n 'Type of documents to migrate. You can add multiple types separated by comma (optional)',\n })\n })\n\n test('prompts user for template selection after migration name and optional document types', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n\n await testCommand(CreateMigrationCommand, ['Migration Title'])\n\n expect(mockSelect).toHaveBeenCalledWith({\n choices: [\n {\n name: 'Minimalistic migration to get you started',\n value: 'Minimalistic migration to get you started',\n },\n {\n name: 'Rename an object type',\n value: 'Rename an object type',\n },\n {\n name: 'Rename a field',\n value: 'Rename a field',\n },\n {\n name: 'Convert string field to Portable Text',\n value: 'Convert string field to Portable Text',\n },\n {\n name: 'Advanced template using async iterators providing more fine grained control',\n value: 'Advanced template using async iterators providing more fine grained control',\n },\n ],\n message: 'Select a template',\n })\n })\n\n test('creates directory when it does not exist', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockRejectedValue(new Error('ENOENT: no such file or directory'))\n\n await testCommand(CreateMigrationCommand, ['Migration Title'])\n\n expect(mockMkdir).toHaveBeenCalledWith(\n expect.stringContaining('/test/path/migrations/migration-title'),\n {\n recursive: true,\n },\n )\n expect(mockConfirm).not.toHaveBeenCalled()\n })\n\n test('prompts the user to overwrite when directory already exists', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockConfirm.mockResolvedValue(true)\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockConfirm).toHaveBeenCalledWith({\n default: false,\n message: expect.stringContaining(\n 'Migration directory /test/path/migrations/my-migration already exists. Overwrite?',\n ),\n })\n expect(mockMkdir).toHaveBeenCalled()\n })\n\n test('does not create directory when user declines overwrite', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockConfirm.mockResolvedValue(false)\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockConfirm).toHaveBeenCalled()\n expect(mockMkdir).not.toHaveBeenCalled()\n })\n\n test('creates directory after user confirms overwrite', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockConfirm.mockResolvedValue(true)\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockConfirm).toHaveBeenCalled()\n expect(mockMkdir).toHaveBeenCalledWith(\n expect.stringContaining('test/path/migrations/my-migration'),\n {\n recursive: true,\n },\n )\n })\n\n test('exits gracefully when directory creation fails', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockMkdir.mockRejectedValue(new Error('Permission denied'))\n\n const {error} = await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(error).toBeDefined()\n expect(error?.message).toContain('Failed to create migration directory: Permission denied')\n expect(mockWriteFile).not.toHaveBeenCalled()\n })\n\n test('output migration instructions after migrations folder has been created', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n const {stdout} = await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockWriteFile).toHaveBeenCalled()\n\n expect(stdout).toMatchInlineSnapshot(`\n \"\n ✓ Migration created!\n\n Next steps:\n Open /test/path/migrations/my-migration/index.ts in your code editor and write the code for your migration.\n Dry run the migration with:\n \\`sanity migration run my-migration --project=<projectId> --dataset <dataset> \\`\n Run the migration against a dataset with:\n \\`sanity migration run my-migration --project=<projectId> --dataset <dataset> --no-dry-run\\`\n\n 👉 Learn more about schema and content migrations at https://www.sanity.io/docs/schema-and-content-migrations\n \"\n `)\n })\n\n test('creates minimalSimple template in migration folder when user selects it', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Minimalistic migration to get you started')\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockTemplates.minimalSimple).toHaveBeenCalled()\n })\n\n test('creates renameType template in migration folder when user selects it', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename an object type')\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockTemplates.renameType).toHaveBeenCalled()\n })\n\n test('creates renameField template in migration folder when user selects it', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Rename a field')\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockTemplates.renameField).toHaveBeenCalled()\n })\n\n test('creates stringToPTE template in migration folder when user selects it', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue('Convert string field to Portable Text')\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockTemplates.stringToPTE).toHaveBeenCalled()\n })\n\n test('creates minimalAdvanced template in migration folder when user selects it', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue(\n 'Advanced template using async iterators providing more fine grained control',\n )\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n\n await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(mockTemplates.minimalAdvanced).toHaveBeenCalled()\n })\n\n test('exits gracefully when writing the template to the directory fails', async () => {\n mockInput.mockResolvedValueOnce('document-1, document-2, document-3')\n mockSelect.mockResolvedValue(\n 'Advanced template using async iterators providing more fine grained control',\n )\n mockAccess.mockResolvedValue()\n mockMkdir.mockResolvedValue('test/path/migrations/my-migration')\n mockWriteFile.mockRejectedValue(new Error('Permission denied'))\n\n const {error, stdout} = await testCommand(CreateMigrationCommand, ['My Migration'])\n\n expect(error).toBeDefined()\n expect(error?.message).toContain('Failed to create migration file: Permission denied')\n expect(stdout).toBe('')\n })\n})\n"],"names":["access","mkdir","writeFile","runCommand","testCommand","afterEach","beforeEach","describe","expect","test","vi","CreateMigrationCommand","mocks","hoisted","confirm","fn","findProjectRoot","input","select","mockTemplates","minimalAdvanced","minimalSimple","renameField","renameType","stringToPTE","mock","actual","importActual","mockConfirm","mockFindProjectRoot","mockInput","mockSelect","mockAccess","mocked","mockMkdir","mockWriteFile","mockResolvedValue","directory","root","type","clearAllMocks","stdout","toMatchInlineSnapshot","toHaveBeenCalledWith","message","validate","any","Function","mockRejectedValue","Error","error","toContain","mockResolvedValueOnce","calls","toStrictEqual","choices","name","value","stringContaining","recursive","not","toHaveBeenCalled","default","toBeDefined","toBe"],"mappings":"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"}
@@ -1,166 +0,0 @@
1
- import { readdir } from 'node:fs/promises';
2
- import { runCommand } from '@oclif/test';
3
- import { testCommand } from '@sanity/cli-test';
4
- import { afterEach, describe, expect, test, vi } from 'vitest';
5
- import { resolveMigrationScript } from '../../../utils/migration/resolveMigrationScript.js';
6
- import { ListMigrationCommand } from '../list.js';
7
- vi.mock('node:fs/promises', ()=>({
8
- readdir: vi.fn()
9
- }));
10
- vi.mock('../../../../../cli-core/src/config/findProjectRoot.js', ()=>({
11
- findProjectRoot: vi.fn().mockResolvedValue({
12
- directory: '/test/project',
13
- root: '/test/project',
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('../../../utils/migration/resolveMigrationScript.js', async (importOriginal)=>{
25
- const actual = await importOriginal();
26
- return {
27
- ...actual,
28
- isLoadableMigrationScript: actual.isLoadableMigrationScript,
29
- resolveMigrationScript: vi.fn()
30
- };
31
- });
32
- const mockReaddir = vi.mocked(readdir);
33
- const mockResolveMigrationScript = vi.mocked(resolveMigrationScript);
34
- describe('#migration:list', ()=>{
35
- afterEach(()=>{
36
- vi.clearAllMocks();
37
- });
38
- test('--help works', async ()=>{
39
- const { stdout } = await runCommand([
40
- 'migration list',
41
- '--help'
42
- ]);
43
- expect(stdout).toMatchInlineSnapshot(`
44
- "List available migrations
45
-
46
- USAGE
47
- $ sanity migration list
48
-
49
- DESCRIPTION
50
- List available migrations
51
-
52
- EXAMPLES
53
- List all available migrations in the project
54
-
55
- $ sanity migration list
56
-
57
- "
58
- `);
59
- });
60
- test('lists migrations successfully with various formats', async ()=>{
61
- // Mock readdir to return both files and directories with different extensions
62
- mockReaddir.mockResolvedValue([
63
- {
64
- isDirectory: ()=>false,
65
- name: 'add-author-field.ts'
66
- },
67
- {
68
- isDirectory: ()=>true,
69
- name: 'migration-dir'
70
- },
71
- {
72
- isDirectory: ()=>false,
73
- name: 'rename-tags.js'
74
- }
75
- ]);
76
- // Mock resolveMigrationScript for .ts file
77
- mockResolveMigrationScript.mockResolvedValueOnce([
78
- {
79
- absolutePath: '/test/project/migrations/add-author-field.ts',
80
- mod: {
81
- default: {
82
- migrate: vi.fn(),
83
- title: 'Add author field to articles'
84
- }
85
- },
86
- relativePath: 'migrations/add-author-field.ts'
87
- }
88
- ]);
89
- // Mock resolveMigrationScript for directory
90
- mockResolveMigrationScript.mockResolvedValueOnce([
91
- {
92
- absolutePath: '/test/project/migrations/migration-dir/index.ts',
93
- mod: {
94
- default: {
95
- migrate: vi.fn(),
96
- title: 'Directory-based migration'
97
- }
98
- },
99
- relativePath: 'migrations/migration-dir/index.ts'
100
- }
101
- ]);
102
- // Mock resolveMigrationScript for .js file
103
- mockResolveMigrationScript.mockResolvedValueOnce([
104
- {
105
- absolutePath: '/test/project/migrations/rename-tags.js',
106
- mod: {
107
- default: {
108
- migrate: vi.fn(),
109
- title: 'Rename tags to categories'
110
- }
111
- },
112
- relativePath: 'migrations/rename-tags.js'
113
- }
114
- ]);
115
- const { stdout } = await testCommand(ListMigrationCommand, []);
116
- // Verify count
117
- expect(stdout).toContain('Found 3 migrations in project');
118
- // Verify .ts file (extension removed)
119
- expect(stdout).toContain('add-author-field');
120
- expect(stdout).not.toContain('add-author-field.ts');
121
- expect(stdout).toContain('Add author field to articles');
122
- // Verify directory
123
- expect(stdout).toContain('migration-dir');
124
- expect(stdout).toContain('Directory-based migration');
125
- // Verify .js file (extension removed)
126
- expect(stdout).toContain('rename-tags');
127
- expect(stdout).not.toContain('rename-tags.js');
128
- expect(stdout).toContain('Rename tags to categories');
129
- expect(stdout).toContain('Run `sanity migration run <ID>` to run a migration');
130
- });
131
- test('handles empty migrations folder', async ()=>{
132
- // Mock readdir to return empty array
133
- mockReaddir.mockResolvedValue([]);
134
- const { stdout } = await testCommand(ListMigrationCommand, []);
135
- expect(stdout).toContain('No migrations found in migrations folder of the project');
136
- expect(stdout).toContain('Run `sanity migration create <NAME>` to create a new migration');
137
- });
138
- test('handles missing migrations folder', async ()=>{
139
- // Mock readdir to throw ENOENT error
140
- const enoentError = new Error('ENOENT: no such file or directory');
141
- Object.assign(enoentError, {
142
- code: 'ENOENT'
143
- });
144
- mockReaddir.mockRejectedValue(enoentError);
145
- const { stdout } = await testCommand(ListMigrationCommand, []);
146
- expect(stdout).toContain('No migrations folder found in the project');
147
- expect(stdout).toContain('Run `sanity migration create <NAME>` to create a new migration');
148
- });
149
- test('handles migration loading errors', async ()=>{
150
- // Mock readdir to return migration files
151
- mockReaddir.mockResolvedValue([
152
- {
153
- isDirectory: ()=>false,
154
- name: 'broken-migration.ts'
155
- }
156
- ]);
157
- // Mock resolveMigrationScript to throw error
158
- mockResolveMigrationScript.mockRejectedValue(new Error('Syntax error in migration file'));
159
- const { error } = await testCommand(ListMigrationCommand, []);
160
- expect(error?.message).toContain('List migrations failed');
161
- expect(error?.message).toContain('Syntax error in migration file');
162
- expect(error?.oclif?.exit).toBe(1);
163
- });
164
- });
165
-
166
- //# sourceMappingURL=list.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../src/commands/migration/__tests__/list.test.ts"],"sourcesContent":["import {readdir} from 'node:fs/promises'\n\nimport {runCommand} from '@oclif/test'\nimport {testCommand} from '@sanity/cli-test'\nimport {type Migration} from '@sanity/migrate'\nimport {afterEach, describe, expect, test, vi} from 'vitest'\n\nimport {resolveMigrationScript} from '../../../utils/migration/resolveMigrationScript.js'\nimport {ListMigrationCommand} from '../list.js'\n\nvi.mock('node:fs/promises', () => ({\n readdir: vi.fn(),\n}))\n\nvi.mock('../../../../../cli-core/src/config/findProjectRoot.js', () => ({\n findProjectRoot: vi.fn().mockResolvedValue({\n directory: '/test/project',\n root: '/test/project',\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('../../../utils/migration/resolveMigrationScript.js', async (importOriginal) => {\n const actual =\n await importOriginal<typeof import('../../../utils/migration/resolveMigrationScript.js')>()\n return {\n ...actual,\n isLoadableMigrationScript: actual.isLoadableMigrationScript,\n resolveMigrationScript: vi.fn(),\n }\n})\n\nconst mockReaddir = vi.mocked(readdir)\nconst mockResolveMigrationScript = vi.mocked(resolveMigrationScript)\n\ndescribe('#migration:list', () => {\n afterEach(() => {\n vi.clearAllMocks()\n })\n\n test('--help works', async () => {\n const {stdout} = await runCommand(['migration list', '--help'])\n expect(stdout).toMatchInlineSnapshot(`\n \"List available migrations\n\n USAGE\n $ sanity migration list\n\n DESCRIPTION\n List available migrations\n\n EXAMPLES\n List all available migrations in the project\n\n $ sanity migration list\n\n \"\n `)\n })\n\n test('lists migrations successfully with various formats', async () => {\n // Mock readdir to return both files and directories with different extensions\n mockReaddir.mockResolvedValue([\n {isDirectory: () => false, name: 'add-author-field.ts'} as unknown as Awaited<\n ReturnType<typeof readdir>\n >[0],\n {isDirectory: () => true, name: 'migration-dir'} as unknown as Awaited<\n ReturnType<typeof readdir>\n >[0],\n {isDirectory: () => false, name: 'rename-tags.js'} as unknown as Awaited<\n ReturnType<typeof readdir>\n >[0],\n ])\n\n // Mock resolveMigrationScript for .ts file\n mockResolveMigrationScript.mockResolvedValueOnce([\n {\n absolutePath: '/test/project/migrations/add-author-field.ts',\n mod: {\n default: {\n migrate: vi.fn(),\n title: 'Add author field to articles',\n } as Migration,\n },\n relativePath: 'migrations/add-author-field.ts',\n },\n ])\n\n // Mock resolveMigrationScript for directory\n mockResolveMigrationScript.mockResolvedValueOnce([\n {\n absolutePath: '/test/project/migrations/migration-dir/index.ts',\n mod: {\n default: {\n migrate: vi.fn(),\n title: 'Directory-based migration',\n } as Migration,\n },\n relativePath: 'migrations/migration-dir/index.ts',\n },\n ])\n\n // Mock resolveMigrationScript for .js file\n mockResolveMigrationScript.mockResolvedValueOnce([\n {\n absolutePath: '/test/project/migrations/rename-tags.js',\n mod: {\n default: {\n migrate: vi.fn(),\n title: 'Rename tags to categories',\n } as Migration,\n },\n relativePath: 'migrations/rename-tags.js',\n },\n ])\n\n const {stdout} = await testCommand(ListMigrationCommand, [])\n\n // Verify count\n expect(stdout).toContain('Found 3 migrations in project')\n\n // Verify .ts file (extension removed)\n expect(stdout).toContain('add-author-field')\n expect(stdout).not.toContain('add-author-field.ts')\n expect(stdout).toContain('Add author field to articles')\n\n // Verify directory\n expect(stdout).toContain('migration-dir')\n expect(stdout).toContain('Directory-based migration')\n\n // Verify .js file (extension removed)\n expect(stdout).toContain('rename-tags')\n expect(stdout).not.toContain('rename-tags.js')\n expect(stdout).toContain('Rename tags to categories')\n\n expect(stdout).toContain('Run `sanity migration run <ID>` to run a migration')\n })\n\n test('handles empty migrations folder', async () => {\n // Mock readdir to return empty array\n mockReaddir.mockResolvedValue([])\n\n const {stdout} = await testCommand(ListMigrationCommand, [])\n\n expect(stdout).toContain('No migrations found in migrations folder of the project')\n expect(stdout).toContain('Run `sanity migration create <NAME>` to create a new migration')\n })\n\n test('handles missing migrations folder', async () => {\n // Mock readdir to throw ENOENT error\n const enoentError = new Error('ENOENT: no such file or directory')\n Object.assign(enoentError, {code: 'ENOENT'})\n mockReaddir.mockRejectedValue(enoentError)\n\n const {stdout} = await testCommand(ListMigrationCommand, [])\n\n expect(stdout).toContain('No migrations folder found in the project')\n expect(stdout).toContain('Run `sanity migration create <NAME>` to create a new migration')\n })\n\n test('handles migration loading errors', async () => {\n // Mock readdir to return migration files\n mockReaddir.mockResolvedValue([\n {isDirectory: () => false, name: 'broken-migration.ts'} as unknown as Awaited<\n ReturnType<typeof readdir>\n >[0],\n ])\n\n // Mock resolveMigrationScript to throw error\n mockResolveMigrationScript.mockRejectedValue(new Error('Syntax error in migration file'))\n\n const {error} = await testCommand(ListMigrationCommand, [])\n\n expect(error?.message).toContain('List migrations failed')\n expect(error?.message).toContain('Syntax error in migration file')\n expect(error?.oclif?.exit).toBe(1)\n })\n})\n"],"names":["readdir","runCommand","testCommand","afterEach","describe","expect","test","vi","resolveMigrationScript","ListMigrationCommand","mock","fn","findProjectRoot","mockResolvedValue","directory","root","type","getCliConfig","api","projectId","importOriginal","actual","isLoadableMigrationScript","mockReaddir","mocked","mockResolveMigrationScript","clearAllMocks","stdout","toMatchInlineSnapshot","isDirectory","name","mockResolvedValueOnce","absolutePath","mod","default","migrate","title","relativePath","toContain","not","enoentError","Error","Object","assign","code","mockRejectedValue","error","message","oclif","exit","toBe"],"mappings":"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"}