1+ param (
2+ [Parameter (Mandatory )]
3+ [string ] $repo ,
4+ [Parameter (Mandatory )]
5+ [string ] $token ,
6+ [Parameter (Mandatory )]
7+ [string ] $keepDays
8+ )
9+
10+ $baseUri = " https://api.github.com"
11+ $repoBaseUri = " $baseUri /repos/$repo "
12+ $actionsBaseUri = " $repoBaseUri /actions"
13+ $runsBaseUri = " $actionsBaseUri /runs"
14+
15+ $headers = @ {
16+ Authorization = " Bearer $token "
17+ Accept = " application/vnd.github+json"
18+ }
19+
20+ function Get () {
21+ param (
22+ [string ] $uri
23+ )
24+ return Invoke-RestMethod - Uri $uri - Headers $headers - Method Get
25+ }
26+
27+ function DeleteRuns () {
28+ param (
29+ [System.Collections.ArrayList ] $runIds
30+ )
31+
32+ foreach ($id in $runIds ) {
33+ Write-Host " Deleting run $id "
34+ $deleteUri = " $runsBaseUri /$id "
35+ Invoke-RestMethod - Uri $deleteUri - Headers $headers - Method Delete
36+ }
37+ }
38+
39+ #
40+ # Gets all workflow runs, finds among them the ones that meet deletion requirements
41+ # (inactive workflow, closed pull-request or older than required days)
42+ # and sorts them into several buckets - "inactive", "pull_request", "workflow_dispatch", "push"
43+ # and "schedule"
44+ #
45+ function GetWorkflowRunsForDeletion ()
46+ {
47+ [OutputType ([System.Collections.Generic.Dictionary [System.String , System.Collections.ArrayList ]])]
48+ param (
49+ [System.Int32 ] $storeDays
50+ )
51+
52+ [System.Collections.Generic.HashSet [int ]]$inactiveWorkflows = New-Object System.Collections.Generic.HashSet[int ]
53+
54+ $allWorkflows = Invoke-RestMethod - Uri " $actionsBaseUri /workflows" - Headers $headers - Method Get
55+
56+ # number of workflows is less then number of runs
57+ # so more efficient to get them all and find inactive ones
58+ foreach ($wf in $allWorkflows.workflows ) {
59+ if ($wf.state -ne " active" ) {
60+ $inactiveWorkflows.Add ($wf.id ) | Out-Null ;
61+ }
62+ }
63+
64+ [System.Collections.Generic.Dictionary [System.String , System.Collections.ArrayList ]]$result = New-Object System.Collections.Generic.Dictionary" [System.String, System.Collections.ArrayList]"
65+
66+ # keys of the dictionary equal to events of workflows
67+ $result [" pull_request" ] = New-Object System.Collections.ArrayList
68+ $result [" workflow_dispatch" ] = New-Object System.Collections.ArrayList
69+ $result [" push" ] = New-Object System.Collections.ArrayList
70+ $result [" schedule" ] = New-Object System.Collections.ArrayList
71+ # special bucket
72+ $result [" inactive" ] = New-Object System.Collections.ArrayList
73+
74+
75+ $page = 1
76+ $per_page = 100
77+
78+ do {
79+ $uri = " $runsBaseUri " + " ?page=$page &per_page=$per_page "
80+ $response = Invoke-RestMethod - Uri $uri - Headers $headers - Method Get
81+
82+ if ($response.total_count -eq 0 ) {
83+ return $result
84+ }
85+
86+ [System.DateTime ]$created = (Get-Date ).AddDays(- $storeDays )
87+
88+ foreach ($run in $response.workflow_runs ) {
89+ if ($result.ContainsKey ($run.event ) -eq $true ) {
90+ # Doesn't matter how old the run is - if the workflow is inactive
91+ # put it for deletion
92+ if ($inactiveWorkflows.Contains ($run.workflow_id )) {
93+ $result [" inactive" ].Add($run ) | Out-Null
94+ }
95+ else {
96+ if ($run.event -eq " pull_request" ) {
97+ # for PRs we collect only closed ones
98+ if ($run.pull_requests.Count -eq 0 ) {
99+ $result [$run.event ].Add($run ) | Out-Null
100+ }
101+ }
102+ else {
103+ # for the rest, we apply date filter
104+ $created_at = [System.DateTime ]::Parse($run.created_at )
105+ if ($created_at -lt $created ) {
106+ $result [$run.event ].Add($run ) | Out-Null
107+ }
108+ }
109+ }
110+ }
111+ }
112+
113+ $page ++
114+ } while ($response.workflow_runs.Count -eq $per_page )
115+
116+ return $result
117+ }
118+
119+ #
120+ # Deletes runs of inactive workflows (of pull_request, push, workflow_dispatch or schedule event)
121+ #
122+ function DeleteRunsOfInactiveWorkflows () {
123+ param (
124+ [System.Collections.Generic.Dictionary [System.String , System.Collections.ArrayList ]] $groups
125+ )
126+
127+ [System.Collections.ArrayList ]$runs = $groups [" inactive" ]
128+
129+ if ($runs.Count -eq 0 ) {
130+ Write-Host " No runs of inactive workflows. Skipping"
131+ return
132+ }
133+
134+ Write-Host " Deleting runs of inactive workflows"
135+ $run_ids = $runs | Select-Object - ExpandProperty id
136+ DeleteRuns $run_ids
137+ }
138+
139+ #
140+ # Deletes runs of closed pull-requests
141+ #
142+ function DeleteRunsForClosedPR () {
143+ param (
144+ [System.Collections.Generic.Dictionary [System.String , System.Collections.ArrayList ]] $groups
145+ )
146+
147+ [System.Collections.ArrayList ]$runs = $groups [" pull_request" ]
148+
149+ if ($runs.Count -eq 0 ) {
150+ Write-Host " No runs for closed pull requests. Skipping"
151+ return
152+ }
153+
154+ Write-Host " Deleting runs for closed pull requests"
155+ $run_ids = $runs | Select-Object - ExpandProperty id
156+ DeleteRuns $run_ids
157+ }
158+
159+ #
160+ # Deletes runs of 'workflow_dispatch' event marked for deletion
161+ #
162+ function DeleteOldDispatchedRuns () {
163+ param (
164+ [System.Collections.Generic.Dictionary [System.String , System.Collections.ArrayList ]] $groups
165+ )
166+
167+ [System.Collections.ArrayList ]$runs = $groups [" workflow_dispatch" ]
168+
169+ if ($runs.Count -eq 0 ) {
170+ Write-Host " No dispatched runs to delete. Skipping"
171+ return
172+ }
173+
174+ Write-Host " Deleting old runs that were dispatched"
175+ $run_ids = $runs | Select-Object - ExpandProperty id
176+ DeleteRuns $run_ids
177+ }
178+
179+ #
180+ # Deletes runs of 'push' event marked for deletion
181+ #
182+ function DeleteOldRunsOnPush () {
183+ param (
184+ [System.Collections.Generic.Dictionary [System.String , System.Collections.ArrayList ]] $groups
185+ )
186+
187+ [System.Collections.ArrayList ]$runs = $groups [" push" ]
188+
189+ if ($runs.Count -eq 0 ) {
190+ Write-Host " No runs triggered by push to delete. Skipping"
191+ return
192+ }
193+
194+ Write-Host " Deleting old runs triggered by push"
195+ $run_ids = $runs | Select-Object - ExpandProperty id
196+ DeleteRuns $run_ids
197+ }
198+
199+ #
200+ # Deletes runs of 'schedule' event marked for deletion
201+ #
202+ function DeleteOldScheduledRuns () {
203+ param (
204+ [System.Collections.Generic.Dictionary [System.String , System.Collections.ArrayList ]] $groups
205+ )
206+
207+ [System.Collections.ArrayList ]$runs = $groups [" schedule" ]
208+
209+ if ($runs.Count -eq 0 ) {
210+ Write-Host " No scheduled runs to delete. Skipping"
211+ return
212+ }
213+
214+ Write-Host " Deleting old runs triggered on schedule"
215+ $run_ids = $runs | Select-Object - ExpandProperty id
216+ DeleteRuns $run_ids
217+ }
218+
219+ Write-Host " Collecting runs for closed PRs, inactive workflow runs, and other runs older than $keepDays days"
220+
221+ $preserveDays = [System.Int32 ]::Parse($keepDays )
222+
223+ $runsForDeletion = GetWorkflowRunsForDeletion $preserveDays
224+
225+ if ($runsForDeletion.ToString () -eq " System.Object[]" )
226+ {
227+ # just in case somebody screws up method and forgot to apply out-null to some operation
228+ # and results of method became array of objects
229+ $runsForDeletion = $runsForDeletion [$runsForDeletion.Length - 1 ];
230+ }
231+
232+ DeleteRunsOfInactiveWorkflows $runsForDeletion
233+
234+ DeleteRunsForClosedPR $runsForDeletion
235+
236+ DeleteOldDispatchedRuns $runsForDeletion
237+
238+ DeleteOldRunsOnPush $runsForDeletion
239+
240+ DeleteOldScheduledRuns $runsForDeletion
0 commit comments