def prepare_webapp_deploy(language, code_dir=None, proj_file_path=None): if not code_dir: code_dir = os.getcwd() logger.info('--code-dir not provided, defaulting to current working directory: %s\n' 'For more information, run "az bot prepare-deploy -h"', code_dir) elif not os.path.exists(code_dir): raise CLIError('Provided --code-dir value ({0}) does not exist'.format(code_dir)) def does_file_exist(file_name): if os.path.exists(os.path.join(code_dir, file_name)): raise CLIError('%s found in %s\nPlease delete this %s before calling "az bot ' # pylint:disable=logging-not-lazy 'prepare-deploy"' % (file_name, code_dir, file_name)) if language != 'Csharp': if proj_file_path: raise CLIError('--proj-file-path should not be passed in if language is not Csharp') does_file_exist('web.config') BotPublishPrep.prepare_publish_v4(logger, code_dir, proj_file_path, {'lang': language, 'has_web_config': False, 'has_iisnode_yml': True}) else: if not proj_file_path: raise CLIError('--proj-file-path must be provided if language is Csharp') does_file_exist('.deployment') csproj_file = os.path.join(code_dir, proj_file_path) if not os.path.exists(csproj_file): raise CLIError('{0} file not found\nPlease verify the relative path to the .csproj file from the ' '--code-dir'.format(csproj_file)) with open(os.path.join(code_dir, '.deployment'), 'w') as f: f.write('[config]\n') proj_file = proj_file_path.lower() proj_file = proj_file if proj_file.endswith('.csproj') else proj_file + '.csproj' f.write('SCM_SCRIPT_GENERATOR_ARGS=--aspNetCore "{0}"\n'.format(proj_file))
def publish_app( cmd, client, resource_group_name, resource_name, code_dir=None, proj_file_path=None, version='v4', # pylint:disable=too-many-statements keep_node_modules=None, timeout=None): if version == 'v4': logger.warning( 'DEPRECATION WARNING: `az bot publish` is deprecated for v4 bots. We recommend using `az webapp`' ' to deploy your bot to Azure. For more information on how to deploy a v4 bot, see ' 'https://aka.ms/deploy-your-bot.') # Get the bot information and ensure it's not only a registration bot. bot = client.bots.get(resource_group_name=resource_group_name, resource_name=resource_name) if bot.kind == 'bot': raise CLIError( 'Bot kind is \'bot\', meaning it is a registration bot. ' 'Source publish is not supported for registration only bots.') # If the user does not pass in a path to the local bot project, get the current working directory. if not code_dir: code_dir = os.getcwd() logger.info( 'Parameter --code-dir not provided, defaulting to current working directory, %s. ' 'For more information, run \'az bot publish -h\'', code_dir) code_dir = code_dir.strip() if not os.path.isdir(code_dir): raise CLIError( 'The path %s is not a valid directory. ' 'Please supply a valid directory path containing your source code.' % code_dir) # If local IIS Node.js files exist, this means two things: # 1. We may not need to download the necessary web.config and iisnode.yml files to deploy a Node.js bot on IIS. # 2. We shouldn't delete their local web.config and issnode.yml files (if they exist). iis_publish_info = { 'lang': CSHARP if not os.path.exists(os.path.join(code_dir, 'package.json')) else JAVASCRIPT, 'has_web_config': True if os.path.exists(os.path.join(code_dir, 'web.config')) else False, 'has_iisnode_yml': True if os.path.exists(os.path.join(code_dir, 'iisnode.yml')) else False } # Ensure that the directory contains appropriate post deploy scripts folder if 'PostDeployScripts' not in os.listdir(code_dir): if version == 'v4': logger.info( 'Detected SDK version v4. Running prepare publish in code directory %s and for project file %s' # pylint:disable=logging-not-lazy % (code_dir, proj_file_path)) # Automatically run prepare-publish in case of v4. BotPublishPrep.prepare_publish_v4(logger, code_dir, proj_file_path, iis_publish_info) else: logger.info( 'Detected SDK version v3. PostDeploymentScripts folder not found in directory provided: %s', code_dir) raise CLIError( 'Publish directory provided is uses Bot Builder SDK V3, and as a legacy bot needs to be ' 'prepared for deployment. Please run prepare-publish. For more information, run \'az bot ' 'prepare-publish -h\'.') zip_filepath = BotPublishPrep.create_upload_zip(logger, code_dir, include_node_modules=False) logger.info('Zip file path created, at %s.', zip_filepath) kudu_client = KuduClient(cmd, resource_group_name, resource_name, bot, logger) output = kudu_client.publish(zip_filepath, timeout, keep_node_modules, iis_publish_info['lang']) logger.info( 'Bot source published. Preparing bot application to run the new source.' ) os.remove('upload.zip') # If the bot is a Node.js bot and did not initially have web.config, delete web.config and iisnode.yml. if iis_publish_info['lang'] == JAVASCRIPT: if not iis_publish_info['has_web_config'] and os.path.exists( os.path.join(code_dir, 'web.config')): os.remove(os.path.join(code_dir, 'web.config')) if not iis_publish_info['has_iisnode_yml'] and os.path.exists( os.path.join(code_dir, 'iisnode.yml')): os.remove(os.path.join(code_dir, 'iisnode.yml')) if not iis_publish_info['has_iisnode_yml'] and not iis_publish_info[ 'has_web_config']: logger.info( "web.config and iisnode.yml for Node.js bot were fetched from Azure for deployment using IIS. " "These files have now been removed from %s." "To see the two files used for your deployment, either visit your bot's Kudu site or download " "the files from https://icscratch.blob.core.windows.net/bot-packages/node_v4_publish.zip", code_dir) elif not iis_publish_info['has_iisnode_yml']: logger.info( "iisnode.yml for Node.js bot was fetched from Azure for deployment using IIS. To see this file " "that was used for your deployment, either visit your bot's Kudu site or download the file " "from https://icscratch.blob.core.windows.net/bot-packages/node_v4_publish.zip" ) elif not iis_publish_info['has_web_config']: logger.info( "web.config for Node.js bot was fetched from Azure for deployment using IIS. To see this file " "that was used for your deployment, either visit your bot's Kudu site or download the file " "from https://icscratch.blob.core.windows.net/bot-packages/node_v4_publish.zip" ) if os.path.exists(os.path.join('.', 'package.json')) and not keep_node_modules: logger.info( 'Detected language javascript. Installing node dependencies in remote bot.' ) kudu_client.install_node_dependencies() if output.get('active'): logger.info('Deployment successful!') if not output.get('active'): scm_url = output.get('url') deployment_id = output.get('id') # Instead of replacing "latest", which would could be in the bot name, we replace "deployments/latest" deployment_url = scm_url.replace('deployments/latest', 'deployments/%s' % deployment_id) logger.error( 'Deployment failed. To find out more information about this deployment, please visit %s.', deployment_url) return output
def publish_app(cmd, client, resource_group_name, resource_name, code_dir=None, proj_name=None, version='v3'): """Publish local bot code to Azure. This method is directly called via "bot publish" :param cmd: :param client: :param resource_group_name: :param resource_name: :param code_dir: :param proj_name: :param version: :return: """ # Get the bot information and ensure it's not only a registration bot. bot = client.bots.get( resource_group_name=resource_group_name, resource_name=resource_name ) if bot.kind == 'bot': raise CLIError('Bot kind is \'bot\', meaning it is a registration bot. ' 'Source publish is not supported for registration only bots.') # If the user does not pass in a path to the local bot project, get the current working directory. if not code_dir: code_dir = os.getcwd() logger.info('Parameter --code-dir not provided, defaulting to current working directory, %s. ' 'For more information, run \'az bot publish -h\'', code_dir) code_dir = code_dir.strip() if not os.path.isdir(code_dir): raise CLIError('The path %s is not a valid directory. ' 'Please supply a valid directory path containing your source code.' % code_dir) # Ensure that the directory contains appropriate post deploy scripts folder if 'PostDeployScripts' not in os.listdir(code_dir): if version == 'v4': logger.info('Detected SDK version v4. Running prepare publish in code directory %s and for project file %s' # pylint:disable=logging-not-lazy % (code_dir, proj_name)) # Automatically run prepare-publish in case of v4. BotPublishPrep.prepare_publish_v4(logger, code_dir, proj_name) else: logger.info('Detected SDK version v3. PostDeploymentScripts folder not found in directory provided: %s', code_dir) raise CLIError('Publish directory provided is uses Bot Builder SDK V3, and as a legacy bot needs to be ' 'prepared for deployment. Please run prepare-publish. For more information, run \'az bot ' 'prepare-publish -h\'.') logger.info('Creating upload zip file.') zip_filepath = BotPublishPrep.create_upload_zip(logger, code_dir, include_node_modules=False) logger.info('Zip file path created, at %s.', zip_filepath) kudu_client = KuduClient(cmd, resource_group_name, resource_name, bot, logger) output = kudu_client.publish(zip_filepath) logger.info('Bot source published. Preparing bot application to run the new source.') os.remove('upload.zip') if os.path.exists(os.path.join('.', 'package.json')): logger.info('Detected language javascript. Installing node dependencies in remote bot.') kudu_client.install_node_dependencies() logger.info('Bot publish completed successfully.') return output
def publish_app(cmd, client, resource_group_name, resource_name, code_dir=None, proj_name=None, version='v3'): """Publish local bot code to Azure. This method is directly called via "bot publish" :param cmd: :param client: :param resource_group_name: :param resource_name: :param code_dir: :param proj_name: :param version: :return: """ if version == 'v3': return publish_appv3(cmd, client, resource_group_name, resource_name, code_dir) # Get the bot information and ensure it's not only a registration bot. bot = client.bots.get( resource_group_name=resource_group_name, resource_name=resource_name ) if bot.kind == 'bot': raise CLIError('Bot kind is \'bot\', meaning it is a registration bot. ' 'Source publish is not supported for registration only bots.') # If the user does not pass in a path to the local bot project, get the current working directory. if not code_dir: code_dir = os.getcwd() logger.info('Parameter --code-dir not provided, defaulting to current working directory, %s. ' 'For more information, run \'az bot publish -h\'', code_dir) if not os.path.isdir(code_dir): raise CLIError('The path %s is not a valid directory. ' 'Please supply a valid directory path containing your source code.' % code_dir) # Ensure that the directory contains appropriate post deploy scripts folder if 'PostDeployScripts' not in os.listdir(code_dir): BotPublishPrep.prepare_publish_v4(logger, code_dir, proj_name) logger.info('Creating upload zip file.') zip_filepath = BotPublishPrep.create_upload_zip(logger, code_dir, include_node_modules=False) logger.info('Zip file path created, at %s.', zip_filepath) kudu_client = KuduClient(cmd, resource_group_name, resource_name, bot) output = kudu_client.publish(zip_filepath) logger.info('Bot source published. Preparing bot application to run the new source.') os.remove('upload.zip') if os.path.exists(os.path.join('.', 'package.json')): logger.info('Detected language javascript. Installing node dependencies in remote bot.') __install_node_dependencies(kudu_client) if output.get('active'): logger.info('Deployment successful!') if not output.get('active'): scm_url = output.get('url') deployment_id = output.get('id') # Instead of replacing "latest", which would could be in the bot name, we replace "deployments/latest" deployment_url = scm_url.replace('deployments/latest', 'deployments/%s' % deployment_id) logger.error('Deployment failed. To find out more information about this deployment, please visit %s.' % deployment_url) return output
def publish_app( cmd, client, resource_group_name, resource_name, code_dir=None, proj_file_path=None, version='v3', # pylint:disable=too-many-statements keep_node_modules=None, timeout=None): """Publish local bot code to Azure. This method is directly called via "bot publish" :param cmd: :param client: :param resource_group_name: :param resource_name: :param code_dir: :param proj_file_path: :param version: :param keep_node_modules: :param timeout: :return: """ # Get the bot information and ensure it's not only a registration bot. bot = client.bots.get(resource_group_name=resource_group_name, resource_name=resource_name) if bot.kind == 'bot': raise CLIError( 'Bot kind is \'bot\', meaning it is a registration bot. ' 'Source publish is not supported for registration only bots.') # If the user does not pass in a path to the local bot project, get the current working directory. if not code_dir: code_dir = os.getcwd() logger.info( 'Parameter --code-dir not provided, defaulting to current working directory, %s. ' 'For more information, run \'az bot publish -h\'', code_dir) code_dir = code_dir.strip() if not os.path.isdir(code_dir): raise CLIError( 'The path %s is not a valid directory. ' 'Please supply a valid directory path containing your source code.' % code_dir) # If local IIS Node.js files exist, this means two things: # 1. We may not need to download the necessary web.config and iisnode.yml files to deploy a Node.js bot on IIS. # 2. We shouldn't delete their local web.config and issnode.yml files (if they exist). iis_publish_info = { 'lang': 'Csharp' if not os.path.exists(os.path.join(code_dir, 'package.json')) else 'Node', 'has_web_config': True if os.path.exists(os.path.join(code_dir, 'web.config')) else False, 'has_iisnode_yml': True if os.path.exists(os.path.join(code_dir, 'iisnode.yml')) else False } # Ensure that the directory contains appropriate post deploy scripts folder if 'PostDeployScripts' not in os.listdir(code_dir): if version == 'v4': logger.info( 'Detected SDK version v4. Running prepare publish in code directory %s and for project file %s' # pylint:disable=logging-not-lazy % (code_dir, proj_file_path)) # Automatically run prepare-publish in case of v4. BotPublishPrep.prepare_publish_v4(logger, code_dir, proj_file_path, iis_publish_info) else: logger.info( 'Detected SDK version v3. PostDeploymentScripts folder not found in directory provided: %s', code_dir) raise CLIError( 'Publish directory provided is uses Bot Builder SDK V3, and as a legacy bot needs to be ' 'prepared for deployment. Please run prepare-publish. For more information, run \'az bot ' 'prepare-publish -h\'.') zip_filepath = BotPublishPrep.create_upload_zip(logger, code_dir, include_node_modules=False) logger.info('Zip file path created, at %s.', zip_filepath) kudu_client = KuduClient(cmd, resource_group_name, resource_name, bot, logger) app_settings = WebAppOperations.get_app_settings( cmd=cmd, resource_group_name=resource_group_name, name=kudu_client.bot_site_name) scm_do_build = [ item['value'] for item in app_settings if item['name'] == 'SCM_DO_BUILD_DURING_DEPLOYMENT' ] if scm_do_build and scm_do_build[0] == 'true': logger.info( 'Detected SCM_DO_BUILD_DURING_DEPLOYMENT with value of "true" in App Service\'s Application ' 'Settings. Build will commence during deployment. For more information, see ' 'https://github.com/projectkudu/kudu/wiki/Deploying-from-a-zip-file' ) else: logger.warning( 'Didn\'t detect SCM_DO_BUILD_DURING_DEPLOYMENT or its value was "false" in App Service\'s ' 'Application Settings. Build may not commence during deployment. To learn how to trigger a build' ' when deploying to your App Service, see ' 'https://github.com/projectkudu/kudu/wiki/Deploying-from-a-zip-file' ) subscription_id = get_subscription_id(cmd.cli_ctx) logger.warning( 'To change the Application Setting via az cli, use the following command:\naz webapp config ' # pylint:disable=logging-not-lazy 'appsettings set -n %s -g %s --subscription %s --settings SCM_DO_BUILD_DURING_DEPLOYMENT=true' % (kudu_client.bot_site_name, resource_group_name, subscription_id)) output = kudu_client.publish(zip_filepath, timeout, keep_node_modules, iis_publish_info['lang']) logger.info( 'Bot source published. Preparing bot application to run the new source.' ) os.remove('upload.zip') # If the bot is a Node.js bot and did not initially have web.config, delete web.config and iisnode.yml. if iis_publish_info['lang'] == 'Node': if not iis_publish_info['has_web_config'] and os.path.exists( os.path.join(code_dir, 'web.config')): os.remove(os.path.join(code_dir, 'web.config')) if not iis_publish_info['has_iisnode_yml'] and os.path.exists( os.path.join(code_dir, 'iisnode.yml')): os.remove(os.path.join(code_dir, 'iisnode.yml')) if not iis_publish_info['has_iisnode_yml'] and not iis_publish_info[ 'has_web_config']: logger.info( "web.config and iisnode.yml for Node.js bot were fetched from Azure for deployment using IIS. " "These files have now been removed from %s." "To see the two files used for your deployment, either visit your bot's Kudu site or download " "the files from https://icscratch.blob.core.windows.net/bot-packages/node_v4_publish.zip", code_dir) elif not iis_publish_info['has_iisnode_yml']: logger.info( "iisnode.yml for Node.js bot was fetched from Azure for deployment using IIS. To see this file " "that was used for your deployment, either visit your bot's Kudu site or download the file " "from https://icscratch.blob.core.windows.net/bot-packages/node_v4_publish.zip" ) elif not iis_publish_info['has_web_config']: logger.info( "web.config for Node.js bot was fetched from Azure for deployment using IIS. To see this file " "that was used for your deployment, either visit your bot's Kudu site or download the file " "from https://icscratch.blob.core.windows.net/bot-packages/node_v4_publish.zip" ) if os.path.exists(os.path.join('.', 'package.json')) and not keep_node_modules: logger.info( 'Detected language javascript. Installing node dependencies in remote bot.' ) kudu_client.install_node_dependencies() if output.get('active'): logger.info('Deployment successful!') if not output.get('active'): scm_url = output.get('url') deployment_id = output.get('id') # Instead of replacing "latest", which would could be in the bot name, we replace "deployments/latest" deployment_url = scm_url.replace('deployments/latest', 'deployments/%s' % deployment_id) logger.error( 'Deployment failed. To find out more information about this deployment, please visit %s.', deployment_url) return output
def publish_app(cmd, client, resource_group_name, resource_name, code_dir=None, proj_file_path=None, version='v3', # pylint:disable=too-many-statements keep_node_modules=None, timeout=None): """Publish local bot code to Azure. This method is directly called via "bot publish" :param cmd: :param client: :param resource_group_name: :param resource_name: :param code_dir: :param proj_file_path: :param version: :param keep_node_modules: :param timeout: :return: """ # Get the bot information and ensure it's not only a registration bot. bot = client.bots.get( resource_group_name=resource_group_name, resource_name=resource_name ) if bot.kind == 'bot': raise CLIError('Bot kind is \'bot\', meaning it is a registration bot. ' 'Source publish is not supported for registration only bots.') # If the user does not pass in a path to the local bot project, get the current working directory. if not code_dir: code_dir = os.getcwd() logger.info('Parameter --code-dir not provided, defaulting to current working directory, %s. ' 'For more information, run \'az bot publish -h\'', code_dir) code_dir = code_dir.strip() if not os.path.isdir(code_dir): raise CLIError('The path %s is not a valid directory. ' 'Please supply a valid directory path containing your source code.' % code_dir) # If local IIS Node.js files exist, this means two things: # 1. We may not need to download the necessary web.config and iisnode.yml files to deploy a Node.js bot on IIS. # 2. We shouldn't delete their local web.config and issnode.yml files (if they exist). iis_publish_info = { 'lang': 'Csharp' if not os.path.exists(os.path.join(code_dir, 'package.json')) else 'Node', 'has_web_config': True if os.path.exists(os.path.join(code_dir, 'web.config')) else False, 'has_iisnode_yml': True if os.path.exists(os.path.join(code_dir, 'iisnode.yml')) else False } # Ensure that the directory contains appropriate post deploy scripts folder if 'PostDeployScripts' not in os.listdir(code_dir): if version == 'v4': logger.info('Detected SDK version v4. Running prepare publish in code directory %s and for project file %s' # pylint:disable=logging-not-lazy % (code_dir, proj_file_path)) # Automatically run prepare-publish in case of v4. BotPublishPrep.prepare_publish_v4(logger, code_dir, proj_file_path, iis_publish_info) else: logger.info('Detected SDK version v3. PostDeploymentScripts folder not found in directory provided: %s', code_dir) raise CLIError('Publish directory provided is uses Bot Builder SDK V3, and as a legacy bot needs to be ' 'prepared for deployment. Please run prepare-publish. For more information, run \'az bot ' 'prepare-publish -h\'.') zip_filepath = BotPublishPrep.create_upload_zip(logger, code_dir, include_node_modules=False) logger.info('Zip file path created, at %s.', zip_filepath) kudu_client = KuduClient(cmd, resource_group_name, resource_name, bot, logger) app_settings = WebAppOperations.get_app_settings( cmd=cmd, resource_group_name=resource_group_name, name=kudu_client.bot_site_name ) scm_do_build = [item['value'] for item in app_settings if item['name'] == 'SCM_DO_BUILD_DURING_DEPLOYMENT'] if scm_do_build and scm_do_build[0] == 'true': logger.info('Detected SCM_DO_BUILD_DURING_DEPLOYMENT with value of "true" in App Service\'s Application ' 'Settings. Build will commence during deployment. For more information, see ' 'https://github.com/projectkudu/kudu/wiki/Deploying-from-a-zip-file') else: logger.warning('Didn\'t detect SCM_DO_BUILD_DURING_DEPLOYMENT or its value was "false" in App Service\'s ' 'Application Settings. Build may not commence during deployment. To learn how to trigger a build' ' when deploying to your App Service, see ' 'https://github.com/projectkudu/kudu/wiki/Deploying-from-a-zip-file') subscription_id = get_subscription_id(cmd.cli_ctx) logger.warning('To change the Application Setting via az cli, use the following command:\naz webapp config ' # pylint:disable=logging-not-lazy 'appsettings set -n %s -g %s --subscription %s --settings SCM_DO_BUILD_DURING_DEPLOYMENT=true' % (kudu_client.bot_site_name, resource_group_name, subscription_id)) output = kudu_client.publish(zip_filepath, timeout, keep_node_modules, iis_publish_info['lang']) logger.info('Bot source published. Preparing bot application to run the new source.') os.remove('upload.zip') # If the bot is a Node.js bot and did not initially have web.config, delete web.config and iisnode.yml. if iis_publish_info['lang'] == 'Node': if not iis_publish_info['has_web_config'] and os.path.exists(os.path.join(code_dir, 'web.config')): os.remove(os.path.join(code_dir, 'web.config')) if not iis_publish_info['has_iisnode_yml'] and os.path.exists(os.path.join(code_dir, 'iisnode.yml')): os.remove(os.path.join(code_dir, 'iisnode.yml')) if not iis_publish_info['has_iisnode_yml'] and not iis_publish_info['has_web_config']: logger.info("web.config and iisnode.yml for Node.js bot were fetched from Azure for deployment using IIS. " "These files have now been removed from %s." "To see the two files used for your deployment, either visit your bot's Kudu site or download " "the files from https://icscratch.blob.core.windows.net/bot-packages/node_v4_publish.zip", code_dir) elif not iis_publish_info['has_iisnode_yml']: logger.info("iisnode.yml for Node.js bot was fetched from Azure for deployment using IIS. To see this file " "that was used for your deployment, either visit your bot's Kudu site or download the file " "from https://icscratch.blob.core.windows.net/bot-packages/node_v4_publish.zip") elif not iis_publish_info['has_web_config']: logger.info("web.config for Node.js bot was fetched from Azure for deployment using IIS. To see this file " "that was used for your deployment, either visit your bot's Kudu site or download the file " "from https://icscratch.blob.core.windows.net/bot-packages/node_v4_publish.zip") if os.path.exists(os.path.join('.', 'package.json')) and not keep_node_modules: logger.info('Detected language javascript. Installing node dependencies in remote bot.') kudu_client.install_node_dependencies() if output.get('active'): logger.info('Deployment successful!') if not output.get('active'): scm_url = output.get('url') deployment_id = output.get('id') # Instead of replacing "latest", which would could be in the bot name, we replace "deployments/latest" deployment_url = scm_url.replace('deployments/latest', 'deployments/%s' % deployment_id) logger.error('Deployment failed. To find out more information about this deployment, please visit %s.', deployment_url) return output