Skip to content
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

Added flag for ingesting coverage files #88

Merged
merged 1 commit into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading