1# -------------------------------------------------------------------------------------------- 2# Copyright (c) Microsoft Corporation. All rights reserved. 3# Licensed under the MIT License. See License.txt in the project root for license information. 4# -------------------------------------------------------------------------------------------- 5 6from argcomplete.completers import FilesCompleter 7 8from knack.arguments import CLIArgumentType 9 10from azure.cli.core.commands.parameters import (resource_group_name_type, get_location_type, 11 get_resource_name_completion_list, file_type, 12 get_three_state_flag, get_enum_type, tags_type) 13from azure.cli.core.util import get_file_json 14from azure.cli.core.local_context import LocalContextAttribute, LocalContextAction 15from azure.cli.command_modules.appservice._appservice_utils import MSI_LOCAL_ID 16from azure.mgmt.web.models import DatabaseType, ConnectionStringType, BuiltInAuthenticationProvider, AzureStorageType 17 18from ._completers import get_hostname_completion_list 19from ._constants import FUNCTIONS_VERSIONS, FUNCTIONS_STACKS_API_JSON_PATHS, FUNCTIONS_STACKS_API_KEYS 20from ._validators import (validate_timeout_value, validate_site_create, validate_asp_create, 21 validate_add_vnet, validate_front_end_scale_factor, validate_ase_create, validate_ip_address, 22 validate_service_tag, validate_public_cloud) 23 24AUTH_TYPES = { 25 'AllowAnonymous': 'na', 26 'LoginWithAzureActiveDirectory': BuiltInAuthenticationProvider.azure_active_directory, 27 'LoginWithFacebook': BuiltInAuthenticationProvider.facebook, 28 'LoginWithGoogle': BuiltInAuthenticationProvider.google, 29 'LoginWithMicrosoftAccount': BuiltInAuthenticationProvider.microsoft_account, 30 'LoginWithTwitter': BuiltInAuthenticationProvider.twitter} 31 32MULTI_CONTAINER_TYPES = ['COMPOSE', 'KUBE'] 33FTPS_STATE_TYPES = ['AllAllowed', 'FtpsOnly', 'Disabled'] 34OS_TYPES = ['Windows', 'Linux'] 35LINUX_RUNTIMES = ['dotnet', 'node', 'python', 'java'] 36WINDOWS_RUNTIMES = ['dotnet', 'node', 'java', 'powershell'] 37ACCESS_RESTRICTION_ACTION_TYPES = ['Allow', 'Deny'] 38ASE_LOADBALANCER_MODES = ['Internal', 'External'] 39ASE_KINDS = ['ASEv2', 'ASEv3'] 40ASE_OS_PREFERENCE_TYPES = ['Windows', 'Linux'] 41 42 43# pylint: disable=too-many-statements, too-many-lines 44 45 46def load_arguments(self, _): 47 # pylint: disable=line-too-long 48 # PARAMETER REGISTRATION 49 name_arg_type = CLIArgumentType(options_list=['--name', '-n'], metavar='NAME') 50 sku_arg_type = CLIArgumentType( 51 help='The pricing tiers, e.g., F1(Free), D1(Shared), B1(Basic Small), B2(Basic Medium), B3(Basic Large), S1(Standard Small), P1V2(Premium V2 Small), P1V3(Premium V3 Small), P2V3(Premium V3 Medium), P3V3(Premium V3 Large), PC2 (Premium Container Small), PC3 (Premium Container Medium), PC4 (Premium Container Large), I1 (Isolated Small), I2 (Isolated Medium), I3 (Isolated Large), I1v2 (Isolated V2 Small), I2v2 (Isolated V2 Medium), I3v2 (Isolated V2 Large)', 52 arg_type=get_enum_type( 53 ['F1', 'FREE', 'D1', 'SHARED', 'B1', 'B2', 'B3', 'S1', 'S2', 'S3', 'P1V2', 'P2V2', 'P3V2', 'P1V3', 'P2V3', 'P3V3', 'PC2', 'PC3', 54 'PC4', 'I1', 'I2', 'I3', 'I1v2', 'I2v2', 'I3v2'])) 55 webapp_name_arg_type = CLIArgumentType(configured_default='web', options_list=['--name', '-n'], metavar='NAME', 56 completer=get_resource_name_completion_list('Microsoft.Web/sites'), 57 id_part='name', 58 help="name of the web app. If left unspecified, a name will be randomly generated. You can configure the default using `az configure --defaults web=<name>`", 59 local_context_attribute=LocalContextAttribute(name='web_name', actions=[ 60 LocalContextAction.GET])) 61 functionapp_name_arg_type = CLIArgumentType(options_list=['--name', '-n'], metavar='NAME', 62 help="name of the function app.", 63 local_context_attribute=LocalContextAttribute(name='functionapp_name', 64 actions=[ 65 LocalContextAction.GET])) 66 logicapp_name_arg_type = CLIArgumentType(options_list=['--name', '-n'], metavar='NAME', 67 help="name of the logic app.", 68 local_context_attribute=LocalContextAttribute(name='logicapp_name', 69 actions=[LocalContextAction.GET])) 70 name_arg_type_dict = { 71 'functionapp': functionapp_name_arg_type, 72 'logicapp': logicapp_name_arg_type 73 } 74 isolated_sku_arg_type = CLIArgumentType( 75 help='The Isolated pricing tiers, e.g., I1 (Isolated Small), I2 (Isolated Medium), I3 (Isolated Large)', 76 arg_type=get_enum_type(['I1', 'I2', 'I3'])) 77 78 static_web_app_sku_arg_type = CLIArgumentType( 79 help='The pricing tiers for Static Web App', 80 arg_type=get_enum_type(['Free', 'Standard']) 81 ) 82 83 functionapp_runtime_strings, functionapp_runtime_to_version_strings = _get_functionapp_runtime_versions() 84 85 # use this hidden arg to give a command the right instance, that functionapp commands 86 # work on function app and webapp ones work on web app 87 with self.argument_context('webapp') as c: 88 c.ignore('app_instance') 89 c.argument('resource_group_name', arg_type=resource_group_name_type) 90 c.argument('location', arg_type=get_location_type(self.cli_ctx)) 91 c.argument('slot', options_list=['--slot', '-s'], 92 help="the name of the slot. Default to the productions slot if not specified") 93 c.argument('name', arg_type=webapp_name_arg_type) 94 95 with self.argument_context('appservice') as c: 96 c.argument('resource_group_name', arg_type=resource_group_name_type) 97 c.argument('location', arg_type=get_location_type(self.cli_ctx)) 98 99 with self.argument_context('appservice list-locations') as c: 100 c.argument('linux_workers_enabled', action='store_true', 101 help='get regions which support hosting web apps on Linux workers') 102 c.argument('sku', arg_type=sku_arg_type) 103 104 with self.argument_context('appservice plan') as c: 105 c.argument('name', arg_type=name_arg_type, help='The name of the app service plan', 106 completer=get_resource_name_completion_list('Microsoft.Web/serverFarms'), 107 configured_default='appserviceplan', id_part='name', 108 local_context_attribute=LocalContextAttribute(name='plan_name', actions=[LocalContextAction.GET])) 109 c.argument('number_of_workers', help='Number of workers to be allocated.', type=int, default=1) 110 c.argument('admin_site_name', help='The name of the admin web app.', 111 deprecate_info=c.deprecate(expiration='0.2.17')) 112 c.ignore('max_burst') 113 114 with self.argument_context('appservice plan create') as c: 115 c.argument('name', options_list=['--name', '-n'], help="Name of the new app service plan", completer=None, 116 validator=validate_asp_create, 117 local_context_attribute=LocalContextAttribute(name='plan_name', actions=[LocalContextAction.SET], 118 scopes=['appservice', 'webapp', 'functionapp'])) 119 c.argument('app_service_environment', options_list=['--app-service-environment', '-e'], 120 help="Name or ID of the app service environment", 121 local_context_attribute=LocalContextAttribute(name='ase_name', actions=[LocalContextAction.GET])) 122 c.argument('sku', arg_type=sku_arg_type) 123 c.argument('is_linux', action='store_true', required=False, help='host web app on Linux worker') 124 c.argument('hyper_v', action='store_true', required=False, help='Host web app on Windows container') 125 c.argument('per_site_scaling', action='store_true', required=False, help='Enable per-app scaling at the ' 126 'App Service plan level to allow for ' 127 'scaling an app independently from ' 128 'the App Service plan that hosts it.') 129 c.argument('tags', arg_type=tags_type) 130 131 with self.argument_context('appservice plan update') as c: 132 c.argument('sku', arg_type=sku_arg_type) 133 c.ignore('allow_pending_state') 134 135 with self.argument_context('appservice plan delete') as c: 136 c.argument('name', arg_type=name_arg_type, help='The name of the app service plan', 137 completer=get_resource_name_completion_list('Microsoft.Web/serverFarms'), 138 configured_default='appserviceplan', id_part='name', local_context_attribute=None) 139 140 with self.argument_context('webapp create') as c: 141 c.argument('name', options_list=['--name', '-n'], help='name of the new web app', 142 validator=validate_site_create, 143 local_context_attribute=LocalContextAttribute(name='web_name', actions=[LocalContextAction.SET], 144 scopes=['webapp', 'cupertino'])) 145 c.argument('startup_file', help="Linux only. The web's startup file") 146 c.argument('docker_registry_server_user', options_list=['--docker-registry-server-user', '-s'], help='the container registry server username') 147 c.argument('docker_registry_server_password', options_list=['--docker-registry-server-password', '-w'], help='The container registry server password. Required for private registries.') 148 c.argument('multicontainer_config_type', options_list=['--multicontainer-config-type'], help="Linux only.", arg_type=get_enum_type(MULTI_CONTAINER_TYPES)) 149 c.argument('multicontainer_config_file', options_list=['--multicontainer-config-file'], help="Linux only. Config file for multicontainer apps. (local or remote)") 150 c.argument('runtime', options_list=['--runtime', '-r'], help="canonicalized web runtime in the format of Framework|Version, e.g. \"PHP|7.2\". Allowed delimiters: \"|\" or \":\". " 151 "Use `az webapp list-runtimes` for available list") # TODO ADD completer 152 c.argument('plan', options_list=['--plan', '-p'], configured_default='appserviceplan', 153 completer=get_resource_name_completion_list('Microsoft.Web/serverFarms'), 154 help="name or resource id of the app service plan. Use 'appservice plan create' to get one", 155 local_context_attribute=LocalContextAttribute(name='plan_name', actions=[LocalContextAction.GET])) 156 c.ignore('language') 157 c.ignore('using_webapp_up') 158 159 with self.argument_context('webapp show') as c: 160 c.argument('name', arg_type=webapp_name_arg_type) 161 162 with self.argument_context('webapp list-instances') as c: 163 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 164 c.argument('slot', options_list=['--slot', '-s'], help='Name of the web app slot. Default to the productions slot if not specified.') 165 166 with self.argument_context('webapp list-runtimes') as c: 167 c.argument('linux', action='store_true', help='list runtime stacks for linux based web apps') 168 169 with self.argument_context('webapp deleted list') as c: 170 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 171 c.argument('slot', options_list=['--slot', '-s'], help='Name of the deleted web app slot.') 172 173 with self.argument_context('webapp deleted restore') as c: 174 c.argument('deleted_id', options_list=['--deleted-id'], help='Resource ID of the deleted web app') 175 c.argument('name', options_list=['--name', '-n'], help='name of the web app to restore the deleted content to') 176 c.argument('slot', options_list=['--slot', '-s'], help='slot to restore the deleted content to') 177 c.argument('restore_content_only', action='store_true', 178 help='restore only deleted files without web app settings') 179 180 with self.argument_context('webapp traffic-routing') as c: 181 c.argument('distribution', options_list=['--distribution', '-d'], nargs='+', 182 help='space-separated slot routings in a format of `<slot-name>=<percentage>` e.g. staging=50. Unused traffic percentage will go to the Production slot') 183 184 with self.argument_context('webapp update') as c: 185 c.argument('client_affinity_enabled', help="Enables sending session affinity cookies.", 186 arg_type=get_three_state_flag(return_label=True)) 187 c.argument('https_only', help="Redirect all traffic made to an app using HTTP to HTTPS.", 188 arg_type=get_three_state_flag(return_label=True)) 189 c.argument('force_dns_registration', help="If true, web app hostname is force registered with DNS", 190 arg_type=get_three_state_flag(return_label=True), deprecate_info=c.deprecate(expiration='3.0.0')) 191 c.argument('skip_custom_domain_verification', 192 help="If true, custom (non *.azurewebsites.net) domains associated with web app are not verified", 193 arg_type=get_three_state_flag(return_label=True), deprecate_info=c.deprecate(expiration='3.0.0')) 194 c.argument('ttl_in_seconds', help="Time to live in seconds for web app's default domain name", 195 arg_type=get_three_state_flag(return_label=True), deprecate_info=c.deprecate(expiration='3.0.0')) 196 c.argument('skip_dns_registration', help="If true web app hostname is not registered with DNS on creation", 197 arg_type=get_three_state_flag(return_label=True), deprecate_info=c.deprecate(expiration='3.0.0')) 198 199 with self.argument_context('webapp browse') as c: 200 c.argument('logs', options_list=['--logs', '-l'], action='store_true', 201 help='Enable viewing the log stream immediately after launching the web app') 202 with self.argument_context('webapp delete') as c: 203 c.argument('name', arg_type=webapp_name_arg_type, local_context_attribute=None) 204 c.argument('keep_empty_plan', action='store_true', help='keep empty app service plan') 205 c.argument('keep_metrics', action='store_true', help='keep app metrics') 206 c.argument('keep_dns_registration', action='store_true', help='keep DNS registration', 207 deprecate_info=c.deprecate(expiration='3.0.0')) 208 209 with self.argument_context('webapp webjob') as c: 210 c.argument('webjob_name', help='The name of the webjob', options_list=['--webjob-name', '-w']) 211 with self.argument_context('webapp webjob continuous list') as c: 212 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 213 with self.argument_context('webapp webjob triggered list') as c: 214 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 215 216 for scope in ['webapp', 'functionapp', 'logicapp']: 217 with self.argument_context(scope + ' create') as c: 218 c.argument('deployment_container_image_name', options_list=['--deployment-container-image-name', '-i'], 219 help='Linux only. Container image name from Docker Hub, e.g. publisher/image-name:tag') 220 c.argument('deployment_local_git', action='store_true', options_list=['--deployment-local-git', '-l'], 221 help='enable local git') 222 c.argument('deployment_zip', options_list=['--deployment-zip', '-z'], 223 help='perform deployment using zip file') 224 c.argument('deployment_source_url', options_list=['--deployment-source-url', '-u'], 225 help='Git repository URL to link with manual integration') 226 c.argument('deployment_source_branch', options_list=['--deployment-source-branch', '-b'], 227 help='the branch to deploy') 228 c.argument('tags', arg_type=tags_type) 229 230 for scope in ['webapp', 'functionapp']: 231 with self.argument_context(scope) as c: 232 c.argument('assign_identities', nargs='*', options_list=['--assign-identity'], 233 help='accept system or user assigned identities separated by spaces. Use \'[system]\' to refer system assigned identity, or a resource id to refer user assigned identity. Check out help for more examples') 234 c.argument('scope', options_list=['--scope'], help="Scope that the system assigned identity can access") 235 c.argument('role', options_list=['--role'], help="Role name or id the system assigned identity will have") 236 237 with self.argument_context(scope + ' config ssl bind') as c: 238 c.argument('ssl_type', help='The ssl cert type', arg_type=get_enum_type(['SNI', 'IP'])) 239 with self.argument_context(scope + ' config ssl upload') as c: 240 c.argument('certificate_password', help='The ssl cert password') 241 c.argument('certificate_file', type=file_type, help='The filepath for the .pfx file') 242 c.argument('slot', options_list=['--slot', '-s'], 243 help='The name of the slot. Default to the productions slot if not specified') 244 with self.argument_context(scope + ' config ssl') as c: 245 c.argument('certificate_thumbprint', help='The ssl cert thumbprint') 246 with self.argument_context(scope + ' config appsettings') as c: 247 c.argument('settings', nargs='+', help="space-separated app settings in a format of `<name>=<value>`") 248 c.argument('setting_names', nargs='+', help="space-separated app setting names") 249 with self.argument_context(scope + ' config ssl import') as c: 250 c.argument('key_vault', help='The name or resource ID of the Key Vault') 251 c.argument('key_vault_certificate_name', help='The name of the certificate in Key Vault') 252 with self.argument_context(scope + ' config ssl create') as c: 253 c.argument('hostname', help='The custom domain name') 254 c.argument('name', options_list=['--name', '-n'], help='Name of the web app.') 255 c.argument('resource-group', options_list=['--resource-group', '-g'], help='Name of resource group.') 256 with self.argument_context(scope + ' config ssl show') as c: 257 c.argument('certificate_name', help='The name of the certificate') 258 with self.argument_context(scope + ' config hostname') as c: 259 c.argument('hostname', completer=get_hostname_completion_list, 260 help="hostname assigned to the site, such as custom domains", id_part='child_name_1') 261 with self.argument_context(scope + ' deployment user') as c: 262 c.argument('user_name', help='user name') 263 c.argument('password', help='password, will prompt if not specified') 264 with self.argument_context(scope + ' deployment source') as c: 265 c.argument('manual_integration', action='store_true', 266 help='disable automatic sync between source control and web') 267 c.argument('repo_url', options_list=['--repo-url', '-u'], 268 help='repository url to pull the latest source from, e.g. https://github.com/foo/foo-web') 269 c.argument('branch', help='the branch name of the repository') 270 c.argument('repository_type', help='repository type', 271 arg_type=get_enum_type(['git', 'mercurial', 'github', 'externalgit', 'localgit'])) 272 c.argument('git_token', help='Git access token required for auto sync') 273 c.argument('github_action', options_list=['--github-action'], help='If using github action, default to False') 274 with self.argument_context(scope + ' identity') as c: 275 c.argument('scope', help="The scope the managed identity has access to") 276 c.argument('role', help="Role name or id the managed identity will be assigned") 277 with self.argument_context(scope + ' identity assign') as c: 278 c.argument('assign_identities', options_list=['--identities'], nargs='*', help="Space-separated identities to assign. Use '{0}' to refer to the system assigned identity. Default: '{0}'".format(MSI_LOCAL_ID)) 279 with self.argument_context(scope + ' identity remove') as c: 280 c.argument('remove_identities', options_list=['--identities'], nargs='*', help="Space-separated identities to assign. Use '{0}' to refer to the system assigned identity. Default: '{0}'".format(MSI_LOCAL_ID)) 281 282 with self.argument_context(scope + ' deployment source config-zip') as c: 283 c.argument('src', help='a zip file path for deployment') 284 c.argument('build_remote', help='enable remote build during deployment', 285 arg_type=get_three_state_flag(return_label=True)) 286 c.argument('timeout', type=int, options_list=['--timeout', '-t'], 287 help='Configurable timeout in seconds for checking the status of deployment', 288 validator=validate_timeout_value) 289 290 with self.argument_context(scope + ' config appsettings list') as c: 291 c.argument('name', arg_type=(webapp_name_arg_type if scope == 'webapp' else functionapp_name_arg_type), 292 id_part=None) 293 294 with self.argument_context(scope + ' config hostname list') as c: 295 c.argument('webapp_name', arg_type=webapp_name_arg_type, id_part=None, options_list='--webapp-name') 296 297 with self.argument_context(scope + ' cors') as c: 298 c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*', 299 help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*" and remove all other origins from the list') 300 301 with self.argument_context(scope + ' config set') as c: 302 c.argument('number_of_workers', help='The number of workers to be allocated.', type=int) 303 c.argument('remote_debugging_enabled', help='enable or disable remote debugging', 304 arg_type=get_three_state_flag(return_label=True)) 305 c.argument('web_sockets_enabled', help='enable or disable web sockets', 306 arg_type=get_three_state_flag(return_label=True)) 307 c.argument('always_on', 308 help='ensure web app gets loaded all the time, rather unloaded after been idle. Recommended when you have continuous web jobs running', 309 arg_type=get_three_state_flag(return_label=True)) 310 c.argument('auto_heal_enabled', help='enable or disable auto heal', 311 arg_type=get_three_state_flag(return_label=True)) 312 c.argument('use32_bit_worker_process', options_list=['--use-32bit-worker-process'], 313 help='use 32 bits worker process or not', arg_type=get_three_state_flag(return_label=True)) 314 c.argument('php_version', help='The version used to run your web app if using PHP, e.g., 5.5, 5.6, 7.0') 315 c.argument('python_version', help='The version used to run your web app if using Python, e.g., 2.7, 3.4') 316 c.argument('net_framework_version', help="The version used to run your web app if using .NET Framework, e.g., 'v4.0' for .NET 4.6 and 'v3.0' for .NET 3.5") 317 c.argument('linux_fx_version', help="The runtime stack used for your linux-based webapp, e.g., \"RUBY|2.5.5\", \"NODE|10.14\", \"PHP|7.2\", \"DOTNETCORE|2.1\". See https://aka.ms/linux-stacks for more info.") 318 c.argument('windows_fx_version', help="A docker image name used for your windows container web app, e.g., microsoft/nanoserver:ltsc2016") 319 if scope == 'functionapp': 320 c.ignore('windows_fx_version') 321 c.argument('pre_warmed_instance_count', options_list=['--prewarmed-instance-count'], 322 help="Number of pre-warmed instances a function app has") 323 if scope == 'webapp': 324 c.ignore('reserved_instance_count') 325 c.argument('java_version', 326 help="The version used to run your web app if using Java, e.g., '1.7' for Java 7, '1.8' for Java 8") 327 c.argument('java_container', help="The java container, e.g., Tomcat, Jetty") 328 c.argument('java_container_version', help="The version of the java container, e.g., '8.0.23' for Tomcat") 329 c.argument('min_tls_version', 330 help="The minimum version of TLS required for SSL requests, e.g., '1.0', '1.1', '1.2'") 331 c.argument('http20_enabled', help="configures a web site to allow clients to connect over http2.0.", 332 arg_type=get_three_state_flag(return_label=True)) 333 c.argument('app_command_line', options_list=['--startup-file'], 334 help="The startup file for linux hosted web apps, e.g. 'process.json' for Node.js web") 335 c.argument('ftps_state', help="Set the Ftps state value for an app. Default value is 'AllAllowed'.", 336 arg_type=get_enum_type(FTPS_STATE_TYPES)) 337 c.argument('vnet_route_all_enabled', help="Configure regional VNet integration to route all traffic to the VNet.", 338 arg_type=get_three_state_flag(return_label=True)) 339 c.argument('generic_configurations', nargs='+', 340 help='Provide site configuration list in a format of either `key=value` pair or `@<json_file>`. To avoid compatibility issues, it is recommended to use a JSON file to provide these configurations. If using a key=value pair, PowerShell and Windows Command Prompt users should be sure to use escape characters like so: {\\"key\\": value}, instead of: `{"key": value}`.') 341 342 with self.argument_context(scope + ' config container') as c: 343 c.argument('docker_registry_server_url', options_list=['--docker-registry-server-url', '-r'], 344 help='the container registry server url') 345 c.argument('docker_custom_image_name', options_list=['--docker-custom-image-name', '-c', '-i'], 346 help='the container custom image name and optionally the tag name') 347 c.argument('docker_registry_server_user', options_list=['--docker-registry-server-user', '-u'], 348 help='the container registry server username') 349 c.argument('docker_registry_server_password', options_list=['--docker-registry-server-password', '-p'], 350 help='the container registry server password') 351 c.argument('websites_enable_app_service_storage', options_list=['--enable-app-service-storage', '-t'], 352 help='enables platform storage (custom container only)', 353 arg_type=get_three_state_flag(return_label=True)) 354 c.argument('multicontainer_config_type', options_list=['--multicontainer-config-type'], help='config type', 355 arg_type=get_enum_type(MULTI_CONTAINER_TYPES)) 356 c.argument('multicontainer_config_file', options_list=['--multicontainer-config-file'], 357 help="config file for multicontainer apps") 358 c.argument('show_multicontainer_config', action='store_true', 359 help='shows decoded config if a multicontainer config is set') 360 361 with self.argument_context(scope + ' deployment container config') as c: 362 c.argument('enable', options_list=['--enable-cd', '-e'], help='enable/disable continuous deployment', 363 arg_type=get_three_state_flag(return_label=True)) 364 365 with self.argument_context('webapp config connection-string list') as c: 366 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 367 368 with self.argument_context('webapp config storage-account list') as c: 369 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 370 371 with self.argument_context('webapp config hostname') as c: 372 c.argument('webapp_name', 373 help="webapp name. You can configure the default using `az configure --defaults web=<name>`", 374 configured_default='web', 375 completer=get_resource_name_completion_list('Microsoft.Web/sites'), id_part='name', 376 local_context_attribute=LocalContextAttribute(name='web_name', actions=[LocalContextAction.GET])) 377 with self.argument_context('webapp deployment list-publishing-profiles') as c: 378 c.argument('xml', options_list=['--xml'], required=False, help='retrieves the publishing profile details in XML format') 379 with self.argument_context('webapp deployment slot') as c: 380 c.argument('slot', help='the name of the slot') 381 c.argument('webapp', arg_type=name_arg_type, completer=get_resource_name_completion_list('Microsoft.Web/sites'), 382 help='Name of the webapp', id_part='name', 383 local_context_attribute=LocalContextAttribute(name='web_name', actions=[LocalContextAction.GET])) 384 c.argument('auto_swap_slot', help='target slot to auto swap', default='production') 385 c.argument('disable', help='disable auto swap', action='store_true') 386 c.argument('target_slot', help="target slot to swap, default to 'production'") 387 c.argument('preserve_vnet', help="preserve Virtual Network to the slot during swap, default to 'true'", 388 arg_type=get_three_state_flag(return_label=True)) 389 with self.argument_context('webapp deployment slot create') as c: 390 c.argument('configuration_source', 391 help="source slot to clone configurations from. Use web app's name to refer to the production slot") 392 with self.argument_context('webapp deployment slot swap') as c: 393 c.argument('action', 394 help="swap types. use 'preview' to apply target slot's settings on the source slot first; use 'swap' to complete it; use 'reset' to reset the swap", 395 arg_type=get_enum_type(['swap', 'preview', 'reset'])) 396 397 with self.argument_context('webapp deployment github-actions')as c: 398 c.argument('name', arg_type=webapp_name_arg_type) 399 c.argument('resource_group', arg_type=resource_group_name_type, options_list=['--resource-group', '-g']) 400 c.argument('repo', help='The GitHub repository to which the workflow file will be added. In the format: <owner>/<repository-name>') 401 c.argument('token', help='A Personal Access Token with write access to the specified repository. For more information: https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line') 402 c.argument('slot', options_list=['--slot', '-s'], help='The name of the slot. Default to the production slot if not specified.') 403 c.argument('branch', options_list=['--branch', '-b'], help='The branch to which the workflow file will be added. Defaults to "master" if not specified.') 404 c.argument('login_with_github', help='Interactively log in with Github to retrieve the Personal Access Token', action='store_true') 405 406 with self.argument_context('webapp deployment github-actions add')as c: 407 c.argument('runtime', options_list=['--runtime', '-r'], help='Canonicalized web runtime in the format of Framework|Version, e.g. "PHP|5.6". Use "az webapp list-runtimes" for available list.') 408 c.argument('force', options_list=['--force', '-f'], help='When true, the command will overwrite any workflow file with a conflicting name.', action='store_true') 409 410 with self.argument_context('webapp log config') as c: 411 c.argument('application_logging', help='configure application logging', 412 arg_type=get_enum_type(['filesystem', 'azureblobstorage', 'off'])) 413 c.argument('detailed_error_messages', help='configure detailed error messages', 414 arg_type=get_three_state_flag(return_label=True)) 415 c.argument('failed_request_tracing', help='configure failed request tracing', 416 arg_type=get_three_state_flag(return_label=True)) 417 c.argument('level', help='logging level', 418 arg_type=get_enum_type(['error', 'warning', 'information', 'verbose'])) 419 c.argument('web_server_logging', help='configure Web server logging', 420 arg_type=get_enum_type(['off', 'filesystem'])) 421 c.argument('docker_container_logging', help='configure gathering STDOUT and STDERR output from container', 422 arg_type=get_enum_type(['off', 'filesystem'])) 423 424 with self.argument_context('webapp log tail') as c: 425 c.argument('provider', 426 help="By default all live traces configured by `az webapp log config` will be shown, but you can scope to certain providers/folders, e.g. 'application', 'http', etc. For details, check out https://github.com/projectkudu/kudu/wiki/Diagnostic-Log-Stream") 427 428 with self.argument_context('webapp log download') as c: 429 c.argument('log_file', default='webapp_logs.zip', type=file_type, completer=FilesCompleter(), 430 help='the downloaded zipped log file path') 431 432 with self.argument_context('webapp log deployment show') as c: 433 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 434 c.argument('resource_group', arg_type=resource_group_name_type) 435 c.argument('slot', options_list=['--slot', '-s'], help="the name of the slot. Default to the productions slot if not specified") 436 c.argument('deployment_id', options_list=['--deployment-id'], help='Deployment ID. If none specified, returns the deployment logs of the latest deployment.') 437 438 with self.argument_context('webapp log deployment list') as c: 439 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 440 c.argument('resource_group', arg_type=resource_group_name_type) 441 c.argument('slot', options_list=['--slot', '-s'], help="the name of the slot. Default to the productions slot if not specified") 442 443 with self.argument_context('functionapp log deployment show') as c: 444 c.argument('name', arg_type=functionapp_name_arg_type, id_part=None) 445 c.argument('resource_group', arg_type=resource_group_name_type) 446 c.argument('slot', options_list=['--slot', '-s'], help="the name of the slot. Default to the productions slot if not specified") 447 c.argument('deployment_id', options_list=['--deployment-id'], help='Deployment ID. If none specified, returns the deployment logs of the latest deployment.') 448 449 with self.argument_context('functionapp log deployment list') as c: 450 c.argument('name', arg_type=functionapp_name_arg_type, id_part=None) 451 c.argument('resource_group', arg_type=resource_group_name_type) 452 c.argument('slot', options_list=['--slot', '-s'], help="the name of the slot. Default to the productions slot if not specified") 453 454 for scope in ['appsettings', 'connection-string']: 455 with self.argument_context('webapp config ' + scope) as c: 456 c.argument('settings', nargs='+', help="space-separated {} in a format of `<name>=<value>`".format(scope)) 457 c.argument('slot_settings', nargs='+', 458 help="space-separated slot {} in a format of either `<name>=<value>` or `@<json_file>`".format( 459 scope)) 460 c.argument('setting_names', nargs='+', help="space-separated {} names".format(scope)) 461 462 with self.argument_context('webapp config connection-string') as c: 463 c.argument('connection_string_type', options_list=['--connection-string-type', '-t'], 464 help='connection string type', arg_type=get_enum_type(ConnectionStringType)) 465 c.argument('ids', options_list=['--ids'], 466 help="One or more resource IDs (space delimited). If provided no other 'Resource Id' arguments should be specified.", 467 required=True) 468 c.argument('resource_group', options_list=['--resource-group', '-g'], 469 help='Name of resource group. You can configure the default group using `az configure --default-group=<name>`. If `--ids` is provided this should NOT be specified.') 470 c.argument('name', options_list=['--name', '-n'], 471 help='Name of the web app. You can configure the default using `az configure --defaults web=<name>`. If `--ids` is provided this should NOT be specified.', 472 local_context_attribute=LocalContextAttribute(name='web_name', actions=[LocalContextAction.GET])) 473 474 with self.argument_context('webapp config storage-account') as c: 475 c.argument('custom_id', options_list=['--custom-id', '-i'], help='name of the share configured within the web app') 476 c.argument('storage_type', options_list=['--storage-type', '-t'], help='storage type', 477 arg_type=get_enum_type(AzureStorageType)) 478 c.argument('account_name', options_list=['--account-name', '-a'], help='storage account name') 479 c.argument('share_name', options_list=['--share-name', '--sn'], 480 help='name of the file share as given in the storage account') 481 c.argument('access_key', options_list=['--access-key', '-k'], help='storage account access key') 482 c.argument('mount_path', options_list=['--mount-path', '-m'], 483 help='the path which the web app uses to read-write data ex: /share1 or /share2') 484 c.argument('slot', options_list=['--slot', '-s'], 485 help="the name of the slot. Default to the productions slot if not specified") 486 with self.argument_context('webapp config storage-account add') as c: 487 c.argument('slot_setting', options_list=['--slot-setting'], help="slot setting") 488 with self.argument_context('webapp config storage-account update') as c: 489 c.argument('slot_setting', options_list=['--slot-setting'], help="slot setting") 490 491 with self.argument_context('webapp config backup') as c: 492 c.argument('storage_account_url', help='URL with SAS token to the blob storage container', 493 options_list=['--container-url']) 494 c.argument('webapp_name', help='The name of the web app', 495 local_context_attribute=LocalContextAttribute(name='web_name', actions=[LocalContextAction.GET])) 496 c.argument('db_name', help='Name of the database in the backup', arg_group='Database') 497 c.argument('db_connection_string', help='Connection string for the database in the backup', 498 arg_group='Database') 499 c.argument('db_type', help='Type of database in the backup', arg_group='Database', 500 arg_type=get_enum_type(DatabaseType)) 501 502 with self.argument_context('webapp config backup create') as c: 503 c.argument('backup_name', 504 help='Name of the backup. If unspecified, the backup will be named with the web app name and a timestamp', 505 local_context_attribute=LocalContextAttribute(name='backup_name', actions=[LocalContextAction.SET], 506 scopes=['webapp'])) 507 508 with self.argument_context('webapp config backup update') as c: 509 c.argument('backup_name', 510 help='Name of the backup. If unspecified, the backup will be named with the web app name and a timestamp', 511 local_context_attribute=LocalContextAttribute(name='backup_name', actions=[LocalContextAction.GET])) 512 c.argument('frequency', 513 help='How often to backup. Use a number followed by d or h, e.g. 5d = 5 days, 2h = 2 hours') 514 c.argument('keep_at_least_one_backup', help='Always keep one backup, regardless of how old it is', 515 options_list=['--retain-one'], arg_type=get_three_state_flag(return_label=True)) 516 c.argument('retention_period_in_days', 517 help='How many days to keep a backup before automatically deleting it. Set to 0 for indefinite retention', 518 options_list=['--retention']) 519 520 with self.argument_context('webapp config backup restore') as c: 521 c.argument('backup_name', help='Name of the backup to restore', 522 local_context_attribute=LocalContextAttribute(name='backup_name', actions=[LocalContextAction.GET])) 523 c.argument('target_name', 524 help='The name to use for the restored web app. If unspecified, will default to the name that was used when the backup was created') 525 c.argument('overwrite', help='Overwrite the source web app, if --target-name is not specified', 526 action='store_true') 527 c.argument('ignore_hostname_conflict', help='Ignores custom hostnames stored in the backup', 528 action='store_true') 529 530 with self.argument_context('webapp config snapshot') as c: 531 c.argument('name', arg_type=webapp_name_arg_type) 532 c.argument('slot', options_list=['--slot', '-s'], help='The name of the slot.') 533 534 with self.argument_context('webapp config snapshot list') as c: 535 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 536 537 with self.argument_context('webapp config snapshot restore') as c: 538 c.argument('time', help='Timestamp of the snapshot to restore.') 539 c.argument('restore_content_only', help='Restore the web app files without restoring the settings.') 540 c.argument('source_resource_group', help='Name of the resource group to retrieve snapshot from.') 541 c.argument('source_name', help='Name of the web app to retrieve snapshot from.') 542 c.argument('source_slot', help='Name of the web app slot to retrieve snapshot from.') 543 544 with self.argument_context('webapp auth update') as c: 545 c.argument('enabled', arg_type=get_three_state_flag(return_label=True)) 546 c.argument('token_store_enabled', options_list=['--token-store'], 547 arg_type=get_three_state_flag(return_label=True), help='use App Service Token Store') 548 c.argument('action', arg_type=get_enum_type(AUTH_TYPES)) 549 c.argument('runtime_version', 550 help='Runtime version of the Authentication/Authorization feature in use for the current app') 551 c.argument('token_refresh_extension_hours', type=float, help="Hours, must be formattable into a float") 552 c.argument('allowed_external_redirect_urls', nargs='+', help="One or more urls (space-delimited).") 553 c.argument('client_id', options_list=['--aad-client-id'], arg_group='Azure Active Directory', 554 help='Application ID to integrate AAD organization account Sign-in into your web app') 555 c.argument('client_secret', options_list=['--aad-client-secret'], arg_group='Azure Active Directory', 556 help='AAD application secret') 557 c.argument('client_secret_certificate_thumbprint', options_list=['--aad-client-secret-certificate-thumbprint', '--thumbprint'], arg_group='Azure Active Directory', 558 help='Alternative to AAD Client Secret, thumbprint of a certificate used for signing purposes') 559 c.argument('allowed_audiences', nargs='+', options_list=['--aad-allowed-token-audiences'], 560 arg_group='Azure Active Directory', help="One or more token audiences (space-delimited).") 561 c.argument('issuer', options_list=['--aad-token-issuer-url'], 562 help='This url can be found in the JSON output returned from your active directory endpoint using your tenantID. The endpoint can be queried from `az cloud show` at \"endpoints.activeDirectory\". ' 563 'The tenantID can be found using `az account show`. Get the \"issuer\" from the JSON at <active directory endpoint>/<tenantId>/.well-known/openid-configuration.', 564 arg_group='Azure Active Directory') 565 c.argument('facebook_app_id', arg_group='Facebook', 566 help="Application ID to integrate Facebook Sign-in into your web app") 567 c.argument('facebook_app_secret', arg_group='Facebook', help='Facebook Application client secret') 568 c.argument('facebook_oauth_scopes', nargs='+', 569 help="One or more facebook authentication scopes (space-delimited).", arg_group='Facebook') 570 c.argument('twitter_consumer_key', arg_group='Twitter', 571 help='Application ID to integrate Twitter Sign-in into your web app') 572 c.argument('twitter_consumer_secret', arg_group='Twitter', help='Twitter Application client secret') 573 c.argument('google_client_id', arg_group='Google', 574 help='Application ID to integrate Google Sign-in into your web app') 575 c.argument('google_client_secret', arg_group='Google', help='Google Application client secret') 576 c.argument('google_oauth_scopes', nargs='+', help="One or more Google authentication scopes (space-delimited).", 577 arg_group='Google') 578 c.argument('microsoft_account_client_id', arg_group='Microsoft', 579 help="AAD V2 Application ID to integrate Microsoft account Sign-in into your web app") 580 c.argument('microsoft_account_client_secret', arg_group='Microsoft', help='AAD V2 Application client secret') 581 c.argument('microsoft_account_oauth_scopes', nargs='+', 582 help="One or more Microsoft authentification scopes (space-delimited).", arg_group='Microsoft') 583 584 with self.argument_context('webapp hybrid-connection') as c: 585 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 586 c.argument('slot', help="the name of the slot. Default to the productions slot if not specified") 587 c.argument('namespace', help="Hybrid connection namespace") 588 c.argument('hybrid_connection', help="Hybrid connection name") 589 590 with self.argument_context('functionapp hybrid-connection') as c: 591 c.argument('name', id_part=None, local_context_attribute=LocalContextAttribute(name='functionapp_name', 592 actions=[ 593 LocalContextAction.GET])) 594 c.argument('slot', help="the name of the slot. Default to the productions slot if not specified") 595 c.argument('namespace', help="Hybrid connection namespace") 596 c.argument('hybrid_connection', help="Hybrid connection name") 597 598 with self.argument_context('appservice hybrid-connection set-key') as c: 599 c.argument('plan', help="AppService plan", 600 local_context_attribute=LocalContextAttribute(name='plan_name', actions=[LocalContextAction.GET])) 601 c.argument('namespace', help="Hybrid connection namespace") 602 c.argument('hybrid_connection', help="Hybrid connection name") 603 c.argument('key_type', help="Which key (primary or secondary) should be used") 604 605 with self.argument_context('appservice vnet-integration list') as c: 606 c.argument('plan', help="AppService plan", 607 local_context_attribute=LocalContextAttribute(name='plan_name', actions=[LocalContextAction.GET])) 608 c.argument('resource_group', arg_type=resource_group_name_type) 609 610 with self.argument_context('webapp up') as c: 611 c.argument('name', arg_type=webapp_name_arg_type, 612 local_context_attribute=LocalContextAttribute(name='web_name', actions=[LocalContextAction.GET, 613 LocalContextAction.SET], 614 scopes=['webapp', 'cupertino'])) 615 c.argument('plan', options_list=['--plan', '-p'], configured_default='appserviceplan', 616 completer=get_resource_name_completion_list('Microsoft.Web/serverFarms'), 617 help="name of the appserviceplan associated with the webapp", 618 local_context_attribute=LocalContextAttribute(name='plan_name', actions=[LocalContextAction.GET])) 619 c.argument('sku', arg_type=sku_arg_type) 620 c.argument('os_type', options_list=['--os-type'], arg_type=get_enum_type(OS_TYPES), help="Set the OS type for the app to be created.") 621 c.argument('runtime', options_list=['--runtime', '-r'], help="canonicalized web runtime in the format of Framework|Version, e.g. \"PHP|7.2\". Allowed delimiters: \"|\" or \":\". " 622 "Use `az webapp list-runtimes` for available list.") 623 c.argument('dryrun', help="show summary of the create and deploy operation instead of executing it", 624 default=False, action='store_true') 625 c.argument('location', arg_type=get_location_type(self.cli_ctx)) 626 c.argument('launch_browser', help="Launch the created app using the default browser", default=False, 627 action='store_true', options_list=['--launch-browser', '-b']) 628 c.argument('logs', 629 help="Configure default logging required to enable viewing log stream immediately after launching the webapp", 630 default=False, action='store_true') 631 c.argument('html', help="Ignore app detection and deploy as an html app", default=False, action='store_true') 632 c.argument('app_service_environment', options_list=['--app-service-environment', '-e'], help='name of the (pre-existing) App Service Environment to deploy to. Requires an Isolated V2 sku [I1v2, I2v2, I3v2]') 633 634 with self.argument_context('webapp ssh') as c: 635 c.argument('port', options_list=['--port', '-p'], 636 help='Port for the remote connection. Default: Random available port', type=int) 637 c.argument('timeout', options_list=['--timeout', '-t'], help='timeout in seconds. Defaults to none', type=int) 638 c.argument('instance', options_list=['--instance', '-i'], help='Webapp instance to connect to. Defaults to none.') 639 640 with self.argument_context('webapp create-remote-connection') as c: 641 c.argument('port', options_list=['--port', '-p'], 642 help='Port for the remote connection. Default: Random available port', type=int) 643 c.argument('timeout', options_list=['--timeout', '-t'], help='timeout in seconds. Defaults to none', type=int) 644 c.argument('instance', options_list=['--instance', '-i'], help='Webapp instance to connect to. Defaults to none.') 645 646 with self.argument_context('webapp vnet-integration') as c: 647 c.argument('name', arg_type=webapp_name_arg_type, id_part=None) 648 c.argument('slot', help="The name of the slot. Default to the productions slot if not specified.") 649 c.argument('vnet', help="The name or resource ID of the Vnet", 650 local_context_attribute=LocalContextAttribute(name='vnet_name', actions=[LocalContextAction.GET])) 651 c.argument('subnet', help="The name or resource ID of the subnet", 652 local_context_attribute=LocalContextAttribute(name='subnet_name', actions=[LocalContextAction.GET])) 653 c.argument('skip_delegation_check', help="Skip check if you do not have permission or the VNet is in another subscription.", 654 arg_type=get_three_state_flag(return_label=True)) 655 656 with self.argument_context('webapp deploy') as c: 657 c.argument('name', options_list=['--name', '-n'], help='Name of the webapp to deploy to.') 658 c.argument('src_path', options_list=['--src-path'], help='Path of the artifact to be deployed. Ex: "myapp.zip" or "/myworkspace/apps/myapp.war"') 659 c.argument('src_url', options_list=['--src-url'], help='URL of the artifact. The webapp will pull the artifact from this URL. Ex: "http://mysite.com/files/myapp.war?key=123"') 660 c.argument('target_path', options_list=['--target-path'], help='Absolute path that the artifact should be deployed to. Defaults to "home/site/wwwroot/" Ex: "/home/site/deployments/tools/", "/home/site/scripts/startup-script.sh".') 661 c.argument('artifact_type', options_list=['--type'], help='Used to override the type of artifact being deployed.', choices=['war', 'jar', 'ear', 'lib', 'startup', 'static', 'zip']) 662 c.argument('is_async', options_list=['--async'], help='If true, the artifact is deployed asynchronously. (The command will exit once the artifact is pushed to the web app.)', choices=['true', 'false']) 663 c.argument('restart', options_list=['--restart'], help='If true, the web app will be restarted following the deployment. Set this to false if you are deploying multiple artifacts and do not want to restart the site on the earlier deployments.', choices=['true', 'false']) 664 c.argument('clean', options_list=['--clean'], help='If true, cleans the target directory prior to deploying the file(s). Default value is determined based on artifact type.', choices=['true', 'false']) 665 c.argument('ignore_stack', options_list=['--ignore-stack'], help='If true, any stack-specific defaults are ignored.', choices=['true', 'false']) 666 c.argument('timeout', options_list=['--timeout'], help='Timeout for the deployment operation in milliseconds.') 667 c.argument('slot', help="The name of the slot. Default to the productions slot if not specified.") 668 669 with self.argument_context('functionapp deploy') as c: 670 c.argument('name', options_list=['--name', '-n'], help='Name of the function app to deploy to.') 671 c.argument('src_path', options_list=['--src-path'], help='Path of the artifact to be deployed. Ex: "myapp.zip" or "/myworkspace/apps/myapp.war"') 672 c.argument('src_url', options_list=['--src-url'], help='URL of the artifact. The webapp will pull the artifact from this URL. Ex: "http://mysite.com/files/myapp.war?key=123"') 673 c.argument('target_path', options_list=['--target-path'], help='Absolute path that the artifact should be deployed to. Defaults to "home/site/wwwroot/". Ex: "/home/site/deployments/tools/", "/home/site/scripts/startup-script.sh".') 674 c.argument('artifact_type', options_list=['--type'], help='Used to override the type of artifact being deployed.', choices=['war', 'jar', 'ear', 'lib', 'startup', 'static', 'zip']) 675 c.argument('is_async', options_list=['--async'], help='Asynchronous deployment', choices=['true', 'false']) 676 c.argument('restart', options_list=['--restart'], help='If true, the web app will be restarted following the deployment, default value is true. Set this to false if you are deploying multiple artifacts and do not want to restart the site on the earlier deployments.', choices=['true', 'false']) 677 c.argument('clean', options_list=['--clean'], help='If true, cleans the target directory prior to deploying the file(s). Default value is determined based on artifact type.', choices=['true', 'false']) 678 c.argument('ignore_stack', options_list=['--ignore-stack'], help='If true, any stack-specific defaults are ignored.', choices=['true', 'false']) 679 c.argument('timeout', options_list=['--timeout'], help='Timeout for the deployment operation in milliseconds.') 680 c.argument('slot', help="The name of the slot. Default to the productions slot if not specified.") 681 682 with self.argument_context('functionapp vnet-integration') as c: 683 c.argument('name', arg_type=functionapp_name_arg_type, id_part=None) 684 c.argument('slot', help="The name of the slot. Default to the productions slot if not specified") 685 c.argument('vnet', help="The name or resource ID of the Vnet", validator=validate_add_vnet, 686 local_context_attribute=LocalContextAttribute(name='vnet_name', actions=[LocalContextAction.GET])) 687 c.argument('subnet', help="The name or resource ID of the subnet", 688 local_context_attribute=LocalContextAttribute(name='subnet_name', actions=[LocalContextAction.GET])) 689 c.argument('skip_delegation_check', help="Skip check if you do not have permission or the VNet is in another subscription.", 690 arg_type=get_three_state_flag(return_label=True)) 691 692 for scope in ['functionapp', 'logicapp']: 693 app_type = scope[:-3] # 'function' or 'logic' 694 with self.argument_context(scope) as c: 695 c.ignore('app_instance') 696 c.argument('name', arg_type=name_arg_type_dict[scope], id_part='name', help='name of the {} app'.format(app_type)) 697 c.argument('slot', options_list=['--slot', '-s'], 698 help="the name of the slot. Default to the productions slot if not specified") 699 700 with self.argument_context(scope + ' create') as c: 701 c.argument('plan', options_list=['--plan', '-p'], configured_default='appserviceplan', 702 completer=get_resource_name_completion_list('Microsoft.Web/serverFarms'), 703 help="name or resource id of the {} app service plan. Use 'appservice plan create' to get one. If using an App Service plan from a different resource group, the full resource id must be used and not the plan name.".format(scope), 704 local_context_attribute=LocalContextAttribute(name='plan_name', actions=[LocalContextAction.GET])) 705 c.argument('name', options_list=['--name', '-n'], help='name of the new {} app'.format(app_type), 706 local_context_attribute=LocalContextAttribute(name=scope + '_name', 707 actions=[LocalContextAction.SET], 708 scopes=[scope])) 709 c.argument('storage_account', options_list=['--storage-account', '-s'], 710 help='Provide a string value of a Storage Account in the provided Resource Group. Or Resource ID of a Storage Account in a different Resource Group', 711 local_context_attribute=LocalContextAttribute(name='storage_account_name', actions=[LocalContextAction.GET])) 712 c.argument('consumption_plan_location', options_list=['--consumption-plan-location', '-c'], 713 help="Geographic location where {} app will be hosted. Use `az {} list-consumption-locations` to view available locations.".format(app_type, scope)) 714 c.argument('os_type', arg_type=get_enum_type(OS_TYPES), help="Set the OS type for the app to be created.") 715 c.argument('app_insights_key', help="Instrumentation key of App Insights to be added.") 716 c.argument('app_insights', 717 help="Name of the existing App Insights project to be added to the {} app. Must be in the ".format(app_type) + 718 "same resource group.") 719 c.argument('disable_app_insights', arg_type=get_three_state_flag(return_label=True), 720 help="Disable creating application insights resource during {} create. No logs will be available.".format(scope)) 721 c.argument('docker_registry_server_user', options_list=['--docker-registry-server-user', '-d'], help='The container registry server username.') 722 c.argument('docker_registry_server_password', options_list=['--docker-registry-server-password', '-w'], 723 help='The container registry server password. Required for private registries.') 724 if scope == 'functionapp': 725 c.argument('functions_version', help='The functions app version.', arg_type=get_enum_type(FUNCTIONS_VERSIONS)) 726 c.argument('runtime', help='The functions runtime stack.', 727 arg_type=get_enum_type(functionapp_runtime_strings)) 728 c.argument('runtime_version', 729 help='The version of the functions runtime stack. ' 730 'Allowed values for each --runtime are: ' + ', '.join(functionapp_runtime_to_version_strings)) 731 732 with self.argument_context('functionapp config hostname') as c: 733 c.argument('webapp_name', arg_type=functionapp_name_arg_type, id_part='name') 734 # For commands with shared impl between web app and function app and has output, we apply type validation to avoid confusions 735 with self.argument_context('functionapp show') as c: 736 c.argument('name', arg_type=functionapp_name_arg_type) 737 with self.argument_context('functionapp delete') as c: 738 c.argument('name', arg_type=functionapp_name_arg_type, local_context_attribute=None) 739 with self.argument_context('functionapp config appsettings') as c: 740 c.argument('slot_settings', nargs='+', help="space-separated slot app settings in a format of `<name>=<value>`") 741 742 with self.argument_context('logicapp show') as c: 743 c.argument('name', arg_type=logicapp_name_arg_type) 744 with self.argument_context('logicapp delete') as c: 745 c.argument('name', arg_type=logicapp_name_arg_type, local_context_attribute=None) 746 747 with self.argument_context('functionapp plan') as c: 748 c.argument('name', arg_type=name_arg_type, help='The name of the app service plan', 749 completer=get_resource_name_completion_list('Microsoft.Web/serverFarms'), 750 configured_default='appserviceplan', id_part='name', 751 local_context_attribute=LocalContextAttribute(name='plan_name', actions=[LocalContextAction.GET])) 752 c.argument('is_linux', arg_type=get_three_state_flag(return_label=True), required=False, 753 help='host function app on Linux worker') 754 c.argument('number_of_workers', options_list=['--number-of-workers', '--min-instances'], 755 help='The number of workers for the app service plan.') 756 c.argument('max_burst', 757 help='The maximum number of elastic workers for the plan.') 758 c.argument('tags', arg_type=tags_type) 759 760 with self.argument_context('functionapp update') as c: 761 c.argument('plan', required=False, help='The name or resource id of the plan to update the functionapp with.') 762 c.argument('force', required=False, help='Required if attempting to migrate functionapp from Premium to Consumption --plan.', 763 action='store_true') 764 765 with self.argument_context('functionapp plan create') as c: 766 c.argument('name', arg_type=name_arg_type, help='The name of the app service plan', 767 completer=get_resource_name_completion_list('Microsoft.Web/serverFarms'), 768 configured_default='appserviceplan', id_part='name', 769 local_context_attribute=LocalContextAttribute(name='plan_name', actions=[LocalContextAction.SET], 770 scopes=['appservice', 'webapp', 'functionapp'])) 771 c.argument('sku', required=True, help='The SKU of the app service plan.') 772 773 with self.argument_context('functionapp plan update') as c: 774 c.argument('sku', required=False, help='The SKU of the app service plan.') 775 776 with self.argument_context('functionapp plan delete') as c: 777 c.argument('name', arg_type=name_arg_type, help='The name of the app service plan', 778 completer=get_resource_name_completion_list('Microsoft.Web/serverFarms'), 779 configured_default='appserviceplan', id_part='name', 780 local_context_attribute=None) 781 782 with self.argument_context('functionapp devops-build create') as c: 783 c.argument('functionapp_name', help="Name of the Azure function app that you want to use", required=False, 784 local_context_attribute=LocalContextAttribute(name='functionapp_name', 785 actions=[LocalContextAction.GET])) 786 c.argument('organization_name', help="Name of the Azure DevOps organization that you want to use", 787 required=False) 788 c.argument('project_name', help="Name of the Azure DevOps project that you want to use", required=False) 789 c.argument('repository_name', help="Name of the Azure DevOps repository that you want to use", required=False) 790 c.argument('overwrite_yaml', help="If you have an existing yaml, should it be overwritten?", 791 arg_type=get_three_state_flag(return_label=True), required=False) 792 c.argument('allow_force_push', 793 help="If Azure DevOps repository is not clean, should it overwrite remote content?", 794 arg_type=get_three_state_flag(return_label=True), required=False) 795 c.argument('github_pat', help="Github personal access token for creating pipeline from Github repository", 796 required=False) 797 c.argument('github_repository', help="Fullname of your Github repository (e.g. Azure/azure-cli)", 798 required=False) 799 800 with self.argument_context('functionapp devops-pipeline create') as c: 801 c.argument('functionapp_name', help="Name of the Azure function app that you want to use", required=False, 802 local_context_attribute=LocalContextAttribute(name='functionapp_name', 803 actions=[LocalContextAction.GET])) 804 c.argument('organization_name', help="Name of the Azure DevOps organization that you want to use", 805 required=False) 806 c.argument('project_name', help="Name of the Azure DevOps project that you want to use", required=False) 807 c.argument('repository_name', help="Name of the Azure DevOps repository that you want to use", required=False) 808 c.argument('overwrite_yaml', help="If you have an existing yaml, should it be overwritten?", 809 arg_type=get_three_state_flag(return_label=True), required=False) 810 c.argument('allow_force_push', 811 help="If Azure DevOps repository is not clean, should it overwrite remote content?", 812 arg_type=get_three_state_flag(return_label=True), required=False) 813 c.argument('github_pat', help="Github personal access token for creating pipeline from Github repository", 814 required=False) 815 c.argument('github_repository', help="Fullname of your Github repository (e.g. Azure/azure-cli)", 816 required=False) 817 818 with self.argument_context('functionapp deployment list-publishing-profiles') as c: 819 c.argument('xml', options_list=['--xml'], required=False, help='retrieves the publishing profile details in XML format') 820 with self.argument_context('functionapp deployment slot') as c: 821 c.argument('slot', help='the name of the slot') 822 # This is set to webapp to simply reuse webapp functions, without rewriting same functions for function apps. 823 # The help will still show "-n or --name", so it should not be a problem to do it this way 824 c.argument('webapp', arg_type=functionapp_name_arg_type, 825 completer=get_resource_name_completion_list('Microsoft.Web/sites'), 826 help='Name of the function app', id_part='name') 827 c.argument('auto_swap_slot', help='target slot to auto swap', default='production') 828 c.argument('disable', help='disable auto swap', action='store_true') 829 c.argument('target_slot', help="target slot to swap, default to 'production'") 830 c.argument('preserve_vnet', help="preserve Virtual Network to the slot during swap, default to 'true'", 831 arg_type=get_three_state_flag(return_label=True)) 832 with self.argument_context('functionapp deployment slot create') as c: 833 c.argument('configuration_source', 834 help="source slot to clone configurations from. Use function app's name to refer to the production slot") 835 with self.argument_context('functionapp deployment slot swap') as c: 836 c.argument('action', 837 help="swap types. use 'preview' to apply target slot's settings on the source slot first; use 'swap' to complete it; use 'reset' to reset the swap", 838 arg_type=get_enum_type(['swap', 'preview', 'reset'])) 839 840 with self.argument_context('functionapp keys', id_part=None) as c: 841 c.argument('resource_group_name', arg_type=resource_group_name_type,) 842 c.argument('name', arg_type=functionapp_name_arg_type, 843 completer=get_resource_name_completion_list('Microsoft.Web/sites'), 844 help='Name of the function app') 845 c.argument('slot', options_list=['--slot', '-s'], 846 help="The name of the slot. Defaults to the productions slot if not specified") 847 with self.argument_context('functionapp keys set', id_part=None) as c: 848 c.argument('key_name', help="Name of the key to set.") 849 c.argument('key_value', help="Value of the new key. If not provided, a value will be generated.") 850 c.argument('key_type', help="Type of key.", arg_type=get_enum_type(['systemKey', 'functionKeys', 'masterKey'])) 851 with self.argument_context('functionapp keys delete', id_part=None) as c: 852 c.argument('key_name', help="Name of the key to set.") 853 c.argument('key_type', help="Type of key.", arg_type=get_enum_type(['systemKey', 'functionKeys', 'masterKey'])) 854 855 with self.argument_context('functionapp function', id_part=None) as c: 856 c.argument('resource_group_name', arg_type=resource_group_name_type,) 857 c.argument('name', arg_type=functionapp_name_arg_type, 858 completer=get_resource_name_completion_list('Microsoft.Web/sites'), 859 help='Name of the function app') 860 c.argument('function_name', help="Name of the Function") 861 with self.argument_context('functionapp function keys', id_part=None) as c: 862 c.argument('slot', options_list=['--slot', '-s'], 863 help="The name of the slot. Defaults to the productions slot if not specified") 864 with self.argument_context('functionapp function keys set', id_part=None) as c: 865 c.argument('key_name', help="Name of the key to set.") 866 c.argument('key_value', help="Value of the new key. If not provided, a value will be generated.") 867 with self.argument_context('functionapp function keys delete', id_part=None) as c: 868 c.argument('key_name', help="Name of the key to set.") 869 870 # Access Restriction Commands 871 for scope in ['webapp', 'functionapp']: 872 with self.argument_context(scope + ' config access-restriction show') as c: 873 c.argument('name', arg_type=(webapp_name_arg_type if scope == 'webapp' else functionapp_name_arg_type)) 874 875 with self.argument_context(scope + ' config access-restriction add') as c: 876 c.argument('name', arg_type=(webapp_name_arg_type if scope == 'webapp' else functionapp_name_arg_type)) 877 c.argument('rule_name', options_list=['--rule-name', '-r'], 878 help='Name of the access restriction rule to add') 879 c.argument('priority', options_list=['--priority', '-p'], 880 help="Priority of the access restriction rule") 881 c.argument('description', help='Description of the access restriction rule') 882 c.argument('action', arg_type=get_enum_type(ACCESS_RESTRICTION_ACTION_TYPES), 883 help="Allow or deny access") 884 c.argument('ip_address', help="IP address or CIDR range (optional comma separated list of up to 8 ranges)", 885 validator=validate_ip_address) 886 c.argument('service_tag', help="Service Tag (optional comma separated list of up to 8 tags)", 887 validator=validate_service_tag) 888 c.argument('vnet_name', help="vNet name") 889 c.argument('subnet', help="Subnet name (requires vNet name) or subnet resource id") 890 c.argument('ignore_missing_vnet_service_endpoint', 891 options_list=['--ignore-missing-endpoint', '-i'], 892 help='Create access restriction rule with checking if the subnet has Microsoft.Web service endpoint enabled', 893 arg_type=get_three_state_flag(), 894 default=False) 895 c.argument('scm_site', help='True if access restrictions is added for scm site', 896 arg_type=get_three_state_flag()) 897 c.argument('vnet_resource_group', help='Resource group of virtual network (default is web app resource group)') 898 c.argument('http_headers', nargs='+', help="space-separated http headers in a format of `<name>=<value>`") 899 with self.argument_context(scope + ' config access-restriction remove') as c: 900 c.argument('name', arg_type=(webapp_name_arg_type if scope == 'webapp' else functionapp_name_arg_type)) 901 c.argument('rule_name', options_list=['--rule-name', '-r'], 902 help='Name of the access restriction to remove') 903 c.argument('ip_address', help="IP address or CIDR range (optional comma separated list of up to 8 ranges)", 904 validator=validate_ip_address) 905 c.argument('service_tag', help="Service Tag (optional comma separated list of up to 8 tags)", 906 validator=validate_service_tag) 907 c.argument('vnet_name', help="vNet name") 908 c.argument('subnet', help="Subnet name (requires vNet name) or subnet resource id") 909 c.argument('scm_site', help='True if access restriction should be removed from scm site', 910 arg_type=get_three_state_flag()) 911 c.argument('action', arg_type=get_enum_type(ACCESS_RESTRICTION_ACTION_TYPES), 912 help="Allow or deny access") 913 with self.argument_context(scope + ' config access-restriction set') as c: 914 c.argument('name', arg_type=(webapp_name_arg_type if scope == 'webapp' else functionapp_name_arg_type)) 915 c.argument('use_same_restrictions_for_scm_site', 916 help="Use same access restrictions for scm site", 917 arg_type=get_three_state_flag()) 918 919 # App Service Environment Commands 920 with self.argument_context('appservice ase show') as c: 921 c.argument('name', options_list=['--name', '-n'], help='Name of the app service environment', 922 local_context_attribute=LocalContextAttribute(name='ase_name', actions=[LocalContextAction.GET])) 923 with self.argument_context('appservice ase create') as c: 924 c.argument('name', options_list=['--name', '-n'], validator=validate_ase_create, 925 help='Name of the app service environment', 926 local_context_attribute=LocalContextAttribute(name='ase_name', actions=[LocalContextAction.SET], 927 scopes=['appservice'])) 928 c.argument('kind', options_list=['--kind', '-k'], arg_type=get_enum_type(ASE_KINDS), 929 default='ASEv2', help="Specify App Service Environment version") 930 c.argument('subnet', help='Name or ID of existing subnet. To create vnet and/or subnet \ 931 use `az network vnet [subnet] create`') 932 c.argument('vnet_name', help='Name of the vNet. Mandatory if only subnet name is specified.') 933 c.argument('virtual_ip_type', arg_type=get_enum_type(ASE_LOADBALANCER_MODES), 934 help="Specify if app service environment should be accessible from internet") 935 c.argument('ignore_subnet_size_validation', arg_type=get_three_state_flag(), 936 help='Do not check if subnet is sized according to recommendations.') 937 c.argument('ignore_route_table', arg_type=get_three_state_flag(), 938 help='Configure route table manually. Applies to ASEv2 only.') 939 c.argument('ignore_network_security_group', arg_type=get_three_state_flag(), 940 help='Configure network security group manually. Applies to ASEv2 only.') 941 c.argument('force_route_table', arg_type=get_three_state_flag(), 942 help='Override route table for subnet. Applies to ASEv2 only.') 943 c.argument('force_network_security_group', arg_type=get_three_state_flag(), 944 help='Override network security group for subnet. Applies to ASEv2 only.') 945 c.argument('front_end_scale_factor', type=int, validator=validate_front_end_scale_factor, 946 help='Scale of front ends to app service plan instance ratio. Applies to ASEv2 only.', default=15) 947 c.argument('front_end_sku', arg_type=isolated_sku_arg_type, default='I1', 948 help='Size of front end servers. Applies to ASEv2 only.') 949 c.argument('os_preference', arg_type=get_enum_type(ASE_OS_PREFERENCE_TYPES), 950 help='Determine if app service environment should start with Linux workers. Applies to ASEv2 only.') 951 c.argument('zone_redundant', arg_type=get_three_state_flag(), 952 help='Configure App Service Environment as Zone Redundant. Applies to ASEv3 only.') 953 with self.argument_context('appservice ase delete') as c: 954 c.argument('name', options_list=['--name', '-n'], help='Name of the app service environment') 955 with self.argument_context('appservice ase update') as c: 956 c.argument('name', options_list=['--name', '-n'], help='Name of the app service environment', 957 local_context_attribute=LocalContextAttribute(name='ase_name', actions=[LocalContextAction.GET])) 958 c.argument('front_end_scale_factor', type=int, validator=validate_front_end_scale_factor, 959 help='Scale of front ends to app service plan instance ratio between 5 and 15.') 960 c.argument('front_end_sku', arg_type=isolated_sku_arg_type, help='Size of front end servers.') 961 with self.argument_context('appservice ase list-addresses') as c: 962 c.argument('name', options_list=['--name', '-n'], help='Name of the app service environment', 963 local_context_attribute=LocalContextAttribute(name='ase_name', actions=[LocalContextAction.GET])) 964 with self.argument_context('appservice ase list-plans') as c: 965 c.argument('name', options_list=['--name', '-n'], help='Name of the app service environment', 966 local_context_attribute=LocalContextAttribute(name='ase_name', actions=[LocalContextAction.GET])) 967 with self.argument_context('appservice ase create-inbound-services') as c: 968 c.argument('name', options_list=['--name', '-n'], help='Name of the app service environment', 969 local_context_attribute=LocalContextAttribute(name='ase_name', actions=[LocalContextAction.GET])) 970 c.argument('subnet', help='Name or ID of existing subnet for inbound traffic to ASEv3. \ 971 To create vnet and/or subnet use `az network vnet [subnet] create`') 972 c.argument('vnet_name', help='Name of the vNet. Mandatory if only subnet name is specified.') 973 c.argument('skip_dns', arg_type=get_three_state_flag(), 974 help='Do not create Private DNS Zone and DNS records.') 975 976 # App Service Domain Commands 977 with self.argument_context('appservice domain create') as c: 978 c.argument('hostname', options_list=['--hostname', '-n'], help='Name of the custom domain') 979 c.argument('contact_info', options_list=['--contact-info', '-c'], help='The file path to a JSON object with your contact info for domain registration. ' 980 'Please see the following link for the format of the JSON file expected: ' 981 'https://github.com/AzureAppServiceCLI/appservice_domains_templates/blob/master/contact_info.json') 982 c.argument('privacy', options_list=['--privacy', '-p'], help='Enable privacy protection') 983 c.argument('auto_renew', options_list=['--auto-renew', '-a'], help='Enable auto-renew on the domain') 984 c.argument('accept_terms', options_list=['--accept-terms'], help='By using this flag, you are accepting ' 985 'the conditions shown using the --show-hostname-purchase-terms flag. ') 986 c.argument('tags', arg_type=tags_type) 987 c.argument('dryrun', help='Show summary of the purchase and create operation instead of executing it') 988 c.argument('no_wait', help='Do not wait for the create to complete, and return immediately after queuing the create.') 989 c.argument('validate', help='Generate and validate the ARM template without creating any resources') 990 991 with self.argument_context('appservice domain show-terms') as c: 992 c.argument('hostname', options_list=['--hostname', '-n'], help='Name of the custom domain') 993 994 with self.argument_context('staticwebapp', validator=validate_public_cloud) as c: 995 c.argument('name', options_list=['--name', '-n'], metavar='NAME', help="Name of the static site") 996 c.argument('source', options_list=['--source', '-s'], help="URL for the repository of the static site.") 997 c.argument('token', options_list=['--token', '-t'], 998 help="A user's github repository token. This is used to setup the Github Actions workflow file and " 999 "API secrets. If you need to create a Github Personal Access Token, " 1000 "please run with the '--login-with-github' flag or follow the steps found at the following link:\n" 1001 "https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line") 1002 c.argument('login_with_github', help="Interactively log in with Github to retrieve the Personal Access Token") 1003 c.argument('branch', options_list=['--branch', '-b'], help="The target branch in the repository.") 1004 with self.argument_context('staticwebapp environment') as c: 1005 c.argument('environment_name', 1006 options_list=['--environment-name'], help="Name of the environment of static site") 1007 with self.argument_context('staticwebapp hostname') as c: 1008 c.argument('hostname', 1009 options_list=['--hostname'], 1010 help="custom hostname such as www.example.com. Only support sub domain in preview.") 1011 with self.argument_context('staticwebapp appsettings') as c: 1012 c.argument('setting_pairs', options_list=['--setting-names'], 1013 help="Space-separated app settings in 'key=value' format. ", 1014 nargs='*') 1015 c.argument('setting_names', options_list=['--setting-names'], help="Space-separated app setting names.", 1016 nargs='*') 1017 with self.argument_context('staticwebapp users') as c: 1018 c.argument('authentication_provider', options_list=['--authentication-provider'], 1019 help="Authentication provider of the user identity such as AAD, Facebook, GitHub, Google, Twitter.") 1020 c.argument('user_details', options_list=['--user-details'], 1021 help="Email for AAD, Facebook, and Google. Account name (handle) for GitHub and Twitter.") 1022 c.argument('user_id', 1023 help="Given id of registered user.") 1024 c.argument('domain', options_list=['--domain'], 1025 help="A domain added to the static app in quotes.") 1026 c.argument('roles', options_list=['--roles'], 1027 help="Comma-separated default or user-defined role names. " 1028 "Roles that can be assigned to a user are comma separated and case-insensitive (at most 50 " 1029 "roles up to 25 characters each and restricted to 0-9,A-Z,a-z, and _). " 1030 "Define roles in routes.json during root directory of your GitHub repo.") 1031 c.argument('invitation_expiration_in_hours', options_list=['--invitation-expiration-in-hours'], 1032 help="This value sets when the link will expire in hours. The maximum is 168 (7 days).") 1033 with self.argument_context('staticwebapp create') as c: 1034 c.argument('location', arg_type=get_location_type(self.cli_ctx)) 1035 c.argument('tags', arg_type=tags_type) 1036 c.argument('sku', arg_type=static_web_app_sku_arg_type) 1037 c.argument('app_location', options_list=['--app-location'], 1038 help="Location of your application code. For example, '/' represents the root of your app, " 1039 "while '/app' represents a directory called 'app'") 1040 c.argument('api_location', options_list=['--api-location'], 1041 help="Location of your Azure Functions code. For example, '/api' represents a folder called 'api'.") 1042 c.argument('app_artifact_location', options_list=['--app-artifact-location'], 1043 help="The path of your build output relative to your apps location. For example, setting a value " 1044 "of 'build' when your app location is set to '/app' will cause the content at '/app/build' to " 1045 "be served.", 1046 deprecate_info=c.deprecate(expiration='2.22.1')) 1047 c.argument('output_location', options_list=['--output-location'], 1048 help="The path of your build output relative to your apps location. For example, setting a value " 1049 "of 'build' when your app location is set to '/app' will cause the content at '/app/build' to " 1050 "be served.") 1051 with self.argument_context('staticwebapp update') as c: 1052 c.argument('tags', arg_type=tags_type) 1053 c.argument('sku', arg_type=static_web_app_sku_arg_type) 1054 1055 1056def _get_functionapp_runtime_versions(): 1057 # set up functionapp create help menu 1058 KEYS = FUNCTIONS_STACKS_API_KEYS() 1059 stacks_api_json_list = [] 1060 stacks_api_json_list.append(get_file_json(FUNCTIONS_STACKS_API_JSON_PATHS['windows'])) 1061 stacks_api_json_list.append(get_file_json(FUNCTIONS_STACKS_API_JSON_PATHS['linux'])) 1062 1063 # build a map of runtime -> runtime version -> runtime version properties 1064 runtime_to_version = {} 1065 for stacks_api_json in stacks_api_json_list: 1066 for runtime_json in stacks_api_json[KEYS.VALUE]: 1067 runtime_name = runtime_json[KEYS.NAME] 1068 for runtime_version_json in runtime_json[KEYS.PROPERTIES][KEYS.MAJOR_VERSIONS]: 1069 runtime_version = runtime_version_json[KEYS.DISPLAY_VERSION] 1070 runtime_version_properties = { 1071 KEYS.IS_HIDDEN: runtime_version_json[KEYS.IS_HIDDEN], 1072 KEYS.IS_DEPRECATED: runtime_version_json[KEYS.IS_DEPRECATED], 1073 KEYS.IS_PREVIEW: runtime_version_json[KEYS.IS_PREVIEW], 1074 } 1075 runtime_to_version[runtime_name] = runtime_to_version.get(runtime_name, dict()) 1076 runtime_to_version[runtime_name][runtime_version] = runtime_version_properties 1077 1078 # traverse the map to build an ordered string of runtimes -> runtime versions, 1079 # taking their properties into account (i.e. isHidden, isPreview) 1080 runtime_to_version_strings = [] 1081 for runtime, runtime_versions in runtime_to_version.items(): 1082 # dotnet and custom version is not configurable, so leave out of help menu 1083 if runtime in ('dotnet', 'custom'): 1084 continue 1085 ordered_runtime_versions = list(runtime_versions.keys()) 1086 ordered_runtime_versions.sort(key=float) 1087 ordered_runtime_versions_strings = [] 1088 for version in ordered_runtime_versions: 1089 if runtime_versions[version][KEYS.IS_HIDDEN] or runtime_versions[version][KEYS.IS_DEPRECATED]: 1090 continue 1091 if runtime_versions[version][KEYS.IS_PREVIEW]: 1092 ordered_runtime_versions_strings.append(version + ' (preview)') 1093 else: 1094 ordered_runtime_versions_strings.append(version) 1095 runtime_to_version_strings.append(runtime + ' -> [' + ', '.join(ordered_runtime_versions_strings) + ']') 1096 1097 return runtime_to_version.keys(), runtime_to_version_strings 1098