Skip to content

Commit

Permalink
🌱 convert CITest check to probes
Browse files Browse the repository at this point in the history
Signed-off-by: AdamKorcz <[email protected]>
  • Loading branch information
AdamKorcz committed Dec 4, 2023
1 parent e4fc815 commit 0b8d614
Show file tree
Hide file tree
Showing 7 changed files with 819 additions and 507 deletions.
18 changes: 11 additions & 7 deletions checks/ci_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import (
"github.com/ossf/scorecard/v4/checks/evaluation"
"github.com/ossf/scorecard/v4/checks/raw"
sce "github.com/ossf/scorecard/v4/errors"
"github.com/ossf/scorecard/v4/probes"
"github.com/ossf/scorecard/v4/probes/zrunner"
)

// CheckCodeReview is the registered name for DoesCodeReview.
const CheckCITests = "CI-Tests"

//nolint:gochecknoinits
Expand All @@ -35,19 +36,22 @@ func init() {
}
}

// CodeReview will check if the maintainers perform code review.
func CITests(c *checker.CheckRequest) checker.CheckResult {
rawData, err := raw.CITests(c.RepoClient)
if err != nil {
e := sce.WithMessage(sce.ErrScorecardInternal, err.Error())
return checker.CreateRuntimeErrorResult(CheckCITests, e)
}

// Return raw results.
if c.RawResults != nil {
c.RawResults.CITestResults = rawData
pRawResults := getRawResults(c)
pRawResults.CITestResults = rawData

// Evaluate the probes.
findings, err := zrunner.Run(pRawResults, probes.CITests)
if err != nil {
e := sce.WithMessage(sce.ErrScorecardInternal, err.Error())
return checker.CreateRuntimeErrorResult(CheckCITests, e)
}

// Return the score evaluation.
return evaluation.CITests(CheckCITests, &rawData, c.Dlogger)
return evaluation.CITests(CheckCITests, findings, c.Dlogger)
}
130 changes: 30 additions & 100 deletions checks/evaluation/ci_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,122 +16,52 @@ package evaluation

import (
"fmt"
"strings"

"github.com/ossf/scorecard/v4/checker"
sce "github.com/ossf/scorecard/v4/errors"
"github.com/ossf/scorecard/v4/finding"
"github.com/ossf/scorecard/v4/probes/testsRunInCI"
)

const (
// CheckCITests is the registered name for CITests.
CheckCITests = "CI-Tests"
success = "success"
)

func CITests(_ string, c *checker.CITestData, dl checker.DetailLogger) checker.CheckResult {
totalMerged := 0
totalTested := 0
for i := range c.CIInfo {
r := c.CIInfo[i]
totalMerged++

var foundCI bool

// GitHub Statuses.
prSuccessStatus, err := prHasSuccessStatus(r, dl)
if err != nil {
return checker.CreateRuntimeErrorResult(CheckCITests, err)
}
if prSuccessStatus {
totalTested++
foundCI = true
continue
}

// GitHub Check Runs.
prCheckSuccessful, err := prHasSuccessfulCheck(r, dl)
if err != nil {
return checker.CreateRuntimeErrorResult(CheckCITests, err)
}
if prCheckSuccessful {
totalTested++
foundCI = true
}
const CheckCITests = "CI-Tests"

if !foundCI {
// Log message says commit, but really we only care about PRs, and
// use only one commit (branch HEAD) to refer to all commits in a PR

dl.Debug(&checker.LogMessage{
Text: fmt.Sprintf("merged PR %d without CI test at HEAD: %s", r.PullRequestNumber, r.HeadSHA),
})
}
func CITests(name string,
findings []finding.Finding,
dl checker.DetailLogger,
) checker.CheckResult {
expectedProbes := []string{
testsRunInCI.Probe,
}
if !finding.UniqueProbesEqual(findings, expectedProbes) {
e := sce.WithMessage(sce.ErrScorecardInternal, "invalid probe results")
return checker.CreateRuntimeErrorResult(name, e)
}

if totalMerged == 0 {
// check whether there are any negative findings
if noPullRequestsFound(findings) {
return checker.CreateInconclusiveResult(CheckCITests, "no pull request found")
}

reason := fmt.Sprintf("%d out of %d merged PRs checked by a CI test", totalTested, totalMerged)
return checker.CreateProportionalScoreResult(CheckCITests, reason, totalTested, totalMerged)
}
totalMerged := findings[0].Values["totalMerged"]
totalTested := findings[0].Values["totalTested"]

// PR has a status marked 'success' and a CI-related context.
//
//nolint:unparam
func prHasSuccessStatus(r checker.RevisionCIInfo, dl checker.DetailLogger) (bool, error) {
for _, status := range r.Statuses {
if status.State != success {
continue
}
if isTest(status.Context) || isTest(status.TargetURL) {
dl.Debug(&checker.LogMessage{
Path: status.URL,
Type: finding.FileTypeURL,
Text: fmt.Sprintf("CI test found: pr: %s, context: %s", r.HeadSHA,
status.Context),
})
return true, nil
}
if totalMerged < totalTested || len(findings) != totalTested {
e := sce.WithMessage(sce.ErrScorecardInternal, "invalid probe results")
return checker.CreateRuntimeErrorResult(name, e)
}
return false, nil
}

// PR has a successful CI-related check.
//
//nolint:unparam
func prHasSuccessfulCheck(r checker.RevisionCIInfo, dl checker.DetailLogger) (bool, error) {
for _, cr := range r.CheckRuns {
if cr.Status != "completed" {
continue
}
if cr.Conclusion != success {
continue
}
if isTest(cr.App.Slug) {
dl.Debug(&checker.LogMessage{
Path: cr.URL,
Type: finding.FileTypeURL,
Text: fmt.Sprintf("CI test found: pr: %d, context: %s", r.PullRequestNumber,
cr.App.Slug),
})
return true, nil
}
}
return false, nil
}
// Log all findings
checker.LogFindings(nonNegativeFindings(findings), dl)

// isTest returns true if the given string is a CI test.
func isTest(s string) bool {
l := strings.ToLower(s)
// All findings (should) have "totalMerged" and "totalTested"
reason := fmt.Sprintf("%d out of %d merged PRs checked by a CI test", totalTested, totalMerged)
return checker.CreateProportionalScoreResult(CheckCITests, reason, totalTested, totalMerged)
}

// Add more patterns here!
for _, pattern := range []string{
"appveyor", "buildkite", "circleci", "e2e", "github-actions", "jenkins",
"mergeable", "packit-as-a-service", "semaphoreci", "test", "travis-ci",
"flutter-dashboard", "Cirrus CI", "azure-pipelines",
} {
if strings.Contains(l, pattern) {
func noPullRequestsFound(findings []finding.Finding) bool {
for i := range findings {
f := &findings[i]
if f.Outcome == finding.OutcomeNotApplicable {
return true
}
}
Expand Down
Loading

0 comments on commit 0b8d614

Please sign in to comment.