From 3d2cb5d459fc01614f66caacafbdbe531642bae9 Mon Sep 17 00:00:00 2001 From: Ivan Ribakov Date: Fri, 24 Jan 2025 17:30:06 +0100 Subject: [PATCH 1/5] Make addlicense.spdxFlag type public --- addlicense/main.go | 22 +++++++++++----------- addlicense/tmpl.go | 2 +- addlicense/tmpl_test.go | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/addlicense/main.go b/addlicense/main.go index c0e8963..c711bc1 100644 --- a/addlicense/main.go +++ b/addlicense/main.go @@ -53,7 +53,7 @@ Flags: var ( skipExtensionFlags stringSlice ignorePatterns stringSlice - spdx spdxFlag + spdx SpdxFlag holder = flag.String("c", "Google LLC", "copyright holder") license = flag.String("l", "apache", "license type: apache, bsd, mit, mpl") @@ -85,22 +85,22 @@ func (i *stringSlice) Set(value string) error { return nil } -// spdxFlag defines the line flag behavior for specifying SPDX support. -type spdxFlag string +// SpdxFlag defines the line flag behavior for specifying SPDX support. +type SpdxFlag string const ( - spdxOff spdxFlag = "" - spdxOn spdxFlag = "true" // value set by flag package on bool flag - spdxOnly spdxFlag = "only" + spdxOff SpdxFlag = "" + spdxOn SpdxFlag = "true" // value set by flag package on bool flag + spdxOnly SpdxFlag = "only" ) // IsBoolFlag causes a bare '-s' flag to be set as the string 'true'. This // allows the use of the bare '-s' or setting a string '-s=only'. -func (i *spdxFlag) IsBoolFlag() bool { return true } -func (i *spdxFlag) String() string { return string(*i) } +func (i *SpdxFlag) IsBoolFlag() bool { return true } +func (i *SpdxFlag) String() string { return string(*i) } -func (i *spdxFlag) Set(value string) error { - v := spdxFlag(value) +func (i *SpdxFlag) Set(value string) error { + v := SpdxFlag(value) if v != spdxOn && v != spdxOnly { return fmt.Errorf("error: flag 's' expects '%v' or '%v'", spdxOn, spdxOnly) } @@ -180,7 +180,7 @@ func validatePatterns(patterns []string) error { // Run executes addLicense with supplied variables func Run( ignorePatternList []string, - spdx spdxFlag, + spdx SpdxFlag, license LicenseData, licenseFileOverride string, // Provide a file to use as the license header verbose bool, diff --git a/addlicense/tmpl.go b/addlicense/tmpl.go index 8eba269..6646657 100644 --- a/addlicense/tmpl.go +++ b/addlicense/tmpl.go @@ -50,7 +50,7 @@ type LicenseData struct { // optional templateFile. If templateFile is provided, the license is read // from the specified file. Otherwise, a template is loaded for the specified // license, if recognized. -func fetchTemplate(license string, templateFile string, spdx spdxFlag) (string, error) { +func fetchTemplate(license string, templateFile string, spdx SpdxFlag) (string, error) { var t string if spdx == spdxOnly { t = tmplSPDX diff --git a/addlicense/tmpl_test.go b/addlicense/tmpl_test.go index 93635cc..56c8e74 100644 --- a/addlicense/tmpl_test.go +++ b/addlicense/tmpl_test.go @@ -34,7 +34,7 @@ func TestFetchTemplate(t *testing.T) { description string // test case description license string // license passed to fetchTemplate templateFile string // templatefile passed to fetchTemplate - spdx spdxFlag // spdx value passed to fetchTemplate + spdx SpdxFlag // spdx value passed to fetchTemplate wantTemplate string // expected returned template wantErr error // expected returned error }{ From 106b98cf72bb88221eb2efac998acc89906ef7a0 Mon Sep 17 00:00:00 2001 From: Ivan Ribakov Date: Fri, 24 Jan 2025 17:32:23 +0100 Subject: [PATCH 2/5] Configure, load and use custom license template --- cmd/headers.go | 23 ++++++++++++++++++++++- config/config.go | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/cmd/headers.go b/cmd/headers.go index 7cae659..94bc98b 100644 --- a/cmd/headers.go +++ b/cmd/headers.go @@ -97,6 +97,27 @@ config, see the "copywrite init" command.`, SPDXID: conf.Project.License, } + // If custom license template is configured, reate a temporary file + // and write template to it + licenseFile := "" + var useSPDX addlicense.SpdxFlag = "only" + if conf.Project.LicenseTemplate != "" { + errMsg := "Failed to create a temporary file for custom license template: %v\n\n" + if f, e := os.CreateTemp("", "copywrite-custom-license.tpl"); e == nil { + licenseFile = f.Name() + useSPDX = "" // Don't force SPDX template in case of custom template + defer os.Remove(f.Name()) + if _, e := f.WriteString(conf.Project.LicenseTemplate); e != nil { + cmd.Print(text.FgRed.Sprintf(errMsg, e)) + return + } + f.Close() + } else { + cmd.Print(text.FgRed.Sprintf(errMsg, e)) + return + } + } + verbose := true // Wrap hclogger to use standard lib's log.Logger @@ -113,7 +134,7 @@ config, see the "copywrite init" command.`, // return a non-zero error code. gha.StartGroup("The following files are missing headers:") - err := addlicense.Run(ignoredPatterns, "only", licenseData, "", verbose, plan, []string{"."}, stdcliLogger) + err := addlicense.Run(ignoredPatterns, useSPDX, licenseData, licenseFile, verbose, plan, []string{"."}, stdcliLogger) gha.EndGroup() cobra.CheckErr(err) diff --git a/config/config.go b/config/config.go index 1b70f03..68962dc 100644 --- a/config/config.go +++ b/config/config.go @@ -29,6 +29,7 @@ type Project struct { CopyrightHolder string `koanf:"copyright_holder"` HeaderIgnore []string `koanf:"header_ignore"` License string `koanf:"license"` + LicenseTemplate string `koanf:"license_template"` // Upstream is optional and only used if a given repo pulls from another Upstream string `koanf:"upstream"` From ea79b258b723afac3abf54b599ef0616f2ad823b Mon Sep 17 00:00:00 2001 From: Ivan Ribakov Date: Fri, 24 Jan 2025 17:44:39 +0100 Subject: [PATCH 3/5] Use ASCII copyright symbol for detecting copyright headers --- addlicense/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addlicense/main.go b/addlicense/main.go index c711bc1..59a2150 100644 --- a/addlicense/main.go +++ b/addlicense/main.go @@ -453,5 +453,6 @@ func hasLicense(b []byte) bool { } return bytes.Contains(bytes.ToLower(b[:n]), []byte("copyright")) || bytes.Contains(bytes.ToLower(b[:n]), []byte("mozilla public")) || - bytes.Contains(bytes.ToLower(b[:n]), []byte("spdx-license-identifier")) + bytes.Contains(bytes.ToLower(b[:n]), []byte("spdx-license-identifier")) || + bytes.Contains(bytes.ToLower(b[:n]), []byte("©")) } From 26fb50819465ead307b4526a93453e5cd62e256d Mon Sep 17 00:00:00 2001 From: Ivan Ribakov Date: Fri, 24 Jan 2025 17:46:57 +0100 Subject: [PATCH 4/5] Update unit tests --- addlicense/main_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/addlicense/main_test.go b/addlicense/main_test.go index bc5f098..ae79d6c 100644 --- a/addlicense/main_test.go +++ b/addlicense/main_test.go @@ -407,6 +407,7 @@ func TestHasLicense(t *testing.T) { {"Subject to the terms of the Mozilla Public License", true}, {"SPDX-License-Identifier: MIT", true}, {"spdx-license-identifier: MIT", true}, + {"© 2000 Acme Inc.", true}, } for _, tt := range tests { From 307896b11742c3bd667862c9e8d6524301bc133c Mon Sep 17 00:00:00 2001 From: Ivan Ribakov Date: Fri, 24 Jan 2025 17:49:16 +0100 Subject: [PATCH 5/5] Code comments --- cmd/headers.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/headers.go b/cmd/headers.go index 94bc98b..8ba6578 100644 --- a/cmd/headers.go +++ b/cmd/headers.go @@ -97,10 +97,12 @@ config, see the "copywrite init" command.`, SPDXID: conf.Project.License, } - // If custom license template is configured, reate a temporary file + // By default force addlicense's SDPX template + var useSPDX addlicense.SpdxFlag = "only" + + // If custom license template is configured, create a temporary file // and write template to it licenseFile := "" - var useSPDX addlicense.SpdxFlag = "only" if conf.Project.LicenseTemplate != "" { errMsg := "Failed to create a temporary file for custom license template: %v\n\n" if f, e := os.CreateTemp("", "copywrite-custom-license.tpl"); e == nil {