Skip to content

Commit 02c0de4

Browse files
🚀 [Feature]: Introduce GitHubEnvironment Class and Improve Handling of Special Characters in Environment Names (#326)
## Description This pull request introduces a new `GitHubEnvironment` class and updates several functions to use this class for better type safety and consistency. Additionally, it includes enhancements to handle environment names with special characters and updates to the test cases to cover these changes. ### Introduction of `GitHubEnvironment` class: * Added a new `GitHubEnvironment` class with properties such as `Name`, `Repository`, `Owner`, `DatabaseID`, `NodeID`, `Url`, `CreatedAt`, `UpdatedAt`, `CanAdminsBypass`, `ProtectionRules`, and `DeploymentBranchPolicy`. This class includes constructors for initialization from a hashtable or a PSCustomObject. ### Updates to functions: * Updated `Get-GitHubEnvironmentByName`, `Get-GitHubEnvironmentList`, and `Set-GitHubEnvironment` functions to use the new `GitHubEnvironment` class instead of `PSCustomObject` for output type. [[1]](diffhunk://#diff-281ec1cdd72ba78fe2f547115ac26085efe035f4c30b748e579a7b71c3de9882L37-R45) [[2]](diffhunk://#diff-b7e6a0698de85126a8c0bf19e78924ae225511ad39ea20b05b2fcf6d262e82efL34-R42) [[3]](diffhunk://#diff-0d4fc874a278df0f48aba7cc73b05f002c068d4006e2acb0bdd24ab3eb6574e2L46-R58) * Modified `Get-GitHubEnvironmentByName`, `Get-GitHubEnvironmentList`, `Set-GitHubEnvironment`, and `Remove-GitHubEnvironment` functions to handle environment names with special characters using URL encoding. [[1]](diffhunk://#diff-281ec1cdd72ba78fe2f547115ac26085efe035f4c30b748e579a7b71c3de9882R83-R105) [[2]](diffhunk://#diff-b7e6a0698de85126a8c0bf19e78924ae225511ad39ea20b05b2fcf6d262e82efL90-R104) [[3]](diffhunk://#diff-0d4fc874a278df0f48aba7cc73b05f002c068d4006e2acb0bdd24ab3eb6574e2R218-R242) [[4]](diffhunk://#diff-7318eee8b888e260d6170db2abcae8cba8146173a0a7036f2756777ebc9fd5e8R60-R63) ### Enhancements to `Get-GitHubEnvironment`: * Simplified the `Get-GitHubEnvironment` function by removing the parameter set logic and using wildcard support for the `Name` parameter, allowing for more flexible environment name matching. [[1]](diffhunk://#diff-4ce9e4defaf029427d3215c1a0688b6bf11a705532e17295851e80b2e8948b0fL66-R66) [[2]](diffhunk://#diff-4ce9e4defaf029427d3215c1a0688b6bf11a705532e17295851e80b2e8948b0fL84-R89) [[3]](diffhunk://#diff-4ce9e4defaf029427d3215c1a0688b6bf11a705532e17295851e80b2e8948b0fL110-R108) ### Test case updates: * Added test cases to cover scenarios where environment names contain slashes and other special characters, ensuring that these names are correctly handled by the `Set-GitHubEnvironment` and `Remove-GitHubEnvironment` functions. [[1]](diffhunk://#diff-ca54665720a68eba32ad311ca6499070fd8435bd09671198175cf2f7e1d76073L46-R61) [[2]](diffhunk://#diff-ca54665720a68eba32ad311ca6499070fd8435bd09671198175cf2f7e1d76073L98-R126) [[3]](diffhunk://#diff-ca54665720a68eba32ad311ca6499070fd8435bd09671198175cf2f7e1d76073L155-R197) [[4]](diffhunk://#diff-ca54665720a68eba32ad311ca6499070fd8435bd09671198175cf2f7e1d76073L208-R264) These changes improve the robustness and flexibility of the environment management functions and ensure that they handle special cases more gracefully. ## Type of change <!-- Use the check-boxes [x] on the options that are relevant. --> - [ ] 📖 [Docs] - [ ] 🪲 [Fix] - [ ] 🩹 [Patch] - [ ] ⚠️ [Security fix] - [x] 🚀 [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 --------- Co-authored-by: github-actions <[email protected]>
1 parent 1e14577 commit 02c0de4

File tree

7 files changed

+186
-39
lines changed

7 files changed

+186
-39
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
class GitHubEnvironment {
2+
# The name of the environment.
3+
[string] $Name
4+
5+
# The repository where the environment is.
6+
[string] $Repository
7+
8+
# The owner of the environment.
9+
[string] $Owner
10+
11+
# The ID of the environment.
12+
[UInt64] $DatabaseID
13+
14+
# The Node ID of the environment.
15+
[string] $NodeID
16+
17+
# URL of the environment.
18+
[string] $Url
19+
20+
# The date and time the environment was created.
21+
[datetime] $CreatedAt
22+
23+
# The date and time the environment was last updated.
24+
[datetime] $UpdatedAt
25+
26+
# Whether admins can bypass protection rules.
27+
[bool] $CanAdminsBypass
28+
29+
# Protection rules associated with the environment.
30+
[object[]] $ProtectionRules
31+
32+
# Deployment branch policy details.
33+
[object] $DeploymentBranchPolicy
34+
35+
# Simple parameterless constructor
36+
GitHubEnvironment() {}
37+
38+
# Constructor that initializes the class from a hashtable
39+
GitHubEnvironment([hashtable]$Properties) {
40+
foreach ($Property in $Properties.Keys) {
41+
$this.$Property = $Properties.$Property
42+
}
43+
}
44+
45+
# Constructor that initializes the class from a PSCustomObject
46+
GitHubEnvironment([PSCustomObject]$Object) {
47+
$Object.PSObject.Properties | ForEach-Object {
48+
$this.($_.Name) = $_.Value
49+
}
50+
}
51+
}

src/functions/private/Environments/Get-GitHubEnvironmentByName.ps1

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ filter Get-GitHubEnvironmentByName {
3434
Retrieves details of the "test" environment in the specified repository.
3535
3636
.OUTPUTS
37-
PSCustomObject
37+
GitHubEnvironment
3838
3939
.NOTES
4040
Contains environment details, including name, URL, and protection settings.
4141
4242
.LINK
4343
https://psmodule.io/GitHub/Functions/Get-GitHubEnvironmentByName/
4444
#>
45-
[OutputType([pscustomobject])]
45+
[OutputType([GitHubEnvironment])]
4646
[CmdletBinding()]
4747
param(
4848
# The account owner of the repository. The name is not case sensitive.
@@ -80,14 +80,29 @@ filter Get-GitHubEnvironmentByName {
8080
}
8181

8282
process {
83+
$encodedName = [System.Uri]::EscapeDataString($Name)
8384
$inputObject = @{
84-
Method = 'GET'
85-
APIEndpoint = "/repos/$Owner/$Repository/environments/$Name"
86-
Context = $Context
85+
Method = 'GET'
86+
Uri = $Context.ApiBaseUri + "/repos/$Owner/$Repository/environments/$encodedName"
87+
Context = $Context
8788
}
8889

8990
Invoke-GitHubAPI @inputObject | ForEach-Object {
90-
Write-Output $_.Response
91+
Write-Output $_.Response | ForEach-Object {
92+
[GitHubEnvironment]@{
93+
Name = $_.name
94+
DatabaseID = $_.id
95+
NodeID = $_.node_id
96+
Url = $_.html_url
97+
Owner = $Owner
98+
Repository = $Repository
99+
CreatedAt = $_.created_at
100+
UpdatedAt = $_.updated_at
101+
CanAdminsBypass = $_.can_admins_bypass
102+
ProtectionRules = $_.protection_rules
103+
DeploymentBranchPolicy = $_.deployment_branch_policy
104+
}
105+
}
91106
}
92107
}
93108

src/functions/private/Environments/Get-GitHubEnvironmentList.ps1

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ filter Get-GitHubEnvironmentList {
3131
Lists all environments available in the "EnvironmentTest" repository owned by "PSModule".
3232
3333
.OUTPUTS
34-
PSCustomObject
34+
GitHubEnvironment
3535
3636
.NOTES
3737
Contains details of each environment in the repository, including its name and protection settings.
3838
3939
.LINK
4040
[List environments](https://docs.github.com/rest/deployments/environments#list-environments)
4141
#>
42-
[OutputType([pscustomobject])]
42+
[OutputType([GitHubEnvironment])]
4343
[CmdletBinding()]
4444
param(
4545
# The account owner of the repository. The name is not case sensitive.
@@ -87,7 +87,21 @@ filter Get-GitHubEnvironmentList {
8787
}
8888

8989
Invoke-GitHubAPI @inputObject | ForEach-Object {
90-
Write-Output $_.Response.environments
90+
Write-Output $_.Response.environments | ForEach-Object {
91+
[GitHubEnvironment]@{
92+
Name = $_.name
93+
Repository = $Repository
94+
Owner = $Owner
95+
DatabaseID = $_.id
96+
NodeID = $_.node_id
97+
Url = $_.html_url
98+
CreatedAt = $_.created_at
99+
UpdatedAt = $_.updated_at
100+
CanAdminsBypass = $_.can_admins_bypass
101+
ProtectionRules = $_.protection_rules
102+
DeploymentBranchPolicy = $_.deployment_branch_policy
103+
}
104+
}
91105
}
92106
}
93107

src/functions/public/Environments/Get-GitHubEnvironment.ps1

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ filter Get-GitHubEnvironment {
6363
https://psmodule.io/GitHub/Functions/Environments/Get-GitHubEnvironment/
6464
#>
6565
[OutputType([pscustomobject])]
66-
[CmdletBinding(DefaultParameterSetName = 'List')]
66+
[CmdletBinding()]
6767
param(
6868
# The name of the organization.
6969
[Parameter(
@@ -81,15 +81,12 @@ filter Get-GitHubEnvironment {
8181
[string] $Repository,
8282

8383
# The name of the environment.
84-
[Parameter(
85-
Mandatory,
86-
ParameterSetName = 'ByName',
87-
ValueFromPipelineByPropertyName
88-
)]
89-
[string] $Name,
84+
[Parameter(ValueFromPipelineByPropertyName)]
85+
[SupportsWildcards()]
86+
[string] $Name = '*',
9087

9188
# The maximum number of environments to return per request.
92-
[Parameter(ParameterSetName = 'List')]
89+
[Parameter()]
9390
[ValidateRange(0, 100)]
9491
[int] $PerPage,
9592

@@ -107,14 +104,8 @@ filter Get-GitHubEnvironment {
107104
}
108105

109106
process {
110-
switch ($PSCmdlet.ParameterSetName) {
111-
'ByName' {
112-
Get-GitHubEnvironmentByName -Owner $Owner -Repository $Repository -Name $Name -Context $Context
113-
}
114-
'List' {
115-
Get-GitHubEnvironmentList -Owner $Owner -Repository $Repository -PerPage $PerPage -Context $Context
116-
}
117-
}
107+
Get-GitHubEnvironmentList -Owner $Owner -Repository $Repository -PerPage $PerPage -Context $Context |
108+
Where-Object { $_.Name -like $Name }
118109
}
119110

120111
end {

src/functions/public/Environments/Remove-GitHubEnvironment.ps1

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,11 @@ filter Remove-GitHubEnvironment {
5757
}
5858

5959
process {
60+
$encodedName = [System.Uri]::EscapeDataString($Name)
6061
$inputObject = @{
61-
Method = 'DELETE'
62-
APIEndpoint = "/repos/$Owner/$Repository/environments/$Name"
63-
Context = $Context
62+
Method = 'DELETE'
63+
Uri = $Context.ApiBaseUri + "/repos/$Owner/$Repository/environments/$encodedName"
64+
Context = $Context
6465
}
6566

6667
if ($PSCmdlet.ShouldProcess("Environment [$Owner/$Repository/$Name]", 'Delete')) {

src/functions/public/Environments/Set-GitHubEnvironment.ps1

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ filter Set-GitHubEnvironment {
2222
WaitTimer = 30
2323
Reviewers = @{ type = $user.Type; id = $user.id }, @{ type = 'team'; id = $team.DatabaseID }
2424
DeploymentBranchPolicy = 'CustomBranchPolicies'
25+
}
2526
Set-GitHubEnvironment @params
2627
2728
Output:
@@ -43,15 +44,18 @@ filter Set-GitHubEnvironment {
4344
Creates or updates the "staging" environment with a 30-minute wait timer.
4445
4546
.OUTPUTS
46-
PSCustomObject
47+
GitHubEnvironment
4748
4849
.NOTES
4950
Returns the response object from the GitHub API call.
5051
5152
.LINK
5253
https://psmodule.io/GitHub/Functions/Environments/Set-GitHubEnvironment/
54+
55+
.LINK
56+
[Create or update an environment](https://docs.github.com/rest/deployments/environments#create-or-update-an-environment)
5357
#>
54-
[OutputType([pscustomobject])]
58+
[OutputType([GitHubEnvironment])]
5559
[CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Default')]
5660
param(
5761
# The name of the organization.
@@ -211,16 +215,31 @@ filter Set-GitHubEnvironment {
211215
$body['prevent_self_review'] = [bool]$PreventSelfReview
212216
}
213217

218+
$encodedName = [System.Uri]::EscapeDataString($Name)
214219
$inputObject = @{
215-
Method = 'PUT'
216-
APIEndpoint = "/repos/$Owner/$Repository/environments/$Name"
217-
Body = $body
218-
Context = $Context
220+
Method = 'PUT'
221+
Uri = $Context.ApiBaseUri + "/repos/$Owner/$Repository/environments/$encodedName"
222+
Body = $body
223+
Context = $Context
219224
}
220225

221226
if ($PSCmdlet.ShouldProcess("Environment [$Owner/$Repository/$Name]", 'Set')) {
222227
Invoke-GitHubAPI @inputObject | ForEach-Object {
223-
Write-Output $_.Response
228+
Write-Output $_.Response | ForEach-Object {
229+
[GitHubEnvironment]@{
230+
Name = $_.name
231+
DatabaseID = $_.id
232+
NodeID = $_.node_id
233+
Url = $_.html_url
234+
Owner = $Owner
235+
Repository = $Repository
236+
CreatedAt = $_.created_at
237+
UpdatedAt = $_.updated_at
238+
CanAdminsBypass = $_.can_admins_bypass
239+
ProtectionRules = $_.protection_rules
240+
DeploymentBranchPolicy = $_.deployment_branch_policy
241+
}
242+
}
224243
}
225244
}
226245
}

tests/Environments.Tests.ps1

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ param()
1414
BeforeAll {
1515
$repoSuffix = 'EnvironmentTest'
1616
$environmentName = 'production'
17+
$os = $env:RUNNER_OS
1718
}
1819

1920
Describe 'As a user - Fine-grained PAT token - user account access (USER_FG_PAT)' {
@@ -43,7 +44,21 @@ Describe 'As a user - Fine-grained PAT token - user account access (USER_FG_PAT)
4344
$result = Set-GitHubEnvironment -Owner $owner -Repository $repo -Name $environmentName -WaitTimer 10
4445
$result | Should -Not -BeNullOrEmpty
4546
$result.Name | Should -Be $environmentName
46-
$result.protection_rules.wait_timer | Should -Be 10
47+
$result.ProtectionRules.wait_timer | Should -Be 10
48+
}
49+
50+
It 'Set-GitHubEnvironment - creates an environment with a slash in the name' {
51+
$result = Set-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os"
52+
$result | Should -Not -BeNullOrEmpty
53+
$result.Name | Should -Be "$environmentName/$os"
54+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Should -Not -BeNullOrEmpty
55+
}
56+
57+
It 'Remove-GitHubEnvironment - deletes an environment with a slash in the name' {
58+
{
59+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Remove-GitHubEnvironment -Confirm:$false
60+
} | Should -Not -Throw
61+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Should -BeNullOrEmpty
4762
}
4863

4964
It 'Get-GitHubEnvironment - retrieves a specific environment' {
@@ -95,7 +110,20 @@ Describe 'As a user - Fine-grained PAT token - organization account access (ORG_
95110
$result = Set-GitHubEnvironment -Owner $owner -Repository $repo -Name $environmentName -WaitTimer 10
96111
$result | Should -Not -BeNullOrEmpty
97112
$result.Name | Should -Be $environmentName
98-
$result.protection_rules.wait_timer | Should -Be 10
113+
$result.ProtectionRules.wait_timer | Should -Be 10
114+
}
115+
116+
It 'Set-GitHubEnvironment - creates an environment with a slash in the name' {
117+
$result = Set-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os"
118+
$result | Should -Not -BeNullOrEmpty
119+
$result.Name | Should -Be "$environmentName/$os"
120+
}
121+
122+
It 'Remove-GitHubEnvironment - deletes an environment with a slash in the name' {
123+
{
124+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Remove-GitHubEnvironment -Confirm:$false
125+
} | Should -Not -Throw
126+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Should -BeNullOrEmpty
99127
}
100128

101129
It 'Get-GitHubEnvironment - retrieves a specific environment' {
@@ -152,7 +180,21 @@ Describe 'As a GitHub App - Enterprise (APP_ENT)' {
152180
$result = Set-GitHubEnvironment -Owner $owner -Repository $repo -Name $environmentName -WaitTimer 10
153181
$result | Should -Not -BeNullOrEmpty
154182
$result.Name | Should -Be $environmentName
155-
$result.protection_rules.wait_timer | Should -Be 10
183+
$result.ProtectionRules.wait_timer | Should -Be 10
184+
}
185+
186+
It 'Set-GitHubEnvironment - creates an environment with a slash in the name' {
187+
$result = Set-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os"
188+
$result | Should -Not -BeNullOrEmpty
189+
$result.Name | Should -Be "$environmentName/$os"
190+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Should -Not -BeNullOrEmpty
191+
}
192+
193+
It 'Remove-GitHubEnvironment - deletes an environment with a slash in the name' {
194+
{
195+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Remove-GitHubEnvironment -Confirm:$false
196+
} | Should -Not -Throw
197+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Should -BeNullOrEmpty
156198
}
157199

158200
It 'Get-GitHubEnvironment - retrieves a specific environment' {
@@ -205,7 +247,21 @@ Describe 'As a GitHub App - Organization (APP_ORG)' {
205247
$result = Set-GitHubEnvironment -Owner $owner -Repository $repo -Name $environmentName -WaitTimer 10
206248
$result | Should -Not -BeNullOrEmpty
207249
$result.Name | Should -Be $environmentName
208-
$result.protection_rules.wait_timer | Should -Be 10
250+
$result.ProtectionRules.wait_timer | Should -Be 10
251+
}
252+
253+
It 'Set-GitHubEnvironment - creates an environment with a slash in the name' {
254+
$result = Set-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os"
255+
$result | Should -Not -BeNullOrEmpty
256+
$result.Name | Should -Be "$environmentName/$os"
257+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Should -Not -BeNullOrEmpty
258+
}
259+
260+
It 'Remove-GitHubEnvironment - deletes an environment with a slash in the name' {
261+
{
262+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Remove-GitHubEnvironment -Confirm:$false
263+
} | Should -Not -Throw
264+
Get-GitHubEnvironment -Owner $owner -Repository $repo -Name "$environmentName/$os" | Should -BeNullOrEmpty
209265
}
210266

211267
It 'Get-GitHubEnvironment - retrieves a specific environment' {

0 commit comments

Comments
 (0)