From c09d22963904ebe1f87e9ee348d5e042c0d28762 Mon Sep 17 00:00:00 2001 From: Shane McLaughlin Date: Tue, 18 Apr 2023 10:30:13 -0500 Subject: [PATCH] feat: more scratch org creation flags (#641) * feat: more scratch org creation flags * fix: edit messages for new flags * feat: edition overrides definition file, both are allowed * test: allow edition with config file * test: remove unused test dep --------- Co-authored-by: Juliet Shackell --- command-snapshot.json | 4 +++ messages/create_scratch.md | 48 +++++++++++++++++++++++++++--- package.json | 2 +- src/commands/org/create/scratch.ts | 30 +++++++++++++++---- test/nut/scratchCreate.nut.ts | 16 +++++++--- 5 files changed, 86 insertions(+), 14 deletions(-) diff --git a/command-snapshot.json b/command-snapshot.json index f99dd485..f284ef35 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -78,14 +78,18 @@ "async", "client-id", "definition-file", + "description", "duration-days", "edition", "json", + "name", "no-ancestors", "no-namespace", + "release", "set-default", "target-dev-hub", "track-source", + "username", "wait" ], "alias": ["env:create:scratch"] diff --git a/messages/create_scratch.md b/messages/create_scratch.md index 9c1bd2b0..1c96bc7b 100644 --- a/messages/create_scratch.md +++ b/messages/create_scratch.md @@ -4,7 +4,17 @@ Create a scratch org. # description -There are two ways to create a scratch org: specify a definition file that contains the options or use the --edition flag to specify the one required option. If you want to set options other than the edition, such as org features or settings, you must use a definition file. +There are two ways to create a scratch org: either specify a definition file that contains the options or use the --edition flag to specify the one required option. + +For either method, you can also use these flags; if you use them with --definition-file, they override their equivalent option in the scratch org definition file: + + * --description + * --name (equivalent to the "orgName" option) + * --username + * --release + * --edition + +If you want to set options other than the preceding ones, such as org features or settings, you must use a definition file. You must specify a Dev Hub to create a scratch org, either with the --target-dev-hub flag or by setting your default Dev Hub with the target-dev-hub configuration variable. @@ -14,9 +24,13 @@ You must specify a Dev Hub to create a scratch org, either with the --target-dev <%= config.bin %> <%= command.id %> --edition=developer --alias my-scratch-org -- Specify the Dev Hub using its alias and a scratch org definition file. Set the scratch org as your default and specify that it expires in 3 days: +- Create a scratch org with a definition file. Specify the Dev Hub using its alias, set the scratch org as your default, and specify that it expires in 3 days: + + <%= config.bin %> <%= command.id %> --target-dev-hub MyHub --definition-file config/project-scratch-def.json --set-default --duration-days 3 + +- Create a preview Enterprise edition scratch org; for use only during Salesforce release transition periods: - <%= config.bin %> <%= command.id %> --target-dev-hub=MyHub --definition-file config/project-scratch-def.json --set-default --duration-days 3 + <%= config.bin %> <%= command.id %> --edition=enterprise --alias my-scratch-org --target-dev-hub MyHub --release preview # flags.target-hub.summary @@ -44,7 +58,7 @@ Don't include second-generation managed package (2GP) ancestors in the scratch o # flags.edition.summary -Salesforce edition of the scratch org. +Salesforce edition of the scratch org. Overrides the value of the "edition" option in the definition file, if set. # flags.async.summary @@ -96,6 +110,32 @@ Create the scratch org with no namespace, even if the Dev Hub has a namespace. Number of days before the org expires. +# flags.username.summary + +Username of the scratch org admin user. Overrides the value of the "username" option in the definition file, if set. + +# flags.username.description + +The username must be unique within the entire scratch org and sandbox universe. You must add your own logic to ensure uniqueness. + +Omit this flag to have Salesforce generate a unique username for your org. + +# flags.description.summary + +Description of the scratch org in the Dev Hub. Overrides the value of the "description" option in the definition file, if set. + +# flags.name.summary + +Name of the org, such as "Acme Company". Overrides the value of the "orgName" option in the definition file, if set. + +# flags.release.summary + +Release of the scratch org as compared to the Dev Hub release. + +# flags.release.description + +By default, scratch orgs are on the same release as the Dev Hub. During Salesforce release transition periods, you can override this default behavior and opt in or out of the new release. + # prompt.secret OAuth client secret of your personal connected app diff --git a/package.json b/package.json index f4c7dd33..afe42e19 100644 --- a/package.json +++ b/package.json @@ -234,4 +234,4 @@ "output": [] } } -} \ No newline at end of file +} diff --git a/src/commands/org/create/scratch.ts b/src/commands/org/create/scratch.ts index 4a4b4d3a..8ef13505 100644 --- a/src/commands/org/create/scratch.ts +++ b/src/commands/org/create/scratch.ts @@ -51,7 +51,6 @@ export default class EnvCreateScratch extends SfCommand { char: 'f', summary: messages.getMessage('flags.definition-file.summary'), description: messages.getMessage('flags.definition-file.description'), - exactlyOne: ['definition-file', 'edition'], }), 'target-dev-hub': Flags.requiredHub({ char: 'v', @@ -78,7 +77,6 @@ export default class EnvCreateScratch extends SfCommand { 'partner-group', 'partner-professional', ], - exactlyOne: ['definition-file', 'edition'], }), 'no-namespace': Flags.boolean({ char: 'm', @@ -115,6 +113,21 @@ export default class EnvCreateScratch extends SfCommand { description: messages.getMessage('flags.track-source.description'), allowNo: true, }), + username: Flags.string({ + summary: messages.getMessage('flags.username.summary'), + description: messages.getMessage('flags.username.description'), + }), + description: Flags.string({ + summary: messages.getMessage('flags.description.summary'), + }), + name: Flags.string({ + summary: messages.getMessage('flags.name.summary'), + }), + release: Flags.string({ + summary: messages.getMessage('flags.release.summary'), + description: messages.getMessage('flags.release.description'), + options: ['preview', 'previous'], + }), }; public async run(): Promise { const lifecycle = Lifecycle.getInstance(); @@ -123,9 +136,16 @@ export default class EnvCreateScratch extends SfCommand { if (!baseUrl) { throw new SfError('No instance URL found for the dev hub'); } - const orgConfig = flags['definition-file'] - ? (JSON.parse(await fs.promises.readFile(flags['definition-file'], 'utf-8')) as Record) - : { edition: flags.edition }; + const orgConfig = { + ...(flags['definition-file'] + ? (JSON.parse(await fs.promises.readFile(flags['definition-file'], 'utf-8')) as Record) + : {}), + ...(flags.edition ? { edition: flags.edition } : {}), + ...(flags.username ? { username: flags.username } : {}), + ...(flags.description ? { description: flags.description } : {}), + ...(flags.name ? { orgName: flags.name } : {}), + ...(flags.release ? { release: flags.release } : {}), + }; const createCommandOptions: ScratchOrgCreateOptions = { hubOrg: flags['target-dev-hub'], diff --git a/test/nut/scratchCreate.nut.ts b/test/nut/scratchCreate.nut.ts index 615f5981..1fa0ef23 100644 --- a/test/nut/scratchCreate.nut.ts +++ b/test/nut/scratchCreate.nut.ts @@ -6,7 +6,7 @@ */ import * as fs from 'fs'; import * as path from 'path'; -import { execCmd, TestSession } from '@salesforce/cli-plugins-testkit'; +import { execCmd, genUniqueString, TestSession } from '@salesforce/cli-plugins-testkit'; import { assert, expect } from 'chai'; import { AuthFields, Messages, Global, StateAggregator } from '@salesforce/core'; import { secretTimeout } from '../../src/commands/org/create/scratch'; @@ -42,9 +42,6 @@ describe('env create scratch NUTs', () => { it('non-existent config file', () => { execCmd('env:create:scratch -f badfile.json', { ensureExitCode: 1 }); }); - it('config file AND edition', () => { - execCmd('env:create:scratch -f config/project-scratch-def.json --edition developer', { ensureExitCode: 1 }); - }); it('wait zero', () => { execCmd('env:create:scratch -f config/project-scratch-def.json --wait 0', { ensureExitCode: 1 }); }); @@ -85,6 +82,17 @@ describe('env create scratch NUTs', () => { ).jsonOutput?.result; expect(resp).to.have.all.keys(keys); }); + it('creates an org from config file with "override" flags ', () => { + const expectedUsername = genUniqueString('%s@nut.org'); + const resp = execCmd( + `env:create:scratch -f config/project-scratch-def.json --json --username ${expectedUsername} --description "new one" --name TheOrg --wait 60`, + { + ensureExitCode: 0, + } + ).jsonOutput?.result; + expect(resp).to.have.all.keys(keys); + expect(resp?.username).to.equal(expectedUsername); + }); it('creates an org with tracking disabled ', async () => { const resp = execCmd( 'env:create:scratch --edition developer --no-track-source --json --wait 60',