@microsoft/managed-apps-cli 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -24
- package/dist/ArgumentProvider.d.ts +10 -2
- package/dist/ArgumentProvider.d.ts.map +1 -1
- package/dist/ArgumentProvider.js +11 -2
- package/dist/ArgumentProvider.js.map +1 -1
- package/dist/Authentication/ActiveAccountStore.d.ts +24 -0
- package/dist/Authentication/ActiveAccountStore.d.ts.map +1 -0
- package/dist/Authentication/ActiveAccountStore.js +54 -0
- package/dist/Authentication/ActiveAccountStore.js.map +1 -0
- package/dist/Authentication/EnvironmentVariableAuthenticationProvider.d.ts +26 -0
- package/dist/Authentication/EnvironmentVariableAuthenticationProvider.d.ts.map +1 -0
- package/dist/Authentication/EnvironmentVariableAuthenticationProvider.js +31 -0
- package/dist/Authentication/EnvironmentVariableAuthenticationProvider.js.map +1 -0
- package/dist/Authentication/NodeMsalAuthenticationProvider.d.ts +57 -3
- package/dist/Authentication/NodeMsalAuthenticationProvider.d.ts.map +1 -1
- package/dist/Authentication/NodeMsalAuthenticationProvider.js +187 -27
- package/dist/Authentication/NodeMsalAuthenticationProvider.js.map +1 -1
- package/dist/Cli.d.ts.map +1 -1
- package/dist/Cli.js +74 -23
- package/dist/Cli.js.map +1 -1
- package/dist/CliUtils.d.ts +2 -8
- package/dist/CliUtils.d.ts.map +1 -1
- package/dist/CliUtils.js.map +1 -1
- package/dist/Constants/CommandRegistry.d.ts.map +1 -1
- package/dist/Constants/CommandRegistry.js +32 -6
- package/dist/Constants/CommandRegistry.js.map +1 -1
- package/dist/Constants/HelpStrings.d.ts +39 -3
- package/dist/Constants/HelpStrings.d.ts.map +1 -1
- package/dist/Constants/HelpStrings.js +63 -10
- package/dist/Constants/HelpStrings.js.map +1 -1
- package/dist/Constants.d.ts +2 -0
- package/dist/Constants.d.ts.map +1 -1
- package/dist/Constants.js +2 -0
- package/dist/Constants.js.map +1 -1
- package/dist/Errors/GitHubErrorMap.d.ts +39 -0
- package/dist/Errors/GitHubErrorMap.d.ts.map +1 -0
- package/dist/Errors/GitHubErrorMap.js +187 -0
- package/dist/Errors/GitHubErrorMap.js.map +1 -0
- package/dist/HttpClient/CliHttpClient.d.ts +8 -3
- package/dist/HttpClient/CliHttpClient.d.ts.map +1 -1
- package/dist/HttpClient/CliHttpClient.js +33 -13
- package/dist/HttpClient/CliHttpClient.js.map +1 -1
- package/dist/Logger/ConsoleWriter.d.ts.map +1 -1
- package/dist/Logger/ConsoleWriter.js +7 -7
- package/dist/Logger/ConsoleWriter.js.map +1 -1
- package/dist/Middletier/FunctionsBundler.d.ts +17 -0
- package/dist/Middletier/FunctionsBundler.d.ts.map +1 -0
- package/dist/Middletier/FunctionsBundler.js +165 -0
- package/dist/Middletier/FunctionsBundler.js.map +1 -0
- package/dist/Middletier/PackFunctions.d.ts +52 -0
- package/dist/Middletier/PackFunctions.d.ts.map +1 -0
- package/dist/Middletier/PackFunctions.js +122 -0
- package/dist/Middletier/PackFunctions.js.map +1 -0
- package/dist/Types/Cli.types.d.ts +42 -1
- package/dist/Types/Cli.types.d.ts.map +1 -1
- package/dist/Types/Command.types.d.ts +1 -1
- package/dist/Types/Command.types.d.ts.map +1 -1
- package/dist/Utils/ConsoleOutput.d.ts +6 -0
- package/dist/Utils/ConsoleOutput.d.ts.map +1 -1
- package/dist/Utils/ConsoleOutput.js +23 -12
- package/dist/Utils/ConsoleOutput.js.map +1 -1
- package/dist/Utils/EnvVars.d.ts +1 -1
- package/dist/Utils/EnvVars.d.ts.map +1 -1
- package/dist/Utils/EnvVars.js.map +1 -1
- package/dist/Utils/EnvironmentRoutingUtils.d.ts +8 -0
- package/dist/Utils/EnvironmentRoutingUtils.d.ts.map +1 -0
- package/dist/Utils/EnvironmentRoutingUtils.js +45 -0
- package/dist/Utils/EnvironmentRoutingUtils.js.map +1 -0
- package/dist/Utils/GitHubDcfFlow.d.ts +59 -0
- package/dist/Utils/GitHubDcfFlow.d.ts.map +1 -0
- package/dist/Utils/GitHubDcfFlow.js +165 -0
- package/dist/Utils/GitHubDcfFlow.js.map +1 -0
- package/dist/Utils/GitUtils.d.ts +5 -0
- package/dist/Utils/GitUtils.d.ts.map +1 -1
- package/dist/Utils/GitUtils.js +15 -0
- package/dist/Utils/GitUtils.js.map +1 -1
- package/dist/Utils/Paging.d.ts.map +1 -1
- package/dist/Utils/Paging.js +4 -4
- package/dist/Utils/Paging.js.map +1 -1
- package/dist/Utils/RepoUrl.d.ts +13 -0
- package/dist/Utils/RepoUrl.d.ts.map +1 -0
- package/dist/Utils/RepoUrl.js +6 -0
- package/dist/Utils/RepoUrl.js.map +1 -0
- package/dist/Utils/Spinner.d.ts +9 -1
- package/dist/Utils/Spinner.d.ts.map +1 -1
- package/dist/Utils/Spinner.js +25 -5
- package/dist/Utils/Spinner.js.map +1 -1
- package/dist/Verbs/AddAction.d.ts.map +1 -1
- package/dist/Verbs/AddAction.js +12 -41
- package/dist/Verbs/AddAction.js.map +1 -1
- package/dist/Verbs/AddConnector.d.ts +24 -0
- package/dist/Verbs/AddConnector.d.ts.map +1 -0
- package/dist/Verbs/AddConnector.js +156 -0
- package/dist/Verbs/AddConnector.js.map +1 -0
- package/dist/Verbs/AddConnectorFlows.d.ts +72 -0
- package/dist/Verbs/AddConnectorFlows.d.ts.map +1 -0
- package/dist/Verbs/AddConnectorFlows.js +198 -0
- package/dist/Verbs/AddConnectorFlows.js.map +1 -0
- package/dist/Verbs/AddDataSource.js +1 -1
- package/dist/Verbs/AddDataSource.js.map +1 -1
- package/dist/Verbs/AddFlow.d.ts.map +1 -1
- package/dist/Verbs/AddFlow.js +3 -2
- package/dist/Verbs/AddFlow.js.map +1 -1
- package/dist/Verbs/AddTable.d.ts.map +1 -1
- package/dist/Verbs/AddTable.js +15 -100
- package/dist/Verbs/AddTable.js.map +1 -1
- package/dist/Verbs/AuthStatus.d.ts.map +1 -1
- package/dist/Verbs/AuthStatus.js +34 -6
- package/dist/Verbs/AuthStatus.js.map +1 -1
- package/dist/Verbs/AuthSwitch.d.ts +6 -0
- package/dist/Verbs/AuthSwitch.d.ts.map +1 -0
- package/dist/Verbs/AuthSwitch.js +67 -0
- package/dist/Verbs/AuthSwitch.js.map +1 -0
- package/dist/Verbs/ConnectorHelpers.d.ts +54 -1
- package/dist/Verbs/ConnectorHelpers.d.ts.map +1 -1
- package/dist/Verbs/ConnectorHelpers.js +217 -16
- package/dist/Verbs/ConnectorHelpers.js.map +1 -1
- package/dist/Verbs/CreateMaafApp.d.ts +26 -1
- package/dist/Verbs/CreateMaafApp.d.ts.map +1 -1
- package/dist/Verbs/CreateMaafApp.js +310 -135
- package/dist/Verbs/CreateMaafApp.js.map +1 -1
- package/dist/Verbs/DeployMaafApp.d.ts.map +1 -1
- package/dist/Verbs/DeployMaafApp.js +4 -0
- package/dist/Verbs/DeployMaafApp.js.map +1 -1
- package/dist/Verbs/Dev.js +5 -5
- package/dist/Verbs/Dev.js.map +1 -1
- package/dist/Verbs/FindDataverseApi.js +15 -15
- package/dist/Verbs/FindDataverseApi.js.map +1 -1
- package/dist/Verbs/GetSettings.d.ts +1 -1
- package/dist/Verbs/GetSettings.js +1 -1
- package/dist/Verbs/Init.d.ts.map +1 -1
- package/dist/Verbs/Init.js +129 -61
- package/dist/Verbs/Init.js.map +1 -1
- package/dist/Verbs/ListConnectors.d.ts.map +1 -1
- package/dist/Verbs/ListConnectors.js +4 -2
- package/dist/Verbs/ListConnectors.js.map +1 -1
- package/dist/Verbs/ListDatasets.d.ts.map +1 -1
- package/dist/Verbs/ListDatasets.js +5 -0
- package/dist/Verbs/ListDatasets.js.map +1 -1
- package/dist/Verbs/ListSqlStoredProcedures.d.ts.map +1 -1
- package/dist/Verbs/ListSqlStoredProcedures.js +5 -0
- package/dist/Verbs/ListSqlStoredProcedures.js.map +1 -1
- package/dist/Verbs/ListTables.d.ts.map +1 -1
- package/dist/Verbs/ListTables.js +5 -0
- package/dist/Verbs/ListTables.js.map +1 -1
- package/dist/Verbs/Login.d.ts.map +1 -1
- package/dist/Verbs/Login.js +16 -13
- package/dist/Verbs/Login.js.map +1 -1
- package/dist/Verbs/Logout.d.ts.map +1 -1
- package/dist/Verbs/Logout.js +19 -13
- package/dist/Verbs/Logout.js.map +1 -1
- package/dist/Verbs/MaafAppPermissions.d.ts +26 -6
- package/dist/Verbs/MaafAppPermissions.d.ts.map +1 -1
- package/dist/Verbs/MaafAppPermissions.js +193 -28
- package/dist/Verbs/MaafAppPermissions.js.map +1 -1
- package/dist/Verbs/Pack.d.ts +6 -6
- package/dist/Verbs/Pack.d.ts.map +1 -1
- package/dist/Verbs/Pack.js +80 -12
- package/dist/Verbs/Pack.js.map +1 -1
- package/dist/Verbs/RefreshDataSource.d.ts.map +1 -1
- package/dist/Verbs/RefreshDataSource.js +4 -3
- package/dist/Verbs/RefreshDataSource.js.map +1 -1
- package/dist/Verbs/RefreshGitAuth.d.ts +6 -0
- package/dist/Verbs/RefreshGitAuth.d.ts.map +1 -0
- package/dist/Verbs/RefreshGitAuth.js +153 -0
- package/dist/Verbs/RefreshGitAuth.js.map +1 -0
- package/dist/Verbs/RemoveFlow.d.ts.map +1 -1
- package/dist/Verbs/RemoveFlow.js +4 -3
- package/dist/Verbs/RemoveFlow.js.map +1 -1
- package/dist/Verbs/SetSetting.d.ts +1 -1
- package/dist/Verbs/SetSetting.js +1 -1
- package/dist/Verbs/VerbConstants.d.ts +72 -16
- package/dist/Verbs/VerbConstants.d.ts.map +1 -1
- package/dist/Verbs/VerbConstants.js +64 -16
- package/dist/Verbs/VerbConstants.js.map +1 -1
- package/dist/Verbs/index.d.ts +3 -0
- package/dist/Verbs/index.d.ts.map +1 -1
- package/dist/Verbs/index.js +3 -0
- package/dist/Verbs/index.js.map +1 -1
- package/package.json +8 -8
- package/dist/Authentication/OrchardAuthenticationProvider.d.ts +0 -13
- package/dist/Authentication/OrchardAuthenticationProvider.d.ts.map +0 -1
- package/dist/Authentication/OrchardAuthenticationProvider.js +0 -30
- package/dist/Authentication/OrchardAuthenticationProvider.js.map +0 -1
- package/dist/HttpClient/OrchardProxy.d.ts +0 -11
- package/dist/HttpClient/OrchardProxy.d.ts.map +0 -1
- package/dist/HttpClient/OrchardProxy.js +0 -25
- package/dist/HttpClient/OrchardProxy.js.map +0 -1
- package/dist/HttpClient/Proxy.d.ts +0 -7
- package/dist/HttpClient/Proxy.d.ts.map +0 -1
- package/dist/HttpClient/Proxy.js +0 -5
- package/dist/HttpClient/Proxy.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Copyright (C) Microsoft Corporation. All rights reserved.
|
|
3
3
|
*/
|
|
4
|
-
import { createAsync, getPlayerServiceConfig, updateEnvironmentName, writeRepoConfig, } from '@microsoft/managed-apps-actions';
|
|
4
|
+
import { authenticateForRepoAsync, createAsync, getPlayerServiceConfig, GrsServerError, updateEnvironmentName, writeRepoConfig, } from '@microsoft/managed-apps-actions';
|
|
5
5
|
import { AppConfigFileName } from '@microsoft/managed-apps-common/config';
|
|
6
|
-
import { getUserRoutingEnvironmentAsync
|
|
6
|
+
import { getUserRoutingEnvironmentAsync } from '@microsoft/managed-apps-common/services';
|
|
7
7
|
import { execFileSync } from 'child_process';
|
|
8
8
|
import * as fs from 'fs';
|
|
9
9
|
import { downloadTemplate } from 'giget';
|
|
@@ -13,9 +13,13 @@ import { createDefaultStringOption } from '../CliUtils.js';
|
|
|
13
13
|
import { CLI_CLIENT_ID } from '../Constants.js';
|
|
14
14
|
import { CLI_BINARY_NAME } from '../Constants/CliConstants.js';
|
|
15
15
|
import { HelpStrings } from '../Constants/HelpStrings.js';
|
|
16
|
-
import { AppError, ConfigurationError,
|
|
17
|
-
import {
|
|
16
|
+
import { AppError, ConfigurationError, UsageError } from '../Errors/CliError.js';
|
|
17
|
+
import { mapGitHubServerErrorToCliError, matchGitHubAuthError } from '../Errors/GitHubErrorMap.js';
|
|
18
|
+
import { printInfo, printJsonLine, printJsonSuccess, printSuccess, printWarning, } from '../Utils/ConsoleOutput.js';
|
|
19
|
+
import { resolveRoutingEnvironmentIdAsync } from '../Utils/EnvironmentRoutingUtils.js';
|
|
18
20
|
import { buildGcmConfig } from '../Utils/GitCredentialConfig.js';
|
|
21
|
+
import { ConsoleGitHubDcfDisplay, JsonGitHubDcfDisplay } from '../Utils/GitHubDcfFlow.js';
|
|
22
|
+
import { computeRepoHash, parseGitHubRepoUrl } from '../Utils/RepoUrl.js';
|
|
19
23
|
import { CreateMaafAppArguments } from './VerbConstants.js';
|
|
20
24
|
const DEFAULT_TEMPLATE = 'github:microsoft/Managed-Apps/templates/vite8';
|
|
21
25
|
/**
|
|
@@ -32,6 +36,10 @@ const REPO_NONE_SENTINEL = 'none';
|
|
|
32
36
|
* - `none` (case-insensitive) → `none` (no GRS, no local setup)
|
|
33
37
|
* - any other non-empty value → `github` (external GHE binding, value flows through as
|
|
34
38
|
* `remoteUrl` to the action and the eventual git clone)
|
|
39
|
+
*
|
|
40
|
+
* Runtime invariant: `remoteUrl` is set iff `repoType === 'github'`. Consumers
|
|
41
|
+
* branch on `repoType` and assert `remoteUrl!` at github use sites — see
|
|
42
|
+
* `RepoSelection` for why narrowing is not automatic.
|
|
35
43
|
*/
|
|
36
44
|
export function parseRepoOption(rawRepoValue) {
|
|
37
45
|
if (rawRepoValue === undefined || rawRepoValue === '') {
|
|
@@ -42,6 +50,17 @@ export function parseRepoOption(rawRepoValue) {
|
|
|
42
50
|
}
|
|
43
51
|
return { repoType: 'github', remoteUrl: rawRepoValue };
|
|
44
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Creates a new MAAF app and (where applicable) sets up local source control.
|
|
55
|
+
*
|
|
56
|
+
* Three repo flows, selected by `--repo`:
|
|
57
|
+
* - `native` (default): server auto-provisions a GRS repo; local clone happens via GCM.
|
|
58
|
+
* - `github`: external GHE Cloud binding. Clones the user's repo locally. On the first
|
|
59
|
+
* `createAsync` call, a missing/expired server-side GitHub identity mapping is
|
|
60
|
+
* recoverable in-band: a single inline DCF run + exactly one `createAsync` retry.
|
|
61
|
+
* Any other error — or a second mapping failure after DCF — is a hard fail.
|
|
62
|
+
* - `none`: no git binding at all (just the server record + template + ms.config.json).
|
|
63
|
+
*/
|
|
45
64
|
export async function createMaafAppAsync(argumentProvider) {
|
|
46
65
|
createOptionSchema(argumentProvider);
|
|
47
66
|
await argumentProvider.runVerb();
|
|
@@ -60,13 +79,9 @@ export async function createMaafAppAsync(argumentProvider) {
|
|
|
60
79
|
const appDir = argumentProvider.getPositionalArg(0) ?? process.cwd();
|
|
61
80
|
const template = await argumentProvider.getOption('template', /* ignorePrompt */ true);
|
|
62
81
|
// CLI surface is --repo. Three flows, decided up front so the rest of the verb can
|
|
63
|
-
// branch on `repoType` instead of inspecting `remoteUrl` everywhere
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
// - any other value → github (external GHE binding; clone the URL locally)
|
|
67
|
-
// The local variable name `remoteUrl` is preserved on purpose: the wire contract to
|
|
68
|
-
// RP and the apps-actions param are still `remoteUrl` / `externalRepo.remoteUrl`, so
|
|
69
|
-
// renaming end-to-end is deferred until those callers move.
|
|
82
|
+
// branch on `repoType` instead of inspecting `remoteUrl` everywhere. RepoSelection
|
|
83
|
+
// is a flat interface (not a discriminated union), so we branch on `repoType` and
|
|
84
|
+
// assert `remoteUrl!` at github use sites where `string` is required.
|
|
70
85
|
const rawRepoValue = await argumentProvider.getOption('repo',
|
|
71
86
|
/* ignorePrompt */ true);
|
|
72
87
|
const { repoType, remoteUrl } = parseRepoOption(rawRepoValue);
|
|
@@ -97,20 +112,16 @@ export async function createMaafAppAsync(argumentProvider) {
|
|
|
97
112
|
// local-setup failure leaves them orphaned with no clean recovery path.
|
|
98
113
|
// Anything we can validate without hitting the server belongs here.
|
|
99
114
|
//
|
|
100
|
-
// --repo path:
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
// giget call validates the source. To bind a non-empty directory to a
|
|
105
|
-
// MAAF app, use `ms app init` instead.
|
|
115
|
+
// --repo path: requires git installed, writable target, and an empty target
|
|
116
|
+
// (since `git clone` refuses non-empty destinations and we don't destructively
|
|
117
|
+
// wipe local files). To bind a non-empty directory to a MAAF app, use `ms app
|
|
118
|
+
// init` instead.
|
|
106
119
|
//
|
|
107
|
-
// --repo none path: no git, no clone
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
// required: the user opted out of scaffolding, so dropping an
|
|
113
|
-
// ms.config.json next to existing files is the intent.
|
|
120
|
+
// --repo none path: no git, no clone — ms.config.json and the template are
|
|
121
|
+
// written locally. The preflight reduces to (1) target dir must be writable
|
|
122
|
+
// so the config and template writes won't fail post-create, and (2) the dir
|
|
123
|
+
// must be empty (template scaffolding requires a clean target, same as the
|
|
124
|
+
// other flows).
|
|
114
125
|
// ──────────────────────────────────────────────────────────────────────────
|
|
115
126
|
if (!jsonMode) {
|
|
116
127
|
printInfo('Running preflight checks...');
|
|
@@ -122,30 +133,23 @@ export async function createMaafAppAsync(argumentProvider) {
|
|
|
122
133
|
throw new UsageError("'--repo none' is incompatible with '--repository-id'. " +
|
|
123
134
|
"Use '--repo none' for an app with no git binding, or omit '--repo' (or pass a repo URL) to use a backing repository.");
|
|
124
135
|
}
|
|
125
|
-
|
|
126
|
-
// silently dropped. Reject up front rather than appear to honor it.
|
|
127
|
-
if (repoType === 'none' && template !== DEFAULT_TEMPLATE) {
|
|
128
|
-
throw new UsageError("'--template' is not supported with '--repo none' because no files are scaffolded. " +
|
|
129
|
-
"Remove '--template' or drop '--repo none' if you want template scaffolding.");
|
|
130
|
-
}
|
|
136
|
+
ensureTemplateSourceValid(template);
|
|
131
137
|
if (repoType !== 'none') {
|
|
132
138
|
ensureGitInstalled();
|
|
133
139
|
}
|
|
134
|
-
if (repoType === 'native') {
|
|
135
|
-
ensureTemplateSourceValid(template);
|
|
136
|
-
}
|
|
137
140
|
ensureTargetDirectoryWritable(appDir);
|
|
138
141
|
if (repoType === 'github') {
|
|
142
|
+
// RepoSelection is a flat interface (not a discriminated union), so `remoteUrl`
|
|
143
|
+
// doesn't auto-narrow to `string` here even though the github branch guarantees it.
|
|
139
144
|
ensureRepoTargetDirectoryEmpty(appDir);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
145
|
+
// Validate --repo as a *.ghe.com URL before any network call. Throws
|
|
146
|
+
// UsageError ("not a valid GitHub Enterprise Cloud URL") for
|
|
147
|
+
// `github.com/...` and other non-GHE hosts, malformed URIs, etc. — mirrors
|
|
148
|
+
// `git auth refresh`'s up-front check.
|
|
149
|
+
parseGitHubRepoUrl(remoteUrl);
|
|
143
150
|
}
|
|
144
151
|
else {
|
|
145
|
-
|
|
146
|
-
// overwriting an existing ms.config.json so the user can't silently rebind a
|
|
147
|
-
// pre-existing app folder to a brand-new server app.
|
|
148
|
-
ensureNoExistingConfig(appDir);
|
|
152
|
+
ensureTargetDirectoryEmpty(appDir);
|
|
149
153
|
}
|
|
150
154
|
// ─── End preflight ────────────────────────────────────────────────────────
|
|
151
155
|
// The debug env-var override (MS_CLI_MAAF_DEBUG_ENVIRONMENT_ID) is honored by ArgumentProvider
|
|
@@ -170,6 +174,8 @@ export async function createMaafAppAsync(argumentProvider) {
|
|
|
170
174
|
const buildPath = await argumentProvider.getOption('buildPath', /* ignorePrompt */ true);
|
|
171
175
|
const buildCommand = await argumentProvider.getOption('buildCommand',
|
|
172
176
|
/* ignorePrompt */ true);
|
|
177
|
+
const buildEntryPoint = await argumentProvider.getOption('buildEntryPoint',
|
|
178
|
+
/* ignorePrompt */ true);
|
|
173
179
|
// Explicit branch keeps the non-null read of routingEnvPromise reachable only when
|
|
174
180
|
// preResolvedEnvironmentId is undefined — i.e. exactly when routingEnvPromise is defined.
|
|
175
181
|
const environmentId = preResolvedEnvironmentId !== undefined
|
|
@@ -186,33 +192,118 @@ export async function createMaafAppAsync(argumentProvider) {
|
|
|
186
192
|
if (repoType === 'github') {
|
|
187
193
|
ensureRepoTargetDirectoryEmpty(appDir);
|
|
188
194
|
}
|
|
189
|
-
else if (repoType === 'native') {
|
|
190
|
-
ensureTargetDirectoryEmpty(appDir);
|
|
191
|
-
}
|
|
192
195
|
else {
|
|
193
|
-
|
|
196
|
+
ensureTargetDirectoryEmpty(appDir);
|
|
194
197
|
}
|
|
195
|
-
|
|
198
|
+
// Read --no-browser alongside --json so the recovery DCF helper has both
|
|
199
|
+
// inputs ready without a second async option read inside the catch block.
|
|
200
|
+
// Commander converts kebab-case flag names to camelCase property keys;
|
|
201
|
+
// the camelName constant keeps this lookup in sync with NoBrowser.name.
|
|
202
|
+
const noBrowser = (await argumentProvider.getOption(CreateMaafAppArguments.NoBrowser.camelName,
|
|
203
|
+
/* ignorePrompt */ true)) ?? false;
|
|
204
|
+
// JSON mode (github flow only): emit a structured `create-validation` event
|
|
205
|
+
// right before the server call so automation parsing NDJSON sees the
|
|
206
|
+
// validation→createAsync boundary — needed because the github flow has a
|
|
207
|
+
// catch-and-retry branch where validation precedes a recoverable DCF.
|
|
208
|
+
// Gated to `github` so we don't change the NDJSON wire contract for
|
|
209
|
+
// existing `native` / `none` `--json` consumers.
|
|
210
|
+
if (jsonMode && repoType === 'github') {
|
|
211
|
+
printJsonLine({ phase: 'create-validation' });
|
|
212
|
+
}
|
|
213
|
+
// Hoisted so the first attempt and the post-DCF retry share the exact same
|
|
214
|
+
// action payload — no risk of the two calls drifting apart and no per-call
|
|
215
|
+
// object rebuild.
|
|
216
|
+
const actionsParams = {
|
|
217
|
+
displayName,
|
|
218
|
+
description,
|
|
219
|
+
repositoryId,
|
|
220
|
+
remoteUrl,
|
|
221
|
+
repoType,
|
|
222
|
+
};
|
|
223
|
+
const runCreate = () => createAsync({
|
|
196
224
|
tenantId,
|
|
197
225
|
environmentId,
|
|
198
226
|
logger,
|
|
199
|
-
actionsParams
|
|
227
|
+
actionsParams,
|
|
200
228
|
});
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
229
|
+
// Inline catch-and-retry for recoverable GitHub auth errors. On the github
|
|
230
|
+
// flow, a missing/expired GitHub identity mapping is recoverable in-band by
|
|
231
|
+
// running the DCF wrapper inline against
|
|
232
|
+
// the same GRS environment, then retrying createAsync exactly once. Any
|
|
233
|
+
// other recognized GrsServerError — on either the first attempt or the
|
|
234
|
+
// post-DCF retry — is mapped via mapGitHubServerErrorToCliError before
|
|
235
|
+
// being rethrown so the user sees a friendly CLI-typed error rather than
|
|
236
|
+
// the raw server payload. Any second mapping-missing/expired after DCF —
|
|
237
|
+
// and anything not recognized at all — escapes as a hard failure (single-retry
|
|
238
|
+
// contract; we never loop).
|
|
239
|
+
let createResult;
|
|
240
|
+
try {
|
|
241
|
+
createResult = await runCreate();
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
if (repoType !== 'github')
|
|
245
|
+
throw err;
|
|
246
|
+
const matched = matchGitHubAuthError(err);
|
|
247
|
+
if (!matched) {
|
|
248
|
+
if (err instanceof GrsServerError) {
|
|
249
|
+
const mapped = mapGitHubServerErrorToCliError({
|
|
250
|
+
code: err.code,
|
|
251
|
+
message: err.message,
|
|
252
|
+
status: err.status,
|
|
253
|
+
details: err.details,
|
|
254
|
+
}, { repoUrl: remoteUrl, verb: 'app create' });
|
|
255
|
+
if (mapped)
|
|
256
|
+
throw mapped;
|
|
257
|
+
}
|
|
258
|
+
throw err;
|
|
259
|
+
}
|
|
260
|
+
await runDcfRecoveryAsync({
|
|
261
|
+
remoteUrl: remoteUrl,
|
|
262
|
+
tenantId,
|
|
263
|
+
jsonMode,
|
|
264
|
+
noBrowser,
|
|
265
|
+
verb: 'app create',
|
|
266
|
+
});
|
|
267
|
+
try {
|
|
268
|
+
createResult = await runCreate();
|
|
215
269
|
}
|
|
270
|
+
catch (retryErr) {
|
|
271
|
+
const remapped = matchGitHubAuthError(retryErr);
|
|
272
|
+
if (remapped) {
|
|
273
|
+
// Single-retry contract: a second mapping-missing/expired surfaces
|
|
274
|
+
// as a hard AuthenticationError with the standard remediation
|
|
275
|
+
// pointer. We deliberately do NOT loop DCF — repeated failures
|
|
276
|
+
// suggest the user can't complete the device-code flow (denied,
|
|
277
|
+
// wrong account, app uninstalled, etc.) and another loop would
|
|
278
|
+
// just hang.
|
|
279
|
+
const mapped = mapGitHubServerErrorToCliError(remapped.payload, {
|
|
280
|
+
repoUrl: remoteUrl,
|
|
281
|
+
verb: 'app create',
|
|
282
|
+
});
|
|
283
|
+
throw mapped ?? retryErr;
|
|
284
|
+
}
|
|
285
|
+
if (retryErr instanceof GrsServerError) {
|
|
286
|
+
const mapped = mapGitHubServerErrorToCliError({
|
|
287
|
+
code: retryErr.code,
|
|
288
|
+
message: retryErr.message,
|
|
289
|
+
status: retryErr.status,
|
|
290
|
+
details: retryErr.details,
|
|
291
|
+
}, { repoUrl: remoteUrl, verb: 'app create' });
|
|
292
|
+
if (mapped)
|
|
293
|
+
throw mapped;
|
|
294
|
+
}
|
|
295
|
+
throw retryErr;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const { app, cloneUrl } = createResult;
|
|
299
|
+
// Only the `native` flow expects a GRS clone URL — it's the origin for the first
|
|
300
|
+
// local push to the auto-provisioned platform-managed repo. `github` binds an
|
|
301
|
+
// external GHE repo (no GRS) and `none` is by-design source-control-free, so neither
|
|
302
|
+
// produces a `cloneUrl`. Missing on `native` is a server bug — the hoisted check
|
|
303
|
+
// below guards both the pretty-output `(clone URL: undefined)` and JSON-envelope
|
|
304
|
+
// `gitRemoteUrl: undefined` failure modes that would otherwise leak through.
|
|
305
|
+
if (repoType === 'native' && !cloneUrl) {
|
|
306
|
+
const recoveryHint = buildOrphanedAppRecoveryHint(app.id, app.environmentId);
|
|
216
307
|
throw new AppError(`App '${app.displayName}' was created on the server, but creating a git repository failed. ` +
|
|
217
308
|
`This is a platform-side issue; please report it. ` +
|
|
218
309
|
`In the meantime, the partial app needs to be cleaned up.\n` +
|
|
@@ -225,7 +316,7 @@ export async function createMaafAppAsync(argumentProvider) {
|
|
|
225
316
|
// then overlay the template, then write ms.config.json.
|
|
226
317
|
// - github: clone the user's external repo, sanity-check it's empty,
|
|
227
318
|
// overlay the template, then write ms.config.json.
|
|
228
|
-
// - none: no git, no
|
|
319
|
+
// - none: no git, no clone — mkdir -p, overlay the template, write ms.config.json.
|
|
229
320
|
try {
|
|
230
321
|
if (repoType === 'github') {
|
|
231
322
|
// External GitHub Enterprise path: clone the developer's repo. Auth flows through
|
|
@@ -253,35 +344,30 @@ export async function createMaafAppAsync(argumentProvider) {
|
|
|
253
344
|
});
|
|
254
345
|
}
|
|
255
346
|
else {
|
|
256
|
-
// --repo none:
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
// empty dir). `mkdirSync(..., { recursive: true })` is a no-op if the
|
|
260
|
-
// directory already exists.
|
|
347
|
+
// --repo none: no git setup. Ensure the target dir exists so the
|
|
348
|
+
// subsequent downloadTemplate and writeRepoConfig calls can land their
|
|
349
|
+
// files. The preflight already verified the dir is empty.
|
|
261
350
|
fs.mkdirSync(appDir, { recursive: true });
|
|
262
351
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
// (if any) are left alone.
|
|
266
|
-
if (repoType !== 'none') {
|
|
267
|
-
if (!jsonMode) {
|
|
268
|
-
printInfo(`Fetching template '${template}' into ${appDir}...`);
|
|
269
|
-
}
|
|
270
|
-
await downloadTemplate(template, { dir: appDir, force: true });
|
|
352
|
+
if (!jsonMode) {
|
|
353
|
+
printInfo(`Fetching template '${template}' into ${appDir}...`);
|
|
271
354
|
}
|
|
355
|
+
await downloadTemplate(template, { dir: appDir, force: true });
|
|
272
356
|
const config = {
|
|
273
357
|
appId: app.id,
|
|
274
358
|
appDisplayName: app.displayName,
|
|
275
359
|
description: app.description,
|
|
276
360
|
environmentId: app.environmentId,
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
|
|
361
|
+
// Only the `native` flow has a platform-managed git binding. `github` tracks
|
|
362
|
+
// external binding server-side via `externalRepo`, and `none` intentionally has
|
|
363
|
+
// no platform-managed binding. Omit `repositoryId` for both so downstream verbs
|
|
364
|
+
// key off `repoType` instead of a placeholder value.
|
|
365
|
+
...(repoType === 'native' && { repositoryId: app.repositoryId }),
|
|
281
366
|
repoType,
|
|
282
367
|
cloud: argumentProvider.getCloud(),
|
|
283
368
|
buildPath: buildPath ?? './dist',
|
|
284
369
|
buildCommand: buildCommand ?? 'npm run build',
|
|
370
|
+
buildEntryPoint: buildEntryPoint ?? 'index.html',
|
|
285
371
|
};
|
|
286
372
|
await writeRepoConfig(path.join(appDir, AppConfigFileName), config);
|
|
287
373
|
}
|
|
@@ -297,23 +383,23 @@ export async function createMaafAppAsync(argumentProvider) {
|
|
|
297
383
|
if (jsonMode) {
|
|
298
384
|
// `appId` is the bare GUID returned by the server (`MaafAppDefinition.id`) and
|
|
299
385
|
// also written to ms.config.json — used by every subsequent CLI command
|
|
300
|
-
// (build, deploy, info, etc.). `gitRemoteUrl` is the GRS clone URL
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
//
|
|
386
|
+
// (build, deploy, info, etc.). `gitRemoteUrl` is the GRS clone URL and is only
|
|
387
|
+
// present for the `native` flow (the only flow that auto-provisions a
|
|
388
|
+
// platform-managed git repo). `externalRepoUrl` is the user-supplied GHE URL and
|
|
389
|
+
// only appears in the `github` flow. `repoType` is always emitted so automation
|
|
390
|
+
// can detect which source-control mode the app was created in.
|
|
305
391
|
printJsonSuccess({
|
|
306
392
|
appId: app.id,
|
|
307
393
|
repoType,
|
|
308
394
|
...(repoType === 'github' && remoteUrl && { externalRepoUrl: remoteUrl }),
|
|
309
|
-
...(repoType
|
|
395
|
+
...(repoType === 'native' && cloneUrl && { gitRemoteUrl: cloneUrl }),
|
|
310
396
|
appDir,
|
|
311
397
|
});
|
|
312
398
|
}
|
|
313
399
|
else {
|
|
314
400
|
printSuccess(`Created app '${app.displayName}' in ${appDir}.`);
|
|
315
401
|
if (repoType === 'github') {
|
|
316
|
-
printInfo(`
|
|
402
|
+
printInfo(`Bound to external repository: ${remoteUrl}.`);
|
|
317
403
|
}
|
|
318
404
|
else if (repoType === 'none') {
|
|
319
405
|
printInfo('Your app has been created. Run `git init` (or your VCS of choice) when ready; ' +
|
|
@@ -321,43 +407,6 @@ export async function createMaafAppAsync(argumentProvider) {
|
|
|
321
407
|
}
|
|
322
408
|
}
|
|
323
409
|
}
|
|
324
|
-
async function resolveRoutingEnvironmentIdAsync(resultPromise, httpClient, logger) {
|
|
325
|
-
// Translate routing-service errors into a UsageError so the user sees an actionable message
|
|
326
|
-
// rather than the raw "ManagedGovernance request failed with status 403" implementation detail.
|
|
327
|
-
// NotFoundError throws inside the try also flow through `toRoutingUsageError`, which leaves
|
|
328
|
-
// non-ManagedGovernance errors unchanged.
|
|
329
|
-
try {
|
|
330
|
-
const result = await resultPromise;
|
|
331
|
-
if (result.status === 200) {
|
|
332
|
-
const name = result.data.environment?.name;
|
|
333
|
-
if (!name) {
|
|
334
|
-
throw new NotFoundError('Routing service returned 200 with no environment name.');
|
|
335
|
-
}
|
|
336
|
-
return name;
|
|
337
|
-
}
|
|
338
|
-
// 202: provisioning is in progress — poll until it completes.
|
|
339
|
-
// Non-2xx responses are already thrown as ManagedGovernanceError inside
|
|
340
|
-
// getUserRoutingEnvironmentAsync, so only 200/202 reach this code path.
|
|
341
|
-
const routingResponse = await pollRoutingEnvironmentAsync(httpClient, result.pollingUrl, result.authResource, logger);
|
|
342
|
-
if (!routingResponse.environment?.name) {
|
|
343
|
-
throw new NotFoundError('Routing service finished provisioning but returned no environment name.');
|
|
344
|
-
}
|
|
345
|
-
return routingResponse.environment.name;
|
|
346
|
-
}
|
|
347
|
-
catch (err) {
|
|
348
|
-
throw toRoutingUsageError(err);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
function toRoutingUsageError(err) {
|
|
352
|
-
if (err instanceof ManagedGovernanceError) {
|
|
353
|
-
return new UsageError(`Could not provision a Developer environment for your tenant (status ${err.status}). ` +
|
|
354
|
-
'Ensure your account has the required permissions to create a Developer environment.');
|
|
355
|
-
}
|
|
356
|
-
if (err instanceof ManagedGovernanceTimeoutError) {
|
|
357
|
-
return new UsageError('Timed out waiting for a Developer environment to provision. Try again.');
|
|
358
|
-
}
|
|
359
|
-
return err instanceof Error ? err : new Error(String(err));
|
|
360
|
-
}
|
|
361
410
|
/**
|
|
362
411
|
* Clones the developer's external repo (GitHub Enterprise Cloud in v1) into `directory`.
|
|
363
412
|
* Auth flows through the user's existing git credential setup — the CLI does not inject
|
|
@@ -590,19 +639,6 @@ export function ensureRepoTargetDirectoryEmpty(appDir) {
|
|
|
590
639
|
throw new UsageError(`'${appDir}' is not empty. --repo requires an empty target directory; specify an empty directory as the first argument or move to one before running.`);
|
|
591
640
|
}
|
|
592
641
|
}
|
|
593
|
-
export function ensureNoExistingConfig(appDir) {
|
|
594
|
-
// --repo none variant: empty-dir is not required, but we MUST refuse to overwrite an
|
|
595
|
-
// existing ms.config.json. Silently replacing it would rebind the folder (and any
|
|
596
|
-
// subsequent `ms app push/build/deploy` invocations) to a different server app — a
|
|
597
|
-
// footgun loud enough to gate fail-fast in preflight. Called twice (preflight +
|
|
598
|
-
// just-before-createAsync) for the same TOCTOU reasons as ensureTargetDirectoryEmpty.
|
|
599
|
-
const configPath = path.join(appDir, AppConfigFileName);
|
|
600
|
-
if (fs.existsSync(configPath)) {
|
|
601
|
-
throw new UsageError(`'${configPath}' already exists. --repo none refuses to overwrite an existing app config; ` +
|
|
602
|
-
`remove the file (or choose a different directory) before retrying, or run 'ms app init' ` +
|
|
603
|
-
`to bind this directory to a new app interactively.`);
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
642
|
export function ensureTargetDirectoryWritable(appDir) {
|
|
607
643
|
// Probe write permission on the target dir (or its nearest existing
|
|
608
644
|
// ancestor, where mkdirSync will need to write). Catches read-only mounts
|
|
@@ -634,6 +670,131 @@ export function ensureTargetDirectoryWritable(appDir) {
|
|
|
634
670
|
throw new ConfigurationError(`'${appDir}' is not writable. Choose a different directory or fix the permissions and retry.`);
|
|
635
671
|
}
|
|
636
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Inline DCF recovery branch for the github catch-and-retry: only the
|
|
675
|
+
* `github` flow ever calls this — `native` and `none` have no GitHub identity
|
|
676
|
+
* mapping to refresh. SIGINT handling is scoped to this helper (registered
|
|
677
|
+
* and removed inside the `try/finally`) so Ctrl+C during the device-code
|
|
678
|
+
* polling loop doesn't leak a listener back to the verb's outer body. Server
|
|
679
|
+
* errors thrown by `authenticateForRepoAsync` are mapped through
|
|
680
|
+
* {@link mapGitHubServerErrorToCliError} before being rethrown so the verb's
|
|
681
|
+
* outer catch (and the single-retry contract) sees CLI-typed errors.
|
|
682
|
+
*/
|
|
683
|
+
async function runDcfRecoveryAsync(options) {
|
|
684
|
+
const { remoteUrl, tenantId, jsonMode, noBrowser, verb } = options;
|
|
685
|
+
// Re-parse here rather than threading the parsed components through every
|
|
686
|
+
// catch-and-retry call: preflight already validated the URL shape, so this
|
|
687
|
+
// is a cheap string-split on a rare path.
|
|
688
|
+
const { host, owner, repo } = parseGitHubRepoUrl(remoteUrl);
|
|
689
|
+
const repoHash = computeRepoHash(owner, repo);
|
|
690
|
+
const logger = getCliLogger();
|
|
691
|
+
// Telemetry: PII-safe — host is the parsed string, repoHash is a truncated
|
|
692
|
+
// SHA256. Emit Start at the top so a recovery that never reaches the retry
|
|
693
|
+
// (e.g. user denied auth) is still observable.
|
|
694
|
+
logger.trackActivityEvent('Maaf.Create.GitHubDcfRecovery', {
|
|
695
|
+
repoHost: host,
|
|
696
|
+
repoHash,
|
|
697
|
+
});
|
|
698
|
+
if (!jsonMode) {
|
|
699
|
+
printInfo('GitHub authentication is required to bind this repository.');
|
|
700
|
+
}
|
|
701
|
+
const display = composeRecoveryDisplay({ isJson: jsonMode, noBrowser });
|
|
702
|
+
// SIGINT plumbing: a Ctrl+C during the (potentially 15-minute) polling
|
|
703
|
+
// loop drops us out cleanly rather than leaving a dangling promise.
|
|
704
|
+
// Scoped to the recovery block only — createAsync itself doesn't take a
|
|
705
|
+
// signal yet.
|
|
706
|
+
const controller = new AbortController();
|
|
707
|
+
const onSigint = () => {
|
|
708
|
+
controller.abort();
|
|
709
|
+
};
|
|
710
|
+
process.once('SIGINT', onSigint);
|
|
711
|
+
try {
|
|
712
|
+
// The resolved auth result (githubLogin, mappingExpiresAt, etc.) is
|
|
713
|
+
// intentionally discarded: the retry path below doesn't need it — it
|
|
714
|
+
// just needs the server-side identity mapping to now exist so the next
|
|
715
|
+
// `createAsync` call clears the 401.
|
|
716
|
+
await authenticateForRepoAsync({
|
|
717
|
+
remoteUrl: `https://${host}/${owner}/${repo}`,
|
|
718
|
+
tenantId,
|
|
719
|
+
logger,
|
|
720
|
+
display,
|
|
721
|
+
// Browser launch is gated by the `display` object selected above:
|
|
722
|
+
// `composeRecoveryDisplay` returns a display whose `openVerificationUri`
|
|
723
|
+
// is undefined when `noBrowser` is true. `skipBrowser` here is the
|
|
724
|
+
// legacy lower-level kill-switch the action exposes; we hardcode it
|
|
725
|
+
// to false so the display contract is the single source of truth.
|
|
726
|
+
skipBrowser: false,
|
|
727
|
+
signal: controller.signal,
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
catch (error) {
|
|
731
|
+
// Telemetry: pair the Start event with a Failed event on every error path
|
|
732
|
+
// so a recovery that throws (DCF declined, server error, abort) still
|
|
733
|
+
// shows up as a closed pair in the activity stream rather than an
|
|
734
|
+
// orphaned Start. Pattern A (emit Failed in the catch) — chosen over a
|
|
735
|
+
// success-flag-in-finally to keep the existing throw flow untouched and
|
|
736
|
+
// avoid restructuring the GrsServerError mapping branch below.
|
|
737
|
+
logger.trackActivityEvent('Maaf.Create.GitHubDcfRecovery.Failed', {
|
|
738
|
+
repoHost: host,
|
|
739
|
+
repoHash,
|
|
740
|
+
});
|
|
741
|
+
// Only GrsServerError carries a structured `code` we can translate to a
|
|
742
|
+
// CLI-typed AppError. Anything else (plain Error, network error, etc.)
|
|
743
|
+
// propagates as-is — the verb's outer flow treats it as a hard failure
|
|
744
|
+
// (no retry, no second "Resuming create...").
|
|
745
|
+
if (error instanceof GrsServerError) {
|
|
746
|
+
const mapped = mapGitHubServerErrorToCliError({
|
|
747
|
+
code: error.code,
|
|
748
|
+
message: error.message,
|
|
749
|
+
status: error.status,
|
|
750
|
+
details: error.details,
|
|
751
|
+
}, { repoUrl: remoteUrl, verb });
|
|
752
|
+
if (mapped)
|
|
753
|
+
throw mapped;
|
|
754
|
+
}
|
|
755
|
+
throw error;
|
|
756
|
+
}
|
|
757
|
+
finally {
|
|
758
|
+
// Safe in both branches: if SIGINT already fired, `process.once` has
|
|
759
|
+
// already auto-removed the listener and `removeListener` is a no-op.
|
|
760
|
+
process.removeListener('SIGINT', onSigint);
|
|
761
|
+
}
|
|
762
|
+
logger.trackActivityEvent('Maaf.Create.GitHubDcfRecovery.Complete', {
|
|
763
|
+
repoHost: host,
|
|
764
|
+
repoHash,
|
|
765
|
+
});
|
|
766
|
+
if (!jsonMode) {
|
|
767
|
+
// Printed here (before the helper returns) rather than at the retry
|
|
768
|
+
// call site so it's adjacent to the DCF-completed telemetry event. If
|
|
769
|
+
// the subsequent createAsync retry hard-fails, the user sees
|
|
770
|
+
// "Resuming create..." followed by the failure message — still accurate:
|
|
771
|
+
// we DID resume; the resumed call is what failed.
|
|
772
|
+
printInfo('Resuming create...');
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Build the right {@link GitHubDcfDisplay} for the create recovery path:
|
|
777
|
+
* - JSON mode → NDJSON events, never opens a browser.
|
|
778
|
+
* - `--no-browser` → console output, browser launch suppressed.
|
|
779
|
+
* - Default → console output + best-effort browser launch (TTY-gated).
|
|
780
|
+
*
|
|
781
|
+
* Note the inverted default vs `git auth refresh`: in recovery the user has
|
|
782
|
+
* already started a destructive operation (create), so we lean toward
|
|
783
|
+
* launching a browser by default and require explicit opt-out, instead of
|
|
784
|
+
* the refresh verb's explicit opt-in.
|
|
785
|
+
*/
|
|
786
|
+
function composeRecoveryDisplay(opts) {
|
|
787
|
+
if (opts.isJson) {
|
|
788
|
+
return new JsonGitHubDcfDisplay();
|
|
789
|
+
}
|
|
790
|
+
if (opts.noBrowser) {
|
|
791
|
+
return {
|
|
792
|
+
...ConsoleGitHubDcfDisplay,
|
|
793
|
+
openVerificationUri: undefined,
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
return ConsoleGitHubDcfDisplay;
|
|
797
|
+
}
|
|
637
798
|
function createOptionSchema(argumentProvider) {
|
|
638
799
|
argumentProvider.setDescription(HelpStrings.app.create.description);
|
|
639
800
|
argumentProvider.addExamples(HelpStrings.app.create.examples);
|
|
@@ -707,6 +868,20 @@ function createOptionSchema(argumentProvider) {
|
|
|
707
868
|
default: 'npm run build',
|
|
708
869
|
description: HelpStrings.app.create.options.buildCommand,
|
|
709
870
|
}),
|
|
871
|
+
createDefaultStringOption({
|
|
872
|
+
flags: {
|
|
873
|
+
key: CreateMaafAppArguments.BuildEntryPoint.name,
|
|
874
|
+
},
|
|
875
|
+
env: CreateMaafAppArguments.BuildEntryPoint.envVar,
|
|
876
|
+
message: CreateMaafAppArguments.BuildEntryPoint.promptMessage,
|
|
877
|
+
initialValue: CreateMaafAppArguments.BuildEntryPoint.initialValue,
|
|
878
|
+
default: 'index.html',
|
|
879
|
+
description: HelpStrings.app.create.options.buildEntryPoint,
|
|
880
|
+
}),
|
|
710
881
|
]);
|
|
882
|
+
argumentProvider.addSwitch({
|
|
883
|
+
flags: { key: CreateMaafAppArguments.NoBrowser.name },
|
|
884
|
+
description: HelpStrings.app.create.options.noBrowser,
|
|
885
|
+
});
|
|
711
886
|
}
|
|
712
887
|
//# sourceMappingURL=CreateMaafApp.js.map
|