Use urfave/cli functionality for configuration
Instead of re-inventing the wheel regarding configuration location handling and validation, introduce a new command flag `--config` allowing for full flexibility of configuration filename and location. Even environment variable overrides are used so that the custom env lookup is unnecessary. Signed-off-by: Steven Kriegler <sk.bunsenbrenner@gmail.com>
This commit is contained in:
parent
5cb3daab60
commit
85d9e671fd
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"gitea-sonarqube-pr-bot/internal/api"
|
||||
giteaSdk "gitea-sonarqube-pr-bot/internal/clients/gitea"
|
||||
|
@ -15,23 +14,22 @@ import (
|
|||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func getConfigLocation() string {
|
||||
configPath := path.Join("config")
|
||||
if customConfigPath, ok := os.LookupEnv("PRBOT_CONFIG_PATH"); ok {
|
||||
configPath = customConfigPath
|
||||
}
|
||||
|
||||
return configPath
|
||||
}
|
||||
|
||||
func main() {
|
||||
settings.Load(getConfigLocation())
|
||||
|
||||
app := &cli.App{
|
||||
Name: "gitea-sonarqube-pr-bot",
|
||||
Usage: "Improve your experience with SonarQube and Gitea",
|
||||
Description: `By default, gitea-sonarqube-pr-bot will start running the webserver if no arguments are passed.`,
|
||||
Action: serveApi,
|
||||
Flags: []cli.Flag{
|
||||
&cli.PathFlag{
|
||||
Name: "config",
|
||||
Aliases: []string{"c"},
|
||||
Value: "./config/config.yaml",
|
||||
Usage: "Full path to configuration file.",
|
||||
EnvVars: []string{"GITEA_SQ_BOT_CONFIG_PATH"},
|
||||
TakesFile: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := app.Run(os.Args)
|
||||
|
@ -42,6 +40,7 @@ func main() {
|
|||
|
||||
func serveApi(c *cli.Context) error {
|
||||
fmt.Println("Hi! I'm the Gitea-SonarQube-PR bot. At your service.")
|
||||
settings.Load(c.Path("config"))
|
||||
|
||||
giteaHandler := api.NewGiteaWebhookHandler(giteaSdk.New(), sonarQubeSdk.New())
|
||||
sqHandler := api.NewSonarQubeWebhookHandler(giteaSdk.New(), sonarQubeSdk.New())
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetConfigLocationWithDefault(t *testing.T) {
|
||||
assert.Equal(t, "config", getConfigLocation())
|
||||
}
|
||||
|
||||
func TestGetConfigLocationWithEnvironmentOverride(t *testing.T) {
|
||||
os.Setenv("PRBOT_CONFIG_PATH", "/tmp/")
|
||||
|
||||
assert.Equal(t, "/tmp/", getConfigLocation())
|
||||
|
||||
t.Cleanup(func() {
|
||||
os.Unsetenv("PRBOT_CONFIG_PATH")
|
||||
})
|
||||
}
|
|
@ -13,10 +13,9 @@ var (
|
|||
Projects []Project
|
||||
)
|
||||
|
||||
func newConfigReader() *viper.Viper {
|
||||
func newConfigReader(configFile string) *viper.Viper {
|
||||
v := viper.New()
|
||||
v.SetConfigName("config.yaml")
|
||||
v.SetConfigType("yaml")
|
||||
v.SetConfigFile(configFile)
|
||||
v.SetEnvPrefix("prbot")
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
v.AllowEmptyEnv(true)
|
||||
|
@ -38,9 +37,8 @@ func newConfigReader() *viper.Viper {
|
|||
return v
|
||||
}
|
||||
|
||||
func Load(configPath string) {
|
||||
r := newConfigReader()
|
||||
r.AddConfigPath(configPath)
|
||||
func Load(configFile string) {
|
||||
r := newConfigReader(configFile)
|
||||
|
||||
err := r.ReadInConfig()
|
||||
if err != nil {
|
||||
|
|
|
@ -31,7 +31,7 @@ projects:
|
|||
name: pr-bot
|
||||
`)
|
||||
|
||||
func WriteConfigFile(t *testing.T, content []byte) {
|
||||
func WriteConfigFile(t *testing.T, content []byte) string {
|
||||
dir := os.TempDir()
|
||||
config := path.Join(dir, "config.yaml")
|
||||
|
||||
|
@ -40,21 +40,23 @@ func WriteConfigFile(t *testing.T, content []byte) {
|
|||
})
|
||||
|
||||
_ = ioutil.WriteFile(config, content, 0444)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func TestLoadWithMissingFile(t *testing.T) {
|
||||
assert.Panics(t, func() { Load(os.TempDir()) }, "No panic while reading missing file")
|
||||
assert.Panics(t, func() { Load(path.Join(os.TempDir(), "config.yaml")) }, "No panic while reading missing file")
|
||||
}
|
||||
|
||||
func TestLoadWithExistingFile(t *testing.T) {
|
||||
WriteConfigFile(t, defaultConfig)
|
||||
c := WriteConfigFile(t, defaultConfig)
|
||||
|
||||
assert.NotPanics(t, func() { Load(os.TempDir()) }, "Unexpected panic while reading existing file")
|
||||
assert.NotPanics(t, func() { Load(c) }, "Unexpected panic while reading existing file")
|
||||
}
|
||||
|
||||
func TestLoadGiteaStructure(t *testing.T) {
|
||||
WriteConfigFile(t, defaultConfig)
|
||||
Load(os.TempDir())
|
||||
c := WriteConfigFile(t, defaultConfig)
|
||||
Load(c)
|
||||
|
||||
expected := GiteaConfig{
|
||||
Url: "https://example.com/gitea",
|
||||
|
@ -72,8 +74,8 @@ func TestLoadGiteaStructure(t *testing.T) {
|
|||
func TestLoadGiteaStructureInjectedEnvs(t *testing.T) {
|
||||
os.Setenv("PRBOT_GITEA_WEBHOOK_SECRET", "injected-webhook-secret")
|
||||
os.Setenv("PRBOT_GITEA_TOKEN_VALUE", "injected-token")
|
||||
WriteConfigFile(t, defaultConfig)
|
||||
Load(os.TempDir())
|
||||
c := WriteConfigFile(t, defaultConfig)
|
||||
Load(c)
|
||||
|
||||
expected := GiteaConfig{
|
||||
Url: "https://example.com/gitea",
|
||||
|
@ -94,8 +96,8 @@ func TestLoadGiteaStructureInjectedEnvs(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLoadSonarQubeStructure(t *testing.T) {
|
||||
WriteConfigFile(t, defaultConfig)
|
||||
Load(os.TempDir())
|
||||
c := WriteConfigFile(t, defaultConfig)
|
||||
Load(c)
|
||||
|
||||
expected := SonarQubeConfig{
|
||||
Url: "https://example.com/sonarqube",
|
||||
|
@ -112,7 +114,7 @@ func TestLoadSonarQubeStructure(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLoadSonarQubeStructureWithAdditionalMetrics(t *testing.T) {
|
||||
WriteConfigFile(t, []byte(
|
||||
c := WriteConfigFile(t, []byte(
|
||||
`gitea:
|
||||
url: https://example.com/gitea
|
||||
token:
|
||||
|
@ -129,7 +131,7 @@ projects:
|
|||
owner: example-organization
|
||||
name: pr-bot
|
||||
`))
|
||||
Load(os.TempDir())
|
||||
Load(c)
|
||||
|
||||
expected := SonarQubeConfig{
|
||||
Url: "https://example.com/sonarqube",
|
||||
|
@ -152,8 +154,8 @@ projects:
|
|||
func TestLoadSonarQubeStructureInjectedEnvs(t *testing.T) {
|
||||
os.Setenv("PRBOT_SONARQUBE_WEBHOOK_SECRET", "injected-webhook-secret")
|
||||
os.Setenv("PRBOT_SONARQUBE_TOKEN_VALUE", "injected-token")
|
||||
WriteConfigFile(t, defaultConfig)
|
||||
Load(os.TempDir())
|
||||
c := WriteConfigFile(t, defaultConfig)
|
||||
Load(c)
|
||||
|
||||
expected := SonarQubeConfig{
|
||||
Url: "https://example.com/sonarqube",
|
||||
|
@ -186,7 +188,7 @@ func TestLoadStructureWithFileReferenceResolving(t *testing.T) {
|
|||
sonarqubeTokenFile := path.Join(os.TempDir(), "token-secret-sonarqube")
|
||||
_ = ioutil.WriteFile(sonarqubeTokenFile, []byte(`a09eb5785b25bb2cbacf48808a677a0709f02d8e`), 0444)
|
||||
|
||||
WriteConfigFile(t, []byte(
|
||||
c := WriteConfigFile(t, []byte(
|
||||
`gitea:
|
||||
url: https://example.com/gitea
|
||||
token:
|
||||
|
@ -232,7 +234,7 @@ projects:
|
|||
AdditionalMetrics: []string{},
|
||||
}
|
||||
|
||||
Load(os.TempDir())
|
||||
Load(c)
|
||||
assert.EqualValues(t, expectedGitea, Gitea)
|
||||
assert.EqualValues(t, expectedSonarQube, SonarQube)
|
||||
|
||||
|
@ -249,8 +251,8 @@ projects:
|
|||
}
|
||||
|
||||
func TestLoadProjectsStructure(t *testing.T) {
|
||||
WriteConfigFile(t, defaultConfig)
|
||||
Load(os.TempDir())
|
||||
c := WriteConfigFile(t, defaultConfig)
|
||||
Load(c)
|
||||
|
||||
expectedProjects := []Project{
|
||||
{
|
||||
|
@ -283,7 +285,7 @@ sonarqube:
|
|||
secret: haxxor-sonarqube-secret
|
||||
projects: []
|
||||
`)
|
||||
WriteConfigFile(t, invalidConfig)
|
||||
c := WriteConfigFile(t, invalidConfig)
|
||||
|
||||
assert.Panics(t, func() { Load(os.TempDir()) }, "No panic for empty project mapping that is required")
|
||||
assert.Panics(t, func() { Load(c) }, "No panic for empty project mapping that is required")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue