From 9a1b56420a70f65ad69aab4cab4432c35fcd0090 Mon Sep 17 00:00:00 2001 From: S Raghav Date: Sun, 3 Feb 2019 22:57:14 +0530 Subject: [PATCH 1/3] Initial cut, tested manually. Not ready for review --- GitHubRepositoryMerge.ps1 | 113 ++++++++++++++++++++++++++++++++++++++ PowerShellForGitHub.psd1 | 2 + 2 files changed, 115 insertions(+) create mode 100644 GitHubRepositoryMerge.ps1 diff --git a/GitHubRepositoryMerge.ps1 b/GitHubRepositoryMerge.ps1 new file mode 100644 index 00000000..2864b5fc --- /dev/null +++ b/GitHubRepositoryMerge.ps1 @@ -0,0 +1,113 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +function Merge-GitHubRepositoryBranches +{ +<# + .SYNOPSIS + Branch a branch into another + + .DESCRIPTION + Merge a branch into another + Calls the API: https://developer.github.com/v3/repos/merging/ + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER State + The state of the pull requests that should be returned back. + + .PARAMETER Base + The name of the base branch that the head will be merged into. + + .PARAMETER Head + The head to merge. This can be a branch name or a commit SHA1. + + .PARAMETER CommitMessage + Commit message to use for the merge commit. If omitted, a default message will be used. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .OUTPUTS + //TODO: FInd the output for POST commands and put it here + + .EXAMPLE + //TODO: Give an example here +#> + +[CmdletBinding( + SupportsShouldProcess, + DefaultParametersetName='Elements')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification="Methods called within here make use of PSShouldProcess, and the switch is passed on to them inherently.")] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ParameterSetName='Uri')] + [string] $Uri, + + [string] $Base, + + [string] $CommitMessage, + + [string] $Head, + + [string] $AccessToken, + + [switch] $NoStatus + ) + Write-InvocationLog + + $elements = Resolve-RepositoryElements -DisableValidation + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $hashBody = @{ + 'base'= $Base; + 'head' = $Head; + 'commit_message' = $CommitMessage; + } + + $params = @{ + 'UriFragment' = "repos/$OwnerName/$RepositoryName/merges" + 'Body' = (ConvertTo-Json -InputObject $hashBody) + 'Method' = 'Post' + 'Description' = "Merging branch $Head to $Base in $RepositoryName" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return Invoke-GHRestMethod @params +} diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 2afe65a0..82992c1d 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -34,6 +34,7 @@ 'GitHubPullRequests.ps1', 'GitHubRepositories.ps1', 'GitHubRepositoryForks.ps1', + 'GitHubRepositoryMerge.ps1', 'GitHubRepositoryTraffic.ps1', 'GitHubTeams.ps1', 'GitHubUsers.ps1', @@ -85,6 +86,7 @@ 'Invoke-GHRestMethod', 'Invoke-GHRestMethodMultipleResult', 'Lock-GitHubIssue', + 'Merge-GitHubRepositoryBranches', 'Move-GitHubRepositoryOwnership', 'New-GithubAssignee', 'New-GitHubComment', From ff62aa001126128069f665e9d2403a3ea11b0a61 Mon Sep 17 00:00:00 2001 From: S Raghav Date: Sun, 24 Mar 2019 17:11:13 +0530 Subject: [PATCH 2/3] * Functionality for Get-GitHubReference and New-GitHubReference implemented * Includes tests for a few common scenarios * Contains test cases --- GitHubReferences.ps1 | 219 +++++++++++++++++++++++++++++++ PowerShellForGitHub.psd1 | 5 +- Tests/GitHubReferences.Tests.ps1 | 173 ++++++++++++++++++++++++ 3 files changed, 396 insertions(+), 1 deletion(-) create mode 100644 GitHubReferences.ps1 create mode 100644 Tests/GitHubReferences.Tests.ps1 diff --git a/GitHubReferences.ps1 b/GitHubReferences.ps1 new file mode 100644 index 00000000..038eecfc --- /dev/null +++ b/GitHubReferences.ps1 @@ -0,0 +1,219 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +function Get-GitHubReference +{ +<# + .SYNOPSIS + Retrieve a reference of a given GitHub repository. + + .DESCRIPTION + Retrieve a reference of a given GitHub repository. + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER Reference + Name of the reference, for example: "heads/" for branches and "tags/" for tags + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .EXAMPLE + Get-GitHubReference -OwnerName Powershell -RepositoryName PowerShellForGitHub -Reference heads/master +#> + [CmdletBinding( + SupportsShouldProcess, + DefaultParametersetName='Elements')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification="Methods called within here make use of PSShouldProcess, and the switch is passed on to them inherently.")] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ParameterSetName='Uri')] + [string] $Uri, + + [Parameter(Mandatory)] + [string] $Reference, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog -Invocation $MyInvocation + + $elements = Resolve-RepositoryElements -BoundParameters $PSBoundParameters -DisableValidation + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + if ($OwnerName -xor $RepositoryName) + { + $message = 'You must specify both Owner Name and Repository Name.' + Write-Log -Message $message -Level Error + throw $message + } + $uriFragment = "/repos/$OwnerName/$RepositoryName/git/refs/$Reference" + $description = "Getting Reference $Reference for $RepositoryName" + + $params = @{ + 'UriFragment' = $uriFragment + 'Method' = 'Get' + 'Description' = $description + 'AcceptHeader' = 'application/vnd.github.symmetra-preview+json' + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + try + { + return Invoke-GHRestMethod @params + } + catch + { + Write-InteractiveHost "No reference named $Reference exists in repository $RepositoryName" -NoNewline -f Red + Write-Log -Level Error "No reference named $Reference exists in repository $RepositoryName" + return $null + } + +} + +function New-GitHubReference +{ + <# + .SYNOPSIS + Create a reference in a given GitHub repository. + + .DESCRIPTION + Create a reference in a given GitHub repository. + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER Reference + The name of the fully qualified reference to be created (eg: refs/heads/master) + + .PARAMETER Sha + The SHA1 value for the reference to be created + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .EXAMPLE + -GitHubReference -OwnerName Powershell -RepositoryName PowerShellForGitHub -Reference refs/heads/master -Sha aa218f56b14c9653891f9e74264a383fa43fefbd + #> + [CmdletBinding( + SupportsShouldProcess, + DefaultParametersetName='Elements')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification="Methods called within here make use of PSShouldProcess, and the switch is passed on to them inherently.")] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ParameterSetName='Uri')] + [string] $Uri, + + [Parameter(Mandatory)] + [string] $Reference, + + [Parameter(Mandatory)] + [string] $Sha, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog -Invocation $MyInvocation + + $elements = Resolve-RepositoryElements -BoundParameters $PSBoundParameters -DisableValidation + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + if ($OwnerName -xor $RepositoryName) + { + $message = 'You must specify both Owner Name and Repository Name.' + Write-Log -Message $message -Level Error + throw $message + } + + $uriFragment = "/repos/$OwnerName/$RepositoryName/git/refs" + $description = "Creating Reference $Reference for $RepositoryName from SHA $Sha" + + $hashBody = @{ + 'ref' = $Reference + 'sha' = $Sha + } + + $params = @{ + 'UriFragment' = $uriFragment + 'Method' = 'Post' + 'Body' = (ConvertTo-Json -InputObject $hashBody) + 'Description' = $description + 'AcceptHeader' = 'application/vnd.github.symmetra-preview+json' + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return Invoke-GHRestMethod @params +} diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index ac292970..0a26438d 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -32,6 +32,7 @@ 'GitHubMiscellaneous.ps1', 'GitHubOrganizations.ps1', 'GitHubPullRequests.ps1', + 'GitHubReferences.ps1', 'GitHubRepositories.ps1', 'GitHubRepositoryForks.ps1', 'GitHubRepositoryTraffic.ps1', @@ -115,7 +116,9 @@ 'Update-GitHubCurrentUser', 'Update-GitHubIssue', 'Update-GitHubLabel', - 'Update-GitHubRepository' + 'Update-GitHubRepository', + 'Get-GitHubReference', + 'New-GithubReference' ) AliasesToExport = @( diff --git a/Tests/GitHubReferences.Tests.ps1 b/Tests/GitHubReferences.Tests.ps1 new file mode 100644 index 00000000..f0d68ab0 --- /dev/null +++ b/Tests/GitHubReferences.Tests.ps1 @@ -0,0 +1,173 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +<# +.Synopsis + Tests for GitHubReferences.ps1 module +#> + +[String] $root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path) +. (Join-Path -Path $root -ChildPath 'Tests\Config\Settings.ps1') +Import-Module -Name $root -Force + +function Initialize-AppVeyor +{ +<# + .SYNOPSIS + Configures the tests to run with the authentication information stored in AppVeyor + (if that information exists in the environment). + + .DESCRIPTION + Configures the tests to run with the authentication information stored in AppVeyor + (if that information exists in the environment). + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .NOTES + Internal-only helper method. + + The only reason this exists is so that we can leverage CodeAnalysis.SuppressMessageAttribute, + which can only be applied to functions. + + We call this immediately after the declaration so that AppVeyor initialization can heppen + (if applicable). + +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Justification="Needed to configure with the stored, encrypted string value in AppVeyor.")] + param() + + if ($env:AppVeyor) + { + $secureString = $env:avAccessToken | ConvertTo-SecureString -AsPlainText -Force + $cred = New-Object System.Management.Automation.PSCredential "", $secureString + Set-GitHubAuthentication -Credential $cred + + $script:ownerName = $env:avOwnerName + $script:organizationName = $env:avOrganizationName + + $message = @( + 'This run is executed in the AppVeyor environment.', + 'The GitHub Api Token won''t be decrypted in PR runs causing some tests to fail.', + '403 errors possible due to GitHub hourly limit for unauthenticated queries.', + 'Use Set-GitHubAuthentication manually. modify the values in Tests\Config\Settings.ps1,', + 'and run tests on your machine first.') + Write-Warning -Message ($message -join [Environment]::NewLine) + } +} + +Initialize-AppVeyor + +$accessTokenConfigured = Test-GitHubAuthenticationConfigured +if (-not $accessTokenConfigured) +{ + $message = @( + 'GitHub API Token not defined, some of the tests will be skipped.', + '403 errors possible due to GitHub hourly limit for unauthenticated queries.') + Write-Warning -Message ($message -join [Environment]::NewLine) +} + +# Backup the user's configuration before we begin, and ensure we're at a pure state before running +# the tests. We'll restore it at the end. +$configFile = New-TemporaryFile + +try +{ + Backup-GitHubConfiguration -Path $configFile + Reset-GitHubConfiguration + Set-GitHubConfiguration -DisableTelemetry # We don't want UT's to impact telemetry + Set-GitHubConfiguration -LogRequestBody # Make it easier to debug UT failures + + if ($accessTokenConfigured) + { + + Describe 'Create a new reference(branch) in repository' { + $repositoryName = [Guid]::NewGuid() + $repo = New-GitHubRepository -RepositoryName $repositoryName -AutoInit + $existingref = @(Get-GitHubReference -OwnerName $ownerName -RepositoryName $repositoryName -Reference "heads/master") + $sha = $existingref.object.sha + + Context 'On creating a valid reference in a new repository from a given SHA' { + $refName = "refs/heads/" + [Guid]::NewGuid().ToString() + $result = @(New-GitHubReference -OwnerName $ownerName -RepositoryName $repositoryName -Reference $refName -Sha $sha) + + It 'Should successfully create the reference' { + $result.ref | Should Be $refName + } + } + + Context 'On creating a valid reference in a new repository (specified by Uri) from a given SHA' { + $refName = "refs/heads/" + [Guid]::NewGuid().ToString() + $result = @(New-GitHubReference -Uri $repo.svn_url -Reference $refName -Sha $sha) + + It 'Should successfully create the reference' { + $result.ref | Should Be $refName + } + } + + Context 'On creating an existing reference in a new repository from a given SHA' { + $refName = "refs/heads/master" + + It 'Should throw an Exception' { + { @(New-GitHubReference -OwnerName $ownerName -RepositoryName $repositoryName -Reference $refName -Sha $sha) } | Should Throw + } + } + + Context 'On creating an existing reference in a new repository (specified by Uri) from a given SHA' { + $refName = "refs/heads/master" + + It 'Should throw an exception' { + { @(New-GitHubReference -Uri $repo.svn_url -Reference $refName -Sha $sha) } | Should Throw + } + } + + + + $null = Remove-GitHubRepository -OwnerName $ownerName -RepositoryName $repositoryName + } + + Describe 'Getting a reference(branch) from repository' { + $repositoryName = [Guid]::NewGuid() + $repo = New-GitHubRepository -RepositoryName $repositoryName -AutoInit + + Context 'On getting a valid reference from a new repository' { + $reference = @(Get-GitHubReference -OwnerName $ownerName -RepositoryName $repositoryName -Reference "heads/master") + + It 'Should return details of the reference' { + $reference.ref | Should be "refs/heads/master" + } + } + + Context 'On getting an invalid reference from a new repository' { + $reference = @(Get-GitHubReference -OwnerName $ownerName -RepositoryName $repositoryName -Reference "heads/someRandomRef") + + It 'Should not return any details' { + $reference | Should be $null + } + } + + Context 'On getting a valid reference using Uri from a new repository' { + $reference = @(Get-GitHubReference -Uri $repo.svn_url -Reference "heads/master") + + It 'Should return details of the reference' { + $reference.ref | Should be "refs/heads/master" + } + } + + Context 'On getting an invalid reference using Uri from a new repository' { + $reference = @(Get-GitHubReference -Uri $repo.svn_url -Reference "heads/someRandomRef") + + It 'Should not return any details' { + $reference | Should be $null + } + } + $null = Remove-GitHubRepository -OwnerName $ownerName -RepositoryName $repositoryName + } + } +} +catch +{ + # Restore the user's configuration to its pre-test state + Restore-GitHubConfiguration -Path $configFile +} + From 13d16ccd3051e8bb85accb35a460eb94a668a005 Mon Sep 17 00:00:00 2001 From: S Raghav Date: Sun, 24 Mar 2019 21:41:02 +0530 Subject: [PATCH 3/3] Added test cases and address review comments --- GitHubRepositoryMerge.ps1 | 44 ++++++--- PowerShellForGitHub.psd1 | 2 +- Tests/GitHubRepositoryMerge.tests.ps1 | 132 ++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 14 deletions(-) create mode 100644 Tests/GitHubRepositoryMerge.tests.ps1 diff --git a/GitHubRepositoryMerge.ps1 b/GitHubRepositoryMerge.ps1 index 2864b5fc..9d17ff78 100644 --- a/GitHubRepositoryMerge.ps1 +++ b/GitHubRepositoryMerge.ps1 @@ -1,15 +1,14 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -function Merge-GitHubRepositoryBranches +function Merge-GitHubRepositoryBranch { <# .SYNOPSIS - Branch a branch into another + Merge the specified branch into another branch .DESCRIPTION - Merge a branch into another - Calls the API: https://developer.github.com/v3/repos/merging/ + Merge the specified branch into another branch The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub @@ -37,7 +36,7 @@ function Merge-GitHubRepositoryBranches .PARAMETER CommitMessage Commit message to use for the merge commit. If omitted, a default message will be used. - + .PARAMETER AccessToken If provided, this will be used as the AccessToken for authentication with the REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. @@ -49,10 +48,10 @@ function Merge-GitHubRepositoryBranches If not supplied here, the DefaultNoStatus configuration property value will be used. .OUTPUTS - //TODO: FInd the output for POST commands and put it here + PSCustomObject .EXAMPLE - //TODO: Give an example here + Merge-GitHubRepositoryBranch -OwnerName PowerShell -RepositoryName PowerShellForGitHub -Base 'master' -Head 'new_feature' -CommitMessage 'Merging branch new_feature into master' #> [CmdletBinding( @@ -71,16 +70,19 @@ function Merge-GitHubRepositoryBranches ParameterSetName='Uri')] [string] $Uri, + [Parameter(Mandatory)] [string] $Base, - [string] $CommitMessage, - + [Parameter(Mandatory)] [string] $Head, + [string] $CommitMessage, + [string] $AccessToken, [switch] $NoStatus ) + Write-InvocationLog $elements = Resolve-RepositoryElements -DisableValidation @@ -93,9 +95,13 @@ function Merge-GitHubRepositoryBranches } $hashBody = @{ - 'base'= $Base; - 'head' = $Head; - 'commit_message' = $CommitMessage; + 'base'= $Base + 'head' = $Head + } + + if(-not $CommitMessage -eq $null) + { + $hashBody['commit_message'] = $CommitMessage } $params = @{ @@ -109,5 +115,17 @@ function Merge-GitHubRepositoryBranches 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) } - return Invoke-GHRestMethod @params + try { + $result = Invoke-GHRestMethod @params -ExtendedResult + if ($result.statusCode -eq 204) + { + Write-Log -Message "Nothing to merge. The branch $Base already contains changes from $Head" -Level Warning + } + return $result.result + } + catch { + #TODO: Read the error message and find out the kind of issue + Write-Error $_.Exception + Write-Log -Message "Unable to merge. Either the branch $Base or branch $Head does not exist or there is a conflict" -Level Warning + } } diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 601e79ed..5734c956 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -87,7 +87,7 @@ 'Invoke-GHRestMethod', 'Invoke-GHRestMethodMultipleResult', 'Lock-GitHubIssue', - 'Merge-GitHubRepositoryBranches', + 'Merge-GitHubRepositoryBranch', 'Move-GitHubRepositoryOwnership', 'New-GithubAssignee', 'New-GitHubComment', diff --git a/Tests/GitHubRepositoryMerge.tests.ps1 b/Tests/GitHubRepositoryMerge.tests.ps1 new file mode 100644 index 00000000..6ae9d452 --- /dev/null +++ b/Tests/GitHubRepositoryMerge.tests.ps1 @@ -0,0 +1,132 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +<# +.Synopsis + Tests for GitHubRepositoryMerge.ps1 module +#> + +[String] $root = Split-Path -Parent (Split-Path -Parent $Script:MyInvocation.MyCommand.Path) +. (Join-Path -Path $root -ChildPath 'Tests\Config\Settings.ps1') +Import-Module -Name $root -Force + +function Create-Branch($repoName, $branchName) +{ + $existingref = @(Get-GitHubReference -OwnerName $ownerName -RepositoryName $repoName -Reference "heads/master") + $sha = $existingref.object.sha + New-GitHubReference -OwnerName $ownerName -RepositoryName $repoName -Reference $branchName -Sha $sha +} + +function Initialize-AppVeyor +{ +<# + .SYNOPSIS + Configures the tests to run with the authentication information stored in AppVeyor + (if that information exists in the environment). + + .DESCRIPTION + Configures the tests to run with the authentication information stored in AppVeyor + (if that information exists in the environment). + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .NOTES + Internal-only helper method. + + The only reason this exists is so that we can leverage CodeAnalysis.SuppressMessageAttribute, + which can only be applied to functions. + + We call this immediately after the declaration so that AppVeyor initialization can heppen + (if applicable). + +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Justification="Needed to configure with the stored, encrypted string value in AppVeyor.")] + param() + + if ($env:AppVeyor) + { + $secureString = $env:avAccessToken | ConvertTo-SecureString -AsPlainText -Force + $cred = New-Object System.Management.Automation.PSCredential "", $secureString + Set-GitHubAuthentication -Credential $cred + + $script:ownerName = $env:avOwnerName + $script:organizationName = $env:avOrganizationName + + $message = @( + 'This run is executed in the AppVeyor environment.', + 'The GitHub Api Token won''t be decrypted in PR runs causing some tests to fail.', + '403 errors possible due to GitHub hourly limit for unauthenticated queries.', + 'Use Set-GitHubAuthentication manually. modify the values in Tests\Config\Settings.ps1,', + 'and run tests on your machine first.') + Write-Warning -Message ($message -join [Environment]::NewLine) + } +} + +Initialize-AppVeyor + +$script:accessTokenConfigured = Test-GitHubAuthenticationConfigured +if (-not $script:accessTokenConfigured) +{ + $message = @( + 'GitHub API Token not defined, some of the tests will be skipped.', + '403 errors possible due to GitHub hourly limit for unauthenticated queries.') + Write-Warning -Message ($message -join [Environment]::NewLine) +} + +# Backup the user's configuration before we begin, and ensure we're at a pure state before running +# the tests. We'll restore it at the end. +$configFile = New-TemporaryFile +try +{ + Backup-GitHubConfiguration -Path $configFile + Reset-GitHubConfiguration + Set-GitHubConfiguration -DisableTelemetry # We don't want UT's to impact telemetry + Set-GitHubConfiguration -LogRequestBody # Make it easier to debug UT failures + + Describe 'Creating and merging a branch to master' { + #TODO: Remove the below note before merging + #NOTE: These changes depend on the GitHubReference changes + # and should be merged only after those changes are merged + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit + $branchName = "refs/heads/" + $([Guid]::NewGuid().Guid).ToString() + Create-Branch $repoName $branchName + + Context 'Merging a branch with the same changes as base' { + $result = Merge-GitHubRepositoryBranch -OwnerName $ownerName -RepositoryName $repoName -Base 'master' -Head $branchName -CommitMessage 'This merge isnt needed' + + It "Should return null" { + $result | Should be $null + } + } + + Context 'Merging a branch to non-existent base' { + $result = Merge-GitHubRepositoryBranch -OwnerName $ownerName -RepositoryName $repoName -Base ([Guid]::NewGuid().Guid) -Head $branchName -CommitMessage 'This base doesnt exist' + + It "Should return null" { + $result | Should be $null + } + } + + Context 'Merging a non-existent branch to base' { + $result = Merge-GitHubRepositoryBranch -OwnerName $ownerName -RepositoryName $repoName -Base 'master' -Head ([Guid]::NewGuid().Guid) -CommitMessage 'This merge isnt happening' + + It "Should return null" { + $result | Should be $null + } + } + + #TODO: Test cases for + # 1. merge conflict + # 2. actual merging + # 3. Empty commit message + + Remove-GitHubRepository -Uri $repo.svn_url + } +} +finally +{ + # Restore the user's configuration to its pre-test state + Restore-GitHubConfiguration -Path $configFile +} \ No newline at end of file