|
5 | 5 | * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause |
6 | 6 | */ |
7 | 7 |
|
| 8 | +import { MultiStageOutput } from '@oclif/multi-stage-output'; |
8 | 9 | import { |
9 | 10 | Lifecycle, |
10 | 11 | Messages, |
11 | 12 | Org, |
12 | 13 | scratchOrgCreate, |
13 | 14 | ScratchOrgLifecycleEvent, |
14 | 15 | scratchOrgLifecycleEventName, |
| 16 | + scratchOrgLifecycleStages, |
15 | 17 | SfError, |
16 | 18 | } from '@salesforce/core'; |
17 | 19 | import { Flags, SfCommand } from '@salesforce/sf-plugins-core'; |
18 | 20 | import { Duration } from '@salesforce/kit'; |
| 21 | +import terminalLink from 'terminal-link'; |
19 | 22 | import { buildScratchOrgRequest } from '../../../shared/scratchOrgRequest.js'; |
20 | | -import { buildStatus } from '../../../shared/scratchOrgOutput.js'; |
21 | 23 | import { ScratchCreateResponse } from '../../../shared/orgTypes.js'; |
22 | 24 |
|
23 | 25 | Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); |
24 | 26 | const messages = Messages.loadMessages('@salesforce/plugin-org', 'create_scratch'); |
25 | 27 |
|
26 | 28 | const definitionFileHelpGroupName = 'Definition File Override'; |
| 29 | + |
27 | 30 | export default class OrgCreateScratch extends SfCommand<ScratchCreateResponse> { |
28 | 31 | public static readonly summary = messages.getMessage('summary'); |
29 | 32 | public static readonly description = messages.getMessage('description'); |
@@ -167,38 +170,69 @@ export default class OrgCreateScratch extends SfCommand<ScratchCreateResponse> { |
167 | 170 | flags, |
168 | 171 | flags['client-id'] ? await this.secretPrompt({ message: messages.getMessage('prompt.secret') }) : undefined |
169 | 172 | ); |
170 | | - let lastStatus: string | undefined; |
171 | 173 |
|
172 | | - if (!flags.async) { |
173 | | - lifecycle.on<ScratchOrgLifecycleEvent>(scratchOrgLifecycleEventName, async (data): Promise<void> => { |
174 | | - lastStatus = buildStatus(data, baseUrl); |
175 | | - this.spinner.status = lastStatus; |
176 | | - return Promise.resolve(); |
177 | | - }); |
178 | | - } |
179 | | - this.log(); |
180 | | - this.spinner.start( |
181 | | - flags.async ? 'Requesting Scratch Org (will not wait for completion because --async)' : 'Creating Scratch Org' |
182 | | - ); |
| 174 | + const stager = new MultiStageOutput<ScratchOrgLifecycleEvent & { alias: string | undefined }>({ |
| 175 | + stages: flags.async ? ['prepare request', 'send request', 'done'] : scratchOrgLifecycleStages, |
| 176 | + title: flags.async ? 'Creating Scratch Org (async)' : 'Creating Scratch Org', |
| 177 | + data: { alias: flags.alias }, |
| 178 | + jsonEnabled: this.jsonEnabled(), |
| 179 | + postStagesBlock: [ |
| 180 | + { |
| 181 | + label: 'Request Id', |
| 182 | + type: 'dynamic-key-value', |
| 183 | + get: (data) => |
| 184 | + data?.scratchOrgInfo?.Id && terminalLink(data.scratchOrgInfo.Id, `${baseUrl}/${data.scratchOrgInfo.Id}`), |
| 185 | + bold: true, |
| 186 | + }, |
| 187 | + { |
| 188 | + label: 'OrgId', |
| 189 | + type: 'dynamic-key-value', |
| 190 | + get: (data) => data?.scratchOrgInfo?.ScratchOrg, |
| 191 | + bold: true, |
| 192 | + color: 'cyan', |
| 193 | + }, |
| 194 | + { |
| 195 | + label: 'Username', |
| 196 | + type: 'dynamic-key-value', |
| 197 | + get: (data) => data?.scratchOrgInfo?.SignupUsername, |
| 198 | + bold: true, |
| 199 | + color: 'cyan', |
| 200 | + }, |
| 201 | + { |
| 202 | + label: 'Alias', |
| 203 | + type: 'static-key-value', |
| 204 | + get: (data) => data?.alias, |
| 205 | + }, |
| 206 | + ], |
| 207 | + }); |
| 208 | + |
| 209 | + lifecycle.on<ScratchOrgLifecycleEvent>(scratchOrgLifecycleEventName, async (data): Promise<void> => { |
| 210 | + stager.goto(data.stage, data); |
| 211 | + if (data.stage === 'done') { |
| 212 | + stager.stop(); |
| 213 | + } |
| 214 | + return Promise.resolve(); |
| 215 | + }); |
183 | 216 |
|
184 | 217 | try { |
185 | 218 | const { username, scratchOrgInfo, authFields, warnings } = await scratchOrgCreate(createCommandOptions); |
186 | 219 |
|
187 | | - this.spinner.stop(lastStatus); |
188 | 220 | if (!scratchOrgInfo) { |
189 | 221 | throw new SfError('The scratch org did not return with any information'); |
190 | 222 | } |
191 | | - this.log(); |
| 223 | + |
192 | 224 | if (flags.async) { |
| 225 | + stager.goto('done', { scratchOrgInfo }); |
| 226 | + stager.stop(); |
193 | 227 | this.info(messages.getMessage('action.resume', [this.config.bin, scratchOrgInfo.Id])); |
194 | 228 | } else { |
195 | 229 | this.logSuccess(messages.getMessage('success')); |
196 | 230 | } |
197 | 231 |
|
198 | 232 | return { username, scratchOrgInfo, authFields, warnings, orgId: authFields?.orgId }; |
199 | 233 | } catch (error) { |
| 234 | + stager.stop(error as Error); |
200 | 235 | if (error instanceof SfError && error.name === 'ScratchOrgInfoTimeoutError') { |
201 | | - this.spinner.stop(lastStatus); |
202 | 236 | const scratchOrgInfoId = (error.data as { scratchOrgInfoId: string }).scratchOrgInfoId; |
203 | 237 | const resumeMessage = messages.getMessage('action.resume', [this.config.bin, scratchOrgInfoId]); |
204 | 238 |
|
|
0 commit comments