253 lines
6.6 KiB
Go
253 lines
6.6 KiB
Go
|
// Copyright 2021 Woodpecker Authors
|
||
|
//
|
||
|
// 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.
|
||
|
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"os"
|
||
|
"time"
|
||
|
|
||
|
plugLib "git.kle.li/woodpecker/plugin-lib/urfave"
|
||
|
"git.kle.li/woodpecker/plugin-sonar/pkg/plugin"
|
||
|
"git.kle.li/woodpecker/plugin-sonar/pkg/sonar"
|
||
|
"github.com/urfave/cli/v2"
|
||
|
"go.uber.org/zap"
|
||
|
)
|
||
|
|
||
|
var appVersion = "v0.0.1"
|
||
|
|
||
|
func main() {
|
||
|
app := &cli.App{
|
||
|
Name: "Woodpecker-SonarQube-Plugin",
|
||
|
Usage: "Trigger SonarQube scan from a Woodpecker-CI pipeline",
|
||
|
Version: appVersion,
|
||
|
Compiled: time.Now(),
|
||
|
Authors: []*cli.Author{
|
||
|
{
|
||
|
Name: "Michael Amann [@gapodo:kle.li]",
|
||
|
Email: "gapodo@geekvoid.net",
|
||
|
},
|
||
|
},
|
||
|
Copyright: "(c) 2022 Woodpecker Authors",
|
||
|
Before: func(ctx *cli.Context) error {
|
||
|
fmt.Fprintf(ctx.App.Writer, "Woodpecker-CI SonarQube plugin\n")
|
||
|
return nil
|
||
|
},
|
||
|
After: func(ctx *cli.Context) error {
|
||
|
fmt.Fprintf(ctx.App.Writer, "Exiting Woodpecker-CI SonarQube plugin\n")
|
||
|
return nil
|
||
|
},
|
||
|
Action: run,
|
||
|
Flags: Flags(),
|
||
|
}
|
||
|
|
||
|
app.Run(os.Args)
|
||
|
}
|
||
|
|
||
|
func Flags() []cli.Flag {
|
||
|
flags := []cli.Flag{
|
||
|
&cli.StringFlag{
|
||
|
Name: "logLevel",
|
||
|
Usage: "plugin log level (debug, info, warn, error, dpanic, panic, and fatal)",
|
||
|
Value: "info",
|
||
|
EnvVars: []string{"PLUGIN_LOG_LEVEL"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "key",
|
||
|
Usage: "SonarQube project key",
|
||
|
EnvVars: []string{"PLUGIN_SONAR_KEY"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "name",
|
||
|
Usage: "SonarQube project name",
|
||
|
EnvVars: []string{"PLUGIN_SONAR_NAME"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "host-url",
|
||
|
Usage: "SonarQube host url",
|
||
|
EnvVars: []string{"PLUGIN_SONAR_URL"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "token",
|
||
|
Usage: "SonarQube analysis token",
|
||
|
EnvVars: []string{"PLUGIN_SONAR_TOKEN"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "ver",
|
||
|
Usage: "Project version",
|
||
|
EnvVars: []string{"PLUGIN_SONAR_VERSION"},
|
||
|
},
|
||
|
&cli.IntFlag{
|
||
|
Name: "http-timeout",
|
||
|
Usage: "Web request timeout",
|
||
|
Value: 300,
|
||
|
EnvVars: []string{"PLUGIN_TIMEOUT"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "sources",
|
||
|
Usage: "analysis sources",
|
||
|
Value: ".",
|
||
|
EnvVars: []string{"PLUGIN_SOURCES"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "inclusions",
|
||
|
Usage: "code inclusions",
|
||
|
EnvVars: []string{"PLUGIN_INCLUSIONS"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "exclusions",
|
||
|
Usage: "code exclusions",
|
||
|
EnvVars: []string{"PLUGIN_EXCLUSIONS"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "sonar-log-Level",
|
||
|
Usage: "sonar-scanner log level (as per sonar-scanner)",
|
||
|
Value: "INFO",
|
||
|
EnvVars: []string{"PLUGIN_SONAR_LOG_LEVEL"},
|
||
|
},
|
||
|
&cli.BoolFlag{
|
||
|
Name: "showProfiling",
|
||
|
Usage: "showProfiling during analysis",
|
||
|
Value: false,
|
||
|
EnvVars: []string{"PLUGIN_SHOWPROFILING"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "branchAnalysis",
|
||
|
Usage: "execute branchAnalysis (true, auto, false)",
|
||
|
EnvVars: []string{"PLUGIN_BRANCHANALYSIS"},
|
||
|
Value: "false",
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "usingProperties",
|
||
|
Usage: "using sonar-project.properties",
|
||
|
EnvVars: []string{"PLUGIN_USINGPROPERTIES"},
|
||
|
Value: "false",
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "binaries",
|
||
|
Usage: "Java Binaries",
|
||
|
EnvVars: []string{"PLUGIN_BINARIES"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "quality-target",
|
||
|
Usage: "Quality Gate target",
|
||
|
EnvVars: []string{"PLUGIN_QUALITYGATE"},
|
||
|
Value: "OK",
|
||
|
},
|
||
|
&cli.BoolFlag{
|
||
|
Name: "quality-gate-enabled",
|
||
|
Usage: "true or false - stop pipeline if sonar quality gate conditions are not met",
|
||
|
Value: true,
|
||
|
EnvVars: []string{"PLUGIN_SONAR_QUALITY_ENABLED"},
|
||
|
},
|
||
|
&cli.IntFlag{
|
||
|
Name: "quality-gate-timeout",
|
||
|
Usage: "number in seconds for timeout",
|
||
|
Value: 300,
|
||
|
EnvVars: []string{"PLUGIN_SONAR_QUALITY_GATE_TIMEOUT"},
|
||
|
},
|
||
|
&cli.StringFlag{
|
||
|
Name: "artifact-file",
|
||
|
Usage: "Artifact file location that will be generated by the plugin. This file will include information of docker images that are uploaded by the plugin.",
|
||
|
Value: "artifact.json",
|
||
|
EnvVars: []string{"PLUGIN_ARTIFACT_FILE"},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
flags = append(flags, plugLib.BuildFlags()...)
|
||
|
|
||
|
return flags
|
||
|
}
|
||
|
|
||
|
func run(ctx *cli.Context) error {
|
||
|
|
||
|
slog := setupSugaredLogger(ctx.String("logLevel"))
|
||
|
|
||
|
slog.Infow("SonarQube plugin for Woodpecker", "version", appVersion)
|
||
|
|
||
|
slog.Infow("Parsing values from env")
|
||
|
plugin := pluginFromContext(ctx, slog)
|
||
|
slog.Infow("Starting scanner")
|
||
|
plugin.Exec()
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func pluginFromContext(ctx *cli.Context, logger *zap.SugaredLogger) plugin.Plugin {
|
||
|
config := sonar.Config{
|
||
|
Key: ctx.String("key"),
|
||
|
Name: ctx.String("name"),
|
||
|
HostURL: ctx.String("host-url"),
|
||
|
Token: ctx.String("token"),
|
||
|
Version: ctx.String("ver"),
|
||
|
HttpTimeout: ctx.Int("http-timeout"),
|
||
|
Sources: ctx.String("sources"),
|
||
|
Inclusions: ctx.String("inclusions"),
|
||
|
Exclusions: ctx.String("exclusions"),
|
||
|
SonarLogLevel: ctx.String("sonar-log-Level"),
|
||
|
ShowProfiling: ctx.String("showProfiling"),
|
||
|
BranchAnalysis: ctx.String("branchAnalysis"),
|
||
|
UsingProperties: ctx.Bool("usingProperties"),
|
||
|
Binaries: ctx.String("binaries"),
|
||
|
Quality: ctx.String("quality-target"),
|
||
|
QualityEnabled: ctx.Bool("quality-gate-enabled"),
|
||
|
QualityTimeout: ctx.Int("quality-gate-timeout"),
|
||
|
ArtifactFile: ctx.String("artifact-file"),
|
||
|
|
||
|
Logger: logger,
|
||
|
}
|
||
|
|
||
|
bdata := plugLib.BuildDataFromContext(ctx, nil)
|
||
|
|
||
|
plug := plugin.Plugin{
|
||
|
Config: &config,
|
||
|
BuildData: &bdata,
|
||
|
Logger: logger,
|
||
|
}
|
||
|
|
||
|
return plug
|
||
|
}
|
||
|
|
||
|
func setupSugaredLogger(level string) *zap.SugaredLogger {
|
||
|
|
||
|
fmt.Printf("loglevel %s", level)
|
||
|
|
||
|
alvl, err := zap.ParseAtomicLevel(level)
|
||
|
if err != nil {
|
||
|
log.Fatal(fmt.Errorf("provided plugin log level failed to parse \"%s\": %w", level, err))
|
||
|
}
|
||
|
|
||
|
conf := zap.NewProductionConfig()
|
||
|
conf.EncoderConfig.TimeKey = "" // don't print a timestamp
|
||
|
conf.EncoderConfig.CallerKey = "" // don't show caller
|
||
|
conf.Level = alvl
|
||
|
|
||
|
if conf.Level.Level() == zap.DebugLevel {
|
||
|
conf.EncoderConfig.CallerKey = "caller"
|
||
|
conf.EncoderConfig.FunctionKey = "func"
|
||
|
}
|
||
|
|
||
|
logger := zap.Must(conf.Build())
|
||
|
defer logger.Sync()
|
||
|
|
||
|
sugar := logger.Sugar()
|
||
|
|
||
|
sugar.Infow("Logger setup", "levelConf", level)
|
||
|
sugar.Debugw("debug level enabled")
|
||
|
|
||
|
return sugar
|
||
|
}
|