Skip to content

Commit

Permalink
Tool-253 collect unmappable test results to other tab (#18)
Browse files Browse the repository at this point in the history
* refactor: better funcion name

* collect results to 'other' dir if variant unknown

* fix: forgot to rename reference

* export non android test results to 'other' folder

* typo fixes

* report and results inputs clarification

* added new test case

* default report dir pattern update

* logging updates, unique Others dir, debug log fix

* log fixes

* other dir name update

* step.yml update, removed unused var

* PR updates
  • Loading branch information
lszucs authored and godrei committed Aug 30, 2019
1 parent dd2535d commit 9d5c1d4
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 96 deletions.
16 changes: 12 additions & 4 deletions bitrise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ workflows:
- gradlew_path: ./gradlew
- path::./:
title: Android Unit Test (monorepo projects in source dir)
inputs:
- is_debug: "true"
after-run:
- check-artifacts

Expand Down Expand Up @@ -72,6 +74,7 @@ workflows:
inputs:
- module: app
- variant: Debug
- is_debug: "true"
after-run:
- check-artifacts

Expand All @@ -95,6 +98,8 @@ workflows:
- gradlew_path: ./gradlew
- path::./:
title: Android Unit Test (android project & mono repo projects in /tmp dir)
inputs:
- is_debug: "true"
after-run:
- check-artifacts

Expand All @@ -121,6 +126,8 @@ workflows:
- gradlew_path: ./gradlew
- path::./:
title: Android Unit Test (android project with build.gradle.kts)
inputs:
- is_debug: "true"
after-run:
- check-artifacts

Expand Down Expand Up @@ -178,7 +185,7 @@ workflows:
- is_create_path: true
- script:
inputs:
- content: git clone -b no-failures $SAMPLE_REPO_GIT_CLONE_URL .
- content: git clone -b no-failures $SAMPLE_REPO_GIT_CLONE_URL -b code-coverage .
- install-missing-android-tools:
inputs:
- gradlew_path: ./gradlew
Expand All @@ -195,21 +202,22 @@ workflows:
inputs:
- module: app
- variant: Debug
- is_debug: "true"
- script:
title: check exported arftifacts
title: check exported artifacts
is_always_run: true
inputs:
- content: |-
#!/usr/bin/env bash
set -ex
# check directory and test-info.json existense
# check directory and test-info.json existence
if [ $(find ${BITRISE_TEST_DEPLOY_DIR} -regex ".*/app-debug/test-info.json" | grep -c .) -eq 0 ]; then
echo "ERROR: ${BITRISE_TEST_DEPLOY_DIR} does not contain app-debug/test-info.json."
exit 1
fi
# check result xml existense
# check result xml existence
if [ ! $(find ${BITRISE_TEST_DEPLOY_DIR} -regex ".*/app-debug/TEST.*.xml" | grep -c .) -eq 2 ]; then
echo "ERROR: ${BITRISE_TEST_DEPLOY_DIR} does not contain all test result XMLs."
exit 1
Expand Down
119 changes: 74 additions & 45 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"time"

Expand All @@ -17,18 +18,19 @@ import (
shellquote "github.com/kballard/go-shellquote"
)

const resultArtifactPathPattern = "*TEST*.xml"

// Configs ...
type Configs struct {
ProjectLocation string `env:"project_location,dir"`
ReportPathPattern string `env:"report_path_pattern"`
ResultPathPattern string `env:"result_path_pattern"`
Variant string `env:"variant"`
Module string `env:"module"`
Arguments string `env:"arguments"`
CacheLevel string `env:"cache_level,opt[none,only_deps,all]"`
IsDebug bool `env:"is_debug,opt[true,false]"`
ProjectLocation string `env:"project_location,dir"`
HTMLResultDirPattern string `env:"report_path_pattern"`
XMLResultDirPattern string `env:"result_path_pattern"`
Variant string `env:"variant"`
Module string `env:"module"`
Arguments string `env:"arguments"`
CacheLevel string `env:"cache_level,opt[none,only_deps,all]"`
IsDebug bool `env:"is_debug,opt[true,false]"`

DeployDir string `env:"BITRISE_DEPLOY_DIR"`
TestResultDir string `env:"BITRISE_TEST_RESULT_DIR"`
}

func failf(f string, args ...interface{}) {
Expand Down Expand Up @@ -60,6 +62,14 @@ func getArtifacts(gradleProject gradle.Project, started time.Time, pattern strin
return
}

func workDirRel(pth string) (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}
return filepath.Rel(wd, pth)
}

func exportArtifacts(deployDir string, artifacts []gradle.Artifact) error {
for _, artifact := range artifacts {
artifact.Name += ".zip"
Expand All @@ -73,7 +83,12 @@ func exportArtifacts(deployDir string, artifacts []gradle.Artifact) error {
artifact.Name = fmt.Sprintf("%s-%s%s", strings.TrimSuffix(artifact.Name, ".zip"), timestamp, ".zip")
}

log.Printf(" Export [ %s => $BITRISE_DEPLOY_DIR/%s ]", filepath.Base(artifact.Path), artifact.Name)
src := filepath.Base(artifact.Path)
if rel, err := workDirRel(artifact.Path); err == nil {
src = "./" + rel
}

log.Printf(" Export [ %s => $BITRISE_DEPLOY_DIR/%s ]", src, artifact.Name)

if err := artifact.ExportZIP(deployDir); err != nil {
log.Warnf("failed to export artifact (%s), error: %v", artifact.Path, err)
Expand Down Expand Up @@ -110,25 +125,42 @@ func filterVariants(module, variant string, variantsMap gradle.Variants) (gradle
return filteredVariants, nil
}

func main() {
var config Configs
func tryExportTestAddonArtifact(artifactPth, outputDir string, lastOtherDirIdx int) int {
dir := getExportDir(artifactPth)

if config.IsDebug {
log.SetEnableDebugLog(true)
log.Debugf("Debug mode enabled")
if dir == OtherDirName {
// start indexing other dir name, to avoid overrideing it
// e.g.: other, other-1, other-2
lastOtherDirIdx++
if lastOtherDirIdx > 0 {
dir = dir + "-" + strconv.Itoa(lastOtherDirIdx)
}
}

if err := testaddon.ExportArtifact(artifactPth, outputDir, dir); err != nil {
log.Warnf("Failed to export test results for test addon: %s", err)
} else {
src := artifactPth
if rel, err := workDirRel(artifactPth); err == nil {
src = "./" + rel
}
log.Printf(" Export [%s => %s]", src, filepath.Join("$BITRISE_TEST_RESULT_DIR", dir, filepath.Base(artifactPth)))
}
return lastOtherDirIdx
}

func main() {
var config Configs

if err := stepconf.Parse(&config); err != nil {
failf("Couldn't create step config: %v\n", err)
}

stepconf.Print(config)

deployDir := os.Getenv("BITRISE_DEPLOY_DIR")

log.Printf("- Deploy dir: %s", deployDir)
fmt.Println()

log.SetEnableDebugLog(config.IsDebug)

gradleProject, err := gradle.NewProject(config.ProjectLocation)
if err != nil {
failf("Failed to open project, error: %s", err)
Expand Down Expand Up @@ -182,53 +214,50 @@ func main() {
log.Errorf("Test task failed, error: %v", testErr)
}
fmt.Println()

log.Infof("Export reports:")
log.Infof("Export HTML results:")
fmt.Println()

reports, err := getArtifacts(gradleProject, started, config.ReportPathPattern, true, true)
reports, err := getArtifacts(gradleProject, started, config.HTMLResultDirPattern, true, true)
if err != nil {
failf("Failed to find reports, error: %v", err)
}

if err := exportArtifacts(deployDir, reports); err != nil {
if err := exportArtifacts(config.DeployDir, reports); err != nil {
failf("Failed to export reports, error: %v", err)
}

fmt.Println()

log.Infof("Export results:")
log.Infof("Export XML results:")
fmt.Println()

results, err := getArtifacts(gradleProject, started, config.ResultPathPattern, true, true)
results, err := getArtifacts(gradleProject, started, config.XMLResultDirPattern, true, true)
if err != nil {
failf("Failed to find results, error: %v", err)
}

if err := exportArtifacts(deployDir, results); err != nil {
if err := exportArtifacts(config.DeployDir, results); err != nil {
failf("Failed to export results, error: %v", err)
}

log.Infof("Export test results for test addon:")
fmt.Println()
if config.TestResultDir != "" {
// Test Addon is turned on
fmt.Println()
log.Infof("Export XML results for test addon:")
fmt.Println()

resultXMLs, err := getArtifacts(gradleProject, started, resultArtifactPathPattern, false, false)
if err != nil {
log.Warnf("Failed to find test result XMLs, error: %s", err)
} else {
if baseDir := os.Getenv("BITRISE_TEST_RESULT_DIR"); baseDir != "" {
xmlResultFilePattern := config.XMLResultDirPattern
if !strings.HasSuffix(xmlResultFilePattern, "*.xml") {
xmlResultFilePattern += "*.xml"
}

resultXMLs, err := getArtifacts(gradleProject, started, xmlResultFilePattern, false, false)
if err != nil {
log.Warnf("Failed to find test XML test results, error: %s", err)
} else {
lastOtherDirIdx := -1
for _, artifact := range resultXMLs {
uniqueDir, err := getUniqueDir(artifact.Path)
if err != nil {
log.Warnf("Failed to export test results for test addon: cannot get export directory for artifact (%s): %s", err)
continue
}

if err := testaddon.ExportArtifact(artifact.Path, baseDir, uniqueDir); err != nil {
log.Warnf("Failed to export test results for test addon: %s", err)
}
lastOtherDirIdx = tryExportTestAddonArtifact(artifact.Path, config.TestResultDir, lastOtherDirIdx)
}
log.Printf(" Exporting test results to test addon successful [ %s ] ", baseDir)
}
}

Expand Down
73 changes: 73 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package main

import (
"os"
"path/filepath"
"testing"

"github.com/bitrise-io/go-utils/pathutil"
)

func Test_tryExportTestAddonArtifact(t *testing.T) {
tmpDir, err := pathutil.NormalizedOSTempDirPath("")
if err != nil {
t.Fatal(err)
}

tests := []struct {
name string
artifactPth string
outputDir string
lastOtherDirIdx int

wantIdx int
wantOutputPth string
}{
{
name: "Exports Local Unit Test result XML file",
artifactPth: filepath.Join(tmpDir, "./app/build/test-results/testDebugUnitTest/TEST-sample.results.test.multiple.bitrise.com.multipletestresultssample.UnitTest0.xml"),
outputDir: filepath.Join(tmpDir, "1"),
lastOtherDirIdx: 0,
wantIdx: 0,
wantOutputPth: filepath.Join(tmpDir, "1", "app-debug", "TEST-sample.results.test.multiple.bitrise.com.multipletestresultssample.UnitTest0.xml"),
},
{
name: "Exports Jacoco result XML file",
artifactPth: filepath.Join(tmpDir, "./app/build/test-results/jacocoTestReleaseUnitTestReport/jacocoTestReleaseUnitTestReport.xml"),
outputDir: filepath.Join(tmpDir, "2"),
lastOtherDirIdx: 0,
wantIdx: 1,
wantOutputPth: filepath.Join(tmpDir, "2", "other-1", "jacocoTestReleaseUnitTestReport.xml"),
},
{
name: "Exports Other XML file",
artifactPth: filepath.Join(tmpDir, "./app/build/test-results/TEST-sample.results.test.multiple.bitrise.com.multipletestresultssample.UnitTest0.xml"),
outputDir: filepath.Join(tmpDir, "3"),
lastOtherDirIdx: 0,
wantIdx: 1,
wantOutputPth: filepath.Join(tmpDir, "3", "other-1", "TEST-sample.results.test.multiple.bitrise.com.multipletestresultssample.UnitTest0.xml"),
},
}
for _, tt := range tests {
dir := filepath.Dir(tt.artifactPth)
if err := os.MkdirAll(dir, 0700); err != nil {
t.Error(err)
continue
}
if _, err := os.Create(tt.artifactPth); err != nil {
t.Error(err)
continue
}

t.Run(tt.name, func(t *testing.T) {
if got := tryExportTestAddonArtifact(tt.artifactPth, tt.outputDir, tt.lastOtherDirIdx); got != tt.wantIdx {
t.Errorf("tryExportTestAddonArtifact() = %v, want %v", got, tt.wantIdx)
}
if exist, err := pathutil.IsPathExists(tt.wantOutputPth); err != nil {
t.Error(err)
} else if !exist {
t.Errorf("expected output file (%s) does not exist", tt.wantOutputPth)
}
})
}
}
Loading

0 comments on commit 9d5c1d4

Please sign in to comment.