Skip to content
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
10 changes: 8 additions & 2 deletions magefiles/magebuild/magebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,14 @@ func collectLicenses() error {

env := map[string]string{"GOROOT": goRoot}

err = sh.RunWith(env, cmdAbsPath, "save", "--save_path", mageutil.LicenseDir(), "--force", "./...")
if err != nil {
// go-licenses spews a benign glog warning to stderr for every dependency that contains non-Go
// (assembly) code. Capture stderr, strip those warnings, and only surface what's left on failure.
var stderr strings.Builder

if _, err := sh.Exec(env, os.Stdout, &stderr, cmdAbsPath,
"save", "--save_path", mageutil.LicenseDir(), "--force", "./..."); err != nil {
mageutil.PrintLicenseOutput(stderr.String())

return mageutil.PrintAndReturnError(errorText, ErrLicenses, err)
}

Expand Down
72 changes: 49 additions & 23 deletions magefiles/magecheckfix/checkfix.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package magecheckfix
import (
"errors"
"fmt"
"io"
"os"
"path"
"strings"
Expand Down Expand Up @@ -246,12 +245,9 @@ func licenseCheck() error {
mageutil.MagePrintln(mageutil.MsgStart, "Checking licenses...")

outFilePath := path.Join(mageutil.OutDir(), "licenses.csv")

errorText := "Failed to check licenses."
successText := "License check complete, results written to " + outFilePath

err := sh.Run(mg.GoCmd(), "mod", "download")
if err != nil {
if err := sh.Run(mg.GoCmd(), "mod", "download"); err != nil {
return mageutil.PrintAndReturnError(errorText, ErrCheck, err)
}

Expand All @@ -260,9 +256,6 @@ func licenseCheck() error {
return mageutil.PrintAndReturnError(errorText, ErrCheck, err)
}

// per https://github.com/google/go-licenses?tab=readme-ov-file#check
disallowedLicenseTypes := []string{"unknown", "forbidden", "restricted"}

commonOptions := []string{
// Ignore golang.org/x dependencies to avoid spurious errors about .s files that can't be checked
// and some odd errors we started seeing with standard library packages post 1.24.0.
Expand All @@ -274,9 +267,6 @@ func licenseCheck() error {
"./...",
}

checkArgs := append([]string{"check", "--disallowed_types=" + strings.Join(disallowedLicenseTypes, ",")},
commonOptions...)

// go-licenses complains about various standard library .go files unless we explicitly
// set the right GOROOT. We invoke "go env" to find the correct GOROOT and then run
// go-licenses in an environment with it set.
Expand All @@ -285,32 +275,68 @@ func licenseCheck() error {
return mageutil.PrintAndReturnError(errorText, ErrCheck, err)
}

env := map[string]string{"GOROOT": goRoot}
if err := runLicenseCheck(cmdAbsPath, goRoot, commonOptions); err != nil {
return err
}

err = sh.RunWithV(env, cmdAbsPath, checkArgs...)
if err != nil {
return mageutil.PrintAndReturnError(errorText, ErrCheck, err)
if err := runLicenseReport(cmdAbsPath, goRoot, commonOptions, outFilePath); err != nil {
return err
}

reportArgs := append([]string{"report"}, commonOptions...)
mageutil.MagePrintln(mageutil.MsgSuccess, "License check complete, results written to "+outFilePath)

report, err := sh.OutputWith(env, cmdAbsPath, reportArgs...)
if err != nil {
return mageutil.PrintAndReturnError(errorText, ErrCheck, err)
return nil
}

// runLicenseCheck runs "go-licenses check" for disallowed license types, suppressing the benign
// non-Go-code warnings on success and only surfacing real errors on failure.
func runLicenseCheck(cmdAbsPath, goRoot string, commonOptions []string) error {
// per https://github.com/google/go-licenses?tab=readme-ov-file#check
disallowedLicenseTypes := []string{"unknown", "forbidden", "restricted"}

checkArgs := append([]string{"check", "--disallowed_types=" + strings.Join(disallowedLicenseTypes, ",")},
commonOptions...)

// go-licenses spews a glog warning for every dependency that contains non-Go (assembly) code.
// These are benign and constant, so capture the combined output, strip those warnings, and only
// surface what's left (real errors) when the check fails.
env := map[string]string{"GOROOT": goRoot}

var out strings.Builder

if _, err := sh.Exec(env, &out, &out, cmdAbsPath, checkArgs...); err != nil {
mageutil.PrintLicenseOutput(out.String())

return mageutil.PrintAndReturnError("Failed to check licenses.", ErrCheck, err)
}

return nil
}

// runLicenseReport runs "go-licenses report" and writes the resulting CSV to outFilePath. The same
// non-Go-code warnings are emitted to stderr; they are captured and only surfaced on failure.
func runLicenseReport(cmdAbsPath, goRoot string, commonOptions []string, outFilePath string) error {
errorText := "Failed to check licenses."

reportArgs := append([]string{"report"}, commonOptions...)

outFile, err := os.Create(outFilePath)
if err != nil {
return mageutil.PrintAndReturnError(errorText, ErrCheck, err)
}
defer outFile.Close()
Comment thread
dmcilvaney marked this conversation as resolved.

_, err = io.WriteString(outFile, report)
if err != nil {
// Stream stdout (the CSV) straight to the file and capture stderr separately so the benign
// non-Go-code warnings never reach the terminal; only surface them on failure.
env := map[string]string{"GOROOT": goRoot}

var stderr strings.Builder

if _, err := sh.Exec(env, outFile, &stderr, cmdAbsPath, reportArgs...); err != nil {
mageutil.PrintLicenseOutput(stderr.String())

return mageutil.PrintAndReturnError(errorText, ErrCheck, err)
}

mageutil.MagePrintln(mageutil.MsgSuccess, successText)

return nil
}
38 changes: 38 additions & 0 deletions magefiles/mageutil/mageutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,44 @@ func CreateLicenseDir() error {
return createDir(LicenseDir())
}

// PrintLicenseOutput filters benign go-licenses warnings out of output and prints whatever remains.
func PrintLicenseOutput(output string) {
filtered := FilterLicenseNoise(output)
if filtered == "" {
return
}

for _, line := range strings.Split(filtered, "\n") {
MagePrintln(MsgInfo, line)
}
}

// FilterLicenseNoise strips go-licenses' benign "contains non-Go code" glog warnings (and their
// following file-path continuation lines) from the given output, returning the remaining lines.
func FilterLicenseNoise(output string) string {
var kept []string

skipping := false

for _, line := range strings.Split(output, "\n") {
switch {
case strings.Contains(line, "contains non-Go code that can't be inspected"):
// Start of a warning block; drop this line and its path continuation lines.
skipping = true
case skipping && strings.HasPrefix(line, "/"):
// Continuation file path under the current warning; drop it.
default:
skipping = false

if strings.TrimSpace(line) != "" {
kept = append(kept, line)
}
}
}

return strings.Join(kept, "\n")
}

// getCallerFunctionName returns the name of the function that called the function that called it.
// fnDepth is the number of functions to go back in the call stack to find the user's function name.
func getCallerFunctionName(fnDepth int) string {
Expand Down
Loading