@microsoft/managed-apps-cli 0.19.0 → 0.21.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/LICENSE +17 -149
- package/THIRD-PARTY-NOTICES.txt +9549 -0
- package/dist/AddConnector-4AMM746J.js +41 -0
- package/dist/AuthStatus-ZZIP3LBD.js +11 -0
- package/dist/AuthSwitch-HK7JU2FR.js +13 -0
- package/dist/Bin.js +8 -3
- package/dist/BuildMaafApp-MOTZOLJZ.js +11 -0
- package/dist/Cli-6CCXMCPX.js +54 -0
- package/dist/CreateMaafApp-TUO72CW7.js +20 -0
- package/dist/DeleteMaafApp-MZVGIAX3.js +11 -0
- package/dist/DeployMaafApp-KXATM3E3.js +14 -0
- package/dist/Dev-SHIA5S7X.js +14 -0
- package/dist/EnvironmentVariableAuthenticationProvider-5YTMRAE4.js +11 -0
- package/dist/GetMaafApp-ELB5KMHW.js +11 -0
- package/dist/GetMaafBuildStatus-3W7LI5TJ.js +11 -0
- package/dist/GetSettings-NM6H2U5F.js +11 -0
- package/dist/Init-CH5DUQWA.js +11 -0
- package/dist/ListConnectorActions-7SIFGPYR.js +11 -0
- package/dist/ListConnectors-TRKIWRVQ.js +11 -0
- package/dist/ListMaafApps-RT3PGZSJ.js +11 -0
- package/dist/Login-HG5S7LBC.js +11 -0
- package/dist/Logout-BUPHLOAH.js +11 -0
- package/dist/MockFetch-4CYTSNJ7.js +13 -0
- package/dist/NoOpAuthenticationProvider-DX3XNXF5.js +11 -0
- package/dist/NodeMsalAuthenticationProvider-HTH3V3G2.js +17 -0
- package/dist/Pack-AHKC2MYF.js +8 -0
- package/dist/PlayMaafApp-LWKJU2IN.js +12 -0
- package/dist/RefreshDataSource-ZFZJXJ5L.js +11 -0
- package/dist/RefreshGitAuth-5A3SX2HC.js +11 -0
- package/dist/RemoveDataSource-57JJLK5I.js +14 -0
- package/dist/ServicePrincipalAuthenticationProvider-SVKDZG6X.js +11 -0
- package/dist/SetSetting-RB3F7IXG.js +11 -0
- package/dist/ShareLinkCreate-7BCDPWY6.js +11 -0
- package/dist/ShareLinkList-4BI3WMNN.js +11 -0
- package/dist/ShareLinkRevoke-EEJVCRCY.js +11 -0
- package/dist/ShareList-LJDAEGI3.js +11 -0
- package/dist/ShareMaafApp-QFRXLYUD.js +11 -0
- package/dist/ShowMaafApp-3KK6NUG2.js +11 -0
- package/dist/TelemetrySettings-A474HALH.js +11 -0
- package/dist/UnshareMaafApp-423RNXCN.js +11 -0
- package/dist/acorn-CYBWGE5M.js +23 -0
- package/dist/angular-Q62TJP23.js +11 -0
- package/dist/babel-AOXBHIIS.js +22 -0
- package/dist/chunk-3BRAT6NP.js +11 -0
- package/dist/chunk-3YRE4IQ3.js +132 -0
- package/dist/chunk-5AUOEXAR.js +50 -0
- package/dist/chunk-6FFQN2SO.js +13 -0
- package/dist/chunk-6MXOK2LG.js +11 -0
- package/dist/chunk-7NXJAIJX.js +11 -0
- package/dist/chunk-DREO7EYO.js +20 -0
- package/dist/chunk-EV3TTTOT.js +8 -0
- package/dist/chunk-G33Q5FWT.js +42325 -0
- package/dist/chunk-HBLO3WDD.js +13 -0
- package/dist/chunk-MFPX2RFH.js +11 -0
- package/dist/chunk-NP2KJOYC.js +12 -0
- package/dist/chunk-OL6CTXQR.js +11 -0
- package/dist/chunk-PVAIJSAI.js +11 -0
- package/dist/chunk-QAFCXGBD.js +11 -0
- package/dist/chunk-QSB5P4RM.js +38 -0
- package/dist/chunk-RBG2H562.js +11 -0
- package/dist/chunk-S5HEU7XK.js +11 -0
- package/dist/chunk-TYRVM4PP.js +8 -0
- package/dist/chunk-U36HMOQW.js +77 -0
- package/dist/chunk-UBTSW22U.js +11 -0
- package/dist/chunk-USRRI5H4.js +11 -0
- package/dist/chunk-UT667QSU.js +8 -0
- package/dist/chunk-VFSTQAZ2.js +12 -0
- package/dist/chunk-VNEZZ3RI.js +11 -0
- package/dist/chunk-W7EWOZPO.js +104 -0
- package/dist/chunk-Y5AMO72S.js +10 -0
- package/dist/chunk-YIKNM523.js +15 -0
- package/dist/chunk-YMXXWGRV.js +11 -0
- package/dist/estree-HPTPQIMZ.js +51 -0
- package/dist/flow-B6JUMONE.js +27 -0
- package/dist/glimmer-36KZ3DJ5.js +44 -0
- package/dist/graphql-E6CIFZFV.js +35 -0
- package/dist/html-BUTTPQE6.js +32 -0
- package/dist/markdown-K2C5OZHT.js +69 -0
- package/dist/meriyah-27UE2OSX.js +12 -0
- package/dist/postcss-QUHZLBB7.js +68 -0
- package/dist/typescript-G2G6TDZF.js +28 -0
- package/dist/yaml-W5P5CGFK.js +166 -0
- package/package.json +22 -17
- package/dist/ArgumentProvider.d.ts +0 -144
- package/dist/ArgumentProvider.d.ts.map +0 -1
- package/dist/ArgumentProvider.js +0 -493
- package/dist/ArgumentProvider.js.map +0 -1
- package/dist/Authentication/ActiveAccountStore.d.ts +0 -24
- package/dist/Authentication/ActiveAccountStore.d.ts.map +0 -1
- package/dist/Authentication/ActiveAccountStore.js +0 -54
- package/dist/Authentication/ActiveAccountStore.js.map +0 -1
- package/dist/Authentication/EnvironmentVariableAuthenticationProvider.d.ts +0 -26
- package/dist/Authentication/EnvironmentVariableAuthenticationProvider.d.ts.map +0 -1
- package/dist/Authentication/EnvironmentVariableAuthenticationProvider.js +0 -31
- package/dist/Authentication/EnvironmentVariableAuthenticationProvider.js.map +0 -1
- package/dist/Authentication/NoOpAuthenticationProvider.d.ts +0 -25
- package/dist/Authentication/NoOpAuthenticationProvider.d.ts.map +0 -1
- package/dist/Authentication/NoOpAuthenticationProvider.js +0 -31
- package/dist/Authentication/NoOpAuthenticationProvider.js.map +0 -1
- package/dist/Authentication/NodeMsalAuthenticationProvider.d.ts +0 -103
- package/dist/Authentication/NodeMsalAuthenticationProvider.d.ts.map +0 -1
- package/dist/Authentication/NodeMsalAuthenticationProvider.js +0 -391
- package/dist/Authentication/NodeMsalAuthenticationProvider.js.map +0 -1
- package/dist/Authentication/ServicePrincipalAuthenticationProvider.d.ts +0 -23
- package/dist/Authentication/ServicePrincipalAuthenticationProvider.d.ts.map +0 -1
- package/dist/Authentication/ServicePrincipalAuthenticationProvider.js +0 -60
- package/dist/Authentication/ServicePrincipalAuthenticationProvider.js.map +0 -1
- package/dist/Bin.d.ts +0 -6
- package/dist/Bin.d.ts.map +0 -1
- package/dist/Bin.js.map +0 -1
- package/dist/Cli.d.ts +0 -2
- package/dist/Cli.d.ts.map +0 -1
- package/dist/Cli.js +0 -207
- package/dist/Cli.js.map +0 -1
- package/dist/CliSettings.d.ts +0 -17
- package/dist/CliSettings.d.ts.map +0 -1
- package/dist/CliSettings.js +0 -103
- package/dist/CliSettings.js.map +0 -1
- package/dist/CliUtils.d.ts +0 -100
- package/dist/CliUtils.d.ts.map +0 -1
- package/dist/CliUtils.js +0 -204
- package/dist/CliUtils.js.map +0 -1
- package/dist/Constants/CliConstants.d.ts +0 -6
- package/dist/Constants/CliConstants.d.ts.map +0 -1
- package/dist/Constants/CliConstants.js +0 -6
- package/dist/Constants/CliConstants.js.map +0 -1
- package/dist/Constants/CommandRegistry.d.ts +0 -22
- package/dist/Constants/CommandRegistry.d.ts.map +0 -1
- package/dist/Constants/CommandRegistry.js +0 -245
- package/dist/Constants/CommandRegistry.js.map +0 -1
- package/dist/Constants/HelpStrings.d.ts +0 -432
- package/dist/Constants/HelpStrings.d.ts.map +0 -1
- package/dist/Constants/HelpStrings.js +0 -623
- package/dist/Constants/HelpStrings.js.map +0 -1
- package/dist/Constants.d.ts +0 -18
- package/dist/Constants.d.ts.map +0 -1
- package/dist/Constants.js +0 -41
- package/dist/Constants.js.map +0 -1
- package/dist/Errors/CliError.d.ts +0 -5
- package/dist/Errors/CliError.d.ts.map +0 -1
- package/dist/Errors/CliError.js +0 -7
- package/dist/Errors/CliError.js.map +0 -1
- package/dist/Errors/GitHubErrorMap.d.ts +0 -68
- package/dist/Errors/GitHubErrorMap.d.ts.map +0 -1
- package/dist/Errors/GitHubErrorMap.js +0 -238
- package/dist/Errors/GitHubErrorMap.js.map +0 -1
- package/dist/FS/CliFs.d.ts +0 -41
- package/dist/FS/CliFs.d.ts.map +0 -1
- package/dist/FS/CliFs.js +0 -136
- package/dist/FS/CliFs.js.map +0 -1
- package/dist/HttpClient/CliHttpClient.d.ts +0 -43
- package/dist/HttpClient/CliHttpClient.d.ts.map +0 -1
- package/dist/HttpClient/CliHttpClient.js +0 -320
- package/dist/HttpClient/CliHttpClient.js.map +0 -1
- package/dist/HttpClient/HttpForward.d.ts +0 -9
- package/dist/HttpClient/HttpForward.d.ts.map +0 -1
- package/dist/HttpClient/HttpForward.js +0 -56
- package/dist/HttpClient/HttpForward.js.map +0 -1
- package/dist/Logger/BufferedTelemetryWriter.d.ts +0 -20
- package/dist/Logger/BufferedTelemetryWriter.d.ts.map +0 -1
- package/dist/Logger/BufferedTelemetryWriter.js +0 -163
- package/dist/Logger/BufferedTelemetryWriter.js.map +0 -1
- package/dist/Logger/CliLogger.d.ts +0 -59
- package/dist/Logger/CliLogger.d.ts.map +0 -1
- package/dist/Logger/CliLogger.js +0 -364
- package/dist/Logger/CliLogger.js.map +0 -1
- package/dist/Logger/ConsoleWriter.d.ts +0 -23
- package/dist/Logger/ConsoleWriter.d.ts.map +0 -1
- package/dist/Logger/ConsoleWriter.js +0 -66
- package/dist/Logger/ConsoleWriter.js.map +0 -1
- package/dist/Logger/Constants.d.ts +0 -6
- package/dist/Logger/Constants.d.ts.map +0 -1
- package/dist/Logger/Constants.js +0 -15
- package/dist/Logger/Constants.js.map +0 -1
- package/dist/Logger/LoggerSettings.d.ts +0 -18
- package/dist/Logger/LoggerSettings.d.ts.map +0 -1
- package/dist/Logger/LoggerSettings.js +0 -78
- package/dist/Logger/LoggerSettings.js.map +0 -1
- package/dist/Logger/OneDSWriter.d.ts +0 -26
- package/dist/Logger/OneDSWriter.d.ts.map +0 -1
- package/dist/Logger/OneDSWriter.js +0 -211
- package/dist/Logger/OneDSWriter.js.map +0 -1
- package/dist/Logger/Scrubber/ScrubCustomDimensions.d.ts +0 -5
- package/dist/Logger/Scrubber/ScrubCustomDimensions.d.ts.map +0 -1
- package/dist/Logger/Scrubber/ScrubCustomDimensions.js +0 -46
- package/dist/Logger/Scrubber/ScrubCustomDimensions.js.map +0 -1
- package/dist/Logger/Scrubber/ScrubCustomDimensionsConfig.d.ts +0 -27
- package/dist/Logger/Scrubber/ScrubCustomDimensionsConfig.d.ts.map +0 -1
- package/dist/Logger/Scrubber/ScrubCustomDimensionsConfig.js +0 -168
- package/dist/Logger/Scrubber/ScrubCustomDimensionsConfig.js.map +0 -1
- package/dist/Logger/Scrubber/ScrubUtils.d.ts +0 -8
- package/dist/Logger/Scrubber/ScrubUtils.d.ts.map +0 -1
- package/dist/Logger/Scrubber/ScrubUtils.js +0 -34
- package/dist/Logger/Scrubber/ScrubUtils.js.map +0 -1
- package/dist/Middletier/FunctionsBundler.d.ts +0 -17
- package/dist/Middletier/FunctionsBundler.d.ts.map +0 -1
- package/dist/Middletier/FunctionsBundler.js +0 -169
- package/dist/Middletier/FunctionsBundler.js.map +0 -1
- package/dist/Middletier/PackFunctions.d.ts +0 -53
- package/dist/Middletier/PackFunctions.d.ts.map +0 -1
- package/dist/Middletier/PackFunctions.js +0 -123
- package/dist/Middletier/PackFunctions.js.map +0 -1
- package/dist/Testing/MockFetch.d.ts +0 -23
- package/dist/Testing/MockFetch.d.ts.map +0 -1
- package/dist/Testing/MockFetch.js +0 -177
- package/dist/Testing/MockFetch.js.map +0 -1
- package/dist/Testing/MockRoutes.d.ts +0 -34
- package/dist/Testing/MockRoutes.d.ts.map +0 -1
- package/dist/Testing/MockRoutes.js +0 -226
- package/dist/Testing/MockRoutes.js.map +0 -1
- package/dist/Testing/fixtures/connectors/commondataserviceforapps.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/commondataserviceforapps.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/commondataserviceforapps.js +0 -25
- package/dist/Testing/fixtures/connectors/commondataserviceforapps.js.map +0 -1
- package/dist/Testing/fixtures/connectors/dataverseContactEntity.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/dataverseContactEntity.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/dataverseContactEntity.js +0 -55
- package/dist/Testing/fixtures/connectors/dataverseContactEntity.js.map +0 -1
- package/dist/Testing/fixtures/connectors/excelonlinebusiness.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/excelonlinebusiness.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/excelonlinebusiness.js +0 -1970
- package/dist/Testing/fixtures/connectors/excelonlinebusiness.js.map +0 -1
- package/dist/Testing/fixtures/connectors/kusto.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/kusto.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/kusto.js +0 -1333
- package/dist/Testing/fixtures/connectors/kusto.js.map +0 -1
- package/dist/Testing/fixtures/connectors/msnweather.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/msnweather.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/msnweather.js +0 -917
- package/dist/Testing/fixtures/connectors/msnweather.js.map +0 -1
- package/dist/Testing/fixtures/connectors/office365groups.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/office365groups.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/office365groups.js +0 -2144
- package/dist/Testing/fixtures/connectors/office365groups.js.map +0 -1
- package/dist/Testing/fixtures/connectors/office365users.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/office365users.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/office365users.js +0 -1969
- package/dist/Testing/fixtures/connectors/office365users.js.map +0 -1
- package/dist/Testing/fixtures/connectors/onedriveforbusiness.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/onedriveforbusiness.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/onedriveforbusiness.js +0 -4873
- package/dist/Testing/fixtures/connectors/onedriveforbusiness.js.map +0 -1
- package/dist/Testing/fixtures/connectors/powerappsforappmakers.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/powerappsforappmakers.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/powerappsforappmakers.js +0 -4682
- package/dist/Testing/fixtures/connectors/powerappsforappmakers.js.map +0 -1
- package/dist/Testing/fixtures/connectors/sharepointTestListMetadata.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/sharepointTestListMetadata.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/sharepointTestListMetadata.js +0 -1078
- package/dist/Testing/fixtures/connectors/sharepointTestListMetadata.js.map +0 -1
- package/dist/Testing/fixtures/connectors/sharepointonline.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/sharepointonline.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/sharepointonline.js +0 -28
- package/dist/Testing/fixtures/connectors/sharepointonline.js.map +0 -1
- package/dist/Testing/fixtures/connectors/teams.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/teams.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/teams.js +0 -9987
- package/dist/Testing/fixtures/connectors/teams.js.map +0 -1
- package/dist/Testing/fixtures/connectors/translatorv2.d.ts +0 -6
- package/dist/Testing/fixtures/connectors/translatorv2.d.ts.map +0 -1
- package/dist/Testing/fixtures/connectors/translatorv2.js +0 -307
- package/dist/Testing/fixtures/connectors/translatorv2.js.map +0 -1
- package/dist/Testing/fixtures/index.d.ts +0 -23
- package/dist/Testing/fixtures/index.d.ts.map +0 -1
- package/dist/Testing/fixtures/index.js +0 -96
- package/dist/Testing/fixtures/index.js.map +0 -1
- package/dist/Types/Argument.types.d.ts +0 -28
- package/dist/Types/Argument.types.d.ts.map +0 -1
- package/dist/Types/Argument.types.js +0 -5
- package/dist/Types/Argument.types.js.map +0 -1
- package/dist/Types/Cli.types.d.ts +0 -82
- package/dist/Types/Cli.types.d.ts.map +0 -1
- package/dist/Types/Cli.types.js +0 -5
- package/dist/Types/Cli.types.js.map +0 -1
- package/dist/Types/Command.types.d.ts +0 -69
- package/dist/Types/Command.types.d.ts.map +0 -1
- package/dist/Types/Command.types.js +0 -20
- package/dist/Types/Command.types.js.map +0 -1
- package/dist/Types/Datasource.types.d.ts +0 -30
- package/dist/Types/Datasource.types.d.ts.map +0 -1
- package/dist/Types/Datasource.types.js +0 -5
- package/dist/Types/Datasource.types.js.map +0 -1
- package/dist/Types/LoggerTypes.types.d.ts +0 -18
- package/dist/Types/LoggerTypes.types.d.ts.map +0 -1
- package/dist/Types/LoggerTypes.types.js +0 -5
- package/dist/Types/LoggerTypes.types.js.map +0 -1
- package/dist/Utils/BuildPolling.d.ts +0 -43
- package/dist/Utils/BuildPolling.d.ts.map +0 -1
- package/dist/Utils/BuildPolling.js +0 -139
- package/dist/Utils/BuildPolling.js.map +0 -1
- package/dist/Utils/BuildVerbDescriptionTable.d.ts +0 -29
- package/dist/Utils/BuildVerbDescriptionTable.d.ts.map +0 -1
- package/dist/Utils/BuildVerbDescriptionTable.js +0 -147
- package/dist/Utils/BuildVerbDescriptionTable.js.map +0 -1
- package/dist/Utils/CoerceCliVersion.d.ts +0 -27
- package/dist/Utils/CoerceCliVersion.d.ts.map +0 -1
- package/dist/Utils/CoerceCliVersion.js +0 -67
- package/dist/Utils/CoerceCliVersion.js.map +0 -1
- package/dist/Utils/ConnectorIds.d.ts +0 -12
- package/dist/Utils/ConnectorIds.d.ts.map +0 -1
- package/dist/Utils/ConnectorIds.js +0 -20
- package/dist/Utils/ConnectorIds.js.map +0 -1
- package/dist/Utils/ConsoleOutput.d.ts +0 -86
- package/dist/Utils/ConsoleOutput.d.ts.map +0 -1
- package/dist/Utils/ConsoleOutput.js +0 -162
- package/dist/Utils/ConsoleOutput.js.map +0 -1
- package/dist/Utils/DcfRecovery.d.ts +0 -84
- package/dist/Utils/DcfRecovery.d.ts.map +0 -1
- package/dist/Utils/DcfRecovery.js +0 -246
- package/dist/Utils/DcfRecovery.js.map +0 -1
- package/dist/Utils/DetectPackageManager.d.ts +0 -9
- package/dist/Utils/DetectPackageManager.d.ts.map +0 -1
- package/dist/Utils/DetectPackageManager.js +0 -24
- package/dist/Utils/DetectPackageManager.js.map +0 -1
- package/dist/Utils/DownloadTemplate.d.ts +0 -45
- package/dist/Utils/DownloadTemplate.d.ts.map +0 -1
- package/dist/Utils/DownloadTemplate.js +0 -161
- package/dist/Utils/DownloadTemplate.js.map +0 -1
- package/dist/Utils/EnhanceNetworkError.d.ts +0 -14
- package/dist/Utils/EnhanceNetworkError.d.ts.map +0 -1
- package/dist/Utils/EnhanceNetworkError.js +0 -61
- package/dist/Utils/EnhanceNetworkError.js.map +0 -1
- package/dist/Utils/EnvVars.d.ts +0 -17
- package/dist/Utils/EnvVars.d.ts.map +0 -1
- package/dist/Utils/EnvVars.js +0 -38
- package/dist/Utils/EnvVars.js.map +0 -1
- package/dist/Utils/EnvironmentRoutingUtils.d.ts +0 -81
- package/dist/Utils/EnvironmentRoutingUtils.d.ts.map +0 -1
- package/dist/Utils/EnvironmentRoutingUtils.js +0 -204
- package/dist/Utils/EnvironmentRoutingUtils.js.map +0 -1
- package/dist/Utils/FindAvailablePort.d.ts +0 -39
- package/dist/Utils/FindAvailablePort.d.ts.map +0 -1
- package/dist/Utils/FindAvailablePort.js +0 -105
- package/dist/Utils/FindAvailablePort.js.map +0 -1
- package/dist/Utils/GitCredentialConfig.d.ts +0 -12
- package/dist/Utils/GitCredentialConfig.d.ts.map +0 -1
- package/dist/Utils/GitCredentialConfig.js +0 -32
- package/dist/Utils/GitCredentialConfig.js.map +0 -1
- package/dist/Utils/GitErrorClassifier.d.ts +0 -40
- package/dist/Utils/GitErrorClassifier.d.ts.map +0 -1
- package/dist/Utils/GitErrorClassifier.js +0 -120
- package/dist/Utils/GitErrorClassifier.js.map +0 -1
- package/dist/Utils/GitHubDcfFlow.d.ts +0 -59
- package/dist/Utils/GitHubDcfFlow.d.ts.map +0 -1
- package/dist/Utils/GitHubDcfFlow.js +0 -165
- package/dist/Utils/GitHubDcfFlow.js.map +0 -1
- package/dist/Utils/GitRunner.d.ts +0 -107
- package/dist/Utils/GitRunner.d.ts.map +0 -1
- package/dist/Utils/GitRunner.js +0 -89
- package/dist/Utils/GitRunner.js.map +0 -1
- package/dist/Utils/GitUtils.d.ts +0 -43
- package/dist/Utils/GitUtils.d.ts.map +0 -1
- package/dist/Utils/GitUtils.js +0 -120
- package/dist/Utils/GitUtils.js.map +0 -1
- package/dist/Utils/GitVersionChecker.d.ts +0 -38
- package/dist/Utils/GitVersionChecker.d.ts.map +0 -1
- package/dist/Utils/GitVersionChecker.js +0 -64
- package/dist/Utils/GitVersionChecker.js.map +0 -1
- package/dist/Utils/HelpBanner.d.ts +0 -11
- package/dist/Utils/HelpBanner.d.ts.map +0 -1
- package/dist/Utils/HelpBanner.js +0 -15
- package/dist/Utils/HelpBanner.js.map +0 -1
- package/dist/Utils/MaafAppConfig.d.ts +0 -24
- package/dist/Utils/MaafAppConfig.d.ts.map +0 -1
- package/dist/Utils/MaafAppConfig.js +0 -38
- package/dist/Utils/MaafAppConfig.js.map +0 -1
- package/dist/Utils/NodeVersionChecker.d.ts +0 -10
- package/dist/Utils/NodeVersionChecker.d.ts.map +0 -1
- package/dist/Utils/NodeVersionChecker.js +0 -21
- package/dist/Utils/NodeVersionChecker.js.map +0 -1
- package/dist/Utils/Paging.d.ts +0 -29
- package/dist/Utils/Paging.d.ts.map +0 -1
- package/dist/Utils/Paging.js +0 -102
- package/dist/Utils/Paging.js.map +0 -1
- package/dist/Utils/PinCli.d.ts +0 -33
- package/dist/Utils/PinCli.d.ts.map +0 -1
- package/dist/Utils/PinCli.js +0 -77
- package/dist/Utils/PinCli.js.map +0 -1
- package/dist/Utils/ReadPackageJson.d.ts +0 -9
- package/dist/Utils/ReadPackageJson.d.ts.map +0 -1
- package/dist/Utils/ReadPackageJson.js +0 -13
- package/dist/Utils/ReadPackageJson.js.map +0 -1
- package/dist/Utils/RepoDetails.d.ts +0 -29
- package/dist/Utils/RepoDetails.d.ts.map +0 -1
- package/dist/Utils/RepoDetails.js +0 -37
- package/dist/Utils/RepoDetails.js.map +0 -1
- package/dist/Utils/RepoOption.d.ts +0 -42
- package/dist/Utils/RepoOption.d.ts.map +0 -1
- package/dist/Utils/RepoOption.js +0 -63
- package/dist/Utils/RepoOption.js.map +0 -1
- package/dist/Utils/RepoUrl.d.ts +0 -18
- package/dist/Utils/RepoUrl.d.ts.map +0 -1
- package/dist/Utils/RepoUrl.js +0 -6
- package/dist/Utils/RepoUrl.js.map +0 -1
- package/dist/Utils/ResolveCommand.d.ts +0 -62
- package/dist/Utils/ResolveCommand.d.ts.map +0 -1
- package/dist/Utils/ResolveCommand.js +0 -141
- package/dist/Utils/ResolveCommand.js.map +0 -1
- package/dist/Utils/RunCommand.d.ts +0 -33
- package/dist/Utils/RunCommand.d.ts.map +0 -1
- package/dist/Utils/RunCommand.js +0 -83
- package/dist/Utils/RunCommand.js.map +0 -1
- package/dist/Utils/ShareAccessRouting.d.ts +0 -78
- package/dist/Utils/ShareAccessRouting.d.ts.map +0 -1
- package/dist/Utils/ShareAccessRouting.js +0 -93
- package/dist/Utils/ShareAccessRouting.js.map +0 -1
- package/dist/Utils/Spinner.d.ts +0 -23
- package/dist/Utils/Spinner.d.ts.map +0 -1
- package/dist/Utils/Spinner.js +0 -94
- package/dist/Utils/Spinner.js.map +0 -1
- package/dist/Utils/zipBuildArtifact.d.ts +0 -35
- package/dist/Utils/zipBuildArtifact.d.ts.map +0 -1
- package/dist/Utils/zipBuildArtifact.js +0 -100
- package/dist/Utils/zipBuildArtifact.js.map +0 -1
- package/dist/Verbs/AddAction.d.ts +0 -6
- package/dist/Verbs/AddAction.d.ts.map +0 -1
- package/dist/Verbs/AddAction.js +0 -58
- package/dist/Verbs/AddAction.js.map +0 -1
- package/dist/Verbs/AddConnector.d.ts +0 -26
- package/dist/Verbs/AddConnector.d.ts.map +0 -1
- package/dist/Verbs/AddConnector.js +0 -222
- package/dist/Verbs/AddConnector.js.map +0 -1
- package/dist/Verbs/AddConnectorFlows.d.ts +0 -97
- package/dist/Verbs/AddConnectorFlows.d.ts.map +0 -1
- package/dist/Verbs/AddConnectorFlows.js +0 -298
- package/dist/Verbs/AddConnectorFlows.js.map +0 -1
- package/dist/Verbs/AddDataSource.d.ts +0 -18
- package/dist/Verbs/AddDataSource.d.ts.map +0 -1
- package/dist/Verbs/AddDataSource.js +0 -162
- package/dist/Verbs/AddDataSource.js.map +0 -1
- package/dist/Verbs/AddFlow.d.ts +0 -12
- package/dist/Verbs/AddFlow.d.ts.map +0 -1
- package/dist/Verbs/AddFlow.js +0 -62
- package/dist/Verbs/AddFlow.js.map +0 -1
- package/dist/Verbs/AddTable.d.ts +0 -6
- package/dist/Verbs/AddTable.d.ts.map +0 -1
- package/dist/Verbs/AddTable.js +0 -78
- package/dist/Verbs/AddTable.js.map +0 -1
- package/dist/Verbs/AuthStatus.d.ts +0 -6
- package/dist/Verbs/AuthStatus.d.ts.map +0 -1
- package/dist/Verbs/AuthStatus.js +0 -49
- package/dist/Verbs/AuthStatus.js.map +0 -1
- package/dist/Verbs/AuthSwitch.d.ts +0 -6
- package/dist/Verbs/AuthSwitch.d.ts.map +0 -1
- package/dist/Verbs/AuthSwitch.js +0 -67
- package/dist/Verbs/AuthSwitch.js.map +0 -1
- package/dist/Verbs/BuildMaafApp.d.ts +0 -6
- package/dist/Verbs/BuildMaafApp.d.ts.map +0 -1
- package/dist/Verbs/BuildMaafApp.js +0 -172
- package/dist/Verbs/BuildMaafApp.js.map +0 -1
- package/dist/Verbs/ConnectorHelpers.d.ts +0 -164
- package/dist/Verbs/ConnectorHelpers.d.ts.map +0 -1
- package/dist/Verbs/ConnectorHelpers.js +0 -563
- package/dist/Verbs/ConnectorHelpers.js.map +0 -1
- package/dist/Verbs/CreateMaafApp.d.ts +0 -107
- package/dist/Verbs/CreateMaafApp.d.ts.map +0 -1
- package/dist/Verbs/CreateMaafApp.js +0 -1081
- package/dist/Verbs/CreateMaafApp.js.map +0 -1
- package/dist/Verbs/DeleteMaafApp.d.ts +0 -27
- package/dist/Verbs/DeleteMaafApp.d.ts.map +0 -1
- package/dist/Verbs/DeleteMaafApp.js +0 -114
- package/dist/Verbs/DeleteMaafApp.js.map +0 -1
- package/dist/Verbs/DeployMaafApp.d.ts +0 -6
- package/dist/Verbs/DeployMaafApp.d.ts.map +0 -1
- package/dist/Verbs/DeployMaafApp.js +0 -495
- package/dist/Verbs/DeployMaafApp.js.map +0 -1
- package/dist/Verbs/Dev.d.ts +0 -6
- package/dist/Verbs/Dev.d.ts.map +0 -1
- package/dist/Verbs/Dev.js +0 -276
- package/dist/Verbs/Dev.js.map +0 -1
- package/dist/Verbs/FindDataverseApi.d.ts +0 -12
- package/dist/Verbs/FindDataverseApi.d.ts.map +0 -1
- package/dist/Verbs/FindDataverseApi.js +0 -87
- package/dist/Verbs/FindDataverseApi.js.map +0 -1
- package/dist/Verbs/GetMaafApp.d.ts +0 -6
- package/dist/Verbs/GetMaafApp.d.ts.map +0 -1
- package/dist/Verbs/GetMaafApp.js +0 -80
- package/dist/Verbs/GetMaafApp.js.map +0 -1
- package/dist/Verbs/GetMaafBuildStatus.d.ts +0 -6
- package/dist/Verbs/GetMaafBuildStatus.d.ts.map +0 -1
- package/dist/Verbs/GetMaafBuildStatus.js +0 -132
- package/dist/Verbs/GetMaafBuildStatus.js.map +0 -1
- package/dist/Verbs/GetSettings.d.ts +0 -12
- package/dist/Verbs/GetSettings.d.ts.map +0 -1
- package/dist/Verbs/GetSettings.js +0 -39
- package/dist/Verbs/GetSettings.js.map +0 -1
- package/dist/Verbs/Init.d.ts +0 -6
- package/dist/Verbs/Init.d.ts.map +0 -1
- package/dist/Verbs/Init.js +0 -426
- package/dist/Verbs/Init.js.map +0 -1
- package/dist/Verbs/ListConnectionReferences.d.ts +0 -6
- package/dist/Verbs/ListConnectionReferences.d.ts.map +0 -1
- package/dist/Verbs/ListConnectionReferences.js +0 -56
- package/dist/Verbs/ListConnectionReferences.js.map +0 -1
- package/dist/Verbs/ListConnectorActions.d.ts +0 -6
- package/dist/Verbs/ListConnectorActions.d.ts.map +0 -1
- package/dist/Verbs/ListConnectorActions.js +0 -87
- package/dist/Verbs/ListConnectorActions.js.map +0 -1
- package/dist/Verbs/ListConnectors.d.ts +0 -6
- package/dist/Verbs/ListConnectors.d.ts.map +0 -1
- package/dist/Verbs/ListConnectors.js +0 -91
- package/dist/Verbs/ListConnectors.js.map +0 -1
- package/dist/Verbs/ListDatasets.d.ts +0 -6
- package/dist/Verbs/ListDatasets.d.ts.map +0 -1
- package/dist/Verbs/ListDatasets.js +0 -73
- package/dist/Verbs/ListDatasets.js.map +0 -1
- package/dist/Verbs/ListEnvironmentVariables.d.ts +0 -14
- package/dist/Verbs/ListEnvironmentVariables.d.ts.map +0 -1
- package/dist/Verbs/ListEnvironmentVariables.js +0 -52
- package/dist/Verbs/ListEnvironmentVariables.js.map +0 -1
- package/dist/Verbs/ListFlows.d.ts +0 -13
- package/dist/Verbs/ListFlows.d.ts.map +0 -1
- package/dist/Verbs/ListFlows.js +0 -73
- package/dist/Verbs/ListFlows.js.map +0 -1
- package/dist/Verbs/ListMaafApps.d.ts +0 -84
- package/dist/Verbs/ListMaafApps.d.ts.map +0 -1
- package/dist/Verbs/ListMaafApps.js +0 -221
- package/dist/Verbs/ListMaafApps.js.map +0 -1
- package/dist/Verbs/ListSqlStoredProcedures.d.ts +0 -6
- package/dist/Verbs/ListSqlStoredProcedures.d.ts.map +0 -1
- package/dist/Verbs/ListSqlStoredProcedures.js +0 -75
- package/dist/Verbs/ListSqlStoredProcedures.js.map +0 -1
- package/dist/Verbs/ListTables.d.ts +0 -6
- package/dist/Verbs/ListTables.d.ts.map +0 -1
- package/dist/Verbs/ListTables.js +0 -85
- package/dist/Verbs/ListTables.js.map +0 -1
- package/dist/Verbs/Login.d.ts +0 -6
- package/dist/Verbs/Login.d.ts.map +0 -1
- package/dist/Verbs/Login.js +0 -39
- package/dist/Verbs/Login.js.map +0 -1
- package/dist/Verbs/Logout.d.ts +0 -6
- package/dist/Verbs/Logout.d.ts.map +0 -1
- package/dist/Verbs/Logout.js +0 -34
- package/dist/Verbs/Logout.js.map +0 -1
- package/dist/Verbs/MaafAppPermissions.d.ts +0 -40
- package/dist/Verbs/MaafAppPermissions.d.ts.map +0 -1
- package/dist/Verbs/MaafAppPermissions.js +0 -651
- package/dist/Verbs/MaafAppPermissions.js.map +0 -1
- package/dist/Verbs/Pack.d.ts +0 -71
- package/dist/Verbs/Pack.d.ts.map +0 -1
- package/dist/Verbs/Pack.js +0 -370
- package/dist/Verbs/Pack.js.map +0 -1
- package/dist/Verbs/PlayMaafApp.d.ts +0 -22
- package/dist/Verbs/PlayMaafApp.d.ts.map +0 -1
- package/dist/Verbs/PlayMaafApp.js +0 -147
- package/dist/Verbs/PlayMaafApp.js.map +0 -1
- package/dist/Verbs/RefreshDataSource.d.ts +0 -21
- package/dist/Verbs/RefreshDataSource.d.ts.map +0 -1
- package/dist/Verbs/RefreshDataSource.js +0 -87
- package/dist/Verbs/RefreshDataSource.js.map +0 -1
- package/dist/Verbs/RefreshGitAuth.d.ts +0 -6
- package/dist/Verbs/RefreshGitAuth.d.ts.map +0 -1
- package/dist/Verbs/RefreshGitAuth.js +0 -155
- package/dist/Verbs/RefreshGitAuth.js.map +0 -1
- package/dist/Verbs/RemoveDataSource.d.ts +0 -6
- package/dist/Verbs/RemoveDataSource.d.ts.map +0 -1
- package/dist/Verbs/RemoveDataSource.js +0 -172
- package/dist/Verbs/RemoveDataSource.js.map +0 -1
- package/dist/Verbs/RemoveFlow.d.ts +0 -12
- package/dist/Verbs/RemoveFlow.d.ts.map +0 -1
- package/dist/Verbs/RemoveFlow.js +0 -94
- package/dist/Verbs/RemoveFlow.js.map +0 -1
- package/dist/Verbs/SetSetting.d.ts +0 -12
- package/dist/Verbs/SetSetting.d.ts.map +0 -1
- package/dist/Verbs/SetSetting.js +0 -131
- package/dist/Verbs/SetSetting.js.map +0 -1
- package/dist/Verbs/ShareLinkCreate.d.ts +0 -23
- package/dist/Verbs/ShareLinkCreate.d.ts.map +0 -1
- package/dist/Verbs/ShareLinkCreate.js +0 -73
- package/dist/Verbs/ShareLinkCreate.js.map +0 -1
- package/dist/Verbs/ShareLinkList.d.ts +0 -16
- package/dist/Verbs/ShareLinkList.d.ts.map +0 -1
- package/dist/Verbs/ShareLinkList.js +0 -84
- package/dist/Verbs/ShareLinkList.js.map +0 -1
- package/dist/Verbs/ShareLinkRevoke.d.ts +0 -22
- package/dist/Verbs/ShareLinkRevoke.d.ts.map +0 -1
- package/dist/Verbs/ShareLinkRevoke.js +0 -137
- package/dist/Verbs/ShareLinkRevoke.js.map +0 -1
- package/dist/Verbs/ShareList.d.ts +0 -10
- package/dist/Verbs/ShareList.d.ts.map +0 -1
- package/dist/Verbs/ShareList.js +0 -254
- package/dist/Verbs/ShareList.js.map +0 -1
- package/dist/Verbs/ShareMaafApp.d.ts +0 -12
- package/dist/Verbs/ShareMaafApp.d.ts.map +0 -1
- package/dist/Verbs/ShareMaafApp.js +0 -14
- package/dist/Verbs/ShareMaafApp.js.map +0 -1
- package/dist/Verbs/ShowMaafApp.d.ts +0 -100
- package/dist/Verbs/ShowMaafApp.d.ts.map +0 -1
- package/dist/Verbs/ShowMaafApp.js +0 -224
- package/dist/Verbs/ShowMaafApp.js.map +0 -1
- package/dist/Verbs/TelemetrySettings.d.ts +0 -8
- package/dist/Verbs/TelemetrySettings.d.ts.map +0 -1
- package/dist/Verbs/TelemetrySettings.js +0 -104
- package/dist/Verbs/TelemetrySettings.js.map +0 -1
- package/dist/Verbs/UnshareMaafApp.d.ts +0 -12
- package/dist/Verbs/UnshareMaafApp.d.ts.map +0 -1
- package/dist/Verbs/UnshareMaafApp.js +0 -14
- package/dist/Verbs/UnshareMaafApp.js.map +0 -1
- package/dist/Verbs/VerbConstants.d.ts +0 -628
- package/dist/Verbs/VerbConstants.d.ts.map +0 -1
- package/dist/Verbs/VerbConstants.js +0 -557
- package/dist/Verbs/VerbConstants.js.map +0 -1
- package/dist/Verbs/index.d.ts +0 -47
- package/dist/Verbs/index.d.ts.map +0 -1
- package/dist/Verbs/index.js +0 -47
- package/dist/Verbs/index.js.map +0 -1
|
@@ -1,1081 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (C) Microsoft Corporation. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
import { createAsync, getPlayerServiceConfig, writeRepoConfig, } from '@microsoft/managed-apps-actions';
|
|
5
|
-
import { AppConfigFileName } from '@microsoft/managed-apps-common/config';
|
|
6
|
-
import { HttpClientError, regionToCloudSafe } from '@microsoft/managed-apps-common/services';
|
|
7
|
-
import * as fs from 'fs';
|
|
8
|
-
import * as os from 'os';
|
|
9
|
-
import * as path from 'path';
|
|
10
|
-
import { getCliLogger, getSettings } from '../CliSettings.js';
|
|
11
|
-
import { createDefaultStringOption, resolveEnvironmentId } from '../CliUtils.js';
|
|
12
|
-
import { CLI_BINARY_NAME } from '../Constants/CliConstants.js';
|
|
13
|
-
import { HelpStrings } from '../Constants/HelpStrings.js';
|
|
14
|
-
import { AppError, AuthenticationError, ConfigurationError, NetworkError, UsageError, } from '../Errors/CliError.js';
|
|
15
|
-
import { printInfo, printJsonLine, printJsonSuccess, printSuccess, printWarning, } from '../Utils/ConsoleOutput.js';
|
|
16
|
-
import { withGitHubDcfRecoveryAsync } from '../Utils/DcfRecovery.js';
|
|
17
|
-
import { downloadTemplate, parseGithubTemplate } from '../Utils/DownloadTemplate.js';
|
|
18
|
-
import { awaitRoutingEnvironmentAsync, startPdeRoutingAsync, } from '../Utils/EnvironmentRoutingUtils.js';
|
|
19
|
-
import { buildGcmConfig } from '../Utils/GitCredentialConfig.js';
|
|
20
|
-
import { runGit } from '../Utils/GitRunner.js';
|
|
21
|
-
import { ensureGitInstalled } from '../Utils/GitVersionChecker.js';
|
|
22
|
-
import { buildMaafAppConfig } from '../Utils/MaafAppConfig.js';
|
|
23
|
-
import { pinCliIntoAppPackageJson } from '../Utils/PinCli.js';
|
|
24
|
-
import { parseRepoOption } from '../Utils/RepoOption.js';
|
|
25
|
-
import { CliSpinner } from '../Utils/Spinner.js';
|
|
26
|
-
import { CreateMaafAppArguments } from './VerbConstants.js';
|
|
27
|
-
const DEFAULT_TEMPLATE = 'github:microsoft/Managed-Apps/templates/vite8';
|
|
28
|
-
/** Commit message for the initial scaffold, shared by the auto-push and every
|
|
29
|
-
* manual-recovery hint */
|
|
30
|
-
const SCAFFOLD_COMMIT_MESSAGE = "Initial scaffold from 'ms app create'";
|
|
31
|
-
/**
|
|
32
|
-
* Creates a new MAAF app and (where applicable) sets up local source control.
|
|
33
|
-
*
|
|
34
|
-
* Three repo flows, selected by `--repo`:
|
|
35
|
-
* - `native` (default): server auto-provisions a GRS repo; local clone happens via GCM.
|
|
36
|
-
* - `github`: external GitHub binding (`*.ghe.com` or `github.com`). Clones the user's repo locally. On the first
|
|
37
|
-
* `createAsync` call, a missing/expired server-side GitHub identity mapping is
|
|
38
|
-
* recoverable in-band: a single inline DCF run + exactly one `createAsync` retry.
|
|
39
|
-
* Any other error — or a second mapping failure after DCF — is a hard fail.
|
|
40
|
-
* - `none`: no git binding at all (just the server record + template + ms.config.json).
|
|
41
|
-
*/
|
|
42
|
-
export async function createMaafAppAsync(argumentProvider) {
|
|
43
|
-
createOptionSchema(argumentProvider);
|
|
44
|
-
await argumentProvider.runVerb();
|
|
45
|
-
const tenantId = await argumentProvider.getTenantIdAsync();
|
|
46
|
-
if (!tenantId) {
|
|
47
|
-
throw new UsageError('Unable to determine tenant ID. Ensure you are logged in.');
|
|
48
|
-
}
|
|
49
|
-
const logger = getCliLogger();
|
|
50
|
-
const { region } = getPlayerServiceConfig();
|
|
51
|
-
const displayName = await argumentProvider.getOption('displayName');
|
|
52
|
-
if (!displayName) {
|
|
53
|
-
throw new UsageError('Argument displayName is required. Use --display-name or -n to specify it.');
|
|
54
|
-
}
|
|
55
|
-
// The positional arg (or cwd) is both the git repo root and the app dir.
|
|
56
|
-
const appDir = argumentProvider.getPositionalArg(0) ?? process.cwd();
|
|
57
|
-
const template = await argumentProvider.getOption('template', /* ignorePrompt */ true);
|
|
58
|
-
// CLI surface is --repo. Three flows, decided up front so the rest of the verb can
|
|
59
|
-
// branch on `repoType` instead of inspecting `remoteUrl` everywhere. RepoSelection
|
|
60
|
-
// is a flat interface (not a discriminated union), so we branch on `repoType` and
|
|
61
|
-
// assert `remoteUrl!` at github use sites where `string` is required.
|
|
62
|
-
const rawRepoValue = await argumentProvider.getOption('repo',
|
|
63
|
-
/* ignorePrompt */ true);
|
|
64
|
-
const { repoType, remoteUrl } = parseRepoOption(rawRepoValue);
|
|
65
|
-
// Read --repository-id up front (instead of after preflight, like the other prompts)
|
|
66
|
-
// so the `--repo none` conflict check below has it. It is `optionalInNonInteractive`
|
|
67
|
-
// and registered with `ignorePrompt: true`, so reading early never triggers an
|
|
68
|
-
// interactive prompt.
|
|
69
|
-
const repositoryId = await argumentProvider.getOption('repositoryId',
|
|
70
|
-
/* ignorePrompt */ true);
|
|
71
|
-
// --json emits a single machine-parseable envelope on stdout, so every
|
|
72
|
-
// informational `printInfo` below is gated behind `!jsonMode` to keep
|
|
73
|
-
// stdout free of prose ahead of the envelope. `printError` writes to
|
|
74
|
-
// stderr and is unaffected.
|
|
75
|
-
const jsonMode = argumentProvider.isJsonMode();
|
|
76
|
-
// Identity confirmation: print the tenant + cloud we're targeting before
|
|
77
|
-
// anything else — preflight, routing, createAsync — so a user with multiple
|
|
78
|
-
// accounts signed in has the longest possible window to CTRL-C before any
|
|
79
|
-
// local check runs or server call fires. Environment id isn't known yet
|
|
80
|
-
// (routing is what resolves it); included in the success line at the end.
|
|
81
|
-
// Wording is intentionally tentative ("About to create…") so a preflight
|
|
82
|
-
// failure on the next line doesn't read as contradicting a "Creating…" line.
|
|
83
|
-
//
|
|
84
|
-
// Surface `cloud` (user-facing, e.g. `public` / `usgov`) instead of `region`
|
|
85
|
-
// (internal, e.g. `prod` / `gccmoderate`) so the value matches what the user
|
|
86
|
-
// typed on `--cloud`. Regions without a Cloud equivalent (`preview`, `ex`,
|
|
87
|
-
// `rx`, or developer modes `local` / `dev`) fall back to the raw region —
|
|
88
|
-
// these don't reach this print via the current `cloudToRegion(this._cloud)`
|
|
89
|
-
// chain in ArgumentProvider, so the fallback is defensive against future
|
|
90
|
-
// code paths (e.g. routing-resolved regions).
|
|
91
|
-
if (!jsonMode) {
|
|
92
|
-
const cloud = regionToCloudSafe(region);
|
|
93
|
-
const target = cloud ? `cloud ${cloud}` : `region ${region}`;
|
|
94
|
-
printInfo(`About to create app '${displayName}' in tenant ${tenantId} (${target}).`);
|
|
95
|
-
}
|
|
96
|
-
// ─── Preflight ────────────────────────────────────────────────────────────
|
|
97
|
-
// Run all local-only checks before any server call. Once createAsync
|
|
98
|
-
// succeeds the user has a MAAF app + GRS repo on the server; a later
|
|
99
|
-
// local-setup failure leaves them with created resources that need recovery.
|
|
100
|
-
// Anything we can validate without hitting the server belongs here.
|
|
101
|
-
//
|
|
102
|
-
// --repo path: requires git installed, writable target, and an empty target
|
|
103
|
-
// (since `git clone` refuses non-empty destinations and we don't destructively
|
|
104
|
-
// wipe local files). To bind a non-empty directory to a MAAF app, use `ms app
|
|
105
|
-
// init` instead.
|
|
106
|
-
//
|
|
107
|
-
// --repo none path: no source-control git (no `git init`, no `git clone` of a
|
|
108
|
-
// user-supplied remote). Git itself is still required, because the template
|
|
109
|
-
// download is a sparse `git clone` of the github-hosted template repo —
|
|
110
|
-
// hence `ensureGitInstalled` runs unconditionally below.
|
|
111
|
-
// ──────────────────────────────────────────────────────────────────────────
|
|
112
|
-
const usePreflightSpinner = !jsonMode && process.stdout.isTTY;
|
|
113
|
-
if (!jsonMode && !usePreflightSpinner) {
|
|
114
|
-
printInfo('Running preflight checks...');
|
|
115
|
-
}
|
|
116
|
-
// Spinner runs only in TTY interactive mode; --json keeps stdout clean and
|
|
117
|
-
// non-TTY (CI, piped output) uses plain prose so log files stay readable.
|
|
118
|
-
// Most preflight checks are sync, so the spinner frame can pause while a
|
|
119
|
-
// check runs; we still update the status label before each check so users
|
|
120
|
-
// always see the current step. The try/finally guarantees we restore the
|
|
121
|
-
// cursor even if a preflight check throws.
|
|
122
|
-
const preflightSpinner = usePreflightSpinner ? new CliSpinner() : null;
|
|
123
|
-
preflightSpinner?.start('Running preflight checks...');
|
|
124
|
-
try {
|
|
125
|
-
// --repo none is incompatible with --repository-id: the former opts out of any
|
|
126
|
-
// platform-managed git binding, the latter forces one. Fail fast before any
|
|
127
|
-
// server call so we don't half-bind the app.
|
|
128
|
-
if (repoType === 'none' && repositoryId) {
|
|
129
|
-
throw new UsageError("'--repo none' is incompatible with '--repository-id'. " +
|
|
130
|
-
"Use '--repo none' for an app with no git binding, or omit '--repo' (or pass a repo URL) to use a backing repository.");
|
|
131
|
-
}
|
|
132
|
-
preflightSpinner?.update('Validating template source...');
|
|
133
|
-
ensureTemplateSourceValid(template);
|
|
134
|
-
preflightSpinner?.update('Checking git installation...');
|
|
135
|
-
ensureGitInstalled();
|
|
136
|
-
preflightSpinner?.update('Verifying target directory is writable...');
|
|
137
|
-
ensureTargetDirectoryWritable(appDir);
|
|
138
|
-
if (repoType === 'github') {
|
|
139
|
-
// RepoSelection is a flat interface (not a discriminated union), so `remoteUrl`
|
|
140
|
-
// doesn't auto-narrow to `string` here even though the github branch guarantees it.
|
|
141
|
-
preflightSpinner?.update('Verifying target directory is empty...');
|
|
142
|
-
ensureRepoTargetDirectoryEmpty(appDir);
|
|
143
|
-
// Pre-network: cheap partial clone into a temp dir + ls-tree HEAD to detect
|
|
144
|
-
// a non-empty remote before createAsync runs. Catches the rejection case
|
|
145
|
-
// without leaving a server-side app or scaffolded files in
|
|
146
|
-
// appDir. Cheapest probe shape: --depth=1 --filter=blob:none --no-checkout
|
|
147
|
-
// pulls refs + the tip commit + its tree(s) only (no blob bytes, no working
|
|
148
|
-
// tree). On any probe error (network, auth, server doesn't support partial
|
|
149
|
-
// clone, etc.) we swallow and let the subsequent cloneRepo emit its
|
|
150
|
-
// friendlier error — see ensureExternalRepoIsEmpty for the rationale.
|
|
151
|
-
preflightSpinner?.update(`Verifying ${remoteUrl} is empty...`);
|
|
152
|
-
ensureExternalRepoIsEmpty(remoteUrl);
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
preflightSpinner?.update('Verifying target directory is empty...');
|
|
156
|
-
ensureTargetDirectoryEmpty(appDir);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
finally {
|
|
160
|
-
preflightSpinner?.stop();
|
|
161
|
-
}
|
|
162
|
-
// ─── End preflight ────────────────────────────────────────────────────────
|
|
163
|
-
// The debug env-var override (MS_CLI_MAAF_DEBUG_ENVIRONMENT_ID) is honored by ArgumentProvider
|
|
164
|
-
// and surfaced via getEnvironmentId(), which also owns explicit option resolution. When set,
|
|
165
|
-
// skip the automatic environment-selection API call entirely. Without an explicit id,
|
|
166
|
-
// getEnvironmentId() returns undefined and the automatic environment lookup runs.
|
|
167
|
-
const preResolvedEnvironmentId = await resolveEnvironmentId(argumentProvider, {
|
|
168
|
-
failIfMissing: false,
|
|
169
|
-
});
|
|
170
|
-
// Fire off PDE routing in parallel with the remaining option prompts. The result is awaited
|
|
171
|
-
// immediately before createAsync, so prompt latency is hidden behind the network call.
|
|
172
|
-
// Skipped entirely when the env id is pre-resolved (--environment-id flag or debug override).
|
|
173
|
-
const routingEnvPromise = preResolvedEnvironmentId
|
|
174
|
-
? undefined
|
|
175
|
-
: startPdeRoutingAsync(argumentProvider, tenantId, logger, 'CreateMaafApp');
|
|
176
|
-
const description = await argumentProvider.getOption('description',
|
|
177
|
-
/* ignorePrompt */ true);
|
|
178
|
-
const buildPath = await argumentProvider.getOption('buildPath', /* ignorePrompt */ true);
|
|
179
|
-
const buildCommand = await argumentProvider.getOption('buildCommand',
|
|
180
|
-
/* ignorePrompt */ true);
|
|
181
|
-
const buildEntryPoint = await argumentProvider.getOption('buildEntryPoint',
|
|
182
|
-
/* ignorePrompt */ true);
|
|
183
|
-
// Shared environment-routing logic between CreateMaafApp and Init.
|
|
184
|
-
// `awaitRoutingEnvironmentAsync` prints a `--environment-id` hint on any
|
|
185
|
-
// failure — HTTP error codes, `operationSuccess: false`, and exceptions.
|
|
186
|
-
const environmentId = await awaitRoutingEnvironmentAsync(preResolvedEnvironmentId, routingEnvPromise);
|
|
187
|
-
argumentProvider.updateEnvironmentId(environmentId);
|
|
188
|
-
// Re-check the directory invariant right before the server call. The same
|
|
189
|
-
// check ran in preflight, but the routing-env resolution between then and
|
|
190
|
-
// now is async and may take seconds — long enough for the user (or another
|
|
191
|
-
// tool) to drop a file (or ms.config.json) into appDir. Repeating the check
|
|
192
|
-
// here keeps the TOCTOU window between "directory looks fine" and
|
|
193
|
-
// "createAsync succeeded" as small as possible without creating a server-side
|
|
194
|
-
// app before local invariants are verified.
|
|
195
|
-
if (repoType === 'github') {
|
|
196
|
-
ensureRepoTargetDirectoryEmpty(appDir);
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
ensureTargetDirectoryEmpty(appDir);
|
|
200
|
-
}
|
|
201
|
-
// Read --open-browser alongside --json so the recovery DCF helper has both
|
|
202
|
-
// inputs ready without a second async option read inside the catch block.
|
|
203
|
-
// Commander converts kebab-case flag names to camelCase property keys;
|
|
204
|
-
// the camelName constant keeps this lookup in sync with OpenBrowser.name.
|
|
205
|
-
const openBrowser = (await argumentProvider.getOption(CreateMaafAppArguments.OpenBrowser.camelName,
|
|
206
|
-
/* ignorePrompt */ true)) ?? false;
|
|
207
|
-
// Forces DCF re-authentication even when a valid mapping exists.
|
|
208
|
-
const forceReauth = (await argumentProvider.getOption(CreateMaafAppArguments.ForceReauth.camelName,
|
|
209
|
-
/* ignorePrompt */ true)) ?? false;
|
|
210
|
-
// JSON mode (github flow only): emit a structured `create-validation` event
|
|
211
|
-
// right before the server call so automation parsing NDJSON sees the
|
|
212
|
-
// validation→createAsync boundary — needed because the github flow has a
|
|
213
|
-
// catch-and-retry branch where validation precedes a recoverable DCF.
|
|
214
|
-
// Gated to `github` so we don't change the NDJSON wire contract for
|
|
215
|
-
// existing `native` / `none` `--json` consumers.
|
|
216
|
-
if (jsonMode && repoType === 'github') {
|
|
217
|
-
printJsonLine({ phase: 'create-validation' });
|
|
218
|
-
}
|
|
219
|
-
// Hoisted so the fixed-shape params are defined once and reused across the
|
|
220
|
-
// first attempt and the post-DCF retry. `forceReauth` is injected per-call
|
|
221
|
-
// via `isRetry` so the retry does not re-trigger the server-side mapping
|
|
222
|
-
// bypass against the just-refreshed mapping.
|
|
223
|
-
const baseActionsParams = {
|
|
224
|
-
displayName,
|
|
225
|
-
description,
|
|
226
|
-
repositoryId,
|
|
227
|
-
remoteUrl,
|
|
228
|
-
repoType,
|
|
229
|
-
origin: getSettings().origin,
|
|
230
|
-
};
|
|
231
|
-
const runCreate = ({ isRetry, }) => createAsync({
|
|
232
|
-
tenantId,
|
|
233
|
-
environmentId,
|
|
234
|
-
logger,
|
|
235
|
-
actionsParams: {
|
|
236
|
-
...baseActionsParams,
|
|
237
|
-
...(forceReauth && !isRetry && { forceReauth: true }),
|
|
238
|
-
},
|
|
239
|
-
});
|
|
240
|
-
// On `repoType: 'github'`, wrap createAsync with the DCF catch-and-retry:
|
|
241
|
-
// a missing/expired GitHub identity mapping is recovered in-band by running
|
|
242
|
-
// DCF and retrying once; any other recognized server error is mapped to a
|
|
243
|
-
// friendly CLI error. Non-github flows pass through untouched. See
|
|
244
|
-
// `withGitHubDcfRecoveryAsync` for the full contract.
|
|
245
|
-
//
|
|
246
|
-
// Any server error that escapes the DCF wrapper (all repo types) is routed
|
|
247
|
-
// through `translateCreateError`, which keys off the HTTP status code to
|
|
248
|
-
// surface an actionable message (e.g. a 403 becomes a permission error naming
|
|
249
|
-
// the environment) instead of the raw `HTTP error status: ...` blob from the RP.
|
|
250
|
-
let createResult;
|
|
251
|
-
try {
|
|
252
|
-
createResult = await withGitHubDcfRecoveryAsync(runCreate, {
|
|
253
|
-
repoType,
|
|
254
|
-
externalRepoUrl: remoteUrl,
|
|
255
|
-
tenantId,
|
|
256
|
-
jsonMode,
|
|
257
|
-
openBrowser,
|
|
258
|
-
verb: 'app create',
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
catch (createError) {
|
|
262
|
-
const translated = translateCreateError(createError, { repoType, environmentId });
|
|
263
|
-
if (translated)
|
|
264
|
-
throw translated;
|
|
265
|
-
throw createError;
|
|
266
|
-
}
|
|
267
|
-
const { app, cloneUrl } = createResult;
|
|
268
|
-
// Only the `native` flow expects a GRS clone URL — it's the origin for the first
|
|
269
|
-
// local push to the auto-provisioned platform-managed repo, which GRS seeds with
|
|
270
|
-
// an initial commit on `main`. `github` binds an external GitHub repo (no GRS)
|
|
271
|
-
// and `none` is by-design source-control-free, so neither produces a `cloneUrl`.
|
|
272
|
-
// Missing on `native` is a server bug — the hoisted check below guards both the
|
|
273
|
-
// pretty-output `(clone URL: undefined)` and JSON-envelope `gitRemoteUrl: undefined`
|
|
274
|
-
// failure modes that would otherwise leak through.
|
|
275
|
-
if (repoType === 'native' && !cloneUrl) {
|
|
276
|
-
const recoveryHint = buildOrphanedAppRecoveryHint(app.id, app.environmentId);
|
|
277
|
-
throw new AppError(`App '${app.displayName}' was created on the server, but creating a git repository failed. ` +
|
|
278
|
-
`This is a platform-side issue; please report it. ` +
|
|
279
|
-
`In the meantime, the partial app needs to be cleaned up.\n` +
|
|
280
|
-
recoveryHint);
|
|
281
|
-
}
|
|
282
|
-
// Set up local files. Runs after the API calls succeed; if any step here
|
|
283
|
-
// fails the server app is already created. The branch per `repoType`:
|
|
284
|
-
// - native: init local git repo + GCM config for the auto-provisioned GRS
|
|
285
|
-
// repo (seeded with an initial commit on `main`), overlay the
|
|
286
|
-
// template, then write ms.config.json. The push phase reconciles
|
|
287
|
-
// the scaffold onto that seeded history before pushing.
|
|
288
|
-
// - github: clone the user's external repo, sanity-check it's empty,
|
|
289
|
-
// overlay the template, then write ms.config.json.
|
|
290
|
-
// - none: no git, no clone — mkdir -p, overlay the template, write ms.config.json.
|
|
291
|
-
let pushOutcome = null;
|
|
292
|
-
try {
|
|
293
|
-
if (repoType === 'github') {
|
|
294
|
-
// External GitHub path: clone the developer's repo. Auth flows through
|
|
295
|
-
// the user's existing git credential setup (gh, GCM browser OAuth, SSH key, PAT,
|
|
296
|
-
// x509 client cert, etc.); the CLI does not inject any tokens at this layer (the
|
|
297
|
-
// Microsoft GitHub App is server-side only per the MAAF GitHub Integration design
|
|
298
|
-
// doc Requirement 1). The post-clone empty-check that used to live here moved
|
|
299
|
-
// to the preflight (ensureExternalRepoIsEmpty), so by the time we get here the
|
|
300
|
-
// remote is known to be empty and the clone produces an empty working tree.
|
|
301
|
-
cloneRepo({ directory: appDir, repoUrl: remoteUrl });
|
|
302
|
-
// Safety net: the pre-network probe (ensureExternalRepoIsEmpty) is fail-OPEN
|
|
303
|
-
// on errors (e.g. os.tmpdir() inaccessible, server doesn't support partial
|
|
304
|
-
// clone). When that happens, the actual cloneRepo may have pulled content
|
|
305
|
-
// we missed. One last readdirSync of appDir guarantees we don't silently
|
|
306
|
-
// overlay the template onto the user's files.
|
|
307
|
-
// The repo must be _completely_ empty — including hidden / dotfiles like
|
|
308
|
-
// .gitignore, .gitattributes, README, LICENSE, .git-credentials, etc.
|
|
309
|
-
// We only filter `.git` itself (the internal directory created by clone);
|
|
310
|
-
// any other entry, hidden or not, means the user has prior content here.
|
|
311
|
-
const workingTreeEntries = fs.readdirSync(appDir).filter((entry) => entry !== '.git');
|
|
312
|
-
if (workingTreeEntries.length > 0) {
|
|
313
|
-
throw new UsageError(`Repository ${remoteUrl} is not empty (must contain no files of any kind, including hidden files like .gitignore, .gitattributes, README, or LICENSE). Choose a different repository to create an app or run 'ms app init' to update the existing app.\n\n` +
|
|
314
|
-
buildOrphanedAppRecoveryHint(app.id, app.environmentId));
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
else if (repoType === 'native') {
|
|
318
|
-
initLocalRepo({
|
|
319
|
-
directory: appDir,
|
|
320
|
-
gitUrl: cloneUrl,
|
|
321
|
-
loginAuthority: argumentProvider.getLoginAuthority(tenantId),
|
|
322
|
-
authResource: argumentProvider.getAuthResourceUrl(),
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
// --repo none: no git setup. Ensure the target dir exists so the
|
|
327
|
-
// subsequent downloadTemplate and writeRepoConfig calls can land their
|
|
328
|
-
// files. The preflight already verified the dir is empty.
|
|
329
|
-
fs.mkdirSync(appDir, { recursive: true });
|
|
330
|
-
}
|
|
331
|
-
if (!jsonMode) {
|
|
332
|
-
printInfo(`Fetching template '${template}' into ${appDir}...`);
|
|
333
|
-
}
|
|
334
|
-
downloadTemplate(template, { dir: appDir });
|
|
335
|
-
// Pin the CLI into the app so a later package install provides a project-local
|
|
336
|
-
// `ms` — resolved by `npx ms` / `pnpm exec` / `bun x` ahead of any globally-
|
|
337
|
-
// installed CLI — at the version it was created with (or the latest published
|
|
338
|
-
// version for a prerelease build). Runs for every repo flow (the template, and
|
|
339
|
-
// therefore its package.json, lands via downloadTemplate above regardless of
|
|
340
|
-
// `--repo`).
|
|
341
|
-
await pinCliIntoAppPackageJson(appDir, jsonMode, argumentProvider.getHttpClient());
|
|
342
|
-
const config = buildMaafAppConfig({
|
|
343
|
-
appId: app.id,
|
|
344
|
-
appDisplayName: app.displayName,
|
|
345
|
-
description: app.description,
|
|
346
|
-
environmentId: app.environmentId,
|
|
347
|
-
repoType,
|
|
348
|
-
cloud: argumentProvider.getCloud(),
|
|
349
|
-
buildPath,
|
|
350
|
-
buildCommand,
|
|
351
|
-
buildEntryPoint,
|
|
352
|
-
// Only the `native` flow has a platform-managed git binding. `github` tracks
|
|
353
|
-
// external binding server-side via `externalRepo`, and `none` intentionally has
|
|
354
|
-
// no platform-managed binding. Omit `repositoryId` for both so downstream verbs
|
|
355
|
-
// key off `repoType` instead of a placeholder value.
|
|
356
|
-
repositoryId: repoType === 'native' ? app.repositoryId : undefined,
|
|
357
|
-
// externalRepoUrl is persisted only for github-bound apps so that post-create verbs
|
|
358
|
-
// (build, deploy) know which GitHub host to authenticate against during inline DCF
|
|
359
|
-
// recovery without re-prompting the user for the URL.
|
|
360
|
-
externalRepoUrl: repoType === 'github' ? remoteUrl : undefined,
|
|
361
|
-
});
|
|
362
|
-
await writeRepoConfig(path.join(appDir, AppConfigFileName), config);
|
|
363
|
-
// Auto commit + push for git-backed flows (native + github). The `none` flow
|
|
364
|
-
// has no remote, so it's skipped. Push failure is non-fatal — see the warning
|
|
365
|
-
// path in commitAndPushScaffoldAsync.
|
|
366
|
-
if (repoType !== 'none') {
|
|
367
|
-
pushOutcome = await commitAndPushScaffoldAsync(appDir, jsonMode, repoType === 'native' ? cloneUrl : undefined);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
catch (setupError) {
|
|
371
|
-
// UsageError carries already-actionable messages (e.g. "repo already contains an
|
|
372
|
-
// app — try ms app init") and, for the non-native flows that raise it, its own
|
|
373
|
-
// recovery hint. Let those through unwrapped. The native flow has already created
|
|
374
|
-
// the server app + repo by the time any setup step throws, so it always routes
|
|
375
|
-
// through the generic re-messaging below to surface the cleanup hint.
|
|
376
|
-
if (setupError instanceof UsageError && repoType !== 'native') {
|
|
377
|
-
throw setupError;
|
|
378
|
-
}
|
|
379
|
-
const detail = setupError instanceof Error ? setupError.message : String(setupError);
|
|
380
|
-
const message = `App '${app.displayName}' was created, but local setup failed: ${detail}\n` +
|
|
381
|
-
`The local directory ${appDir} may contain partial files; remove them or choose a new directory before retrying.\n` +
|
|
382
|
-
buildOrphanedAppRecoveryHint(app.id, app.environmentId);
|
|
383
|
-
// Re-message a typed AppError in place rather than re-wrapping it, so the
|
|
384
|
-
// failure category survives the setup-recovery prefix intact: a classified
|
|
385
|
-
// AuthenticationError keeps its exit code (3), name, errorData, AND its
|
|
386
|
-
// subclass identity (`instanceof AuthenticationError` still holds for any
|
|
387
|
-
// future handler that branches on the class). Constructing a fresh AppError
|
|
388
|
-
// would downgrade everything to exit 1 and erase the subclass. The original
|
|
389
|
-
// message is preserved as `detail` inside the new message, so nothing is lost.
|
|
390
|
-
if (setupError instanceof AppError) {
|
|
391
|
-
setupError.message = message;
|
|
392
|
-
throw setupError;
|
|
393
|
-
}
|
|
394
|
-
throw new AppError(message);
|
|
395
|
-
}
|
|
396
|
-
if (jsonMode) {
|
|
397
|
-
// `appId` is the bare GUID returned by the server (`MaafAppDefinition.id`) and
|
|
398
|
-
// also written to ms.config.json — used by every subsequent CLI command
|
|
399
|
-
// (build, deploy, info, etc.). `gitRemoteUrl` is the GRS clone URL and is only
|
|
400
|
-
// present for the `native` flow (the only flow that auto-provisions a
|
|
401
|
-
// platform-managed git repo). `externalRepoUrl` is the user-supplied external
|
|
402
|
-
// GitHub URL and only appears in the `github` flow. `repoType` is always emitted so
|
|
403
|
-
// automation can detect which source-control mode the app was created in.
|
|
404
|
-
printJsonSuccess({
|
|
405
|
-
appId: app.id,
|
|
406
|
-
repoType,
|
|
407
|
-
...(repoType === 'github' && remoteUrl && { externalRepoUrl: remoteUrl }),
|
|
408
|
-
...(repoType === 'native' && cloneUrl && { gitRemoteUrl: cloneUrl }),
|
|
409
|
-
appDir,
|
|
410
|
-
...(pushOutcome && { push: pushOutcome }),
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
else {
|
|
414
|
-
printSuccess(`Created app '${app.displayName}' in ${appDir}.`);
|
|
415
|
-
if (repoType === 'github') {
|
|
416
|
-
printInfo(`Bound to external repository: ${remoteUrl}.`);
|
|
417
|
-
}
|
|
418
|
-
else if (repoType === 'none') {
|
|
419
|
-
printInfo('Your app has been created. Run `git init` (or your VCS of choice) when ready; ' +
|
|
420
|
-
'subsequent `ms app deploy` calls do not require a git remote.');
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
* Commits the scaffolded files and pushes to the remote. Called by both `native`
|
|
426
|
-
* and `github` flows after writeRepoConfig.
|
|
427
|
-
*
|
|
428
|
-
* Failure is non-fatal: prints a warning with the retry command and returns
|
|
429
|
-
* `{ success: false, ... }`. The server-side app and local scaffold are unchanged.
|
|
430
|
-
*
|
|
431
|
-
* All three git commands go through {@link runGit}, so stdin is ignored (the
|
|
432
|
-
* child can never block waiting for input) and stdout is discarded (git's
|
|
433
|
-
* progress prose stays out of our pretty output). Stderr handling follows the
|
|
434
|
-
* runGit policy: the un-classified `add`/`commit` steps re-emit git's stderr on
|
|
435
|
-
* failure, and the `push` step either streams stderr live (un-classified github
|
|
436
|
-
* flow, `network: true`) or pipes it for classification (native flow) — either
|
|
437
|
-
* way git's own error context reaches the user alongside our warning. A
|
|
438
|
-
* classified push error is caught here, so its exit code never propagates;
|
|
439
|
-
* classification only shapes the warning text and the `--json` error payload.
|
|
440
|
-
*
|
|
441
|
-
* Commit identity (user.name / user.email) is read by git itself from
|
|
442
|
-
* local-then-global config — we pass nothing. Missing identity surfaces as
|
|
443
|
-
* git's own descriptive commit error via runGit's stderr handling.
|
|
444
|
-
*/
|
|
445
|
-
export async function commitAndPushScaffoldAsync(appDir, jsonMode, nativeGitUrl) {
|
|
446
|
-
// Full add+commit+push sequence: any of the three commands may have been the
|
|
447
|
-
// one that failed (e.g. `git commit` errors when user.name/user.email aren't
|
|
448
|
-
// set), so re-running just `git push` wouldn't recover. The sequence is
|
|
449
|
-
// idempotent: rerunning `git add .` and `git commit` on an already-committed
|
|
450
|
-
// state either no-ops or errors with "nothing to commit", in which case
|
|
451
|
-
// `git push` still pushes the existing commit.
|
|
452
|
-
//
|
|
453
|
-
// Native (GRS) has no safe one-line recovery: the failure could be at the
|
|
454
|
-
// fetch/reconcile step (scaffold not yet re-parented onto the seeded main) or
|
|
455
|
-
// at the final push (already re-parented), and a single copy-paste command
|
|
456
|
-
// can't be correct for both. So we surface no command for native and instead
|
|
457
|
-
// point the user at the local scaffold below.
|
|
458
|
-
const retryCommand = nativeGitUrl
|
|
459
|
-
? undefined
|
|
460
|
-
: `git add . && git commit -m "${SCAFFOLD_COMMIT_MESSAGE}" && git push -u origin HEAD`;
|
|
461
|
-
try {
|
|
462
|
-
runGit(['add', '.'], { cwd: appDir });
|
|
463
|
-
runGit(['commit', '-m', SCAFFOLD_COMMIT_MESSAGE], { cwd: appDir });
|
|
464
|
-
if (nativeGitUrl) {
|
|
465
|
-
reconcileNativeScaffoldWithSeededMain(appDir, nativeGitUrl, jsonMode);
|
|
466
|
-
}
|
|
467
|
-
runGit(['push', '-u', 'origin', 'HEAD'], {
|
|
468
|
-
cwd: appDir,
|
|
469
|
-
network: true,
|
|
470
|
-
classify: nativeGitUrl ? { action: `pushing to ${gitHostLabel(nativeGitUrl)}` } : undefined,
|
|
471
|
-
});
|
|
472
|
-
return { success: true };
|
|
473
|
-
}
|
|
474
|
-
catch (err) {
|
|
475
|
-
// Capture the entire error structurally — name + message + stack for
|
|
476
|
-
// Error instances, spread of own properties otherwise. JSON.stringify
|
|
477
|
-
// would otherwise drop Error's non-enumerable fields and emit `{}`.
|
|
478
|
-
const errorPayload = err instanceof Error
|
|
479
|
-
? { name: err.name, message: err.message, stack: err.stack }
|
|
480
|
-
: typeof err === 'object' && err !== null
|
|
481
|
-
? { ...err }
|
|
482
|
-
: { message: String(err) };
|
|
483
|
-
if (!jsonMode) {
|
|
484
|
-
// A classified native push failure (AuthenticationError / NetworkError)
|
|
485
|
-
// carries the actionable, cause-specific guidance — plus git's own output —
|
|
486
|
-
// in its message, but runGit's classify path throws *before* re-emitting
|
|
487
|
-
// stderr, so without this the human-readable terminal would only see the
|
|
488
|
-
// generic hint. (Unclassified add/commit failures and the live-stderr
|
|
489
|
-
// github push already surfaced git's output, so only re-print for the
|
|
490
|
-
// classified case to avoid duplicate noise.)
|
|
491
|
-
if (err instanceof AppError) {
|
|
492
|
-
printWarning(err.message);
|
|
493
|
-
}
|
|
494
|
-
const finishHint = retryCommand
|
|
495
|
-
? `To finish wiring it up, run:\n ${retryCommand}`
|
|
496
|
-
: `Resolve the git issue above, then finish the initial push from ${appDir}.`;
|
|
497
|
-
printWarning(`Could not commit and push the initial scaffold. Your app and local scaffold are ready. ` +
|
|
498
|
-
finishHint);
|
|
499
|
-
}
|
|
500
|
-
return { success: false, error: errorPayload, retryCommand };
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
/**
|
|
504
|
-
* Reconciles the freshly committed local scaffold with the platform-seeded
|
|
505
|
-
* `main` branch just before the native (GRS) push. GRS provisions the repo
|
|
506
|
-
* with an initial commit on `main` (a README).
|
|
507
|
-
*
|
|
508
|
-
* 1. `git fetch origin` — bring the seed commit into origin/main
|
|
509
|
-
* (retried once on a transient auth miss).
|
|
510
|
-
* 2. `git reset --soft origin/main` — move HEAD onto the seed while keeping the
|
|
511
|
-
* scaffold tree fully staged.
|
|
512
|
-
* 3. `git commit` — record the scaffold as a child of the seed.
|
|
513
|
-
*/
|
|
514
|
-
function reconcileNativeScaffoldWithSeededMain(appDir, gitUrl, jsonMode) {
|
|
515
|
-
announceGitAuthentication(gitUrl, jsonMode, 'the initial git fetch and push');
|
|
516
|
-
fetchOriginWithRetry(appDir, gitUrl);
|
|
517
|
-
const seededMain = runGit(['rev-parse', '--verify', 'origin/main'], {
|
|
518
|
-
cwd: appDir,
|
|
519
|
-
allowFailure: true,
|
|
520
|
-
emitStderr: false,
|
|
521
|
-
});
|
|
522
|
-
if (!seededMain.success) {
|
|
523
|
-
return;
|
|
524
|
-
}
|
|
525
|
-
runGit(['reset', '--soft', 'origin/main'], { cwd: appDir });
|
|
526
|
-
runGit(['commit', '-m', SCAFFOLD_COMMIT_MESSAGE], { cwd: appDir });
|
|
527
|
-
}
|
|
528
|
-
/**
|
|
529
|
-
* Fetches `origin`, retrying exactly once if the first attempt fails.
|
|
530
|
-
*
|
|
531
|
-
* The first attempt is silent (`allowFailure`, stderr piped-not-emitted) so a
|
|
532
|
-
* recoverable miss produces no scary output.
|
|
533
|
-
*/
|
|
534
|
-
function fetchOriginWithRetry(appDir, gitUrl) {
|
|
535
|
-
const firstAttempt = runGit(['fetch', 'origin'], {
|
|
536
|
-
cwd: appDir,
|
|
537
|
-
network: true,
|
|
538
|
-
allowFailure: true,
|
|
539
|
-
emitStderr: false,
|
|
540
|
-
});
|
|
541
|
-
if (firstAttempt.success) {
|
|
542
|
-
return;
|
|
543
|
-
}
|
|
544
|
-
runGit(['fetch', 'origin'], {
|
|
545
|
-
cwd: appDir,
|
|
546
|
-
network: true,
|
|
547
|
-
classify: { action: `fetching from ${gitHostLabel(gitUrl)}` },
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
const GIT_CLONE_ACCESS_FAILURE_SIGNATURES = [
|
|
551
|
-
'repository not found',
|
|
552
|
-
'fatal: repository',
|
|
553
|
-
'could not read username',
|
|
554
|
-
'terminal prompts disabled',
|
|
555
|
-
'authentication failed',
|
|
556
|
-
'permission denied',
|
|
557
|
-
'403',
|
|
558
|
-
'remote: not found',
|
|
559
|
-
];
|
|
560
|
-
function getCapturedStderr(err) {
|
|
561
|
-
const stderr = err.stderr;
|
|
562
|
-
if (typeof stderr === 'string') {
|
|
563
|
-
return stderr;
|
|
564
|
-
}
|
|
565
|
-
if (Buffer.isBuffer(stderr)) {
|
|
566
|
-
return stderr.toString();
|
|
567
|
-
}
|
|
568
|
-
if (stderr instanceof Uint8Array) {
|
|
569
|
-
return Buffer.from(stderr).toString();
|
|
570
|
-
}
|
|
571
|
-
return '';
|
|
572
|
-
}
|
|
573
|
-
function getUnderlyingCloneError(err, stderr) {
|
|
574
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
575
|
-
const trimmedStderr = stderr.trim();
|
|
576
|
-
if (!trimmedStderr || message.includes(trimmedStderr)) {
|
|
577
|
-
return message;
|
|
578
|
-
}
|
|
579
|
-
return `${message}\n${trimmedStderr}`;
|
|
580
|
-
}
|
|
581
|
-
function isGitCloneAccessFailure(stderr) {
|
|
582
|
-
const normalizedStderr = stderr.toLowerCase();
|
|
583
|
-
return GIT_CLONE_ACCESS_FAILURE_SIGNATURES.some((signature) => normalizedStderr.includes(signature));
|
|
584
|
-
}
|
|
585
|
-
// Shared remediation body for the two access-failure surfaces (the pre-create
|
|
586
|
-
// probe and the post-create clone). Both are LOCAL `git clone` failures. The
|
|
587
|
-
// external-repo clone injects no credentials/config — it relies entirely on the
|
|
588
|
-
// user's own git setup — so the CLI can't meaningfully point at a specific
|
|
589
|
-
// credential mechanism (GCM, gh, SSH, PAT, …); the guidance stays generic.
|
|
590
|
-
// It also deliberately does NOT mention the Microsoft GitHub App or
|
|
591
|
-
// `git auth refresh`, which only affect the server-side Entra↔GitHub mapping.
|
|
592
|
-
// Carries no raw git output either; the raw detail is preserved on the thrown
|
|
593
|
-
// error's `errorData` for telemetry/debug — see the throw sites below.
|
|
594
|
-
function gitHubAccessFailureGuidance() {
|
|
595
|
-
return `Make sure the repository exists and that you have access to it.`;
|
|
596
|
-
}
|
|
597
|
-
function buildGitHubCloneAccessErrorMessage({ directory, repoUrl }) {
|
|
598
|
-
return `Failed to clone '${repoUrl}' into '${directory}'. ` + gitHubAccessFailureGuidance();
|
|
599
|
-
}
|
|
600
|
-
// Pre-create variant: the probe runs BEFORE the server app is created, so the
|
|
601
|
-
// lead makes explicit that nothing was created (no cleanup / no recovery hint).
|
|
602
|
-
function buildGitHubAccessPreflightErrorMessage(repoUrl) {
|
|
603
|
-
return (`Cannot access repository '${repoUrl}', so no app was created. ` + gitHubAccessFailureGuidance());
|
|
604
|
-
}
|
|
605
|
-
function buildGenericCloneFailureMessage({ directory, repoUrl }) {
|
|
606
|
-
return `Failed to clone '${repoUrl}' into '${directory}'. See the git output above for details.`;
|
|
607
|
-
}
|
|
608
|
-
/**
|
|
609
|
-
* Clones the developer's external GitHub repo (`*.ghe.com` tenant or `github.com`) into `directory`.
|
|
610
|
-
* Auth flows through the user's existing git credential setup — the CLI does not inject
|
|
611
|
-
* tokens here. On failure, surfaces a CLI-friendly error pointing the user at the
|
|
612
|
-
* GitHub App install prerequisite. Git's stderr is captured (via `runGit`, with
|
|
613
|
-
* `emitStderr: false`) so it can be run through the access-failure classification,
|
|
614
|
-
* and is re-emitted on failure so the underlying message still appears inline
|
|
615
|
-
* above the wrapper.
|
|
616
|
-
*
|
|
617
|
-
* Targeting rules (mirrors `git clone` semantics):
|
|
618
|
-
* - directory non-existent → clone creates it
|
|
619
|
-
* - directory exists and is empty → clone fills it
|
|
620
|
-
* - directory exists and is non-empty → clone fails (caller's pre-network guard
|
|
621
|
-
* should reject this case earlier with a clearer message)
|
|
622
|
-
*/
|
|
623
|
-
export function cloneRepo({ directory, repoUrl }) {
|
|
624
|
-
try {
|
|
625
|
-
// Pipe + capture stderr (no `network`, so it is not inherited) so the catch
|
|
626
|
-
// can run it through `isGitCloneAccessFailure`; `emitStderr: false` lets the
|
|
627
|
-
// catch own the single re-emission below instead of runGit double-printing.
|
|
628
|
-
runGit(['clone', repoUrl, directory], { emitStderr: false });
|
|
629
|
-
}
|
|
630
|
-
catch (err) {
|
|
631
|
-
const stderr = getCapturedStderr(err);
|
|
632
|
-
if (stderr) {
|
|
633
|
-
// Re-emit git's own output live so the raw detail is still visible to the
|
|
634
|
-
// user (and in logs) without polluting the thrown error's message.
|
|
635
|
-
process.stderr.write(stderr);
|
|
636
|
-
}
|
|
637
|
-
const message = isGitCloneAccessFailure(stderr)
|
|
638
|
-
? buildGitHubCloneAccessErrorMessage({ directory, repoUrl })
|
|
639
|
-
: buildGenericCloneFailureMessage({ directory, repoUrl });
|
|
640
|
-
// Keep the user-facing message clean; preserve the raw git detail on
|
|
641
|
-
// errorData for telemetry/debug rather than embedding it in the message.
|
|
642
|
-
// Clone failures span remote access and local git credential configuration.
|
|
643
|
-
throw new ConfigurationError(message, {
|
|
644
|
-
underlyingError: getUnderlyingCloneError(err, stderr),
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
export function initLocalRepo({ directory, gitUrl, loginAuthority, authResource, }) {
|
|
649
|
-
const gcmConfig = buildGcmConfigOrThrow({ gitUrl, loginAuthority, authResource });
|
|
650
|
-
gitInit(directory);
|
|
651
|
-
writeGcmConfig(directory, gcmConfig);
|
|
652
|
-
addOrUpdateRemote(directory, gitUrl);
|
|
653
|
-
}
|
|
654
|
-
/**
|
|
655
|
-
* Builds the per-host GCM OAuth config, re-wrapping any URL/protocol validation
|
|
656
|
-
* failure from {@link buildGcmConfig} as a `ConfigurationError` so the verb's
|
|
657
|
-
* error handling treats an invalid clone URL as a user-actionable setup problem.
|
|
658
|
-
*/
|
|
659
|
-
function buildGcmConfigOrThrow({ gitUrl, loginAuthority, authResource, }) {
|
|
660
|
-
try {
|
|
661
|
-
return buildGcmConfig({ gitUrl, loginAuthority, authResource });
|
|
662
|
-
}
|
|
663
|
-
catch (err) {
|
|
664
|
-
throw new ConfigurationError(`Git credential helper setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
/**
|
|
668
|
-
* Creates the target directory (idempotent) and initializes an empty git repo
|
|
669
|
-
* whose initial branch is `main`.
|
|
670
|
-
*/
|
|
671
|
-
function gitInit(directory) {
|
|
672
|
-
fs.mkdirSync(directory, { recursive: true });
|
|
673
|
-
runGit(['init'], { cwd: directory });
|
|
674
|
-
// use `git symbolic-ref HEAD refs/heads/main` to set the initial branch to `main` instead of `master`. This is
|
|
675
|
-
// used instead of `git init -b main` / `-c init.defaultBranch=main` because both
|
|
676
|
-
// of those landed in git 2.28, one minor above this package's enforced 2.27 floor
|
|
677
|
-
runGit(['symbolic-ref', 'HEAD', 'refs/heads/main'], { cwd: directory });
|
|
678
|
-
}
|
|
679
|
-
/** Writes GCM config before pushing so the first network call is already authenticated. */
|
|
680
|
-
function writeGcmConfig(directory, gcmConfig) {
|
|
681
|
-
for (const [key, value] of gcmConfig) {
|
|
682
|
-
runGit(['config', '--local', key, value], { cwd: directory });
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* Adds `origin`, tolerating the already-exists case by falling back to
|
|
687
|
-
* `set-url`. `git remote add` fails if origin already exists. Capture stderr
|
|
688
|
-
* (allowFailure) so we can inspect the message and only fall back to `set-url`
|
|
689
|
-
* for that specific case — other failures (permissions, corrupt repo) must
|
|
690
|
-
* propagate rather than produce a misleading set-url error.
|
|
691
|
-
*/
|
|
692
|
-
function addOrUpdateRemote(directory, gitUrl) {
|
|
693
|
-
const addRemote = runGit(['remote', 'add', 'origin', gitUrl], {
|
|
694
|
-
cwd: directory,
|
|
695
|
-
allowFailure: true,
|
|
696
|
-
emitStderr: false,
|
|
697
|
-
});
|
|
698
|
-
if (!addRemote.success) {
|
|
699
|
-
if (!addRemote.stderr.includes('already exists')) {
|
|
700
|
-
process.stderr.write(addRemote.stderr);
|
|
701
|
-
// `runGit` always populates `error` on the failure variant, so no fallback
|
|
702
|
-
// is needed (the GitResult union guarantees it here).
|
|
703
|
-
throw addRemote.error;
|
|
704
|
-
}
|
|
705
|
-
runGit(['remote', 'set-url', 'origin', gitUrl], { cwd: directory });
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
/**
|
|
709
|
-
* Best-effort host label for a git remote URL. Returns the URL's host, or — when
|
|
710
|
-
* the string isn't a parseable URL — the original string. Used for human-facing
|
|
711
|
-
* action labels (auth/push messages) where a malformed URL must not turn a
|
|
712
|
-
* cosmetic label into a thrown `Invalid URL` that masquerades as the real
|
|
713
|
-
* failure. The platform issues these URLs, so the fallback is effectively
|
|
714
|
-
* unreachable, but the guard keeps the label site from becoming a crash site.
|
|
715
|
-
*/
|
|
716
|
-
function gitHostLabel(gitUrl) {
|
|
717
|
-
try {
|
|
718
|
-
return new URL(gitUrl).host;
|
|
719
|
-
}
|
|
720
|
-
catch {
|
|
721
|
-
return gitUrl;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
/**
|
|
725
|
-
* Prints the pre-network authentication notice. The first git network call triggers
|
|
726
|
-
* GCM's OAuth flow if the user has no cached credentials, which can pop a
|
|
727
|
-
* browser without warning. Tell the user up front so they don't see the browser
|
|
728
|
-
* as a surprise (and know which host / account to authenticate against). Skipped
|
|
729
|
-
* under `--json` so the prose doesn't end up interleaved with the JSON envelope
|
|
730
|
-
* on stdout.
|
|
731
|
-
*/
|
|
732
|
-
function announceGitAuthentication(gitUrl, jsonMode, action) {
|
|
733
|
-
if (!jsonMode) {
|
|
734
|
-
printInfo(`Authenticating to ${gitHostLabel(gitUrl)} for ${action}. ` +
|
|
735
|
-
'A browser window may open. Sign in with the account associated with this tenant.');
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
// ─── Recovery hint for post-create failures ─────────────────────────────────
|
|
739
|
-
// Once createAsync returns, the MAAF app + GRS repo exist on the server; any
|
|
740
|
-
// later failure (no gitUrl, initLocalRepo, downloadTemplate, writeRepoConfig)
|
|
741
|
-
// strands them. Append this hint to the error message so the user can copy a
|
|
742
|
-
// working `app delete --force` line straight from their terminal and retry.
|
|
743
|
-
// ────────────────────────────────────────────────────────────────────────────
|
|
744
|
-
export function buildOrphanedAppRecoveryHint(serverAppId, environmentId) {
|
|
745
|
-
return (`The server app is still in environment ${environmentId} (id: ${serverAppId}).\n` +
|
|
746
|
-
`If you want to clean it up before retrying, run the following command:\n` +
|
|
747
|
-
` ${CLI_BINARY_NAME} app delete --app ${serverAppId} --environment-id ${environmentId} --force`);
|
|
748
|
-
}
|
|
749
|
-
/** Extracts `error.message` from a JSON `{ error: { message } }` envelope; `undefined` otherwise. */
|
|
750
|
-
function extractServerMessage(err) {
|
|
751
|
-
if (!err.body)
|
|
752
|
-
return undefined;
|
|
753
|
-
try {
|
|
754
|
-
const parsed = JSON.parse(err.body);
|
|
755
|
-
if (typeof parsed?.error?.message === 'string' && parsed.error.message.trim()) {
|
|
756
|
-
return parsed.error.message;
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
catch {
|
|
760
|
-
// not JSON; fall through
|
|
761
|
-
}
|
|
762
|
-
return undefined;
|
|
763
|
-
}
|
|
764
|
-
/**
|
|
765
|
-
* Translates a server error thrown while creating the app (the `createAsync`
|
|
766
|
-
* RP/GRS calls) into a user-facing {@link AppError}, or returns `null` to signal
|
|
767
|
-
* "not handled — propagate the original". For the handled status codes below we
|
|
768
|
-
* key off the HTTP status to pick the error category (which drives the exit code)
|
|
769
|
-
* and surface an actionable message rather than the raw HTTP error blob
|
|
770
|
-
* (`HTTP error status: 403 for POST ...: {...}`). Unrecognized statuses (e.g. 500)
|
|
771
|
-
* return `null` and propagate unchanged, so the raw error can still surface for
|
|
772
|
-
* those — we only suppress the blob for the statuses we explicitly handle.
|
|
773
|
-
*
|
|
774
|
-
* The RP returns a structured `{ error: { code, message } }` envelope whose
|
|
775
|
-
* `message` is the source of truth — it names the offending principal and
|
|
776
|
-
* environment (e.g. "User '<oid>' does not have permission to create
|
|
777
|
-
* repositories in environment '<id>'."). We prefer that server message and fall
|
|
778
|
-
* back to CLI-generated text only when the body carries no usable message.
|
|
779
|
-
*
|
|
780
|
-
* Only translates {@link HttpClientError}. Errors already mapped to a typed
|
|
781
|
-
* {@link AppError} by the GitHub DCF recovery path (see `withGitHubDcfRecoveryAsync`)
|
|
782
|
-
* are passed through untouched.
|
|
783
|
-
*/
|
|
784
|
-
function translateCreateError(err, ctx) {
|
|
785
|
-
if (!(err instanceof HttpClientError))
|
|
786
|
-
return null;
|
|
787
|
-
const { environmentId } = ctx;
|
|
788
|
-
// Prefer the RP's own `error.message` — it's the source of truth and carries
|
|
789
|
-
// specifics (principal object id, environment id) the CLI can't reconstruct.
|
|
790
|
-
const serverMessage = extractServerMessage(err);
|
|
791
|
-
// The `native` (default) flow auto-provisions a platform-managed GRS repository,
|
|
792
|
-
// so a permission failure there is specifically about repository creation. The
|
|
793
|
-
// `github` / `none` flows don't provision a repo, so the denial is about creating
|
|
794
|
-
// the app itself. Used only for the fallback wording when the RP sends no message.
|
|
795
|
-
const creatingRepo = ctx.repoType === 'native';
|
|
796
|
-
// Operation-agnostic so it reads correctly whether it's appended to the RP's
|
|
797
|
-
// "...create repositories..." message, the "...create an app..." fallback, or
|
|
798
|
-
// the native/github variants — avoids a "repositories" vs "apps" mismatch.
|
|
799
|
-
const grantHint = 'Ask an admin to grant you the required permission in this environment.';
|
|
800
|
-
if (err.status === 401) {
|
|
801
|
-
return new AuthenticationError(serverMessage ??
|
|
802
|
-
'Your sign-in session has expired or is invalid. Run `ms auth login` and try again.');
|
|
803
|
-
}
|
|
804
|
-
if (err.status === 403) {
|
|
805
|
-
const base = serverMessage ??
|
|
806
|
-
(creatingRepo
|
|
807
|
-
? `You do not have permission to create repositories in environment ${environmentId}.`
|
|
808
|
-
: `You do not have permission to create an app in environment ${environmentId}.`);
|
|
809
|
-
return new AuthenticationError(`${base} ${grantHint}`);
|
|
810
|
-
}
|
|
811
|
-
if (err.status === 404) {
|
|
812
|
-
return new UsageError(serverMessage ??
|
|
813
|
-
`Environment ${environmentId} was not found. Verify the environment id and that you have access to it.`);
|
|
814
|
-
}
|
|
815
|
-
if (err.status === 409) {
|
|
816
|
-
return new UsageError(serverMessage ??
|
|
817
|
-
`An app with the same name already exists in environment ${environmentId}. Choose a different name.`);
|
|
818
|
-
}
|
|
819
|
-
if (err.status === 429 || err.status === 503) {
|
|
820
|
-
return new NetworkError(serverMessage ??
|
|
821
|
-
'The service is temporarily unavailable or rate-limited. Wait a moment and try again.');
|
|
822
|
-
}
|
|
823
|
-
return null;
|
|
824
|
-
}
|
|
825
|
-
// ─── Preflight helpers ──────────────────────────────────────────────────────
|
|
826
|
-
// All checks below run before any server call so a local misconfiguration
|
|
827
|
-
// (bad template source, unwritable directory, …) fails fast before it creates
|
|
828
|
-
// a MAAF app + GRS repo on the server. The git presence + version
|
|
829
|
-
// check lives in `Utils/GitVersionChecker.ts`.
|
|
830
|
-
// ────────────────────────────────────────────────────────────────────────────
|
|
831
|
-
export function ensureTemplateSourceValid(source) {
|
|
832
|
-
// Delegates to the github-only parser in DownloadTemplate. The parser throws
|
|
833
|
-
// `UsageError` for any unsupported shape (non-`github:` prefix, malformed
|
|
834
|
-
// URL, missing owner/repo) — which is what preflight wants: surface the
|
|
835
|
-
// problem before any server call. We discard the parsed result; the real
|
|
836
|
-
// download path re-parses at call time.
|
|
837
|
-
parseGithubTemplate(source);
|
|
838
|
-
}
|
|
839
|
-
export function ensureTargetDirectoryEmpty(appDir) {
|
|
840
|
-
// Scaffolding into a non-empty directory would mix the template with the
|
|
841
|
-
// user's files, and initLocalRepo's `git remote set-url` fallback would
|
|
842
|
-
// silently replace an existing `origin` remote. Called twice: once in
|
|
843
|
-
// preflight (fail fast before any network) and once right before
|
|
844
|
-
// createAsync (catch a TOCTOU race where the dir gets populated during
|
|
845
|
-
// routing/option resolution).
|
|
846
|
-
if (!fs.existsSync(appDir))
|
|
847
|
-
return;
|
|
848
|
-
const entries = fs.readdirSync(appDir);
|
|
849
|
-
if (entries.length > 0) {
|
|
850
|
-
throw new UsageError(`'${appDir}' is not empty. Specify an empty directory as the first argument, or run 'ms app init' to bind an existing project to a new app.`);
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
export function ensureRepoTargetDirectoryEmpty(appDir) {
|
|
854
|
-
// --repo variant: empty-dir is mandatory. `git clone` refuses non-empty
|
|
855
|
-
// destinations and we don't destructively wipe local files. To bind an
|
|
856
|
-
// existing local project to a new MAAF app, use `ms app init` instead.
|
|
857
|
-
// Called twice (preflight + just-before-createAsync) for the same TOCTOU
|
|
858
|
-
// reasons as ensureTargetDirectoryEmpty.
|
|
859
|
-
if (!fs.existsSync(appDir))
|
|
860
|
-
return;
|
|
861
|
-
const entries = fs.readdirSync(appDir);
|
|
862
|
-
if (entries.length > 0) {
|
|
863
|
-
throw new UsageError(`'${appDir}' is not empty. --repo requires an empty target directory; specify an empty directory as the first argument, move to one before running, or run 'ms app init' to bind an existing project to a new app.`);
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
/**
|
|
867
|
-
* Cheap pre-network probe to detect a non-empty remote BEFORE createAsync runs.
|
|
868
|
-
*
|
|
869
|
-
* Implementation: partial clone (`--depth=1 --filter=blob:none --no-checkout`)
|
|
870
|
-
* into an OS temp dir, then `git ls-tree -r HEAD`. The clone pulls refs + the
|
|
871
|
-
* tip commit + its tree objects only — no blob bytes, no working tree — so the
|
|
872
|
-
* bandwidth on the rejection path is tens of KB even for a multi-GB repo. The
|
|
873
|
-
* temp dir is removed in `finally`.
|
|
874
|
-
*
|
|
875
|
-
* Failure semantics:
|
|
876
|
-
* - Non-empty tree at HEAD → throws `UsageError` with the "is not empty" /
|
|
877
|
-
* "ms app init" actionable lead, BEFORE createAsync. Nothing created.
|
|
878
|
-
* - Empty tree (incl. the cleaned-up-repo edge case: commit1 add, commit2
|
|
879
|
-
* delete all) → ls-tree returns no lines → returns without throwing.
|
|
880
|
-
* - Clone fails with a recognizable access/auth signature (private repo
|
|
881
|
-
* hidden as "not found", missing local credentials, 403, …) → throws
|
|
882
|
-
* `ConfigurationError` BEFORE createAsync so we never create a server-side
|
|
883
|
-
* app the user can't clone.
|
|
884
|
-
* - Any other git error (network blip, server doesn't support --filter,
|
|
885
|
-
* temp-fs hiccup, …) → swallow and return (fail OPEN). The subsequent
|
|
886
|
-
* cloneRepo surfaces the friendlier message for the user-facing failure;
|
|
887
|
-
* we don't want this probe to become a parallel error-message surface.
|
|
888
|
-
*/
|
|
889
|
-
export function ensureExternalRepoIsEmpty(repoUrl) {
|
|
890
|
-
let probeDir;
|
|
891
|
-
try {
|
|
892
|
-
probeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ms-app-create-probe-'));
|
|
893
|
-
}
|
|
894
|
-
catch {
|
|
895
|
-
// Can't make a temp dir → punt. Real cloneRepo will surface any actionable
|
|
896
|
-
// issue (writable-fs, etc.) on the subsequent attempt.
|
|
897
|
-
return;
|
|
898
|
-
}
|
|
899
|
-
try {
|
|
900
|
-
const probeClone = runGit(['clone', '--depth=1', '--filter=blob:none', '--no-checkout', repoUrl, probeDir], { allowFailure: true, emitStderr: false });
|
|
901
|
-
if (!probeClone.success) {
|
|
902
|
-
// Clone failed. When git reports a recognizable access/auth failure
|
|
903
|
-
// (a private repo hidden as "not found", missing local credentials, a
|
|
904
|
-
// 403, etc.) fail FAST here — before createAsync — so we never create a
|
|
905
|
-
// server-side app the user can't clone. For ambiguous or
|
|
906
|
-
// transient errors (server doesn't support --filter, network blip, a
|
|
907
|
-
// temp-fs hiccup, …) stay fail-OPEN and let the later cloneRepo surface
|
|
908
|
-
// the friendlier, fuller message.
|
|
909
|
-
const stderr = probeClone.stderr;
|
|
910
|
-
if (isGitCloneAccessFailure(stderr)) {
|
|
911
|
-
// Clean user-facing message; raw git detail kept on errorData for
|
|
912
|
-
// telemetry/debug. The probe clone is silent (stderr piped, not
|
|
913
|
-
// inherited), so we don't echo the confusing internal probe command.
|
|
914
|
-
throw new ConfigurationError(buildGitHubAccessPreflightErrorMessage(repoUrl), {
|
|
915
|
-
underlyingError: getUnderlyingCloneError(probeClone.error, stderr),
|
|
916
|
-
});
|
|
917
|
-
}
|
|
918
|
-
return;
|
|
919
|
-
}
|
|
920
|
-
const lsTree = runGit(['-C', probeDir, 'ls-tree', '-r', 'HEAD'], {
|
|
921
|
-
captureStdout: true,
|
|
922
|
-
allowFailure: true,
|
|
923
|
-
emitStderr: false,
|
|
924
|
-
});
|
|
925
|
-
if (!lsTree.success) {
|
|
926
|
-
// Truly empty repo (no commits, no HEAD): ls-tree errors. Treat as empty
|
|
927
|
-
// so create proceeds; cloneRepo of a no-commits remote produces an empty
|
|
928
|
-
// working tree, which is the happy path.
|
|
929
|
-
return;
|
|
930
|
-
}
|
|
931
|
-
const lsTreeOutput = lsTree.stdout;
|
|
932
|
-
if (lsTreeOutput.trim().length > 0) {
|
|
933
|
-
// `ls-tree -r HEAD` enumerates every tracked path — including hidden
|
|
934
|
-
// ones (.gitignore, .gitattributes, etc.). Any tracked file at all
|
|
935
|
-
// means the repo isn't a valid binding target for a fresh app.
|
|
936
|
-
throw new UsageError(`Repository ${repoUrl} is not empty (must contain no tracked files of any kind, including hidden files like .gitignore, .gitattributes, README, or LICENSE). Choose a different repository to create an app or run 'ms app init' to update the existing app.`);
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
finally {
|
|
940
|
-
try {
|
|
941
|
-
fs.rmSync(probeDir, { recursive: true, force: true });
|
|
942
|
-
}
|
|
943
|
-
catch {
|
|
944
|
-
// Best-effort cleanup; a leftover temp dir is acceptable.
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
export function ensureTargetDirectoryWritable(appDir) {
|
|
949
|
-
// Probe write permission on the target dir (or its nearest existing
|
|
950
|
-
// ancestor, where mkdirSync will need to write). Catches read-only mounts
|
|
951
|
-
// and permission-denied locations before any server-side resource is
|
|
952
|
-
// created. The empty-dir check is intentionally NOT here — it runs inline
|
|
953
|
-
// just before initLocalRepo so the TOCTOU window between check and write
|
|
954
|
-
// stays as small as possible (a directory can become non-empty while the
|
|
955
|
-
// routing/createAsync calls are in flight).
|
|
956
|
-
//
|
|
957
|
-
// Best-effort caveat: `accessSync(W_OK)` is a syscall-level approximation,
|
|
958
|
-
// not a real write. On Windows in particular, NTFS ACL inheritance can grant
|
|
959
|
-
// W_OK on the ancestor while the actual CreateDirectory / CreateFile fails
|
|
960
|
-
// later (UAC virtualization, parent ACE applies but a deny ACE on the leaf
|
|
961
|
-
// does not). We accept that: catching every Windows ACL edge case requires
|
|
962
|
-
// a real mkdir+write+delete probe, which leaves debris on success and has
|
|
963
|
-
// its own TOCTOU. The recovery hint on post-create failures is the
|
|
964
|
-
// backstop when the probe is too optimistic.
|
|
965
|
-
let probe = appDir;
|
|
966
|
-
while (!fs.existsSync(probe)) {
|
|
967
|
-
const parent = path.dirname(probe);
|
|
968
|
-
if (parent === probe)
|
|
969
|
-
break;
|
|
970
|
-
probe = parent;
|
|
971
|
-
}
|
|
972
|
-
try {
|
|
973
|
-
fs.accessSync(probe, fs.constants.W_OK);
|
|
974
|
-
}
|
|
975
|
-
catch {
|
|
976
|
-
throw new ConfigurationError(`'${appDir}' is not writable. Choose a different directory or fix the permissions and retry.`);
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
function createOptionSchema(argumentProvider) {
|
|
980
|
-
argumentProvider.setDescription(HelpStrings.app.create.description);
|
|
981
|
-
argumentProvider.addExamples(HelpStrings.app.create.examples);
|
|
982
|
-
argumentProvider.consumePositionalArg('[directory]');
|
|
983
|
-
argumentProvider.addOptions([
|
|
984
|
-
{
|
|
985
|
-
flags: {
|
|
986
|
-
key: CreateMaafAppArguments.EnvironmentId.name,
|
|
987
|
-
alias: CreateMaafAppArguments.EnvironmentId.alias,
|
|
988
|
-
},
|
|
989
|
-
env: CreateMaafAppArguments.EnvironmentId.envVar,
|
|
990
|
-
description: HelpStrings.app.create.options.environmentId,
|
|
991
|
-
optionalInNonInteractive: true,
|
|
992
|
-
},
|
|
993
|
-
createDefaultStringOption({
|
|
994
|
-
flags: {
|
|
995
|
-
key: CreateMaafAppArguments.DisplayName.name,
|
|
996
|
-
alias: CreateMaafAppArguments.DisplayName.alias,
|
|
997
|
-
},
|
|
998
|
-
env: CreateMaafAppArguments.DisplayName.envVar,
|
|
999
|
-
message: CreateMaafAppArguments.DisplayName.promptMessage,
|
|
1000
|
-
description: HelpStrings.app.create.options.displayName,
|
|
1001
|
-
}),
|
|
1002
|
-
{
|
|
1003
|
-
flags: {
|
|
1004
|
-
key: CreateMaafAppArguments.Description.name,
|
|
1005
|
-
alias: CreateMaafAppArguments.Description.alias,
|
|
1006
|
-
},
|
|
1007
|
-
env: CreateMaafAppArguments.Description.envVar,
|
|
1008
|
-
description: HelpStrings.app.create.options.description,
|
|
1009
|
-
optionalInNonInteractive: true,
|
|
1010
|
-
},
|
|
1011
|
-
{
|
|
1012
|
-
flags: {
|
|
1013
|
-
key: CreateMaafAppArguments.RepositoryId.name,
|
|
1014
|
-
alias: CreateMaafAppArguments.RepositoryId.alias,
|
|
1015
|
-
},
|
|
1016
|
-
env: CreateMaafAppArguments.RepositoryId.envVar,
|
|
1017
|
-
description: HelpStrings.app.create.options.repositoryId,
|
|
1018
|
-
optionalInNonInteractive: true,
|
|
1019
|
-
},
|
|
1020
|
-
{
|
|
1021
|
-
flags: {
|
|
1022
|
-
key: CreateMaafAppArguments.Template.name,
|
|
1023
|
-
alias: CreateMaafAppArguments.Template.alias,
|
|
1024
|
-
},
|
|
1025
|
-
env: CreateMaafAppArguments.Template.envVar,
|
|
1026
|
-
default: DEFAULT_TEMPLATE,
|
|
1027
|
-
description: HelpStrings.app.create.options.template,
|
|
1028
|
-
optionalInNonInteractive: true,
|
|
1029
|
-
},
|
|
1030
|
-
{
|
|
1031
|
-
// No short alias for --repo yet; see VerbConstants.CreateMaafAppArguments.Repo.
|
|
1032
|
-
flags: {
|
|
1033
|
-
key: CreateMaafAppArguments.Repo.name,
|
|
1034
|
-
},
|
|
1035
|
-
env: CreateMaafAppArguments.Repo.envVar,
|
|
1036
|
-
description: HelpStrings.app.create.options.repo,
|
|
1037
|
-
optionalInNonInteractive: true,
|
|
1038
|
-
},
|
|
1039
|
-
createDefaultStringOption({
|
|
1040
|
-
flags: {
|
|
1041
|
-
key: CreateMaafAppArguments.BuildPath.name,
|
|
1042
|
-
alias: CreateMaafAppArguments.BuildPath.alias,
|
|
1043
|
-
},
|
|
1044
|
-
env: CreateMaafAppArguments.BuildPath.envVar,
|
|
1045
|
-
message: CreateMaafAppArguments.BuildPath.promptMessage,
|
|
1046
|
-
initialValue: CreateMaafAppArguments.BuildPath.initialValue,
|
|
1047
|
-
default: './dist',
|
|
1048
|
-
description: HelpStrings.app.create.options.buildPath,
|
|
1049
|
-
}),
|
|
1050
|
-
createDefaultStringOption({
|
|
1051
|
-
flags: {
|
|
1052
|
-
key: CreateMaafAppArguments.BuildCommand.name,
|
|
1053
|
-
alias: CreateMaafAppArguments.BuildCommand.alias,
|
|
1054
|
-
},
|
|
1055
|
-
env: CreateMaafAppArguments.BuildCommand.envVar,
|
|
1056
|
-
message: CreateMaafAppArguments.BuildCommand.promptMessage,
|
|
1057
|
-
initialValue: CreateMaafAppArguments.BuildCommand.initialValue,
|
|
1058
|
-
default: 'npm run build',
|
|
1059
|
-
description: HelpStrings.app.create.options.buildCommand,
|
|
1060
|
-
}),
|
|
1061
|
-
createDefaultStringOption({
|
|
1062
|
-
flags: {
|
|
1063
|
-
key: CreateMaafAppArguments.BuildEntryPoint.name,
|
|
1064
|
-
},
|
|
1065
|
-
env: CreateMaafAppArguments.BuildEntryPoint.envVar,
|
|
1066
|
-
message: CreateMaafAppArguments.BuildEntryPoint.promptMessage,
|
|
1067
|
-
initialValue: CreateMaafAppArguments.BuildEntryPoint.initialValue,
|
|
1068
|
-
default: 'index.html',
|
|
1069
|
-
description: HelpStrings.app.create.options.buildEntryPoint,
|
|
1070
|
-
}),
|
|
1071
|
-
]);
|
|
1072
|
-
argumentProvider.addSwitch({
|
|
1073
|
-
flags: { key: CreateMaafAppArguments.OpenBrowser.name },
|
|
1074
|
-
description: HelpStrings.app.create.options.openBrowser,
|
|
1075
|
-
});
|
|
1076
|
-
argumentProvider.addSwitch({
|
|
1077
|
-
flags: { key: CreateMaafAppArguments.ForceReauth.name },
|
|
1078
|
-
description: HelpStrings.app.create.options.forceReauth,
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
//# sourceMappingURL=CreateMaafApp.js.map
|