Skip to content

Commit e01341e

Browse files
🚀 [Feature]: GitHub App creation and installation management (#281)
## Description ### Added functions for Enterprise App management. src/functions/private/Apps/GitHub Apps/Get-GitHubEnterpriseOrganizationAppInstallation.ps1 - Fixes #277 ### General alignments: * Adds a guidance file that defines conventions for a module `CodingStandards.md` - will be promoted to the `docs` repository later. * Remove most re-throw `try{...} catch { throw $_ }` statements. * Fixes #289 * Added `#Requires -Modules` statements to ensure necessary modules are marked as requirements for the module. * Parameter hashtables for Invoke-GitHubAPI is now sorted like: - Method: UPPERCASED - Endpoint - Header related stuff - Body related stuff - Context * Function name aligning: * Parameter name aligning: * Changed `Repo` to `Repository` - throughout the module. The repo abbreviation can still be used, but in classes, object and commands, we standardize on Repository. * Clean up aliases: * Remove all but one alias for Connect/Disconnect-GitHub * Remove org alias for Organization parameters #### Private functions: * Made `Context` mandatory in private functions * Removed `Resolve-GitHubContext` in private functions #### Public functions: - Fixes #297 - Fixes #249 ## 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
1 parent 048b37c commit e01341e

File tree

258 files changed

+4725
-5329
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

258 files changed

+4725
-5329
lines changed

CodingStandard.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# Coding Standards for `GitHub`
2+
3+
Start by reading the general coding standards for [`PSModule`](https://psmodule.io/docs) which is the basis for all modules in the framework.
4+
Additions or adjustments to those defaults are covered in this document to ensure that the modules drive consistancy for all developers.
5+
6+
## General Coding Standards
7+
8+
1. **PowerShell Keywords**
9+
- All PowerShell keywords (e.g. `if`, `return`, `throw`, `function`, `param`) **must** be in lowercase.
10+
11+
2. **Brace Style**
12+
- Use **One True Bracing Style (OTBS)**.
13+
- Opening brace on the same line as the statement; closing brace on its own line.
14+
15+
3. **Coverage**
16+
- We do **not** need 100% coverage of the GitHub API.
17+
- Maintain a separate file listing the endpoints you intentionally **do not** cover, so the coverage report can mark them accordingly (e.g., ⚠️).
18+
19+
4. **Convert Filter Types**
20+
- Wherever filters are used, ensure they are implemented as standard PowerShell functions with `begin`, `process`, and `end` blocks.
21+
22+
---
23+
24+
## Functions
25+
26+
- **Grouping**
27+
- Group functions by the *object type* they handle, using folders named for that object type (e.g. “Repository”), **not** by the API endpoint URL.
28+
29+
- **Naming**
30+
- Public function name format: **`Verb-GitHubNoun`**.
31+
- Private function name format: **`Verb-GitHubNoun`** (same style but no aliases).
32+
- **`Get-`** functions must **not** include `[CmdletBinding(SupportsShouldProcess)]`. You only use `SupportsShouldProcess` on commands that change or remove data (`Set-`, `Remove-`, `Add-`, etc.).
33+
34+
- **Default Parameter Sets**
35+
- Do **not** declare `DefaultParameterSetName = '__AllParameterSets'`.
36+
- Only specify a `DefaultParameterSetName` if it is actually different from the first parameter set.
37+
38+
- **One API Call = One Function**
39+
- If you find that a single function is handling multiple distinct API calls, split it into multiple functions.
40+
41+
- **Public vs. Private**
42+
1. **Public Functions**
43+
- Support pipeline input if appropriate.
44+
- Should begin by calling `Resolve-GitHubContext` to handle the `Context` parameter, which can be either a string or a `GitHubContext` object.
45+
- Use parameter sets (with `begin`, `process`, `end`) if you have multiple ways to call the same logical operation.
46+
- If choosing among multiple underlying private functions, use a `switch` statement in the `process` block keyed on the parameter set name.
47+
- If a parameter like `$Repository` is missing, you can default to `$Context.Repo`. If no value is found, **throw** an error.
48+
2. **Private Functions**
49+
- **No pipeline input**.
50+
- No aliases on either the function or its parameters.
51+
- **`Context` is mandatory** (type `GitHubContext`), since public functions should already have resolved it.
52+
- **`Owner`, `Organization`, `ID`, `Repository`** are also mandatory if required by the endpoint.
53+
- Must not contain logic to default parameters from `Context`; that is resolved in public functions.
54+
55+
---
56+
57+
## Documentation for Functions
58+
59+
All function documentation follows standard PowerShell help conventions, with some notes:
60+
61+
1. **.SYNOPSIS**, **.DESCRIPTION**, **.EXAMPLES**
62+
- Examples in your code should include fencing (e.g., triple backticks) because the PSModule framework removes default fences.
63+
64+
2. **.PARAMETER**
65+
- Do **not** store parameter documentation in a comment block separate from the parameter. Instead, use inline parameter documentation via the `[Parameter()]` attribute and descriptions in triple-slash (`///`) comments above each parameter.
66+
67+
3. **.NOTES**
68+
- Include a link to the official documentation (if any) that the function is based on, so it’s discoverable via online help.
69+
70+
4. **.LINK**
71+
- First link should be the function’s own local documentation (generated for the PowerShell module).
72+
- Additional links can point to official GitHub or API documentation.
73+
74+
---
75+
76+
## Parameter Guidelines
77+
78+
1. **Always Declare [Parameter()]**
79+
- Every parameter must explicitly have a `[Parameter()]` attribute, even if empty.
80+
- Place these attributes in a consistent order (see **Parameter Attributes Order** below).
81+
82+
2. **Parameter Types**
83+
- Always specify a type, e.g. `[string] $Owner` (rather than `$Owner` alone).
84+
85+
3. **Parameter Naming**
86+
- Use **PascalCase** for parameters.
87+
- Convert snake_case from the API docs to **PascalCase** in the function.
88+
- **`ID`** should be the short name. If needed, add an alias for a long form (e.g., `[Alias('SomeLongName')]`) or for a different style (`'id'`, `'Id'`), depending on user expectations.
89+
- If the function name implies the object (e.g., `Get-GitHubRepository`), do **not** name the parameter `RepositoryId`. Just `ID` (or `Name`, etc.) suffices. Keep it object-oriented rather than repeating the context.
90+
- `Owner` should always have the aliases: `Organization` and `User`.
91+
- `Username` can have the alias `Login` if relevant for a particular API.
92+
- Use `Repository` (not `Repo`). If you need an alias for backward compatibility, add `[Alias('Repo')]`.
93+
94+
4. **Parameter Attribute Order**
95+
1. `[Parameter()]`
96+
2. `[ValidateNotNullOrEmpty()]` or other validation attributes
97+
3. `[Alias()]` if any
98+
4. Then the parameter definition itself: `[string] $ParamName`
99+
100+
5. **Parameter Defaulting**
101+
- For **public** functions, if the user hasn’t provided a parameter (like `$Repository`), default it from the context:
102+
```powershell
103+
if (-not $Repository) {
104+
$Repository = $Context.Repo
105+
}
106+
if (-not $Repository) {
107+
throw "Repository not specified and not found in the context."
108+
}
109+
```
110+
- For **private** functions, the calling function should already have done this. Private functions assume mandatory parameters.
111+
112+
6. **Remove `[org]` Alias**
113+
- Do not use `[Alias('org')]` on the `$Organization` parameter. Use `[Alias('User','Organization')]` on `$Owner` instead.
114+
115+
---
116+
117+
## Function Content & Flow
118+
119+
1. **Structure**
120+
- Always use `begin`, `process`, and `end` blocks.
121+
- **`begin`**: Validate parameters, call `Assert-GitHubContext` if needed, set up any local state.
122+
- Add a comment stating which permissions are required for the API call.
123+
- **`process`**: Main logic, including pipeline handling if public.
124+
- **`end`**: Cleanup if necessary.
125+
126+
2. **ShouldProcess**
127+
- Only use `[CmdletBinding(SupportsShouldProcess)]` for commands that create, update, or remove data. **Do not** apply it to `Get-` commands.
128+
129+
3. **API Method Naming**
130+
- Use PascalCase for the method in your splat (e.g., `Post`, `Delete`, `Put`, `Get`).
131+
- The `Method` property in your hashtable to `Invoke-GitHubAPI` (or other REST calls) should reflect that standard.
132+
133+
4. **Splatting**
134+
- Always splat the API call. The standard order in the splat is:
135+
1. `Method`
136+
2. `APIEndpoint` (or `Endpoint`, with `APIEndpoint` as an alias if necessary)
137+
3. `Body`
138+
4. `Context`
139+
- Body is always a hashtable containing the payload for `POST`, `PATCH`, or `PUT` calls.
140+
141+
5. **Removing String Checks**
142+
- Do **not** use `if ([string]::IsNullOrEmpty($Param))`. Instead, check `-not $Param` or rely on `[ValidateNotNullOrEmpty()]`.
143+
144+
6. **Pipeline Output**
145+
- After calling `Invoke-GitHubAPI @inputObject`, you can **either**:
146+
- `ForEach-Object { Write-Output $_.Response }`
147+
- or `Select-Object -ExpandProperty Response`
148+
- Choose which pattern best fits your scenario, but be consistent within a function.
149+
150+
---
151+
152+
## Classes
153+
154+
1. **One Class per Resource**
155+
- Each distinct resource type gets its own `.ps1` or `.psm1` with a single class definition.
156+
157+
2. **Property and Method Naming**
158+
- Use PascalCase for all public properties and methods.
159+
160+
3. **Return Types / Interfaces**
161+
- Each class that you return should have a consistent interface.
162+
- Remove any properties that are purely “API wrapper” fields (e.g., raw HTTP artifacts that aren’t relevant to the user).
163+
164+
---
165+
166+
## Additional Notes
167+
168+
1. **Endpoint Coverage File**
169+
- Maintain a list of endpoints you’re deliberately **not** implementing, so that your coverage reporting can include a ⚠️ for them.
170+
171+
2. **Parameter Name Design**
172+
- Use object-oriented naming that reflects the entity. For example, if the function is `Remove-GitHubRepository`, simply use `-ID` (or `-Name`) rather than `-RepositoryID`.
173+
174+
3. **Aliases**
175+
- Private functions have **no** aliases (function-level or parameter-level).
176+
- Public functions can add aliases where it makes sense (`Owner` has `-User`/`-Organization`, `Repository` might have `-Repo` alias if needed, `Username` might have `-Login`).
177+
178+
4. **Mandatory Context for Private**
179+
- Private functions must always expect a resolved `[GitHubContext] $Context`. Public functions handle any string-based or null context resolution logic.
180+
181+
5. **We Do Not Have to Cover Every Possible API**
182+
- Some endpoints (e.g., “hovercards” or other rarely used features) can be excluded.
183+
184+
---
185+
186+
That’s it. This spec captures all the bullet points and original guidelines in one place. Use it as the authoritative reference for coding style, function naming, parameter declarations, and general best practices in your module.

examples/Apps/AppManagement.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
$appIDs = @(
33
'Iv1.f26b61bc99e69405'
44
)
5-
$orgs = Get-GitHubEnterpriseInstallableOrganization -Enterprise 'msx'
5+
$orgs = Get-GitHubAppInstallableOrganization -Enterprise 'msx'
66
foreach ($org in $orgs) {
77
foreach ($appID in $appIDs) {
88
Install-GitHubAppOnEnterpriseOrganization -Enterprise msx -Organization $org.login -ClientID $appID -RepositorySelection all

examples/Apps/EnterpriseApps.ps1

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,8 @@ filter Install-GithubApp {
1919
[string] $AppID
2020
)
2121

22-
begin {
23-
24-
}
25-
2622
process {
27-
$installableOrgs = Get-GitHubEnterpriseInstallableOrganization -Enterprise $Enterprise -Debug -Verbose
23+
$installableOrgs = Get-GitHubAppInstallableOrganization -Enterprise $Enterprise -Debug -Verbose
2824
$orgs = $installableOrgs | Where-Object { $_.login -like $organization }
2925
foreach ($org in $orgs) {
3026
foreach ($appIDitem in $AppID) {
@@ -37,12 +33,8 @@ filter Install-GithubApp {
3733
}
3834
}
3935
}
40-
41-
end {
42-
43-
}
4436
}
4537

46-
$appIDs | Install-GithubApp -Organization $organization -Debug -Verbose
38+
$appIDs | Install-GitHubApp -Organization $organization -Debug -Verbose
4739

4840
$installation = Get-GitHubAppInstallation

examples/Connecting.ps1

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
###
1+
#Requires -Modules @{ ModuleName = 'Context'; RequiredVersion = '6.0.0' }
2+
#Requires -Modules @{ ModuleName = 'Microsoft.PowerShell.SecretManagement'; RequiredVersion = '1.1.2' }
3+
4+
###
25
### CONNECTING
36
###
47

examples/Teams/Get-AllTeams.ps1

Lines changed: 0 additions & 1 deletion
This file was deleted.

scripts/Update-CoverageReport.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#Requires -Modules MarkdownPS
1+
#Requires -Modules @{ ModuleName = 'MarkdownPS'; RequiredVersion = '1.10' }
22

33
[CmdletBinding()]
44
param()

src/classes/public/Config/GitHubConfig.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
# The default value for the HTTP protocol version.
2424
[string] $HttpVersion
2525

26-
# The default value for the 'per_page' API parameter used in 'Get' functions that support paging.
26+
# The default value for the 'per_page' API parameter used in 'GET' functions that support paging.
2727
[int] $PerPage
2828

2929
# Simple parameterless constructor

src/classes/public/Context/GitHubContext.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@
5353
# The default value for the Owner parameter.
5454
[string] $Owner
5555

56-
# The default value for the Repo parameter.
57-
[string] $Repo
56+
# The default value for the Repository parameter.
57+
[string] $Repository
5858

5959
# The default value for the HTTP protocol version.
6060
[string] $HttpVersion
6161

62-
# The default value for the 'per_page' API parameter used in 'Get' functions that support paging.
62+
# The default value for the 'per_page' API parameter used in 'GET' functions that support paging.
6363
[int] $PerPage
6464

6565
# Simple parameterless constructor

src/functions/private/Actions/Get-GitHubWorkflowRunByRepo.ps1

Lines changed: 26 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@
1212
`created`, `event`, `head_sha`, `status`.
1313
1414
.EXAMPLE
15-
Get-GitHubWorkflowRunByRepo -Owner 'owner' -Repo 'repo'
15+
Get-GitHubWorkflowRunByRepo -Owner 'owner' -Repository 'repo'
1616
1717
Lists all workflow runs for a repository.
1818
1919
.EXAMPLE
20-
Get-GitHubWorkflowRunByRepo -Owner 'owner' -Repo 'repo' -Actor 'octocat' -Branch 'main' -Event 'push' -Status 'success'
20+
Get-GitHubWorkflowRunByRepo -Owner 'owner' -Repository 'repo' -Actor 'octocat' -Branch 'main' -Event 'push' -Status 'success'
2121
2222
Lists all workflow runs for a repository with the specified actor, branch, event, and status.
2323
2424
.NOTES
2525
[List workflow runs for a repository](https://docs.github.com/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-repository)
2626
#>
27-
[CmdletBinding(DefaultParameterSetName = 'Repo')]
27+
[CmdletBinding()]
2828
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains a long link.')]
2929
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', 'Event',
3030
Justification = 'A parameter that is used in the api call.')]
@@ -35,7 +35,7 @@
3535

3636
# The name of the repository. The name is not case sensitive.
3737
[Parameter(Mandatory)]
38-
[string] $Repo,
38+
[string] $Repository,
3939

4040
# Returns someone's workflow runs. Use the login for the user who created the push associated with the check suite or workflow run.
4141
[Parameter()]
@@ -82,53 +82,38 @@
8282
[int] $PerPage,
8383

8484
# The context to run the command in. Used to get the details for the API call.
85-
# Can be either a string or a GitHubContext object.
86-
[Parameter()]
87-
[object] $Context = (Get-GitHubContext)
85+
[Parameter(Mandatory)]
86+
[object] $Context
8887
)
8988

9089
begin {
9190
$stackPath = Get-PSCallStackPath
9291
Write-Debug "[$stackPath] - Start"
93-
$Context = Resolve-GitHubContext -Context $Context
9492
Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
95-
if ([string]::IsNullOrEmpty($Owner)) {
96-
$Owner = $Context.Owner
93+
}
94+
95+
process {
96+
$body = @{
97+
actor = $Actor
98+
branch = $Branch
99+
event = $Event
100+
status = $Status
101+
created = $Created
102+
exclude_pull_requests = $ExcludePullRequests
103+
check_suite_id = $CheckSuiteID
104+
head_sha = $HeadSHA
105+
per_page = $PerPage
97106
}
98-
Write-Debug "Owner: [$Owner]"
99107

100-
if ([string]::IsNullOrEmpty($Repo)) {
101-
$Repo = $Context.Repo
108+
$inputObject = @{
109+
Method = 'GET'
110+
APIEndpoint = "/repos/$Owner/$Repository/actions/runs"
111+
Body = $body
112+
Context = $Context
102113
}
103-
Write-Debug "Repo: [$Repo]"
104-
}
105114

106-
process {
107-
try {
108-
$body = @{
109-
actor = $Actor
110-
branch = $Branch
111-
event = $Event
112-
status = $Status
113-
created = $Created
114-
exclude_pull_requests = $ExcludePullRequests
115-
check_suite_id = $CheckSuiteID
116-
head_sha = $HeadSHA
117-
per_page = $PerPage
118-
}
119-
120-
$inputObject = @{
121-
Context = $Context
122-
APIEndpoint = "/repos/$Owner/$Repo/actions/runs"
123-
Method = 'GET'
124-
Body = $body
125-
}
126-
127-
Invoke-GitHubAPI @inputObject | ForEach-Object {
128-
Write-Output $_.Response.workflow_runs
129-
}
130-
} catch {
131-
throw $_
115+
Invoke-GitHubAPI @inputObject | ForEach-Object {
116+
Write-Output $_.Response.workflow_runs
132117
}
133118
}
134119

0 commit comments

Comments
 (0)