code-intelligence.com/cifuzz@v0.40.0/internal/cmd/coverage/gradle/gradle.go (about) 1 package gradle 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "os/signal" 8 "path/filepath" 9 "strings" 10 "syscall" 11 12 "github.com/pkg/errors" 13 14 "code-intelligence.com/cifuzz/internal/build/gradle" 15 "code-intelligence.com/cifuzz/internal/cmd/coverage/summary" 16 "code-intelligence.com/cifuzz/internal/cmdutils" 17 "code-intelligence.com/cifuzz/internal/coverage" 18 "code-intelligence.com/cifuzz/pkg/log" 19 "code-intelligence.com/cifuzz/pkg/runfiles" 20 "code-intelligence.com/cifuzz/util/executil" 21 "code-intelligence.com/cifuzz/util/stringutil" 22 ) 23 24 const GradleReportTask = "cifuzzReport" 25 26 type CoverageGenerator struct { 27 OutputFormat string 28 OutputPath string 29 FuzzTest string 30 ProjectDir string 31 32 Parallel gradle.ParallelOptions 33 34 Stderr io.Writer 35 BuildStdout io.Writer 36 BuildStderr io.Writer 37 38 runfilesFinder runfiles.RunfilesFinder 39 } 40 41 func (cov *CoverageGenerator) BuildFuzzTestForCoverage() error { 42 // ensure a finder is set 43 if cov.runfilesFinder == nil { 44 cov.runfilesFinder = runfiles.Finder 45 } 46 47 gradleArgs := []string{ 48 fmt.Sprintf("-Pcifuzz.fuzztest=%s", cov.FuzzTest), 49 } 50 51 if cov.OutputPath == "" { 52 buildDir, err := gradle.GetBuildDirectory(cov.ProjectDir) 53 if err != nil { 54 return err 55 } 56 cov.OutputPath = filepath.Join(buildDir, "reports", "jacoco", GradleReportTask) 57 } 58 59 // Make sure that directory exists, otherwise the command for --format=jacocoxml will fail 60 err := os.MkdirAll(cov.OutputPath, 0700) 61 if err != nil { 62 return err 63 } 64 65 gradleArgs = append(gradleArgs, GradleReportTask, fmt.Sprintf("-Pcifuzz.report.output=%s", cov.OutputPath)) 66 67 if cov.OutputFormat == coverage.FormatJacocoXML { 68 gradleArgs = append(gradleArgs, fmt.Sprintf("-Pcifuzz.report.format=%s", coverage.FormatJacocoXML)) 69 } 70 71 return cov.runGradleCommand(gradleArgs) 72 } 73 74 func (cov *CoverageGenerator) GenerateCoverageReport() (string, error) { 75 reportPath := filepath.Join(cov.OutputPath, "jacoco.xml") 76 reportFile, err := os.Open(reportPath) 77 if err != nil { 78 return "", errors.WithStack(err) 79 } 80 defer reportFile.Close() 81 summary.ParseJacocoXML(reportFile).PrintTable(cov.Stderr) 82 83 if cov.OutputFormat == coverage.FormatJacocoXML { 84 return filepath.Join(cov.OutputPath, "jacoco.xml"), nil 85 } 86 87 return filepath.Join(cov.OutputPath, "html"), nil 88 } 89 90 func (cov *CoverageGenerator) runGradleCommand(args []string) error { 91 gradleCmd, err := gradle.GetGradleCommand(cov.ProjectDir) 92 if err != nil { 93 return err 94 } 95 96 cmd := executil.Command(gradleCmd, args...) 97 cmd.Dir = cov.ProjectDir 98 cmd.Stdout = cov.BuildStdout 99 cmd.Stderr = cov.BuildStderr 100 log.Debugf("Running gradle command: %s", strings.Join(stringutil.QuotedStrings(cmd.Args), " ")) 101 102 sigs := make(chan os.Signal, 1) 103 signal.Notify(sigs, os.Interrupt, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT) 104 go func() { 105 <-sigs 106 err = cmd.TerminateProcessGroup() 107 if err != nil { 108 log.Error(err) 109 } 110 }() 111 112 err = cmd.Run() 113 if err != nil { 114 return cmdutils.WrapExecError(errors.WithStack(err), cmd.Cmd) 115 } 116 117 return nil 118 }