blob: 2c8a8f07dba7c8fd8e337b5830576516a33b961f [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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.
// Package bufcheck contains the implementations of the lint and breaking change detection rules.
//
// There is a lot of shared logic between the two, and originally they were actually combined into
// one logical entity (where some checks happened to be linters, and some checks happen to be
// breaking change detectors), so some of this is historical.
package bufcheck
import (
"encoding/json"
"fmt"
"io"
"strings"
"text/tabwriter"
"go.uber.org/multierr"
)
// AllRuleFormatStrings is all rule format strings.
var AllRuleFormatStrings = []string{
"text",
"json",
}
// Rule is a rule.
type Rule interface {
json.Marshaler
// ID returns the ID of the Rule.
//
// UPPER_SNAKE_CASE.
ID() string
// Categories returns the categories of the Rule.
//
// UPPER_SNAKE_CASE.
// Sorted.
// May be empty.
Categories() []string
// Purpose returns the purpose of the Rule.
//
// Full sentence.
Purpose() string
}
// PrintRules prints the rules to the writer.
//
// The empty string defaults to text.
func PrintRules(writer io.Writer, rules []Rule, formatString string) (retErr error) {
if len(rules) == 0 {
return nil
}
var asJSON bool
switch s := strings.ToLower(strings.TrimSpace(formatString)); s {
case "", "text":
asJSON = false
case "json":
asJSON = true
default:
return fmt.Errorf("unknown format: %q", s)
}
if !asJSON {
tabWriter := tabwriter.NewWriter(writer, 0, 0, 2, ' ', 0)
defer func() {
retErr = multierr.Append(retErr, tabWriter.Flush())
}()
writer = tabWriter
if _, err := fmt.Fprintln(writer, "ID\tCATEGORIES\tPURPOSE"); err != nil {
return err
}
}
for _, rule := range rules {
if err := printRule(writer, rule, asJSON); err != nil {
return err
}
}
return nil
}
func printRule(writer io.Writer, rule Rule, asJSON bool) error {
if asJSON {
data, err := json.Marshal(rule)
if err != nil {
return err
}
if _, err := fmt.Fprintln(writer, string(data)); err != nil {
return err
}
return nil
}
if _, err := fmt.Fprintf(writer, "%s\t%s\t%s\n", rule.ID(), strings.Join(rule.Categories(), ", "), rule.Purpose()); err != nil {
return err
}
return nil
}