build/analysis/haslicense: introduce haslicense lint
This linter checks that all go source code has our copyright header
Change-Id: Ib79c0685d09bfe26ef87b29b22654eafabd7dba6
Reviewed-on: https://review.monogon.dev/c/monogon/+/3444
Reviewed-by: Leopold Schabel <leo@monogon.tech>
Tested-by: Jenkins CI
diff --git a/build/analysis/haslicense/BUILD.bazel b/build/analysis/haslicense/BUILD.bazel
new file mode 100644
index 0000000..3637434
--- /dev/null
+++ b/build/analysis/haslicense/BUILD.bazel
@@ -0,0 +1,12 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "haslicense",
+ srcs = ["haslicense.go"],
+ importpath = "source.monogon.dev/build/analysis/haslicense",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//build/analysis/lib",
+ "@org_golang_x_tools//go/analysis",
+ ],
+)
diff --git a/build/analysis/haslicense/haslicense.go b/build/analysis/haslicense/haslicense.go
new file mode 100644
index 0000000..ff76285
--- /dev/null
+++ b/build/analysis/haslicense/haslicense.go
@@ -0,0 +1,63 @@
+// Copyright The Monogon Project Authors.
+// SPDX-License-Identifier: Apache-2.0
+
+package haslicense
+
+import (
+ "fmt"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+
+ alib "source.monogon.dev/build/analysis/lib"
+)
+
+const header = `// Copyright The Monogon Project Authors.
+// SPDX-License-Identifier: Apache-2.0
+
+`
+
+var Analyzer = &analysis.Analyzer{
+ Name: "haslicense",
+ Doc: "haslicense checks for an existing license header in monogon source code.",
+ Run: func(p *analysis.Pass) (any, error) {
+ for _, file := range p.Files {
+ if alib.IsGeneratedFile(file) {
+ continue
+ }
+
+ if len(file.Comments) > 0 {
+ var sb strings.Builder
+ for _, c := range file.Comments[0].List {
+ sb.WriteString(c.Text)
+ sb.WriteRune('\n')
+ }
+ sb.WriteRune('\n')
+
+ if strings.HasPrefix(sb.String(), header) {
+ continue
+ }
+ }
+
+ p.Report(analysis.Diagnostic{
+ Pos: file.FileStart,
+ End: file.FileStart,
+ Message: "File is missing license header. Please add it.",
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: fmt.Sprintf("should prepend file with `%s`", header),
+ TextEdits: []analysis.TextEdit{
+ {
+ Pos: file.FileStart,
+ End: file.FileStart,
+ NewText: []byte(header),
+ },
+ },
+ },
+ },
+ })
+ }
+
+ return nil, nil
+ },
+}