diff --git a/.licenserc.yaml b/.licenserc.yaml index c15acff..df06c9e 100644 --- a/.licenserc.yaml +++ b/.licenserc.yaml @@ -71,6 +71,7 @@ header: # `header` section is configurations for source codes license header. - '**/assets/header-templates/**' - '**/assets/lcs-templates/**' - '**/assets/languages.yaml' + - '**/assets/default-license.tpl' - '**/assets/assets.gen.go' - 'docs/**.svg' diff --git a/README.md b/README.md index 9292c54..1b3d849 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ To check dependencies license in GitHub Actions, add a step in your GitHub workf # log: debug # optional: set the log level. The default value is `info`. # config: .licenserc.yaml # optional: set the config file. The default value is `.licenserc.yaml`. # mode: # optional: Which mode License-Eye should be run in. Choices are `check` or `resolve`. The default value is `check`. + # flags: # optional: Extra flags appended to the command, for example, `--summary=path/to/template.tmpl` ``` ### Docker Image @@ -189,10 +190,11 @@ This command assists human audits of the dependencies licenses. It's exit code i It supports two flags: -|Flag name|Short name|Description| -|---------|----------|-----------| -|`--output`|`-o`|Save the dependencies' `LICENSE` files to a specified directory so that you can put them in distribution package if needed.| -|`--summary`|`-s`|Based on the template, aggregate all dependency information and generate a `LICENSE` file.| +| Flag name | Short name | Description | +|-------------|------------|----------------------------------------------------------------------------------------------------------------------------------------| +| `--output` | `-o` | Save the dependencies' `LICENSE` files to a specified directory so that you can put them in distribution package if needed. | +| `--summary` | `-s` | Based on the template, aggregate all dependency information and generate a `LICENSE` file. | +| `--license` | `-l` | The output path to the LICENSE file to be generated. The default summary format will be used if summary template file is not specified | ```bash license-eye -c test/testdata/.licenserc_for_test_check.yaml dep resolve -o ./dependencies/licenses -s LICENSE.tpl diff --git a/assets/assets.go b/assets/assets.go index 68c32d0..37f9152 100644 --- a/assets/assets.go +++ b/assets/assets.go @@ -26,6 +26,10 @@ import ( //go:embed * var assets embed.FS +func FS() fs.FS { + return assets +} + func Asset(file string) ([]byte, error) { return assets.ReadFile(filepath.ToSlash(file)) } diff --git a/assets/default-license.tpl b/assets/default-license.tpl new file mode 100644 index 0000000..2f1c679 --- /dev/null +++ b/assets/default-license.tpl @@ -0,0 +1,9 @@ +{{.LicenseContent }} +{{ range .Groups }} +======================================================================== +{{.LicenseID}} licenses +======================================================================== +{{range .Deps}} + {{.Name}} {{.Version}} {{.LicenseID}} +{{- end }} +{{ end }} diff --git a/commands/deps_resolve.go b/commands/deps_resolve.go index a130377..2a5e8fe 100644 --- a/commands/deps_resolve.go +++ b/commands/deps_resolve.go @@ -25,6 +25,8 @@ import ( "strings" "text/template" + "github.com/apache/skywalking-eyes/assets" + "github.com/spf13/cobra" "github.com/apache/skywalking-eyes/internal/logger" @@ -32,6 +34,7 @@ import ( ) var outDir string +var licensePath string var summaryTplPath string var summaryTpl *template.Template @@ -41,6 +44,8 @@ func init() { DepsResolveCommand.PersistentFlags().StringVarP(&summaryTplPath, "summary", "s", "", "the template file to write the summary of dependencies' licenses, a new file named \"LICENSE\" will be "+ "created in the same directory as the template file, to save the final summary.") + DepsResolveCommand.PersistentFlags().StringVarP(&licensePath, "license", "l", "", + "the path to the LICENSE file to be generated. The default summary format will be used if summary template file is not specified") } var fileNamePattern = regexp.MustCompile(`[^a-zA-Z0-9\\.\-]`) @@ -66,12 +71,30 @@ var DepsResolveCommand = &cobra.Command{ return err } summaryTplPath = absPath - tpl, err := deps.ParseTemplate(summaryTplPath) + tpl, err := deps.ParseTemplate(os.DirFS(filepath.Dir(absPath)), filepath.Base(absPath)) if err != nil { return err } summaryTpl = tpl } + if licensePath != "" { + absPath, err := filepath.Abs(licensePath) + if err != nil { + return err + } + licensePath = absPath + if err := os.MkdirAll(filepath.Dir(outDir), 0o700); err != nil && !os.IsExist(err) { + return err + } + + if summaryTpl == nil { + tpl, err := deps.ParseTemplate(assets.FS(), "default-license.tpl") + if err != nil { + return err + } + summaryTpl = tpl + } + } return nil }, RunE: func(cmd *cobra.Command, args []string) error { @@ -83,7 +106,7 @@ var DepsResolveCommand = &cobra.Command{ } if summaryTpl != nil { - if err := writeSummary(&report); err != nil { + if err := writeSummary(&report, licensePath); err != nil { return err } } @@ -131,8 +154,11 @@ func writeLicense(result *deps.Result) { } } -func writeSummary(rep *deps.Report) error { - file, err := os.Create(filepath.Join(filepath.Dir(summaryTplPath), "LICENSE")) +func writeSummary(rep *deps.Report, path string) error { + if path == "" { + path = filepath.Join(filepath.Dir(summaryTplPath), "LICENSE") + } + file, err := os.Create(path) if err != nil { return err } diff --git a/commands/header_check.go b/commands/header_check.go index 19f0e97..19644ad 100644 --- a/commands/header_check.go +++ b/commands/header_check.go @@ -74,7 +74,7 @@ func writeSummaryQuietly(result *header.Result) { if result.HasFailure() { _, _ = summaryFile.WriteString(", the following files are lack of license headers:\n") for _, failure := range result.Failure { - _, _ = summaryFile.WriteString(fmt.Sprintf("- %s\n", failure)) + _, _ = fmt.Fprintf(summaryFile, "- %s\n", failure) } } } diff --git a/dependency/action.yml b/dependency/action.yml index 8999902..2c5a97d 100644 --- a/dependency/action.yml +++ b/dependency/action.yml @@ -35,6 +35,10 @@ inputs: default value is `check`. required: false default: check + flags: + description: | + Extra flags appended to the command, for example, --summary=path/to/template.tmpl + required: false runs: using: "composite" steps: @@ -48,4 +52,4 @@ runs: - shell: bash env: GITHUB_TOKEN: ${{ inputs.token }} - run: license-eye -v ${{ inputs.log }} -c ${{ inputs.config }} dependency ${{ inputs.mode }} + run: license-eye -v ${{ inputs.log }} -c ${{ inputs.config }} dependency ${{ inputs.mode }} ${{ inputs.flags }} diff --git a/pkg/deps/summary.go b/pkg/deps/summary.go index a025a44..494443a 100644 --- a/pkg/deps/summary.go +++ b/pkg/deps/summary.go @@ -19,7 +19,7 @@ package deps import ( "bytes" - "os" + "io/fs" "sort" "text/template" @@ -45,8 +45,8 @@ type SummaryRenderLicense struct { LicenseID string // License ID } -func ParseTemplate(path string) (*template.Template, error) { - tpl, err := os.ReadFile(path) +func ParseTemplate(f fs.FS, path string) (*template.Template, error) { + tpl, err := fs.ReadFile(f, path) if err != nil { return nil, err }