Skip to content

Commit

Permalink
feat: Add deployment frequency (#10)
Browse files Browse the repository at this point in the history
* feat: add deploy frequency range to determine when a deploy needs to happen

* feat: adds support to create either an upgrade or a downgrade branch

* feat: added support for merging pull requests

* feat: Deploy loop now checks for status checks and waits for the deploy workflow to finish

* chore: cleaned up dead code

* chore: resolves some linting violations

* chore: resolved linting violation buy configuring genqlient to make shorter type names
  • Loading branch information
jburns24 authored Jul 17, 2024
1 parent 8433f95 commit a3b8d8c
Show file tree
Hide file tree
Showing 8 changed files with 1,222 additions and 156 deletions.
96 changes: 86 additions & 10 deletions dorateamhelper.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
package main

import (
"context"
"fmt"
"math/rand"
"time"
)

type Range struct {
LowerBound int
UpperBound int
}

type DoraTeam struct {
Level string
MinutesBetweenDeploys int
Level string
MinutesBetweenDeployRange Range
}

// Performance level Elite:
Expand All @@ -12,8 +24,14 @@ type DoraTeam struct {
// Failed deployment recovery time: Less than one hour
func NewEliteDoraTeam() *DoraTeam {
return &DoraTeam{
Level: "Elite",
MinutesBetweenDeploys: 240, // 4 hours
Level: "Elite",
MinutesBetweenDeployRange: Range{ // Between 1 and 12 hours
// Testing bounds
// LowerBound: 1,
// UpperBound: 2,
LowerBound: 60,
UpperBound: 720,
},
}
}

Expand All @@ -24,8 +42,11 @@ func NewEliteDoraTeam() *DoraTeam {
// Failed deployment recovery time: Less than one day
func NewHighDoraTeam() *DoraTeam {
return &DoraTeam{
Level: "High",
MinutesBetweenDeploys: 60,
Level: "High",
MinutesBetweenDeployRange: Range{
LowerBound: 1440, // 24 hours
UpperBound: 10080, // 7 days
},
}
}

Expand All @@ -36,8 +57,11 @@ func NewHighDoraTeam() *DoraTeam {
// Failed deployment recovery time: Between one day and one week
func NewMediumDoraTeam() *DoraTeam {
return &DoraTeam{
Level: "Medium",
MinutesBetweenDeploys: 1440,
Level: "Medium",
MinutesBetweenDeployRange: Range{
LowerBound: 10080, // 1 week
UpperBound: 40320, // 4 weeks
},
}
}

Expand All @@ -48,7 +72,59 @@ func NewMediumDoraTeam() *DoraTeam {
// Failed deployment recovery time: Between one month and six months
func NewLowDoraTeam() *DoraTeam {
return &DoraTeam{
Level: "Low",
MinutesBetweenDeploys: 10080,
Level: "Low",
MinutesBetweenDeployRange: Range{
LowerBound: 40320, // 4 weeks
UpperBound: 201600, // 24 weeks
},
}
}

// Given a teams performance level this function will return the number of minutes
// until the next deployment should be generated. Takes into account when the
// last deployment was made and the range of minutes between deployments for the
// DORA team.
//
// Returns -1 if we should skip this deployment
func (d *DoraTeam) MinutesUntilNextDeployment(ctx context.Context, ghrc *GitHubRepoContext) (int, error) {
recentDeployments, err := ghrc.GetLastDeployment(ctx)

if err != nil {
return 0, fmt.Errorf("Error getting latest deployments for %s/%s: %s", ghrc.org, ghrc.name, err)
}

lastDeploy := time.Unix(0, 0)
if recentDeployments != nil {
lastDeploy = recentDeployments.CreatedAt
}

// If the last deployment was less than the lower bound of the DORA team's
// deployment frequency, then we don't need to generate a deployment.
if time.Since(lastDeploy) < time.Duration(d.MinutesBetweenDeployRange.LowerBound)*time.Minute {
return -1, nil
}

// If the last deployment was more than the upper bound of the DORA team's
// deployment frequency, then we need to generate a deployment now.
var minutesUntilNextDeploy int
if time.Since(lastDeploy) > time.Duration(d.MinutesBetweenDeployRange.UpperBound)*time.Minute {
minutesUntilNextDeploy = 1 // time.Ticker will panic if 0
} else {
// Generate a random number that is at most upper bound deploy range from the last deployment
maxThresholdTime := lastDeploy.Add(time.Duration(d.MinutesBetweenDeployRange.UpperBound) * time.Minute)

rangeOfMinutesUntilNextDeploy := int(time.Until(maxThresholdTime).Minutes())
if rangeOfMinutesUntilNextDeploy <= 0 { // This case should not be possible but rand.Intn panics if 0
rangeOfMinutesUntilNextDeploy = 1
}

//nolint:gosec // No security issue, just need a psudo-random interval
minutesUntilNextDeploy = rand.Intn(rangeOfMinutesUntilNextDeploy)

if minutesUntilNextDeploy == 0 {
minutesUntilNextDeploy = 1
}
}

return minutesUntilNextDeploy, nil
}
Loading

0 comments on commit a3b8d8c

Please sign in to comment.