diff --git a/Team.psd1 b/Team.psd1 index 5f7157907..56bf8e6ce 100644 --- a/Team.psd1 +++ b/Team.psd1 @@ -13,7 +13,7 @@ RootModule = '' # Version number of this module. - ModuleVersion = '0.1.22' + ModuleVersion = '0.1.23' # Supported PSEditions # CompatiblePSEditions = @() @@ -82,6 +82,7 @@ # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. FunctionsToExport = @('Add-AzureRMServiceEndpoint', + 'Add-SonarQubeEndpoint', 'Add-Build', 'Add-BuildDefinition', 'Add-Project', diff --git a/en-US/Team-Help.xml b/en-US/Team-Help.xml index 3ec7c9fa7..71ed62cad 100644 --- a/en-US/Team-Help.xml +++ b/en-US/Team-Help.xml @@ -1,6 +1,6 @@  - + @@ -210,7 +210,7 @@ Remove-BuildDefinition Add-AzureRMServiceEndpoint - + Adds a new Azure Resource Manager service endpoint. @@ -220,7 +220,7 @@ Remove-BuildDefinition - + The cmdlet adds a new connection between TFS/VSTS and Azure using the Azure Resource Manager connection type. @@ -264,9 +264,10 @@ you do not have to pass the ProjectName with each call. EndpointName - + The name displayed on the services page. In VSTS this is the Connection Name. String + @@ -311,14 +312,14 @@ you do not have to pass the ProjectName with each call. EndpointName - + The name displayed on the services page. In VSTS this is the Connection Name. String String - + @@ -365,6 +366,147 @@ you do not have to pass the ProjectName with each call. + + + + Add-SonarQubeEndpoint + + Adds a new SonarQube service endpoint. + + + + + Add + SonarQubeEndpoint + + + + The cmdlet adds a new connection between TFS/VSTS and a SonarQube server using the SonarQube connection type. This is only used when using the SonarQube tasks. Using SonarQube with the Maven tasks uses a Generic Connection type. + + + + + Add-SonarQubeEndpoint + + + ProjectName + + Specifies the team project for which this function operates. + You can tab complete from a list of available projects. + You can use Set-DefaultProject to set a default project so +you do not have to pass the ProjectName with each call. + + String + + + + Token + + Authentication Token generated by SonarQube. + + String + + + + SonarQubeUrl + + URL of the sonarqube server. + + String + + + + EndpointName + + The name displayed on the services page. In VSTS this is the Connection Name. + + String + + + + + + + + SonarQubeUrl + + URL of the sonarqube server. + + String + + String + + + + + + Token + + Authentication Token generated by SonarQube. + + String + + String + + + + + + EndpointName + + The name displayed on the services page. In VSTS this is the Connection Name. + + String + + String + + + + + + + ProjectName + + Specifies the team project for which this function operates. + You can tab complete from a list of available projects. + You can use Set-DefaultProject to set a default project so +you do not have to pass the ProjectName with each call. + + String + + String + + + + + + + + + + + System.String + + + + + + + + + + + + + System.Object + + + + + + + + @@ -5556,5 +5698,5 @@ to pass the ProjectName with each call. - + \ No newline at end of file diff --git a/src/serviceendpoints.psm1 b/src/serviceendpoints.psm1 index 2ef915e6e..6c44058af 100644 --- a/src/serviceendpoints.psm1 +++ b/src/serviceendpoints.psm1 @@ -133,6 +133,85 @@ function Remove-ServiceEndpoint { } } +function Add-SonarQubeEndpoint { + [CmdletBinding(DefaultParameterSetName = 'Secure')] + param( + [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [string] $endpointName, + [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] + [string] $sonarqubeUrl, + [parameter(ParameterSetName = 'Plain', Mandatory = $true, Position = 2, HelpMessage = 'Personal Access Token')] + [string] $personalAccessToken, + [parameter(ParameterSetName = 'Secure', Mandatory = $true, HelpMessage = 'Personal Access Token')] + [securestring] $securePersonalAccessToken + ) + + DynamicParam { + _buildProjectNameDynamicParam + } + + Process { + + + if ($personalAccessToken) { + $token = $personalAccessToken + } + else { + $credential = New-Object System.Management.Automation.PSCredential "nologin", $securePersonalAccessToken + $token = $credential.GetNetworkCredential().Password + } + # Bind the parameter to a friendly variable + $ProjectName = $PSBoundParameters["ProjectName"] + + # Build the url + $url = _buildURL -projectName $projectName + + $obj = @{ + authorization = @{ + parameters = @{ + username = $token; + password = '' + }; + scheme = 'UsernamePassword' + }; + data = @{ + }; + name = $endpointName; + type = 'sonarqube'; + url = $sonarqubeUrl + } + + $body = $obj | ConvertTo-Json + + try { + + # Call the REST API + if (_useWindowsAuthenticationOnPremise) { + $resp = Invoke-RestMethod -UserAgent (_getUserAgent) -Method Post -Body $body -ContentType "application/json" -Uri $url -UseDefaultCredentials + } + else { + $resp = Invoke-RestMethod -UserAgent (_getUserAgent) -Method Post -Body $body -ContentType "application/json" -Uri $url -Headers @{Authorization = "Basic $env:TEAM_PAT"} + } + + } + catch [System.Net.WebException] { + if ($_.Exception.status -eq "ProtocolError") { + $errorDetails = ConvertFrom-Json $_.ErrorDetails + [string] $message = $errorDetails.message + if ($message.StartsWith("Endpoint type couldn't be recognized 'sonarqube'")) { + Write-Error -Message "The Sonarqube extension not installed. Please install from https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarqube" + return + } + } + throw + } + _trackProgress -projectName $projectName -resp $resp -title 'Creating Service Endpoint' -msg "Creating $endpointName" + + return Get-ServiceEndpoint -projectName $projectName -id $resp.id + } + } + + function Add-AzureRMServiceEndpoint { [CmdletBinding()] param( @@ -254,4 +333,4 @@ function Get-ServiceEndpoint { } } -Export-ModuleMember -Alias * -Function Get-ServiceEndpoint, Add-AzureRMServiceEndpoint, Remove-ServiceEndpoint \ No newline at end of file +Export-ModuleMember -Alias * -Function Get-ServiceEndpoint, Add-AzureRMServiceEndpoint, Remove-ServiceEndpoint, Add-SonarQubeEndpoint \ No newline at end of file diff --git a/src/team.psm1 b/src/team.psm1 index b4be3a26e..4f0fc6958 100644 --- a/src/team.psm1 +++ b/src/team.psm1 @@ -62,7 +62,7 @@ function Add-TeamAccount { [parameter(ParameterSetName='Plain', Mandatory=$true, Position=2, HelpMessage='Personal Access Token')] [string] $PersonalAccessToken, [parameter(ParameterSetName='Secure', Mandatory=$true, HelpMessage='Personal Access Token')] - [securestring] $PAT + [securestring] $SecurePersonalAccessToken ) DynamicParam { @@ -133,26 +133,23 @@ function Add-TeamAccount { } $UsingWindowsAuth = $PSBoundParameters[$ParameterName2] - if (!($PAT) -and !($PersonalAccessToken) -and !($UsingWindowsAuth)) { + if (!($SecurePersonalAccessToken) -and !($PersonalAccessToken) -and !($UsingWindowsAuth)) { Write-Error "Personal Access Token must be provided if you are not using Windows Authentication; please see the help." } } else { $Level = "Process" } - - if ($PAT) { + if ($SecurePersonalAccessToken) { # Convert the securestring to a normal string # this was the one technique that worked on Mac, Linux and Windows - $credential = New-Object System.Management.Automation.PSCredential $account,$PAT + $credential = New-Object System.Management.Automation.PSCredential $account,$SecurePersonalAccessToken $_pat = $credential.GetNetworkCredential().Password } else { $_pat = $PersonalAccessToken } - - # If they only gave an account name add visualstudio.com if($Account.ToLower().Contains('http') -eq $false) { $Account = "https://$($Account).visualstudio.com" @@ -160,7 +157,7 @@ function Add-TeamAccount { $encodedPat = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$_pat")) - # If no PAT is entered, and on windows, are we using default credentials for REST calls + # If no SecurePersonalAccessToken is entered, and on windows, are we using default credentials for REST calls if ((!$_pat) -and (_isOnWindows) -and ($UsingWindowsAuth)) { Write-Verbose "Using Default Windows Credentials for authentication; no Personal Access Token required" $encodedPat = "" diff --git a/test/serviceendpoints.Tests.ps1 b/test/serviceendpoints.Tests.ps1 index 1fa615944..e71218635 100644 --- a/test/serviceendpoints.Tests.ps1 +++ b/test/serviceendpoints.Tests.ps1 @@ -71,5 +71,36 @@ InModuleScope serviceendpoints { Assert-MockCalled Invoke-RestMethod -Exactly -Scope It -Times 1 -ParameterFilter { $Method -eq 'Post' } } } + + Context 'Add-SonarQubeEndpoint' { + Mock Write-Progress + Mock Invoke-RestMethod { $returnObject = $false + return @{id = '23233-2342'} } -ParameterFilter { $Method -eq 'Post'} + Mock Invoke-RestMethod { + + # This $i is in the module. Because we use InModuleScope + # we can see it + if ($i -gt 9) { + return @{ + isReady = $true + operationStatus = @{state = 'Ready'} + } + } + + return @{ + isReady = $false + createdBy = @{} + authorization = @{} + data = @{} + operationStatus = @{state = 'InProgress'} + } + } + + It 'should create a new SonarQube Serviceendpoint' { + Add-SonarQubeEndpoint -projectName 'project' -endpointName 'PM_DonovanBrown' -sonarqubeUrl 'http://mysonarserver.local' -personalAccessToken '72f988bf-86f1-41af-91ab-2d7cd011db47' + + Assert-MockCalled Invoke-RestMethod -Exactly -Scope It -Times 1 -ParameterFilter { $Method -eq 'Post' } + } + } } } \ No newline at end of file