diff --git a/src/GitHub/GitHub.psd1 b/src/GitHub/GitHub.psd1 index 14bc32924..bea4814b7 100644 --- a/src/GitHub/GitHub.psd1 +++ b/src/GitHub/GitHub.psd1 @@ -3,7 +3,7 @@ Author = 'Marius Storhaug' # Version number of this module - ModuleVersion = '0.1.1' + ModuleVersion = '0.2.0' # Description of the functionality provided by this module Description = 'GitHub PowerShell Module' diff --git a/src/GitHub/en_US/about_Auth.help.txt b/src/GitHub/en_US/about_Auth.help.txt index d7bf1793f..2571c556d 100644 --- a/src/GitHub/en_US/about_Auth.help.txt +++ b/src/GitHub/en_US/about_Auth.help.txt @@ -38,8 +38,8 @@ KEYWORDS SEE ALSO For more information on the Device Flow visit: - - https://docs.github.com/en/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app + - https://docs.github.com/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app For information about scopes and other authentication methods on GitHub: - - https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps - - https://docs.github.com/en/rest/overview/other-authentication-methods#authenticating-for-saml-sso + - https://docs.github.com/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps + - https://docs.github.com/rest/overview/other-authentication-methods#authenticating-for-saml-sso diff --git a/src/GitHub/private/Auth/DeviceFlow/Invoke-GitHubDeviceFlowLogin.ps1 b/src/GitHub/private/Auth/DeviceFlow/Invoke-GitHubDeviceFlowLogin.ps1 index 712462fbb..6bc64b2d6 100644 --- a/src/GitHub/private/Auth/DeviceFlow/Invoke-GitHubDeviceFlowLogin.ps1 +++ b/src/GitHub/private/Auth/DeviceFlow/Invoke-GitHubDeviceFlowLogin.ps1 @@ -14,8 +14,8 @@ .NOTES For more info about the Device Flow visit: - https://docs.github.com/en/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app - https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#device-flow + https://docs.github.com/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app + https://docs.github.com/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#device-flow #> [OutputType([void])] [CmdletBinding()] @@ -27,7 +27,7 @@ # The scope of the access token, when using OAuth authentication. # Provide the list of scopes as space-separated values. # For more information on scopes visit: - # https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps + # https://docs.github.com/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps [Parameter()] [string] $Scope, diff --git a/src/GitHub/private/Auth/DeviceFlow/Request-GitHubAccessToken.ps1 b/src/GitHub/private/Auth/DeviceFlow/Request-GitHubAccessToken.ps1 index 171d5bbe1..d920e8f6e 100644 --- a/src/GitHub/private/Auth/DeviceFlow/Request-GitHubAccessToken.ps1 +++ b/src/GitHub/private/Auth/DeviceFlow/Request-GitHubAccessToken.ps1 @@ -14,7 +14,7 @@ .NOTES For more info about the Device Flow visit: - https://docs.github.com/en/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app + https://docs.github.com/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app #> [OutputType([PSCustomObject])] [CmdletBinding(DefaultParameterSetName = 'DeviceFlow')] diff --git a/src/GitHub/private/Auth/DeviceFlow/Request-GitHubDeviceCode.ps1 b/src/GitHub/private/Auth/DeviceFlow/Request-GitHubDeviceCode.ps1 index dc6cdf796..1171229ea 100644 --- a/src/GitHub/private/Auth/DeviceFlow/Request-GitHubDeviceCode.ps1 +++ b/src/GitHub/private/Auth/DeviceFlow/Request-GitHubDeviceCode.ps1 @@ -13,7 +13,7 @@ .NOTES For more info about the Device Flow visit: - https://docs.github.com/en/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app + https://docs.github.com/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app #> [OutputType([PSCustomObject])] [CmdletBinding()] @@ -25,7 +25,7 @@ # The scope of the access token, when using OAuth authentication. # Provide the list of scopes as space-separated values. # For more information on scopes visit: - # https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps + # https://docs.github.com/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps [Parameter()] [string] $Scope = 'gist, read:org, repo, workflow' ) diff --git a/src/GitHub/private/Auth/DeviceFlow/Wait-GitHubAccessToken.ps1 b/src/GitHub/private/Auth/DeviceFlow/Wait-GitHubAccessToken.ps1 index 867d5890e..2a45ed719 100644 --- a/src/GitHub/private/Auth/DeviceFlow/Wait-GitHubAccessToken.ps1 +++ b/src/GitHub/private/Auth/DeviceFlow/Wait-GitHubAccessToken.ps1 @@ -17,7 +17,7 @@ .NOTES For more info about the Device Flow visit: - https://docs.github.com/en/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app + https://docs.github.com/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app #> [OutputType([PSCustomObject])] [CmdletBinding(DefaultParameterSetName = 'DeviceFlow')] diff --git a/src/GitHub/private/Menu/Invoke-Meny.ps1 b/src/GitHub/private/Menu/Invoke-Meny.ps1 index dcdbe6091..caab756fc 100644 --- a/src/GitHub/private/Menu/Invoke-Meny.ps1 +++ b/src/GitHub/private/Menu/Invoke-Meny.ps1 @@ -18,7 +18,7 @@ if ($pos -ge $menuItems.length) { $pos = $menuItems.length - 1 } Invoke-DrawMenu $menuItems $pos $menuTitel } - Write-Output $($menuItems[$pos]) + $($menuItems[$pos]) } diff --git a/src/GitHub/private/Organization/Get-GitHubAllOrganization.ps1 b/src/GitHub/private/Organization/Get-GitHubAllOrganization.ps1 new file mode 100644 index 000000000..9448116a1 --- /dev/null +++ b/src/GitHub/private/Organization/Get-GitHubAllOrganization.ps1 @@ -0,0 +1,45 @@ +filter Get-GitHubAllOrganization { + <# + .SYNOPSIS + List organizations + + .DESCRIPTION + Lists all organizations, in the order that they were created on GitHub. + + **Note:** Pagination is powered exclusively by the `since` parameter. Use the [Link header](https://docs.github.com/rest/guides/using-pagination-in-the-rest-api#using-link-headers) to get the URL for the next page of organizations. + + .EXAMPLE + Get-GitHubAllOrganization -Since 142951047 + + List organizations, starting with PSModule + + .NOTES + https://docs.github.com/rest/orgs/orgs#list-organizations + + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # A organization ID. Only return organizations with an ID greater than this ID. + [Parameter()] + [int] $Since = 0, + + # The number of results per page (max 100). + [Parameter()] + [int] $PerPage = 30 + ) + + $body = @{ + since = $Since + per_page = $PerPage + } + + $inputObject = @{ + APIEndpoint = '/organizations' + Method = 'GET' + Body = $body + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/private/Organization/Get-GitHubMyOrganization.ps1 b/src/GitHub/private/Organization/Get-GitHubMyOrganization.ps1 new file mode 100644 index 000000000..d90f84142 --- /dev/null +++ b/src/GitHub/private/Organization/Get-GitHubMyOrganization.ps1 @@ -0,0 +1,41 @@ +filter Get-GitHubMyOrganization { + <# + .SYNOPSIS + List organizations for the authenticated user + + .DESCRIPTION + List organizations for the authenticated user. + + **OAuth scope requirements** + + This only lists organizations that your authorization allows you to operate on in some way (e.g., you can list teams with `read:org` scope, you can publicize your organization membership with `user` scope, etc.). Therefore, this API requires at least `user` or `read:org` scope. OAuth requests with insufficient scope receive a `403 Forbidden` response. + + .EXAMPLE + Get-GitHubMyOrganization + + List organizations for the authenticated user. + + .NOTES + https://docs.github.com/rest/orgs/orgs#list-organizations-for-the-authenticated-user + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The number of results per page (max 100). + [Parameter()] + [int] $PerPage = 30 + ) + + $body = @{ + per_page = $PerPage + } + + $inputObject = @{ + APIEndpoint = '/user/orgs' + Method = 'GET' + Body = $body + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/private/Organization/Get-GitHubOrganizationByName.ps1 b/src/GitHub/private/Organization/Get-GitHubOrganizationByName.ps1 new file mode 100644 index 000000000..1e7c140fd --- /dev/null +++ b/src/GitHub/private/Organization/Get-GitHubOrganizationByName.ps1 @@ -0,0 +1,42 @@ +filter Get-GitHubOrganizationByName { + <# + .SYNOPSIS + Get an organization + + .DESCRIPTION + To see many of the organization response values, you need to be an authenticated organization owner with the `admin:org` scope. When the value of `two_factor_requirement_enabled` is `true`, the organization requires all members, billing managers, and outside collaborators to enable [two-factor authentication](https://docs.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/). + + GitHub Apps with the `Organization plan` permission can use this endpoint to retrieve information about an organization's GitHub plan. See "[Authenticating with GitHub Apps](https://docs.github.com/apps/building-github-apps/authenticating-with-github-apps/)" for details. For an example response, see 'Response with GitHub plan information' below." + + .EXAMPLE + Get-GitHubOrganizationByName -OrganizationName 'github' + + Get the 'GitHub' organization + + .NOTES + https://docs.github.com/rest/orgs/orgs#get-an-organization + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The organization name. The name is not case sensitive. + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName + )] + [Alias('login')] + [Alias('org')] + [Alias('owner')] + [string] $OrganizationName + ) + + + $inputObject = @{ + APIEndpoint = "/orgs/$OrganizationName" + Method = 'GET' + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/private/Organization/Get-GitHubUserOrganization.ps1 b/src/GitHub/private/Organization/Get-GitHubUserOrganization.ps1 new file mode 100644 index 000000000..1e815c218 --- /dev/null +++ b/src/GitHub/private/Organization/Get-GitHubUserOrganization.ps1 @@ -0,0 +1,43 @@ +filter Get-GitHubUserOrganization { + <# + .SYNOPSIS + List organizations for a user + + .DESCRIPTION + List [public organization memberships](https://docs.github.com/articles/publicizing-or-concealing-organization-membership) for the specified user. + + This method only lists _public_ memberships, regardless of authentication. If you need to fetch all of the organization memberships (public and private) for the authenticated user, use the [List organizations for the authenticated user](https://docs.github.com/rest/orgs/orgs#list-organizations-for-the-authenticated-user) API instead. + + .EXAMPLE + Get-GitHubUserOrganization -Username 'octocat' + + List public organizations for the user 'octocat'. + + .NOTES + https://docs.github.com/rest/orgs/orgs#list-organizations-for-a-user + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The handle for the GitHub user account. + [Parameter(Mandatory)] + [string] $Username, + + # The number of results per page (max 100). + [Parameter()] + [int] $PerPage = 30 + ) + + $body = @{ + per_page = $PerPage + } + + $inputObject = @{ + APIEndpoint = "/users/$Username/orgs" + Method = 'GET' + Body = $body + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/public/Users/Get-GitHubUserList.ps1 b/src/GitHub/private/Users/Get-GitHubAllUser.ps1 similarity index 74% rename from src/GitHub/public/Users/Get-GitHubUserList.ps1 rename to src/GitHub/private/Users/Get-GitHubAllUser.ps1 index 960bfbe2c..a996a830e 100644 --- a/src/GitHub/public/Users/Get-GitHubUserList.ps1 +++ b/src/GitHub/private/Users/Get-GitHubAllUser.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubUserList { +filter Get-GitHubAllUser { <# .SYNOPSIS List users @@ -9,9 +9,9 @@ Note: Pagination is powered exclusively by the `since` parameter. Use the [Link header](https://docs.github.com/rest/guides/using-pagination-in-the-rest-api#using-link-headers) to get the URL for the next page of users. .EXAMPLE - Get-GitHubUserList -Since 17722253 + Get-GitHubAllUser -Since 17722253 - Get the authenticated user + Get a list of users, starting with the user 'MariusStorhaug'. .NOTES https://docs.github.com/rest/users/users#list-users @@ -22,15 +22,13 @@ # A user ID. Only return users with an ID greater than this ID. [Parameter()] [int] $Since = 0, + # The number of results per page (max 100). [Parameter()] - [int] $PerPage = 100 + [int] $PerPage = 30 ) - $body = @{ - since = $Since - per_page = $PerPage - } + $body = $PSBoundParameters | ConvertFrom-HashTable | ConvertTo-HashTable -NameCasingStyle snake_case $inputObject = @{ APIEndpoint = "/users" @@ -38,6 +36,6 @@ Body = $body } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/private/Users/Get-GitHubMyUser.ps1 b/src/GitHub/private/Users/Get-GitHubMyUser.ps1 new file mode 100644 index 000000000..3bec059c4 --- /dev/null +++ b/src/GitHub/private/Users/Get-GitHubMyUser.ps1 @@ -0,0 +1,30 @@ +filter Get-GitHubMyUser { + <# + .SYNOPSIS + Get the authenticated user + + .DESCRIPTION + If the authenticated user is authenticated with an OAuth token with the `user` scope, then the response lists public and private profile information. + If the authenticated user is authenticated through OAuth without the `user` scope, then the response lists only public profile information. + + .EXAMPLE + Get-GitHubMyUser + + Get the authenticated user + + .NOTES + https://docs.github.com/rest/users/users#get-the-authenticated-user + #> + [OutputType([pscustomobject])] + [Alias('Get-GitHubContext')] + [CmdletBinding()] + param () + + $inputObject = @{ + APIEndpoint = '/user' + Method = 'GET' + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/private/Users/Get-GitHubUserByName.ps1 b/src/GitHub/private/Users/Get-GitHubUserByName.ps1 new file mode 100644 index 000000000..6d78f9716 --- /dev/null +++ b/src/GitHub/private/Users/Get-GitHubUserByName.ps1 @@ -0,0 +1,41 @@ +filter Get-GitHubUserByName { + <# + .SYNOPSIS + Get a user + + .DESCRIPTION + Provides publicly available information about someone with a GitHub account. + GitHub Apps with the `Plan` user permission can use this endpoint to retrieve information about a user's GitHub plan. The GitHub App must be authenticated as a user. See "[Identifying and authorizing users for GitHub Apps](https://docs.github.com/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps/)" for details about authentication. For an example response, see 'Response with GitHub plan information' below" + The `email` key in the following response is the publicly visible email address from your GitHub [profile page](https://github.com/settings/profile). When setting up your profile, you can select a primary email address to be ΓÇ£publicΓÇ¥ which provides an email entry for this endpoint. If you do not set a public email address for `email`, then it will have a value of `null`. You only see publicly visible email addresses when authenticated with GitHub. For more information, see [Authentication](https://docs.github.com/rest/overview/resources-in-the-rest-api#authentication). + The Emails API enables you to list all of your email addresses, and toggle a primary email to be visible publicly. For more information, see "[Emails API](https://docs.github.com/rest/users/emails)". + + .EXAMPLE + Get-GitHubUserByName -Username 'octocat' + + Get the 'octocat' user. + + .NOTES + https://docs.github.com/rest/users/users#get-a-user + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The handle for the GitHub user account. + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName + )] + [Alias('login')] + [string] $Username + ) + + + $inputObject = @{ + APIEndpoint = "/users/$Username" + Method = 'GET' + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/private/Utilities/Casing/Convert-StringCasingStyle.ps1 b/src/GitHub/private/Utilities/Casing/Convert-StringCasingStyle.ps1 new file mode 100644 index 000000000..780ebbe75 --- /dev/null +++ b/src/GitHub/private/Utilities/Casing/Convert-StringCasingStyle.ps1 @@ -0,0 +1,69 @@ +filter Convert-StringCasingStyle { + <# + .SYNOPSIS + Convert a string to a different casing style + + .DESCRIPTION + This function converts a string to a different casing style. + + .EXAMPLE + 'thisIsCamelCase' | Convert-StringCasingStyle -To 'snake_case' + + Convert the string 'thisIsCamelCase' to 'this_is_camel_case' + + .EXAMPLE + 'thisIsCamelCase' | Convert-StringCasingStyle -To 'UPPER_SNAKE_CASE' + + Convert the string 'thisIsCamelCase' to 'THIS_IS_CAMEL_CASE' + + .EXAMPLE + 'thisIsCamelCase' | Convert-StringCasingStyle -To 'kebab-case' + + .NOTES + General notes + #> + [OutputType([string])] + [CmdletBinding()] + param ( + # The string to convert + [Parameter( + Mandatory, + ValueFromPipeline + )] + [string] $Text, + + # The casing style to convert the string to + [Parameter(Mandatory)] + [ValidateSet( + 'lowercase', + 'UPPERCASE', + 'Title Case', + 'Sentencecase', + 'PascalCase', + 'camelCase', + 'kebab-case', + 'UPPER-KEBAB-CASE', + 'snake_case', + 'UPPER_SNAKE_CASE' + )] + [string] $To + ) + + $currentStyle = Get-StringCasingStyle -Text $Text + + $words = Split-StringByCasingStyle -Text $Text -By $currentStyle + + # Convert the words into the target style + switch ($To) { + 'lowercase' { ($words -join '').toLower() } + 'UPPERCASE' { ($words -join '').toUpper() } + 'Title Case' { ($words | ForEach-Object { $_.Substring(0, 1).ToUpper() + $_.Substring(1).ToLower() }) -join ' ' } + 'Sentencecase' { $words -join '' | ForEach-Object { $_.Substring(0, 1).ToUpper() + $_.Substring(1).ToLower() } } + 'kebab-case' { ($words -join '-').ToLower() } + 'snake_case' { ($words -join '_').ToLower() } + 'PascalCase' { ($words | ForEach-Object { $_.Substring(0, 1).ToUpper() + $_.Substring(1).ToLower() }) -join '' } + 'camelCase' { $words[0].toLower() + (($words | Select-Object -Skip 1 | ForEach-Object { $_.Substring(0, 1).ToUpper() + $_.Substring(1) }) -join '') } + 'UPPER_SNAKE_CASE' { ($words -join '_').toUpper() } + 'UPPER-KEBAB-CASE' { ($words -join '-').toUpper() } + } +} diff --git a/src/GitHub/private/Utilities/Casing/Get-StringCasingStyle.ps1 b/src/GitHub/private/Utilities/Casing/Get-StringCasingStyle.ps1 new file mode 100644 index 000000000..49e4624e7 --- /dev/null +++ b/src/GitHub/private/Utilities/Casing/Get-StringCasingStyle.ps1 @@ -0,0 +1,98 @@ +filter Get-StringCasingStyle { + <# + .SYNOPSIS + Detects the casing style of a string + + .DESCRIPTION + This function detects the casing style of a string. + + .EXAMPLE + 'testtesttest' | Get-StringCasingStyle + + lowercase + + .EXAMPLE + 'TESTTESTTEST' | Get-StringCasingStyle + + UPPERCASE + + .EXAMPLE + 'Testtesttest' | Get-StringCasingStyle + + Sentencecase + + .EXAMPLE + 'TestTestTest' | Get-StringCasingStyle + + PascalCase + + .EXAMPLE + 'testTestTest' | Get-StringCasingStyle + + camelCase + + .EXAMPLE + 'test-test-test' | Get-StringCasingStyle + + kebab-case + + .EXAMPLE + 'TEST-TEST-TEST' | Get-StringCasingStyle + + UPPER-KEBAB-CASE + + .EXAMPLE + 'test_test_test' | Get-StringCasingStyle + + snake_case + + .EXAMPLE + 'TEST_TEST_TEST' | Get-StringCasingStyle + + UPPER_SNAKE_CASE + + .EXAMPLE + 'Test_teSt-Test' | Get-StringCasingStyle + + Unknown + #> + [OutputType([string])] + [CmdletBinding()] + param ( + # The string to check the casing style of + [Parameter( + Mandatory, + ValueFromPipeline + )] + [ValidateNotNullOrEmpty()] + [string] $Text + ) + + $style = if ([regex]::Match($Text, '^[a-z][a-z0-9]*$').Success) { + 'lowercase' + } elseif ([regex]::Match($Text, '^[A-Z][A-Z0-9]*$').Success) { + 'UPPERCASE' + } elseif ([regex]::Match($Text, '^[A-Z][a-z0-9]*$').Success) { + 'Sentencecase' + } elseif ([regex]::Match($Text, '^([A-Z][a-z]*)(\s+[A-Z][a-z]*)+$').Success) { + 'Title Case' + } elseif ([regex]::Match($Text, '^[A-Z][a-z0-9]*([A-Z][a-z0-9]*)+$').Success) { + 'PascalCase' + } elseif ([regex]::Match($Text, '^[a-z][a-z0-9]*([A-Z][a-z0-9]*)+$').Success) { + 'camelCase' + } elseif ([regex]::Match($Text, '^[a-z][a-z0-9]*(-[a-z0-9]+)+$').Success) { + 'kebab-case' + } elseif ([regex]::Match($Text, '^[A-Z][A-Z0-9]*(-[A-Z0-9]+)+$').Success) { + 'UPPER-KEBAB-CASE' + } elseif ([regex]::Match($Text, '^[a-z][a-z0-9]*(_[a-z0-9]+)+$').Success) { + 'snake_case' + } elseif ([regex]::Match($Text, '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)+$').Success) { + 'UPPER_SNAKE_CASE' + } else { + 'Unknown' + } + + Write-Verbose "Detected casing style: [$style]" + $style + +} diff --git a/src/GitHub/private/Utilities/Casing/Split-StringByCasingStyle.ps1 b/src/GitHub/private/Utilities/Casing/Split-StringByCasingStyle.ps1 new file mode 100644 index 000000000..a3cd8d78b --- /dev/null +++ b/src/GitHub/private/Utilities/Casing/Split-StringByCasingStyle.ps1 @@ -0,0 +1,101 @@ +filter Split-StringByCasingStyle { + <# + .SYNOPSIS + Splits a kebab-case string into an array of words + + .DESCRIPTION + This function splits a kebab-case string into an array of words. + + .EXAMPLE + Split-StringByCasingStyle -Text 'this-is-a-kebab-case-string' -By kebab-case + + this + is + a + kebab + case + string + + .EXAMPLE + Split-StringByCasingStyle -Text 'this_is_a_kebab_case_string' -By 'snake_case' + + this + is + a + kebab + case + string + + .EXAMPLE + Split-StringByCasingStyle -Text 'ThisIsAPascalCaseString' -By 'PascalCase' + + This + Is + A + Pascal + Case + String + + .EXAMPLE + Split-StringByCasingStyle -Text 'thisIsACamelCaseString' -By 'camelCase' + + this + Is + A + Camel + Case + String + + .EXAMPLE + Split-StringByCasingStyle -Text 'this_is_a-CamelCaseString' -By kebab-case | Split-StringByCasingStyle -By snake_case + + this_is_a + camelcasestring + + + #> + [OutputType([string[]])] + [CmdletBinding()] + param ( + # The string to split + [Parameter( + Mandatory, + ValueFromPipeline + )] + [string] $Text, + + # The casing style to split the string by + [Parameter()] + [ValidateSet( + 'lowercase', + 'UPPERCASE', + 'Sentencecase', + 'Title Case', + 'PascalCase', + 'camelCase', + 'kebab-case', + 'UPPER-KEBAB-CASE', + 'snake_case', + 'UPPER_SNAKE_CASE' + )] + [string] $By + ) + + $styles = $PSBoundParameters | Where-Object { $_.Value -eq $true } | Select-Object -ExpandProperty Name + + Write-Verbose "Splitting string [$Text] by casing style [$($styles -join ', ' )]" + $splitText = switch ($By) { + 'PascalCase' { [regex]::Matches($Text, '([A-Z][a-z]*)').Value; break } + 'camelCase' { [regex]::Matches($Text, '([A-Z][a-z]*)|^[a-z]+').Value; break } + 'kebab-case' { $Text -split '-'; break } + 'UPPER-KEBAB-CASE' { $Text -split '-'; break } + 'snake_case' { $Text -split '_'; break } + 'UPPER_SNAKE_CASE' { $Text -split '_'; break } + default { + $Text -split ' ' + } + } + + Write-Verbose "Result: [$($splitText -join ', ')]" + $splitText +} diff --git a/src/GitHub/private/Utilities/ConvertFrom-HashTable.ps1 b/src/GitHub/private/Utilities/ConvertFrom-HashTable.ps1 deleted file mode 100644 index 567e8a276..000000000 --- a/src/GitHub/private/Utilities/ConvertFrom-HashTable.ps1 +++ /dev/null @@ -1,11 +0,0 @@ -function ConvertFrom-HashTable { - [CmdletBinding()] - param ( - [Parameter( - Mandatory, - ValueFromPipeline - )] - [object]$InputObject - ) - ([pscustomobject](@{} + $InputObject)) -} diff --git a/src/GitHub/private/Utilities/ConvertTo-HashTable.ps1 b/src/GitHub/private/Utilities/ConvertTo-HashTable.ps1 deleted file mode 100644 index c750d5f45..000000000 --- a/src/GitHub/private/Utilities/ConvertTo-HashTable.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -function ConvertTo-HashTable { - [CmdletBinding()] - param ( - [Parameter( - Mandatory, - ValueFromPipeline - )] - [pscustomobject]$InputObject - ) - [hashtable]$hashtable = @{} - - foreach ($item in $InputObject.PSobject.Properties) { - Write-Verbose "$($item.Name) : $($item.Value) : $($item.TypeNameOfValue)" - $hashtable.$($item.Name) = $item.Value - } - $hashtable -} diff --git a/src/GitHub/private/Utilities/Hashtable/ConvertFrom-HashTable.ps1 b/src/GitHub/private/Utilities/Hashtable/ConvertFrom-HashTable.ps1 new file mode 100644 index 000000000..1db300f69 --- /dev/null +++ b/src/GitHub/private/Utilities/Hashtable/ConvertFrom-HashTable.ps1 @@ -0,0 +1,44 @@ +filter ConvertFrom-HashTable { + <# + .SYNOPSIS + Converts a hashtable to a pscustomobject + + .DESCRIPTION + This function converts a hashtable to a pscustomobject. + + .EXAMPLE + $object = @{a = 1;b = 2;c = 3} + $object | ConvertFrom-HashTable | Format-Table + + a b c + - - - + 1 2 3 + + Converts the hashtable to a pscustomobject and displays it in a table. + + .EXAMPLE + $object = @{a = 1;b = 2;c = 3} + $object | ConvertFrom-Dictionary | ConvertTo-Json + + { + "a": 1, + "b": 2, + "c": 3 + } + + Converts the hashtable to a pscustomobject and then to JSON. + Using the alias 'ConvertFrom-Dictionary' instead of 'ConvertFrom-HashTable'. + #> + [OutputType([pscustomobject])] + [Alias('ConvertFrom-Dictionary')] + [CmdletBinding()] + param ( + # The hashtable to be converted. The input takes any type of dictionary. The original dictionary is not modified. + [Parameter( + Mandatory, + ValueFromPipeline + )] + [object]$InputObject + ) + $InputObject | ConvertTo-Json -Depth 100 | ConvertFrom-Json +} diff --git a/src/GitHub/private/Utilities/Hashtable/ConvertTo-HashTable.ps1 b/src/GitHub/private/Utilities/Hashtable/ConvertTo-HashTable.ps1 new file mode 100644 index 000000000..8b9023554 --- /dev/null +++ b/src/GitHub/private/Utilities/Hashtable/ConvertTo-HashTable.ps1 @@ -0,0 +1,67 @@ +filter ConvertTo-HashTable { + <# + .SYNOPSIS + Converts an object to a hashtable + + .DESCRIPTION + This function converts an object to a hashtable. + + .EXAMPLE + $object = [pscustomobject]@{a = 1;b = 2;c = 3} + $object | ConvertTo-HashTable | Format-Table + + Name Value + ---- ----- + a 1 + b 2 + c 3 + + Converts the object to a hashtable and displays it in a table. + + .EXAMPLE + $object = [pscustomobject]@{a = 1;b = 2;c = 3} + $object | ConvertTo-Dictionary | ConvertTo-Json + + { + "a": 1, + "b": 2, + "c": 3 + } + + Converts the object to a hashtable and then to JSON. + Using the alias 'ConvertTo-Dictionary' instead of 'ConvertTo-HashTable'. + #> + [OutputType([hashtable])] + [Alias('ConvertTo-Dictionary')] + [CmdletBinding()] + param ( + # The object to be converted. The input takes any type of object. The original object is not modified. + [Parameter( + Mandatory, + ValueFromPipeline + )] + [object]$InputObject, + + # The casing style of the hashtable keys. + [Parameter()] + [ValidateSet( + 'lowercase', + 'UPPERCASE', + 'Title Case', + 'PascalCase', + 'camelCase', + 'kebab-case', + 'UPPER-KEBAB-CASE', + 'snake_case', + 'UPPER_SNAKE_CASE' + )] + [string]$NameCasingStyle + ) + [hashtable]$hashtable = @{} + + foreach ($item in $InputObject.PSObject.Properties) { + $name = $NameCasingStyle ? ($item.Name | Convert-StringCasingStyle -To $NameCasingStyle) : $item.Name + $hashtable[$name] = $item.Value + } + $hashtable +} diff --git a/src/GitHub/private/Utilities/Hashtable/Join-Object.ps1 b/src/GitHub/private/Utilities/Hashtable/Join-Object.ps1 new file mode 100644 index 000000000..9f4bb4355 --- /dev/null +++ b/src/GitHub/private/Utilities/Hashtable/Join-Object.ps1 @@ -0,0 +1,92 @@ +filter Join-Object { + <# + .SYNOPSIS + Merges two or more objects into a single object + + .DESCRIPTION + Merges two or more objects into a single object. The first object is the main object, and the remaining objects are overrides. The overrides are applied in order, so the last object in the list will override any previous values. + + .EXAMPLE + $main = [pscustomobject]@{a = 1; b = 2; c = 3} + $overrides = [pscustomobject]@{a = 4; b = 5; d = 6} + $overrides2 = [pscustomobject]@{a = 7; b = 8; e = 9} + Join-Object -Main $main -Overrides $overrides, $overrides2 + + a b c d e + - - - - - + 7 8 3 6 9 + + Merges the three objects into a single object. The values from the last object override the values from the previous objects. + + .EXAMPLE + $main = @{a = 1;b = 2} + $overrides = @{a = 3;c = 4} + Merge-Object -Main $main -Overrides $overrides -AsHashtable + + Name Value + ---- ----- + a 3 + b 2 + c 4 + + Merges the two hashtables into a single hashtable. The values from the last hashtable override the values from the previous hashtables. + Using the alias 'Merge-Object' instead of 'Join-Object'. + + .EXAMPLE + $main = @{a = 1;b = 1;c = 1} + $overrides = @{b = 2;d = 2} + $overrides2 = @{c = 3;e = 3} + $main | Join-Object -Overrides $overrides, $overrides2 | Format-Table + + a b c d e + - - - - - + 1 2 3 2 3 + + Merges the three hashtables into a single hashtable. The values from the last hashtable override the values from the previous hashtables. + Using the pipeline to pass the main object instead of the -Main parameter. + #> + [OutputType([pscustomobject])] + [OutputType(ParameterSetName = 'AsHashTable', [hashtable])] + [Alias('Merge-Object')] + [CmdletBinding(DefaultParameterSetName = '__DefaultSet')] + param ( + # The main object to merge into. This object will be cloned, so the original object will not be modified. + [Parameter( + Mandatory, + ValueFromPipeline + )] + [object] $Main, + + # The objects to merge into the main object + [Parameter(Mandatory)] + [object[]] $Overrides, + + # Return the result as a hashtable instead of a pscustomobject + [Parameter( + Mandatory, + ParameterSetName = 'AsHashTable' + )] + [switch] $AsHashtable + ) + + if ($Main -isnot [hashtable]) { + $Main = $Main | ConvertTo-HashTable + } + $hashtable = $Main.clone() + + foreach ($Override in $Overrides) { + if ($Override -isnot [hashtable]) { + $Override = $Override | ConvertTo-HashTable + } + + $Override.Keys | ForEach-Object { + $hashtable[$_] = $Override[$_] + } + } + + if ($AsHashtable) { + return $hashtable + } + + $hashtable | ConvertFrom-HashTable +} diff --git a/src/GitHub/private/Utilities/Remove-HashTableEntries.ps1 b/src/GitHub/private/Utilities/Hashtable/Remove-HashTableEntries.ps1 similarity index 98% rename from src/GitHub/private/Utilities/Remove-HashTableEntries.ps1 rename to src/GitHub/private/Utilities/Hashtable/Remove-HashTableEntries.ps1 index 3d7a8c411..110bb3ed0 100644 --- a/src/GitHub/private/Utilities/Remove-HashTableEntries.ps1 +++ b/src/GitHub/private/Utilities/Hashtable/Remove-HashTableEntries.ps1 @@ -1,4 +1,4 @@ -function Remove-HashtableEntries { +filter Remove-HashtableEntries { [OutputType([void])] [CmdletBinding()] param ( @@ -7,14 +7,19 @@ ValueFromPipeline )] [hashtable] $Hashtable, + [Parameter()] [switch] $NullOrEmptyValues, + [Parameter()] [string[]] $RemoveTypes, + [Parameter()] [string[]] $RemoveNames, + [Parameter()] [string[]] $KeepTypes, + [Parameter()] [string[]] $KeepNames diff --git a/src/GitHub/private/Utilities/Join-Hashtable.ps1 b/src/GitHub/private/Utilities/Join-Hashtable.ps1 deleted file mode 100644 index b53bedb49..000000000 --- a/src/GitHub/private/Utilities/Join-Hashtable.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -function Join-Hashtable { - [OutputType([void])] - [Alias('Merge-HashTable')] - [CmdletBinding()] - param ( - [hashtable] $Main, - [hashtable] $Overrides - ) - $hashtable = @{} - $Main.Keys | ForEach-Object { - $hashtable[$_] = $Main[$_] - } - $Overrides.Keys | ForEach-Object { - $hashtable[$_] = $Overrides[$_] - } - $hashtable -} diff --git a/src/GitHub/private/Utilities/Web/ConvertTo-QueryString.ps1 b/src/GitHub/private/Utilities/Web/ConvertTo-QueryString.ps1 new file mode 100644 index 000000000..fed644eef --- /dev/null +++ b/src/GitHub/private/Utilities/Web/ConvertTo-QueryString.ps1 @@ -0,0 +1,50 @@ +filter ConvertTo-QueryString { + <# + .SYNOPSIS + Convert an object to a query string + + .DESCRIPTION + Convert an object to a query string + + .EXAMPLE + ConvertTo-QueryString -InputObject @{a=1;b=2} + + ?a=1&b=2 + + .EXAMPLE + ConvertTo-QueryString -InputObject @{a='this is value of a';b='valueOfB'} + + ?a=this%20is%20value%20of%20a&b=valueOfB + + .EXAMPLE + ConvertTo-QueryString -InputObject @{a='this is value of a';b='valueOfB'} -AsURLEncoded + + ?a=this+is+value+of+a&b=valueOfB + #> + [OutputType([string])] + [CmdletBinding()] + param( + [Parameter( + Mandatory, + ValueFromPipeline + )] + [object] $InputObject, + + [Parameter()] + [switch] $AsURLEncoded + ) + + if ($InputObject -isnot [hashtable]) { + $InputObject = $InputObject | ConvertTo-HashTable + } + + $parameters = if ($AsURLEncoded) { + ($InputObject.GetEnumerator() | ForEach-Object { "$([System.Web.HttpUtility]::UrlEncode($_.Key))=$([System.Web.HttpUtility]::UrlEncode($_.Value))" }) -join '&' + } else { + ($InputObject.GetEnumerator() | ForEach-Object { "$([System.Uri]::EscapeDataString($_.Key))=$([System.Uri]::EscapeDataString($_.Value))" }) -join '&' + } + + if ($parameters) { + '?' + $parameters + } +} diff --git a/src/GitHub/public/API/Invoke-GitHubAPI.ps1 b/src/GitHub/public/API/Invoke-GitHubAPI.ps1 index c8ab7a099..6945c056e 100644 --- a/src/GitHub/public/API/Invoke-GitHubAPI.ps1 +++ b/src/GitHub/public/API/Invoke-GitHubAPI.ps1 @@ -1,4 +1,4 @@ -function Invoke-GitHubAPI { +filter Invoke-GitHubAPI { <# .SYNOPSIS Calls the GitHub API using the provided parameters. @@ -42,7 +42,7 @@ # The 'Accept' header for the API request. If not provided, the default will be used by GitHub's API. [Parameter()] - [string] $Accept = 'application/vnd.github+json', + [string] $Accept = 'application/vnd.github+json; charset=utf-8', # Specifies the HTTP version used for the request. [Parameter()] @@ -58,11 +58,15 @@ # The 'Content-Type' header for the API request. The default is 'application/vnd.github+json'. [Parameter()] - [string] $ContentType = 'application/vnd.github+json', + [string] $ContentType = 'application/vnd.github+json; charset=utf-8', # The GitHub API version to be used. By default, it pulls from a configuration script variable. [Parameter()] - [string] $Version = (Get-GitHubConfig -Name ApiVersion) + [string] $Version = (Get-GitHubConfig -Name ApiVersion), + + # Declares the state of a resource by passing all parameters/body properties to Invoke-RestMethod, even if empty + [Parameter()] + [switch] $Declare ) $functionName = $MyInvocation.MyCommand.Name @@ -102,22 +106,20 @@ ContentType = $ContentType HttpVersion = $HttpVersion FollowRelLink = $FollowRelLink - StatusCodeVariable = 'StatusCode' - ResponseHeadersVariable = 'ResponseHeaders' + StatusCodeVariable = 'APICallStatusCode' + ResponseHeadersVariable = 'APICallResponseHeaders' } $APICall | Remove-HashTableEntries -NullOrEmptyValues if ($Body) { - $Body | Remove-HashTableEntries -NullOrEmptyValues # Use body to create the query string for GET requests if ($Method -eq 'GET') { - $queryParams = ($Body.GetEnumerator() | - ForEach-Object { "$([System.Web.HttpUtility]::UrlEncode($_.Key))=$([System.Web.HttpUtility]::UrlEncode($_.Value))" }) -join '&' - if ($queryParams) { - $APICall.Uri = $APICall.Uri + '?' + $queryParams - } + $queryString = $Body | ConvertTo-QueryString + $APICall.Uri = $APICall.Uri + $queryString } + + # Use body to create the form data if ($Body -is [string]) { $APICall.Body = $Body } else { @@ -125,14 +127,14 @@ } } - try { - Invoke-RestMethod @APICall | Write-Output - Write-Verbose ($StatusCode | ConvertTo-Json -Depth 100) - Write-Verbose ($responseHeaders | ConvertTo-Json -Depth 100) - } catch { - Write-Error "[$functionName] - Status code - [$StatusCode]" - $err = $_ | ConvertFrom-Json -Depth 10 - Write-Error "[$functionName] - $($err.Message)" - Write-Error "[$functionName] - For more info please see: [$($err.documentation_url)]" + Invoke-RestMethod @APICall | ForEach-Object { + $statusCode = $APICallStatusCode | ConvertTo-Json -Depth 100 | ConvertFrom-Json + $responseHeaders = $APICallResponseHeaders | ConvertTo-Json -Depth 100 | ConvertFrom-Json + [pscustomobject]@{ + Request = $APICall + Response = $_ + StatusCode = $statusCode + ResponseHeaders = $responseHeaders + } } } diff --git a/src/GitHub/public/Actions/Disable-GitHubWorkflow.ps1 b/src/GitHub/public/Actions/Disable-GitHubWorkflow.ps1 index e430c3b64..8ec149a8a 100644 --- a/src/GitHub/public/Actions/Disable-GitHubWorkflow.ps1 +++ b/src/GitHub/public/Actions/Disable-GitHubWorkflow.ps1 @@ -1,7 +1,7 @@ -Function Disable-GitHubWorkflow { +filter Disable-GitHubWorkflow { <# .NOTES - https://docs.github.com/en/rest/reference/actions#disable-a-workflow + https://docs.github.com/rest/reference/actions#disable-a-workflow #> [CmdletBinding()] param ( @@ -18,17 +18,11 @@ [string[]] $ID ) - begin {} - - process { - $inputObject = @{ - APIEndpoint = "/repos/$Owner/$Repo/actions/workflows/$ID/disable" - Method = 'PUT' - } - - Invoke-GitHubAPI @inputObject | Out-Null - + $inputObject = @{ + APIEndpoint = "/repos/$Owner/$Repo/actions/workflows/$ID/disable" + Method = 'PUT' } - end {} + Invoke-GitHubAPI @inputObject | Out-Null + } diff --git a/src/GitHub/public/Actions/Enable-GitHubWorkflow.ps1 b/src/GitHub/public/Actions/Enable-GitHubWorkflow.ps1 index d46c2e569..681139fe7 100644 --- a/src/GitHub/public/Actions/Enable-GitHubWorkflow.ps1 +++ b/src/GitHub/public/Actions/Enable-GitHubWorkflow.ps1 @@ -1,7 +1,7 @@ -Function Enable-GitHubWorkflow { +filter Enable-GitHubWorkflow { <# .NOTES - https://docs.github.com/en/rest/reference/actions#enable-a-workflow + https://docs.github.com/rest/reference/actions#enable-a-workflow #> [CmdletBinding()] param ( @@ -18,17 +18,11 @@ [string[]] $ID ) - begin {} - - process { - $inputObject = @{ - APIEndpoint = "/repos/$Owner/$Repo/actions/workflows/$ID/enable" - Method = 'PUT' - } - - Invoke-GitHubAPI @inputObject | Out-Null - + $inputObject = @{ + APIEndpoint = "/repos/$Owner/$Repo/actions/workflows/$ID/enable" + Method = 'PUT' } - end {} + Invoke-GitHubAPI @inputObject | Out-Null + } diff --git a/src/GitHub/public/Actions/Get-GitHubWorkflow.ps1 b/src/GitHub/public/Actions/Get-GitHubWorkflow.ps1 index d5368fac7..0be3d2b40 100644 --- a/src/GitHub/public/Actions/Get-GitHubWorkflow.ps1 +++ b/src/GitHub/public/Actions/Get-GitHubWorkflow.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubWorkflow { +filter Get-GitHubWorkflow { <# .SYNOPSIS Lists the workflows in a repository. @@ -19,7 +19,7 @@ Gets the 'hello-world.yml' workflow in the 'octocat/hello-world' repository. .NOTES - https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#list-repository-workflows + https://docs.github.com/rest/actions/workflows?apiVersion=2022-11-28#list-repository-workflows #> [CmdletBinding(DefaultParameterSetName = 'ByName')] param ( @@ -36,24 +36,20 @@ [string] $ID, [Parameter()] - [int] $PerPage = 100 + [int] $PerPage = 30 ) - begin {} - process { - - $body = @{ - per_page = $PerPage - } + $body = @{ + per_page = $PerPage + } - $inputObject = @{ - APIEndpoint = "/repos/$Owner/$Repo/actions/workflows" - Method = 'GET' - Body = $body - } + $inputObject = @{ + APIEndpoint = "/repos/$Owner/$Repo/actions/workflows" + Method = 'GET' + Body = $body + } - Invoke-GitHubAPI @inputObject | Select-Object -ExpandProperty workflows | Write-Output + (Invoke-GitHubAPI @inputObject).Response.workflows - } } diff --git a/src/GitHub/public/Actions/Get-GitHubWorkflowRun.ps1 b/src/GitHub/public/Actions/Get-GitHubWorkflowRun.ps1 index 15206b51c..eaecf3997 100644 --- a/src/GitHub/public/Actions/Get-GitHubWorkflowRun.ps1 +++ b/src/GitHub/public/Actions/Get-GitHubWorkflowRun.ps1 @@ -1,8 +1,8 @@ -Function Get-GitHubWorkflowRun { +filter Get-GitHubWorkflowRun { <# .NOTES - https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-workflow - https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-repository + https://docs.github.com/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-workflow + https://docs.github.com/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-repository #> [CmdletBinding(DefaultParameterSetName = 'Repo')] param ( @@ -19,37 +19,29 @@ [string] $ID, [Parameter()] - [int] $PerPage = 100 + [int] $PerPage = 30 ) - begin {} - - process { - - $body = @{ - per_page = $PerPage - } - - if ($Name) { - $ID = (Get-GitHubWorkflow -Owner $Owner -Repo $Repo -Name $Name).id - } - - if ($ID) { - $Uri = "/repos/$Owner/$Repo/actions/workflows/$ID/runs" - } else { - $Uri = "/repos/$Owner/$Repo/actions/runs" - } + $body = @{ + per_page = $PerPage + } - $inputObject = @{ - APIEndpoint = $Uri - Method = 'GET' - Body = $body - } + if ($Name) { + $ID = (Get-GitHubWorkflow -Owner $Owner -Repo $Repo -Name $Name).id + } - Invoke-GitHubAPI @inputObject | Select-Object -ExpandProperty workflow_runs | Write-Output + if ($ID) { + $Uri = "/repos/$Owner/$Repo/actions/workflows/$ID/runs" + } else { + $Uri = "/repos/$Owner/$Repo/actions/runs" + } + $inputObject = @{ + APIEndpoint = $Uri + Method = 'GET' + Body = $body } - end {} + (Invoke-GitHubAPI @inputObject).Response.workflow_runs } diff --git a/src/GitHub/public/Actions/Get-GitHubWorkflowUsage.ps1 b/src/GitHub/public/Actions/Get-GitHubWorkflowUsage.ps1 index 4ca08c6ec..2d541c094 100644 --- a/src/GitHub/public/Actions/Get-GitHubWorkflowUsage.ps1 +++ b/src/GitHub/public/Actions/Get-GitHubWorkflowUsage.ps1 @@ -1,4 +1,4 @@ -Function Get-GitHubWorkflowUsage { +filter Get-GitHubWorkflowUsage { <# .SYNOPSIS Short description @@ -19,7 +19,7 @@ An example .NOTES - https://docs.github.com/en/rest/reference/actions#get-workflow-usage + https://docs.github.com/rest/reference/actions#get-workflow-usage #> [CmdletBinding( DefaultParameterSetName = 'ByName' @@ -38,18 +38,11 @@ [string[]] $ID ) - begin {} - - process { - - $inputObject = @{ - Method = 'GET' - APIEndpoint = "/repos/$Owner/$Repo/actions/workflows/$ID/timing" - } - - Invoke-GitHubAPI @inputObject | Select-Object -ExpandProperty billable | Write-Output - + $inputObject = @{ + Method = 'GET' + APIEndpoint = "/repos/$Owner/$Repo/actions/workflows/$ID/timing" } - end {} + (Invoke-GitHubAPI @inputObject).Response.billable + } diff --git a/src/GitHub/public/Actions/Remove-GitHubWorkflowRun.ps1 b/src/GitHub/public/Actions/Remove-GitHubWorkflowRun.ps1 index 6e1438563..88fd9d921 100644 --- a/src/GitHub/public/Actions/Remove-GitHubWorkflowRun.ps1 +++ b/src/GitHub/public/Actions/Remove-GitHubWorkflowRun.ps1 @@ -1,4 +1,4 @@ -function Remove-GitHubWorkflowRun { +filter Remove-GitHubWorkflowRun { [CmdletBinding()] param ( [Parameter()] @@ -14,18 +14,11 @@ [string] $ID ) - begin {} - - process { - - $inputObject = @{ - APIEndpoint = "repos/$Owner/$Repo/actions/runs/$ID" - Method = 'DELETE' - } - - Invoke-GitHubAPI @inputObject - + $inputObject = @{ + APIEndpoint = "repos/$Owner/$Repo/actions/runs/$ID" + Method = 'DELETE' } - end {} + (Invoke-GitHubAPI @inputObject).Response + } diff --git a/src/GitHub/public/Actions/Start-GitHubWorkflow.ps1 b/src/GitHub/public/Actions/Start-GitHubWorkflow.ps1 index 1d1ae9a6b..1dc3a42a8 100644 --- a/src/GitHub/public/Actions/Start-GitHubWorkflow.ps1 +++ b/src/GitHub/public/Actions/Start-GitHubWorkflow.ps1 @@ -1,4 +1,4 @@ -function Start-GitHubWorkflow { +filter Start-GitHubWorkflow { <# .SYNOPSIS Start a workflow run using the workflow's ID. @@ -16,7 +16,7 @@ .NOTES # API Reference - # https://docs.github.com/en/free-pro-team@latest/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event + # https://docs.github.com/free-pro-team@latest/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event #> [CmdletBinding()] param ( @@ -43,24 +43,17 @@ [hashtable] $Inputs = @{} ) - begin {} - - process { - - $body = @{ - ref = $Ref - inputs = $Inputs - } - - $inputObject = @{ - APIEndpoint = "/repos/$Owner/$Repo/actions/workflows/$ID/dispatches" - Method = 'POST' - Body = $body - } - - Invoke-GitHubAPI @inputObject + $body = @{ + ref = $Ref + inputs = $Inputs + } + $inputObject = @{ + APIEndpoint = "/repos/$Owner/$Repo/actions/workflows/$ID/dispatches" + Method = 'POST' + Body = $body } - end {} + (Invoke-GitHubAPI @inputObject).Response + } diff --git a/src/GitHub/public/Actions/Start-GitHubWorkflowReRun.ps1 b/src/GitHub/public/Actions/Start-GitHubWorkflowReRun.ps1 index 3c9ddd66a..3d4ae80b6 100644 --- a/src/GitHub/public/Actions/Start-GitHubWorkflowReRun.ps1 +++ b/src/GitHub/public/Actions/Start-GitHubWorkflowReRun.ps1 @@ -1,4 +1,4 @@ -function Start-GitHubWorkflowReRun { +filter Start-GitHubWorkflowReRun { <# .SYNOPSIS Short description @@ -19,7 +19,7 @@ An example .NOTES - https://docs.github.com/en/rest/reference/actions#re-run-a-workflow + https://docs.github.com/rest/reference/actions#re-run-a-workflow #> [CmdletBinding()] param ( @@ -37,18 +37,11 @@ [string] $ID ) - begin {} - - process { - - $inputObject = @{ - Method = 'POST' - APIEndpoint = "/repos/$Owner/$Repo/actions/runs/$ID/rerun" - } - - Invoke-GitHubAPI @inputObject - + $inputObject = @{ + Method = 'POST' + APIEndpoint = "/repos/$Owner/$Repo/actions/runs/$ID/rerun" } - end {} + (Invoke-GitHubAPI @inputObject).Response + } diff --git a/src/GitHub/public/Actions/Stop-GitHubWorkflowRun.ps1 b/src/GitHub/public/Actions/Stop-GitHubWorkflowRun.ps1 index 4821d0737..7b8eb8ecf 100644 --- a/src/GitHub/public/Actions/Stop-GitHubWorkflowRun.ps1 +++ b/src/GitHub/public/Actions/Stop-GitHubWorkflowRun.ps1 @@ -1,4 +1,4 @@ -function Stop-GitHubWorkflowRun { +filter Stop-GitHubWorkflowRun { <# .SYNOPSIS Short description @@ -19,7 +19,7 @@ An example .NOTES - https://docs.github.com/en/rest/reference/actions#cancel-a-workflow-run + https://docs.github.com/rest/reference/actions#cancel-a-workflow-run #> [CmdletBinding()] [alias('Cancel-GitHubWorkflowRun')] @@ -38,18 +38,12 @@ [string] $ID ) - begin {} - - process { - - $inputObject = @{ - Method = 'POST' - APIEndpoint = "/repos/$Owner/$Repo/actions/runs/$ID/cancel" - } - - Invoke-GitHubAPI @inputObject + $inputObject = @{ + Method = 'POST' + APIEndpoint = "/repos/$Owner/$Repo/actions/runs/$ID/cancel" } - end {} + (Invoke-GitHubAPI @inputObject).Response + } diff --git a/src/GitHub/public/Auth/Connect-GitHubAccount.ps1 b/src/GitHub/public/Auth/Connect-GitHubAccount.ps1 index 4b57c307d..a9f8f77ba 100644 --- a/src/GitHub/public/Auth/Connect-GitHubAccount.ps1 +++ b/src/GitHub/public/Auth/Connect-GitHubAccount.ps1 @@ -31,7 +31,7 @@ Connects to GitHub using a device flow login and sets the scope of the access token. .NOTES - https://docs.github.com/en/rest/overview/other-authentication-methods#authenticating-for-saml-sso + https://docs.github.com/rest/overview/other-authentication-methods#authenticating-for-saml-sso #> [Alias('Connect-GHAccount')] [Alias('Connect-GitHub')] @@ -45,7 +45,7 @@ param ( # Choose between authentication methods, either OAuthApp or GitHubApp. # For more info about the types of authentication visit: - # https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/differences-between-github-apps-and-oauth-apps + # https://docs.github.com/apps/oauth-apps/building-oauth-apps/differences-between-github-apps-and-oauth-apps [Parameter(ParameterSetName = 'DeviceFlow')] [ValidateSet('OAuthApp', 'GitHubApp')] [string] $Mode = 'GitHubApp', @@ -53,7 +53,7 @@ # The scope of the access token, when using OAuth authentication. # Provide the list of scopes as space-separated values. # For more information on scopes visit: - # https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps + # https://docs.github.com/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps [Parameter(ParameterSetName = 'DeviceFlow')] [string] $Scope = 'gist read:org repo workflow', @@ -87,9 +87,12 @@ } else { $accessTokenValidity = [datetime](Get-GitHubConfig -Name 'AccessTokenExpirationDate') - (Get-Date) $accessTokenIsValid = $accessTokenValidity.Seconds -gt 0 - $accessTokenValidityText = "$($accessTokenValidity.Hours):$($accessTokenValidity.Minutes):$($accessTokenValidity.Seconds)" + $hours = $accessTokenValidity.Hours.ToString().PadLeft(2, '0') + $minutes = $accessTokenValidity.Minutes.ToString().PadLeft(2, '0') + $seconds = $accessTokenValidity.Seconds.ToString().PadLeft(2, '0') + $accessTokenValidityText = "$hours`:$minutes`:$seconds" if ($accessTokenIsValid) { - if ($accessTokenValidity -gt 4) { + if ($accessTokenValidity.TotalHours -gt 4) { Write-Host '✓ ' -ForegroundColor Green -NoNewline Write-Host "Access token is still valid for $accessTokenValidityText ..." return diff --git a/src/GitHub/public/Branches/Get-GitHubRepoBranch.ps1 b/src/GitHub/public/Branches/Get-GitHubRepoBranch.ps1 index a8691d6af..7150c6dad 100644 --- a/src/GitHub/public/Branches/Get-GitHubRepoBranch.ps1 +++ b/src/GitHub/public/Branches/Get-GitHubRepoBranch.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubRepoBranch { +filter Get-GitHubRepoBranch { [CmdletBinding()] param ( [Parameter()] @@ -13,6 +13,6 @@ Method = 'GET' } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/public/Config/Get-GitHubConfig.ps1 b/src/GitHub/public/Config/Get-GitHubConfig.ps1 index a279f7989..a0bf05ab7 100644 --- a/src/GitHub/public/Config/Get-GitHubConfig.ps1 +++ b/src/GitHub/public/Config/Get-GitHubConfig.ps1 @@ -40,7 +40,7 @@ $RefreshTokenData = (Get-SecretInfo -Name "$prefix`RefreshToken").Metadata | ConvertFrom-HashTable | ConvertTo-HashTable $AccessTokenData = (Get-SecretInfo -Name "$prefix`AccessToken").Metadata | ConvertFrom-HashTable | ConvertTo-HashTable - $metadata = Join-Hashtable -Main $RefreshTokenData -Overrides $AccessTokenData + $metadata = Join-Object -Main $RefreshTokenData -Overrides $AccessTokenData -AsHashtable switch($Name) { 'AccessToken' { @@ -54,6 +54,7 @@ $metadata.$Name } else { $metadata + # TODO: Fix sorting } } } diff --git a/src/GitHub/public/Config/Set-GitHubConfig.ps1 b/src/GitHub/public/Config/Set-GitHubConfig.ps1 index ab215ef15..4f23a7b7a 100644 --- a/src/GitHub/public/Config/Set-GitHubConfig.ps1 +++ b/src/GitHub/public/Config/Set-GitHubConfig.ps1 @@ -89,7 +89,7 @@ $secretInfo = Get-SecretInfo @secretGetInfoParam Write-Verbose "$secretName - secretInfo : $($secretInfo | Out-String)" $secretMetadata = $secretInfo.Metadata | ConvertFrom-HashTable | ConvertTo-HashTable - $newSecretMetadata = Join-Hashtable -Main $newSecretMetadata -Overrides $secretMetadata + $newSecretMetadata = Join-Object -Main $newSecretMetadata -Overrides $secretMetadata -AsHashtable } # Get metadata updates from parameters and clean up unwanted data @@ -99,7 +99,7 @@ Remove-HashTableEntries -Hashtable $updateSecretMetadata -KeepTypes $keepTypes -RemoveNames $removeKeys Write-Verbose "updateSecretMetadata : $($updateSecretMetadata | Out-String)" - $newSecretMetadata = Join-HashTable -Main $newSecretMetadata -Overrides $updateSecretMetadata + $newSecretMetadata = Join-Object -Main $newSecretMetadata -Overrides $updateSecretMetadata -AsHashtable Write-Verbose "newSecretMetadata : $($newSecretMetadata | Out-String)" Write-Verbose "newSecretMetadataType : $($newSecretMetadata.GetType())" @@ -136,7 +136,7 @@ $secretInfo = Get-SecretInfo @secretGetInfoParam Write-Verbose "$secretName - secretInfo : $($secretInfo | Out-String)" $secretMetadata = $secretInfo.Metadata | ConvertFrom-HashTable | ConvertTo-HashTable - $newSecretMetadata = Join-Hashtable -Main $newSecretMetadata -Overrides $secretMetadata + $newSecretMetadata = Join-Object -Main $newSecretMetadata -Overrides $secretMetadata -AsHashtable } # Get metadata updates from parameters and clean up unwanted data @@ -146,7 +146,7 @@ Remove-HashTableEntries -Hashtable $updateSecretMetadata -KeepTypes $keepTypes -RemoveNames $removeKeys Write-Verbose "updateSecretMetadata : $($updateSecretMetadata | Out-String)" - $newSecretMetadata = Join-HashTable -Main $newSecretMetadata -Overrides $updateSecretMetadata + $newSecretMetadata = Join-Object -Main $newSecretMetadata -Overrides $updateSecretMetadata -AsHashtable Write-Verbose "newSecretMetadata : $($newSecretMetadata | Out-String)" Write-Verbose "newSecretMetadataType : $($newSecretMetadata.GetType())" diff --git a/src/GitHub/public/Deployments/Get-GitHubEnvironment.ps1 b/src/GitHub/public/Deployments/Get-GitHubEnvironment.ps1 index 15a39c62e..0cb07872f 100644 --- a/src/GitHub/public/Deployments/Get-GitHubEnvironment.ps1 +++ b/src/GitHub/public/Deployments/Get-GitHubEnvironment.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubEnvironment { +filter Get-GitHubEnvironment { <# .SYNOPSIS Get GitHub environment @@ -16,7 +16,7 @@ An example .NOTES - https://docs.github.com/en/rest/reference/repos#get-all-environments + https://docs.github.com/rest/reference/repos#get-all-environments #> [CmdletBinding()] param ( @@ -27,18 +27,11 @@ [string] $Repo = (Get-GitHubConfig -Name Repo) ) - begin {} - - process { - - $inputObject = @{ - APIEndpoint = "/repos/$Owner/$Repo/environments" - Method = 'GET' - } - - Invoke-GitHubAPI @inputObject - + $inputObject = @{ + APIEndpoint = "/repos/$Owner/$Repo/environments" + Method = 'GET' } - end {} + (Invoke-GitHubAPI @inputObject).Response + } diff --git a/src/GitHub/public/Deployments/Get-GitHubEnvironmentSecrets.ps1 b/src/GitHub/public/Deployments/Get-GitHubEnvironmentSecrets.ps1 index 602e2d922..643eb7167 100644 --- a/src/GitHub/public/Deployments/Get-GitHubEnvironmentSecrets.ps1 +++ b/src/GitHub/public/Deployments/Get-GitHubEnvironmentSecrets.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubEnvironmentSecrets { +filter Get-GitHubEnvironmentSecrets { <# .SYNOPSIS Get GitHub environment secrets @@ -19,7 +19,7 @@ An example .NOTES - https://docs.github.com/en/rest/reference/repos#get-all-environments + https://docs.github.com/rest/reference/repos#get-all-environments #> [CmdletBinding()] param ( @@ -29,26 +29,21 @@ [Parameter()] [string] $Repo = (Get-GitHubConfig -Name Repo), - [Alias('name')] [Parameter( Mandatory, ValueFromPipelineByPropertyName )] + [Alias('name')] [string] $EnvironmentName ) - begin {} - - process { - $RepoID = (Get-GitHubRepo).id + $RepoID = (Get-GitHubRepo).id - $inputObject = @{ - APIEndpoint = "/repositories/$RepoID/environments/$EnvironmentName/secrets" - Method = 'GET' - } - - Invoke-GitHubAPI @inputObject + $inputObject = @{ + APIEndpoint = "/repositories/$RepoID/environments/$EnvironmentName/secrets" + Method = 'GET' } - end {} + (Invoke-GitHubAPI @inputObject).Response + } diff --git a/src/GitHub/public/Deployments/Update-GitHubEnvironment.ps1 b/src/GitHub/public/Deployments/Update-GitHubEnvironment.ps1 index 25da09436..c03cc78f2 100644 --- a/src/GitHub/public/Deployments/Update-GitHubEnvironment.ps1 +++ b/src/GitHub/public/Deployments/Update-GitHubEnvironment.ps1 @@ -1,7 +1,7 @@ -function Update-GitHubEnvironment { +filter Update-GitHubEnvironment { <# .NOTES - https://docs.github.com/en/rest/reference/repos#create-or-update-an-environment + https://docs.github.com/rest/reference/repos#create-or-update-an-environment #> [CmdletBinding()] param ( @@ -19,24 +19,18 @@ [string] $Name ) - begin {} - - process { - $body = @{ - owner = $Owner - repo = $Repo - environment_name = $Name - } - - $inputObject = @{ - APIEndpoint = "/repos/$Owner/$Repo/environments/$Name" - Method = 'PUT' - Body = $body - } - - Invoke-GitHubAPI @inputObject + $body = @{ + owner = $Owner + repo = $Repo + environment_name = $Name + } + $inputObject = @{ + APIEndpoint = "/repos/$Owner/$Repo/environments/$Name" + Method = 'PUT' + Body = $body } - end {} + (Invoke-GitHubAPI @inputObject).Response + } diff --git a/src/GitHub/public/Emojis/Get-GitHubEmojis.ps1 b/src/GitHub/public/Emojis/Get-GitHubEmojis.ps1 index b90763bc8..5342ae458 100644 --- a/src/GitHub/public/Emojis/Get-GitHubEmojis.ps1 +++ b/src/GitHub/public/Emojis/Get-GitHubEmojis.ps1 @@ -1,7 +1,7 @@ -function Get-GitHubEmojis { +filter Get-GitHubEmojis { <# .NOTES - https://docs.github.com/en/rest/reference/emojis#get-emojis + https://docs.github.com/rest/reference/emojis#get-emojis #> [CmdletBinding()] param ( @@ -14,10 +14,10 @@ Method = 'GET' } - $response = Invoke-GitHubAPI @inputObject + $response = (Invoke-GitHubAPI @inputObject).Response if (Test-Path -Path $Destination) { - $response.PSobject.Properties | ForEach-Object -Parallel { + $response.PSObject.Properties | ForEach-Object -Parallel { Invoke-WebRequest -Uri $_.Value -OutFile "$using:Destination/$($_.Name).png" } } else { diff --git a/src/GitHub/public/Markdown/Get-GitHubMarkdown.ps1 b/src/GitHub/public/Markdown/Get-GitHubMarkdown.ps1 index ebcb6ed92..8070f9131 100644 --- a/src/GitHub/public/Markdown/Get-GitHubMarkdown.ps1 +++ b/src/GitHub/public/Markdown/Get-GitHubMarkdown.ps1 @@ -1,11 +1,15 @@ -function Get-GitHubMarkdown { +filter Get-GitHubMarkdown { <# .NOTES - https://docs.github.com/en/rest/reference/meta#github-api-root + https://docs.github.com/rest/reference/meta#github-api-root #> [CmdletBinding()] param ( - [Parameter()] + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName + )] [switch] $Text, [Parameter()] @@ -28,6 +32,6 @@ Body = $body } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/public/Markdown/Get-GitHubMarkdownRaw.ps1 b/src/GitHub/public/Markdown/Get-GitHubMarkdownRaw.ps1 index 4316e10a3..053764516 100644 --- a/src/GitHub/public/Markdown/Get-GitHubMarkdownRaw.ps1 +++ b/src/GitHub/public/Markdown/Get-GitHubMarkdownRaw.ps1 @@ -1,12 +1,12 @@ -function Get-GitHubMarkdownRaw { +filter Get-GitHubMarkdownRaw { <# .NOTES - https://docs.github.com/en/rest/reference/meta#github-api-root + https://docs.github.com/rest/reference/meta#github-api-root #> [CmdletBinding()] param ( [Parameter()] - [switch] $Text + [string] $Text ) $inputObject = @{ @@ -16,6 +16,6 @@ Method = 'POST' } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/public/Meta/Get-GitHubApiVersions.ps1 b/src/GitHub/public/Meta/Get-GitHubApiVersions.ps1 index cbb1bc3b6..20172b44e 100644 --- a/src/GitHub/public/Meta/Get-GitHubApiVersions.ps1 +++ b/src/GitHub/public/Meta/Get-GitHubApiVersions.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubApiVersions { +filter Get-GitHubApiVersions { <# .SYNOPSIS Get all API versions. @@ -23,6 +23,6 @@ Method = 'GET' } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/public/Meta/Get-GitHubMeta.ps1 b/src/GitHub/public/Meta/Get-GitHubMeta.ps1 index ccc4c9cbf..0dd7b568e 100644 --- a/src/GitHub/public/Meta/Get-GitHubMeta.ps1 +++ b/src/GitHub/public/Meta/Get-GitHubMeta.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubMeta { +filter Get-GitHubMeta { <# .SYNOPSIS Get GitHub meta information. @@ -29,6 +29,6 @@ Method = 'GET' } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/public/Meta/Get-GitHubOctocat.ps1 b/src/GitHub/public/Meta/Get-GitHubOctocat.ps1 index 96ce2fa89..49f2fd89c 100644 --- a/src/GitHub/public/Meta/Get-GitHubOctocat.ps1 +++ b/src/GitHub/public/Meta/Get-GitHubOctocat.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubOctocat { +filter Get-GitHubOctocat { <# .SYNOPSIS Get Octocat. @@ -12,7 +12,7 @@ Get the octocat as ASCII art .EXAMPLE - Get-GitHubOctocat -S 'The glass is never half empty. It's just twice as big as it needs to be.' + Get-GitHubOctocat -S "Hello world" Get the octocat as ASCII art with a custom saying @@ -26,8 +26,7 @@ [Parameter()] [Alias('Say')] [Alias('Saying')] - [string] - $S + [string] $S ) $body = @{ @@ -40,6 +39,6 @@ Body = $body } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/public/Meta/Get-GitHubRoot.ps1 b/src/GitHub/public/Meta/Get-GitHubRoot.ps1 index c4a52e16a..5637d66ee 100644 --- a/src/GitHub/public/Meta/Get-GitHubRoot.ps1 +++ b/src/GitHub/public/Meta/Get-GitHubRoot.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubRoot { +filter Get-GitHubRoot { <# .SYNOPSIS GitHub API Root. @@ -22,6 +22,6 @@ Method = 'GET' } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/public/Meta/Get-GitHubZen.ps1 b/src/GitHub/public/Meta/Get-GitHubZen.ps1 index 8ddf4a7e7..b4609085b 100644 --- a/src/GitHub/public/Meta/Get-GitHubZen.ps1 +++ b/src/GitHub/public/Meta/Get-GitHubZen.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubZen { +filter Get-GitHubZen { <# .SYNOPSIS Get the Zen of GitHub. @@ -22,6 +22,6 @@ Method = 'GET' } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/public/Organization/Blocking/Assert-GitHubOrganizationBlockedUser.ps1 b/src/GitHub/public/Organization/Blocking/Assert-GitHubOrganizationBlockedUser.ps1 new file mode 100644 index 000000000..67219e3e8 --- /dev/null +++ b/src/GitHub/public/Organization/Blocking/Assert-GitHubOrganizationBlockedUser.ps1 @@ -0,0 +1,55 @@ +filter Assert-GitHubOrganizationBlockedUser { + <# + .SYNOPSIS + Check if a user is blocked by an organization + + .DESCRIPTION + Returns a 204 if the given user is blocked by the given organization. Returns a 404 if the organization is not blocking the user, or if the user account has been identified as spam by GitHub. + + .EXAMPLE + Get-GitHubOrganizationBlockedUser -OrganizationName 'github' + + Lists all users blocked by the organization `github`. + + .NOTES + https://docs.github.com/rest/orgs/blocking#check-if-a-user-is-blocked-by-an-organization + #> + [OutputType([pscustomobject])] + [Alias('Is-GitHubOrganizationBlockedUser')] + [Alias('Check-GitHubOrganizationBlockedUser')] + [CmdletBinding()] + param ( + # The organization name. The name is not case sensitive. + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName + )] + [Alias('org')] + [Alias('owner')] + [Alias('login')] + [string] $OrganizationName, + + # The handle for the GitHub user account. + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName + )] + [string] $Username + ) + + $inputObject = @{ + APIEndpoint = "/orgs/$OrganizationName/blocks/$Username" + Method = 'GET' + } + + $statusCode = (Invoke-GitHubAPI @inputObject -ErrorAction SilentlyContinue).StatusCode + + if ($statusCode -eq 204) { + return $true + } elseif ($statusCode -eq 404) { + return $false + } else { + throw "Unexpected status code: $statusCode" + } +} diff --git a/src/GitHub/public/Organization/Blocking/Get-GitHubOrganizationBlockedUser.ps1 b/src/GitHub/public/Organization/Blocking/Get-GitHubOrganizationBlockedUser.ps1 new file mode 100644 index 000000000..587152403 --- /dev/null +++ b/src/GitHub/public/Organization/Blocking/Get-GitHubOrganizationBlockedUser.ps1 @@ -0,0 +1,44 @@ +filter Get-GitHubOrganizationBlockedUser { + <# + .SYNOPSIS + List users blocked by an organization + + .DESCRIPTION + List the users blocked by an organization. + + .EXAMPLE + Get-GitHubOrganizationBlockedUser -OrganizationName 'github' + + Lists all users blocked by the organization `github`. + + .NOTES + https://docs.github.com/rest/orgs/blocking#list-users-blocked-by-an-organization + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The organization name. The name is not case sensitive. + [Parameter(Mandatory)] + [Alias('org')] + [Alias('owner')] + [Alias('login')] + [string] $OrganizationName, + + # The number of results per page (max 100). + [Parameter()] + [int] $PerPage = 30 + ) + + $body = @{ + per_page = $PerPage + } + + $inputObject = @{ + APIEndpoint = "/orgs/$OrganizationName/blocks" + Method = 'GET' + Body = $body + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/public/Organization/Get-GitHubOrganization.ps1 b/src/GitHub/public/Organization/Get-GitHubOrganization.ps1 new file mode 100644 index 000000000..054242e3e --- /dev/null +++ b/src/GitHub/public/Organization/Get-GitHubOrganization.ps1 @@ -0,0 +1,89 @@ +filter Get-GitHubOrganization { + <# + .SYNOPSIS + List organization + + .DESCRIPTION + List organizations for the authenticated user - if no parameters are provided. + List organizations for a user - if a username is provided. + Lists all organizations, in the order that they were created on GitHub - if '-All' is provided. + Get an organization - if a organization name is provided. + + .EXAMPLE + Get-GitHubOrganization + + List organizations for the authenticated user. + + .EXAMPLE + Get-GitHubOrganization -Username 'octocat' + + List public organizations for the user 'octocat'. + + .EXAMPLE + Get-GitHubOrganization -All -Since 142951047 + + List organizations, starting with PSModule. + + .EXAMPLE + Get-GitHubOrganization -Name 'PSModule' + + Get the organization 'PSModule'. + + .NOTES + https://docs.github.com/rest/orgs/orgs + #> + [OutputType([pscustomobject])] + [CmdletBinding(DefaultParameterSetName = '__DefaultSet')] + param ( + # The organization name. The name is not case sensitive. + [Parameter( + Mandatory, + ParameterSetName = 'NamedOrg', + ValueFromPipelineByPropertyName + )] + [Alias('login')] + [Alias('org')] + [Alias('owner')] + [string] $OrganizationName, + + # The handle for the GitHub user account. + [Parameter( + Mandatory, + ParameterSetName = 'NamedUser', + ValueFromPipelineByPropertyName + )] + [string] $Username, + + # List all organizations. Use '-Since' to start at a specific organization id. + [Parameter( + Mandatory, + ParameterSetName = 'AllOrg' + )] + [switch] $All, + + # A organization ID. Only return organizations with an ID greater than this ID. + [Parameter(ParameterSetName = 'AllOrg')] + [int] $Since = 0, + + # The number of results per page (max 100). + [Parameter(ParameterSetName = 'AllOrg')] + [Parameter(ParameterSetName = 'UserOrg')] + [Parameter(ParameterSetName = '__DefaultSet')] + [int] $PerPage = 30 + ) + + switch ($PSCmdlet.ParameterSetName) { + '__DefaultSet' { + Get-GitHubMyOrganization -PerPage $PerPage | Get-GitHubOrganizationByName + } + 'NamedOrg' { + Get-GitHubOrganizationByName -OrganizationName $OrganizationName + } + 'NamedUser' { + Get-GitHubUserOrganization -Username $Username + } + 'AllOrg' { + Get-GitHubAllOrganization -Since $Since -PerPage $PerPage + } + } +} diff --git a/src/GitHub/public/Organization/Get-GitHubOrganizationAppInstallation.ps1 b/src/GitHub/public/Organization/Get-GitHubOrganizationAppInstallation.ps1 new file mode 100644 index 000000000..48557d266 --- /dev/null +++ b/src/GitHub/public/Organization/Get-GitHubOrganizationAppInstallation.ps1 @@ -0,0 +1,49 @@ +filter Get-GitHubOrganizationAppInstallation { + <# + .SYNOPSIS + List app installations for an organization + + .DESCRIPTION + Lists all GitHub Apps in an organization. The installation count includes all GitHub Apps installed on repositories in the organization. You must be an organization owner with `admin:read` scope to use this endpoint. + + .EXAMPLE + Get-GitHubOrganizationAppInstallation -OrganizationName 'github' + + Gets all GitHub Apps in the organization `github`. + + .NOTES + https://docs.github.com/rest/orgs/orgs#list-app-installations-for-an-organization + + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The organization name. The name is not case sensitive. + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName + )] + [Alias('org')] + [Alias('owner')] + [Alias('login')] + [string] $OrganizationName, + + # The number of results per page (max 100). + [Parameter()] + [int] $PerPage = 30 + ) + + $body = @{ + per_page = $PerPage + } + + $inputObject = @{ + APIEndpoint = "/orgs/$OrganizationName/installations" + Method = 'GET' + Body = $body + } + + (Invoke-GitHubAPI @inputObject).Response.installations + +} diff --git a/src/GitHub/public/Organization/Remove-GitHubOrganization.ps1 b/src/GitHub/public/Organization/Remove-GitHubOrganization.ps1 new file mode 100644 index 000000000..7789ba0d6 --- /dev/null +++ b/src/GitHub/public/Organization/Remove-GitHubOrganization.ps1 @@ -0,0 +1,42 @@ +filter Remove-GitHubOrganization { + <# + .SYNOPSIS + Delete an organization + + .DESCRIPTION + Deletes an organization and all its repositories. + The organization login will be unavailable for 90 days after deletion. + Please review the Terms of Service regarding account deletion before using this endpoint: + https://docs.github.com/site-policy/github-terms/github-terms-of-service + + .EXAMPLE + Remove-GitHubOrganization -OrganizationName 'github' + + Deletes the organization 'github' and all its repositories. + + .NOTES + https://docs.github.com/rest/orgs/orgs#delete-an-organization + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The organization name. The name is not case sensitive. + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName + )] + [Alias('org')] + [Alias('owner')] + [Alias('login')] + [string] $OrganizationName + ) + + $inputObject = @{ + APIEndpoint = "/orgs/$OrganizationName" + Method = 'DELETE' + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/public/Organization/Set-GitHubOrganization.ps1 b/src/GitHub/public/Organization/Set-GitHubOrganization.ps1 new file mode 100644 index 000000000..4f0e3e6b9 --- /dev/null +++ b/src/GitHub/public/Organization/Set-GitHubOrganization.ps1 @@ -0,0 +1,210 @@ +filter Set-GitHubOrganization { + <# + .SYNOPSIS + Update an organization + + .DESCRIPTION + **Parameter Deprecation Notice:** GitHub will replace and discontinue `members_allowed_repository_creation_type` in favor of more granular permissions. The new input parameters are `members_can_create_public_repositories`, `members_can_create_private_repositories` for all organizations and `members_can_create_internal_repositories` for organizations associated with an enterprise account using GitHub Enterprise Cloud or GitHub Enterprise Server 2.20+. For more information, see the [blog post](https://developer.github.com/changes/2019-12-03-internal-visibility-changes). + + Enables an authenticated organization owner with the `admin:org` scope or the `repo` scope to update the organization's profile and member privileges. + + .EXAMPLE + Set-GitHubOrganization -OrganizationName 'github' -Blog 'https://github.blog' + + Sets the blog URL for the organization 'github' to 'https://github.blog'. + + .EXAMPLE + $param = @{ + OrganizationName = 'github' + MembersCanCreatePublicRepositories = $true + MembersCanCreatePrivateRepositories = $true + MembersCanCreateInternalRepositories = $true + } + Set-GitHubOrganization @param + + Sets the repository creation permissions for the organization 'github' to allow all members to create public, private, and internal repositories. + + .NOTES + https://docs.github.com/rest/orgs/orgs#update-an-organization + + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The organization name. The name is not case sensitive. + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName + )] + [Alias('org')] + [Alias('owner')] + [Alias('login')] + [string] $OrganizationName, + + # Billing email address. This address is not publicized. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('billing_email')] + [string] $BillingEmail, + + # The company name. + [Parameter(ValueFromPipelineByPropertyName)] + [string] $Company, + + # The publicly visible email address. + [Parameter(ValueFromPipelineByPropertyName)] + [string] $Email, + + # The Twitter username of the company. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('twitter_username')] + [string] $TwitterUsername, + + # The location. + [Parameter(ValueFromPipelineByPropertyName)] + [string] $Location, + + # The shorthand name of the company. + [Parameter(ValueFromPipelineByPropertyName)] + [string] $Name, + + # The description of the company. + [Parameter(ValueFromPipelineByPropertyName)] + [string] $Description, + + # Whether an organization can use organization projects. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('has_organization_projects')] + [bool] $HasOrganizationProjects, + + # Whether repositories that belong to the organization can use repository projects. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('has_repository_projects')] + [bool] $HasRepositoryProjects, + + # Default permission level members have for organization repositories. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('default_repository_permission')] + [ValidateSet('read', 'write', 'admin', 'none')] + [string] $DefaultRepositoryPermission, + + # Whether of non-admin organization members can create repositories. Note: A parameter can override this parameter. See members_allowed_repository_creation_type in this table for details. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('members_can_create_repositories')] + [bool] $MembersCanCreateRepositories = $true, + + # Whether organization members can create internal repositories, which are visible to all enterprise members. You can only allow members to create internal repositories if your organization is associated with an enterprise account using GitHub Enterprise Cloud or GitHub Enterprise Server 2.20+. For more information, see "Restricting repository creation in your organization" in the GitHub Help documentation. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('members_can_create_internal_repositories')] + [bool] $MembersCanCreateInternalRepositories, + + # Whether organization members can create private repositories, which are visible to organization members with permission. For more information, see "Restricting repository creation in your organization" in the GitHub Help documentation. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('members_can_create_private_repositories')] + [bool] $MembersCanCreatePrivateRepositories, + + # Whether organization members can create public repositories, which are visible to anyone. For more information, see "Restricting repository creation in your organization" in the GitHub Help documentation. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('members_can_create_public_repositories')] + [bool] $MembersCanCreatePublicRepositories, + + # Specifies which types of repositories non-admin organization members can create. private is only available to repositories that are part of an organization on GitHub Enterprise Cloud. Note: This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in members_can_create_repositories. See the parameter deprecation notice in the operation description for details. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('members_allowed_repository_creation_type')] + [ValidateSet('all', 'private', 'none')] + [string] $MembersAllowedRepositoryCreationType, + + # Whether organization members can create GitHub Pages sites. Existing published sites will not be impacted. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('members_can_create_pages')] + [bool] $MembersCanCreatePages = $true, + + # Whether organization members can create public GitHub Pages sites. Existing published sites will not be impacted. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('members_can_create_public_pages')] + [bool] $MembersCanCreatePublicPages = $true, + + # Whether organization members can create private GitHub Pages sites. Existing published sites will not be impacted. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('members_can_create_private_pages')] + [bool] $MembersCanCreatePrivatePages = $true, + + # Whether organization members can fork private organization repositories. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('members_can_fork_private_repositories')] + [bool] $MembersCanForkPrivateRepositories = $false, + + # Whether contributors to organization repositories are required to sign off on commits they make through GitHub's web interface. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('web_commit_signoff_required')] + [bool] $WebCommitSignoffRequired = $false, + + # Path to the organization's blog. + [Parameter(ValueFromPipelineByPropertyName)] + [string] $Blog, + + # Whether GitHub Advanced Security is automatically enabled for new repositories. + # To use this parameter, you must have admin permissions for the repository or be an owner or security manager for the organization that owns the repository. For more information, see "Managing security managers in your organization." + # You can check which security and analysis features are currently enabled by using a GET /orgs/{org} request. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('advanced_security_enabled_for_new_repositories')] + [bool] $AdvancedSecurityEnabledForNewRepositories = $false, + + # Whether Dependabot alerts is automatically enabled for new repositories. + # To use this parameter, you must have admin permissions for the repository or be an owner or security manager for the organization that owns the repository. For more information, see "Managing security managers in your organization." + # You can check which security and analysis features are currently enabled by using a GET /orgs/{org} request. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('dependabot_alerts_enabled_for_new_repositories')] + [bool] $DependabotAlertsEnabledForNewRepositories = $false, + + # Whether Dependabot security updates is automatically enabled for new repositories. + # To use this parameter, you must have admin permissions for the repository or be an owner or security manager for the organization that owns the repository. For more information, see "Managing security managers in your organization." + # You can check which security and analysis features are currently enabled by using a GET /orgs/{org} request. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('dependabot_security_updates_enabled_for_new_repositories')] + [bool] $DependabotSecurityUpdatesEnabledForNewRepositories = $false, + + # Whether dependency graph is automatically enabled for new repositories. + # To use this parameter, you must have admin permissions for the repository or be an owner or security manager for the organization that owns the repository. For more information, see "Managing security managers in your organization." + # You can check which security and analysis features are currently enabled by using a GET /orgs/{org} request. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('dependency_graph_enabled_for_new_repositories')] + [bool] $DependencyGraphEnabledForNewRepositories = $false, + + # Whether secret scanning is automatically enabled for new repositories. + # To use this parameter, you must have admin permissions for the repository or be an owner or security manager for the organization that owns the repository. For more information, see "Managing security managers in your organization." + # You can check which security and analysis features are currently enabled by using a GET /orgs/{org} request. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('secret_scanning_enabled_for_new_repositories')] + [bool] $SecretScanningEnabledForNewRepositories = $false, + + # Whether secret scanning push protection is automatically enabled for new repositories. + # To use this parameter, you must have admin permissions for the repository or be an owner or security manager for the organization that owns the repository. For more information, see "Managing security managers in your organization." + # You can check which security and analysis features are currently enabled by using a GET /orgs/{org} request. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('secret_scanning_push_protection_enabled_for_new_repositories')] + [bool] $SecretScanningPushProtectionEnabledForNewRepositories = $false, + + # Whether a custom link is shown to contributors who are blocked from pushing a secret by push protection. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('secret_scanning_push_protection_custom_link_enabled')] + [bool] $SecretScanningPushProtectionCustomLinkEnabled = $false, + + # If secret_scanning_push_protection_custom_link_enabled is true, the URL that will be displayed to contributors who are blocked from pushing a secret. + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('secret_scanning_push_protection_custom_link')] + [string] $SecretScanningPushProtectionCustomLink + ) + + $body = $PSBoundParameters | ConvertFrom-HashTable | ConvertTo-HashTable -NameCasingStyle snake_case + Remove-HashTableEntries -Hashtable $body -RemoveNames 'organization_name' + + $inputObject = @{ + APIEndpoint = "/orgs/$OrganizationName" + Method = 'PATCH' + Body = $body + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/public/Organization/Set-GitHubOrganizationSecurityFeature.ps1 b/src/GitHub/public/Organization/Set-GitHubOrganizationSecurityFeature.ps1 new file mode 100644 index 000000000..7a7b88429 --- /dev/null +++ b/src/GitHub/public/Organization/Set-GitHubOrganizationSecurityFeature.ps1 @@ -0,0 +1,65 @@ +filter Set-GitHubOrganizationSecurityFeature { + <# + .SYNOPSIS + Enable or disable a security feature for an organization + + .DESCRIPTION + Enables or disables the specified security feature for all eligible repositories in an organization. + + To use this endpoint, you must be an organization owner or be member of a team with the security manager role. + A token with the 'write:org' scope is also required. + + GitHub Apps must have the `organization_administration:write` permission to use this endpoint. + + For more information, see "[Managing security managers in your organization](https://docs.github.com/organizations/managing-peoples-access-to-your-organization-with-roles/managing-security-managers-in-your-organization)." + + .EXAMPLE + Set-GitHubOrganizationSecurityFeature -OrganizationName 'github' -SecurityProduct 'dependency_graph' -Enablement 'enable_all' + + Enable the dependency graph for all repositories in the organization `github`. + + .NOTES + https://docs.github.com/rest/orgs/orgs#enable-or-disable-a-security-feature-for-an-organization + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The organization name. The name is not case sensitive. + [Parameter(Mandatory)] + [Alias('org')] + [Alias('owner')] + [Alias('login')] + [string] $OrganizationName, + + # The security feature to enable or disable. + [Parameter(Mandatory)] + [Alias('security_product')] + [ValidateSet('dependency_graph', 'dependabot_alerts', 'dependabot_security_updates', 'advanced_security', 'code_scanning_default_setup', 'secret_scanning', 'secret_scanning_push_protection')] + [string] $SecurityProduct, + + # The action to take. + # enable_all means to enable the specified security feature for all repositories in the organization. disable_all means to disable the specified security feature for all repositories in the organization. + [Parameter(Mandatory)] + [ValidateSet('enable_all', 'disable_all')] + [string] $Enablement, + + # CodeQL query suite to be used. If you specify the query_suite parameter, the default setup will be configured with this query suite only on all repositories that didn't have default setup already configured. It will not change the query suite on repositories that already have default setup configured. If you don't specify any query_suite in your request, the preferred query suite of the organization will be applied. + [Parameter()] + [Alias('query_suite')] + [ValidateSet('default', 'extended')] + [string] $QuerySuite + ) + + $body = @{ + query_suite = $QuerySuite + } + + $inputObject = @{ + APIEndpoint = "/orgs/$OrganizationName/$SecurityProduct/$Enablement" + Method = 'POST' + Body = $body + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/public/Teams/Get-GitHubRepoTeam.ps1 b/src/GitHub/public/Teams/Get-GitHubRepoTeam.ps1 index cc3516f1b..c07dd89f1 100644 --- a/src/GitHub/public/Teams/Get-GitHubRepoTeam.ps1 +++ b/src/GitHub/public/Teams/Get-GitHubRepoTeam.ps1 @@ -1,7 +1,7 @@ -function Get-GitHubRepoTeam { +filter Get-GitHubRepoTeam { <# .NOTES - https://docs.github.com/en/rest/reference/repos#get-a-repository + https://docs.github.com/rest/reference/repos#get-a-repository #> [CmdletBinding()] param ( @@ -17,6 +17,6 @@ function Get-GitHubRepoTeam { APIEndpoint = "/repos/$Owner/$Repo/teams" } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/public/Users/Blocking/Get-GitHubBlockedUser copy.ps1 b/src/GitHub/public/Users/Blocking/Get-GitHubBlockedUser copy.ps1 new file mode 100644 index 000000000..2b55d0370 --- /dev/null +++ b/src/GitHub/public/Users/Blocking/Get-GitHubBlockedUser copy.ps1 @@ -0,0 +1,32 @@ +filter Assert-GitHubBlockedUser { + <# + .SYNOPSIS + Check if a user is blocked by the authenticated user + + .DESCRIPTION + Returns a 204 if the given user is blocked by the authenticated user. Returns a 404 if the given user is not blocked by the authenticated user, or if the given user account has been identified as spam by GitHub. + + .EXAMPLE + + .NOTES + https://docs.github.com/rest/users/blocking#check-if-a-user-is-blocked-by-the-authenticated-user + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The number of results per page (max 100). + [Parameter()] + [int] $PerPage = 30 + ) + + $body = $PSBoundParameters | ConvertFrom-HashTable | ConvertTo-HashTable -NameCasingStyle snake_case + + $inputObject = @{ + APIEndpoint = "/user/blocks" + Method = 'GET' + Body = $body + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/public/Users/Blocking/Get-GitHubBlockedUser.ps1 b/src/GitHub/public/Users/Blocking/Get-GitHubBlockedUser.ps1 new file mode 100644 index 000000000..3f5187976 --- /dev/null +++ b/src/GitHub/public/Users/Blocking/Get-GitHubBlockedUser.ps1 @@ -0,0 +1,32 @@ +filter Get-GitHubBlockedUser { + <# + .SYNOPSIS + List users blocked by the authenticated user + + .DESCRIPTION + List the users you've blocked on your personal account. + + .EXAMPLE + + .NOTES + https://docs.github.com/rest/users/blocking#list-users-blocked-by-the-authenticated-user + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param ( + # The number of results per page (max 100). + [Parameter()] + [int] $PerPage = 30 + ) + + $body = $PSBoundParameters | ConvertFrom-HashTable | ConvertTo-HashTable -NameCasingStyle snake_case + + $inputObject = @{ + APIEndpoint = "/user/blocks" + Method = 'GET' + Body = $body + } + + (Invoke-GitHubAPI @inputObject).Response + +} diff --git a/src/GitHub/public/Users/Get-GitHubUser.ps1 b/src/GitHub/public/Users/Get-GitHubUser.ps1 index c1632017c..8efa351fa 100644 --- a/src/GitHub/public/Users/Get-GitHubUser.ps1 +++ b/src/GitHub/public/Users/Get-GitHubUser.ps1 @@ -1,30 +1,67 @@ -function Get-GitHubUser { +filter Get-GitHubUser { <# .SYNOPSIS - Get the authenticated user + List user(s) .DESCRIPTION - If the authenticated user is authenticated with an OAuth token with the `user` scope, then the response lists public and private profile information. - If the authenticated user is authenticated through OAuth without the `user` scope, then the response lists only public profile information. + Get the authenticated user - if no parameters are provided. + Get a given user - if a username is provided. + Lists all users, in the order that they signed up on GitHub - if '-All' is provided. .EXAMPLE Get-GitHubUser - Get the authenticated user + Get the authenticated user. + + .EXAMPLE + Get-GitHubUser -Username 'octocat' + + Get the 'octocat' user. + + .EXAMPLE + Get-GitHubUser -All -Since 17722253 + + Get a list of users, starting with the user 'MariusStorhaug'. .NOTES - https://docs.github.com/rest/users/users#get-the-authenticated-user + https://docs.github.com/rest/users/users #> [OutputType([pscustomobject])] - [Alias('Get-GitHubContext')] - [CmdletBinding()] - param () + [CmdletBinding(DefaultParameterSetName = '__DefaultSet')] + param ( + # The handle for the GitHub user account. + [Parameter( + Mandatory, + ParameterSetName = 'NamedUser', + ValueFromPipelineByPropertyName + )] + [string] $Username, - $inputObject = @{ - APIEndpoint = '/user' - Method = 'GET' - } + # List all users. Use '-Since' to start at a specific user id. + [Parameter( + Mandatory, + ParameterSetName = 'AllUsers' + )] + [switch] $All, - Invoke-GitHubAPI @inputObject + # A user ID. Only return users with an ID greater than this ID. + [Parameter(ParameterSetName = 'AllUsers')] + [int] $Since = 0, + # The number of results per page (max 100). + [Parameter(ParameterSetName = 'AllUsers')] + [int] $PerPage = 30 + ) + + switch ($PSCmdlet.ParameterSetName) { + '__DefaultSet' { + Get-GitHubMyUser + } + 'NamedUser' { + Get-GitHubUserByName -Username $Username + } + 'AllUsers' { + Get-GitHubAllUsers -Since $Since -PerPage $PerPage + } + } } diff --git a/src/GitHub/public/Users/Get-GitHubUserCard.ps1 b/src/GitHub/public/Users/Get-GitHubUserCard.ps1 index 6617af34e..ee7e7d427 100644 --- a/src/GitHub/public/Users/Get-GitHubUserCard.ps1 +++ b/src/GitHub/public/Users/Get-GitHubUserCard.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubUserCard { +filter Get-GitHubUserCard { <# .SYNOPSIS Get contextual information for a user @@ -22,7 +22,11 @@ [OutputType([pscustomobject])] [CmdletBinding()] param ( - [Parameter(Mandatory)] + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName + )] [string] $Username, [Parameter()] [ValidateSet('organization', 'repository', 'issue', 'pull_request')] @@ -42,6 +46,6 @@ Body = $body } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/src/GitHub/public/Users/Set-GitHubUser.ps1 b/src/GitHub/public/Users/Set-GitHubUser.ps1 index 8a388a937..99ceabf61 100644 --- a/src/GitHub/public/Users/Set-GitHubUser.ps1 +++ b/src/GitHub/public/Users/Set-GitHubUser.ps1 @@ -1,4 +1,4 @@ -function Set-GitHubUser { +filter Set-GitHubUser { <# .SYNOPSIS Update the authenticated user @@ -63,11 +63,7 @@ [string] $Bio ) - $body = @{} - - $PSBoundParameters.GetEnumerator() | ForEach-Object { - $body.($_.Key) = $_.Value - } + $body = $PSBoundParameters | ConvertFrom-HashTable | ConvertTo-HashTable -NameCasingStyle snake_case $inputObject = @{ APIEndpoint = '/user' @@ -75,6 +71,6 @@ Method = 'PATCH' } - Invoke-GitHubAPI @inputObject + (Invoke-GitHubAPI @inputObject).Response } diff --git a/tools/utilities/GitHubAPI.ps1 b/tools/utilities/GitHubAPI.ps1 index a5b3004e9..530c90274 100644 --- a/tools/utilities/GitHubAPI.ps1 +++ b/tools/utilities/GitHubAPI.ps1 @@ -21,19 +21,21 @@ $response.paths.psobject.Properties | Select-Object ` @{n = 'PUT'; e = { (($_.value.psobject.Properties.Name) -contains 'PUT') } }, ` @{n = 'PATCH'; e = { (($_.value.psobject.Properties.Name) -contains 'PATCH') } } | format-table -$path = '/users/{username}/hovercard' -$response.paths.$path.get.tags | clip # -> Namespace/foldername -$response.paths.$path.get.operationId | clip # -> FunctionName -$response.paths.$path.get.summary | clip # -> Synopsis -$response.paths.$path.get.description | clip # -> Description -$response.paths.$path.get.externalDocs.url | clip # -> Notes -$response.paths.$path.get.'x-github'.category | clip # -> Namespace/foldername -$response.paths.$path.get.'x-github'.subcategory | clip # -> Namespace/foldername -$response.paths.$path.get.'x-github'.enabledForGitHubApps | clip # -> Note + Warning if running as GitHub App -$response.paths.$path.get.'x-github'.githubCloudOnly | clip # -> Note -$response.paths.$path.get.parameters # -> Parameter list -$response.paths.$path.get.responses.'200'.content.'application/json'.schema # -> OutputType qualifyer -$response.paths.$path.get.responses.'200'.content.'application/json'.schema.items # -> OutputType -$response.paths.$path.get - - +$path = '/user/blocks/{username}' +$method = 'get' +$response.paths.$path.$method +$response.paths.$path.$method.tags | clip # -> Namespace/foldername +$response.paths.$path.$method.operationId | clip # -> FunctionName +$response.paths.$path.$method.summary | clip # -> Synopsis +$response.paths.$path.$method.description | clip # -> Description +$response.paths.$path.$method.externalDocs.url | clip # -> Notes +$response.paths.$path.$method.'x-github'.category | clip # -> Namespace/foldername +$response.paths.$path.$method.'x-github'.subcategory | clip # -> Namespace/foldername +$response.paths.$path.$method.'x-github'.enabledForGitHubApps | clip # -> Note + Warning if running as GitHub App +$response.paths.$path.$method.'x-github'.githubCloudOnly | clip # -> Note +$response.paths.$path.$method.parameters # -> Parameter list +$response.paths.$path.$method.parameters.'$ref' # -> Parameter list +$response.components.parameters.username # -> Parameter list ? +$response.paths.$path.$method.responses # -> Could be used to decide error handling within the function +$response.paths.$path.$method.responses.'200'.content.'application/json'.schema # -> OutputType qualifyer +$response.paths.$path.$method.responses.'200'.content.'application/json'.schema.items # -> OutputType diff --git a/tools/utilities/Local-Testing.ps1 b/tools/utilities/Local-Testing.ps1 index 3157efdae..567aa43ee 100644 --- a/tools/utilities/Local-Testing.ps1 +++ b/tools/utilities/Local-Testing.ps1 @@ -13,25 +13,39 @@ Install-Module -Name GitHub -Force -Verbose -AllowPrerelease # Import-Module -Name 'C:\Repos\GitHub\PSModule\Modules\GitHub\src\GitHub\GitHub.psm1' -Verbose -Force Import-Module -Name GitHub -Verbose -Clear-Host Get-Command -Module GitHub -Get-Variable | Where-Object -Property Module -NE $null | Select-Object Name, Module, ModuleName +Clear-Host Connect-GitHubAccount Connect-GitHubAccount -Mode OAuthApp Connect-GitHubAccount -AccessToken +Get-GitHubConfig Get-GitHubConfig -Name AccessToken -Get-GitHubConfig -Name AccessTokenExpirationDate Get-GitHubConfig -Name RefreshToken -Get-GitHubConfig -Name RefreshTokenExpirationDate -Get-GitHubConfig -Name ApiBaseUri Invoke-GitHubAPI -Method Get -ApiEndpoint /user Get-GitHubMeta -Get-GitHubOctocat -S 'Hello, World!' +Get-GitHubOctocat -S 'Hello World' Disconnect-GitHubAccount -Verbose -$VerbosePreference = 'SIlentlyContinue' +$VerbosePreference = 'SilentlyContinue' $str = '2023-10-27 17:43:40 UTC' $format = "yyyy-MM-dd HH:mm:ss 'UTC'" $date = [datetime]::ParseExact($str, $format, $null) $date + + +Get-GitHubOrganization +Get-GitHubOrganization -OrganizationName 'PowerShell' +Get-GitHubOrganization -OrganizationName 'PSModule' + +Get-GitHubOrganizationAppInstallation -OrganizationName 'PSModule' + +Set-GitHubOrganization -OrganizationName 'PSModule' -Blog 'https://www.psmodule.io' +Set-GitHubOrganization -OrganizationName 'PSModule' -Blog '' + +Set-GitHubOrganization -OrganizationName 'PSModule' -Company 'PSModule123' -DefaultRepositoryPermission admin +Set-GitHubOrganization -OrganizationName 'PSModule' -Company 'PSModule' -DefaultRepositoryPermission read + +Set-GitHubUser -Name 'Marius Storhaug' -Company '@DNBBank' -Email 'marstor@hotmail.com' -Blog 'https://www.github.com/MariusStorhaug' -TwitterUsername MariusStorhaug -Location 'Norway' -Hireable $false -Bio 'DevOps Engineer at DNB Bank. I ❤️ PowerShell and automation.' +Set-GitHubUser -Name 'MariusStorhaug' -Company ' ' +Set-GitHubUser -Name 'MariusStorhaug' -Hireable $true