Skip to content

Commit c15c9f4

Browse files
🩹 [Patch]: Add New-GitHubOrganization function (#462)
## Description This pull request introduces several new features and improvements to the PowerShell module for managing GitHub organizations and apps. Key changes include new functions for creating and managing organizations, enhancements to app installation workflows, and updates to testing coverage for these functionalities. - Fixes #459 ### New and updated functions * Added a `New-GitHubOrganization` function to create GitHub organizations within a specified enterprise. This includes support for specifying owners, billing emails, and enterprise contexts. * Updated the `Remove-GitHubOrganization` function to support removing multiple organizations via an array input parameter, improving flexibility. ### Improvements to App Installation * Modified the `Install-GitHubAppOnEnterpriseOrganization` function to validate repository selection values case-insensitively and return strongly-typed `GitHubAppInstallation` objects. ### Updates to Organization Properties * Corrected property mappings in the `GitHubOrganization` class to ensure accurate handling of `RequireWebCommitSignoff`. ### Testing Enhancements * Added new tests for organization creation, updates, app installation, and removal, improving validation for enterprise workflows. ### Debugging Improvements * Updated `Invoke-GitHubAPI` to include detailed context information in error messages, aiding debugging efforts. ## Type of change <!-- Use the check-boxes [x] on the options that are relevant. --> - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [x] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [ ] 🚀 [Feature] - [ ] 🌟 [Breaking change] ## Checklist <!-- Use the check-boxes [x] on the options that are relevant. --> - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas
1 parent 7baaed8 commit c15c9f4

File tree

7 files changed

+249
-51
lines changed

7 files changed

+249
-51
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
$orgParam = @{
2+
Enterprise = 'msx'
3+
Name = 'Marius-Test7'
4+
Owner = 'GitHub-Automation'
5+
BillingEmail = 'post@msx.no'
6+
}
7+
$org = New-GitHubOrganization @orgParam
8+
9+
$installAppParam = @{
10+
Enterprise = 'msx'
11+
Organization = $org.login
12+
ClientID = (Get-GitHubContext).ClientID
13+
RepositorySelection = 'all'
14+
}
15+
Install-GitHubApp @installAppParam
16+
17+
$updateOrgParam = @{
18+
Name = $org.login
19+
Description = 'Test organization created by PowerShell script'
20+
Location = 'Oslo, Norway'
21+
BillingEmail = 'post@msx.no'
22+
Company = 'MSX AS'
23+
Email = 'info@msx.no'
24+
Blog = 'https://msx.no/blog'
25+
TwitterUsername = 'msx_no'
26+
HasOrganizationProjects = $true
27+
DefaultRepositoryPermission = 'read'
28+
MembersCanCreateRepositories = $true
29+
MembersCanCreatePublicRepositories = $true
30+
MembersCanCreatePrivateRepositories = $true
31+
MembersCanCreateInternalRepositories = $true
32+
MembersCanCreatePages = $true
33+
MembersCanCreatePublicPages = $true
34+
MembersCanCreatePrivatePages = $true
35+
MembersCanForkPrivateRepositories = $true
36+
WebCommitSignoffRequired = $false
37+
SecretScanningPushProtectionEnabledForNewRepositories = $true
38+
SecretScanningPushProtectionCustomLinkEnabled = $false
39+
SecretScanningPushProtectionCustomLink = '<link>'
40+
}
41+
Update-GitHubOrganization @updateOrgParam

src/classes/public/Owner/GitHubOwner/GitHubOrganization.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@
225225
$this.MembersCanInviteCollaborators = $Object.members_can_invite_collaborators
226226
$this.MembersCanCreatePages = $Object.members_can_create_pages
227227
$this.MembersCanForkPrivateRepositories = $Object.members_can_fork_private_repositories ?? $Object.membersCanForkPrivateRepositories
228-
$this.RequireWebCommitSignoff = $Object.web_commit_signoff_required ?? $Object.requiresTwoFactorAuthentication
228+
$this.RequireWebCommitSignoff = $Object.web_commit_signoff_required ?? $Object.webCommitSignoffRequired
229229
$this.DeployKeysEnabledForRepositories = $Object.deploy_keys_enabled_for_repositories
230230
$this.MembersCanCreatePublicPages = $Object.members_can_create_public_pages
231231
$this.MembersCanCreatePrivatePages = $Object.members_can_create_private_pages

src/functions/private/Apps/GitHub Apps/Install-GitHubAppOnEnterpriseOrganization.ps1

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
.EXAMPLE
1212
Install-GitHubAppOnEnterpriseOrganization -Enterprise 'msx' -Organization 'org' -ClientID '123456'
1313
#>
14+
[OutputType([GitHubAppInstallation])]
1415
[CmdletBinding()]
1516
param(
1617
# The enterprise slug or ID.
@@ -29,7 +30,7 @@
2930
# - all - all repositories that the authenticated GitHub App installation can access.
3031
# - selected - select specific repositories.
3132
[Parameter(Mandatory)]
32-
[ValidateSet('all', 'selected')]
33+
[ValidateSet('All', 'Selected')]
3334
[string] $RepositorySelection,
3435

3536
# The names of the repositories to which the installation will be granted access.
@@ -49,6 +50,9 @@
4950
}
5051

5152
process {
53+
if ($RepositorySelection) {
54+
$RepositorySelection = $RepositorySelection.ToLower()
55+
}
5256
$body = @{
5357
client_id = $ClientID
5458
repository_selection = $RepositorySelection
@@ -64,7 +68,7 @@
6468
}
6569

6670
Invoke-GitHubAPI @inputObject | ForEach-Object {
67-
Write-Output $_.Response
71+
[GitHubAppInstallation]::new($_.Response)
6872
}
6973
}
7074

src/functions/public/API/Invoke-GitHubAPI.ps1

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ function Invoke-GitHubAPI {
315315
}
316316

317317
$exception = @"
318+
319+
----------------------------------
320+
Context:
321+
$($Context | Format-List | Out-String)
318322
----------------------------------
319323
Request:
320324
$([pscustomobject]$APICall | Select-Object -ExcludeProperty Body, Headers | Format-List | Out-String)
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
function New-GitHubOrganization {
2+
<#
3+
.SYNOPSIS
4+
Creates a new GitHub organization within a specified enterprise.
5+
6+
.DESCRIPTION
7+
This function creates a new GitHub organization within the specified enterprise.
8+
9+
.EXAMPLE
10+
New-GitHubOrganization -Enterprise 'my-enterprise' -Name 'my-org' -Owner 'user1' -BillingEmail 'billing@example.com'
11+
12+
.OUTPUTS
13+
GitHubOrganization
14+
15+
.LINK
16+
https://psmodule.io/GitHub/Functions/Organization/New-GitHubOrganization/
17+
#>
18+
[OutputType([GitHubOrganization])]
19+
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
20+
param(
21+
# The name of the enterprise to create the organization in.
22+
[Parameter()]
23+
[string]$Enterprise,
24+
25+
# The name of the organization to create.
26+
[Parameter(Mandatory)]
27+
[string]$Name,
28+
29+
# The owners of the organization. This should be a list of GitHub usernames.
30+
[Parameter(Mandatory)]
31+
[string[]]$Owner,
32+
33+
# The billing email for the organization.
34+
[Parameter()]
35+
[string]$BillingEmail,
36+
37+
# The context to run the command in. Used to get the details for the API call.
38+
# Can be either a string or a GitHubContext object.
39+
[Parameter()]
40+
[object] $Context
41+
)
42+
43+
begin {
44+
$stackPath = Get-PSCallStackPath
45+
Write-Debug "[$stackPath] - Start"
46+
$Context = Resolve-GitHubContext -Context $Context
47+
Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
48+
}
49+
50+
process {
51+
$enterpriseObject = Get-GitHubEnterprise -Name $Enterprise -Context $Context
52+
Write-Verbose "Creating organization in enterprise: $($enterpriseObject.Name)"
53+
$graphQLFields = ([GitHubOrganization]::PropertyToGraphQLMap).Values
54+
55+
$inputParams = @{
56+
adminLogins = $Owner
57+
billingEmail = $BillingEmail
58+
enterpriseId = $enterpriseObject.NodeID
59+
login = $Name
60+
profileName = $Name
61+
}
62+
63+
$updateGraphQLInputs = @{
64+
Query = @"
65+
mutation(`$input:CreateEnterpriseOrganizationInput!) {
66+
createEnterpriseOrganization(input:`$input) {
67+
organization {
68+
$graphQLFields
69+
}
70+
}
71+
}
72+
"@
73+
Variables = @{
74+
input = $inputParams
75+
}
76+
Context = $Context
77+
}
78+
if ($PSCmdlet.ShouldProcess("Creating organization '$Name' in enterprise '$Enterprise'")) {
79+
$orgresult = Invoke-GitHubGraphQLQuery @updateGraphQLInputs
80+
[GitHubOrganization]::new($orgresult.createEnterpriseOrganization.organization, $Context)
81+
}
82+
}
83+
84+
end {
85+
Write-Debug "[$stackPath] - End"
86+
}
87+
}
88+

src/functions/public/Organization/Remove-GitHubOrganization.ps1

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@
2424
https://psmodule.io/GitHub/Functions/Organization/Remove-GitHubOrganization
2525
#>
2626
[OutputType([void])]
27-
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
27+
[CmdletBinding(DefaultParameterSetName = 'Remove an organization', SupportsShouldProcess, ConfirmImpact = 'High')]
2828
param(
2929
# The organization name. The name is not case sensitive.
30-
[Parameter(
31-
Mandatory,
32-
ValueFromPipeline,
33-
ValueFromPipelineByPropertyName
34-
)]
30+
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
3531
[string] $Name,
3632

33+
# The input object to process. Can be a single or an array of GitHubOrganization objects.
34+
[Parameter(Mandatory, ParameterSetName = 'ArrayInput', ValueFromPipeline)]
35+
[GitHubOrganization[]] $InputObject,
36+
3737
# The context to run the command in. Used to get the details for the API call.
3838
# Can be either a string or a GitHubContext object.
3939
[Parameter()]
@@ -48,20 +48,32 @@
4848
}
4949

5050
process {
51-
$inputObject = @{
52-
Method = 'DELETE'
53-
APIEndpoint = "/orgs/$Name"
54-
Context = $Context
55-
}
51+
switch ($PSCmdlet.ParameterSetName) {
52+
'ArrayInput' {
53+
foreach ($item in $InputObject) {
54+
$params = @{
55+
Name = $item.Name
56+
Context = $Context
57+
}
58+
Remove-GitHubOrganization @params
59+
}
60+
break
61+
}
62+
default {
63+
$apiParams = @{
64+
Method = 'DELETE'
65+
APIEndpoint = "/orgs/$Name"
66+
Context = $Context
67+
}
5668

57-
if ($PSCmdlet.ShouldProcess("organization [$Name]", 'DELETE')) {
58-
$null = Invoke-GitHubAPI @inputObject
69+
if ($PSCmdlet.ShouldProcess("organization [$Name]", 'Delete')) {
70+
$null = Invoke-GitHubAPI @apiParams
71+
}
72+
}
5973
}
6074
}
6175

6276
end {
6377
Write-Debug "[$stackPath] - End"
6478
}
6579
}
66-
67-
#SkipTest:FunctionTest:Will add a test for this function in a future PR

0 commit comments

Comments
 (0)