Skip to content

Commit

Permalink
Merge pull request #88 from buildpulse/cov
Browse files Browse the repository at this point in the history
Added flag for ingesting coverage files
  • Loading branch information
siddhantdange authored Jul 28, 2023
2 parents 721abb0 + 2d823da commit c859735
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 48 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ To use `test-reporter` with another CI provider, the following environment varia
| `ORGANIZATION_NAME` | Name of the Github organization |
| `REPOSITORY_NAME` | Name of the repository |

The following are flags that can be set. Make sure to **set flags after CLI args**.
| Environment Variable | Required | Description |
|----------------------|----------------------------------|----------------------------------------------|
| `account-id` || BuildPulse account ID (see dashboard) |
| `repository-id` || BuildPulse repository ID (see dashboard) |
| `repository-dir` | Only if `tree` not set | Path to repository directory |
| `tree` | Only if `repository-dir` not set | Git tree SHA |
| `coverage-files` | If using BuildPulse Coverage | **Space-separated** paths to coverage files. |

Example:
```
BUILDPULSE_ACCESS_KEY_ID=$INPUT_KEY \
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/otiai10/copy v1.9.0
github.com/stretchr/testify v1.8.2
gopkg.in/yaml.v3 v3.0.1
github.com/yargevad/filepathx v1.0.0
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/yargevad/filepathx v1.0.0 h1:SYcT+N3tYGi+NvazubCNlvgIPbzAk7i7y2dwg3I5FYc=
github.com/yargevad/filepathx v1.0.0/go.mod h1:BprfX/gpYNJHJfc35GjRRpVcwWXS89gGulUIU5tK3tA=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
Expand Down
90 changes: 80 additions & 10 deletions internal/cmd/submit/submit.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/buildpulse/test-reporter/internal/metadata"
"github.com/buildpulse/test-reporter/internal/tar"
"github.com/google/uuid"
"github.com/yargevad/filepathx"
)

type credentials struct {
Expand Down Expand Up @@ -66,15 +67,17 @@ type Submit struct {
logger logger.Logger
version *metadata.Version

envs map[string]string
paths []string
bucket string
accountID uint64
repositoryID uint64
repositoryPath string
tree string
credentials credentials
commitResolver metadata.CommitResolver
envs map[string]string
paths []string
coveragePathsString string
coveragePaths []string
bucket string
accountID uint64
repositoryID uint64
repositoryPath string
tree string
credentials credentials
commitResolver metadata.CommitResolver
}

// NewSubmit creates a new Submit instance.
Expand All @@ -91,6 +94,7 @@ func NewSubmit(version *metadata.Version, log logger.Logger) *Submit {
s.fs.Uint64Var(&s.repositoryID, "repository-id", 0, "BuildPulse repository ID (required)")
s.fs.StringVar(&s.repositoryPath, "repository-dir", ".", "Path to local clone of repository")
s.fs.StringVar(&s.tree, "tree", "", "SHA-1 hash of git tree")
s.fs.StringVar(&s.coveragePathsString, "coverage-files", "", "Paths to coverage files or directories containing coverage files")
s.fs.SetOutput(io.Discard) // Disable automatic writing to STDERR

s.logger.Printf("Current version: %s", s.version.String())
Expand Down Expand Up @@ -148,6 +152,10 @@ func (s *Submit) Init(args []string, envs map[string]string, commitResolverFacto
return fmt.Errorf("missing required flag: -repository-id")
}

if len(s.coveragePathsString) > 0 {
s.coveragePaths = strings.Split(s.coveragePathsString, " ")
}

id, ok := envs["BUILDPULSE_ACCESS_KEY_ID"]
if !ok || id == "" {
return fmt.Errorf("missing required environment variable: BUILDPULSE_ACCESS_KEY_ID")
Expand Down Expand Up @@ -271,12 +279,30 @@ func (s *Submit) bundle() (string, error) {
s.logger.Printf("Preparing tarball of test results:")
for _, p := range s.paths {
s.logger.Printf("- %s", p)
err = t.Write(p, p)
internalPath := fmt.Sprintf("test_results/%s", p)
err = t.Write(p, internalPath)
if err != nil {
return "", err
}
}

// if coverage file paths are not provided, we infer them
var coveragePaths = s.coveragePaths
if len(coveragePaths) == 0 {
coveragePaths, err = coveragePathsInferred()
}

if err == nil && len(coveragePaths) > 0 {
for _, p := range coveragePaths {
internalPath := fmt.Sprintf("coverage/%s", p)
s.logger.Printf("- %s", p)
err = t.Write(p, internalPath)
if err != nil {
return "", err
}
}
}

// Write the metadata file to the tarfile
//////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -426,6 +452,50 @@ func xmlPathsFromArgs(args []string) ([]string, error) {
return paths, nil
}

func globPatternFromPattern(pattern string) string {
return fmt.Sprintf("./**/%s", pattern)
}

func coveragePathsInferred() ([]string, error) {
coverageFileTypes := []string{
"*coverage*.*",
"nosetests.xml",
"jacoco*.xml",
"clover.xml",
"report.xml",
"*.codecov.!(exe)",
"codecov.!(exe)",
"*cobertura.xml",
"excoveralls.json",
"luacov.report.out",
"coverage-final.json",
"naxsi.info",
"lcov.info",
"lcov.dat",
"*.lcov",
"*.clover",
"cover.out",
"gcov.info",
"*.gcov",
"*.lst",
"test_cov.xml",
}

filePaths := []string{}
for _, filePattern := range coverageFileTypes {
fullPattern := globPatternFromPattern(filePattern)
candidates, err := filepathx.Glob(fullPattern)

if err != nil {
return []string{}, err
}

filePaths = append(filePaths, candidates...)
}

return filePaths, nil
}

// xmlPathsFromDir returns a list of all the XML files in the given directory
// and its subdirectories.
func xmlPathsFromDir(dir string) ([]string, error) {
Expand Down
170 changes: 132 additions & 38 deletions internal/cmd/submit/submit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,29 @@ func TestSubmit_Init_invalidRepoPath(t *testing.T) {
assert.Regexp(t, "invalid value for flag -repository-dir: .* is not a directory", err.Error())
}
})

t.Run("WithCoveragePathString", func(t *testing.T) {
tmpfile, err := os.CreateTemp(os.TempDir(), "buildpulse-cli-test-fixture")
require.NoError(t, err)
defer os.Remove(tmpfile.Name())

s := NewSubmit(&metadata.Version{}, logger.New())
err = s.Init([]string{
".",
"--account-id", "42",
"--repository-id", "8675309",
"--repository-dir", tmpfile.Name(),
"--coverage-files", "./dir1/**/*.xml ./dir2/**/*.xml",
},
exampleEnv,
&stubCommitResolverFactory{},
)
if assert.Error(t, err) {
assert.Regexp(t, "invalid value for flag -repository-dir: .* is not a directory", err.Error())
}

assert.Equal(t, s.coveragePaths, []string{"./dir1/**/*.xml", "./dir2/**/*.xml"})
})
}

func TestSubmit_Run(t *testing.T) {
Expand Down Expand Up @@ -412,48 +435,117 @@ func TestSubmit_Run(t *testing.T) {
}

func Test_bundle(t *testing.T) {
envs := map[string]string{
"GITHUB_ACTIONS": "true",
"GITHUB_SHA": "aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb",
}
t.Run("bundle with coverage files provided", func(t *testing.T) {
envs := map[string]string{
"GITHUB_ACTIONS": "true",
"GITHUB_SHA": "aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb",
}

log := logger.New()
s := &Submit{
logger: log,
version: &metadata.Version{Number: "v1.2.3"},
commitResolver: metadata.NewStaticCommitResolver(&metadata.Commit{TreeSHA: "ccccccccccccccccccccdddddddddddddddddddd"}, log),
envs: envs,
paths: []string{"testdata/example-reports-dir/example-1.xml"},
bucket: "buildpulse-uploads",
accountID: 42,
repositoryID: 8675309,
}
log := logger.New()
s := &Submit{
logger: log,
version: &metadata.Version{Number: "v1.2.3"},
commitResolver: metadata.NewStaticCommitResolver(&metadata.Commit{TreeSHA: "ccccccccccccccccccccdddddddddddddddddddd"}, log),
envs: envs,
paths: []string{"testdata/example-reports-dir/example-1.xml"},
coveragePaths: []string{"testdata/example-reports-dir/coverage-files/report.xml", "testdata/example-reports-dir/coverage-files/report-2.xml"},
bucket: "buildpulse-uploads",
accountID: 42,
repositoryID: 8675309,
}

path, err := s.bundle()
require.NoError(t, err)
path, err := s.bundle()
require.NoError(t, err)

unzipDir := t.TempDir()
err = archiver.Unarchive(path, unzipDir)
require.NoError(t, err)
unzipDir := t.TempDir()
err = archiver.Unarchive(path, unzipDir)
require.NoError(t, err)

// Verify buildpulse.yml is present and contains expected content
yaml, err := os.ReadFile(filepath.Join(unzipDir, "buildpulse.yml"))
require.NoError(t, err)
assert.Contains(t, string(yaml), ":ci_provider: github-actions")
assert.Contains(t, string(yaml), ":commit: aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb")
assert.Contains(t, string(yaml), ":tree: ccccccccccccccccccccdddddddddddddddddddd")
assert.Contains(t, string(yaml), ":reporter_version: v1.2.3")

// Verify test report XML file is present and contains expected content
assertEqualContent(t,
"testdata/example-reports-dir/example-1.xml",
filepath.Join(unzipDir, "testdata/example-reports-dir/example-1.xml"),
)

// Verify buildpulse.log is present and contains expected content
logdata, err := os.ReadFile(filepath.Join(unzipDir, "buildpulse.log"))
require.NoError(t, err)
assert.Contains(t, string(logdata), "Gathering metadata to describe the build")
// Verify buildpulse.yml is present and contains expected content
yaml, err := os.ReadFile(filepath.Join(unzipDir, "buildpulse.yml"))
require.NoError(t, err)
assert.Contains(t, string(yaml), ":ci_provider: github-actions")
assert.Contains(t, string(yaml), ":commit: aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb")
assert.Contains(t, string(yaml), ":tree: ccccccccccccccccccccdddddddddddddddddddd")
assert.Contains(t, string(yaml), ":reporter_version: v1.2.3")

// Verify test report XML file is present and contains expected content
assertEqualContent(t,
"testdata/example-reports-dir/example-1.xml",
filepath.Join(unzipDir, "test_results/testdata/example-reports-dir/example-1.xml"),
)

// Verify coverage files are present and contains expected content
assertEqualContent(t,
"testdata/example-reports-dir/coverage-files/report.xml",
filepath.Join(unzipDir, "coverage/testdata/example-reports-dir/coverage-files/report.xml"),
)

assertEqualContent(t,
"testdata/example-reports-dir/coverage-files/report-2.xml",
filepath.Join(unzipDir, "coverage/testdata/example-reports-dir/coverage-files/report-2.xml"),
)

// Verify buildpulse.log is present and contains expected content
logdata, err := os.ReadFile(filepath.Join(unzipDir, "buildpulse.log"))
require.NoError(t, err)
assert.Contains(t, string(logdata), "Gathering metadata to describe the build")
})

t.Run("bundle with no coverage files provided (inferred)", func(t *testing.T) {
envs := map[string]string{
"GITHUB_ACTIONS": "true",
"GITHUB_SHA": "aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb",
}

log := logger.New()
s := &Submit{
logger: log,
version: &metadata.Version{Number: "v1.2.3"},
commitResolver: metadata.NewStaticCommitResolver(&metadata.Commit{TreeSHA: "ccccccccccccccccccccdddddddddddddddddddd"}, log),
envs: envs,
paths: []string{"testdata/example-reports-dir/example-1.xml"},
bucket: "buildpulse-uploads",
accountID: 42,
repositoryID: 8675309,
}

path, err := s.bundle()
require.NoError(t, err)

unzipDir := t.TempDir()
err = archiver.Unarchive(path, unzipDir)
require.NoError(t, err)

// Verify buildpulse.yml is present and contains expected content
yaml, err := os.ReadFile(filepath.Join(unzipDir, "buildpulse.yml"))
require.NoError(t, err)
assert.Contains(t, string(yaml), ":ci_provider: github-actions")
assert.Contains(t, string(yaml), ":commit: aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb")
assert.Contains(t, string(yaml), ":tree: ccccccccccccccccccccdddddddddddddddddddd")
assert.Contains(t, string(yaml), ":reporter_version: v1.2.3")

// Verify test report XML file is present and contains expected content
assertEqualContent(t,
"testdata/example-reports-dir/example-1.xml",
filepath.Join(unzipDir, "test_results/testdata/example-reports-dir/example-1.xml"),
)

// Verify coverage file is present and contains expected content
assertEqualContent(t,
"testdata/example-reports-dir/coverage-files/report.xml",
filepath.Join(unzipDir, "coverage/testdata/example-reports-dir/coverage-files/report.xml"),
)

ignoredCoverageReportPath := filepath.Join(unzipDir, "coverage/testdata/example-reports-dir/coverage-files/report-2.xml")
_, err = os.Stat(ignoredCoverageReportPath)
assert.True(t, os.IsNotExist(err))

// Verify buildpulse.log is present and contains expected content
logdata, err := os.ReadFile(filepath.Join(unzipDir, "buildpulse.log"))
require.NoError(t, err)
assert.Contains(t, string(logdata), "Gathering metadata to describe the build")
})
}

func Test_upload(t *testing.T) {
Expand Down Expand Up @@ -570,6 +662,8 @@ func Test_xmlPathsFromDir(t *testing.T) {
name: "DirectoryWithFilesAtRootAndInSubDirectories",
path: "testdata/example-reports-dir",
want: []string{
"testdata/example-reports-dir/coverage-files/report.xml",
"testdata/example-reports-dir/coverage-files/report-2.xml",
"testdata/example-reports-dir/example-1.xml",
"testdata/example-reports-dir/example-2.XML",
"testdata/example-reports-dir/dir-with-xml-files/browserstack/example-1.xml",
Expand Down
Empty file.
Empty file.

0 comments on commit c859735

Please sign in to comment.