/// <summary> /// Initializes the singleton instance of the command. /// </summary> /// <param name="package">Owner package, not null.</param> /// <param name="token"></param> public static async Task InitializeAsync(IGoogleCloudExtensionPackage package, CancellationToken token) { if (package == null) { throw new ArgumentNullException(nameof(package)); } if (await package.GetServiceAsync(typeof(IMenuCommandService)) is OleMenuCommandService commandService) { await package.JoinableTaskFactory.SwitchToMainThreadAsync(token); var menuCommandID = new CommandID(CommandSet, CommandId); var menuItem = new OleMenuCommand(OnDeployCommand, menuCommandID); menuItem.BeforeQueryStatus += OnBeforeQueryStatus; commandService.AddCommand(menuItem); } // <summary> // This function is the callback used to execute the command when the menu item is clicked. // See the constructor to see how the menu item is associated with this function using // OleMenuCommandService service and MenuCommand class. // </summary> // <param name="sender">Event sender.</param> // <param name="e">Event args.</param> async void OnDeployCommand(object sender, EventArgs e) { await GoogleCloudExtensionPackage.Instance.JoinableTaskFactory.SwitchToMainThreadAsync(); IParsedDteProject project = SolutionHelper.CurrentSolution.StartupProject.ParsedProject; PublishDialogWindow.PromptUser(project); } void OnBeforeQueryStatus(object sender, EventArgs e) { #pragma warning disable VSTHRD109 // Switch instead of assert in async methods ThreadHelper.ThrowIfNotOnUIThread(); #pragma warning restore VSTHRD109 // Switch instead of assert in async methods if (!(sender is OleMenuCommand menuCommand)) { return; } menuCommand.Visible = true; IParsedDteProject startupProject = SolutionHelper.CurrentSolution.StartupProject?.ParsedProject; if (startupProject == null) { menuCommand.Enabled = false; menuCommand.Text = Resources.PublishDialogGenericMenuHeader; } else { menuCommand.Enabled = PublishDialogWindow.CanPublish(startupProject) && !ShellUtils.Default.IsBusy(); menuCommand.Text = string.Format(Resources.PublishDialogProjectMenuHeader, startupProject.Name); } } }
protected override void BeforeEach() { _propertyServiceMock = new Mock <IVsProjectPropertyService>(); PackageMock.Setup(p => p.GetMefService <IVsProjectPropertyService>()).Returns(_propertyServiceMock.Object); _mockedProject = Mock.Of <Project>(); _mockedParsedProject = Mock.Of <IParsedDteProject>(p => p.Project == _mockedProject); }
public void TestParseProject_ReturnsNullForBadFileExtension() { _projectMock.Setup(p => p.FullName).Returns(@"c:\path\to\project.bad"); IParsedDteProject result = ProjectParser.ParseProject(_projectMock.Object); Assert.IsNull(result); }
public void TestParseProject_ReturnsNullForXProjectExtensionMissingProjectJson() { _projectMock.Setup(p => p.FullName).Returns(@"c:\path\to\project.xproj"); _fileSystemMock.Setup(fs => fs.File.Exists(@"c:\path\to\project.json")).Returns(false); IParsedDteProject result = ProjectParser.ParseProject(_projectMock.Object); Assert.IsNull(result); }
public void TestParseProject_ReturnsJsonProjectForXProjectExtensionWithProjectJson() { _projectMock.Setup(p => p.FullName).Returns(@"c:\path\to\project.xproj"); _fileSystemMock.Setup(fs => fs.File.Exists(@"c:\path\to\project.json")).Returns(true); IParsedDteProject result = ProjectParser.ParseProject(_projectMock.Object); Assert.IsInstanceOfType(result, typeof(JsonProject)); }
private PublishDialogWindow(IParsedDteProject project) : base(string.Format(GoogleCloudExtension.Resources.PublishDialogCaption, project.Name)) { ViewModel = new PublishDialogWindowViewModel(project, Close); Content = new PublishDialogWindowContent { DataContext = ViewModel }; Closed += (sender, args) => ViewModel.FinishFlow(); }
/// <summary> /// This function is the callback used to execute the command when the menu item is clicked. /// See the constructor to see how the menu item is associated with this function using /// OleMenuCommandService service and MenuCommand class. /// </summary> /// <param name="sender">Event sender.</param> /// <param name="e">Event args.</param> private static void OnDeployCommand(object sender, EventArgs e) { ThreadHelper.ThrowIfNotOnUIThread(); ErrorHandlerUtils.HandleExceptions(() => { IParsedDteProject selectedProject = SolutionHelper.CurrentSolution.SelectedProject.ParsedProject; Debug.WriteLine($"Deploying project: {selectedProject.FullPath}"); PublishDialogWindow.PromptUser(selectedProject); }); }
/// <summary> /// Generates the app.yaml for the given project. /// </summary> /// <param name="project">The project.</param> /// <param name="service">The service the new app.yaml will target. Defaults to the default service.</param> public void AddAppYamlItem(IParsedDteProject project, string service = DefaultServiceName) { string targetAppYaml = GetAppYamlPath(project); GenerateAppYaml(targetAppYaml, service); ProjectItem appYamlItem = project.Project.ProjectItems.AddFromFile(targetAppYaml); // Set "Copy To Output Directory" to "Copy if newer". appYamlItem.Properties.Item(ProjectPropertyConstants.CopyToOutputDirectory.Name).Value = ProjectPropertyConstants.CopyToOutputDirectory.CopyIfNewerValue; }
protected override void BeforeEach() { _parsedProjectMock = new Mock <IParsedDteProject> { DefaultValue = DefaultValue.Mock }; _parsedProjectMock.Setup(p => p.DirectoryPath).Returns(ProjectDirectory); _mockedParsedProject = _parsedProjectMock.Object; _fileSystemMock = new Mock <IFileSystem> { DefaultValue = DefaultValue.Mock }; _objectUnderTest = new AppEngineConfiguration(_fileSystemMock.ToLazy()); }
/// <summary> /// Updates or generates tha app.yaml file for the given project with the given servie. /// </summary> /// <param name="project">The project that contains the app.yaml</param> /// <param name="service">The name of the service the app.yaml will target.</param> public void SaveServiceToAppYaml(IParsedDteProject project, string service) { string appYamlPath = GetAppYamlPath(project); if (FileSystem.File.Exists(appYamlPath)) { SetAppYamlService(service, appYamlPath); } else { GenerateAppYaml(appYamlPath, service); } }
public void TestParseProject_ReturnsNullForOldCsprojMissingProjectTypeGuids() { var projectXDocument = new XDocument(new XElement(XName.Get("Project", ProjectParser.MsbuildNamespace))); const string projectFilePath = @"c:\path\to\project.csproj"; _projectMock.Setup(p => p.FullName).Returns(projectFilePath); _fileSystemMock.Setup(fs => fs.XDocument.Load(projectFilePath)).Returns(projectXDocument); IParsedDteProject result = ProjectParser.ParseProject(_projectMock.Object); Assert.IsNull(result); }
protected override void BeforeEach() { _mockedCloseWindowAction = Mock.Of <Action>(); _mockedParsedProject = Mock.Of <IParsedDteProject>(p => p.Project == Mock.Of <Project>()); _changedProperties = new List <string>(); _propertyServiceMock = new Mock <IVsProjectPropertyService>(); PackageMock.Setup(p => p.GetMefService <IVsProjectPropertyService>()).Returns(_propertyServiceMock.Object); _objectUnderTest = new PublishDialogWindowViewModel(_mockedParsedProject, _mockedCloseWindowAction); _objectUnderTest.PropertyChanged += (sender, args) => _changedProperties.Add(args.PropertyName); _stepContentMock = new Mock <FrameworkElement>().As <IStepContent <IPublishDialogStep> >(); _stepContentMock.DefaultValueProvider = DefaultValueProvider.Mock; }
/// <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="targetDeployPath">The Name or Path of the Website or App to publish</param> /// <param name="configuration">The name of the configuration to publish.</param> public async Task <bool> PublishProjectAsync( IParsedDteProject project, Instance targetInstance, WindowsInstanceCredentials credentials, string targetDeployPath, string configuration) { // Ensure NuGet packages are restored. project.Project.DTE.Solution.SolutionBuild.BuildProject(configuration, project.Project.UniqueName, true); string msbuildPath = VsVersionUtils.ToolsPathProvider.GetMsbuildPath(); MSBuildTarget target; switch (project.ProjectType) { case KnownProjectTypes.WebApplication: target = new MSBuildTarget("WebPublish"); break; default: target = new MSBuildTarget("Publish"); break; } var parameters = new object[] { '"' + project.FullPath + '"', target, new MSBuildProperty("Configuration", configuration), new MSBuildProperty("WebPublishMethod", "MSDeploy"), new MSBuildProperty("MSDeployPublishMethod", "WMSVC"), new MSBuildProperty("MSDeployServiceURL", targetInstance.GetPublishUrl()), new MSBuildProperty("DeployIisAppPath", targetDeployPath), new MSBuildProperty("UserName", credentials.User), new MSBuildProperty("Password", credentials.Password), new MSBuildProperty("AllowUntrustedCertificate", "True") }; string publishMessage = string.Format(Resources.GcePublishProgressMessage, targetInstance.Name); using (StatusbarHelper.FreezeText(publishMessage)) using (StatusbarHelper.ShowDeployAnimation()) using (ShellUtils.SetShellUIBusy()) { return(await ProcessService.RunCommandAsync( msbuildPath, string.Join(" ", parameters), GcpOutputWindow.OutputLine)); } }
public void BeforeEach() { _stepContentMock = new Mock <IStepContent <IPublishDialogStep> > { DefaultValueProvider = DefaultValueProvider.Mock }; _mockedCloseWindowAction = Mock.Of <Action>(); _mockedParsedProject = Mock.Of <IParsedDteProject>(p => p.Project == Mock.Of <Project>()); _objectUnderTest = new PublishDialogWindowViewModel(_mockedParsedProject, _mockedCloseWindowAction); _changedProperties = new List <string>(); _objectUnderTest.PropertyChanged += (sender, args) => _changedProperties.Add(args.PropertyName); }
public void TestParseProject_ReturnsNullForCoreCsprojWrongSdk() { var projectXDocument = new XDocument( new XElement( XName.Get("Project"), new XAttribute(XName.Get(ProjectParser.SdkAttributeName), "Microsoft.Net.Sdk.Wrong"))); const string projectFilePath = @"c:\path\to\project.csproj"; _projectMock.Setup(p => p.FullName).Returns(projectFilePath); _fileSystemMock.Setup(fs => fs.XDocument.Load(projectFilePath)).Returns(projectXDocument); IParsedDteProject result = ProjectParser.ParseProject(_projectMock.Object); Assert.IsNull(result); }
public void TestParseProject_ReturnsCoreCsprojProjectForValidCoreCsproj() { var projectXDocument = new XDocument( new XElement( XName.Get("Project"), new XAttribute(XName.Get(ProjectParser.SdkAttributeName), ProjectParser.AspNetCoreSdk), new XElement( XName.Get(ProjectParser.PropertyGroupElementName), new XElement(XName.Get(ProjectParser.TargetFrameworkElementName), "TargetFramework")))); const string projectFilePath = @"c:\path\to\project.csproj"; _projectMock.Setup(p => p.FullName).Returns(projectFilePath); _fileSystemMock.Setup(fs => fs.XDocument.Load(projectFilePath)).Returns(projectXDocument); IParsedDteProject result = ProjectParser.ParseProject(_projectMock.Object); Assert.IsInstanceOfType(result, typeof(NetCoreCsprojProject)); }
private static void OnBeforeQueryStatus(object sender, EventArgs e) { ThreadHelper.ThrowIfNotOnUIThread(); if (!(sender is OleMenuCommand menuCommand)) { return; } IParsedDteProject selectedProject = SolutionHelper.CurrentSolution.SelectedProject?.ParsedProject; if (selectedProject == null || !PublishDialogWindow.CanPublish(selectedProject)) { menuCommand.Visible = false; } else { menuCommand.Visible = true; menuCommand.Enabled = !ShellUtils.Default.IsBusy(); } }
public void TestParseProject_ReturnsNet4CsprojProjectForOldCsprojWithWebAppProjectTypeGuid() { var projectXDocument = new XDocument( new XElement( XName.Get("Project", ProjectParser.MsbuildNamespace), new XElement( XName.Get(ProjectParser.PropertyGroupElementName, ProjectParser.MsbuildNamespace), new XElement( XName.Get(ProjectParser.PropertyTypeGuidsElementName, ProjectParser.MsbuildNamespace), $"{Guid.Empty};{ProjectParser.WebApplicationGuid}")))); const string projectFilePath = @"c:\path\to\project.csproj"; _projectMock.Setup(p => p.FullName).Returns(projectFilePath); _projectMock.Setup(p => p.Properties.Item("TargetFrameworkMoniker").Value) .Returns(".NETFramework,Version=v4.4.4"); _fileSystemMock.Setup(fs => fs.XDocument.Load(projectFilePath)).Returns(projectXDocument); IParsedDteProject result = ProjectParser.ParseProject(_projectMock.Object); Assert.IsInstanceOfType(result, typeof(Net4CsprojProject)); }
/// <summary> /// Saves a property to the project's .user file. /// </summary> /// <param name="parsedProject">The project to save the property to.</param> /// <param name="propertyName">The name of the property to save.</param> /// <param name="value">The value of the property.</param> public static void SaveUserProperty(this IParsedDteProject parsedProject, string propertyName, string value) => ProjectPropertyService.SaveUserProperty(parsedProject.Project, propertyName, value);
/// <summary> /// Deletes a property from the project's .user file. /// </summary> /// <param name="parsedProject">The project to delete the property from.</param> /// <param name="propertyName">The name of the property to delete.</param> public static void DeleteUserProperty(this IParsedDteProject parsedProject, string propertyName) => ProjectPropertyService.DeleteUserProperty(parsedProject.Project, propertyName);
/// <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="targetDeployPath">The Name or Path of the Website or App to publish</param> /// <param name="configuration">The name of the configuration to publish.</param> public async Task <bool> PublishProjectAsync( IParsedDteProject project, Instance targetInstance, WindowsInstanceCredentials credentials, string targetDeployPath, string configuration) { await GoogleCloudExtensionPackage.Instance.JoinableTaskFactory.SwitchToMainThreadAsync(); ShellUtils.SaveAllFiles(); // Ensure NuGet packages are restored. project.Project.DTE.Solution.SolutionBuild.BuildProject(configuration, project.Project.UniqueName, true); await GcpOutputWindow.ClearAsync(); await GcpOutputWindow.OutputLineAsync(string.Format(Resources.GcePublishStepStartMessage, project.Name)); await GcpOutputWindow.ActivateAsync(); string msbuildPath = VsVersionUtils.ToolsPathProvider.GetMsbuildPath(); MSBuildTarget target; switch (project.ProjectType) { case KnownProjectTypes.WebApplication: target = new MSBuildTarget("WebPublish"); break; default: target = new MSBuildTarget("Publish"); break; } var parameters = new object[] { '"' + project.FullPath + '"', target, new MSBuildProperty("Configuration", configuration), new MSBuildProperty("WebPublishMethod", "MSDeploy"), new MSBuildProperty("MSDeployPublishMethod", "WMSVC"), new MSBuildProperty("MSDeployServiceURL", targetInstance.GetPublishUrl()), new MSBuildProperty("DeployIisAppPath", targetDeployPath), new MSBuildProperty("UserName", credentials.User), new MSBuildProperty("Password", credentials.Password), new MSBuildProperty("AllowUntrustedCertificate", "True"), new MSBuildProperty("GoogleCloudExtensionBuild", "True") }; string publishMessage = string.Format(Resources.GcePublishProgressMessage, targetInstance.Name); using (await StatusbarHelper.FreezeTextAsync(publishMessage)) using (await StatusbarHelper.ShowDeployAnimationAsync()) using (await ShellUtils.SetShellUIBusyAsync()) { string msBuildParameters = string.Join(" ", parameters); bool result = await ProcessService.RunCommandAsync( msbuildPath, msBuildParameters, GcpOutputWindow.OutputLineAsync); if (result) { return(true); } await TaskScheduler.Default; // An initial failure is common, retry. await Task.Delay(TimeSpan.FromMilliseconds(100)); return(await ProcessService.RunCommandAsync( msbuildPath, msBuildParameters, GcpOutputWindow.OutputLineAsync)); } }
/// <summary> /// Starts the publish wizard for the given <paramref name="project"/>. /// </summary> /// <param name="project">The project to publish.</param> public static void PromptUser(IParsedDteProject project) { var dialog = new PublishDialogWindow(project); dialog.ShowModal(); }
/// <summary> /// Reads a property from the project's .user file. /// </summary> /// <param name="parsedProject">The project to read the property from.</param> /// <param name="propertyName">The name of the property to read.</param> /// <returns>The value of the property.</returns> public static string GetUserProperty(this IParsedDteProject parsedProject, string propertyName) => ProjectPropertyService.GetUserProperty(parsedProject.Project, propertyName);
/// <summary> /// Queries the user and generates an app.yaml and Docker file. /// </summary> private static async Task GenerateConfigurationAsync() { await GoogleCloudExtensionPackage.Instance.JoinableTaskFactory.SwitchToMainThreadAsync(); IParsedDteProject selectedProject = SolutionHelper.CurrentSolution.SelectedProject.ParsedProject; Debug.WriteLine($"Generating configuration for project: {selectedProject.FullPath}"); IAppEngineConfiguration appEngineConfiguration = GoogleCloudExtensionPackage.Instance.GetMefService <IAppEngineConfiguration>(); ProjectConfigurationStatus configurationStatus = appEngineConfiguration.CheckProjectConfiguration(selectedProject); // If the app.yaml already exists allow the user to skip its generation to preserve the existing file. if (!configurationStatus.HasAppYaml || UserPromptService.Default.ActionPrompt( prompt: Resources.GenerateConfigurationAppYamlOverwriteMessage, title: Resources.GenerateConfigurationOverwritePromptTitle, actionCaption: Resources.UiOverwriteButtonCaption, cancelCaption: Resources.UiSkipFileButtonCaption)) { Debug.WriteLine($"Generating app.yaml for {selectedProject.FullPath}"); try { appEngineConfiguration.AddAppYamlItem(selectedProject); } catch (Exception error) { UserPromptService.Default.ErrorPrompt( string.Format( Resources.GenerateConfigurationFileGenerationErrorMessage, AppEngineConfiguration.AppYamlName), Resources.GenerateConfigurationFileGeneratinErrorTitle, error.Message); return; } await GcpOutputWindow.Default.OutputLineAsync(Resources.GenerateConfigurationAppYamlGeneratedMessage); } // If the Dockerfile already exists allow the user to skip its generation to preserve the existing file. if (!configurationStatus.HasDockerfile || UserPromptService.Default.ActionPrompt( prompt: Resources.GenerateConfigurationDockerfileOverwriteMessage, title: Resources.GenerateConfigurationOverwritePromptTitle, actionCaption: Resources.UiOverwriteButtonCaption, cancelCaption: Resources.UiSkipFileButtonCaption)) { Debug.WriteLine($"Generating Dockerfile for {selectedProject.FullPath}"); try { GoogleCloudExtensionPackage.Instance.GetMefService <INetCoreAppUtils>() .GenerateDockerfile(selectedProject); } catch (Exception exception) { UserPromptService.Default.ErrorPrompt( string.Format( Resources.GenerateConfigurationFileGenerationErrorMessage, NetCoreAppUtils.DockerfileName), Resources.GenerateConfigurationFileGeneratinErrorTitle, exception.Message); return; } await GcpOutputWindow.Default.OutputLineAsync(Resources.GenerateConfigurationDockerfileGeneratedMessage); } }