public async Task <string> ConfigureCdkProject(OrchestratorSession session, CloudApplication cloudApplication, Recommendation recommendation)
        {
            string?cdkProjectPath;

            if (recommendation.Recipe.PersistedDeploymentProject)
            {
                if (string.IsNullOrEmpty(recommendation.Recipe.RecipePath))
                {
                    throw new InvalidOperationException($"{nameof(recommendation.Recipe.RecipePath)} cannot be null");
                }

                // The CDK deployment project is already saved in the same directory.
                cdkProjectPath = _directoryManager.GetDirectoryInfo(recommendation.Recipe.RecipePath).Parent.FullName;
            }
            else
            {
                // Create a new temporary CDK project for a new deployment
                _interactiveService.LogMessageLine($"Generating a {recommendation.Recipe.Name} CDK Project");
                cdkProjectPath = CreateCdkProject(recommendation, session);
            }

            // Write required configuration in appsettings.json
            var appSettingsBody     = _appSettingsBuilder.Build(cloudApplication, recommendation, session);
            var appSettingsFilePath = Path.Combine(cdkProjectPath, "appsettings.json");

            await using var appSettingsFile = new StreamWriter(appSettingsFilePath);
            await appSettingsFile.WriteAsync(appSettingsBody);

            return(cdkProjectPath);
        }
Пример #2
0
        /// <summary>
        /// This method takes a user specified directory path and generates the CDK deployment project at this location.
        /// If the provided directory path is an empty string, then a default directory is created to save the CDK deployment project.
        /// </summary>
        /// <param name="saveCdkDirectoryPath">An absolute or a relative path provided by the user.</param>
        /// <param name="projectDisplayName">The name of the deployment project that will be displayed in the list of available deployment options.</param>
        /// <returns></returns>
        public async Task ExecuteAsync(string saveCdkDirectoryPath, string projectDisplayName)
        {
            var orchestrator    = new Orchestrator(_session, new[] { RecipeLocator.FindRecipeDefinitionsPath() });
            var recommendations = await GenerateRecommendationsToSaveDeploymentProject(orchestrator);

            var selectedRecommendation = _consoleUtilities.AskToChooseRecommendation(recommendations);

            if (string.IsNullOrEmpty(saveCdkDirectoryPath))
            {
                saveCdkDirectoryPath = GenerateDefaultSaveDirectoryPath();
            }

            var newDirectoryCreated = CreateSaveCdkDirectory(saveCdkDirectoryPath);

            var(isValid, errorMessage) = ValidateSaveCdkDirectory(saveCdkDirectoryPath);
            if (!isValid)
            {
                if (newDirectoryCreated)
                {
                    _directoryManager.Delete(saveCdkDirectoryPath);
                }
                errorMessage = $"Failed to generate deployment project.{Environment.NewLine}{errorMessage}";
                throw new InvalidSaveDirectoryForCdkProject(errorMessage.Trim());
            }

            var directoryUnderSourceControl = await IsDirectoryUnderSourceControl(saveCdkDirectoryPath);

            if (!directoryUnderSourceControl)
            {
                var userPrompt = "Warning: The target directory is not being tracked by source control. If the saved deployment " +
                                 "project is used for deployment it is important that the deployment project is retained to allow " +
                                 "future redeployments to previously deployed applications. " + Environment.NewLine + Environment.NewLine +
                                 "Do you still want to continue?";

                _toolInteractiveService.WriteLine();
                var yesNoResult = _consoleUtilities.AskYesNoQuestion(userPrompt, YesNo.Yes);

                if (yesNoResult == YesNo.No)
                {
                    if (newDirectoryCreated)
                    {
                        _directoryManager.Delete(saveCdkDirectoryPath);
                    }
                    return;
                }
            }

            _cdkProjectHandler.CreateCdkProject(selectedRecommendation, _session, saveCdkDirectoryPath);
            await GenerateDeploymentRecipeSnapShot(selectedRecommendation, saveCdkDirectoryPath, projectDisplayName);

            var saveCdkDirectoryFullPath = _directoryManager.GetDirectoryInfo(saveCdkDirectoryPath).FullName;

            _toolInteractiveService.WriteLine();
            _toolInteractiveService.WriteLine($"The CDK deployment project is saved at: {saveCdkDirectoryFullPath}");

            await _deploymentManifestEngine.UpdateDeploymentManifestFile(saveCdkDirectoryFullPath, _targetApplicationFullPath);
        }
Пример #3
0
        public DeploymentManifestFileTests()
        {
            _fileManager          = new FileManager();
            _directoryManager     = new DirectoryManager();
            _testDirectoryManager = new TestDirectoryManager();
            _testAppManager       = new TestAppManager();
            var targetApplicationPath = _testAppManager.GetProjectPath(Path.Combine("testapps", "WebAppWithDockerFile", "WebAppWithDockerFile.csproj"));;

            _targetApplicationFullPath          = _directoryManager.GetDirectoryInfo(targetApplicationPath).FullName;
            _targetApplicationDirectoryFullPath = _directoryManager.GetDirectoryInfo(targetApplicationPath).Parent.FullName;
            _deploymentManifestEngine           = new DeploymentManifestEngine(_testDirectoryManager, _fileManager);
        }
        /// <summary>
        /// Fetches custom recipe paths from other locations that are monitored by the same source control root
        /// as the target application that needs to be deployed.
        /// If the target application is not under source control then it scans the sub-directories of the solution folder for custom recipes.
        /// </summary>
        /// <param name="targetApplicationFullPath">The absolute path to the target application csproj or fsproj file</param>
        /// <param name="solutionDirectoryPath">The absolute path of the directory which contains the solution file for the target application</param>
        /// <returns>A list of recipe definition paths.</returns>
        private async Task <List <string> > LocateAlternateRecipePaths(string targetApplicationFullPath, string solutionDirectoryPath)
        {
            var    targetApplicationDirectoryPath = _directoryManager.GetDirectoryInfo(targetApplicationFullPath).Parent.FullName;
            string?rootDirectoryPath;

            if (await IsDirectoryUnderSourceControl(targetApplicationDirectoryPath))
            {
                rootDirectoryPath = await GetSourceControlRootDirectory(targetApplicationDirectoryPath);
            }
            else
            {
                rootDirectoryPath = solutionDirectoryPath;
            }

            return(GetRecipePathsFromRootDirectory(rootDirectoryPath));
        }
        /// <summary>
        /// This method returns the path at which the local user settings file will be stored.
        /// </summary>
        private string GetLocalUserSettingsFilePath()
        {
            var deployToolWorkspace           = _directoryManager.GetDirectoryInfo(Constants.CDK.DeployToolWorkspaceDirectoryRoot).FullName;
            var localUserSettingsFileFullPath = Path.Combine(deployToolWorkspace, LOCAL_USER_SETTINGS_FILE_NAME);

            return(localUserSettingsFileFullPath);
        }
Пример #6
0
        /// <summary>
        /// This method updates the deployment manifest json file by adding the directory path at which the CDK deployment project is saved.
        /// If the manifest file does not exists then a new file is generated.
        /// <param name="saveCdkDirectoryFullPath">The absolute path to the directory at which the CDK deployment project is saved</param>
        /// <param name="targetApplicationFullPath">The absolute path to the target application csproj or fsproj file.</param>
        /// <exception cref="FailedToUpdateDeploymentManifestFileException">Thrown if an error occured while trying to update the deployment manifest file.</exception>
        /// </summary>
        /// <returns></returns>
        public async Task UpdateDeploymentManifestFile(string saveCdkDirectoryFullPath, string targetApplicationFullPath)
        {
            try
            {
                if (!_directoryManager.Exists(saveCdkDirectoryFullPath))
                {
                    return;
                }

                var deploymentManifestFilePath     = GetDeploymentManifestFilePath(targetApplicationFullPath);
                var targetApplicationDirectoryPath = _directoryManager.GetDirectoryInfo(targetApplicationFullPath).Parent.FullName;
                var saveCdkDirectoryRelativePath   = _directoryManager.GetRelativePath(targetApplicationDirectoryPath, saveCdkDirectoryFullPath);

                DeploymentManifestModel deploymentManifestModel;

                if (_fileManager.Exists(deploymentManifestFilePath))
                {
                    deploymentManifestModel = await ReadManifestFile(deploymentManifestFilePath);

                    if (deploymentManifestModel.DeploymentProjects == null)
                    {
                        deploymentManifestModel.DeploymentProjects = new List <DeploymentManifestEntry> {
                            new DeploymentManifestEntry(saveCdkDirectoryRelativePath)
                        };
                    }
                    else
                    {
                        deploymentManifestModel.DeploymentProjects.Add(new DeploymentManifestEntry(saveCdkDirectoryRelativePath));
                    }
                }
                else
                {
                    var deploymentManifestEntries = new List <DeploymentManifestEntry> {
                        new DeploymentManifestEntry(saveCdkDirectoryRelativePath)
                    };
                    deploymentManifestModel = new DeploymentManifestModel(deploymentManifestEntries);
                }

                var manifestFileJsonString = SerializeManifestModel(deploymentManifestModel);
                await _fileManager.WriteAllTextAsync(deploymentManifestFilePath, manifestFileJsonString);
            }
            catch (Exception ex)
            {
                throw new FailedToUpdateDeploymentManifestFileException($"Failed to update the deployment manifest file " +
                                                                        $"for the deployment project stored at '{saveCdkDirectoryFullPath}'", ex);
            }
        }
Пример #7
0
        /// <summary>
        /// This method parses the target application project and sets the
        /// appropriate metadata as part of the <see cref="ProjectDefinition"/>
        /// </summary>
        /// <param name="projectPath">The project path can be an absolute or a relative path to the
        /// target application project directory or the application project file.</param>
        /// <returns><see cref="ProjectDefinition"/></returns>
        public async Task <ProjectDefinition> Parse(string projectPath)
        {
            if (_directoryManager.Exists(projectPath))
            {
                projectPath = _directoryManager.GetDirectoryInfo(projectPath).FullName;
                var files = _directoryManager.GetFiles(projectPath, "*.csproj");
                if (files.Length == 1)
                {
                    projectPath = Path.Combine(projectPath, files[0]);
                }
                else if (files.Length == 0)
                {
                    files = _directoryManager.GetFiles(projectPath, "*.fsproj");
                    if (files.Length == 1)
                    {
                        projectPath = Path.Combine(projectPath, files[0]);
                    }
                }
            }

            if (!_fileManager.Exists(projectPath))
            {
                throw new ProjectFileNotFoundException(projectPath);
            }

            var xmlProjectFile = new XmlDocument();

            xmlProjectFile.LoadXml(await _fileManager.ReadAllTextAsync(projectPath));

            var projectDefinition = new ProjectDefinition(
                xmlProjectFile,
                projectPath,
                await GetProjectSolutionFile(projectPath),
                xmlProjectFile.DocumentElement?.Attributes["Sdk"]?.Value ??
                throw new InvalidProjectDefinitionException(
                    "The project file that is being referenced does not contain and 'Sdk' attribute.")
                );

            var targetFramework = xmlProjectFile.GetElementsByTagName("TargetFramework");

            if (targetFramework.Count > 0)
            {
                projectDefinition.TargetFramework = targetFramework[0]?.InnerText;
            }

            var assemblyName = xmlProjectFile.GetElementsByTagName("AssemblyName");

            if (assemblyName.Count > 0)
            {
                projectDefinition.AssemblyName = (string.IsNullOrWhiteSpace(assemblyName[0]?.InnerText) ? Path.GetFileNameWithoutExtension(projectPath) : assemblyName[0]?.InnerText);
            }
            else
            {
                projectDefinition.AssemblyName = Path.GetFileNameWithoutExtension(projectPath);
            }

            return(projectDefinition);
        }