diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b335618..4e185661 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -614,6 +614,7 @@ Thank you to all of our contributors, no matter how big or small the contributio - **[Giuseppe Campanelli (@themilanfan)](https://github.com/themilanfan)** - **[Christoph Bergmeister (@bergmeister)](https://github.com/bergmeister)** - **[Simon Heather (@X-Guardian)](https://github.com/X-Guardian)** +- **[Henk Meulekamp (@henkmeulekamp)](https://github.com/henkmeulekamp)** ---------- diff --git a/GitHubRepositoryAutolink.ps1 b/GitHubRepositoryAutolink.ps1 new file mode 100644 index 00000000..5ae21158 --- /dev/null +++ b/GitHubRepositoryAutolink.ps1 @@ -0,0 +1,468 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +@{ + GitHubRepositoryAutolinkTypeName = 'GitHub.RepositoryAutolink' + }.GetEnumerator() | ForEach-Object { + Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value + } + +filter Get-GitHubRepositoryAutolink +{ +<# + .SYNOPSIS + Gets the list of autolinks of the specified GitHub repository. + + .DESCRIPTION + Gets the list of autolinks of the specified 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 AutolinkId + Optional, the unique identifier of the autolink to be retrieved + + .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. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Reaction + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .OUTPUTS + GitHub.RepositoryAutolink + + .EXAMPLE + Get-GitHubRepositoryAutolink -OwnerName microsoft -RepositoryName PowerShellForGitHub + + Gets all of the autolink references for the microsoft\PowerShellForGitHub repository. + + .EXAMPLE + Get-GitHubRepositoryAutolink -OwnerName microsoft -RepositoryName PowerShellForGitHub -AutolinkId 42 + + Gets autolink reference with autolinkId 42 from the microsoft\PowerShellForGitHub repository. + + .NOTES + Information about autolinks are only available to repository administrators. +#> + [CmdletBinding(DefaultParameterSetName = 'Elements')] + [OutputType({$script:GitHubRepositoryAutolinkTypeName})] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="The Uri parameter is only referenced by Resolve-RepositoryElements which get access to it from the stack via Get-Variable -Scope 1.")] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + ValueFromPipeline, + ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int64] $AutolinkId, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $uriFragment = [String]::Empty + if ($AutolinkId -gt 0) { + $uriFragment = "repos/$OwnerName/$RepositoryName/autolinks/$AutolinkId" + } else { + $uriFragment = "repos/$OwnerName/$RepositoryName/autolinks" + } + + $params = @{ + 'UriFragment' = $uriFragment + "?" + ($getParams -join '&') + 'Description' = "Getting all autolinks of $RepositoryName" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + } + + return (Invoke-GHRestMethodMultipleResult @params | Add-GitHubRepositoryAutolinkAdditionalProperties) +} + +filter New-GitHubRepositoryAutolink +{ +<# + .SYNOPSIS + Creates a new autolink on given GitHub repository. + + .DESCRIPTION + Creates a new autolink on 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 KeyPrefix + This prefix appended by certain characters will generate a link any time it is found in + an issue, pull request, or commit. + + .PARAMETER UrlTemplate + The URL must contain for the reference number. matches different characters + depending on the value of is_alphanumeric. + + .PARAMETER IsNumericOnly + Whether this autolink reference matches numeric characters only. + If true, the parameter of the url_template matches numeric characters only. + If false, this autolink reference only matches alphanumeric characters A-Z + (case insensitive), 0-9, and -. + + .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. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Reaction + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .OUTPUTS + GitHub.RepositoryAutolink + + .EXAMPLE + New-GitHubRepositoryAutolink -OwnerName microsoft -RepositoryName PowerShellForGitHub -KeyPrefix 'PRJ-' -UrlTemplate 'https://company.issuetracker.com/browse/prj-' + + Creates an autlink reference on this repository under the current authenticated user's account. + + .EXAMPLE + New-GitHubRepositoryAutolink -OwnerName microsoft -RepositoryName PowerShellForGitHub -OrganizationName OctoLabs -KeyPrefix 'PRJ-' -UrlTemplate 'https://company.issuetracker.com/browse/prj-' -IsNumericOnly + + Creates an autlink reference on this repository under the OctoLabs organization. + + .NOTES + Only users with admin access to the repository can create an autolink. +#> + [CmdletBinding( + SupportsShouldProcess, + DefaultParameterSetName='Elements')] + [OutputType({$script:GitHubRepositoryAutolinkTypeName})] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName)] + [string] $KeyPrefix, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName)] + [ValidateScript({if ($_ -match '^https?://([^\s,]+)') { $true } else { throw "Target URL invalid or is missing a token." }})] + [string] $UrlTemplate, + + [Parameter( + ValueFromPipelineByPropertyName)] + [switch] $IsNumericOnly, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + 'IsNumericOnly' = $IsNumericOnly.IsPresent + } + + $hashBody = @{ + 'key_prefix' = $KeyPrefix + 'url_template' = $UrlTemplate + 'is_alphanumeric' = (-not $IsNumericOnly.IsPresent) + } + + if (-not $PSCmdlet.ShouldProcess($KeyPrefix, 'Create Repository Autolink')) + { + return + } + + $params = @{ + 'UriFragment' = "repos/$OwnerName/$RepositoryName/autolinks" + 'Body' = (ConvertTo-Json -InputObject $hashBody) + 'Method' = 'Post' + 'Description' = "Repository Autolink $KeyPrefix in $RepositoryName" + 'AcceptHeader' = $script:symmetraAcceptHeader + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + } + + return (Invoke-GHRestMethod @params | Add-GitHubRepositoryAutolinkAdditionalProperties) +} + +filter Remove-GitHubRepositoryAutolink +{ +<# + .SYNOPSIS + Deletes an autolink reference from a given GitHub repository. + + .DESCRIPTION + Deletes an autolink reference from 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 AutolinkId + The unique identifier of the autolink to be deleted. + + .PARAMETER Force + If this switch is specified, you will not be prompted for confirmation of command execution. + + .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. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Reaction + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .EXAMPLE + Remove-GitHubRepositoryAutolink -OwnerName microsoft -RepositoryName PowerShellForGitHub -AutolinkId 1 + + Removes the autolink reference with autolinkId 1 from the PowerShellForGitHub project. + + .EXAMPLE + $autolink = $repo | New-GitHubRepositoryAutolink -KeyPrefix 'PRJ-123' + $autolink | Remove-GitHubRepositoryAutolink + + Removes the autolink reference we just created using the pipeline, but will prompt for confirmation + because neither -Confirm:$false nor -Force was specified. + + .EXAMPLE + Remove-GitHubRepositoryAutolink -OwnerName microsoft -RepositoryName PowerShellForGitHub -AutolinkId 1 -Confirm:$false + + Removes the autolink reference with autolinkId 1 from the PowerShellForGitHub project. + Will not prompt for confirmation, as -Confirm:$false was specified. + + .EXAMPLE + Remove-GitHubRepositoryAutolink -OwnerName microsoft -RepositoryName PowerShellForGitHub -AutolinkId 1 -Force + + Removes the autolink reference with autolinkId 1 from the PowerShellForGitHub project. + Will not prompt for confirmation, as -Force was specified. + + .NOTES + Only users with admin access to the repository can delete an autolink. +#> + [CmdletBinding( + SupportsShouldProcess, + DefaultParameterSetName='Elements', + ConfirmImpact="High")] + [Alias('Delete-GitHubRepositoryAutolink')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="The Uri parameter is only referenced by Resolve-RepositoryElements which get access to it from the stack via Get-Variable -Scope 1.")] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int64] $AutolinkId, + + [switch] $Force, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + if ($Force -and (-not $Confirm)) + { + $ConfirmPreference = 'None' + } + + if (-not $PSCmdlet.ShouldProcess($Label, 'Remove GitHub Repository Autolink Reference')) + { + return + } + + $params = @{ + 'UriFragment' = "repos/$OwnerName/$RepositoryName/autolinks/$AutolinkId" + 'Method' = 'Delete' + 'Description' = "Deleting GitHub Autolink Reference $AutolinkId from $RepositoryName" + 'AcceptHeader' = $script:symmetraAcceptHeader + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + } + + return Invoke-GHRestMethod @params +} + + +filter Add-GitHubRepositoryAutolinkAdditionalProperties +{ +<# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Autolink objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER RepositoryUrl + Optionally supplied if the Autolink object doesn't have this value already. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .INPUTS + [PSCustomObject] + + .OUTPUTS + GitHub.RepositoryAutolink +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Internal helper that is definitely adding more than one property.")] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [AllowEmptyCollection()] + [PSCustomObject[]] $InputObject, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubRepositoryAutolinkTypeName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + { + if ($null -ne $item.id) + { + Add-Member -InputObject $item -Name 'AutolinkId' -Value $item.id -MemberType NoteProperty -Force + } + + Add-Member -InputObject $item -Name 'KeyPrefix' -Value $item.key_prefix -MemberType NoteProperty -Force + Add-Member -InputObject $item -Name 'UrlTemplate' -Value $item.url_template -MemberType NoteProperty -Force + + Add-Member -InputObject $item -Name 'IsNumericOnly' -Value (-not $item.is_alphanumeric) -MemberType NoteProperty -Force + } + + Write-Output $item + } +} \ No newline at end of file diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 44369427..5aa244df 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -52,6 +52,7 @@ 'GitHubReactions.ps1', 'GitHubReleases.ps1', 'GitHubRepositories.ps1', + 'GitHubRepositoryAutolink.ps1', 'GitHubRepositoryForks.ps1', 'GitHubRepositoryTraffic.ps1', 'GitHubTeams.ps1', @@ -104,6 +105,7 @@ 'Get-GitHubReleaseAsset', 'Get-GitHubRepository', 'Get-GitHubRepositoryActionsPermission', + 'Get-GitHubRepositoryAutolink', 'Get-GitHubRepositoryBranch', 'Get-GitHubRepositoryBranchPatternProtectionRule', 'Get-GitHubRepositoryBranchProtectionRule', @@ -144,6 +146,7 @@ 'New-GitHubRelease', 'New-GitHubReleaseAsset', 'New-GitHubRepository', + 'New-GitHubRepositoryAutolink', 'New-GitHubRepositoryFromTemplate', 'New-GitHubRepositoryBranch', 'New-GitHubRepositoryBranchPatternProtectionRule', @@ -167,6 +170,7 @@ 'Remove-GitHubRelease', 'Remove-GitHubReleaseAsset', 'Remove-GitHubRepository', + 'Remove-GitHubRepositoryAutolink', 'Remove-GitHubRepositoryBranch' 'Remove-GitHubRepositoryBranchPatternProtectionRule', 'Remove-GitHubRepositoryBranchProtectionRule', @@ -228,6 +232,7 @@ 'Delete-GitHubRelease', 'Delete-GitHubReleaseAsset', 'Delete-GitHubRepository', + 'Delete-GitHubRepositoryAutolink', 'Delete-GitHubRepositoryBranch', 'Delete-GitHubRepositoryBranchPatternProtectionRule', 'Delete-GitHubRepositoryBranchProtectionRule', diff --git a/Tests/GitHubRepositoryAutolinks.tests.ps1 b/Tests/GitHubRepositoryAutolinks.tests.ps1 new file mode 100644 index 00000000..89f9aef9 --- /dev/null +++ b/Tests/GitHubRepositoryAutolinks.tests.ps1 @@ -0,0 +1,82 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +<# +.Synopsis + Tests for GitHubRepositoryAutolink.ps1 module +#> + +[CmdletBinding()] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', + Justification='Suppress false positives in Pester code blocks')] +param() + +# This is common test code setup logic for all Pester test files +$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent +. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') + +try +{ + + Describe 'GitHubRepositoryAutolink\Get-GitHubRepositoryAutolink' { + BeforeAll { + $organizationName = $script:organizationName + } + + Context 'When getting a GitHub Repository Autolinks by repository' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + + $repo = New-GitHubRepository -RepositoryName $repoName -OrganizationName $organizationName + + $keyPrefix = 'PRJ-' + $urlTemplate = 'https://company.issuetracker.com/browse/prj-' + $isNumericOnly = $true + + $newGitHubRepositoryAutolinkParms = @{ + OrganizationName = $organizationName + KeyPrefix = $keyPrefix + UrlTemplate = $urlTemplate + IsNumericOnly = $isNumericOnly + } + + New-GitHubRepositoryAutolink @newGitHubRepositoryAutolinkParms | Out-Null + + $autoLinks = Get-GitHubRepositoryAutolink -OwnerName $organizationName -RepositoryName $repoName + $autolink = $autoLinks | Where-Object -Property AutolinkKeyPrefix -eq $keyPrefix + } + + It 'Should have the expected type and additional properties' { + $autolink.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryAutolink' + $autolink.KeyPrefix | Should -Be $keyPrefix + $autolink.UrlTemplate | Should -Be $urlTemplate + $autolink.IsNumericOnly | Should -BeTrue + $autolink.AutolinkId | Should -BeGreaterThan 0 + $autolink.KeyPrefix | Should -Be $autolink.keyPrefix + $autolink.UrlTemplate | Should -Be $autolink.urlTemplate + $autolink.AutolinkId | Should -Be $autolink.id + } + + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $autolink | Remove-GitHubRepositoryAutolink -Force + } + } + } + } +} +finally +{ + if (Test-Path -Path $script:originalConfigFile -PathType Leaf) + { + # Restore the user's configuration to its pre-test state + Restore-GitHubConfiguration -Path $script:originalConfigFile + $script:originalConfigFile = $null + } +} diff --git a/USAGE.md b/USAGE.md index 1edffac6..c479003c 100644 --- a/USAGE.md +++ b/USAGE.md @@ -70,6 +70,10 @@ * [Forks](#forks) * [Get all the forks for a repository](#get-all-the-forks-for-a-repository) * [Create a new fork](#create-a-new-fork) + * [Autolinks](#autolinks) + * [Get all the autolinks for a repository](#get-all-the-autolinks-for-a-repository) + * [Create a new autolink](#create-a-new-autolink) + * [Remove a repository autolink](#remove-a-repository-autolink) * [Content](#content) * [Get html output for a file](#get-html-output-for-a-file) * [Get raw output for a file](#get-raw-output-for-a-file) @@ -740,6 +744,25 @@ New-GitHubRepositoryFork -OwnerName microsoft -RepositoryName PowerShellForGitHu ---------- +### Autolinks + +#### Get all the autolinks for a repository +```powershell +Get-GitHubRepositoryAutolink -OwnerName microsoft -RepositoryName PowerShellForGitHub +``` + +#### Create a new autolink +```powershell +New-GitHubRepositoryAutolink -OwnerName microsoft -RepositoryName PowerShellForGitHub -KeyPrefix 'PRJ-' -UrlTemplate 'https://company.issuetracker.com/browse/prj-' +``` + +#### Removing a repository autolink +```powershell +Remove-GitHubRepositoryAutolink -OwnerName microsoft -RepositoryName PowerShellForGitHub -AutolinkId 1 +``` + +---------- + ### Content #### Get html output for a file