({
state, targetTag, policy, now, maintenanceWindow,
}: {
state: UpdateState;
targetTag: string;
policy: PolicyResult;
now?: Date;
maintenanceWindow?: MaintenanceWindow | null;
})
| 125 | * persists a new `scheduledFor = nextStart` and re-arms. |
| 126 | */ |
| 127 | export const decideTriggerApply = ({ |
| 128 | state, targetTag, policy, now, maintenanceWindow, |
| 129 | }: { |
| 130 | state: UpdateState; |
| 131 | targetTag: string; |
| 132 | policy: PolicyResult; |
| 133 | now?: Date; |
| 134 | maintenanceWindow?: MaintenanceWindow | null; |
| 135 | }): TriggerApplyDecision => { |
| 136 | if (state.execution.status !== 'scheduled') { |
| 137 | return {action: 'abort', reason: `state=${state.execution.status}`}; |
| 138 | } |
| 139 | if ((state.execution as {targetTag: string}).targetTag !== targetTag) { |
| 140 | return {action: 'abort', reason: `tag=${(state.execution as {targetTag: string}).targetTag}`}; |
| 141 | } |
| 142 | if (!state.latest) return {action: 'abort', reason: 'no-latest'}; |
| 143 | if (!policy.canAuto) return {action: 'clear-schedule', reason: policy.reason || 'policy-denied'}; |
| 144 | if (policy.canAutonomous && maintenanceWindow && now && !inWindow(now, maintenanceWindow)) { |
| 145 | return { |
| 146 | action: 'defer', |
| 147 | nextStart: nextWindowStart(now, maintenanceWindow).toISOString(), |
| 148 | reason: 'outside-maintenance-window', |
| 149 | }; |
| 150 | } |
| 151 | return {action: 'fire'}; |
| 152 | }; |
| 153 | |
| 154 | export interface SchedulerRunnerDeps { |
| 155 | now: () => Date; |
no test coverage detected