Skip to content

Commit 1ee97bb

Browse files
🚀 [Minor]: GitHub API rate limit details now available in action logs (#89)
GitHub API rate limit consumption is now visible directly in the action logs. When enabled, rate limit details - including remaining quota, limit, used count, and reset time for all resource categories - are displayed before and after the user script runs, making it easy to see exactly how many API calls a workflow step consumed. - Fixes #88 ## New: Rate limit visibility in action logs A new `ShowRateLimit` input (default: `'false'`) controls whether rate limit information appears in the logs. When set to `'true'`, a **Rate Limits** LogGroup appears inside the Info fence before the user script, and another **Rate Limits** LogGroup appears inside the Outputs fence after it. ```yaml - uses: PSModule/GitHub-Script@v1 with: ShowRateLimit: 'true' Script: | Get-GitHubRepository -Owner PSModule -Name GitHub-Script ``` The output includes a formatted table of all resource categories returned by `Get-GitHubRateLimit` (core, search, graphql, etc.), each showing `Limit`, `Used`, `Remaining`, `ResetsAt`, and `ResetsIn`. When the input is omitted or set to `'false'` (the default), no rate limit output appears. If `ShowRateLimit` is enabled but `ShowInfo` or `ShowOutput` is off, the corresponding fence still renders with just the rate limit content inside. For auth types that do not support `Get-GitHubRateLimit` (for example GitHub App contexts), a warning is shown instead of failing. ## Technical Details - Added `ShowRateLimit` input to `action.yml` with `required: false` and `default: 'false'`. - Added `PSMODULE_GITHUB_SCRIPT_INPUT_ShowRateLimit` environment variable to the composite step. - Created `src/ratelimit.ps1` as a helper script (no fence borders) that checks the guard and renders a single `Rate Limits` LogGroup. - `src/ratelimit.ps1` now calls `Get-GitHubRateLimit -ErrorAction Stop` so non-terminating errors are caught reliably in unsupported auth contexts. - `src/ratelimit.ps1` explicitly selects `Name`, `Limit`, `Used`, `Remaining`, `ResetsAt`, and `ResetsIn` before formatting to keep columns deterministic. - Modified `src/info.ps1`: adjusted the early-return guard to also consider `ShowRateLimit`, wrapped existing LogGroups in `if ($showInfo)`, and calls `ratelimit.ps1` before the fence close. - Modified `src/outputs.ps1`: adjusted the early-return guard to also consider `ShowRateLimit`, wrapped existing output LogGroups in `if ($result)`, and calls `ratelimit.ps1` before the fence close. - The `action.yml` run block remains in the same flow, while `info.ps1` and `outputs.ps1` invoke the helper internally. - Enabled `ShowRateLimit: true` across all Action-Test scenarios in `.github/workflows/TestWorkflow.yml`, including Basic, WithScript path variants, Commands + Outputs, Matrix Creator, WithoutToken, WithPAT, WithUserFGPAT, WithOrgFGPAT, GitHubAppEnt, GitHubAppOrg + quoted inputs, WithKeyVaultKeyReference, WithKeyVaultKeyReferenceLatest, and PreserveCredentials False. --------- Co-authored-by: anthropic-code-agent[bot] <242468646+Claude@users.noreply.github.com>
1 parent 8649c46 commit 1ee97bb

6 files changed

Lines changed: 124 additions & 46 deletions

File tree

.github/workflows/TestWorkflow.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ jobs:
6262
Prerelease: ${{ inputs.Prerelease }}
6363
Debug: true
6464
Verbose: true
65+
ShowRateLimit: true
6566

6667
- name: Action-Test [ShowInit]
6768
uses: ./
@@ -70,6 +71,7 @@ jobs:
7071
Debug: true
7172
Verbose: true
7273
ShowInit: true
74+
ShowRateLimit: true
7375

7476
ActionTestWithScript:
7577
name: WithScript
@@ -95,48 +97,55 @@ jobs:
9597
with:
9698
Script: tests/info.ps1
9799
Prerelease: ${{ inputs.Prerelease }}
100+
ShowRateLimit: true
98101

99102
- name: Action-Test [.\tests\info.ps1]
100103
if: success() || failure()
101104
uses: ./
102105
with:
103106
Script: .\tests\info.ps1
104107
Prerelease: ${{ inputs.Prerelease }}
108+
ShowRateLimit: true
105109

106110
- name: Action-Test [./tests/info.ps1]
107111
if: success() || failure()
108112
uses: ./
109113
with:
110114
Script: ./tests/info.ps1
111115
Prerelease: ${{ inputs.Prerelease }}
116+
ShowRateLimit: true
112117

113118
- name: Action-Test [. .\tests\info.ps1]
114119
if: success() || failure()
115120
uses: ./
116121
with:
117122
Script: . .\tests\info.ps1
118123
Prerelease: ${{ inputs.Prerelease }}
124+
ShowRateLimit: true
119125

120126
- name: Action-Test [. ./tests/info.ps1]
121127
if: success() || failure()
122128
uses: ./
123129
with:
124130
Script: . ./tests/info.ps1
125131
Prerelease: ${{ inputs.Prerelease }}
132+
ShowRateLimit: true
126133

127134
- name: Action-Test [. '.\tests\info.ps1']
128135
if: success() || failure()
129136
uses: ./
130137
with:
131138
Script: . '.\tests\info.ps1'
132139
Prerelease: ${{ inputs.Prerelease }}
140+
ShowRateLimit: true
133141

134142
- name: Action-Test [. './tests/info.ps1']
135143
if: success() || failure()
136144
uses: ./
137145
with:
138146
Script: . './tests/info.ps1'
139147
Prerelease: ${{ inputs.Prerelease }}
148+
ShowRateLimit: true
140149

141150
ActionTestCommands:
142151
name: Commands + Outputs
@@ -159,6 +168,7 @@ jobs:
159168
Prerelease: ${{ inputs.Prerelease }}
160169
ShowInit: true
161170
ShowOutput: true
171+
ShowRateLimit: true
162172
Script: |
163173
LogGroup 'Get-GitHubZen' {
164174
$cat = Get-GitHubOctocat
@@ -339,6 +349,7 @@ jobs:
339349
Prerelease: true
340350
ShowInit: true
341351
ShowOutput: true
352+
ShowRateLimit: true
342353
Script: |
343354
LogGroup 'MatrixTest' {
344355
$matrixTest = @{
@@ -398,6 +409,7 @@ jobs:
398409
with:
399410
Token: ''
400411
Prerelease: ${{ inputs.Prerelease }}
412+
ShowRateLimit: true
401413
Script: |
402414
LogGroup 'My group' {
403415
'This is a group'
@@ -417,6 +429,7 @@ jobs:
417429
with:
418430
Token: ${{ secrets.TEST_USER_PAT }}
419431
Prerelease: ${{ inputs.Prerelease }}
432+
ShowRateLimit: true
420433
Script: |
421434
LogGroup 'Get-GitHubUser' {
422435
Get-GitHubUser -Debug | Format-Table -AutoSize | Out-String
@@ -444,6 +457,7 @@ jobs:
444457
with:
445458
Token: ${{ secrets.TEST_USER_USER_FG_PAT }}
446459
Prerelease: ${{ inputs.Prerelease }}
460+
ShowRateLimit: true
447461
Script: |
448462
LogGroup 'Get-GitHubUser' {
449463
Get-GitHubUser | Format-Table -AutoSize | Out-String
@@ -471,6 +485,7 @@ jobs:
471485
with:
472486
Token: ${{ secrets.TEST_USER_ORG_FG_PAT }}
473487
Prerelease: ${{ inputs.Prerelease }}
488+
ShowRateLimit: true
474489
Script: |
475490
LogGroup 'Get-GitHubUser' {
476491
Get-GitHubUser | Format-Table -AutoSize | Out-String
@@ -499,6 +514,7 @@ jobs:
499514
ClientID: ${{ secrets.TEST_APP_ENT_CLIENT_ID }}
500515
PrivateKey: ${{ secrets.TEST_APP_ENT_PRIVATE_KEY }}
501516
Prerelease: ${{ inputs.Prerelease }}
517+
ShowRateLimit: true
502518
Script: |
503519
LogGroup 'Get-GitHubApp' {
504520
Get-GitHubApp | Format-List | Out-String
@@ -535,6 +551,7 @@ jobs:
535551
ClientID: '${{ secrets.TEST_APP_ORG_CLIENT_ID }}' # Test with quotes on input
536552
PrivateKey: '${{ secrets.TEST_APP_ORG_PRIVATE_KEY }}' # Test with quotes on input
537553
Prerelease: ${{ inputs.Prerelease }}
554+
ShowRateLimit: true
538555
Script: |
539556
LogGroup 'Get-GitHubApp' {
540557
Get-GitHubApp | Format-List | Out-String
@@ -581,6 +598,7 @@ jobs:
581598
ClientID: ${{ secrets.TEST_APP_ORG_CLIENT_ID }}
582599
KeyVaultKeyReference: 'https://psmodule-test-vault.vault.azure.net/keys/psmodule-org-app/569ae34250e64adca6a2b2d159d454a5'
583600
Prerelease: ${{ inputs.Prerelease }}
601+
ShowRateLimit: true
584602
Script: |
585603
LogGroup 'Context details' {
586604
Get-GitHubContext | Select-Object * | Out-String
@@ -631,6 +649,7 @@ jobs:
631649
ClientID: ${{ secrets.TEST_APP_ORG_CLIENT_ID }}
632650
KeyVaultKeyReference: 'https://psmodule-test-vault.vault.azure.net/keys/psmodule-org-app/'
633651
Prerelease: ${{ inputs.Prerelease }}
652+
ShowRateLimit: true
634653
Script: |
635654
LogGroup 'Context details' {
636655
Get-GitHubContext | Select-Object * | Out-String
@@ -671,6 +690,7 @@ jobs:
671690
Token: ${{ secrets.TEST_USER_PAT }}
672691
PreserveCredentials: false
673692
Prerelease: ${{ inputs.Prerelease }}
693+
ShowRateLimit: true
674694
Script: |
675695
LogGroup 'Get-GitHubUser with credentials that will be cleaned up' {
676696
Get-GitHubUser | Format-Table -AutoSize | Out-String

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ To get started with your own GitHub PowerShell based action, [create a new repos
2424
| `ShowInfo` | Show information about the environment. | false | `'true'` |
2525
| `ShowInit` | Show information about the initialization. | false | `'false'` |
2626
| `ShowOutput` | Show the script's output. | false | `'false'` |
27+
| `ShowRateLimit` | Show GitHub API rate limit information before and after script execution. | false | `'false'` |
2728
| `WorkingDirectory` | The working directory where the script runs. | false | `'.'` |
2829
| `PreserveCredentials` | Preserve credentials after script execution. If false, disconnects GitHub contexts and CLI using Disconnect-GitHubAccount. | false | `'true'` |
2930

@@ -243,3 +244,16 @@ Runs a script with `PreserveCredentials` set to `false` to automatically disconn
243244
Get-GitHubUser
244245
# Credentials will be disconnected after this step
245246
```
247+
248+
#### Example 8: Show GitHub API rate limit usage
249+
250+
Displays the GitHub API rate limit status before and after the script runs. The **Rate Limits** log group shows `Limit`, `Used`, `Remaining`, `ResetsAt`, and `ResetsIn` for every resource category (`core`, `search`, `graphql`, etc.), making it easy to see exactly how many API calls a workflow step consumed.
251+
252+
```yaml
253+
- name: Run script with rate limit visibility
254+
uses: PSModule/GitHub-Script@v1
255+
with:
256+
ShowRateLimit: 'true'
257+
Script: |
258+
Get-GitHubRepository -Owner PSModule -Name GitHub-Script
259+
```

action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ inputs:
5353
description: Show the output of the script.
5454
required: false
5555
default: 'false'
56+
ShowRateLimit:
57+
description: Show GitHub API rate limit information before and after script execution.
58+
required: false
59+
default: 'false'
5660
ErrorView:
5761
description: Configure the PowerShell `$ErrorView` variable. You can use full names ('NormalView', 'CategoryView', 'ConciseView', 'DetailedView'). It matches on partials.
5862
required: false
@@ -91,6 +95,7 @@ runs:
9195
PSMODULE_GITHUB_SCRIPT_INPUT_ShowInfo: ${{ inputs.ShowInfo }}
9296
PSMODULE_GITHUB_SCRIPT_INPUT_ShowOutput: ${{ inputs.ShowOutput }}
9397
PSMODULE_GITHUB_SCRIPT_INPUT_Prerelease: ${{ inputs.Prerelease }}
98+
PSMODULE_GITHUB_SCRIPT_INPUT_ShowRateLimit: ${{ inputs.ShowRateLimit }}
9499
PSMODULE_GITHUB_SCRIPT_INPUT_ErrorView: ${{ inputs.ErrorView }}
95100
PSMODULE_GITHUB_SCRIPT_INPUT_PreserveCredentials: ${{ inputs.PreserveCredentials }}
96101
run: |

src/info.ps1

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,49 +12,57 @@ process {
1212
try {
1313
$fenceTitle = $env:PSMODULE_GITHUB_SCRIPT_INPUT_Name
1414

15-
Write-Debug "[$scriptName] - ShowInfo: $env:PSMODULE_GITHUB_SCRIPT_INPUT_ShowInfo"
16-
if ($env:PSMODULE_GITHUB_SCRIPT_INPUT_ShowInfo -ne 'true') {
15+
$showInfo = $env:PSMODULE_GITHUB_SCRIPT_INPUT_ShowInfo -eq 'true'
16+
$showRateLimit = $env:PSMODULE_GITHUB_SCRIPT_INPUT_ShowRateLimit -eq 'true'
17+
18+
Write-Debug "[$scriptName] - ShowInfo: $showInfo"
19+
Write-Debug "[$scriptName] - ShowRateLimit: $showRateLimit"
20+
if (-not $showInfo -and -not $showRateLimit) {
1721
return
1822
}
1923

2024
$fenceStart = "┏━━┫ $fenceTitle - Info ┣━━━━━━━━┓"
2125
Write-Output $fenceStart
2226

23-
LogGroup ' - Installed modules' {
24-
Get-InstalledPSResource | Select-Object Name, Version, Prerelease | Sort-Object -Property Name | Format-Table -AutoSize | Out-String
25-
}
27+
if ($showInfo) {
28+
LogGroup ' - Installed modules' {
29+
Get-InstalledPSResource | Select-Object Name, Version, Prerelease | Sort-Object -Property Name | Format-Table -AutoSize | Out-String
30+
}
2631

27-
LogGroup ' - GitHub connection - Default' {
28-
$context = Get-GitHubContext
29-
$context | Format-List | Out-String
30-
31-
Write-Verbose "Token? [$([string]::IsNullOrEmpty($env:PSMODULE_GITHUB_SCRIPT_INPUT_Token))]"
32-
Write-Verbose "AuthType? [$($context.AuthType)] - [$($context.AuthType -ne 'APP')]"
33-
Write-Verbose "gh auth? [$($context.AuthType -ne 'APP' -and -not [string]::IsNullOrEmpty($env:PSMODULE_GITHUB_SCRIPT_INPUT_Token))]"
34-
35-
if ($context.AuthType -ne 'APP' -and -not [string]::IsNullOrEmpty($env:PSMODULE_GITHUB_SCRIPT_INPUT_Token)) {
36-
Write-Output 'GitHub CLI status:'
37-
$before = $LASTEXITCODE
38-
gh auth status
39-
if ($LASTEXITCODE -ne $before) {
40-
Write-Warning "LASTEXITCODE has changed [$LASTEXITCODE]"
41-
$global:LASTEXITCODE = $before
32+
LogGroup ' - GitHub connection - Default' {
33+
$context = Get-GitHubContext
34+
$context | Format-List | Out-String
35+
36+
Write-Verbose "Token? [$([string]::IsNullOrEmpty($env:PSMODULE_GITHUB_SCRIPT_INPUT_Token))]"
37+
Write-Verbose "AuthType? [$($context.AuthType)] - [$($context.AuthType -ne 'APP')]"
38+
Write-Verbose "gh auth? [$($context.AuthType -ne 'APP' -and -not [string]::IsNullOrEmpty($env:PSMODULE_GITHUB_SCRIPT_INPUT_Token))]"
39+
40+
if ($context.AuthType -ne 'APP' -and -not [string]::IsNullOrEmpty($env:PSMODULE_GITHUB_SCRIPT_INPUT_Token)) {
41+
Write-Output 'GitHub CLI status:'
42+
$before = $LASTEXITCODE
43+
gh auth status
44+
if ($LASTEXITCODE -ne $before) {
45+
Write-Warning "LASTEXITCODE has changed [$LASTEXITCODE]"
46+
$global:LASTEXITCODE = $before
47+
}
4248
}
4349
}
44-
}
4550

46-
LogGroup ' - GitHub connection - List' {
47-
Get-GitHubContext -ListAvailable | Format-Table | Out-String
48-
}
51+
LogGroup ' - GitHub connection - List' {
52+
Get-GitHubContext -ListAvailable | Format-Table | Out-String
53+
}
4954

50-
LogGroup ' - Configuration' {
51-
Get-GitHubConfig | Format-List | Out-String
52-
}
55+
LogGroup ' - Configuration' {
56+
Get-GitHubConfig | Format-List | Out-String
57+
}
5358

54-
LogGroup ' - Event Information' {
55-
Get-GitHubEventData | Format-List | Out-String
59+
LogGroup ' - Event Information' {
60+
Get-GitHubEventData | Format-List | Out-String
61+
}
5662
}
5763

64+
& "$PSScriptRoot/ratelimit.ps1"
65+
5866
$fenceEnd = '' + ('' * ($fenceStart.Length - 2)) + ''
5967
Write-Output $fenceEnd
6068
} catch {

src/outputs.ps1

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,47 @@ Write-Debug "[$scriptName] - Start"
99
try {
1010
$fenceTitle = $env:PSMODULE_GITHUB_SCRIPT_INPUT_Name
1111

12-
Write-Debug "[$scriptName] - ShowOutput: $env:PSMODULE_GITHUB_SCRIPT_INPUT_ShowOutput"
13-
if ($env:PSMODULE_GITHUB_SCRIPT_INPUT_ShowOutput -ne 'true') {
14-
return
12+
$showOutput = $env:PSMODULE_GITHUB_SCRIPT_INPUT_ShowOutput -eq 'true'
13+
$showRateLimit = $env:PSMODULE_GITHUB_SCRIPT_INPUT_ShowRateLimit -eq 'true'
14+
15+
Write-Debug "[$scriptName] - ShowOutput: $showOutput"
16+
Write-Debug "[$scriptName] - ShowRateLimit: $showRateLimit"
17+
18+
$result = $null
19+
$hasResult = $false
20+
if ($showOutput) {
21+
$result = (Get-GitHubOutput).result
22+
$hasResult = [bool]$result
23+
Write-Debug "[$scriptName] - ResultPresent: $hasResult"
1524
}
1625

17-
$result = (Get-GitHubOutput).result
18-
Write-Debug "[$scriptName] - Result: $(-not $result)"
19-
if (-not $result) {
26+
if (-not $hasResult -and -not $showRateLimit) {
2027
return
2128
}
29+
2230
$fenceStart = "┏━━┫ $fenceTitle - Outputs ┣━━━━━┓"
2331
Write-Output $fenceStart
24-
if ([string]::IsNullOrEmpty($env:GITHUB_ACTION)) {
25-
Write-GitHubWarning 'Outputs cannot be accessed as the step has no ID.'
26-
}
2732

28-
if (-not (Test-Path -Path $env:GITHUB_OUTPUT)) {
29-
Write-Warning "File not found: $env:GITHUB_OUTPUT"
30-
}
33+
if ($hasResult) {
34+
if ([string]::IsNullOrEmpty($env:GITHUB_ACTION)) {
35+
Write-GitHubWarning 'Outputs cannot be accessed as the step has no ID.'
36+
}
3137

32-
foreach ($output in $result.PSObject.Properties) {
33-
$blue = $PSStyle.Foreground.Blue
34-
$reset = $PSStyle.Reset
35-
LogGroup " - $blue$($output.Name)$reset" {
36-
$output.Value | Format-List | Out-String
38+
if (-not (Test-Path -Path $env:GITHUB_OUTPUT)) {
39+
Write-Warning "File not found: $env:GITHUB_OUTPUT"
40+
}
41+
42+
foreach ($output in $result.PSObject.Properties) {
43+
$blue = $PSStyle.Foreground.Blue
44+
$reset = $PSStyle.Reset
45+
LogGroup " - $blue$($output.Name)$reset" {
46+
$output.Value | Format-List | Out-String
47+
}
3748
}
3849
}
50+
51+
& "$PSScriptRoot/ratelimit.ps1"
52+
3953
$fenceEnd = '' + ('' * ($fenceStart.Length - 2)) + ''
4054
Write-Output $fenceEnd
4155
} catch {

src/ratelimit.ps1

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#Requires -Modules GitHub
2+
3+
# Helper script - called from info.ps1 and outputs.ps1 to display rate limit information.
4+
5+
if ($env:PSMODULE_GITHUB_SCRIPT_INPUT_ShowRateLimit -ne 'true') {
6+
return
7+
}
8+
9+
LogGroup ' - Rate Limits' {
10+
try {
11+
Get-GitHubRateLimit -ErrorAction Stop |
12+
Select-Object Name, Limit, Used, Remaining, ResetsAt, ResetsIn |
13+
Format-Table -AutoSize | Out-String
14+
} catch {
15+
Write-Warning "Could not retrieve rate limit information: $($_.Exception.Message)"
16+
}
17+
}

0 commit comments

Comments
 (0)