-
Notifications
You must be signed in to change notification settings - Fork 841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[EngSys] adding coverage tools #15076
Merged
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
fdb9b2e
adding coverage tools
seankane-msft d35b105
forgot to include 'go run'
seankane-msft 2845735
need to find where the script is running from
seankane-msft 43e8cf6
fixing script
seankane-msft 2959f2a
fixing passing of coverage goal value
seankane-msft 28b8608
removing flag from build-test
seankane-msft 4a5da22
fixing tools script for multiple files
seankane-msft 610b45f
updating ci.yml files, polishing script
seankane-msft 597014d
merge conflicts
seankane-msft 4c7d915
removing coverage goals
seankane-msft a136873
undoing changes
seankane-msft 56f0d2d
dropping core down, fixing to.go lint
seankane-msft 295d9a2
creating a config file for the SDK and using that instead of putting …
seankane-msft aadf942
putting coverage in a script
seankane-msft cd10a1a
fixing location of script
seankane-msft e0a6e03
fixing scope
seankane-msft d2205c8
fixing powershell portions, float instead of &float64
seankane-msft 7e2e1c5
forcing pipelines
seankane-msft b6cb592
Update tools/internal/coverage/main.go
seankane-msft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"Packages": [ | ||
{ | ||
"Name": "azidentity", | ||
"CoverageGoal": 0.68 | ||
}, | ||
{ | ||
"Name": "azcore", | ||
"CoverageGoal": 0.68 | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#Requires -Version 7.0 | ||
|
||
$coverageFiles = [Collections.Generic.List[String]]@() | ||
Get-ChildItem -recurse -path . -filter coverage.txt | ForEach-Object { | ||
$covFile = $_.FullName | ||
Write-Host "Adding $covFile to the list of code coverage files" | ||
$coverageFiles.Add($covFile) | ||
} | ||
|
||
# merge coverage files | ||
gocovmerge $coverageFiles > mergedCoverage.txt | ||
gocov convert ./mergedCoverage.txt > ./coverage.json | ||
|
||
# gocov converts rely on standard input | ||
Get-Content ./coverage.json | gocov-xml > ./coverage.xml | ||
Get-Content ./coverage.json | gocov-html > ./coverage.html | ||
|
||
# use internal tool to fail if coverage is too low | ||
go run ../tools/internal/coverage/main.go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/Azure/azure-sdk-for-go/tools/internal/coverage | ||
|
||
go 1.16 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
type CodeCoverage struct { | ||
Packages []Package `json:"Packages"` | ||
} | ||
|
||
type Package struct { | ||
Name string `json:"name"` | ||
CoverageGoal float64 `json:"CoverageGoal"` | ||
} | ||
|
||
const ( | ||
coverageXmlFile = "coverage.xml" | ||
) | ||
|
||
var configFile, _ = filepath.Abs(filepath.Join("..", "eng", "config.json")) | ||
|
||
func check(e error) { | ||
if e != nil { | ||
log.Fatal(e) | ||
} | ||
} | ||
|
||
var coverageFiles []string | ||
|
||
func filterFiles(path string, info os.FileInfo, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
if strings.Contains(path, "coverage.xml") { | ||
coverageFiles = append(coverageFiles, path) | ||
} | ||
return nil | ||
} | ||
|
||
func FindCoverageFiles(p string) { | ||
err := filepath.Walk(".", filterFiles) | ||
check(err) | ||
} | ||
|
||
func ReadConfigData() *CodeCoverage { | ||
jsonFile, err := os.Open(configFile) | ||
check(err) | ||
defer jsonFile.Close() | ||
|
||
byteValue, err := ioutil.ReadAll(jsonFile) | ||
check(err) | ||
|
||
var cov CodeCoverage | ||
err = json.Unmarshal([]byte(byteValue), &cov) | ||
check(err) | ||
return &cov | ||
} | ||
|
||
// This supports doing a single package at a time. If this needs to be expanded in the future | ||
// this method will have to return a []*float64 for each packages goal | ||
func findCoverageGoal(covFiles []string, configData *CodeCoverage) float64 { | ||
for _, covFile := range covFiles { | ||
for _, p := range configData.Packages { | ||
if strings.Contains(covFile, p.Name) { | ||
return p.CoverageGoal | ||
} | ||
} | ||
} | ||
fmt.Println("WARNING: Could not find a coverage goal, defaulting to 95%.") | ||
return 0.95 | ||
} | ||
|
||
func main() { | ||
coverageFiles = make([]string, 0) | ||
rootPath, err := filepath.Abs(".") | ||
check(err) | ||
|
||
FindCoverageFiles(rootPath) | ||
|
||
configData := ReadConfigData() | ||
coverageGoal := findCoverageGoal(coverageFiles, configData) | ||
|
||
fmt.Printf("Failing if the coverage is below %.2f\n", coverageGoal) | ||
|
||
coverageValues := make([]float64, 0) | ||
for _, coverageFile := range coverageFiles { | ||
xmlFile, err := os.Open(coverageFile) | ||
check(err) | ||
defer xmlFile.Close() | ||
|
||
byteValue, err := ioutil.ReadAll(xmlFile) | ||
check(err) | ||
|
||
re := regexp.MustCompile(`<coverage line-rate=\"\d\.\d+\"`) | ||
coverageValue := re.Find(byteValue) //, -1) | ||
if coverageValue == nil { | ||
log.Fatalf("Could not match regexp to coverage.xml file.") | ||
} | ||
|
||
parts := strings.Split(string(coverageValue), "=") | ||
coverageNumber := parts[1] | ||
|
||
coverageNumber = coverageNumber[1 : len(coverageNumber)-1] | ||
coverageFloat, err := strconv.ParseFloat(coverageNumber, 32) | ||
check(err) | ||
coverageValues = append(coverageValues, coverageFloat) | ||
} | ||
|
||
if len(coverageValues) != len(coverageFiles) { | ||
fmt.Printf("Found %d coverage values in %d coverage files\n", len(coverageValues), len(coverageFiles)) | ||
} | ||
|
||
failedCoverage := false | ||
for i := range coverageValues { | ||
status := "Succeeded" | ||
if coverageValues[i] < coverageGoal { | ||
status = "Failed" | ||
} | ||
fmt.Printf("Status: %v\tCoverage file: %v\t Coverage Amount: %.4f\n", status, coverageFiles[i], coverageValues[i]) | ||
if coverageValues[i] < coverageGoal { | ||
failedCoverage = true | ||
} | ||
} | ||
|
||
if failedCoverage { | ||
fmt.Println("Coverage step failed") | ||
os.Exit(1) | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the coverage go tool gains complexity/scope, I think it would be good to follow a convention of an SDK directory config file to store this type of info. As it is in this PR, you can't run the coverage locally to see if it will pass upstream without knowing to manually look up the CoverageGoal in ci.yml. It gets even harder if you want to run coverage for the whole repo (e.g. for cross-cutting changes).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking in general for go is that we want to put as little context in the yaml as possible. In an ideal world the devops yaml would only function as a light orchestration wrapper and not contain any sdk-specific context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an example of another repo that has a config file? Or to store this in a single config file and specifying the information per library?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say it's an open question, perhaps just a config.json file for easy interoperability? I know js uses the convention of putting custom key/value config data into the
package.json
file (e.g. for samples configuration). I don't think there are as many examples in other repos.If you think it's weird/unnecessary, I wouldn't disagree as right now there would be only tool that uses it. As we add more tooling that needs to have per-sdk behavior it could be helpful to have a common place for this kind of stuff that is amenable to both local and pipeline scripts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benbp I added a config.json file in the
eng
directory. Right now it just has a list of packages and their code coverage goal but I think this will be a good way to expand any needs for it in the future.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's going to be in eng and contain all package info, it can probably be a dedicated file called
coverage.json
instead?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went with config.json instead because it may contain more info in the future other than coverage information.