-
Notifications
You must be signed in to change notification settings - Fork 10
/
headers.go
133 lines (112 loc) · 4.62 KB
/
headers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package cmd
import (
"fmt"
"os"
"github.com/hashicorp/copywrite/addlicense"
"github.com/hashicorp/go-hclog"
"github.com/jedib0t/go-pretty/v6/text"
"github.com/samber/lo"
"github.com/spf13/cobra"
)
// Flag variables
var (
plan bool
)
var headersCmd = &cobra.Command{
Use: "headers",
Short: "Adds missing copyright headers to all source code files",
Long: `Recursively checks for all files in the given directory and subdirectories,
adding copyright statements and license headers to any that are missing them.
Autogenerated files and common file types that don't support headers (e.g., prose)
will automatically be exempted. Any other files or folders should be added to the
header_ignore list in your project's .copywrite.hcl config. For help adding a
config, see the "copywrite init" command.`,
GroupID: "common", // Let's put this command in the common section of the help
PreRun: func(cmd *cobra.Command, args []string) {
// Change directory if needed
if dirPath != "." {
err := os.Chdir(dirPath)
cobra.CheckErr(err)
}
// Map command flags to config keys
mapping := map[string]string{
`spdx`: `project.license`,
`copyright-holder`: `project.copyright_holder`,
}
// update the running config with any command-line flags
clobberWithDefaults := false
err := conf.LoadCommandFlags(cmd.Flags(), mapping, clobberWithDefaults)
if err != nil {
cliLogger.Error("Error merging configuration", err)
}
cobra.CheckErr(err)
// Input Validation
isValidSPDX := addlicense.ValidSPDX(conf.Project.License)
if conf.Project.License != "" && !isValidSPDX {
err := fmt.Errorf("invalid SPDX license identifier: %s", conf.Project.License)
cliLogger.Error("Error validating SPDX license", err)
cobra.CheckErr(err)
}
},
Run: func(cmd *cobra.Command, args []string) {
if plan {
cmd.Print(text.FgYellow.Sprint("Executing in dry-run mode. Rerun without the `--plan` flag to apply changes.\n\n"))
}
if conf.Project.License == "" {
cmd.Printf("The --spdx flag was not specified, omitting SPDX license statements.\n\n")
} else {
cmd.Printf("Using license identifier: %s\n", conf.Project.License)
}
cmd.Printf("Using copyright holder: %v\n\n", conf.Project.CopyrightHolder)
if len(conf.Project.HeaderIgnore) == 0 {
cmd.Println("The project.header_ignore list was left empty in config. Processing all files by default.")
} else {
gha.StartGroup("Exempting the following search patterns:")
for _, v := range conf.Project.HeaderIgnore {
cmd.Println(text.FgCyan.Sprint(v))
}
gha.EndGroup()
}
cmd.Println("")
// Append default ignored search patterns (e.g., GitHub Actions workflows)
autoSkippedPatterns := []string{
".github/workflows/**",
".github/dependabot.yml",
"**/node_modules/**",
}
ignoredPatterns := lo.Union(conf.Project.HeaderIgnore, autoSkippedPatterns)
// Construct the configuration addLicense needs to properly format headers
licenseData := addlicense.LicenseData{
Year: "", // by default, we don't include a year in copyright statements
Holder: conf.Project.CopyrightHolder,
SPDXID: conf.Project.License,
}
verbose := true
// Wrap hclogger to use standard lib's log.Logger
stdcliLogger := cliLogger.StandardLogger(&hclog.StandardLoggerOptions{
// InferLevels must be true so that addLicense can set the log level via
// log prefix, e.g. logger.Println("[DEBUG] this is inferred as a debug log")
InferLevels: true,
})
// WARNING: because of the way we redirect cliLogger to os.Stdout, anything
// prefixed with "[ERROR]" will not implicitly be written to stderr.
// However, we propagate errors upward from addlicense and then run a
// cobra.CheckErr on the return, which will indeed output to stderr and
// return a non-zero error code.
gha.StartGroup("The following files are missing headers:")
err := addlicense.Run(ignoredPatterns, "only", licenseData, "", verbose, plan, []string{"."}, stdcliLogger)
gha.EndGroup()
cobra.CheckErr(err)
},
}
func init() {
rootCmd.AddCommand(headersCmd)
// These flags are only locally relevant
headersCmd.Flags().StringVarP(&dirPath, "dirPath", "d", ".", "Path to the directory in which you wish to validate headers")
headersCmd.Flags().BoolVar(&plan, "plan", false, "Performs a dry-run, printing the names of all files missing headers")
// These flags will get mapped to keys in the the global Config
headersCmd.Flags().StringP("spdx", "s", "", "SPDX-compliant license identifier (e.g., 'MPL-2.0')")
headersCmd.Flags().StringP("copyright-holder", "c", "", "Copyright holder (default \"HashiCorp, Inc.\")")
}