Skip to content

Commit

Permalink
Configurable check (#150)
Browse files Browse the repository at this point in the history
* allow to configure the check command

* update linter version + fix new lint issues

* update readme + change flags for consistency

* Don't validate the license names upfront

* simplify the interface

* add extra usage documentation

* add support for unknown licenses

* move global usage comment
  • Loading branch information
becoded authored Sep 28, 2022
1 parent 5d4915e commit 5b8f2a2
Show file tree
Hide file tree
Showing 18 changed files with 427 additions and 54 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ jobs:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
# NOTICE: golangci-lint version should be the same as go.mod. When upgrading, also update go.mod by:
# go get github.com/golangci/[email protected]
version: v1.29
version: v1.49
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ test: FORCE
go test ./...

# Note, when upgrading, also upgrade version in .github/workflows/golangci-lint.yml.
GOLANGCI_LINT_VERSION=v1.29
GOLANGCI_LINT_VERSION=v1.49
lint: FORCE
@which golangci-lint >/dev/null || ( \
echo 'golangci-lint is not installed. Install by:\ngo install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)' \
Expand Down
50 changes: 40 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,19 @@ for licenses considered forbidden.

## Usages

### Global
Typically, specify the Go package that builds your Go binary.
go-licenses expects the same package argument format as `go build`. For examples:

* A rooted import path like `github.com/google/go-licenses` or `github.com/google/go-licenses/licenses`.
* A relative path that denotes the package in that directory, like `.` or `./cmd/some-command`.

To learn more about package argument, run `go help packages`.

To learn more about go-licenses usages, run `go-licenses help`.

### Report

Report usage (default csv output):

```shell
Expand All @@ -192,29 +205,46 @@ Report usage (using custom template file):
go-licenses report <package> [package...] --template=<template_file>
```

### Save

Save licenses, copyright notices and source code (depending on license type):

```shell
go-licenses save <package> [package...] --save_path=<save_path>
```

Checking for forbidden licenses usage:
### Check

Checking for forbidden and unknown licenses usage:

```shell
go-licenses check <package> [package...]
go-licenses check <package> [package...]
```

Typically, specify the Go package that builds your Go binary.
go-licenses expects the same package argument format as `go build`. For examples:
Checking for disallowed license types:

* A rooted import path like `github.com/google/go-licenses` or `github.com/google/go-licenses/licenses`.
* A relative path that denotes the package in that directory, like `.` or `./cmd/some-command`.
```shell
go-licenses check <package> [package...] --disallowed_types=<comma separated license types>
```

To learn more about package argument, run `go help packages`.
Supported license types:
* See `forbidden` list: [github.com/google/licenseclassifier](https://github.com/google/licenseclassifier/blob/e6a9bb99b5a6f71d5a34336b8245e305f5430f99/license_type.go#L341)
* See `notice` list: [github.com/google/licenseclassifier](https://github.com/google/licenseclassifier/blob/e6a9bb99b5a6f71d5a34336b8245e305f5430f99/license_type.go#L249)
* See `permissive` list: [github.com/google/licenseclassifier](https://github.com/google/licenseclassifier/blob/e6a9bb99b5a6f71d5a34336b8245e305f5430f99/license_type.go#L321)
* See `reciprocal` list: [github.com/google/licenseclassifier](https://github.com/google/licenseclassifier/blob/e6a9bb99b5a6f71d5a34336b8245e305f5430f99/license_type.go#L225)
* See `restricted` list: [github.com/google/licenseclassifier](https://github.com/google/licenseclassifier/blob/e6a9bb99b5a6f71d5a34336b8245e305f5430f99/license_type.go#L185)
* See `unencumbered` list: [github.com/google/licenseclassifier](https://github.com/google/licenseclassifier/blob/e6a9bb99b5a6f71d5a34336b8245e305f5430f99/license_type.go#L324)
* `unknown`

To learn more about go-licenses usages, run `go-licenses help`.
Allow only specific license names:

```shell
go-licenses check <package> [package...] --allowed_licenses=<comma separated license names>
```

* See supported license names: [github.com/google/licenseclassifier](https://github.com/google/licenseclassifier/blob/e6a9bb99b5a6f71d5a34336b8245e305f5430f99/license_type.go#L28)

## Build tags
### Build tags

To read dependencies from packages with
[build tags](https://golang.org/pkg/go/build/#hdr-Build_Constraints). Use the
Expand All @@ -233,7 +263,7 @@ github.com/client9/misspell,https://github.com/client9/misspell/blob/master/LICE
github.com/golang/protobuf/proto,https://github.com/golang/protobuf/blob/master/proto/LICENSE,BSD-3-Clause
```

## Ignoring packages
### Ignoring packages

Use the `--ignore` global flag to specify package path prefixes to be ignored.
For example, to ignore your organization's internal packages under `github.com/example-corporation`:
Expand Down
113 changes: 110 additions & 3 deletions check.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,57 @@ package main

import (
"context"
"errors"
"fmt"
"os"
"strings"

"github.com/google/go-licenses/licenses"
"github.com/spf13/cobra"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)

var (
checkHelp = "Checks whether licenses for a package are not Forbidden."
checkHelp = "Checks whether licenses for a package are not allowed."
checkCmd = &cobra.Command{
Use: "check <package> [package...]",
Short: checkHelp,
Long: checkHelp + packageHelp,
Args: cobra.MinimumNArgs(1),
RunE: checkMain,
}

allowedLicenses []string
disallowedTypes []string
)

func init() {
checkCmd.Flags().StringSliceVar(&allowedLicenses, "allowed_licenses", []string{}, "list of allowed license names, can't be used in combination with disallowed_types")
checkCmd.Flags().StringSliceVar(&disallowedTypes, "disallowed_types", []string{}, "list of disallowed license types, can't be used in combination with allowed_licenses (default: forbidden, unknown)")

rootCmd.AddCommand(checkCmd)
}

func checkMain(_ *cobra.Command, args []string) error {
var disallowedLicenseTypes []licenses.Type

allowedLicenseNames := getAllowedLicenseNames()
disallowedLicenseTypes = getDisallowedLicenseTypes()

hasLicenseNames := len(allowedLicenseNames) > 0
hasLicenseType := len(disallowedLicenseTypes) > 0

if hasLicenseNames && hasLicenseType {
return errors.New("allowed_licenses && disallowed_types can't be used at the same time")
}

if !hasLicenseNames && !hasLicenseType {
// fallback to original behaviour to avoid breaking changes
disallowedLicenseTypes = []licenses.Type{licenses.Forbidden, licenses.Unknown}
hasLicenseType = true
}

classifier, err := licenses.NewClassifier(confidenceThreshold)
if err != nil {
return err
Expand All @@ -58,8 +86,18 @@ func checkMain(_ *cobra.Command, args []string) error {
return err
}

if licenseType == licenses.Forbidden {
fmt.Fprintf(os.Stderr, "Forbidden license type %s for library %v\n", licenseName, lib)
if hasLicenseNames && !isAllowedLicenseName(licenseName, allowedLicenseNames) {
fmt.Fprintf(os.Stderr, "Not allowed license %s found for library %v\n", licenseName, lib)
found = true
}

if hasLicenseType && isDisallowedLicenseType(licenseType, disallowedLicenseTypes) {
fmt.Fprintf(
os.Stderr,
"%s license type %s found for library %v\n",
cases.Title(language.English).String(licenseType.String()),
licenseName,
lib)
found = true
}
}
Expand All @@ -70,3 +108,72 @@ func checkMain(_ *cobra.Command, args []string) error {

return nil
}

func getDisallowedLicenseTypes() []licenses.Type {
if len(disallowedTypes) == 0 {
return []licenses.Type{}
}

excludedLicenseTypes := make([]licenses.Type, 0)

for _, v := range disallowedTypes {
switch strings.TrimSpace(strings.ToLower(v)) {
case "forbidden":
excludedLicenseTypes = append(excludedLicenseTypes, licenses.Forbidden)
case "notice":
excludedLicenseTypes = append(excludedLicenseTypes, licenses.Notice)
case "permissive":
excludedLicenseTypes = append(excludedLicenseTypes, licenses.Permissive)
case "reciprocal":
excludedLicenseTypes = append(excludedLicenseTypes, licenses.Reciprocal)
case "restricted":
excludedLicenseTypes = append(excludedLicenseTypes, licenses.Restricted)
case "unencumbered":
excludedLicenseTypes = append(excludedLicenseTypes, licenses.Unencumbered)
case "unknown":
excludedLicenseTypes = append(excludedLicenseTypes, licenses.Unknown)
default:
fmt.Fprintf(
os.Stderr,
"Unknown license type '%s' provided.\n"+
"Allowed types: forbidden, notice, permissive, reciprocal, restricted, unencumbered, unknown\n",
v)
}
}

return excludedLicenseTypes
}

func isDisallowedLicenseType(licenseType licenses.Type, excludedLicenseTypes []licenses.Type) bool {
for _, excluded := range excludedLicenseTypes {
if excluded == licenseType {
return true
}
}

return false
}

func getAllowedLicenseNames() []string {
if len(allowedLicenses) == 0 {
return []string{}
}

var allowed []string

for _, licenseName := range allowedLicenses {
allowed = append(allowed, strings.TrimSpace(licenseName))
}

return allowed
}

func isAllowedLicenseName(licenseName string, allowedLicenseNames []string) bool {
for _, allowed := range allowedLicenseNames {
if allowed == licenseName {
return true
}
}

return false
}
Loading

0 comments on commit 5b8f2a2

Please sign in to comment.