Public/Get-PendingDeployment.ps1
|
# --------------------------------------------------------------------------- # Get-PendingDeployment # Returns the oldest deployment for the given repo and environment that # has not yet reached a terminal status. Terminal statuses are: # success, failure, error, inactive. # # Returns $null when there is no pending deployment, so callers can # use a simple null-check to decide whether to wait and poll again. # # The polling agent calls this on each tick. When a deployment is # returned the agent posts an 'in_progress' status, runs the tests, # then calls Set-DeploymentStatus with the final result. # # Cost note: GitHub never deletes deployments, so an environment's list # endpoint keeps returning a full page of historical, already-terminal # deployments. Fetching every one's statuses on every poll is an # N+1 fan-out that exhausts the API rate limit. -CreatedSince lets the # caller skip the status fetch for deployments older than the cutoff, # collapsing a quiet poll to a single list call. # --------------------------------------------------------------------------- function Get-PendingDeployment { [CmdletBinding()] param( # Bearer token (PAT or GitHub App installation token). [Parameter(Mandatory)] [string] $Token, # GitHub organisation or user that owns the repo. [Parameter(Mandatory)] [string] $Owner, # Repository name (without the owner prefix). [Parameter(Mandatory)] [string] $Repo, # The deployment environment name to filter by. # Must match the 'environment' field on the deployment exactly. [Parameter(Mandatory)] [string] $Environment, # Skip the per-deployment status fetch for any deployment created # before this UTC instant. A pending deployment is always recent, so # anything older than the cutoff cannot be the work we are waiting # for - and historical deployments are all terminal anyway. Default # MinValue checks every returned deployment (the prior behaviour); # the polling agent passes a recent cutoff to stop the N+1 fan-out # over months of accumulated history from exhausting the rate limit. [Parameter()] [DateTime] $CreatedSince = [DateTime]::MinValue ) $terminalStatuses = @('success', 'failure', 'error', 'inactive') $deployments = Invoke-GitHubApi ` -Token $Token ` -Endpoint "repos/$Owner/$Repo/deployments?environment=$Environment" foreach ($deployment in ($deployments | Sort-Object id)) { # Cheap, call-free skip of stale deployments before spending an API # call on their statuses. Property access is guarded so callers (and # tests) whose deployment objects omit created_at keep working; an # absent timestamp is treated as in-window so we never skip a real # pending deployment just because the field was missing. if ($CreatedSince -ne [DateTime]::MinValue -and $deployment.PSObject.Properties['created_at'] -and $deployment.created_at) { $createdAt = [DateTimeOffset] $deployment.created_at if ($createdAt.UtcDateTime -lt $CreatedSince) { continue } } $statuses = Invoke-GitHubApi ` -Token $Token ` -Endpoint "repos/$Owner/$Repo/deployments/$($deployment.id)/statuses" # A deployment with no statuses at all is pending. A deployment # whose most-recent status is non-terminal is still in flight. # The statuses endpoint returns them newest-first. $statusArray = ConvertTo-Array $statuses $latestState = if ($statusArray.Count -gt 0) { $statusArray[0].state } else { $null } if ($latestState -notin $terminalStatuses) { return $deployment } } return $null } |