/// <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);
        }
Example #3
0
        public void TestParseProject_ReturnsNullForBadFileExtension()
        {
            _projectMock.Setup(p => p.FullName).Returns(@"c:\path\to\project.bad");

            IParsedDteProject result = ProjectParser.ParseProject(_projectMock.Object);

            Assert.IsNull(result);
        }
Example #4
0
        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);
        }
Example #5
0
        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();
 }
Example #7
0
 /// <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);
     });
 }
Example #8
0
        /// <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;
        }
Example #9
0
 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());
 }
Example #10
0
        /// <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);
            }
        }
Example #11
0
        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;
        }
Example #13
0
        /// <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));
                    }
        }
Example #14
0
        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);
        }
Example #15
0
        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);
        }
Example #16
0
        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));
        }
Example #17
0
        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();
            }
        }
Example #18
0
        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);
Example #24
0
        /// <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);
            }
        }