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); }
/// <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); }
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); }
/// <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); } }
/// <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); }