Repository: google/addlicense (language: python)

Issue:
Fix empty year generated copyright
Currently if the year is set to empty string `-y=""` the first header will have two consecutive empty spaces between `Copyright` and `Holder`.

Now:
`// Copyright[ ][ ]OpenTelemetry Authors`

After:
`// Copyright[ ]OpenTelemetry Authors`


Discussion / hints:
Unfortunately the markdown decided that 2 consecutive spaces are not ok in the `now` example. but you can look at the raw text.

Fix patch:
diff --git a/tmpl.go b/tmpl.go
index ca83657..eed87cf 100644
--- a/tmpl.go
+++ b/tmpl.go
@@ -101,7 +101,7 @@ func executeTemplate(t *template.Template, d licenseData, top, mid, bot string)
 	return out.Bytes(), nil
 }
 
-const tmplApache = `Copyright {{.Year}} {{.Holder}}
+const tmplApache = `Copyright{{ if .Year }} {{.Year}}{{ end }} {{.Holder}}
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -115,11 +115,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.`
 
-const tmplBSD = `Copyright (c) {{.Year}} {{.Holder}} All rights reserved.
+const tmplBSD = `Copyright (c){{ if .Year }} {{.Year}}{{ end }} {{.Holder}} All rights reserved.
 Use of this source code is governed by a BSD-style
 license that can be found in the LICENSE file.`
 
-const tmplMIT = `Copyright (c) {{.Year}} {{.Holder}}
+const tmplMIT = `Copyright (c){{ if .Year }} {{.Year}}{{ end }} {{.Holder}}
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
@@ -142,7 +142,7 @@ const tmplMPL = `This Source Code Form is subject to the terms of the Mozilla Pu
 License, v. 2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at https://mozilla.org/MPL/2.0/.`
 
-const tmplSPDX = `{{ if and .Year .Holder }}Copyright {{.Year}} {{.Holder}}
+const tmplSPDX = `{{ if .Holder }}Copyright{{ if .Year }} {{.Year}}{{ end }} {{.Holder}}
 {{ end }}SPDX-License-Identifier: {{.SPDXID}}`
 
 const spdxSuffix = "\n\nSPDX-License-Identifier: {{.SPDXID}}"


Test patch:
diff --git a/tmpl_test.go b/tmpl_test.go
index d9a26bc..509c741 100644
--- a/tmpl_test.go
+++ b/tmpl_test.go
@@ -141,30 +141,35 @@ func TestFetchTemplate(t *testing.T) {
 
 func TestExecuteTemplate(t *testing.T) {
 	tests := []struct {
+		name          string
 		template      string
 		data          licenseData
 		top, mid, bot string
 		want          string
 	}{
 		{
+			"empty template",
 			"",
 			licenseData{},
 			"", "", "",
 			"\n",
 		},
 		{
+			"no extra",
 			"{{.Holder}}{{.Year}}{{.SPDXID}}",
 			licenseData{Holder: "H", Year: "Y", SPDXID: "S"},
 			"", "", "",
 			"HYS\n\n",
 		},
 		{
+			"only mid",
 			"{{.Holder}}{{.Year}}{{.SPDXID}}",
 			licenseData{Holder: "H", Year: "Y", SPDXID: "S"},
 			"", "// ", "",
 			"// HYS\n\n",
 		},
 		{
+			"top, mid, bot",
 			"{{.Holder}}{{.Year}}{{.SPDXID}}",
 			licenseData{Holder: "H", Year: "Y", SPDXID: "S"},
 			"/*", " * ", "*/",
@@ -173,24 +178,97 @@ func TestExecuteTemplate(t *testing.T) {
 
 		// ensure we don't escape HTML characters by using the wrong template package
 		{
+			"html chars",
 			"{{.Holder}}",
 			licenseData{Holder: "A&Z"},
 			"", "", "",
 			"A&Z\n\n",
 		},
+
+		// empty near should not add a space
+		{
+			"no year, apache",
+			tmplApache,
+			licenseData{Holder: "Holder"},
+			"", "", "",
+			`Copyright Holder
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+`,
+		},
+		{
+			"no year, BSD",
+			tmplBSD,
+			licenseData{Holder: "Holder"},
+			"", "", "",
+			`Copyright (c) Holder All rights reserved.
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file.
+
+`,
+		},
+		{
+			"no year, MIT",
+			tmplMIT,
+			licenseData{Holder: "Holder"},
+			"", "", "",
+			`Copyright (c) Holder
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+`,
+		},
+		{
+			"no year, SPDX",
+			tmplSPDX,
+			licenseData{Holder: "Holder", SPDXID: "Spdx"},
+			"", "", "",
+			`Copyright Holder
+SPDX-License-Identifier: Spdx
+
+`,
+		},
 	}
 
 	for _, tt := range tests {
-		tpl, err := template.New("").Parse(tt.template)
-		if err != nil {
-			t.Errorf("error parsing template: %v", err)
-		}
-		got, err := executeTemplate(tpl, tt.data, tt.top, tt.mid, tt.bot)
-		if err != nil {
-			t.Errorf("executeTemplate(%q, %v, %q, %q, %q) returned error: %v", tt.template, tt.data, tt.top, tt.mid, tt.bot, err)
-		}
-		if string(got) != tt.want {
-			t.Errorf("executeTemplate(%q, %v, %q, %q, %q) returned %q, want: %q", tt.template, tt.data, tt.top, tt.mid, tt.bot, string(got), tt.want)
-		}
+		t.Run(tt.name, func(t *testing.T) {
+			tpl, err := template.New("").Parse(tt.template)
+			if err != nil {
+				t.Errorf("error parsing template: %v", err)
+			}
+			got, err := executeTemplate(tpl, tt.data, tt.top, tt.mid, tt.bot)
+			if err != nil {
+				t.Errorf("returned error: %v", err)
+			}
+			if string(got) != tt.want {
+				t.Errorf("returned \n%q\n, want: \n%q", string(got), tt.want)
+			}
+		})
 	}
 }