diff --git a/action.yaml b/action.yaml index 30dac95..a1cd6de 100644 --- a/action.yaml +++ b/action.yaml @@ -13,10 +13,12 @@ inputs: description: Initial delay before polling. poll_frequency_seconds: description: Polling frequency. + missing_required_retry_count: + description: Number of times to retry if a required check is missing, for cases where the workflow is still being created. version: description: Release version of action to run. runs: - using: node16 + using: node20 main: index.js branding: icon: "check-square" diff --git a/pkg/reqcheck/action.go b/pkg/reqcheck/action.go index 16d930b..ea301f1 100644 --- a/pkg/reqcheck/action.go +++ b/pkg/reqcheck/action.go @@ -4,13 +4,13 @@ import ( "context" "fmt" "regexp" + "slices" "strings" "time" "github.com/google/go-github/v61/github" "github.com/samber/lo" "github.com/sethvargo/go-githubactions" - "slices" "github.com/roryq/required-checks/pkg/pullrequest" ) @@ -34,6 +34,7 @@ func Run(ctx context.Context, cfg *Config, action *githubactions.Action, gh *git return err } + missingRequiredCount := 0 foundSelf := false for { checks, err := pr.ListChecks(ctx, cfg.TargetSHA, nil) @@ -60,12 +61,17 @@ func Run(ctx context.Context, cfg *Config, action *githubactions.Action, gh *git } } + // If required is not found, retry in case the workflow is still being created then fail as there will not be a successful check. requiredNotFound := lo.OmitByValues(requiredSet, []bool{true}) if len(requiredNotFound) > 0 { - return fmt.Errorf("required checks not found: %q", lo.Keys(requiredNotFound)) + missingRequiredCount++ + if missingRequiredCount > cfg.MissingRequiredRetryCount { + return fmt.Errorf("required checks not found: %q", lo.Keys(requiredNotFound)) + } + action.Infof("Required checks not found: %q, continuing another %d times before failing", lo.Keys(requiredNotFound), cfg.MissingRequiredRetryCount-missingRequiredCount) } - // any failed + // Find failed conclusions, and fail early if there is. failed := lo.Filter(toCheck, func(item *github.CheckRun, _ int) bool { return slices.Contains(failedConclusions, item.GetConclusion()) }) @@ -74,16 +80,18 @@ func Run(ctx context.Context, cfg *Config, action *githubactions.Action, gh *git return fmt.Errorf("required checks failed: %q", checkNames(failed)) } - // not completed + // Wait until all statuses are completed. notCompleted := lo.Filter(toCheck, func(item *github.CheckRun, _ int) bool { return item.GetStatus() != StatusCompleted }) + // Break out of the loop if all checks are completed. if len(notCompleted) == 0 { action.Infof("All checks completed") break } + // sleep and try again. action.Infof("Not all checks completed: %q", checkNames(notCompleted)) action.Infof("Waiting %s before next check", cfg.PollFrequency) time.Sleep(cfg.PollFrequency) diff --git a/pkg/reqcheck/config.go b/pkg/reqcheck/config.go index d8885bb..fa81e51 100644 --- a/pkg/reqcheck/config.go +++ b/pkg/reqcheck/config.go @@ -12,22 +12,25 @@ import ( ) type Config struct { - RequiredWorkflowPatterns []string - InitialDelay time.Duration - PollFrequency time.Duration - TargetSHA string + RequiredWorkflowPatterns []string + InitialDelay time.Duration + PollFrequency time.Duration + MissingRequiredRetryCount int + TargetSHA string } const ( - InitialDelayDefault = 15 * time.Second - PollFrequencyDefault = 30 * time.Second + InitialDelayDefault = 15 * time.Second + PollFrequencyDefault = 30 * time.Second + MissingRequiredRetryCountDefault = 2 ) func ConfigFromInputs(action *githubactions.Action) (*Config, error) { action.Infof("Reading Config From Inputs") c := Config{ - InitialDelay: InitialDelayDefault, - PollFrequency: PollFrequencyDefault, + InitialDelay: InitialDelayDefault, + PollFrequency: PollFrequencyDefault, + MissingRequiredRetryCount: MissingRequiredRetryCountDefault, } requiredWorkflowPatterns := action.GetInput(inputs.RequiredWorkflowPatterns) if requiredWorkflowPatterns != "" { @@ -51,7 +54,15 @@ func ConfigFromInputs(action *githubactions.Action) (*Config, error) { c.PollFrequency = time.Duration(pfs) * time.Second } } - + + if missingRequiredRetryCount := action.GetInput(inputs.MissingRequiredRetryCount); missingRequiredRetryCount != "" { + if mrrc, err := strconv.Atoi(missingRequiredRetryCount); err != nil { + action.Warningf("Failed to parse MissingRequiredRetryCount: %s", err) + } else { + c.MissingRequiredRetryCount = mrrc + } + } + var err error c.TargetSHA, err = defaultTargetSHA(action) if err != nil { diff --git a/pkg/reqcheck/inputs/inputs.go b/pkg/reqcheck/inputs/inputs.go index a023bc2..a923cb0 100644 --- a/pkg/reqcheck/inputs/inputs.go +++ b/pkg/reqcheck/inputs/inputs.go @@ -15,6 +15,9 @@ const ( TargetSHA = "TARGET_SHA" + // MissingRequiredRetryCount is the number of times to retry if a required check is missing, for cases where the workflow is still being created. + MissingRequiredRetryCount = "MISSING_REQUIRED_RETRY_COUNT" + // Version release version of the action to run - Version = "version" + Version = "VERSION" )