diff --git a/GitHubTraffic.ps1 b/GitHubTraffic.ps1 new file mode 100644 index 00000000..f8db7d7b --- /dev/null +++ b/GitHubTraffic.ps1 @@ -0,0 +1,362 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +function Get-GitHubReferrerTraffic +{ +<# + .SYNOPSIS + Get the top 10 referrers over the last 14 days for a given GitHub repository. + + .DESCRIPTION + Get the top 10 referrers over the last 14 days for 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 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-GitHubReferrerTraffic -OwnerName Powershell -RepositoryName PowerShellForGitHub + + Get the top 10 referrers over the last 14 days from the PowerShell\PowerShellForGitHub project. +#> + [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] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog -Invocation $MyInvocation + + $elements = Resolve-RepositoryElements -BoundParameters $PSBoundParameters + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $params = @{ + 'UriFragment' = "repos/$OwnerName/$RepositoryName/traffic/popular/referrers" + 'Method' = 'Get' + 'Description' = "Getting referrers for $RepositoryName" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -BoundParameters $PSBoundParameters -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return Invoke-GHRestMethod @params +} + +function Get-GitHubPathTraffic +{ +<# + .SYNOPSIS + Get the top 10 popular contents over the last 14 days for a given Github repository. + + .DESCRIPTION + Get the top 10 popular contents over the last 14 days for 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 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-GitHubPathTraffic -OwnerName Powershell -RepositoryName PowerShellForGitHub + + Get the top 10 popular contents over the last 14 days from the PowerShell\PowerShellForGitHub project. +#> + [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] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog -Invocation $MyInvocation + + $elements = Resolve-RepositoryElements -BoundParameters $PSBoundParameters + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $params = @{ + 'UriFragment' = "repos/$OwnerName/$RepositoryName/traffic/popular/paths" + 'Method' = 'Get' + 'Description' = "Getting popular contents for $RepositoryName" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -BoundParameters $PSBoundParameters -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return Invoke-GHRestMethod @params +} + +function Get-GitHubViewTraffic +{ +<# + .SYNOPSIS + Get the total number of views and breakdown per day or week for the last 14 days for the given Github Repository. + + .DESCRIPTION + Get the total number of views and breakdown per day or week for the last 14 days. + Timestamps are aligned to UTC midnight of the beginning of the day or week. Week begins on Monday. + + 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 Per + The interval at which return to return the view counts. + + .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-GitHubViewTraffic -OwnerName Powershell -RepositoryName PowerShellForGitHub + + Get the total number of views and breakdown per day or week for the last 14 days from the PowerShell\PowerShellForGitHub project. +#> + [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, + + [ValidateSet('day', 'week')] + [string] $Per = 'day', + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog -Invocation $MyInvocation + + $elements = Resolve-RepositoryElements -BoundParameters $PSBoundParameters + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + 'Per' = $Per + } + + $getParams = @( + "per=$Per" + ) + + $params = @{ + 'UriFragment' = "repos/$OwnerName/$RepositoryName/traffic/views`?" + ($getParams -join '&') + 'Method' = 'Get' + 'Description' = "Getting views for $RepositoryName" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -BoundParameters $PSBoundParameters -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return Invoke-GHRestMethod @params +} + +function Get-GitHubCloneTraffic +{ +<# + .SYNOPSIS + Get the total number of clones and breakdown per day or week for the last 14 days for the given Github Repository. + + .DESCRIPTION + Get the total number of clones and breakdown per day or week for the last 14 days. + Timestamps are aligned to UTC midnight of the beginning of the day or week. Week begins on Monday. + + 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 Per + The interval at which return to return the view counts. + + .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-GitHubCloneTraffic -OwnerName Powershell -RepositoryName PowerShellForGitHub + + Get the total number of clones and breakdown per day or week for the last 14 days from the PowerShell\PowerShellForGitHub project. +#> + [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, + + [ValidateSet('day', 'week')] + [string] $Per = 'day', + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog -Invocation $MyInvocation + + $elements = Resolve-RepositoryElements -BoundParameters $PSBoundParameters + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + 'Per' = $Per + } + + $getParams = @( + "per=$Per" + ) + + $params = @{ + 'UriFragment' = "repos/$OwnerName/$RepositoryName/traffic/clones`?" + ($getParams -join '&') + 'Method' = 'Get' + 'Description' = "Getting number of clones for $RepositoryName" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -BoundParameters $PSBoundParameters -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return Invoke-GHRestMethod @params +} \ No newline at end of file diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index e32bc165..f1bb1ec7 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -30,6 +30,7 @@ 'GitHubRepositories.ps1', 'GitHubRepositoryForks.ps1', 'GitHubTeams.ps1', + 'GitHubTraffic.ps1', 'GitHubUsers.ps1', 'NugetTools.ps1', 'Telemetry.ps1') @@ -42,6 +43,7 @@ 'Backup-GitHubConfiguration', 'Clear-GitHubAuthentication', 'ConvertFrom-Markdown', + 'Get-GitHubCloneTraffic', 'Get-GitHubCodeOfConduct', 'Get-GitHubConfiguration', 'Get-GitHubEmoji', @@ -51,8 +53,10 @@ 'Get-GitHubLabel', 'Get-GitHubLicense', 'Get-GitHubOrganizationMember', + 'Get-GitHubPathTraffic', 'Get-GitHubPullRequest', 'Get-GitHubRateLimit', + 'Get-GitHubReferrerTraffic', 'Get-GitHubRepository', 'Get-GitHubRepositoryBranch', 'Get-GitHubRepositoryCollaborator', @@ -66,6 +70,7 @@ 'Get-GitHubTeamMember', 'Get-GitHubUser', 'Get-GitHubUserContextualInformation', + 'Get-GitHubViewTraffic', 'Group-GitHubIssue', 'Invoke-GHRestMethod', 'Invoke-GHRestMethodMultipleResult', diff --git a/Tests/GitHubTraffic.tests.ps1 b/Tests/GitHubTraffic.tests.ps1 new file mode 100644 index 00000000..eee59303 --- /dev/null +++ b/Tests/GitHubTraffic.tests.ps1 @@ -0,0 +1,133 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +<# +.Synopsis + Tests for GitHubRepositoryForks.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 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 +Backup-GitHubConfiguration -Path $configFile +Reset-GitHubConfiguration + +Describe 'Getting the referrer list' { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + + Context 'When initially created, there are no referrers' { + $referrerList = Get-GitHubReferrerTraffic -Uri $repo.svn_url + + It 'Should return expected number of referrers' { + @($referrerList).Count | Should be 0 + } + + Remove-GitHubRepository -Uri $repo.svn_url + } +} + +Describe 'Getting the popular content over the last 14 days' { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + + Context 'When initially created, there are is no popular content' { + $pathList = Get-GitHubPathTraffic -Uri $repo.svn_url + + It 'Should return expected number of popular content' { + @($pathList).Count | Should be 0 + } + + Remove-GitHubRepository -Uri $repo.svn_url + } +} + +Describe 'Getting the views over the last 14 days' { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + + Context 'When initially created, there are no views' { + $viewList = Get-GitHubViewTraffic -Uri $repo.svn_url + + It 'Should return 0 in the count property' { + $viewList.Count | Should be 0 + } + + Remove-GitHubRepository -Uri $repo.svn_url + } +} + +Describe 'Getting the clones over the last 14 days' { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + + Context 'When initially created, there is 0 clones' { + $cloneList = Get-GitHubCloneTraffic -Uri $repo.svn_url + + It 'Should return expected number of clones' { + $cloneList.Count | Should be 0 + } + + Remove-GitHubRepository -Uri $repo.svn_url + } +} + +# Restore the user's configuration to its pre-test state +Restore-GitHubConfiguration -Path $configFile diff --git a/USAGE.md b/USAGE.md index 064868c6..da6af709 100644 --- a/USAGE.md +++ b/USAGE.md @@ -25,6 +25,11 @@ * [Forks](#forks) * [Get all the forks for a repository](#get-all-the-forks-for-a-repository) * [Create a new fork](#create-a-new-fork) + * [Traffic](#traffic) + * [Get the referrer traffic for a repository](#get-the-referrer-traffic-for-a-repository) + * [Get the popular content for a repository](#get-the-popular-content-for-a-repository) + * [Get the number of views for a repository](#get-the-number-of-views-for-a-repository) + * [Get the number of clones for a repository](#get-the-number-of-clones-for-a-repository) ---------- @@ -313,3 +318,27 @@ Get-GitHubRepositoryFork -OwnerName PowerShell -RepositoryName PowerShellForGitH ```powershell New-GitHubRepositoryForm -OwnerName PowerShell -RepositoryName PowerShellForGitHub ``` + +---------- + +### Traffic + +#### Get the referrer traffic for a repository +```powershell +Get-GitHubReferrerTraffic -OwnerName PowerShell -RepositoryName PowerShellForGitHub +``` + +#### Get the popular content for a repository +```powershell +Get-GitHubPathTraffic -OwnerName PowerShell -RepositoryName PowerShellForGitHub +``` + +#### Get the number of views for a repository +```powershell +Get-GitHubViewTraffic -OwnerName PowerShell -RepositoryName PowerShellForGitHub -Per 'week' +``` + +#### Get the number of clones for a repository +```powershell +Get-GitHubCloneTraffic -OwnerName PowerShell -RepositoryName PowerShellForGitHub -Per 'day' +```