Skip to content

Commit

Permalink
Adding automation to add boilerplate license/copyrights headers
Browse files Browse the repository at this point in the history
Signed-off-by: Mohit Sharma <[email protected]>
  • Loading branch information
mohitsharma-in committed Mar 7, 2023
1 parent 0dc180c commit 8630c6f
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 0 deletions.
46 changes: 46 additions & 0 deletions hack/k-license/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# k-license

## Prepends project files with given template.

* Can be used for adding licence or copyright information on src files of project.
* Skip directory, if template (as provided) already present
* Supports Golang/Python source files, Dockerfile, Makefiles and bash scripts

## Build

`go build -o k-license main.go `

Example
To Apply header from ./templates folder default
```
$ k-license --path=temp
Modified temp/Dockerfile file
Modified temp/create-specinfo.py file
Modified temp/install-dependencies.sh file
```

## Help

```
./k-license --help
Usage: ./k-lic [--help] [-d dir] [--exclude ] [--templates] [--author]
Add a copyright/license header to all source files in a Git repository.
Options:
-author string
Replace Author/ORG name (default "The Kubernetes Authors")
-exclude string
comma-separated list of directories to exclude (default ".git,vendor,node_modules")
-help
Display this help message and exit.
-path string
Absolute Path to directory location (default ".")
-templates string
directory containing license templates (default "./templates")
Examples:
./k-lic # Add license headers to all source files in the current directory and its subdirectories, using the default file extensions and templates directory.
./k-lic --dir /path/to/repo --exclude vendor,node_modules --templates /path/to/templates # Add license headers to all .go, .sh, .py, makefile, docker files in /path/to/repo and its subdirectories, using the license header templates in /path/to/templates.
```
138 changes: 138 additions & 0 deletions hack/k-license/k-license.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package main

import (
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)

var (
templatesDir = flag.String("templates", "../boilerplate", "directory containing license templates")
excludeDirs = flag.String("exclude", ".git,vendor,node_modules", "comma-separated list of directories to exclude")
path = flag.String("path", ".", "Absolute Path to directory location")
author = flag.String("author", "The Kubernetes Authors", "Replace Author/ORG name")
helpFlag = flag.Bool("help", false, "Display this help message and exit.")
)

func main() {
flag.Parse()
if *helpFlag {
printHelp(os.Args[0])
return
}
excludeList := strings.Split(*excludeDirs, ",")
err := filepath.Walk(*path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() && contains(excludeList, info.Name()) {
return filepath.SkipDir
}
if !info.IsDir() && (isCodeFile(path) || isBuildFile(path)) && !hasLicense(path) {
currentYear := strconv.Itoa(time.Now().Year())
err := addLicense(path, *templatesDir, currentYear, *author)
if err != nil {
return err
}
fmt.Printf("Modified %s file\n", path)
}

return nil
})
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

func contains(list []string, str string) bool {
for _, item := range list {
if item == str {
return true
}
}
return false
}

func printHelp(progName string) {
fmt.Fprintf(os.Stderr, "Usage: %s [--help] [-d dir] [--exclude ] [--templates] [--author]\n", progName)
fmt.Fprintln(os.Stderr, "\nAdd a copyright/license header to all source files in a Git repository.\n")
fmt.Fprintln(os.Stderr, "Options:")
flag.PrintDefaults()
fmt.Fprintln(os.Stderr, "\nExamples:")
fmt.Fprintf(os.Stderr, " %s # Add license headers to all source files in the current directory and its subdirectories, using the default file extensions and templates directory.\n", progName)
fmt.Fprintf(os.Stderr, " %s --dir /path/to/repo --exclude vendor,node_modules --templates /path/to/templates # Add license headers to all .go, .sh, .py, makefile, docker files in /path/to/repo and its subdirectories, using the license header templates in /path/to/templates.\n", progName)
}

func isCodeFile(path string) bool {
ext := strings.ToLower(filepath.Ext(path))
switch ext {
case ".go", ".c", ".h", ".cpp", ".py", ".ipynb", ".java":
return true
}
return false
}
func isBuildFile(path string) bool {
switch {
case strings.HasSuffix(path, ".sh"):
return true
case strings.HasSuffix(path, "Makefile"):
return true
case strings.HasSuffix(path, "Dockerfile"):
return true
}
return false
}

func hasLicense(path string) bool {
data, err := ioutil.ReadFile(path)
if err != nil {
return false
}
return strings.Contains(string(data), "Copyright")
}
func getFileType(path string) string {
var tmplFilename string
switch {
case strings.HasSuffix(path, ".sh"):
tmplFilename = "boilerplate.sh.txt"
case strings.HasSuffix(path, "Makefile"):
tmplFilename = "boilerplate.Makefile.txt"
case strings.HasSuffix(path, "Dockerfile"):
tmplFilename = "boilerplate.Dockerfile.txt"
case filepath.Ext(path) == ".py":
tmplFilename = "boilerplate.py.txt"
case filepath.Ext(path) == ".go":
tmplFilename = "boilerplate.go.txt"
default:
tmplFilename = "boilerplate.tf.txt"
}
return tmplFilename
}

func addLicense(path, templatesDir, year, author string) error {

tmplData, err := ioutil.ReadFile(filepath.Join(templatesDir, getFileType(path)))
if err != nil {
return err
}

// Replace placeholders with actual values
tmpl := strings.ReplaceAll(string(tmplData), "<YYYY>", year)
tmpl = strings.ReplaceAll(tmpl, "<Organization Name>", author)

codeData, err := ioutil.ReadFile(path)
if err != nil {
return err
}

newData := append([]byte(tmpl), []byte("\n\n")...)
newData = append(newData, codeData...)

return ioutil.WriteFile(path, newData, 0644)
}
39 changes: 39 additions & 0 deletions hack/k-license/k-license_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

import (
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
)

func TestAddLicense(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "testdir")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)

testfile := filepath.Join(tmpdir, "testfile.go")
err = ioutil.WriteFile(testfile, []byte("package main\n\nfunc main() {\n}\n"), 0644)
if err != nil {
t.Fatal(err)
}
currentYear := strconv.Itoa(time.Now().Year())
err = addLicense(testfile, "./templates", currentYear, "")
if err != nil {
t.Fatal(err)
}

data, err := ioutil.ReadFile(testfile)
if err != nil {
t.Fatal(err)
}

if !strings.Contains(string(data), "Copyright") {
t.Errorf("License not added")
}
}

0 comments on commit 8630c6f

Please sign in to comment.