From 6a51601ec841a52e1fa95cf0e2e0a6fd1100269a Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Tue, 11 Aug 2020 21:45:34 +0100 Subject: [PATCH] GitHubTeams: Add New/Update/Remove Functions (#257) Adds the following functions: - `Add-GitHubTeam` - `Update-GitHubTeam` - `Remove-GitHubTeam` It also adds the `TeamName` parameter to the `Get-GitHubTeam` function to allow getting team details by team name, which is used by the new functions. Pester tests have also been added for the following functions: - `Get-GitHubTeam` - `Add-GitHubTeam` - `Update-GitHubTeam` - `Remove-GitHubTeam` Positional Binding has been set as `false` for the three functions, and `Position` attributes added to the function's mandatory parameters. Type view formats have been added for the `GitHub.TeamSummary` and `GitHub.Team` types. API Reference: [GitHub Teams API](https://developer.github.com/v3/teams/) --- Formatters/GitHubTeams.Format.ps1xml | 80 ++++ GitHubTeams.ps1 | 547 ++++++++++++++++++++- PowerShellForGitHub.psd1 | 7 +- Tests/GitHubTeams.tests.ps1 | 679 ++++++++++++++++++++++++++- USAGE.md | 62 +++ 5 files changed, 1370 insertions(+), 5 deletions(-) create mode 100644 Formatters/GitHubTeams.Format.ps1xml diff --git a/Formatters/GitHubTeams.Format.ps1xml b/Formatters/GitHubTeams.Format.ps1xml new file mode 100644 index 00000000..7b08c7d6 --- /dev/null +++ b/Formatters/GitHubTeams.Format.ps1xml @@ -0,0 +1,80 @@ + + + + + + GitHub.TeamSummary + + GitHub.TeamSummary + + + + + + + name + + + description + + + privacy + + + permission + + + OrganizationName + + + + + + + + + GitHub.Team + + GitHub.Team + + + + + + + name + + + description + + + privacy + + + permission + + + created_at + + + updated_at + + + members_count + + + repos_count + + + parent + + + OrganizationName + + + + + + + + diff --git a/GitHubTeams.ps1 b/GitHubTeams.ps1 index 33a632ed..55d1e31a 100644 --- a/GitHubTeams.ps1 +++ b/GitHubTeams.ps1 @@ -3,6 +3,7 @@ @{ GitHubTeamTypeName = 'GitHub.Team' + GitHubTeamSummaryTypeName = 'GitHub.TeamSummary' }.GetEnumerator() | ForEach-Object { Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value } @@ -34,6 +35,9 @@ filter Get-GitHubTeam .PARAMETER OrganizationName The name of the organization + .PARAMETER TeamName + The name of the specific team to retrieve + .PARAMETER TeamId The ID of the specific team to retrieve @@ -68,12 +72,15 @@ filter Get-GitHubTeam .OUTPUTS GitHub.Team + GitHub.TeamSummary .EXAMPLE Get-GitHubTeam -OrganizationName PowerShell #> [CmdletBinding(DefaultParameterSetName = 'Elements')] - [OutputType({$script:GitHubTeamTypeName})] + [OutputType( + {$script:GitHubTeamTypeName}, + {$script:GitHubTeamSummaryTypeName})] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="One or more parameters (like NoStatus) are only referenced by helper methods which get access to it from the stack via Get-Variable -Scope 1.")] param ( @@ -97,6 +104,11 @@ filter Get-GitHubTeam [ValidateNotNullOrEmpty()] [string] $OrganizationName, + [Parameter(ParameterSetName='Organization')] + [Parameter(ParameterSetName='Elements')] + [Parameter(ParameterSetName='Uri')] + [string] $TeamName, + [Parameter( Mandatory, ValueFromPipelineByPropertyName, @@ -115,6 +127,7 @@ filter Get-GitHubTeam $uriFragment = [String]::Empty $description = [String]::Empty + $teamType = [String]::Empty if ($PSCmdlet.ParameterSetName -in ('Elements', 'Uri')) { $elements = Resolve-RepositoryElements @@ -126,6 +139,7 @@ filter Get-GitHubTeam $uriFragment = "/repos/$OwnerName/$RepositoryName/teams" $description = "Getting teams for $RepositoryName" + $teamType = $script:GitHubTeamSummaryTypeName } elseif ($PSCmdlet.ParameterSetName -eq 'Organization') { @@ -133,6 +147,7 @@ filter Get-GitHubTeam $uriFragment = "/orgs/$OrganizationName/teams" $description = "Getting teams in $OrganizationName" + $teamType = $script:GitHubTeamSummaryTypeName } else { @@ -140,6 +155,7 @@ filter Get-GitHubTeam $uriFragment = "/teams/$TeamId" $description = "Getting team $TeamId" + $teamType = $script:GitHubTeamTypeName } $params = @{ @@ -152,8 +168,40 @@ filter Get-GitHubTeam 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) } - return (Invoke-GHRestMethodMultipleResult @params | - Add-GitHubTeamAdditionalProperties) + $result = Invoke-GHRestMethodMultipleResult @params | + Add-GitHubTeamAdditionalProperties -TypeName $teamType + + if ($PSBoundParameters.ContainsKey('TeamName')) + { + $team = $result | Where-Object -Property name -eq $TeamName + + if ($null -eq $team) + { + $message = "Team '$TeamName' not found" + Write-Log -Message $message -Level Error + throw $message + } + else + { + $uriFragment = "/orgs/$($team.OrganizationName)/teams/$($team.slug)" + $description = "Getting team $($team.slug)" + + $params = @{ + UriFragment = $uriFragment + Description = $description + Method = 'Get' + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + NoStatus = (Resolve-ParameterWithDefaultConfigurationValue ` + -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + $result = Invoke-GHRestMethod @params | Add-GitHubTeamAdditionalProperties + } + } + + return $result } filter Get-GitHubTeamMember @@ -273,6 +321,482 @@ filter Get-GitHubTeamMember return (Invoke-GHRestMethodMultipleResult @params | Add-GitHubUserAdditionalProperties) } +function New-GitHubTeam +{ +<# + .SYNOPSIS + Creates a team within an organization on GitHub. + + .DESCRIPTION + Creates a team within an organization on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OrganizationName + The name of the organization to create the team in. + + .PARAMETER TeamName + The name of the team. + + .PARAMETER Description + The description for the team. + + .PARAMETER MaintainerName + A list of GitHub user names for organization members who will become team maintainers. + + .PARAMETER RepositoryName + The name of repositories to add the team to. + + .PARAMETER Privacy + The level of privacy this team should have. + + .PARAMETER ParentTeamName + The name of a team to set as the parent team. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + GitHub.Team + GitHub.User + System.String + + .OUTPUTS + GitHub.Team + + .EXAMPLE + New-GitHubTeam -OrganizationName PowerShell -TeamName 'Developers' + + Creates a new GitHub team called 'Developers' in the 'PowerShell' organization. + + .EXAMPLE + $teamName = 'Team1' + $teamName | New-GitHubTeam -OrganizationName PowerShell + + You can also pipe in a team name that was returned from a previous command. + + .EXAMPLE + $users = Get-GitHubUsers -OrganizationName PowerShell + $users | New-GitHubTeam -OrganizationName PowerShell -TeamName 'Team1' + + You can also pipe in a list of GitHub users that were returned from a previous command. +#> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', + Justification = 'One or more parameters (like NoStatus) are only referenced by helper + methods which get access to it from the stack via Get-Variable -Scope 1.')] + [CmdletBinding( + SupportsShouldProcess, + PositionalBinding = $false + )] + [OutputType({$script:GitHubTeamTypeName})] + param + ( + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + Position = 1)] + [ValidateNotNullOrEmpty()] + [string] $OrganizationName, + + [Parameter( + Mandatory, + ValueFromPipeline, + Position = 2)] + [ValidateNotNullOrEmpty()] + [string] $TeamName, + + [string] $Description, + + [Parameter(ValueFromPipelineByPropertyName)] + [Alias('UserName')] + [string[]] $MaintainerName, + + [string[]] $RepositoryName, + + [ValidateSet('Secret', 'Closed')] + [string] $Privacy, + + [string] $ParentTeamName, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + begin + { + $maintainerNames = @() + } + + process + { + foreach ($user in $MaintainerName) + { + $maintainerNames += $user + } + } + + end + { + Write-InvocationLog + + $telemetryProperties = @{ + OrganizationName = (Get-PiiSafeString -PlainText $OrganizationName) + TeamName = (Get-PiiSafeString -PlainText $TeamName) + } + + $uriFragment = "/orgs/$OrganizationName/teams" + + $hashBody = @{ + name = $TeamName + } + + if ($PSBoundParameters.ContainsKey('Description')) { $hashBody['description'] = $Description } + if ($PSBoundParameters.ContainsKey('RepositoryName')) + { + $repositoryFullNames = @() + foreach ($repository in $RepositoryName) + { + $repositoryFullNames += "$OrganizationName/$repository" + } + $hashBody['repo_names'] = $repositoryFullNames + } + if ($PSBoundParameters.ContainsKey('Privacy')) { $hashBody['privacy'] = $Privacy.ToLower() } + if ($MaintainerName.Count -gt 0) + { + $hashBody['maintainers'] = $maintainerNames + } + if ($PSBoundParameters.ContainsKey('ParentTeamName')) + { + $getGitHubTeamParms = @{ + OrganizationName = $OrganizationName + TeamName = $ParentTeamName + } + if ($PSBoundParameters.ContainsKey('AccessToken')) + { + $getGitHubTeamParms['AccessToken'] = $AccessToken + } + if ($PSBoundParameters.ContainsKey('NoStatus')) + { + $getGitHubTeamParms['NoStatus'] = $NoStatus + } + + $team = Get-GitHubTeam @getGitHubTeamParms + + $hashBody['parent_team_id'] = $team.id + } + + if (-not $PSCmdlet.ShouldProcess($TeamName, 'Create GitHub Team')) + { + return + } + + $params = @{ + UriFragment = $uriFragment + Body = (ConvertTo-Json -InputObject $hashBody) + Method = 'Post' + Description = "Creating $TeamName" + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + NoStatus = (Resolve-ParameterWithDefaultConfigurationValue ` + -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return (Invoke-GHRestMethod @params | Add-GitHubTeamAdditionalProperties) + } +} + +filter Set-GitHubTeam +{ +<# + .SYNOPSIS + Updates a team within an organization on GitHub. + + .DESCRIPTION + Updates a team within an organization on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OrganizationName + The name of the team's organization. + + .PARAMETER TeamName + The name of the team. + + .PARAMETER Description + The description for the team. + + .PARAMETER Privacy + The level of privacy this team should have. + + .PARAMETER ParentTeamName + The name of a team to set as the parent team. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + GitHub.Organization + GitHub.Team + + .OUTPUTS + GitHub.Team + + .EXAMPLE + Set-GitHubTeam -OrganizationName PowerShell -TeamName Developers -Description 'New Description' + + Updates the description for the 'Developers' GitHub team in the 'PowerShell' organization. + + .EXAMPLE + $team = Get-GitHubTeam -OrganizationName PowerShell -TeamName Developers + $team | Set-GitHubTeam -Description 'New Description' + + You can also pipe in a GitHub team that was returned from a previous command. +#> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', + Justification = 'One or more parameters (like NoStatus) are only referenced by helper + methods which get access to it from the stack via Get-Variable -Scope 1.')] + [CmdletBinding( + SupportsShouldProcess, + PositionalBinding = $false + )] + [OutputType( { $script:GitHubTeamTypeName } )] + param + ( + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + Position = 1)] + [ValidateNotNullOrEmpty()] + [string] $OrganizationName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + Position = 2)] + [ValidateNotNullOrEmpty()] + [string] $TeamName, + + [string] $Description, + + [ValidateSet('Secret','Closed')] + [string] $Privacy, + + [string] $ParentTeamName, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog + + $telemetryProperties = @{ + OrganizationName = (Get-PiiSafeString -PlainText $OrganizationName) + TeamName = (Get-PiiSafeString -PlainText $TeamName) + } + + $getGitHubTeamParms = @{ + OrganizationName = $OrganizationName + } + if ($PSBoundParameters.ContainsKey('AccessToken')) + { + $getGitHubTeamParms['AccessToken'] = $AccessToken + } + if ($PSBoundParameters.ContainsKey('NoStatus')) + { + $getGitHubTeamParms['NoStatus'] = $NoStatus + } + + $orgTeams = Get-GitHubTeam @getGitHubTeamParms + + $team = $orgTeams | Where-Object -Property name -eq $TeamName + + $uriFragment = "/orgs/$OrganizationName/teams/$($team.slug)" + + $hashBody = @{ + name = $TeamName + } + + if ($PSBoundParameters.ContainsKey('Description')) { $hashBody['description'] = $Description } + if ($PSBoundParameters.ContainsKey('Privacy')) { $hashBody['privacy'] = $Privacy.ToLower() } + if ($PSBoundParameters.ContainsKey('ParentTeamName')) + { + $parentTeam = $orgTeams | Where-Object -Property name -eq $ParentTeamName + + $hashBody['parent_team_id'] = $parentTeam.id + } + + if (-not $PSCmdlet.ShouldProcess($TeamName, 'Set GitHub Team')) + { + return + } + + $params = @{ + UriFragment = $uriFragment + Body = (ConvertTo-Json -InputObject $hashBody) + Method = 'Patch' + Description = "Updating $TeamName" + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + NoStatus = (Resolve-ParameterWithDefaultConfigurationValue ` + -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return (Invoke-GHRestMethod @params | Add-GitHubTeamAdditionalProperties) +} + +filter Remove-GitHubTeam +{ +<# + .SYNOPSIS + Removes a team from an organization on GitHub. + + .DESCRIPTION + Removes a team from an organization on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OrganizationName + The name of the organization the team is in. + + .PARAMETER TeamName + The name of the team. + + .PARAMETER Force + If this switch is specified, you will not be prompted for confirmation of command execution. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + GitHub.Organization + GitHub.Team + + .OUTPUTS + None + + .EXAMPLE + Remove-GitHubTeam -OrganizationName PowerShell -TeamName Developers + + Removes the 'Developers' GitHub team from the 'PowerShell' organization. + + .EXAMPLE + Remove-GitHubTeam -OrganizationName PowerShell -TeamName Developers -Force + + Removes the 'Developers' GitHub team from the 'PowerShell' organization without prompting. + + .EXAMPLE + $team = Get-GitHubTeam -OrganizationName PowerShell -TeamName Developers + $team | Remove-GitHubTeam -Force + + You can also pipe in a GitHub team that was returned from a previous command. +#> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', + Justification = 'One or more parameters (like NoStatus) are only referenced by helper + methods which get access to it from the stack via Get-Variable -Scope 1.')] + [CmdletBinding( + SupportsShouldProcess, + PositionalBinding = $false, + ConfirmImpact = 'High' + )] + [Alias('Delete-GitHubTeam')] + param + ( + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName, + Position = 1)] + [ValidateNotNullOrEmpty()] + [string] $OrganizationName, + + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName, + Position = 2)] + [ValidateNotNullOrEmpty()] + [string] $TeamName, + + [switch] $Force, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog + + $telemetryProperties = @{ + OrganizationName = (Get-PiiSafeString -PlainText $RepositoryName) + TeamName = (Get-PiiSafeString -PlainText $TeamName) + } + + $getGitHubTeamParms = @{ + OrganizationName = $OrganizationName + TeamName = $TeamName + } + if ($PSBoundParameters.ContainsKey('AccessToken')) + { + $getGitHubTeamParms['AccessToken'] = $AccessToken + } + if ($PSBoundParameters.ContainsKey('NoStatus')) + { + $getGitHubTeamParms['NoStatus'] = $NoStatus + } + + $team = Get-GitHubTeam @getGitHubTeamParms + + $uriFragment = "/orgs/$OrganizationName/teams/$($team.slug)" + + if ($Force -and (-not $Confirm)) + { + $ConfirmPreference = 'None' + } + + if (-not $PSCmdlet.ShouldProcess($TeamName, 'Remove Github Team')) + { + return + } + + $params = @{ + UriFragment = $uriFragment + Method = 'Delete' + Description = "Deleting $TeamName" + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + NoStatus = (Resolve-ParameterWithDefaultConfigurationValue ` + -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + Invoke-GHRestMethod @params | Out-Null +} + filter Add-GitHubTeamAdditionalProperties { <# @@ -314,6 +838,23 @@ filter Add-GitHubTeamAdditionalProperties Add-Member -InputObject $item -Name 'TeamName' -Value $item.name -MemberType NoteProperty -Force Add-Member -InputObject $item -Name 'TeamId' -Value $item.id -MemberType NoteProperty -Force + $organizationName = [String]::Empty + if ($item.organization) + { + $organizationName = $item.organization.login + } + else + { + $hostName = $(Get-GitHubConfiguration -Name 'ApiHostName') + + if ($item.html_url -match "^https?://$hostName/orgs/([^/]+)/.*$") + { + $organizationName = $Matches[1] + } + } + + Add-Member -InputObject $item -Name 'OrganizationName' -Value $organizationName -MemberType NoteProperty -Force + # Apply these properties to any embedded parent teams as well. if ($null -ne $item.parent) { diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 21dd8820..10944b72 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. @{ @@ -19,6 +19,7 @@ 'Formatters/GitHubGists.Format.ps1xml', 'Formatters/GitHubReleases.Format.ps1xml' 'Formatters/GitHubRepositories.Format.ps1xml' + 'Formatters/GitHubTeams.Format.ps1xml' ) # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess @@ -141,6 +142,7 @@ 'New-GitHubRepositoryBranch', 'New-GitHubRepositoryBranchProtectionRule', 'New-GitHubRepositoryFork', + 'New-GitHubTeam', 'Remove-GitHubAssignee', 'Remove-GitHubComment', 'Remove-GitHubGist', @@ -160,6 +162,7 @@ 'Remove-GitHubRepository', 'Remove-GitHubRepositoryBranch' 'Remove-GitHubRepositoryBranchProtectionRule', + 'Remove-GitHubTeam', 'Rename-GitHubGistFile', 'Rename-GitHubRepository', 'Reset-GitHubConfiguration', @@ -185,6 +188,7 @@ 'Set-GitHubReleaseAsset', 'Set-GitHubRepository', 'Set-GitHubRepositoryTopic', + 'Set-GitHubTeam', 'Split-GitHubUri', 'Test-GitHubAssignee', 'Test-GitHubAuthenticationConfigured', @@ -214,6 +218,7 @@ 'Delete-GitHubRepository', 'Delete-GitHubRepositoryBranch', 'Delete-GitHubRepositoryBranchProtectionRule', + 'Delete-GitHubTeam', 'Fork-GitHubGist', 'Get-GitHubAsset', 'Get-GitHubBranch', diff --git a/Tests/GitHubTeams.tests.ps1 b/Tests/GitHubTeams.tests.ps1 index 21658992..7d312e37 100644 --- a/Tests/GitHubTeams.tests.ps1 +++ b/Tests/GitHubTeams.tests.ps1 @@ -17,7 +17,684 @@ $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent try { - # TODO once more capabilities exist in the module's API set + # Define Script-scoped, readonly, hidden variables. + @{ + defaultRepoDesc = "This is a description." + defaultRepoHomePage = "https://www.microsoft.com/" + defaultRepoTopic = "microsoft" + }.GetEnumerator() | ForEach-Object { + Set-Variable -Force -Scope Script -Option ReadOnly -Visibility Private -Name $_.Key -Value $_.Value + } + + Describe 'GitHubTeams\Get-GitHubTeam' { + BeforeAll { + $organizationName = $script:organizationName + } + + Context 'When getting a GitHub Team by organization' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $MaintainerName = $script:ownerName + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName + } + + New-GitHubTeam @newGithubTeamParms | Out-Null + + $orgTeams = Get-GitHubTeam -OrganizationName $organizationName + + $team = $orgTeams | Where-Object -Property name -eq $teamName + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.TeamSummary' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.parent | Should -BeNullOrEmpty + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + + Context 'When specifying the "TeamName" parameter' { + BeforeAll { + $team = Get-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.parent | Should -BeNullOrEmpty + $team.privacy | Should -Be $privacy + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + } + + Context 'When specifying the "OrganizationName" parameter through the pipeline' { + BeforeAll { + $orgTeams = $team | Get-GitHubTeam + $team = $orgTeams | Where-Object -Property name -eq $teamName + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.TeamSummary' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.parent | Should -BeNullOrEmpty + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } + + Context 'When getting a GitHub Team by repository' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + + $repo = New-GitHubRepository -RepositoryName $repoName -OrganizationName $organizationName + + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + RepositoryName = $repoName + Privacy = $privacy + } + + New-GitHubTeam @newGithubTeamParms | Out-Null + + $orgTeams = Get-GitHubTeam -OwnerName $organizationName -RepositoryName $repoName + $team = $orgTeams | Where-Object -Property name -eq $teamName + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.TeamSummary' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.parent | Should -BeNullOrEmpty + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + + Context 'When specifying the "TeamName" parameter' { + BeforeAll { + $getGitHubTeamParms = @{ + OwnerName = $organizationName + RepositoryName = $repoName + TeamName = $teamName + } + + $team = Get-GitHubTeam @getGitHubTeamParms + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.parent | Should -BeNullOrEmpty + $team.privacy | Should -Be $privacy + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 1 + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + } + + Context 'When specifying the "Uri" parameter through the pipeline' { + BeforeAll { + $orgTeams = $repo | Get-GitHubTeam -TeamName $teamName + $team = $orgTeams | Where-Object -Property name -eq $teamName + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 1 + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + } + + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } + + Context 'When getting a GitHub Team by TeamId' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $MaintainerName = $script:ownerName + + $newGithubTeamParms = @{ + OrganizationName = $script:organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName + } + + $newTeam = New-GitHubTeam @newGithubTeamParms + + $team = Get-GitHubTeam -TeamId $newTeam.id + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } + } + + Describe 'GitHubTeams\New-GitHubTeam' { + BeforeAll { + $organizationName = $script:organizationName + } + + Context 'When creating a new GitHub team with default settings' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + } + + $team = New-GitHubTeam @newGithubTeamParms + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.description | Should -BeNullOrEmpty + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } + + Context 'When creating a new GitHub team with all possible settings' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + + $newGithubRepositoryParms = @{ + RepositoryName = $repoName + OrganizationName = $organizationName + } + + $repo = New-GitHubRepository @newGitHubRepositoryParms + + $maintainer = Get-GitHubUser -UserName $script:ownerName + + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + RepositoryName = $repoName + Privacy = $privacy + MaintainerName = $maintainer.UserName + } + + $team = New-GitHubTeam @newGithubTeamParms + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 1 + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } + + Context 'When creating a child GitHub team' { + BeforeAll { + $parentTeamName = [Guid]::NewGuid().Guid + $privacy = 'Closed' + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $parentTeamName + Privacy = $privacy + } + + $parentTeam = New-GitHubTeam @newGithubTeamParms + + $childTeamName = [Guid]::NewGuid().Guid + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $childTeamName + ParentTeamName = $parentTeamName + Privacy = $privacy + } + + $childTeam = New-GitHubTeam @newGithubTeamParms + } + + It 'Should have the expected type and additional properties' { + $childTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $childTeam.name | Should -Be $childTeamName + $childTeam.organization.login | Should -Be $organizationName + $childTeam.parent.name | Should -Be $parentTeamName + $childTeam.privacy | Should -Be $privacy + $childTeam.TeamName | Should -Be $childTeamName + $childTeam.TeamId | Should -Be $childTeam.id + $childTeam.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name childTeam -ErrorAction SilentlyContinue) + { + $childTeam | Remove-GitHubTeam -Force + } + + if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) + { + $parentTeam | Remove-GitHubTeam -Force + } + } + } + + Context 'When specifying the "Organization" parameter through the pipeline' { + BeforeAll { + $teamName1 = [Guid]::NewGuid().Guid + $teamName2 = [Guid]::NewGuid().Guid + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName1 + } + + $team1 = New-GitHubTeam @newGithubTeamParms + + $team2 = $team1 | New-GitHubTeam -TeamName $teamName2 + } + + It 'Should have the expected type and additional properties' { + $team2.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team2.name | Should -Be $teamName2 + $team2.organization.login | Should -Be $organizationName + $team2.parent | Should -BeNullOrEmpty + $team2.created_at | Should -Not -BeNullOrEmpty + $team2.updated_at | Should -Not -BeNullOrEmpty + $team2.members_count | Should -Be 1 + $team2.repos_count | Should -Be 0 + $team2.TeamName | Should -Be $teamName2 + $team2.TeamId | Should -Be $team2.id + $team2.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name team1 -ErrorAction SilentlyContinue) + { + $team1 | Remove-GitHubTeam -Force + } + + if (Get-Variable -Name team2 -ErrorAction SilentlyContinue) + { + $team2 | Remove-GitHubTeam -Force + } + } + } + + Context 'When specifying the "TeamName" parameter through the pipeline' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + + $team = $teamName | New-GitHubTeam -OrganizationName $organizationName + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } + + Context 'When specifying the "MaintainerName" parameter through the pipeline' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $maintainer = Get-GitHubUser -UserName $script:ownerName + + $team = $maintainer | New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 + $team.TeamName | Should -Be $teamName + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } + } + + Describe 'GitHubTeams\Set-GitHubTeam' { + BeforeAll { + $organizationName = $script:organizationName + } + + Context 'When updating a Child GitHub team' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $parentTeamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'Closed' + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $parentTeamName + Privacy = $privacy + } + + $parentTeam = New-GitHubTeam @newGithubTeamParms + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Privacy = $privacy + } + + $team = New-GitHubTeam @newGithubTeamParms + + $updateGitHubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + ParentTeamName = $parentTeamName + } + + $updatedTeam = Set-GitHubTeam @updateGitHubTeamParms + } + + It 'Should have the expected type and additional properties' { + $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $updatedTeam.name | Should -Be $teamName + $updatedTeam.organization.login | Should -Be $organizationName + $updatedTeam.description | Should -Be $description + $updatedTeam.parent.name | Should -Be $parentTeamName + $updatedTeam.privacy | Should -Be $privacy + $updatedTeam.TeamName | Should -Be $teamName + $updatedTeam.TeamId | Should -Be $team.id + $updatedTeam.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + + if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) + { + $parentTeam | Remove-GitHubTeam -Force + } + } + } + + Context 'When updating a non-child GitHub team' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'Closed' + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Privacy = 'Secret' + } + + $team = New-GitHubTeam @newGithubTeamParms + + $updateGitHubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + } + + $updatedTeam = Set-GitHubTeam @updateGitHubTeamParms + } + + It 'Should have the expected type and additional properties' { + $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $updatedTeam.name | Should -Be $teamName + $updatedTeam.organization.login | Should -Be $OrganizationName + $updatedTeam.description | Should -Be $description + $updatedTeam.parent.name | Should -BeNullOrEmpty + $updatedTeam.privacy | Should -Be $privacy + $updatedTeam.created_at | Should -Not -BeNullOrEmpty + $updatedTeam.updated_at | Should -Not -BeNullOrEmpty + $updatedTeam.members_count | Should -Be 1 + $updatedTeam.repos_count | Should -Be 0 + $updatedTeam.TeamName | Should -Be $teamName + $updatedTeam.TeamId | Should -Be $team.id + $updatedTeam.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } + + Context 'When specifying the "Organization" and "TeamName" parameters through the pipeline' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + } + + $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + + $updatedTeam = $team | Set-GitHubTeam -Description $description + } + + It 'Should have the expected type and additional properties' { + $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $updatedTeam.name | Should -Be $teamName + $updatedTeam.organization.login | Should -Be $OrganizationName + $updatedTeam.description | Should -Be $description + $updatedTeam.parent.name | Should -BeNullOrEmpty + $updatedTeam.created_at | Should -Not -BeNullOrEmpty + $updatedTeam.updated_at | Should -Not -BeNullOrEmpty + $updatedTeam.members_count | Should -Be 1 + $updatedTeam.repos_count | Should -Be 0 + $updatedTeam.TeamName | Should -Be $teamName + $updatedTeam.TeamId | Should -Be $updatedTeam.id + $updatedTeam.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } + } + + Describe 'GitHubTeams\Remove-GitHubTeam' { + BeforeAll { + $organizationName = $script:organizationName + } + + Context 'When removing a GitHub team' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + + $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + } + + It 'Should not throw an exception' { + $removeGitHubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Confirm = $false + } + + { Remove-GitHubTeam @RemoveGitHubTeamParms } | Should -Not -Throw + } + + It 'Should have removed the team' { + { Get-GitHubTeam -OrganizationName $organizationName -TeamName $teamName } | + Should -Throw + } + } + + Context 'When specifying the "Organization" and "TeamName" parameters through the pipeline' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + + $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + } + + It 'Should not throw an exception' { + { $team |Remove-GitHubTeam -Force } | Should -Not -Throw + } + + It 'Should have removed the team' { + { Get-GitHubTeam -OrganizationName $organizationName -TeamName $teamName } | + Should -Throw + } + } + } } finally { diff --git a/USAGE.md b/USAGE.md index 71eaf035..8411ff7e 100644 --- a/USAGE.md +++ b/USAGE.md @@ -29,6 +29,15 @@ * [Updating the current authenticated user](#updating-the-current-authenticated-user) * [Getting any user](#getting-any-user) * [Getting all users](#getting-all-users) + * [Teams](#teams) + * [Getting teams in an Organization](#Getting-teams-in-an-Organization) + * [Getting teams assigned to a repository](#Getting-teams-assigned-to-a-repository) + * [Getting a team by team name](#Getting-a-team-by-team-name) + * [Getting a team by team id](#Getting-a-team-by-team-id) + * [Creating a team](#Creating-a-team) + * [Creating a child team](#Creating-a-child-team) + * [Updating a team](#Updating-a-team) + * [Removing a team](#Removing-a-team) * [Repositories](#repositories]) * [Create a repository](#Create-a-repository) * [Create a repository in an organization](#Create-a-repository-in-an-organization) @@ -478,6 +487,58 @@ Remove-GitHubRepositoryBranch -OwnerName microsoft -RepositoryName PowerShellFor ---------- +### Teams + +#### Getting teams in an Organization + +```powershell +Get-GitHubTeam -OrganizationName microsoft +``` + +#### Getting teams assigned to a repository + +```powershell +Get-GitHubTeam -OwnerName microsoft -RepositoryName PowerShellForGitHub +``` + +#### Getting a team by team name + +```powershell +Get-GitHubTeam -OrganizationName microsoft -TeamName MyTeam +``` + +#### Getting a team by team id + +```powershell +Get-GitHubTeam -OrganizationName microsoft -TeamId 378661 +``` + +#### Creating a team + +```powershell +New-GitHubTeam -OrganizationName microsoft -TeamName MyTeam -Description 'Team Description' +``` + +#### Creating a child team + +```powershell +New-GitHubTeam -OrganizationName microsoft -TeamName MyChildTeam -Description 'Team Description' -ParentTeamName MyTeam +``` + +#### Updating a team + +```powershell +Update-GitHubTeam -OrganizationName microsoft -TeamName MyChildTeam -Description 'Team Description' -ParentTeamName MyTeam +``` + +#### Removing a team + +```powershell +Remove-GitHubTeam -OrganizationName microsoft -TeamName MyTeam +``` + +---------- + ### Repositories #### Create a repository @@ -1091,3 +1152,4 @@ $issue | New-GitHubIssueComment -Body $CommentBody # Close issue $issue | Set-GitHubIssue -State Closed ``` +