From 02a0a8d9cce030504f26697ac9947f24fc8a0f91 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 17:31:00 +0100 Subject: [PATCH 01/16] Made GetTeamByName and ListByOrg private --- src/functions/{public => private}/Teams/Get-GitHubTeamByName.ps1 | 0 .../{public => private}/Teams/Get-GitHubTeamListByOrg.ps1 | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/functions/{public => private}/Teams/Get-GitHubTeamByName.ps1 (100%) rename src/functions/{public => private}/Teams/Get-GitHubTeamListByOrg.ps1 (100%) diff --git a/src/functions/public/Teams/Get-GitHubTeamByName.ps1 b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 similarity index 100% rename from src/functions/public/Teams/Get-GitHubTeamByName.ps1 rename to src/functions/private/Teams/Get-GitHubTeamByName.ps1 diff --git a/src/functions/public/Teams/Get-GitHubTeamListByOrg.ps1 b/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 similarity index 100% rename from src/functions/public/Teams/Get-GitHubTeamListByOrg.ps1 rename to src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 From e1ccf0e669c3b58b42da49fcb72edf42ab0635c9 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 17:31:34 +0100 Subject: [PATCH 02/16] Implement Get-GitHubTeam function to list teams or get a team by name --- src/functions/public/Teams/Get-GitHubTeam.ps1 | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/functions/public/Teams/Get-GitHubTeam.ps1 diff --git a/src/functions/public/Teams/Get-GitHubTeam.ps1 b/src/functions/public/Teams/Get-GitHubTeam.ps1 new file mode 100644 index 000000000..736a56a89 --- /dev/null +++ b/src/functions/public/Teams/Get-GitHubTeam.ps1 @@ -0,0 +1,81 @@ +function Get-GitHubTeam { + <# + .SYNOPSIS + List teams from an org or get a team by name + + .DESCRIPTION + Lists all teams in an organization that are visible to the authenticated user or gets a team using the team's slug. + To create the slug, GitHub replaces special characters in the name string, changes all words to lowercase, + and replaces spaces with a - separator. For example, "My TEam Näme" would become my-team-name. + + .EXAMPLE + Get-GitHubTeam -Organization 'github' + + Gets all teams in the 'github' organization. + + .EXAMPLE + Get-GitHubTeamByName -Organization 'github' -Name 'my-team-name' + + Gets the team with the slug 'my-team-name' in the 'github' organization. + + .NOTES + [List teams](https://docs.github.com/rest/teams/teams#list-teams) + [Get team by name](https://docs.github.com/en/rest/teams/teams#get-a-team-by-name) + #> + [OutputType([pscustomobject])] + [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')] + param( + # The organization name. The name is not case sensitive. + [Parameter(Mandatory)] + [Alias('Org')] + [string] $Organization, + + # The slug of the team name. + [Parameter( + Mandatory, + ParameterSetName = 'GetByName' + )] + [Alias('Team', 'TeamName', 'slug', 'team_slug')] + [string] $Name, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter()] + [object] $Context = (Get-GitHubContext) + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + $Context = Resolve-GitHubContext -Context $Context + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + + if ([string]::IsNullOrEmpty($Organization)) { + $Organization = $Context.Owner + } + Write-Debug "Organization: [$Organization]" + } + + process { + try { + $params = @{ + Organization = $Organization + Context = $Context + } + switch ($PSCmdlet.ParameterSetName) { + 'GetByName' { + Get-GitHubTeamByName @params -Name $Name + } + '__AllParameterSets' { + Get-GitHubTeamListByOrg @params + } + } + } catch { + throw $_ + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} From 77b4db8f4a63ae7eb2577cc74fdea42b8b5fff23 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 17:32:11 +0100 Subject: [PATCH 03/16] Add support for Remove-GitHubTeam to take pipeline values --- src/functions/public/Teams/Remove-GitHubTeam.ps1 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/functions/public/Teams/Remove-GitHubTeam.ps1 b/src/functions/public/Teams/Remove-GitHubTeam.ps1 index ac836f9b5..a2aa00d24 100644 --- a/src/functions/public/Teams/Remove-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Remove-GitHubTeam.ps1 @@ -17,12 +17,18 @@ [CmdletBinding(SupportsShouldProcess)] param( # The organization name. The name is not case sensitive. - [Parameter(Mandatory)] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName + )] [Alias('Org')] [string] $Organization, # The slug of the team name. - [Parameter(Mandatory)] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName + )] [Alias('Team', 'TeamName', 'slug', 'team_slug')] [string] $Name, From 7fb5f34951dec2cc15615b6dbaad1354104c13a0 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 18:42:16 +0100 Subject: [PATCH 04/16] Refactor Get-GitHubTeam to use GraphQL API for fetching teams and add Get-GitHubRESTTeam for REST API support --- .../public/Teams/Get-GitHubRESTTeam.ps1 | 81 +++++++++++ src/functions/public/Teams/Get-GitHubTeam.ps1 | 129 +++++++++++++----- 2 files changed, 174 insertions(+), 36 deletions(-) create mode 100644 src/functions/public/Teams/Get-GitHubRESTTeam.ps1 diff --git a/src/functions/public/Teams/Get-GitHubRESTTeam.ps1 b/src/functions/public/Teams/Get-GitHubRESTTeam.ps1 new file mode 100644 index 000000000..c0823f9a9 --- /dev/null +++ b/src/functions/public/Teams/Get-GitHubRESTTeam.ps1 @@ -0,0 +1,81 @@ +function Get-GitHubRESTTeam { + <# + .SYNOPSIS + List teams from an org or get a team by name + + .DESCRIPTION + Lists all teams in an organization that are visible to the authenticated user or gets a team using the team's slug. + To create the slug, GitHub replaces special characters in the name string, changes all words to lowercase, + and replaces spaces with a - separator. For example, "My TEam Näme" would become my-team-name. + + .EXAMPLE + Get-GitHubRESTTeam -Organization 'github' + + Gets all teams in the 'github' organization. + + .EXAMPLE + Get-GitHubRESTTeam -Organization 'github' -Name 'my-team-name' + + Gets the team with the slug 'my-team-name' in the 'github' organization. + + .NOTES + [List teams](https://docs.github.com/rest/teams/teams#list-teams) + [Get team by name](https://docs.github.com/en/rest/teams/teams#get-a-team-by-name) + #> + [OutputType([pscustomobject])] + [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')] + param( + # The organization name. The name is not case sensitive. + [Parameter(Mandatory)] + [Alias('Org')] + [string] $Organization, + + # The slug of the team name. + [Parameter( + Mandatory, + ParameterSetName = 'GetByName' + )] + [Alias('Team', 'TeamName', 'slug', 'team_slug')] + [string] $Name, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter()] + [object] $Context = (Get-GitHubContext) + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + $Context = Resolve-GitHubContext -Context $Context + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + + if ([string]::IsNullOrEmpty($Organization)) { + $Organization = $Context.Owner + } + Write-Debug "Organization: [$Organization]" + } + + process { + try { + $params = @{ + Organization = $Organization + Context = $Context + } + switch ($PSCmdlet.ParameterSetName) { + 'GetByName' { + Get-GitHubTeamByName @params -Name $Name + } + '__AllParameterSets' { + Get-GitHubTeamListByOrg @params + } + } + } catch { + throw $_ + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/public/Teams/Get-GitHubTeam.ps1 b/src/functions/public/Teams/Get-GitHubTeam.ps1 index 736a56a89..f7314c683 100644 --- a/src/functions/public/Teams/Get-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Get-GitHubTeam.ps1 @@ -1,43 +1,32 @@ function Get-GitHubTeam { <# .SYNOPSIS - List teams from an org or get a team by name + Get the teams for an organization using the GitHub GraphQL API. .DESCRIPTION - Lists all teams in an organization that are visible to the authenticated user or gets a team using the team's slug. - To create the slug, GitHub replaces special characters in the name string, changes all words to lowercase, - and replaces spaces with a - separator. For example, "My TEam Näme" would become my-team-name. + This command will get the teams for an organization using the GitHub GraphQL API. .EXAMPLE - Get-GitHubTeam -Organization 'github' + Get-GitHubTeam -Organization 'PSModule' - Gets all teams in the 'github' organization. + Gets the teams for the PSModule organization. .EXAMPLE - Get-GitHubTeamByName -Organization 'github' -Name 'my-team-name' + Get-GitHubTeam -Organization 'PSModule' -Context $Context - Gets the team with the slug 'my-team-name' in the 'github' organization. - - .NOTES - [List teams](https://docs.github.com/rest/teams/teams#list-teams) - [Get team by name](https://docs.github.com/en/rest/teams/teams#get-a-team-by-name) + Gets the teams for the PSModule organization using the provided context. #> - [OutputType([pscustomobject])] - [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')] + [CmdletBinding()] param( - # The organization name. The name is not case sensitive. - [Parameter(Mandatory)] - [Alias('Org')] - [string] $Organization, - - # The slug of the team name. - [Parameter( - Mandatory, - ParameterSetName = 'GetByName' - )] - [Alias('Team', 'TeamName', 'slug', 'team_slug')] + # The name of the organization to get the teams for. + [Parameter()] [string] $Name, + # The owner of the organization to get the teams for. + # If not provided, the owner from the context will be used. + [Parameter()] + [string] $Organization, + # The context to run the command in. Used to get the details for the API call. # Can be either a string or a GitHubContext object. [Parameter()] @@ -49,8 +38,7 @@ Write-Debug "[$stackPath] - Start" $Context = Resolve-GitHubContext -Context $Context Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT - - if ([string]::IsNullOrEmpty($Organization)) { + if ([string]::IsNullOrEmpty($Owner)) { $Organization = $Context.Owner } Write-Debug "Organization: [$Organization]" @@ -58,17 +46,86 @@ process { try { - $params = @{ - Organization = $Organization - Context = $Context + $teamQuery = $null -ne $Name ? 'slug: `$teamSlug' : 'first: 100, after: `$after' + $query = @" +query(`$org: String!, `$after: String) { + organization(login: `$org) { + teams($teamQuery) { + nodes { + id + name + slug + combinedSlug + databaseId + description + notificationSetting + privacy + parentTeam { + name + slug + } + organization { + login + } + childTeams(first: 100) { + nodes { + name + } + } + createdAt + updatedAt + } + pageInfo { + endCursor + hasNextPage + } + } + } +} +"@ + + # Variables hash that will be sent with the query + $variables = @{ + org = $Organization + teamSlug = $Name } - switch ($PSCmdlet.ParameterSetName) { - 'GetByName' { - Get-GitHubTeamByName @params -Name $Name - } - '__AllParameterSets' { - Get-GitHubTeamListByOrg @params + + # Prepare to store results and handle pagination + $hasNextPage = $true + $after = $null + + while ($hasNextPage) { + # Update the cursor for pagination + $variables['after'] = $after + + # Send the request to the GitHub GraphQL API + $response = Invoke-GitHubGraphQLQuery -Query $query -Variables $variables + + # Extract team data + $teams = $response.data.organization.teams + + # Accumulate the teams in results + $teams.nodes | ForEach-Object { + [PSCustomObject]@{ + Name = $_.name # PSModule Admins + Slug = $_.slug # psmodule-admins + NodeID = $_.id # T_kwDOCIVCh84AgoiD + CombinedSlug = $_.combinedSlug # PSModule/psmodule-admins + DatabaseId = $_.databaseId # 8554627 + Description = $_.description # + Notifications = $_.notificationSetting -eq 'NOTIFICATIONS_ENABLED' ? $true : $false + Privacy = $_.privacy # VISIBLE + ParentTeam = $_.parentTeam.slug + Organization = $_.organization.login + ChildTeams = $_.childTeams.nodes.name + CreatedAt = $_.createdAt # 9/9/2023 11:15:12 AM + UpdatedAt = $_.updatedAt # 3/10/2024 4:42:05 PM + } } + + # Check if there's another page to fetch + $hasNextPage = $teams.pageInfo.hasNextPage + $after = $teams.pageInfo.endCursor } } catch { throw $_ From 40ca70ed00883780e56561b8f081d9ad9db46cad Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 18:50:27 +0100 Subject: [PATCH 05/16] Fix --- src/functions/public/Teams/Get-GitHubRESTTeam.ps1 | 6 +++--- src/functions/public/Teams/Get-GitHubTeam.ps1 | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/functions/public/Teams/Get-GitHubRESTTeam.ps1 b/src/functions/public/Teams/Get-GitHubRESTTeam.ps1 index c0823f9a9..d45ea0100 100644 --- a/src/functions/public/Teams/Get-GitHubRESTTeam.ps1 +++ b/src/functions/public/Teams/Get-GitHubRESTTeam.ps1 @@ -9,14 +9,14 @@ and replaces spaces with a - separator. For example, "My TEam Näme" would become my-team-name. .EXAMPLE - Get-GitHubRESTTeam -Organization 'github' + Get-GitHubRESTTeam -Organization 'GitHub' - Gets all teams in the 'github' organization. + Gets all teams in the `github` organization. .EXAMPLE Get-GitHubRESTTeam -Organization 'github' -Name 'my-team-name' - Gets the team with the slug 'my-team-name' in the 'github' organization. + Gets the team with the slug 'my-team-name' in the `github` organization. .NOTES [List teams](https://docs.github.com/rest/teams/teams#list-teams) diff --git a/src/functions/public/Teams/Get-GitHubTeam.ps1 b/src/functions/public/Teams/Get-GitHubTeam.ps1 index f7314c683..273483632 100644 --- a/src/functions/public/Teams/Get-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Get-GitHubTeam.ps1 @@ -50,7 +50,7 @@ $query = @" query(`$org: String!, `$after: String) { organization(login: `$org) { - teams($teamQuery) { + teams(first: 100, after: `$after) { nodes { id name From 0854c5d0e9012dafe73ff03ae667dcfd42073921 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 19:56:22 +0100 Subject: [PATCH 06/16] Swap REST calls with GraphQL calls for Teams --- .../Teams/Get-GitHubRESTTeam.ps1 | 3 +- .../Teams/Get-GitHubRESTTeamByName.ps1 | 63 ++++++++++ .../Teams/Get-GitHubRESTTeamListByOrg.ps1 | 60 +++++++++ .../private/Teams/Get-GitHubTeamByName.ps1 | 79 +++++++++--- .../private/Teams/Get-GitHubTeamListByOrg.ps1 | 85 +++++++++++-- src/functions/public/Teams/Get-GitHubTeam.ps1 | 117 ++++-------------- 6 files changed, 294 insertions(+), 113 deletions(-) rename src/functions/{public => private}/Teams/Get-GitHubRESTTeam.ps1 (96%) create mode 100644 src/functions/private/Teams/Get-GitHubRESTTeamByName.ps1 create mode 100644 src/functions/private/Teams/Get-GitHubRESTTeamListByOrg.ps1 diff --git a/src/functions/public/Teams/Get-GitHubRESTTeam.ps1 b/src/functions/private/Teams/Get-GitHubRESTTeam.ps1 similarity index 96% rename from src/functions/public/Teams/Get-GitHubRESTTeam.ps1 rename to src/functions/private/Teams/Get-GitHubRESTTeam.ps1 index d45ea0100..ed1859723 100644 --- a/src/functions/public/Teams/Get-GitHubRESTTeam.ps1 +++ b/src/functions/private/Teams/Get-GitHubRESTTeam.ps1 @@ -26,7 +26,8 @@ [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')] param( # The organization name. The name is not case sensitive. - [Parameter(Mandatory)] + # If not provided, the organization from the context is used. + [Parameter()] [Alias('Org')] [string] $Organization, diff --git a/src/functions/private/Teams/Get-GitHubRESTTeamByName.ps1 b/src/functions/private/Teams/Get-GitHubRESTTeamByName.ps1 new file mode 100644 index 000000000..437c83b70 --- /dev/null +++ b/src/functions/private/Teams/Get-GitHubRESTTeamByName.ps1 @@ -0,0 +1,63 @@ +function Get-GitHubTeamByName { + <# + .SYNOPSIS + Get a team by name + + .DESCRIPTION + Gets a team using the team's slug. To create the slug, GitHub replaces special characters in the name string, changes all words to lowercase, + and replaces spaces with a - separator. For example, "My TEam Näme" would become my-team-name. + + .EXAMPLE + Get-GitHubTeamByName -Organization 'github' -Name 'my-team-name' + #> + [OutputType([void])] + [CmdletBinding()] + param( + # The slug of the team name. + [Parameter(Mandatory)] + [Alias('Team', 'TeamName', 'slug', 'team_slug')] + [string] $Name, + + # The organization name. The name is not case sensitive. + [Parameter(Mandatory)] + [Alias('Org')] + [string] $Organization, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter()] + [object] $Context = (Get-GitHubContext) + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + $Context = Resolve-GitHubContext -Context $Context + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + + if ([string]::IsNullOrEmpty($Organization)) { + $Organization = $Context.Owner + } + Write-Debug "Organization: [$Organization]" + } + + process { + try { + $inputObject = @{ + Context = $Context + APIEndpoint = "/orgs/$Organization/teams/$Name" + Method = 'Get' + } + + Invoke-GitHubAPI @inputObject | ForEach-Object { + Write-Output $_.Response + } + } catch { + throw $_ + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Teams/Get-GitHubRESTTeamListByOrg.ps1 b/src/functions/private/Teams/Get-GitHubRESTTeamListByOrg.ps1 new file mode 100644 index 000000000..fb8cf4ec1 --- /dev/null +++ b/src/functions/private/Teams/Get-GitHubRESTTeamListByOrg.ps1 @@ -0,0 +1,60 @@ +function Get-GitHubTeamListByOrg { + <# + .SYNOPSIS + List teams + + .DESCRIPTION + Lists all teams in an organization that are visible to the authenticated user. + + .EXAMPLE + Get-GitHubTeamListByOrg -Organization 'github' + + .NOTES + [List teams](https://docs.github.com/rest/teams/teams#list-teams) + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param( + # The organization name. The name is not case sensitive. + [Parameter(Mandatory)] + [Alias('Org')] + [string] $Organization, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter()] + [object] $Context = (Get-GitHubContext) + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + $Context = Resolve-GitHubContext -Context $Context + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + + if ([string]::IsNullOrEmpty($Organization)) { + $Organization = $Context.Owner + } + Write-Debug "Organization: [$Organization]" + } + + process { + try { + $inputObject = @{ + Context = $Context + APIEndpoint = "/orgs/$Organization/teams" + Method = 'Get' + } + + Invoke-GitHubAPI @inputObject | ForEach-Object { + Write-Output $_.Response + } + } catch { + throw $_ + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 index 9c0231762..7d5fd2ea5 100644 --- a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 @@ -9,23 +9,21 @@ .EXAMPLE Get-GitHubTeamByName -Organization 'github' -Name 'my-team-name' - - .NOTES - [Get team by name](https://docs.github.com/en/rest/teams/teams#get-a-team-by-name) #> [OutputType([void])] [CmdletBinding()] param( - # The organization name. The name is not case sensitive. + # The slug of the team name. [Parameter(Mandatory)] + [Alias('team_slug', 'Name')] + [string] $Slug, + + # The organization name. The name is not case sensitive. + # If not provided, the owner from the context will be used. + [Parameter()] [Alias('Org')] [string] $Organization, - # The slug of the team name. - [Parameter(Mandatory)] - [Alias('Team', 'TeamName', 'slug', 'team_slug')] - [string] $Name, - # The context to run the command in. Used to get the details for the API call. # Can be either a string or a GitHubContext object. [Parameter()] @@ -46,14 +44,65 @@ process { try { - $inputObject = @{ - Context = $Context - APIEndpoint = "/orgs/$Organization/teams/$Name" - Method = 'Get' + $query = @" +query(`$org: String!, `$teamSlug: String!) { + organization(login: `$org) { + team(slug: `$teamSlug) { + id + name + slug + combinedSlug + databaseId + description + notificationSetting + privacy + parentTeam { + name + slug + } + organization { + login + } + childTeams(first: 100) { + nodes { + name + } + } + createdAt + updatedAt + } + } + } +} +"@ + + # Variables hash that will be sent with the query + $variables = @{ + org = $Organization + teamSlug = $Slug } - Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response + # Send the request to the GitHub GraphQL API + $response = Invoke-GitHubGraphQLQuery -Query $query -Variables $variables + + # Extract team data + $team = $response.data.organization.team + + # Accumulate the teams in results + [PSCustomObject]@{ + Name = $team.name # PSModule Admins + Slug = $team.slug # psmodule-admins + NodeID = $team.id # T_kwDOCIVCh84AgoiD + CombinedSlug = $team.combinedSlug # PSModule/psmodule-admins + DatabaseId = $team.databaseId # 8554627 + Description = $team.description # + Notifications = $team.notificationSetting -eq 'NOTIFICATIONS_ENABLED' ? $true : $false + Privacy = $team.privacy # VISIBLE + ParentTeam = $team.parentTeam.slug + Organization = $team.organization.login + ChildTeams = $team.childTeams.nodes.name + CreatedAt = $team.createdAt # 9/9/2023 11:15:12 AM + UpdatedAt = $team.updatedAt # 3/10/2024 4:42:05 PM } } catch { throw $_ diff --git a/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 b/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 index fb8cf4ec1..a5802cb3c 100644 --- a/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 @@ -16,7 +16,8 @@ [CmdletBinding()] param( # The organization name. The name is not case sensitive. - [Parameter(Mandatory)] + # If you don't provide this parameter, the command will use the owner of the context. + [Parameter()] [Alias('Org')] [string] $Organization, @@ -40,14 +41,84 @@ process { try { - $inputObject = @{ - Context = $Context - APIEndpoint = "/orgs/$Organization/teams" - Method = 'Get' + $query = @" +query(`$org: String!, `$after: String) { + organization(login: `$org) { + teams(first: 100, after: `$after) { + nodes { + id + name + slug + combinedSlug + databaseId + description + notificationSetting + privacy + parentTeam { + name + slug + } + organization { + login + } + childTeams(first: 100) { + nodes { + name + } + } + createdAt + updatedAt + } + pageInfo { + endCursor + hasNextPage + } + } + } +} +"@ + + # Variables hash that will be sent with the query + $variables = @{ + org = $Organization } - Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response + # Prepare to store results and handle pagination + $hasNextPage = $true + $after = $null + + while ($hasNextPage) { + # Update the cursor for pagination + $variables['after'] = $after + + # Send the request to the GitHub GraphQL API + $response = Invoke-GitHubGraphQLQuery -Query $query -Variables $variables + + # Extract team data + $teams = $response.data.organization.teams + + # Accumulate the teams in results + $teams.nodes | ForEach-Object { + [PSCustomObject]@{ + Name = $_.name # PSModule Admins + Slug = $_.slug # psmodule-admins + NodeID = $_.id # T_kwDOCIVCh84AgoiD + CombinedSlug = $_.combinedSlug # PSModule/psmodule-admins + DatabaseId = $_.databaseId # 8554627 + Description = $_.description # + Notifications = $_.notificationSetting -eq 'NOTIFICATIONS_ENABLED' ? $true : $false + Privacy = $_.privacy # VISIBLE + ParentTeam = $_.parentTeam.slug + Organization = $_.organization.login + ChildTeams = $_.childTeams.nodes.name + CreatedAt = $_.createdAt # 9/9/2023 11:15:12 AM + UpdatedAt = $_.updatedAt # 3/10/2024 4:42:05 PM + } + } + + # Check if there's another page to fetch + $hasNextPage = $teams.pageInfo.hasNextPage + $after = $teams.pageInfo.endCursor } } catch { throw $_ diff --git a/src/functions/public/Teams/Get-GitHubTeam.ps1 b/src/functions/public/Teams/Get-GitHubTeam.ps1 index 273483632..7560ad3e5 100644 --- a/src/functions/public/Teams/Get-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Get-GitHubTeam.ps1 @@ -1,30 +1,35 @@ function Get-GitHubTeam { <# .SYNOPSIS - Get the teams for an organization using the GitHub GraphQL API. + List teams from an org or get a team by name .DESCRIPTION - This command will get the teams for an organization using the GitHub GraphQL API. + Lists all teams in an organization that are visible to the authenticated user or gets a team using the team's slug. + To create the slug, GitHub replaces special characters in the name string, changes all words to lowercase, + and replaces spaces with a - separator. For example, "My TEam Näme" would become my-team-name. .EXAMPLE - Get-GitHubTeam -Organization 'PSModule' + Get-GitHubTeam -Organization 'GitHub' - Gets the teams for the PSModule organization. + Gets all teams in the `github` organization. .EXAMPLE - Get-GitHubTeam -Organization 'PSModule' -Context $Context + Get-GitHubTeam -Organization 'github' -Name 'my-team-name' - Gets the teams for the PSModule organization using the provided context. + Gets the team with the slug 'my-team-name' in the `github` organization. #> - [CmdletBinding()] + [OutputType([pscustomobject])] + [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')] param( - # The name of the organization to get the teams for. - [Parameter()] - [string] $Name, + # The slug of the team name. + [Parameter(Mandatory)] + [Alias('team_slug', 'Name')] + [string] $Slug, - # The owner of the organization to get the teams for. + # The organization name. The name is not case sensitive. # If not provided, the owner from the context will be used. [Parameter()] + [Alias('Org')] [string] $Organization, # The context to run the command in. Used to get the details for the API call. @@ -38,7 +43,8 @@ Write-Debug "[$stackPath] - Start" $Context = Resolve-GitHubContext -Context $Context Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT - if ([string]::IsNullOrEmpty($Owner)) { + + if ([string]::IsNullOrEmpty($Organization)) { $Organization = $Context.Owner } Write-Debug "Organization: [$Organization]" @@ -46,86 +52,17 @@ process { try { - $teamQuery = $null -ne $Name ? 'slug: `$teamSlug' : 'first: 100, after: `$after' - $query = @" -query(`$org: String!, `$after: String) { - organization(login: `$org) { - teams(first: 100, after: `$after) { - nodes { - id - name - slug - combinedSlug - databaseId - description - notificationSetting - privacy - parentTeam { - name - slug - } - organization { - login - } - childTeams(first: 100) { - nodes { - name - } - } - createdAt - updatedAt - } - pageInfo { - endCursor - hasNextPage - } - } - } -} -"@ - - # Variables hash that will be sent with the query - $variables = @{ - org = $Organization - teamSlug = $Name + $params = @{ + Organization = $Organization + Context = $Context } - - # Prepare to store results and handle pagination - $hasNextPage = $true - $after = $null - - while ($hasNextPage) { - # Update the cursor for pagination - $variables['after'] = $after - - # Send the request to the GitHub GraphQL API - $response = Invoke-GitHubGraphQLQuery -Query $query -Variables $variables - - # Extract team data - $teams = $response.data.organization.teams - - # Accumulate the teams in results - $teams.nodes | ForEach-Object { - [PSCustomObject]@{ - Name = $_.name # PSModule Admins - Slug = $_.slug # psmodule-admins - NodeID = $_.id # T_kwDOCIVCh84AgoiD - CombinedSlug = $_.combinedSlug # PSModule/psmodule-admins - DatabaseId = $_.databaseId # 8554627 - Description = $_.description # - Notifications = $_.notificationSetting -eq 'NOTIFICATIONS_ENABLED' ? $true : $false - Privacy = $_.privacy # VISIBLE - ParentTeam = $_.parentTeam.slug - Organization = $_.organization.login - ChildTeams = $_.childTeams.nodes.name - CreatedAt = $_.createdAt # 9/9/2023 11:15:12 AM - UpdatedAt = $_.updatedAt # 3/10/2024 4:42:05 PM - } + switch ($PSCmdlet.ParameterSetName) { + 'GetByName' { + Get-GitHubTeamByName @params -Slug $Slug + } + '__AllParameterSets' { + Get-GitHubTeamListByOrg @params } - - # Check if there's another page to fetch - $hasNextPage = $teams.pageInfo.hasNextPage - $after = $teams.pageInfo.endCursor } } catch { throw $_ From 4d34caff41d130f20e1671e43f58714167a3473c Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 20:10:27 +0100 Subject: [PATCH 07/16] Update Get-GitHubTeam to specify ParameterSetName for mandatory slug parameter --- src/functions/public/Teams/Get-GitHubTeam.ps1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/functions/public/Teams/Get-GitHubTeam.ps1 b/src/functions/public/Teams/Get-GitHubTeam.ps1 index 7560ad3e5..5ebe0965c 100644 --- a/src/functions/public/Teams/Get-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Get-GitHubTeam.ps1 @@ -22,7 +22,10 @@ [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')] param( # The slug of the team name. - [Parameter(Mandatory)] + [Parameter( + Mandatory, + ParameterSetName = 'ByName' + )] [Alias('team_slug', 'Name')] [string] $Slug, @@ -57,7 +60,7 @@ Context = $Context } switch ($PSCmdlet.ParameterSetName) { - 'GetByName' { + 'ByName' { Get-GitHubTeamByName @params -Slug $Slug } '__AllParameterSets' { From 9a47c1dd9aa04ceafed05c7a23c53bf6331505ce Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 20:55:54 +0100 Subject: [PATCH 08/16] Refactor team management functions to use 'Slug' for team identification and update privacy and notification parameters to boolean values. --- .../private/Teams/Get-GitHubTeamByName.ps1 | 4 +- src/functions/public/Teams/New-GitHubTeam.ps1 | 42 +++++++++++----- .../public/Teams/Remove-GitHubTeam.ps1 | 18 +++---- .../public/Teams/Update-GitHubTeam.ps1 | 48 ++++++++++++------- 4 files changed, 72 insertions(+), 40 deletions(-) diff --git a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 index 7d5fd2ea5..61059f807 100644 --- a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 @@ -97,10 +97,10 @@ query(`$org: String!, `$teamSlug: String!) { DatabaseId = $team.databaseId # 8554627 Description = $team.description # Notifications = $team.notificationSetting -eq 'NOTIFICATIONS_ENABLED' ? $true : $false - Privacy = $team.privacy # VISIBLE + Visible = $team.privacy -eq 'VISIBLE' ? $true : $false ParentTeam = $team.parentTeam.slug Organization = $team.organization.login - ChildTeams = $team.childTeams.nodes.name + ChildTeams = @($team.childTeams.nodes.name) CreatedAt = $team.createdAt # 9/9/2023 11:15:12 AM UpdatedAt = $team.updatedAt # 3/10/2024 4:42:05 PM } diff --git a/src/functions/public/Teams/New-GitHubTeam.ps1 b/src/functions/public/Teams/New-GitHubTeam.ps1 index 858de9a7b..d584f7a3a 100644 --- a/src/functions/public/Teams/New-GitHubTeam.ps1 +++ b/src/functions/public/Teams/New-GitHubTeam.ps1 @@ -29,15 +29,16 @@ #> [CmdletBinding(SupportsShouldProcess)] param( - # The organization name. The name is not case sensitive. - [Parameter(Mandatory)] - [Alias('Org')] - [string] $Organization, - # The name of the team. [Parameter(Mandatory)] [string] $Name, + # The organization name. The name is not case sensitive. + # If not provided, the organization from the context is used. + [Parameter()] + [Alias('Org')] + [string] $Organization, + # The description of the team. [Parameter()] [string] $Description, @@ -59,16 +60,14 @@ # - closed - visible to all members of this organization. # Default for child team: closed [Parameter()] - [ValidateSet('secret', 'closed')] - [string] $Privacy = 'closed', + [bool] $Visible = $true, # The notification setting the team has chosen. The options are: # notifications_enabled - team members receive notifications when the team is @mentioned. # notifications_disabled - no one receives notifications. # Default: notifications_enabled [Parameter()] - [ValidateSet('notifications_enabled', 'notifications_disabled')] - [string] $NotificationSetting, + [bool] $Notifications = $true, # Closing down notice. The permission that new repositories will be added to the team with when none is specified. [Parameter()] @@ -95,6 +94,10 @@ $Organization = $Context.Owner } Write-Debug "Organization: [$Organization]" + + if (-not $Visible -and $ParentTeamID -gt 0) { + throw "A nested team cannot be secret (invisible)." + } } process { @@ -104,8 +107,8 @@ description = $Description maintainers = $Maintainers repo_names = $RepoNames - privacy = $Privacy - notification_setting = $NotificationSetting + privacy = $Visible ? 'closed' : 'secret' + notification_setting = $Notifications ? 'notifications_enabled' : 'notifications_disabled' permission = $Permission parent_team_id = $ParentTeamID -eq 0 ? $null : $ParentTeamID } @@ -120,7 +123,22 @@ if ($PSCmdlet.ShouldProcess("'$Name' in '$Organization'", 'Create team')) { Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response + $team = $_.Response + [PSCustomObject]@{ + Name = $team.name + Slug = $team.slug + NodeID = $team.node_id + CombinedSlug = $Organization + '/' + $team.slug + DatabaseId = $team.id + Description = $team.description + Notifications = $team.notification_setting -eq 'notifications_enabled' ? $true : $false + Visible = $team.privacy -eq "closed" ? $true : $false + ParentTeam = $team.parent.slug + Organization = $team.organization.login + ChildTeams = @() + CreatedAt = $team.createdAt + UpdatedAt = $team.updatedAt + } } } } catch { diff --git a/src/functions/public/Teams/Remove-GitHubTeam.ps1 b/src/functions/public/Teams/Remove-GitHubTeam.ps1 index a2aa00d24..034c23a15 100644 --- a/src/functions/public/Teams/Remove-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Remove-GitHubTeam.ps1 @@ -16,21 +16,21 @@ [OutputType([void])] [CmdletBinding(SupportsShouldProcess)] param( - # The organization name. The name is not case sensitive. + # The slug of the team name. [Parameter( Mandatory, ValueFromPipelineByPropertyName )] - [Alias('Org')] - [string] $Organization, + [Alias('team_slug', 'Name')] + [string] $Slug, - # The slug of the team name. + # The organization name. The name is not case sensitive. + # If not provided, the organization from the context is used. [Parameter( - Mandatory, ValueFromPipelineByPropertyName )] - [Alias('Team', 'TeamName', 'slug', 'team_slug')] - [string] $Name, + [Alias('Org')] + [string] $Organization, # The context to run the command in. Used to get the details for the API call. # Can be either a string or a GitHubContext object. @@ -55,10 +55,10 @@ $inputObject = @{ Context = $Context Method = 'Delete' - APIEndpoint = "/orgs/$Organization/teams/$Name" + APIEndpoint = "/orgs/$Organization/teams/$Slug" } - if ($PSCmdlet.ShouldProcess("$Organization/$Name", 'Delete')) { + if ($PSCmdlet.ShouldProcess("$Organization/$Slug", 'Delete')) { Invoke-GitHubAPI @inputObject | ForEach-Object { Write-Output $_.Response } diff --git a/src/functions/public/Teams/Update-GitHubTeam.ps1 b/src/functions/public/Teams/Update-GitHubTeam.ps1 index c87d1e8f9..dcd6ffc45 100644 --- a/src/functions/public/Teams/Update-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Update-GitHubTeam.ps1 @@ -25,16 +25,17 @@ [OutputType([pscustomobject])] [CmdletBinding(SupportsShouldProcess)] param( - # The organization name. The name is not case sensitive. + # The slug of the team name. [Parameter(Mandatory)] + [Alias('team_slug', 'Name')] + [string] $Slug, + + # The organization name. The name is not case sensitive. + # If you do not provide this parameter, the command will use the organization from the context. + [Parameter()] [Alias('Org')] [string] $Organization, - # The slug of the team name. - [Parameter(Mandatory)] - [Alias('Team', 'TeamName', 'slug', 'team_slug')] - [string] $Name, - # The new team name. [Parameter()] [Alias()] @@ -53,21 +54,19 @@ # - closed - visible to all members of this organization. # Default for child team: closed [Parameter()] - [ValidateSet('secret', 'closed')] - [string] $Privacy = 'closed', + [bool] $Visible, # The notification setting the team has chosen. The options are: # notifications_enabled - team members receive notifications when the team is @mentioned. # notifications_disabled - no one receives notifications. # Default: notifications_enabled [Parameter()] - [ValidateSet('notifications_enabled', 'notifications_disabled')] - [string] $NotificationSetting, + [bool] $Notifications, # Closing down notice. The permission that new repositories will be added to the team with when none is specified. [Parameter()] [ValidateSet('pull', 'push')] - [string] $Permission = 'pull', + [string] $Permission, # The ID of a team to set as the parent team. [Parameter()] @@ -96,23 +95,38 @@ $body = @{ name = $NewName description = $Description - privacy = $Privacy - notification_setting = $NotificationSetting + privacy = $null -ne $Visible ? ($Visible ? 'closed' : 'secret') : $null + notification_setting = $null -ne $Notifications ? ($Notifications ? 'notifications_enabled' : 'notifications_disabled') : $null permission = $Permission - parent_team_id = $ParentTeamID + parent_team_id = $ParentTeamID -eq 0 ? $null : $ParentTeamID } $body | Remove-HashtableEntry -NullOrEmptyValues $inputObject = @{ Context = $Context - APIEndpoint = "/orgs/$Organization/teams/$Name" + APIEndpoint = "/orgs/$Organization/teams/$Slug" Method = 'Patch' Body = $body } - if ($PSCmdlet.ShouldProcess("$Organization/$Name", 'Update')) { + if ($PSCmdlet.ShouldProcess("$Organization/$Slug", 'Update')) { Invoke-GitHubAPI @inputObject | ForEach-Object { - Write-Output $_.Response + $team = $_.Response + [PSCustomObject]@{ + Name = $team.name + Slug = $team.slug + NodeID = $team.node_id + CombinedSlug = $Organization + '/' + $team.slug + DatabaseId = $team.id + Description = $team.description + Notifications = $team.notification_setting -eq 'notifications_enabled' ? $true : $false + Visible = $team.privacy -eq 'closed' ? $true : $false + ParentTeam = $team.parent.slug + Organization = $team.organization.login + ChildTeams = @() + CreatedAt = $team.createdAt + UpdatedAt = $team.updatedAt + } } } } catch { From 873dd644f614144150a5fe999e4a21357f1e519a Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 21:10:24 +0100 Subject: [PATCH 09/16] Fix --- src/functions/public/Teams/New-GitHubTeam.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/functions/public/Teams/New-GitHubTeam.ps1 b/src/functions/public/Teams/New-GitHubTeam.ps1 index d584f7a3a..a0553363e 100644 --- a/src/functions/public/Teams/New-GitHubTeam.ps1 +++ b/src/functions/public/Teams/New-GitHubTeam.ps1 @@ -136,8 +136,8 @@ ParentTeam = $team.parent.slug Organization = $team.organization.login ChildTeams = @() - CreatedAt = $team.createdAt - UpdatedAt = $team.updatedAt + CreatedAt = $team.created_at + UpdatedAt = $team.updated_at } } } From b69699b60ae74ea6fa73954501a4ca961908745d Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 21:13:14 +0100 Subject: [PATCH 10/16] Fix ChildTeams assignment in Get-GitHubTeamByName to correctly extract team names --- src/functions/private/Teams/Get-GitHubTeamByName.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 index 61059f807..b00ec75e9 100644 --- a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 @@ -100,7 +100,7 @@ query(`$org: String!, `$teamSlug: String!) { Visible = $team.privacy -eq 'VISIBLE' ? $true : $false ParentTeam = $team.parentTeam.slug Organization = $team.organization.login - ChildTeams = @($team.childTeams.nodes.name) + ChildTeams = $team.childTeams.nodes.name CreatedAt = $team.createdAt # 9/9/2023 11:15:12 AM UpdatedAt = $team.updatedAt # 3/10/2024 4:42:05 PM } From a7026fe2dfc3032362e4d06f586fc5fd4cbf8967 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 21:26:19 +0100 Subject: [PATCH 11/16] Refactor Update-GitHubTeam to use PSBoundParameters for privacy and notification settings --- src/functions/public/Teams/Update-GitHubTeam.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/functions/public/Teams/Update-GitHubTeam.ps1 b/src/functions/public/Teams/Update-GitHubTeam.ps1 index dcd6ffc45..e4f6531ec 100644 --- a/src/functions/public/Teams/Update-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Update-GitHubTeam.ps1 @@ -95,8 +95,9 @@ $body = @{ name = $NewName description = $Description - privacy = $null -ne $Visible ? ($Visible ? 'closed' : 'secret') : $null - notification_setting = $null -ne $Notifications ? ($Notifications ? 'notifications_enabled' : 'notifications_disabled') : $null + privacy = $PSBoundParameters.ContainsKey('Visible') ? ($Visible ? 'closed' : 'secret') : $null + notification_setting = $PSBoundParameters.ContainsKey('Notifications') ? + ($Notifications ? 'notifications_enabled' : 'notifications_disabled') : $null permission = $Permission parent_team_id = $ParentTeamID -eq 0 ? $null : $ParentTeamID } From 637342c6c65747d24bdc6e2d33fd34dad5448408 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 21:54:34 +0100 Subject: [PATCH 12/16] test --- src/classes/public/Teams/GitHubTeam.ps1 | 61 +++++++++++++++++++ .../private/Teams/Get-GitHubTeamByName.ps1 | 34 ++++++----- .../private/Teams/Get-GitHubTeamListByOrg.ps1 | 34 ++++++----- src/functions/public/Teams/Get-GitHubTeam.ps1 | 8 +-- src/functions/public/Teams/New-GitHubTeam.ps1 | 37 +++++------ .../public/Teams/Remove-GitHubTeam.ps1 | 2 +- .../public/Teams/Update-GitHubTeam.ps1 | 59 ++++++++++-------- 7 files changed, 154 insertions(+), 81 deletions(-) create mode 100644 src/classes/public/Teams/GitHubTeam.ps1 diff --git a/src/classes/public/Teams/GitHubTeam.ps1 b/src/classes/public/Teams/GitHubTeam.ps1 new file mode 100644 index 000000000..de046588c --- /dev/null +++ b/src/classes/public/Teams/GitHubTeam.ps1 @@ -0,0 +1,61 @@ +class GitHubTeam { + # The name of the team. + [string] $Name + + # The slug of the team. + [string] $Slug + + # The organization the team belongs to. + [string] $Organization + + # The combined slug of the team. + [string] $CombinedSlug + + # The ID of the team. + [string] $NodeID + + # The database ID of the team. + [string] $DatabaseID + + # The description of the team. + [string] $Description + + # The notification setting the team has chosen. + # $true = notifications_enabled - team members receive notifications when the team is @mentioned. + # $false = notifications_disabled - no one receives notifications. + [bool] $Notifications = $true + + # The privacy setting of the team. + # $true = closed - visible to all members of this organization. + # $false = secret - only visible to organization owners and members of this team. + [bool] $Visible = $true + + # The parent team of the team. + [string] $ParentTeam + + # The child teams of the team. + [string[]] $ChildTeams + + # The date and time the team was created. + [datetime] $CreatedAt + + # The date and time the team was last updated. + [datetime] $UpdatedAt + + # Simple parameterless constructor + GitHubTeam() {} + + # Creates a object from a hashtable of key-vaule pairs. + GitHubTeam([hashtable]$Properties) { + foreach ($Property in $Properties.Keys) { + $this.$Property = $Properties.$Property + } + } + + # Creates a object from a PSCustomObject. + GitHubTeam([PSCustomObject]$Object) { + $Object.PSObject.Properties | ForEach-Object { + $this.($_.Name) = $_.Value + } + } +} diff --git a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 index b00ec75e9..4a4e36967 100644 --- a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 @@ -10,7 +10,7 @@ .EXAMPLE Get-GitHubTeamByName -Organization 'github' -Name 'my-team-name' #> - [OutputType([void])] + [OutputType([GitHubTeam])] [CmdletBinding()] param( # The slug of the team name. @@ -89,21 +89,23 @@ query(`$org: String!, `$teamSlug: String!) { $team = $response.data.organization.team # Accumulate the teams in results - [PSCustomObject]@{ - Name = $team.name # PSModule Admins - Slug = $team.slug # psmodule-admins - NodeID = $team.id # T_kwDOCIVCh84AgoiD - CombinedSlug = $team.combinedSlug # PSModule/psmodule-admins - DatabaseId = $team.databaseId # 8554627 - Description = $team.description # - Notifications = $team.notificationSetting -eq 'NOTIFICATIONS_ENABLED' ? $true : $false - Visible = $team.privacy -eq 'VISIBLE' ? $true : $false - ParentTeam = $team.parentTeam.slug - Organization = $team.organization.login - ChildTeams = $team.childTeams.nodes.name - CreatedAt = $team.createdAt # 9/9/2023 11:15:12 AM - UpdatedAt = $team.updatedAt # 3/10/2024 4:42:05 PM - } + [GitHubTeam]( + @{ + Name = $team.name + Slug = $team.slug + NodeID = $team.id + CombinedSlug = $team.CombinedSlug + DatabaseID = $team.DatabaseId + Description = $team.description + Notifications = $team.notificationSetting -eq 'NOTIFICATIONS_ENABLED' ? $true : $false + Visible = $team.privacy -eq 'VISIBLE' ? $true : $false + ParentTeam = $team.parentTeam.slug + Organization = $team.organization.login + ChildTeams = $team.childTeams.nodes.name + CreatedAt = $team.createdAt + UpdatedAt = $team.updatedAt + } + ) } catch { throw $_ } diff --git a/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 b/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 index a5802cb3c..a1f90b4db 100644 --- a/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamListByOrg.ps1 @@ -12,7 +12,7 @@ .NOTES [List teams](https://docs.github.com/rest/teams/teams#list-teams) #> - [OutputType([pscustomobject])] + [OutputType([GitHubTeam[]])] [CmdletBinding()] param( # The organization name. The name is not case sensitive. @@ -99,21 +99,23 @@ query(`$org: String!, `$after: String) { # Accumulate the teams in results $teams.nodes | ForEach-Object { - [PSCustomObject]@{ - Name = $_.name # PSModule Admins - Slug = $_.slug # psmodule-admins - NodeID = $_.id # T_kwDOCIVCh84AgoiD - CombinedSlug = $_.combinedSlug # PSModule/psmodule-admins - DatabaseId = $_.databaseId # 8554627 - Description = $_.description # - Notifications = $_.notificationSetting -eq 'NOTIFICATIONS_ENABLED' ? $true : $false - Privacy = $_.privacy # VISIBLE - ParentTeam = $_.parentTeam.slug - Organization = $_.organization.login - ChildTeams = $_.childTeams.nodes.name - CreatedAt = $_.createdAt # 9/9/2023 11:15:12 AM - UpdatedAt = $_.updatedAt # 3/10/2024 4:42:05 PM - } + [GitHubTeam]( + @{ + Name = $_.name + Slug = $_.slug + NodeID = $_.id + CombinedSlug = $_.combinedSlug + DatabaseId = $_.databaseId + Description = $_.description + Notifications = $_.notificationSetting -eq 'NOTIFICATIONS_ENABLED' ? $true : $false + Visible = $_.privacy -eq 'VISIBLE' ? $true : $false + ParentTeam = $_.parentTeam.slug + Organization = $_.organization.login + ChildTeams = $_.childTeams.nodes.name + CreatedAt = $_.createdAt + UpdatedAt = $_.updatedAt + } + ) } # Check if there's another page to fetch diff --git a/src/functions/public/Teams/Get-GitHubTeam.ps1 b/src/functions/public/Teams/Get-GitHubTeam.ps1 index 5ebe0965c..3b32fea17 100644 --- a/src/functions/public/Teams/Get-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Get-GitHubTeam.ps1 @@ -14,19 +14,19 @@ Gets all teams in the `github` organization. .EXAMPLE - Get-GitHubTeam -Organization 'github' -Name 'my-team-name' + Get-GitHubTeam -Organization 'github' -Slug 'my-team-name' Gets the team with the slug 'my-team-name' in the `github` organization. #> - [OutputType([pscustomobject])] + [OutputType([GitHubTeam])] [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')] param( # The slug of the team name. [Parameter( Mandatory, - ParameterSetName = 'ByName' + ParameterSetName = 'BySlug' )] - [Alias('team_slug', 'Name')] + [Alias('team_slug')] [string] $Slug, # The organization name. The name is not case sensitive. diff --git a/src/functions/public/Teams/New-GitHubTeam.ps1 b/src/functions/public/Teams/New-GitHubTeam.ps1 index a0553363e..8ec457a84 100644 --- a/src/functions/public/Teams/New-GitHubTeam.ps1 +++ b/src/functions/public/Teams/New-GitHubTeam.ps1 @@ -27,6 +27,7 @@ .NOTES [Create a team](https://docs.github.com/rest/teams/teams#create-a-team) #> + [OutputType([GitHubTeam])] [CmdletBinding(SupportsShouldProcess)] param( # The name of the team. @@ -76,7 +77,7 @@ # The ID of a team to set as the parent team. [Parameter()] - [int] $ParentTeamID, + [int] $ParentTeamID = 0, # The context to run the command in. Used to get the details for the API call. # Can be either a string or a GitHubContext object. @@ -96,7 +97,7 @@ Write-Debug "Organization: [$Organization]" if (-not $Visible -and $ParentTeamID -gt 0) { - throw "A nested team cannot be secret (invisible)." + throw 'A nested team cannot be secret (invisible).' } } @@ -124,21 +125,23 @@ if ($PSCmdlet.ShouldProcess("'$Name' in '$Organization'", 'Create team')) { Invoke-GitHubAPI @inputObject | ForEach-Object { $team = $_.Response - [PSCustomObject]@{ - Name = $team.name - Slug = $team.slug - NodeID = $team.node_id - CombinedSlug = $Organization + '/' + $team.slug - DatabaseId = $team.id - Description = $team.description - Notifications = $team.notification_setting -eq 'notifications_enabled' ? $true : $false - Visible = $team.privacy -eq "closed" ? $true : $false - ParentTeam = $team.parent.slug - Organization = $team.organization.login - ChildTeams = @() - CreatedAt = $team.created_at - UpdatedAt = $team.updated_at - } + [GitHubTeam]( + @{ + Name = $team.name + Slug = $team.slug + NodeID = $team.node_id + CombinedSlug = $Organization + '/' + $team.slug + DatabaseId = $team.id + Description = $team.description + Notifications = $team.notification_setting -eq 'notifications_enabled' ? $true : $false + Visible = $team.privacy -eq 'closed' ? $true : $false + ParentTeam = $team.parent.slug + Organization = $team.organization.login + ChildTeams = @() + CreatedAt = $team.created_at + UpdatedAt = $team.updated_at + } + ) } } } catch { diff --git a/src/functions/public/Teams/Remove-GitHubTeam.ps1 b/src/functions/public/Teams/Remove-GitHubTeam.ps1 index 034c23a15..bfad8a82d 100644 --- a/src/functions/public/Teams/Remove-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Remove-GitHubTeam.ps1 @@ -21,7 +21,7 @@ Mandatory, ValueFromPipelineByPropertyName )] - [Alias('team_slug', 'Name')] + [Alias('team_slug',)] [string] $Slug, # The organization name. The name is not case sensitive. diff --git a/src/functions/public/Teams/Update-GitHubTeam.ps1 b/src/functions/public/Teams/Update-GitHubTeam.ps1 index e4f6531ec..7a43dcfc4 100644 --- a/src/functions/public/Teams/Update-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Update-GitHubTeam.ps1 @@ -8,26 +8,29 @@ .EXAMPLE $params = @{ - Organization = 'github' - Name = 'team-name' - NewName = 'new-team-name' - Description = 'A new team' - Privacy = 'closed' - NotificationSetting = 'notifications_enabled' - Permission = 'pull' - ParentTeamID = 123456 + Organization = 'github' + Slug = 'team-name' + NewName = 'new team name' + Description = 'A new team' + Visible = $true + Notifications = $true + Permission = 'pull' + ParentTeamID = 123456 } Update-GitHubTeam @params + Updates the team with the slug 'team-name' in the `github` organization with the new name 'new team name', description 'A new team', + visibility set to 'closed', notifications enabled, permission set to 'pull', and the parent team ID set to 123456. + .NOTES [Update a team](https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#update-a-team) #> - [OutputType([pscustomobject])] + [OutputType([GitHubTeam])] [CmdletBinding(SupportsShouldProcess)] param( # The slug of the team name. [Parameter(Mandatory)] - [Alias('team_slug', 'Name')] + [Alias('team_slug')] [string] $Slug, # The organization name. The name is not case sensitive. @@ -39,7 +42,7 @@ # The new team name. [Parameter()] [Alias()] - [string] $NewName, + [string] $Name, # The description of the team. [Parameter()] @@ -93,7 +96,7 @@ process { try { $body = @{ - name = $NewName + name = $Name description = $Description privacy = $PSBoundParameters.ContainsKey('Visible') ? ($Visible ? 'closed' : 'secret') : $null notification_setting = $PSBoundParameters.ContainsKey('Notifications') ? @@ -113,21 +116,23 @@ if ($PSCmdlet.ShouldProcess("$Organization/$Slug", 'Update')) { Invoke-GitHubAPI @inputObject | ForEach-Object { $team = $_.Response - [PSCustomObject]@{ - Name = $team.name - Slug = $team.slug - NodeID = $team.node_id - CombinedSlug = $Organization + '/' + $team.slug - DatabaseId = $team.id - Description = $team.description - Notifications = $team.notification_setting -eq 'notifications_enabled' ? $true : $false - Visible = $team.privacy -eq 'closed' ? $true : $false - ParentTeam = $team.parent.slug - Organization = $team.organization.login - ChildTeams = @() - CreatedAt = $team.createdAt - UpdatedAt = $team.updatedAt - } + [GitHubTeam]( + @{ + Name = $team.name + Slug = $team.slug + NodeID = $team.node_id + CombinedSlug = $Organization + '/' + $team.slug + DatabaseId = $team.id + Description = $team.description + Notifications = $team.notification_setting -eq 'notifications_enabled' ? $true : $false + Visible = $team.privacy -eq 'closed' ? $true : $false + ParentTeam = $team.parent.slug + Organization = $team.organization.login + ChildTeams = @() + CreatedAt = $team.created_at + UpdatedAt = $team.updated_at + } + ) } } } catch { From 4496c89a7041a97ef10d75a42aaee4408fd27a7f Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 22:01:04 +0100 Subject: [PATCH 13/16] Fix --- src/functions/public/Teams/Remove-GitHubTeam.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functions/public/Teams/Remove-GitHubTeam.ps1 b/src/functions/public/Teams/Remove-GitHubTeam.ps1 index bfad8a82d..389b1fd42 100644 --- a/src/functions/public/Teams/Remove-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Remove-GitHubTeam.ps1 @@ -21,7 +21,7 @@ Mandatory, ValueFromPipelineByPropertyName )] - [Alias('team_slug',)] + [Alias('team_slug')] [string] $Slug, # The organization name. The name is not case sensitive. From bcd40778338f09729eaac805c03402229b955a7f Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 22:26:04 +0100 Subject: [PATCH 14/16] Make RepoTeam private --- src/functions/{public => private}/Teams/Get-GitHubRepoTeam.ps1 | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/functions/{public => private}/Teams/Get-GitHubRepoTeam.ps1 (100%) diff --git a/src/functions/public/Teams/Get-GitHubRepoTeam.ps1 b/src/functions/private/Teams/Get-GitHubRepoTeam.ps1 similarity index 100% rename from src/functions/public/Teams/Get-GitHubRepoTeam.ps1 rename to src/functions/private/Teams/Get-GitHubRepoTeam.ps1 From 4b7b0a84e1b16011a2c3d28faecf8a569978f75e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 22:26:08 +0100 Subject: [PATCH 15/16] Enhance Get-GitHubTeamByName to return early if team data is not found --- src/functions/private/Teams/Get-GitHubTeamByName.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 index 4a4e36967..3de550261 100644 --- a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamByName.ps1 @@ -88,7 +88,11 @@ query(`$org: String!, `$teamSlug: String!) { # Extract team data $team = $response.data.organization.team - # Accumulate the teams in results + # Output the team object + if (-not $team) { + return + } + [GitHubTeam]( @{ Name = $team.name From b4879098ad75eaa7a529e03a1b1565a415067907 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 18 Dec 2024 22:52:26 +0100 Subject: [PATCH 16/16] Remove Get-GitHubTeamByName function and replace its usage with Get-GitHubTeamBySlug --- .../{Get-GitHubTeamByName.ps1 => Get-GitHubTeamBySlug.ps1} | 6 +++--- src/functions/public/Teams/Get-GitHubTeam.ps1 | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/functions/private/Teams/{Get-GitHubTeamByName.ps1 => Get-GitHubTeamBySlug.ps1} (96%) diff --git a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 b/src/functions/private/Teams/Get-GitHubTeamBySlug.ps1 similarity index 96% rename from src/functions/private/Teams/Get-GitHubTeamByName.ps1 rename to src/functions/private/Teams/Get-GitHubTeamBySlug.ps1 index 3de550261..7fb42f398 100644 --- a/src/functions/private/Teams/Get-GitHubTeamByName.ps1 +++ b/src/functions/private/Teams/Get-GitHubTeamBySlug.ps1 @@ -1,4 +1,4 @@ -function Get-GitHubTeamByName { +function Get-GitHubTeamBySlug { <# .SYNOPSIS Get a team by name @@ -8,14 +8,14 @@ and replaces spaces with a - separator. For example, "My TEam Näme" would become my-team-name. .EXAMPLE - Get-GitHubTeamByName -Organization 'github' -Name 'my-team-name' + Get-GitHubTeamBySlug -Organization 'github' -Slug 'my-team-name' #> [OutputType([GitHubTeam])] [CmdletBinding()] param( # The slug of the team name. [Parameter(Mandatory)] - [Alias('team_slug', 'Name')] + [Alias('team_slug')] [string] $Slug, # The organization name. The name is not case sensitive. diff --git a/src/functions/public/Teams/Get-GitHubTeam.ps1 b/src/functions/public/Teams/Get-GitHubTeam.ps1 index 3b32fea17..37b7347a8 100644 --- a/src/functions/public/Teams/Get-GitHubTeam.ps1 +++ b/src/functions/public/Teams/Get-GitHubTeam.ps1 @@ -60,8 +60,8 @@ Context = $Context } switch ($PSCmdlet.ParameterSetName) { - 'ByName' { - Get-GitHubTeamByName @params -Slug $Slug + 'BySlug' { + Get-GitHubTeamBySlug @params -Slug $Slug } '__AllParameterSets' { Get-GitHubTeamListByOrg @params