From e8d6bbeb798d9d7b3853b857b912a648e552ad83 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Thu, 26 Mar 2026 13:15:20 -0700 Subject: [PATCH 01/16] wip: allow project creation by name --- src/commands/console/project/create.js | 89 ++++++++++++++++++++ test/commands/console/project/create.test.js | 58 +++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 src/commands/console/project/create.js create mode 100644 test/commands/console/project/create.test.js diff --git a/src/commands/console/project/create.js b/src/commands/console/project/create.js new file mode 100644 index 0000000..1a6b0df --- /dev/null +++ b/src/commands/console/project/create.js @@ -0,0 +1,89 @@ +/* +Copyright 2026 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +const aioConsoleLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-console:project:create', { provider: 'debug' }) +const { Flags } = require('@oclif/core') +const ConsoleCommand = require('../index') + +class CreateCommand extends ConsoleCommand { + async run () { + const { flags } = await this.parse(CreateCommand) + const orgId = flags.orgId || this.getConfig('org.id') + if (!orgId) { + this.log('You have not selected an Organization. Please select first.') + this.printConsoleConfig() + this.exit(1) + } + + if (!flags.name) { + this.log('You have not provided a name for the project. Please provide a name.') + this.exit(1) + } + + const projectDetails = { + name: flags.name, + title: flags.title || flags.name, + description: flags.description || flags.name + } + + await this.initSdk() + const project = await this.consoleCLI.createProject(orgId, projectDetails) + this.log(`Project ${project.name} created successfully.`) + return project + } + + /** + * Retrieve projects from an Org + * + * @param {string} orgId organization id + * @returns {Promise} Projects + */ + async getConsoleOrgProjects (orgId) { + const response = await this.consoleCLI.getProjects(orgId) + return response + } +} + +CreateCommand.description = 'Create a new App Builder Project for the selected Organization' + +CreateCommand.flags = { + ...ConsoleCommand.flags, + orgId: Flags.string({ + description: 'OrgID to create the project in' + }), + name: Flags.string({ + description: 'Name of the project', + required: true + }), + title: Flags.string({ + description: 'Title of the project, defaults to the name' + }), + description: Flags.string({ + description: 'Description of the project, defaults to the name' + }), + json: Flags.boolean({ + description: 'Output json', + char: 'j', + exclusive: ['yml'] + }), + yml: Flags.boolean({ + description: 'Output yml', + char: 'y', + exclusive: ['json'] + }) +} + +CreateCommand.aliases = [ + 'console:project:create', + 'console:project:init' +] + +module.exports = CreateCommand diff --git a/test/commands/console/project/create.test.js b/test/commands/console/project/create.test.js new file mode 100644 index 0000000..c81aa33 --- /dev/null +++ b/test/commands/console/project/create.test.js @@ -0,0 +1,58 @@ +/* +Copyright 2026 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +const { Command } = require('@oclif/core') +const { stdout } = require('stdout-stderr') + +const TheCommand = require('../../../../src/commands/console/project/create') + +const mockProject = { + appId: null, + date_created: '2020-04-29T10:14:17.000Z', + date_last_modified: '2020-04-29T10:14:17.000Z', + deleted: 0, + description: 'Description 1', + id: '1000000001', + name: 'name1', + org_id: 1234567890, + title: 'Title 1', + type: 'default' +} + +const mockConsoleCLIInstance = {} + +function setDefaultMockConsoleCLI () { + mockConsoleCLIInstance.getProjects = jest.fn().mockResolvedValue(mockProject) +} +jest.mock('@adobe/aio-cli-lib-console', () => ({ + init: jest.fn().mockResolvedValue(mockConsoleCLIInstance), + cleanStdOut: jest.fn() + })) + +describe('console:project:create', () => { + let command + + beforeEach(() => { + jest.resetModules() + command = new TheCommand() + setDefaultMockConsoleCLI() + }) + + afterEach(() => { + command = null + }) + + it('should create a project', async () => { + command.argv = ['--name', 'test-project', '--title', 'Test Project', '--description', 'Test Project Description', '--orgId', '1234567890'] + const result = await command.run() + expect(result).toContain('Project test-project created successfully.') // TODO: Add more specific test for the result + }) +}) \ No newline at end of file From 0b4d8f27227aa8d3f13d57c1e81429b4bbf4dcdb Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Thu, 26 Mar 2026 16:17:59 -0700 Subject: [PATCH 02/16] fix: name,title,desc validation. + tests full coverage --- src/commands/console/project/create.js | 51 ++++--- test/commands/console/project/create.test.js | 146 +++++++++++++++---- 2 files changed, 150 insertions(+), 47 deletions(-) diff --git a/src/commands/console/project/create.js b/src/commands/console/project/create.js index 1a6b0df..0c3d03c 100644 --- a/src/commands/console/project/create.js +++ b/src/commands/console/project/create.js @@ -9,7 +9,7 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -const aioConsoleLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-console:project:create', { provider: 'debug' }) +// const aioConsoleLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-console:project:create', { provider: 'debug' }) const { Flags } = require('@oclif/core') const ConsoleCommand = require('../index') @@ -18,14 +18,7 @@ class CreateCommand extends ConsoleCommand { const { flags } = await this.parse(CreateCommand) const orgId = flags.orgId || this.getConfig('org.id') if (!orgId) { - this.log('You have not selected an Organization. Please select first.') - this.printConsoleConfig() - this.exit(1) - } - - if (!flags.name) { - this.log('You have not provided a name for the project. Please provide a name.') - this.exit(1) + this.error('You have not selected an Organization. Please select first.') } const projectDetails = { @@ -35,21 +28,39 @@ class CreateCommand extends ConsoleCommand { } await this.initSdk() + + // first validate name, before calling server to check if it is already in use + // Project name allows only alphanumeric values + if (!/^[a-zA-Z0-9]+$/.test(projectDetails.name)) { + this.error(`Project name ${projectDetails.name} is invalid. It should only contain alphanumeric values.`) + } + // Project name must be between 3 and 45 characters long. + if (projectDetails.name.length < 3 || projectDetails.name.length > 45) { + this.error('Project name is too long. It must be between 3 and 45 characters long.') + } + // check name is not already in use + const projects = await this.consoleCLI.getProjects(orgId) + if (projects.find(project => project.name === projectDetails.name)) { + this.error(`Project ${projectDetails.name} already exists. Please choose a different name.`) + } + + // Project title should only contain English alphanumeric or Latin alphabet characters and spaces. + if (!/^[a-zA-Z0-9\s]+$/.test(projectDetails.title)) { + this.error(`Project title ${projectDetails.title} is invalid. It should only contain English alphanumeric or Latin alphabet characters and spaces.`) + } + // Project title must be between 3 and 45 characters long. + if (projectDetails.title.length < 3 || projectDetails.title.length > 45) { + this.error('Project title is too long. It must be between 3 and 45 characters long.') + } + // Description cannot be over 1000 characters. + if (projectDetails.description.length > 1000) { + this.error('Project description is too long. It cannot be over 1000 characters.') + } + // if we get here, all validation passed, so call server to create project const project = await this.consoleCLI.createProject(orgId, projectDetails) this.log(`Project ${project.name} created successfully.`) return project } - - /** - * Retrieve projects from an Org - * - * @param {string} orgId organization id - * @returns {Promise} Projects - */ - async getConsoleOrgProjects (orgId) { - const response = await this.consoleCLI.getProjects(orgId) - return response - } } CreateCommand.description = 'Create a new App Builder Project for the selected Organization' diff --git a/test/commands/console/project/create.test.js b/test/commands/console/project/create.test.js index c81aa33..a72d8e1 100644 --- a/test/commands/console/project/create.test.js +++ b/test/commands/console/project/create.test.js @@ -9,41 +9,37 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -const { Command } = require('@oclif/core') -const { stdout } = require('stdout-stderr') - -const TheCommand = require('../../../../src/commands/console/project/create') - const mockProject = { - appId: null, - date_created: '2020-04-29T10:14:17.000Z', - date_last_modified: '2020-04-29T10:14:17.000Z', - deleted: 0, - description: 'Description 1', - id: '1000000001', - name: 'name1', - org_id: 1234567890, - title: 'Title 1', - type: 'default' + appId: null, + date_created: '2020-04-29T10:14:17.000Z', + date_last_modified: '2020-04-29T10:14:17.000Z', + deleted: 0, + description: 'Description 1', + id: '1000000001', + name: 'name1', + org_id: 1234567890, + title: 'Title 1', + type: 'default' } -const mockConsoleCLIInstance = {} - -function setDefaultMockConsoleCLI () { - mockConsoleCLIInstance.getProjects = jest.fn().mockResolvedValue(mockProject) +const mockConsoleCLIInstance = { + getProjects: jest.fn().mockResolvedValue([]), + createProject: jest.fn().mockResolvedValue(mockProject) } + jest.mock('@adobe/aio-cli-lib-console', () => ({ - init: jest.fn().mockResolvedValue(mockConsoleCLIInstance), - cleanStdOut: jest.fn() - })) + init: jest.fn().mockResolvedValue(mockConsoleCLIInstance), + cleanStdOut: jest.fn() +})) + +const TheCommand = require('../../../../src/commands/console/project/create') describe('console:project:create', () => { let command beforeEach(() => { - jest.resetModules() command = new TheCommand() - setDefaultMockConsoleCLI() + mockConsoleCLIInstance.createProject.mockReset() }) afterEach(() => { @@ -51,8 +47,104 @@ describe('console:project:create', () => { }) it('should create a project', async () => { - command.argv = ['--name', 'test-project', '--title', 'Test Project', '--description', 'Test Project Description', '--orgId', '1234567890'] + mockConsoleCLIInstance.createProject.mockResolvedValue(mockProject) + command.argv = ['--name', 'testproject', '--title', 'Test Project', '--description', 'Test Project Description', '--orgId', '1234567890'] + const result = await command.run() + expect(mockConsoleCLIInstance.createProject).toHaveBeenCalledWith('1234567890', { + name: 'testproject', + title: 'Test Project', + description: 'Test Project Description' + }) + expect(result).toEqual(mockProject) + }) + + it('should not create a project if the name is not provided', async () => { + command.argv = ['--title', 'Test Project', '--description', 'Test Project Description', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Missing required flag name') + expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() + }) + + it('should not create a project if the orgId is not provided', async () => { + command.argv = ['--name', 'testproject', '--title', 'Test Project', '--description', 'Test Project Description'] + command.getConfig = jest.fn().mockReturnValue(null) + await expect(command.run()).rejects.toThrow('You have not selected an Organization. Please select first.') + expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() + }) + + it('should use config.org.id if no orgId is provided', async () => { + mockConsoleCLIInstance.createProject.mockResolvedValue(mockProject) + command.argv = ['--name', 'testproject', '--title', 'Test Project', '--description', 'Test Project Description'] + command.getConfig = jest.fn().mockReturnValue('0987654321') + const result = await command.run() + expect(mockConsoleCLIInstance.createProject).toHaveBeenCalledWith('0987654321', { + name: 'testproject', + title: 'Test Project', + description: 'Test Project Description' + }) + expect(result).toEqual(mockProject) + }) + + it('should not create a project if the name is already in use', async () => { + mockConsoleCLIInstance.getProjects.mockResolvedValue([mockProject]) + mockConsoleCLIInstance.createProject.mockResolvedValue(mockProject) + command.argv = ['--name', 'name1', '--title', 'Test Project', '--description', 'Test Project Description', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Project name1 already exists. Please choose a different name.') + expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() + }) + + it('should use name as title if no title is provided', async () => { + mockConsoleCLIInstance.getProjects.mockResolvedValue([]) + mockConsoleCLIInstance.createProject.mockResolvedValue(mockProject) + command.argv = ['--name', 'testproject', '--description', 'Test Project Description', '--orgId', '1234567890'] + const result = await command.run() + expect(mockConsoleCLIInstance.createProject).toHaveBeenCalledWith('1234567890', { + name: 'testproject', + title: 'testproject', + description: 'Test Project Description' + }) + expect(result).toEqual(mockProject) + }) + + it('should use name as description if no description is provided', async () => { + mockConsoleCLIInstance.getProjects.mockResolvedValue([]) + mockConsoleCLIInstance.createProject.mockResolvedValue(mockProject) + command.argv = ['--name', 'testproject', '--title', 'Test Project', '--orgId', '1234567890'] const result = await command.run() - expect(result).toContain('Project test-project created successfully.') // TODO: Add more specific test for the result + expect(mockConsoleCLIInstance.createProject).toHaveBeenCalledWith('1234567890', { + name: 'testproject', + title: 'Test Project', + description: 'testproject' + }) + expect(result).toEqual(mockProject) + }) + + it('should not create a project if the name is invalid', async () => { + command.argv = ['--name', 'test-project!', '--title', 'Test Project', '--description', 'Test Project Description', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Project name test-project! is invalid. It should only contain alphanumeric values.') + expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() + }) + + it('should not create a project if the title is invalid', async () => { + command.argv = ['--name', 'testproject', '--title', 'Test Project!', '--description', 'Test Project Description', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Project title Test Project! is invalid. It should only contain English alphanumeric or Latin alphabet characters and spaces.') + expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() + }) + + it('should not create a project if the description is too long', async () => { + command.argv = ['--name', 'testproject', '--title', 'Test Project', '--description', 'Test Project Description'.repeat(1000), '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Project description is too long. It cannot be over 1000 characters.') + expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() + }) + + it('should not create a project if the name is too long', async () => { + command.argv = ['--name', 'testproject'.repeat(50), '--title', 'Test Project', '--description', 'Test Project Description', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Project name is too long. It must be between 3 and 45 characters long.') + expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() + }) + + it('should not create a project if the title is too long', async () => { + command.argv = ['--name', 'testName', '--title', 'Test Project'.repeat(50), '--description', 'Test Project Description', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Project title is too long. It must be between 3 and 45 characters long.') + expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() }) -}) \ No newline at end of file +}) From 69aaa25635b5e3c1d3992ced595486639cffdcde Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Thu, 26 Mar 2026 17:12:17 -0700 Subject: [PATCH 03/16] nit: don't say it is too long if it is too short and don't say it is too short if it is too long. --- src/commands/console/project/create.js | 6 +++--- test/commands/console/project/create.test.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/commands/console/project/create.js b/src/commands/console/project/create.js index 0c3d03c..082f1b3 100644 --- a/src/commands/console/project/create.js +++ b/src/commands/console/project/create.js @@ -36,7 +36,7 @@ class CreateCommand extends ConsoleCommand { } // Project name must be between 3 and 45 characters long. if (projectDetails.name.length < 3 || projectDetails.name.length > 45) { - this.error('Project name is too long. It must be between 3 and 45 characters long.') + this.error('Project name must be between 3 and 45 characters long.') } // check name is not already in use const projects = await this.consoleCLI.getProjects(orgId) @@ -50,11 +50,11 @@ class CreateCommand extends ConsoleCommand { } // Project title must be between 3 and 45 characters long. if (projectDetails.title.length < 3 || projectDetails.title.length > 45) { - this.error('Project title is too long. It must be between 3 and 45 characters long.') + this.error('Project title must be between 3 and 45 characters long.') } // Description cannot be over 1000 characters. if (projectDetails.description.length > 1000) { - this.error('Project description is too long. It cannot be over 1000 characters.') + this.error('Project description cannot be over 1000 characters.') } // if we get here, all validation passed, so call server to create project const project = await this.consoleCLI.createProject(orgId, projectDetails) diff --git a/test/commands/console/project/create.test.js b/test/commands/console/project/create.test.js index a72d8e1..4d34faa 100644 --- a/test/commands/console/project/create.test.js +++ b/test/commands/console/project/create.test.js @@ -132,19 +132,19 @@ describe('console:project:create', () => { it('should not create a project if the description is too long', async () => { command.argv = ['--name', 'testproject', '--title', 'Test Project', '--description', 'Test Project Description'.repeat(1000), '--orgId', '1234567890'] - await expect(command.run()).rejects.toThrow('Project description is too long. It cannot be over 1000 characters.') + await expect(command.run()).rejects.toThrow('Project description cannot be over 1000 characters.') expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() }) it('should not create a project if the name is too long', async () => { command.argv = ['--name', 'testproject'.repeat(50), '--title', 'Test Project', '--description', 'Test Project Description', '--orgId', '1234567890'] - await expect(command.run()).rejects.toThrow('Project name is too long. It must be between 3 and 45 characters long.') + await expect(command.run()).rejects.toThrow('Project name must be between 3 and 45 characters long.') expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() }) it('should not create a project if the title is too long', async () => { command.argv = ['--name', 'testName', '--title', 'Test Project'.repeat(50), '--description', 'Test Project Description', '--orgId', '1234567890'] - await expect(command.run()).rejects.toThrow('Project title is too long. It must be between 3 and 45 characters long.') + await expect(command.run()).rejects.toThrow('Project title must be between 3 and 45 characters long.') expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() }) }) From ecab13140f0858a319c5c143bb95ba92884fac0a Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Thu, 26 Mar 2026 17:21:11 -0700 Subject: [PATCH 04/16] delay initSDK till after validation --- src/commands/console/project/create.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/commands/console/project/create.js b/src/commands/console/project/create.js index 082f1b3..d53f780 100644 --- a/src/commands/console/project/create.js +++ b/src/commands/console/project/create.js @@ -27,8 +27,6 @@ class CreateCommand extends ConsoleCommand { description: flags.description || flags.name } - await this.initSdk() - // first validate name, before calling server to check if it is already in use // Project name allows only alphanumeric values if (!/^[a-zA-Z0-9]+$/.test(projectDetails.name)) { @@ -38,11 +36,6 @@ class CreateCommand extends ConsoleCommand { if (projectDetails.name.length < 3 || projectDetails.name.length > 45) { this.error('Project name must be between 3 and 45 characters long.') } - // check name is not already in use - const projects = await this.consoleCLI.getProjects(orgId) - if (projects.find(project => project.name === projectDetails.name)) { - this.error(`Project ${projectDetails.name} already exists. Please choose a different name.`) - } // Project title should only contain English alphanumeric or Latin alphabet characters and spaces. if (!/^[a-zA-Z0-9\s]+$/.test(projectDetails.title)) { @@ -56,6 +49,14 @@ class CreateCommand extends ConsoleCommand { if (projectDetails.description.length > 1000) { this.error('Project description cannot be over 1000 characters.') } + + await this.initSdk() + // check name is not already in use + const projects = await this.consoleCLI.getProjects(orgId) + if (projects.find(project => project.name === projectDetails.name)) { + this.error(`Project ${projectDetails.name} already exists. Please choose a different name.`) + } + // if we get here, all validation passed, so call server to create project const project = await this.consoleCLI.createProject(orgId, projectDetails) this.log(`Project ${project.name} created successfully.`) From 7fb27c876569245c117bf8a3e9fe63c28b6747cf Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Thu, 26 Mar 2026 17:21:43 -0700 Subject: [PATCH 05/16] nit: test for too short name/title --- test/commands/console/project/create.test.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/commands/console/project/create.test.js b/test/commands/console/project/create.test.js index 4d34faa..f6eee0a 100644 --- a/test/commands/console/project/create.test.js +++ b/test/commands/console/project/create.test.js @@ -136,15 +136,23 @@ describe('console:project:create', () => { expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() }) - it('should not create a project if the name is too long', async () => { + it('should not create a project if the name is too long, or too short', async () => { command.argv = ['--name', 'testproject'.repeat(50), '--title', 'Test Project', '--description', 'Test Project Description', '--orgId', '1234567890'] await expect(command.run()).rejects.toThrow('Project name must be between 3 and 45 characters long.') expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() + + command.argv = ['--name', '1', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Project name must be between 3 and 45 characters long.') + expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() }) - it('should not create a project if the title is too long', async () => { + it('should not create a project if the title is too long or too short', async () => { command.argv = ['--name', 'testName', '--title', 'Test Project'.repeat(50), '--description', 'Test Project Description', '--orgId', '1234567890'] await expect(command.run()).rejects.toThrow('Project title must be between 3 and 45 characters long.') expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() + + command.argv = ['--name', 'testName', '--title', 'HI', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Project title must be between 3 and 45 characters long.') + expect(mockConsoleCLIInstance.createProject).not.toHaveBeenCalled() }) }) From 4ee4c1f470120a4def70f323af1a9447bbdfc02a Mon Sep 17 00:00:00 2001 From: Patrick Russell Date: Thu, 26 Mar 2026 17:33:31 -0700 Subject: [PATCH 06/16] feat: add console:workspace:create command Allow creating new workspaces by project name or title, enabling agent-driven workspace creation without user interaction. --- src/commands/console/workspace/create.js | 108 +++++++++++ .../commands/console/workspace/create.test.js | 170 ++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 src/commands/console/workspace/create.js create mode 100644 test/commands/console/workspace/create.test.js diff --git a/src/commands/console/workspace/create.js b/src/commands/console/workspace/create.js new file mode 100644 index 0000000..f5eed8d --- /dev/null +++ b/src/commands/console/workspace/create.js @@ -0,0 +1,108 @@ +/* +Copyright 2026 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +const { Flags } = require('@oclif/core') +const ConsoleCommand = require('../index') + +class CreateCommand extends ConsoleCommand { + async run () { + const { flags } = await this.parse(CreateCommand) + const orgId = flags.orgId || this.getConfig('org.id') + if (!orgId) { + this.error('You have not selected an Organization. Please select first.') + } + + const workspaceDetails = { + name: flags.name, + title: flags.title || flags.name + } + + // Workspace name allows only alphanumeric values + if (!/^[a-zA-Z0-9]+$/.test(workspaceDetails.name)) { + this.error(`Workspace name ${workspaceDetails.name} is invalid. It should only contain alphanumeric values.`) + } + if (workspaceDetails.name.length < 3 || workspaceDetails.name.length > 45) { + this.error('Workspace name must be between 3 and 45 characters long.') + } + + // Workspace title should only contain alphanumeric characters and spaces + if (!/^[a-zA-Z0-9\s]+$/.test(workspaceDetails.title)) { + this.error(`Workspace title ${workspaceDetails.title} is invalid. It should only contain alphanumeric characters and spaces.`) + } + if (workspaceDetails.title.length < 3 || workspaceDetails.title.length > 45) { + this.error('Workspace title must be between 3 and 45 characters long.') + } + + await this.initSdk() + + try { + // resolve project by name or title to project id + const projects = await this.consoleCLI.getProjects(orgId) + const project = projects.find(p => p.name === flags.projectName || p.title === flags.projectName) + if (!project) { + this.error(`Project ${flags.projectName} not found in the Organization.`) + } + const projectId = project.id + + const workspaces = await this.consoleCLI.getWorkspaces(orgId, projectId) + if (workspaces.find(ws => ws.name === workspaceDetails.name)) { + this.error(`Workspace ${workspaceDetails.name} already exists. Please choose a different name.`) + } + + const workspace = await this.consoleCLI.createWorkspace(orgId, projectId, workspaceDetails) + this.log(`Workspace ${workspace.name} created successfully.`) + return workspace + } catch (err) { + this.error(err.message) + } finally { + this.cleanOutput() + } + } +} + +CreateCommand.description = 'Create a new Workspace for the selected Project' + +CreateCommand.flags = { + ...ConsoleCommand.flags, + orgId: Flags.string({ + description: 'OrgID of the project to create the workspace in' + }), + projectName: Flags.string({ + description: 'Name or title of the project to create the workspace in', + required: true + }), + name: Flags.string({ + description: 'Name of the workspace', + required: true + }), + title: Flags.string({ + description: 'Title of the workspace, defaults to the name' + }), + json: Flags.boolean({ + description: 'Output json', + char: 'j', + exclusive: ['yml'] + }), + yml: Flags.boolean({ + description: 'Output yml', + char: 'y', + exclusive: ['json'] + }) +} + +CreateCommand.aliases = [ + 'console:workspace:create', + 'console:workspace:init', + 'console:ws:create', + 'console:ws:init' +] + +module.exports = CreateCommand diff --git a/test/commands/console/workspace/create.test.js b/test/commands/console/workspace/create.test.js new file mode 100644 index 0000000..586c085 --- /dev/null +++ b/test/commands/console/workspace/create.test.js @@ -0,0 +1,170 @@ +/* +Copyright 2026 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +const mockProject = { + id: '9999', + name: 'myproject', + title: 'My Project' +} + +const mockWorkspace = { + id: '1000000001', + name: 'TestWorkspace', + title: 'Test Workspace', + enabled: 1 +} + +const mockConsoleCLIInstance = { + getProjects: jest.fn().mockResolvedValue([mockProject]), + getWorkspaces: jest.fn().mockResolvedValue([]), + createWorkspace: jest.fn().mockResolvedValue(mockWorkspace) +} + +jest.mock('@adobe/aio-cli-lib-console', () => ({ + init: jest.fn().mockResolvedValue(mockConsoleCLIInstance), + cleanStdOut: jest.fn() +})) + +const TheCommand = require('../../../../src/commands/console/workspace/create') + +describe('console:workspace:create', () => { + let command + + beforeEach(() => { + command = new TheCommand() + mockConsoleCLIInstance.createWorkspace.mockReset() + mockConsoleCLIInstance.createWorkspace.mockResolvedValue(mockWorkspace) + mockConsoleCLIInstance.getWorkspaces.mockReset() + mockConsoleCLIInstance.getWorkspaces.mockResolvedValue([]) + mockConsoleCLIInstance.getProjects.mockReset() + mockConsoleCLIInstance.getProjects.mockResolvedValue([mockProject]) + }) + + afterEach(() => { + command = null + }) + + it('should create a workspace', async () => { + command.argv = ['--name', 'testworkspace', '--title', 'Test Workspace', '--projectName', 'myproject', '--orgId', '1234567890'] + const result = await command.run() + expect(mockConsoleCLIInstance.getProjects).toHaveBeenCalledWith('1234567890') + expect(mockConsoleCLIInstance.createWorkspace).toHaveBeenCalledWith('1234567890', '9999', { + name: 'testworkspace', + title: 'Test Workspace' + }) + expect(result).toEqual(mockWorkspace) + }) + + it('should not create a workspace if the name is not provided', async () => { + command.argv = ['--projectName', 'myproject', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Missing required flag name') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) + + it('should not create a workspace if the projectName is not provided', async () => { + command.argv = ['--name', 'testworkspace', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Missing required flag projectName') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) + + it('should not create a workspace if the orgId is not provided and no config', async () => { + command.argv = ['--name', 'testworkspace', '--projectName', 'myproject'] + command.getConfig = jest.fn().mockReturnValue(null) + await expect(command.run()).rejects.toThrow('You have not selected an Organization. Please select first.') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) + + it('should use config org.id if orgId flag is not provided', async () => { + command.argv = ['--name', 'testworkspace', '--title', 'Test Workspace', '--projectName', 'myproject'] + command.getConfig = jest.fn().mockImplementation(key => { + if (key === 'org.id') return '0987654321' + return null + }) + const result = await command.run() + expect(mockConsoleCLIInstance.getProjects).toHaveBeenCalledWith('0987654321') + expect(mockConsoleCLIInstance.createWorkspace).toHaveBeenCalledWith('0987654321', '9999', { + name: 'testworkspace', + title: 'Test Workspace' + }) + expect(result).toEqual(mockWorkspace) + }) + + it('should resolve project by title', async () => { + command.argv = ['--name', 'testworkspace', '--projectName', 'My Project', '--orgId', '1234567890'] + const result = await command.run() + expect(mockConsoleCLIInstance.getProjects).toHaveBeenCalledWith('1234567890') + expect(mockConsoleCLIInstance.createWorkspace).toHaveBeenCalledWith('1234567890', '9999', { + name: 'testworkspace', + title: 'testworkspace' + }) + expect(result).toEqual(mockWorkspace) + }) + + it('should error if the project name is not found', async () => { + mockConsoleCLIInstance.getProjects.mockResolvedValue([]) + command.argv = ['--name', 'testworkspace', '--projectName', 'nonexistent', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Project nonexistent not found in the Organization.') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) + + it('should not create a workspace if the name is already in use', async () => { + mockConsoleCLIInstance.getWorkspaces.mockResolvedValue([mockWorkspace]) + command.argv = ['--name', 'TestWorkspace', '--projectName', 'myproject', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Workspace TestWorkspace already exists. Please choose a different name.') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) + + it('should use name as title if no title is provided', async () => { + command.argv = ['--name', 'testworkspace', '--projectName', 'myproject', '--orgId', '1234567890'] + const result = await command.run() + expect(mockConsoleCLIInstance.createWorkspace).toHaveBeenCalledWith('1234567890', '9999', { + name: 'testworkspace', + title: 'testworkspace' + }) + expect(result).toEqual(mockWorkspace) + }) + + it('should not create a workspace if the name is invalid', async () => { + command.argv = ['--name', 'test-workspace!', '--projectName', 'myproject', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Workspace name test-workspace! is invalid. It should only contain alphanumeric values.') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) + + it('should not create a workspace if the title is invalid', async () => { + command.argv = ['--name', 'testworkspace', '--title', 'Test Workspace!', '--projectName', 'myproject', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Workspace title Test Workspace! is invalid. It should only contain alphanumeric characters and spaces.') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) + + it('should not create a workspace if the name is too short', async () => { + command.argv = ['--name', 'ab', '--projectName', 'myproject', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Workspace name must be between 3 and 45 characters long.') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) + + it('should not create a workspace if the name is too long', async () => { + command.argv = ['--name', 'testworkspace'.repeat(50), '--projectName', 'myproject', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Workspace name must be between 3 and 45 characters long.') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) + + it('should not create a workspace if the title is too short', async () => { + command.argv = ['--name', 'testworkspace', '--title', 'ab', '--projectName', 'myproject', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Workspace title must be between 3 and 45 characters long.') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) + + it('should not create a workspace if the title is too long', async () => { + command.argv = ['--name', 'testworkspace', '--title', 'Test Workspace'.repeat(50), '--projectName', 'myproject', '--orgId', '1234567890'] + await expect(command.run()).rejects.toThrow('Workspace title must be between 3 and 45 characters long.') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + }) +}) From 452f312e254c8f11f26787466ee27bd139f06057 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Mon, 30 Mar 2026 11:26:17 -0700 Subject: [PATCH 07/16] Update src/commands/console/workspace/create.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/commands/console/workspace/create.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/commands/console/workspace/create.js b/src/commands/console/workspace/create.js index f5eed8d..4b1e80e 100644 --- a/src/commands/console/workspace/create.js +++ b/src/commands/console/workspace/create.js @@ -58,7 +58,13 @@ class CreateCommand extends ConsoleCommand { } const workspace = await this.consoleCLI.createWorkspace(orgId, projectId, workspaceDetails) - this.log(`Workspace ${workspace.name} created successfully.`) + if (flags.json) { + this.printJson(workspace) + } else if (flags.yml) { + this.printYaml(workspace) + } else { + this.log(`Workspace ${workspace.name} created successfully.`) + } return workspace } catch (err) { this.error(err.message) From 32126d72b11f685b1899f3d5ea82d7827b131806 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Mon, 30 Mar 2026 11:26:33 -0700 Subject: [PATCH 08/16] Update src/commands/console/workspace/create.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/commands/console/workspace/create.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/console/workspace/create.js b/src/commands/console/workspace/create.js index 4b1e80e..69128dd 100644 --- a/src/commands/console/workspace/create.js +++ b/src/commands/console/workspace/create.js @@ -34,7 +34,7 @@ class CreateCommand extends ConsoleCommand { } // Workspace title should only contain alphanumeric characters and spaces - if (!/^[a-zA-Z0-9\s]+$/.test(workspaceDetails.title)) { + if (!/^[a-zA-Z0-9 ]+$/.test(workspaceDetails.title)) { this.error(`Workspace title ${workspaceDetails.title} is invalid. It should only contain alphanumeric characters and spaces.`) } if (workspaceDetails.title.length < 3 || workspaceDetails.title.length > 45) { From da420ef11ced8c6d97172e364f64b763cf281473 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Mon, 30 Mar 2026 11:27:09 -0700 Subject: [PATCH 09/16] Update src/commands/console/workspace/create.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/commands/console/workspace/create.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/commands/console/workspace/create.js b/src/commands/console/workspace/create.js index 69128dd..b401e05 100644 --- a/src/commands/console/workspace/create.js +++ b/src/commands/console/workspace/create.js @@ -17,7 +17,9 @@ class CreateCommand extends ConsoleCommand { const { flags } = await this.parse(CreateCommand) const orgId = flags.orgId || this.getConfig('org.id') if (!orgId) { - this.error('You have not selected an Organization. Please select first.') + this.log('You have not selected an Organization. Please select one before running this command.') + this.printConsoleConfig() + process.exit(1) } const workspaceDetails = { From 15840f0407d8b0bde892b238c453e388ba731004 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Mon, 30 Mar 2026 11:27:47 -0700 Subject: [PATCH 10/16] Update src/commands/console/workspace/create.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/commands/console/workspace/create.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/console/workspace/create.js b/src/commands/console/workspace/create.js index b401e05..0a4e5b1 100644 --- a/src/commands/console/workspace/create.js +++ b/src/commands/console/workspace/create.js @@ -81,7 +81,7 @@ CreateCommand.description = 'Create a new Workspace for the selected Project' CreateCommand.flags = { ...ConsoleCommand.flags, orgId: Flags.string({ - description: 'OrgID of the project to create the workspace in' + description: 'OrgID of the organization that contains the project to create the workspace in' }), projectName: Flags.string({ description: 'Name or title of the project to create the workspace in', From 38f5ef62e2d94e972e61b167d7282df77cea423e Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Mon, 30 Mar 2026 11:28:32 -0700 Subject: [PATCH 11/16] Update test/commands/console/workspace/create.test.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../commands/console/workspace/create.test.js | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/commands/console/workspace/create.test.js b/test/commands/console/workspace/create.test.js index 586c085..0baf8f5 100644 --- a/test/commands/console/workspace/create.test.js +++ b/test/commands/console/workspace/create.test.js @@ -63,6 +63,49 @@ describe('console:workspace:create', () => { expect(result).toEqual(mockWorkspace) }) + it('should output JSON when --json is used', async () => { + const stdoutSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => true) + const stderrSpy = jest.spyOn(process.stderr, 'write').mockImplementation(() => true) + + try { + command.argv = ['--name', 'testworkspace', '--title', 'Test Workspace', '--projectName', 'myproject', '--orgId', '1234567890', '--json'] + await command.run() + + const stdout = stdoutSpy.mock.calls.map(args => args[0]).join('') + const stderr = stderrSpy.mock.calls.map(args => args[0]).join('') + + expect(stderr).toBe('') + let parsed + expect(() => { parsed = JSON.parse(stdout) }).not.toThrow() + expect(parsed).toMatchObject(mockWorkspace) + } finally { + stdoutSpy.mockRestore() + stderrSpy.mockRestore() + } + }) + + it('should output YAML when --yml is used', async () => { + const stdoutSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => true) + const stderrSpy = jest.spyOn(process.stderr, 'write').mockImplementation(() => true) + + try { + command.argv = ['--name', 'testworkspace', '--title', 'Test Workspace', '--projectName', 'myproject', '--orgId', '1234567890', '--yml'] + await command.run() + + const stdout = stdoutSpy.mock.calls.map(args => args[0]).join('') + const stderr = stderrSpy.mock.calls.map(args => args[0]).join('') + + expect(stderr).toBe('') + expect(stdout).toContain('id:') + expect(stdout).toContain('name:') + expect(stdout).toContain('title:') + expect(stdout).toContain('Test Workspace') + expect(stdout).toContain('TestWorkspace') + } finally { + stdoutSpy.mockRestore() + stderrSpy.mockRestore() + } + }) it('should not create a workspace if the name is not provided', async () => { command.argv = ['--projectName', 'myproject', '--orgId', '1234567890'] await expect(command.run()).rejects.toThrow('Missing required flag name') From 85b4301209d5c6a296df845048a1e8f78aa80719 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Mon, 30 Mar 2026 11:49:39 -0700 Subject: [PATCH 12/16] Update src/commands/console/workspace/create.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/commands/console/workspace/create.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/console/workspace/create.js b/src/commands/console/workspace/create.js index 0a4e5b1..570f901 100644 --- a/src/commands/console/workspace/create.js +++ b/src/commands/console/workspace/create.js @@ -17,9 +17,9 @@ class CreateCommand extends ConsoleCommand { const { flags } = await this.parse(CreateCommand) const orgId = flags.orgId || this.getConfig('org.id') if (!orgId) { - this.log('You have not selected an Organization. Please select one before running this command.') + this.log('You have not selected an Organization. Please select one first.') this.printConsoleConfig() - process.exit(1) + this.exit(1) } const workspaceDetails = { From 3b936b5022e3796da54bf09b46930e6552aff986 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Mon, 30 Mar 2026 11:50:18 -0700 Subject: [PATCH 13/16] Update src/commands/console/workspace/create.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/commands/console/workspace/create.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/console/workspace/create.js b/src/commands/console/workspace/create.js index 570f901..98e0ef2 100644 --- a/src/commands/console/workspace/create.js +++ b/src/commands/console/workspace/create.js @@ -76,7 +76,7 @@ class CreateCommand extends ConsoleCommand { } } -CreateCommand.description = 'Create a new Workspace for the selected Project' +CreateCommand.description = 'Create a new Workspace in the specified Project' CreateCommand.flags = { ...ConsoleCommand.flags, From dfa0e25b68ca68b65e9df882d2178ffba346724c Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Mon, 30 Mar 2026 11:51:12 -0700 Subject: [PATCH 14/16] Update test/commands/console/workspace/create.test.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- test/commands/console/workspace/create.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/commands/console/workspace/create.test.js b/test/commands/console/workspace/create.test.js index 0baf8f5..f7f2224 100644 --- a/test/commands/console/workspace/create.test.js +++ b/test/commands/console/workspace/create.test.js @@ -39,7 +39,7 @@ describe('console:workspace:create', () => { let command beforeEach(() => { - command = new TheCommand() + command = new TheCommand([]) mockConsoleCLIInstance.createWorkspace.mockReset() mockConsoleCLIInstance.createWorkspace.mockResolvedValue(mockWorkspace) mockConsoleCLIInstance.getWorkspaces.mockReset() From defad00a1623ab4b6be44aedd0bea36ec35066a3 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Mon, 30 Mar 2026 12:38:55 -0700 Subject: [PATCH 15/16] Update test/commands/console/workspace/create.test.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../commands/console/workspace/create.test.js | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/test/commands/console/workspace/create.test.js b/test/commands/console/workspace/create.test.js index f7f2224..a60a71b 100644 --- a/test/commands/console/workspace/create.test.js +++ b/test/commands/console/workspace/create.test.js @@ -119,10 +119,25 @@ describe('console:workspace:create', () => { }) it('should not create a workspace if the orgId is not provided and no config', async () => { - command.argv = ['--name', 'testworkspace', '--projectName', 'myproject'] - command.getConfig = jest.fn().mockReturnValue(null) - await expect(command.run()).rejects.toThrow('You have not selected an Organization. Please select first.') - expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + const stdoutSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => true) + const stderrSpy = jest.spyOn(process.stderr, 'write').mockImplementation(() => true) + + try { + command.argv = ['--name', 'testworkspace', '--projectName', 'myproject'] + command.getConfig = jest.fn().mockReturnValue(null) + + await expect(command.run()).rejects.toThrow() + + const stdout = stdoutSpy.mock.calls.map(args => args[0]).join('') + const stderr = stderrSpy.mock.calls.map(args => args[0]).join('') + + const combinedOutput = stdout + stderr + expect(combinedOutput).toContain('You have not selected an Organization. Please select first.') + expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() + } finally { + stdoutSpy.mockRestore() + stderrSpy.mockRestore() + } }) it('should use config org.id if orgId flag is not provided', async () => { From b2c5b72a3b42e7b7e2ccde7b6b50c8062bca9701 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Mon, 30 Mar 2026 16:32:03 -0700 Subject: [PATCH 16/16] create workspace matches by name only, title not necessarily unique --- src/commands/console/workspace/create.js | 7 +++---- test/commands/console/workspace/create.test.js | 13 +------------ 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/commands/console/workspace/create.js b/src/commands/console/workspace/create.js index 98e0ef2..1610b46 100644 --- a/src/commands/console/workspace/create.js +++ b/src/commands/console/workspace/create.js @@ -46,9 +46,9 @@ class CreateCommand extends ConsoleCommand { await this.initSdk() try { - // resolve project by name or title to project id + // resolve project by name to project id const projects = await this.consoleCLI.getProjects(orgId) - const project = projects.find(p => p.name === flags.projectName || p.title === flags.projectName) + const project = projects.find(p => p.name === flags.projectName) if (!project) { this.error(`Project ${flags.projectName} not found in the Organization.`) } @@ -84,7 +84,7 @@ CreateCommand.flags = { description: 'OrgID of the organization that contains the project to create the workspace in' }), projectName: Flags.string({ - description: 'Name or title of the project to create the workspace in', + description: 'Name of the project to create the workspace in', required: true }), name: Flags.string({ @@ -107,7 +107,6 @@ CreateCommand.flags = { } CreateCommand.aliases = [ - 'console:workspace:create', 'console:workspace:init', 'console:ws:create', 'console:ws:init' diff --git a/test/commands/console/workspace/create.test.js b/test/commands/console/workspace/create.test.js index a60a71b..ef029b9 100644 --- a/test/commands/console/workspace/create.test.js +++ b/test/commands/console/workspace/create.test.js @@ -132,7 +132,7 @@ describe('console:workspace:create', () => { const stderr = stderrSpy.mock.calls.map(args => args[0]).join('') const combinedOutput = stdout + stderr - expect(combinedOutput).toContain('You have not selected an Organization. Please select first.') + expect(combinedOutput).toContain('You have not selected an Organization. Please select one first.') expect(mockConsoleCLIInstance.createWorkspace).not.toHaveBeenCalled() } finally { stdoutSpy.mockRestore() @@ -155,17 +155,6 @@ describe('console:workspace:create', () => { expect(result).toEqual(mockWorkspace) }) - it('should resolve project by title', async () => { - command.argv = ['--name', 'testworkspace', '--projectName', 'My Project', '--orgId', '1234567890'] - const result = await command.run() - expect(mockConsoleCLIInstance.getProjects).toHaveBeenCalledWith('1234567890') - expect(mockConsoleCLIInstance.createWorkspace).toHaveBeenCalledWith('1234567890', '9999', { - name: 'testworkspace', - title: 'testworkspace' - }) - expect(result).toEqual(mockWorkspace) - }) - it('should error if the project name is not found', async () => { mockConsoleCLIInstance.getProjects.mockResolvedValue([]) command.argv = ['--name', 'testworkspace', '--projectName', 'nonexistent', '--orgId', '1234567890']