Conversation
|
Hi @wlynch, I finally got some time to fully clean up and migrate the tool here : ) Because the initial PR is huge, I'd hope we focus on the P0 blockers first. We can log any non-blocking items as follow up issues. |
wlynch
left a comment
There was a problem hiding this comment.
Thanks for the PR!
Unfortunately this is a very large change. I've left some initial comments as a first pass, but we'll likely need to do multiple iterations to resolve everything. Something that would greatly help me out for reviewing is if we could break this up into separate PRs. Here's some individual chunks I see that might be good places to break this apart:
- Using module cache for license source.
- Subfile license checking.
- Config file customization.
- Config file overrides.
- Single licenses.txt output.
- Licenses from binary
Thanks!
| } | ||
|
|
||
| func ListModules() ([]Module, error) { | ||
| out, err := exec.Command("go", "list", "-m", "-json", "all").Output() |
There was a problem hiding this comment.
Prefer using https://pkg.go.dev/golang.org/x/tools over invoking the CLI.
In particular, you probably want https://pkg.go.dev/golang.org/x/tools@v0.1.3/go/packages. This is what v1 already does - the missing piece is using the Module field to know where to access the module cache for source files.
There was a problem hiding this comment.
P2
Because this is already abstracted in a package, can be transparently improved with minimum side effect in the future.
After taking a quick look, https://cs.opensource.google/go/x/tools/+/refs/tags/v0.1.3:go/packages/golist.go
packages also use go list under the hood it seems.
Note that the json flag makes output programmatically parsable, so I don't worry much about using the CLI directly.
Do you have concrete scenarios this may be problematic?
| errorArgs := []interface{}{"module", goModule.ImportPath} | ||
| errorArgs = append(errorArgs, args...) | ||
| klog.ErrorS(err, "Failed", errorArgs...) |
There was a problem hiding this comment.
Would this be equivalent?
| errorArgs := []interface{}{"module", goModule.ImportPath} | |
| errorArgs = append(errorArgs, args...) | |
| klog.ErrorS(err, "Failed", errorArgs...) | |
| klog.ErrorS(err, "Failed", "module", goModule.ImportPath, args...) |
There was a problem hiding this comment.
Unfortunately, that's a compile error, because when using args..., golang only allows passing an array, it's not supported to specify some arguments first and then the args...
| } | ||
| } | ||
| if errorCount > 0 { | ||
| return fmt.Errorf("Failed to scan licenses for %v module(s)", errorCount) |
There was a problem hiding this comment.
This is suppressing the error(s) that encountered, which is going to make it difficult for users to see what failed and if they can do anything about it. Consider including the error here.
It might also be worthwhile to try and process all modules prior to writing the output to a file, this way we don't accidentally write partial output.
There was a problem hiding this comment.
Note that the default logging level is warning and users will easily see the entire list of errors because I added klog logging as I encounter each error (and collect them at the same time for a summary at the end).
When I examine licenses, the partially written file is super useful, because I don't need to wait the entire command to finish.
Can you elaborate more why the partially written file can be harmful?
| } | ||
| klog.InfoS("Done: scan licenses of dependencies", "licenseCount", licenseCount, "moduleCount", len(goModules)) | ||
| return nil | ||
| } |
There was a problem hiding this comment.
This func would definitely benefit from some tests. I'd recommend breaking this logic out into it's own func that takes in a io.Writer.
There was a problem hiding this comment.
P1
Agree, I started everything in this file and gradually extracted stuff out. Ideally, all the logic should not be in cmd folder.
| return records, nil | ||
| } | ||
|
|
||
| func LoadLicenseDict(r io.Reader) (LicenseDict, error) { |
| info, err := loadInfo(config.Module.Csv.Path) | ||
| if err != nil { | ||
| klog.ErrorS(err, "Failed: load license info csv") | ||
| os.Exit(1) | ||
| } | ||
| err = complyWithLicenses(info, *config) |
There was a problem hiding this comment.
Requiring a csv to be generated and save is changing the semantic of the save command (e.g. save is now a 2 step process instead of 1).
I'd prefer to keep similar semantics for save, though I think adding a flag to read from csv could be a reasonable alternative.
There was a problem hiding this comment.
P1
Yes, I was aware this was one of the major differences. Let me have a look at the existing behavior and see how save can be done without csv.
In all my cases, I needed to configure some overrides before actually going to the save step. I am curious why that's different for go-licenses v1. Is it because it doesn't scan the full folder?
|
@wlynch thank you so much for putting time to review this thoroughly : ) I understand your concerns, so let me confirm -- we'll proceed like:
How does the structure sound to you? |
Co-authored-by: Billy Lynch <wlynch92@gmail.com>
|
Close, in favor of #70 |
Closed in favor of #70
this PR is a port from https://github.com/Bobgy/go-mod-licenses
Refer to the README included for comparisons with similar tools including go-licenses v1.
This is still under development, see the roadmap & TODOs section for what needs to happen before finalizing a stable release.
This new tool should be able to resolve:
and might help the following (but needs confirmation):