/// <summary> /// Creates an app bundle by publishing it to the given directory. /// </summary> /// <param name="project">The project.</param> /// <param name="stageDirectory">The directory to which to publish.</param> /// <param name="pathsProvider">The provider for paths.</param> /// <param name="outputAction">The callback to call with output from the command.</param> /// <param name="configuration">The name of the configuration to publish.</param> public static async Task <bool> CreateAppBundleAsync( IParsedProject project, string stageDirectory, IToolsPathProvider pathsProvider, Action <string> outputAction, string configuration) { var arguments = $"publish -o \"{stageDirectory}\" -c {configuration}"; var externalTools = pathsProvider.GetExternalToolsPath(); var workingDir = project.DirectoryPath; var env = new Dictionary <string, string> { { "PATH", $"{Environment.GetEnvironmentVariable("PATH")};{externalTools}" } }; Debug.WriteLine($"Using tools from {externalTools}"); Debug.WriteLine($"Setting working directory to {workingDir}"); Directory.CreateDirectory(stageDirectory); outputAction($"dotnet {arguments}"); bool result = await ProcessUtils.Default.RunCommandAsync( file : pathsProvider.GetDotnetPath(), args : arguments, workingDir : workingDir, handler : (o, e) => outputAction(e.Line), environment : env); await GCloudWrapper.GenerateSourceContextAsync(project.DirectoryPath, stageDirectory); return(result); }
/// <summary> /// Returns true if <paramref name="project"/> can be published using this wizard. /// </summary> /// <param name="project">The project to check.</param> /// <returns>True if the project is supported by this wizard, false otherwise.</returns> public static bool CanPublish(IParsedProject project) { KnownProjectTypes projectType = project.ProjectType; return(projectType == KnownProjectTypes.WebApplication || projectType == KnownProjectTypes.NetCoreWebApplication); }
/// <summary> /// Creates an app bundle by publishing it to the given directory. /// </summary> /// <param name="project">The project.</param> /// <param name="stageDirectory">The directory the build output is published to.</param> /// <param name="outputAction">The callback to call with output from the command.</param> /// <param name="configuration">The name of the configuration to publish.</param> public async Task <bool> CreateAppBundleAsync( IParsedProject project, string stageDirectory, Func <string, OutputStream, Task> outputAction, string configuration) { string arguments = $"publish -o \"{stageDirectory}\" -c {configuration}"; string externalTools = _toolsPathProvider.GetExternalToolsPath(); string workingDir = project.DirectoryPath; var env = new Dictionary <string, string> { { "PATH", $"{Environment.GetEnvironmentVariable("PATH")};{externalTools}" } }; Debug.WriteLine($"Using tools from {externalTools}"); Debug.WriteLine($"Setting working directory to {workingDir}"); FileSystem.Directory.CreateDirectory(stageDirectory); await outputAction($"dotnet {arguments}", OutputStream.StandardOutput); bool result = await ProcessService.RunCommandAsync( file : _toolsPathProvider.GetDotnetPath(), args : arguments, handler : outputAction, workingDir : workingDir, environment : env); await GCloudWrapper.GenerateSourceContextAsync(project.DirectoryPath, stageDirectory); return(result); }
/// <summary> /// Generates the Dockerfile for this .NET Core project. /// </summary> /// <param name="project">The project.</param> internal static void GenerateDockerfile(IParsedProject project) { var targetDockerfile = Path.Combine(project.DirectoryPath, DockerfileName); var content = String.Format(DockerfileDefaultContent, project.Name); File.WriteAllText(targetDockerfile, content); }
/// <summary> /// This method stages the application into the <paramref name="stageDirectory"/> by invoking the WebPublish target /// present in all Web projects. It publishes to the staging directory by using the FileSystem method. /// </summary> private static async Task <bool> CreateAppBundleAsync( IParsedProject project, string stageDirectory, IToolsPathProvider toolsPathProvider, Action <string> outputAction) { var arguments = $@"""{project.FullPath}""" + " " + "/p:Configuration=Release " + "/p:Platform=AnyCPU " + "/t:WebPublish " + "/p:WebPublishMethod=FileSystem " + "/p:DeleteExistingFiles=True " + $@"/p:publishUrl=""{stageDirectory}"""; outputAction($"msbuild.exe {arguments}"); bool result = await ProcessUtils.RunCommandAsync(toolsPathProvider.GetMsbuildPath(), arguments, (o, e) => outputAction(e.Line)); // We perform this check here because it is not required to have gcloud installed in order to deploy // ASP.NET 4.x apps to GCE VMs. Therefore nothing would have checked for the presence of gcloud before // getting here. var gcloudValidation = await GCloudWrapper.ValidateGCloudAsync(); Debug.WriteLineIf(!gcloudValidation.IsValid, "Skipping creating context, gcloud is not installed."); if (gcloudValidation.IsValid) { await GCloudWrapper.GenerateSourceContext(project.DirectoryPath, stageDirectory); } return(result); }
/// <summary> /// Publishes the ASP.NET Core project to App Engine Flex and reports progress to the UI. /// </summary> /// <param name="project">The project to deploy.</param> /// <param name="options">The <see cref="DeploymentOptions"/> to use.</param> public async Task PublishProjectAsync(IParsedProject project, DeploymentOptions options) { try { ShellUtils.SaveAllFiles(); GcpOutputWindow.Activate(); GcpOutputWindow.Clear(); GcpOutputWindow.OutputLine(string.Format(Resources.FlexPublishStepStartMessage, project.Name)); TimeSpan deploymentDuration; AppEngineFlexDeploymentResult result; using (StatusbarHelper.Freeze()) using (StatusbarHelper.ShowDeployAnimation()) using (ProgressBarHelper progress = StatusbarHelper.ShowProgressBar(Resources.FlexPublishProgressMessage)) using (ShellUtils.SetShellUIBusy()) { DateTime startDeploymentTime = DateTime.Now; result = await PublishProjectAsync( project, options, progress, VsVersionUtils.ToolsPathProvider, GcpOutputWindow.OutputLine); deploymentDuration = DateTime.Now - startDeploymentTime; } if (result != null) { GcpOutputWindow.OutputLine(string.Format(Resources.FlexPublishSuccessMessage, project.Name)); StatusbarHelper.SetText(Resources.PublishSuccessStatusMessage); string url = result.GetDeploymentUrl(); GcpOutputWindow.OutputLine(string.Format(Resources.PublishUrlMessage, url)); if (options.OpenWebsite) { Process.Start(url); } EventsReporterWrapper.ReportEvent( GaeDeployedEvent.Create(CommandStatus.Success, deploymentDuration)); } else { GcpOutputWindow.OutputLine(string.Format(Resources.FlexPublishFailedMessage, project.Name)); StatusbarHelper.SetText(Resources.PublishFailureStatusMessage); EventsReporterWrapper.ReportEvent(GaeDeployedEvent.Create(CommandStatus.Failure, deploymentDuration)); } } catch (Exception) { EventsReporterWrapper.ReportEvent(GaeDeployedEvent.Create(CommandStatus.Failure)); GcpOutputWindow.OutputLine(string.Format(Resources.FlexPublishFailedMessage, project.Name)); StatusbarHelper.SetText(Resources.PublishFailureStatusMessage); } }
/// <summary> /// Publishes the ASP.NET Core project to App Engine Flex. /// </summary> /// <param name="project">The project to deploy.</param> /// <param name="options">The <seealso cref="DeploymentOptions"/> to use.</param> /// <param name="progress">The progress indicator.</param> private async Task <AppEngineFlexDeploymentResult> PublishProjectAsync( IParsedProject project, DeploymentOptions options, IProgress <double> progress) { string stageDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Directory.CreateDirectory(stageDirectory); await progress.ReportAsync(0.1); using (new Disposable(() => CommonUtils.Cleanup(stageDirectory))) { // Wait for the bundle creation operation to finish, updating progress as it goes. Task <bool> createAppBundleTask = NetCoreAppUtils.CreateAppBundleAsync( project, stageDirectory, GcpOutputWindow.OutputLineAsync, options.Configuration); if (!await progress.UpdateProgressAsync(createAppBundleTask, 0.1, 0.3)) { Debug.WriteLine("Failed to create app bundle."); return(null); } string runtime = ConfigurationService.GetAppEngineRuntime(project); ConfigurationService.CopyOrCreateAppYaml(project, stageDirectory, options.Service); if (runtime == AppEngineConfiguration.CustomRuntime) { Debug.WriteLine($"Copying Docker file to {stageDirectory} with custom runtime."); NetCoreAppUtils.CopyOrCreateDockerfile(project, stageDirectory); } else { Debug.WriteLine($"Detected runtime {runtime}"); } await progress.ReportAsync(0.4); // Deploy to app engine, this is where most of the time is going to be spent. Wait for // the operation to finish, update the progress as it goes. Task <bool> deployTask = DeployAppBundleAsync( stageDirectory: stageDirectory, version: options.Version, promote: options.Promote, context: options.Context); if (!await progress.UpdateProgressAsync(deployTask, 0.6, 0.9)) { Debug.WriteLine("Failed to deploy bundle."); return(null); } await progress.ReportAsync(1.0); string service = options.Service ?? ConfigurationService.GetAppEngineService(project); return(new AppEngineFlexDeploymentResult( projectId: options.Context.ProjectId, service: service, version: options.Version, promoted: options.Promote)); } }
/// <summary> /// Generates the Dockerfile for this .NET Core project. /// </summary> /// <param name="project">The project.</param> internal static void GenerateDockerfile(IParsedProject project) { var targetDockerfile = Path.Combine(project.DirectoryPath, DockerfileName); var baseImage = s_knownRuntimeImages[project.ProjectType]; var content = String.Format(DockerfileDefaultContent, baseImage, project.Name); File.WriteAllText(targetDockerfile, content); }
/// <summary> /// Generates the Dockerfile for this .NET Core project. /// </summary> /// <param name="project">The project.</param> public static void GenerateDockerfile(IParsedProject project) { string targetDockerfile = Path.Combine(project.DirectoryPath, DockerfileName); string baseImage = string.Format(RuntimeImageFormat, project.FrameworkVersion); string content = string.Format(DockerfileDefaultContent, baseImage, project.Name); File.WriteAllText(targetDockerfile, content); }
/// <summary> /// Checks the project configuration files to see if they exist. /// </summary> /// <param name="project">The project.</param> /// <returns>An instance of <seealso cref="ProjectConfigurationStatus"/> with the status of the config.</returns> public ProjectConfigurationStatus CheckProjectConfiguration(IParsedProject project) { string targetAppYaml = GetAppYamlPath(project); bool hasAppYaml = FileSystem.File.Exists(targetAppYaml); bool hasDockefile = NetCoreAppUtils.CheckDockerfile(project); return(new ProjectConfigurationStatus(hasAppYaml, hasDockefile)); }
/// <summary> /// Generates the Dockerfile for this .NET Core project. /// </summary> /// <param name="project">The project.</param> public void GenerateDockerfile(IParsedProject project) { string targetDockerfile = GetProjectDockerfilePath(project); string baseImage = string.Format(RuntimeImageFormat, project.FrameworkVersion); string content = string.Format(DockerfileDefaultContent, baseImage, project.Name); FileSystem.File.WriteAllText(targetDockerfile, content); }
/// <summary> /// Checks the project configuration files to see if they exist. /// </summary> /// <param name="project">The project.</param> /// <returns>An instance of <seealso cref="ProjectConfigurationStatus"/> with the status of the config.</returns> public static ProjectConfigurationStatus CheckProjectConfiguration(IParsedProject project) { var projectDirectory = project.DirectoryPath; var targetAppYaml = Path.Combine(projectDirectory, AppYamlName); var hasAppYaml = File.Exists(targetAppYaml); var hasDockefile = NetCoreAppUtils.CheckDockerfile(project); return(new ProjectConfigurationStatus(hasAppYaml: hasAppYaml, hasDockerfile: hasDockefile)); }
private static string GetAppEngineRuntime(IParsedProject project) { string appYaml = GetAppYamlPath(project); if (!File.Exists(appYaml)) { return(AspNetCoreRuntime); } return(GetYamlProperty(appYaml, RuntimeYamlProperty)); }
private PublishDialogWindow(IParsedProject project) : base(String.Format(GoogleCloudExtension.Resources.PublishDialogCaption, project.Name)) { var initialStep = ChoiceStepViewModel.CreateStep(); ViewModel = new PublishDialogWindowViewModel(project, initialStep, this); Content = new PublishDialogWindowContent { DataContext = ViewModel }; }
public PublishDialogWindowViewModel(IParsedProject project, IPublishDialogStep initialStep, PublishDialogWindow owner) { _owner = owner; _project = project; PrevCommand = new ProtectedCommand(OnPrevCommand); NextCommand = new ProtectedCommand(OnNextCommand); PublishCommand = new ProtectedCommand(OnPublishCommand); PushStep(initialStep); }
/// <summary> /// Generates the Dockerfile for the given project. /// </summary> /// <param name="project">The project.</param> public static bool GenerateDockerfile(IParsedProject project) { try { NetCoreAppUtils.GenerateDockerfile(project); return(true); } catch (IOException ex) { Debug.WriteLine($"Failed to generate Dockerfile: {ex.Message}"); return(false); } }
/// <summary> /// Gets the runtime defined in the app.yaml, or <see cref="AspNetCoreRuntime"/> if there is no app.yaml. /// </summary> /// <param name="project">The project that contains the app.yaml.</param> /// <returns>The runtime in the app.yaml, or <see cref="AspNetCoreRuntime"/> if there is no app.yaml</returns> public string GetAppEngineRuntime(IParsedProject project) { string appYaml = GetAppYamlPath(project); if (FileSystem.File.Exists(appYaml)) { return(GetYamlProperty(appYaml, RuntimeYamlProperty)); } else { return(AspNetCoreRuntime); } }
private static void CopyOrCreateAppYaml(IParsedProject project, string stageDirectory) { var sourceAppYaml = Path.Combine(project.DirectoryPath, AppYamlName); var targetAppYaml = Path.Combine(stageDirectory, AppYamlName); if (File.Exists(sourceAppYaml)) { File.Copy(sourceAppYaml, targetAppYaml, overwrite: true); } else { File.WriteAllText(targetAppYaml, AppYamlDefaultContent); } }
/// <summary> /// Generates the app.yaml for the given project. /// </summary> /// <param name="project">The project.</param> public static bool GenerateAppYaml(IParsedProject project) { try { var targetAppYaml = Path.Combine(project.DirectoryPath, AppYamlName); File.WriteAllText(targetAppYaml, AppYamlDefaultContent); return(true); } catch (IOException ex) { Debug.WriteLine($"Failed to generate app.yaml: {ex.Message}"); return(false); } }
/// <summary> /// Creates the Dockerfile necessary to package up an ASP.NET Core app if one is not already present at the root /// path of the project. /// </summary> /// <param name="project">The project.</param> /// <param name="stageDirectory">The directory where to save the Dockerfile.</param> internal static void CopyOrCreateDockerfile(IParsedProject project, string stageDirectory) { var sourceDockerfile = Path.Combine(project.DirectoryPath, DockerfileName); var targetDockerfile = Path.Combine(stageDirectory, DockerfileName); if (File.Exists(sourceDockerfile)) { File.Copy(sourceDockerfile, targetDockerfile, overwrite: true); } else { var content = String.Format(DockerfileDefaultContent, project.Name); File.WriteAllText(targetDockerfile, content); } }
/// <summary> /// Creates the Dockerfile necessary to package up an ASP.NET Core app if one is not already present at the root /// path of the project. /// </summary> /// <param name="project">The project.</param> /// <param name="stageDirectory">The directory where to save the Dockerfile.</param> public void CopyOrCreateDockerfile(IParsedProject project, string stageDirectory) { string sourceDockerfile = GetProjectDockerfilePath(project); string targetDockerfile = Path.Combine(stageDirectory, DockerfileName); string entryPointName = CommonUtils.GetEntrypointName(stageDirectory) ?? project.Name; string baseImage = string.Format(RuntimeImageFormat, project.FrameworkVersion); if (FileSystem.File.Exists(sourceDockerfile)) { FileSystem.File.Copy(sourceDockerfile, targetDockerfile, overwrite: true); } else { string content = string.Format(DockerfileDefaultContent, baseImage, entryPointName); FileSystem.File.WriteAllText(targetDockerfile, content); } }
/// <summary> /// Creates the Dockerfile necessary to package up an ASP.NET Core app if one is not already present at the root /// path of the project. /// </summary> /// <param name="project">The project.</param> /// <param name="stageDirectory">The directory where to save the Dockerfile.</param> internal static void CopyOrCreateDockerfile(IParsedProject project, string stageDirectory) { var sourceDockerfile = Path.Combine(project.DirectoryPath, DockerfileName); var targetDockerfile = Path.Combine(stageDirectory, DockerfileName); var entryPointName = CommonUtils.GetEntrypointName(stageDirectory) ?? project.Name; var baseImage = s_knownRuntimeImages[project.ProjectType]; if (File.Exists(sourceDockerfile)) { File.Copy(sourceDockerfile, targetDockerfile, overwrite: true); } else { var content = String.Format(DockerfileDefaultContent, baseImage, entryPointName); File.WriteAllText(targetDockerfile, content); } }
/// <summary> /// Publishes an ASP.NET 4.x project to the given GCE <seealso cref="Instance"/>. /// </summary> /// <param name="project">The project to deploy.</param> /// <param name="targetInstance">The instance to deploy.</param> /// <param name="credentials">The Windows credentials to use to deploy to the <paramref name="targetInstance"/>.</param> /// <param name="progress">The progress indicator.</param> /// <param name="toolsPathProvider">Povides the path to the publishing tools.</param> /// <param name="outputAction">The action to call with lines of output.</param> public static async Task <bool> PublishProjectAsync( IParsedProject project, Instance targetInstance, WindowsInstanceCredentials credentials, IProgress <double> progress, IToolsPathProvider toolsPathProvider, Action <string> outputAction) { var stagingDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Directory.CreateDirectory(stagingDirectory); progress.Report(0.1); var publishSettingsPath = Path.GetTempFileName(); var publishSettingsContent = targetInstance.GeneratePublishSettings(credentials.User, credentials.Password); File.WriteAllText(publishSettingsPath, publishSettingsContent); using (var cleanup = new Disposable(() => Cleanup(publishSettingsPath, stagingDirectory))) { // Wait for the bundle operation to finish and update the progress in the mean time to show progress. if (!await ProgressHelper.UpdateProgress( CreateAppBundleAsync(project, stagingDirectory, toolsPathProvider, outputAction), progress, from: 0.1, to: 0.5)) { return(false); } progress.Report(0.6); // Update for the deploy operation to finish and update the progress as it goes. if (!await ProgressHelper.UpdateProgress( DeployAppAsync(stagingDirectory, publishSettingsPath, toolsPathProvider, outputAction), progress, from: 0.6, to: 0.9)) { return(false); } progress.Report(1); } return(true); }
private void OnBeforeQueryStatus(object sender, EventArgs e) { if (!(sender is OleMenuCommand menuCommand)) { return; } // Ensure that the menu entry is only available for ASP.NET Core projects. IParsedProject selectedProject = SolutionHelper.CurrentSolution.SelectedProject?.ParsedProject; if (selectedProject?.ProjectType != KnownProjectTypes.NetCoreWebApplication) { menuCommand.Visible = false; } else { menuCommand.Visible = true; menuCommand.Enabled = !ShellUtils.Default.IsBusy(); } }
/// <summary> /// This method stages the application into the <paramref name="stageDirectory"/> by invoking the WebPublish target /// present in all Web projects. It publishes to the staging directory by using the FileSystem method. /// </summary> private static async Task <bool> CreateAppBundleAsync( IParsedProject project, string stageDirectory, IToolsPathProvider toolsPathProvider, Action <string> outputAction) { var arguments = $@"""{project.FullPath}""" + " " + "/p:Configuration=Release " + "/p:Platform=AnyCPU " + "/t:WebPublish " + "/p:WebPublishMethod=FileSystem " + "/p:DeleteExistingFiles=True " + $@"/p:publishUrl=""{stageDirectory}"""; outputAction($"msbuild.exe {arguments}"); bool result = await ProcessUtils.RunCommandAsync(toolsPathProvider.GetMsbuildPath(), arguments, (o, e) => outputAction(e.Line)); await GCloudWrapper.GenerateSourceContext(project.DirectoryPath, stageDirectory); return(result); }
private void OutputResultData( IParsedProject project, Options options, Result result) { if (result.ServiceExposed) { if (result.ServicePublicIpAddress != null) { GcpOutputWindow.OutputLine( string.Format( Resources.GkePublishServiceIpMessage, options.DeploymentName, result.ServicePublicIpAddress)); } else if (options.ExposePublicService) { GcpOutputWindow.OutputLine(Resources.GkePublishServiceIpTimeoutMessage); } else { GcpOutputWindow.OutputLine( string.Format( Resources.GkePublishServiceClusterIpMessage, options.DeploymentName, result.ServiceClusterIpAddress)); } } if (result.Failed) { GcpOutputWindow.OutputLine( string.Format(Resources.GkePublishDeploymentFailureMessage, project.Name)); } else { GcpOutputWindow.OutputLine( string.Format(Resources.GkePublishDeploymentSuccessMessage, project.Name)); } }
/// <summary> /// Creates an app.yaml in the target directory that targets the given service. /// If the given project contains an app.yaml, it is the source of the new file. /// Otherwise, a default app.yaml is created. /// </summary> /// <param name="project">The project that may have a source app.yaml to copy.</param> /// <param name="targetDirectory">The directory to create or copy the app.yaml to.</param> /// <param name="service">The service the new app.yaml will target.</param> public void CopyOrCreateAppYaml(IParsedProject project, string targetDirectory, string service) { string sourceAppYaml = GetAppYamlPath(project); string targetAppYaml = Path.Combine(targetDirectory, AppYamlName); if (FileSystem.File.Exists(sourceAppYaml)) { string appYamlService = GetAppEngineService(project); if (service == appYamlService || IsDefaultService(service) && IsDefaultService(appYamlService)) { FileSystem.File.Copy(sourceAppYaml, targetAppYaml, true); } else { SetAppYamlService(service, sourceAppYaml, targetAppYaml); } } else { GenerateAppYaml(targetAppYaml, service); } }
private async Task <string> BuildImageAsync(IParsedProject project, Options options, IProgress <double> progress) { ShellUtils.SaveAllFiles(); string stageDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); await progress.ReportAsync(0.1); using (new Disposable(() => CommonUtils.Cleanup(stageDirectory))) { Task <bool> createAppBundleTask = NetCoreAppUtils.CreateAppBundleAsync( project, stageDirectory, GcpOutputWindow.OutputLineAsync, options.Configuration); if (!await progress.UpdateProgressAsync(createAppBundleTask, 0.1, 0.3)) { return(null); } NetCoreAppUtils.CopyOrCreateDockerfile(project, stageDirectory); string imageTag = CloudBuilderUtils.GetImageTag( options.KubectlContext.ProjectId, options.DeploymentName, options.DeploymentVersion); Task <bool> buildContainerTask = options.KubectlContext.BuildContainerAsync(imageTag, stageDirectory, GcpOutputWindow.OutputLineAsync); if (!await progress.UpdateProgressAsync(buildContainerTask, 0.4, 0.7)) { return(null); } return(imageTag); } }
private string GetAppYamlPath(IParsedProject project) => Path.Combine(project.DirectoryPath, AppYamlName);
/// <summary> /// This methods looks for lines of the form "service: name" in the app.yaml file provided. /// </summary> /// <param name="project">The project.</param> /// <returns>The service name if found, <seealso cref="DefaultServiceName"/> if not found.</returns> public string GetAppEngineService(IParsedProject project) { string appYamlPath = GetAppYamlPath(project); return(GetYamlProperty(appYamlPath, ServiceYamlProperty, DefaultServiceName)); }