Merge pull request #1263 from merico-dev/fix-config-multithread-read-empty

fix: multithread read empty config
diff --git a/api/api.go b/api/api.go
index a3f6cad..8efc44e 100644
--- a/api/api.go
+++ b/api/api.go
@@ -9,7 +9,8 @@
 )
 
 func CreateApiService() {
-	gin.SetMode(config.V.GetString("MODE"))
+	v := config.GetConfig()
+	gin.SetMode(v.GetString("MODE"))
 	router := gin.Default()
 
 	// CORS CONFIG
@@ -23,7 +24,7 @@
 	}))
 
 	RegisterRouter(router)
-	err := router.Run(config.V.GetString("PORT"))
+	err := router.Run(v.GetString("PORT"))
 	if err != nil {
 		panic(err)
 	}
diff --git a/config/config.go b/config/config.go
index bf64ac7..6708a80 100644
--- a/config/config.go
+++ b/config/config.go
@@ -1,61 +1,34 @@
 package config
 
 import (
+	"github.com/sirupsen/logrus"
 	"github.com/spf13/viper"
 )
 
-type Config struct {
-	PORT                               string `mapstructure:"PORT"`
-	DB_URL                             string `mapstructure:"DB_URL"`
-	MODE                               string `mapstructure:"MODE"`
-	JIRA_ENDPOINT                      string `mapstructure:"JIRA_ENDPOINT"`
-	JIRA_BASIC_AUTH_ENCODED            string `mapstructure:"JIRA_BASIC_AUTH_ENCODED"`
-	JIRA_ISSUE_EPIC_KEY_FIELD          string `mapstructure:"JIRA_ISSUE_EPIC_KEY_FIELD"`
-	JIRA_ISSUE_WORKLOAD_FIELD          string `mapstructure:"JIRA_ISSUE_WORKLOAD_FIELD"`
-	JIRA_BOARD_GITLAB_PROJECTS         string `mapstructure:"JIRA_BOARD_GITLAB_PROJECTS"`
-	JIRA_ISSUE_BUG_STATUS_MAPPING      string `mapstructure:"JIRA_ISSUE_BUG_STATUS_MAPPING"`
-	JIRA_ISSUE_INCIDENT_STATUS_MAPPING string `mapstructure:"JIRA_ISSUE_INCIDENT_STATUS_MAPPING"`
-	JIRA_ISSUE_STORY_STATUS_MAPPING    string `mapstructure:"JIRA_ISSUE_STORY_STATUS_MAPPING"`
-	JIRA_ISSUE_TYPE_MAPPING            string `mapstructure:"JIRA_ISSUE_TYPE_MAPPING"`
-	GITLAB_ENDPOINT                    string `mapstructure:"GITLAB_ENDPOINT"`
-	GITLAB_AUTH                        string `mapstructure:"GITLAB_AUTH"`
-	GITHUB_ENDPOINT                    string `mapstructure:"GITHUB_ENDPOINT"`
-	GITHUB_AUTH                        string `mapstructure:"GITHUB_AUTH"`
-	GITHUB_PROXY                       string `mapstructure:"GITHUB_PROXY"`
-	JENKINS_ENDPOINT                   string `mapstructure:"JENKINS_ENDPOINT"`
-	JENKINS_USERNAME                   string `mapstructure:"JENKINS_USERNAME"`
-	JENKINS_PASSWORD                   string `mapstructure:"JENKINS_PASSWORD"`
-	FEISHU_APPID                       string `mapstructure:"FEISHU_APPID"`
-	FEISHU_APPSCRECT                   string `mapstructure:"FEISHU_APPSCRECT"`
-	AE_APP_ID                          string `mapstructure:"AE_APP_ID"`
-	AE_NONCE_STR                       string `mapstructure:"AE_NONCE_STR"`
-	AE_SIGN                            string `mapstructure:"AE_SIGN"`
-	AE_ENDPOINT                        string `mapstructure:"AE_ENDPOINT"`
+// Lowcase V for private this. You can use it by call GetConfig.
+var v *viper.Viper = nil
+
+func GetConfig() *viper.Viper {
+	return v
 }
 
-var V *viper.Viper
-
-func LoadConfigFile() *viper.Viper {
-	V = viper.New()
-	V.SetConfigFile(".env")
-	_ = V.ReadInConfig()
-	V.AutomaticEnv()
-	return V
+// Set default value for no .env or .env not set it
+func setDefaultValue() {
+	v.SetDefault("PORT", ":8080")
+	v.SetDefault("PLUGIN_DIR", "bin/plugins")
 }
 
 func init() {
-	V := LoadConfigFile()
-	V.SetDefault("PORT", ":8080")
-	V.SetDefault("PLUGIN_DIR", "bin/plugins")
-	// This line is essential for reading and writing
-	V.WatchConfig()
-}
-
-func GetConfigJson() (*Config, error) {
-	var configJson Config
-	err := V.Unmarshal(&configJson)
+	// create the object and load the .env file
+	v = viper.New()
+	v.SetConfigFile(".env")
+	err := v.ReadInConfig()
 	if err != nil {
-		return nil, err
+		logrus.Warn("Failed to read [.env] file:", err)
 	}
-	return &configJson, nil
+	v.AutomaticEnv()
+
+	setDefaultValue()
+	// This line is essential for reading and writing
+	v.WatchConfig()
 }
diff --git a/config/config_test.go b/config/config_test.go
index 0412e59..f255fa7 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -6,27 +6,18 @@
 	"github.com/magiconair/properties/assert"
 )
 
-func TestGetConfigJson(t *testing.T) {
-	_, err := GetConfigJson()
-	assert.Equal(t, err == nil, true)
-}
-
 func TestReadAndWriteToConfig(t *testing.T) {
-	// Verify new value is not equal to current value
-	configJson, err := GetConfigJson()
-	assert.Equal(t, err == nil, true)
-	currentDbUrl := configJson.DB_URL
+	v := GetConfig()
+	currentDbUrl := v.GetString("DB_URL")
 	newDbUrl := "ThisIsATest"
 	assert.Equal(t, currentDbUrl != newDbUrl, true)
-	V := LoadConfigFile()
-	V.Set("DB_URL", newDbUrl)
-	err = V.WriteConfig()
+	v.Set("DB_URL", newDbUrl)
+	err := v.WriteConfig()
 	assert.Equal(t, err == nil, true)
-	newConfigJson, err := GetConfigJson()
-	assert.Equal(t, err == nil, true)
-	assert.Equal(t, newConfigJson.DB_URL, newDbUrl)
+	nowDbUrl := v.GetString("DB_URL")
+	assert.Equal(t, nowDbUrl == newDbUrl, true)
 	// Reset back to current
-	V.Set("DB_URL", currentDbUrl)
-	err = V.WriteConfig()
+	v.Set("DB_URL", currentDbUrl)
+	err = v.WriteConfig()
 	assert.Equal(t, err == nil, true)
 }
diff --git a/e2e/database.go b/e2e/database.go
index 4fb224f..2c40673 100644
--- a/e2e/database.go
+++ b/e2e/database.go
@@ -10,8 +10,8 @@
 )
 
 func InitializeDb() (*sql.DB, error) {
-	V := LoadConfigFile()
-	dbUrl := V.GetString("DB_URL")
+	v := LoadConfigFile()
+	dbUrl := v.GetString("DB_URL")
 	db, err := sql.Open("mysql", dbUrl)
 	if err != nil {
 		return nil, err
diff --git a/logger/log.go b/logger/log.go
index b57d893..547c580 100644
--- a/logger/log.go
+++ b/logger/log.go
@@ -29,7 +29,7 @@
 )
 
 func Color(colorString string) func(...interface{}) string {
-	if config.V.GetBool("NO_COLOR") {
+	if config.GetConfig().GetBool("NO_COLOR") {
 		return fmt.Sprint
 	}
 	sprint := func(args ...interface{}) string {
diff --git a/models/init.go b/models/init.go
index 4b0109c..5b28245 100644
--- a/models/init.go
+++ b/models/init.go
@@ -20,8 +20,9 @@
 var Db *gorm.DB
 
 func init() {
-	connectionString := config.V.GetString("DB_URL")
-	if config.V.Get("TEST") == "true" {
+	V := config.GetConfig()
+	connectionString := V.GetString("DB_URL")
+	if V.Get("TEST") == "true" {
 		connectionString = "merico:merico@tcp(localhost:3306)/lake_test"
 	}
 	var err error
diff --git a/plugins/ae/api/ae_sources.go b/plugins/ae/api/ae_sources.go
index bb1580a..c820df4 100644
--- a/plugins/ae/api/ae_sources.go
+++ b/plugins/ae/api/ae_sources.go
@@ -32,22 +32,22 @@
 	if err != nil {
 		return nil, err
 	}
-	V := config.LoadConfigFile()
+	v := config.GetConfig()
 
 	if aeSource.AE_APP_ID != "" {
-		V.Set("AE_SIGN", aeSource.AE_SIGN)
+		v.Set("AE_SIGN", aeSource.AE_SIGN)
 	}
 	if aeSource.AE_SIGN != "" {
-		V.Set("AE_SIGN", aeSource.AE_SIGN)
+		v.Set("AE_SIGN", aeSource.AE_SIGN)
 	}
 	if aeSource.AE_NONCE_STR != "" {
-		V.Set("AE_NONCE_STR", aeSource.AE_NONCE_STR)
+		v.Set("AE_NONCE_STR", aeSource.AE_NONCE_STR)
 	}
 	if aeSource.AE_ENDPOINT != "" {
-		V.Set("AE_ENDPOINT", aeSource.AE_ENDPOINT)
+		v.Set("AE_ENDPOINT", aeSource.AE_ENDPOINT)
 	}
 
-	err = V.WriteConfig()
+	err = v.WriteConfig()
 	if err != nil {
 		return nil, err
 	}
@@ -81,9 +81,9 @@
 }
 
 func GetSourceFromEnv() (*AEResponse, error) {
-	V := config.LoadConfigFile()
+	v := config.GetConfig()
 	var configJson AEConfig
-	err := V.Unmarshal(&configJson)
+	err := v.Unmarshal(&configJson)
 	if err != nil {
 		return nil, err
 	}
diff --git a/plugins/ae/tasks/ae_api_client.go b/plugins/ae/tasks/ae_api_client.go
index 794310d..6f636b2 100644
--- a/plugins/ae/tasks/ae_api_client.go
+++ b/plugins/ae/tasks/ae_api_client.go
@@ -62,11 +62,12 @@
 }
 
 func (client *AEApiClient) beforeRequest(req *http.Request) error {
-	appId := config.V.GetString("AE_APP_ID")
+	V := config.GetConfig()
+	appId := V.GetString("AE_APP_ID")
 	if appId == "" {
 		return fmt.Errorf("invalid AE_APP_ID")
 	}
-	secretKey := config.V.GetString("AE_SECRET_KEY")
+	secretKey := V.GetString("AE_SECRET_KEY")
 	if appId == "" {
 		return fmt.Errorf("invalid AE_SECRET_KEY")
 	}
@@ -83,7 +84,7 @@
 func CreateApiClient(ctx context.Context) *AEApiClient {
 	aeApiClient := &AEApiClient{}
 	aeApiClient.Setup(
-		config.V.GetString("AE_ENDPOINT"),
+		config.GetConfig().GetString("AE_ENDPOINT"),
 		nil,
 		30*time.Second,
 		3,
diff --git a/plugins/compound/compound.go b/plugins/compound/compound.go
index 8a543b2..cd5107e 100644
--- a/plugins/compound/compound.go
+++ b/plugins/compound/compound.go
@@ -24,7 +24,7 @@
 	if err != nil {
 		panic(err)
 	}
-	text := config.V.GetString("JIRA_BOARD_GITLAB_PROJECTS")
+	text := config.GetConfig().GetString("JIRA_BOARD_GITLAB_PROJECTS")
 	if text == "" {
 		return
 	}
diff --git a/plugins/core/plugin_utils.go b/plugins/core/plugin_utils.go
index cdff0c9..2564318 100644
--- a/plugins/core/plugin_utils.go
+++ b/plugins/core/plugin_utils.go
@@ -76,14 +76,14 @@
 // AES + Base64 encryption using ENCODE_KEY in .env as key
 func Encode(Input string) (string, error) {
 	// Read encryption key from configuration
-	V := config.LoadConfigFile()
-	encodingKey := V.GetString(EncodeKeyEnvStr)
+	v := config.GetConfig()
+	encodingKey := v.GetString(EncodeKeyEnvStr)
 	// when encryption key is not set
 	if encodingKey == "" {
 		// Randomly generate a bunch of encryption keys and set them to config
 		encodingKey = RandomCapsStr(128)
-		V.Set(EncodeKeyEnvStr, encodingKey)
-		err := V.WriteConfig()
+		v.Set(EncodeKeyEnvStr, encodingKey)
+		err := v.WriteConfig()
 		if err != nil {
 			return "", err
 		}
@@ -102,8 +102,8 @@
 //  Base64 + AES decryption using ENCODE_KEY in .env as key
 func Decode(Input string) (string, error) {
 	// Read encryption key from configuration
-	V := config.LoadConfigFile()
-	encodingKey := V.GetString(EncodeKeyEnvStr)
+	v := config.GetConfig()
+	encodingKey := v.GetString(EncodeKeyEnvStr)
 	// when encryption key is not set
 	if encodingKey == "" {
 		// return error message
diff --git a/plugins/feishu/feishu.go b/plugins/feishu/feishu.go
index 8e7b153..8e00637 100644
--- a/plugins/feishu/feishu.go
+++ b/plugins/feishu/feishu.go
@@ -4,6 +4,13 @@
 	"context"
 	"encoding/json"
 	"fmt"
+	"net/http"
+	"net/url"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+
 	"github.com/faabiosr/cachego/file"
 	"github.com/fastwego/feishu"
 	"github.com/merico-dev/lake/config"
@@ -13,12 +20,6 @@
 	"github.com/merico-dev/lake/plugins/feishu/apimodels"
 	"github.com/merico-dev/lake/plugins/feishu/models"
 	"github.com/merico-dev/lake/utils"
-	"net/http"
-	"net/url"
-	"os"
-	"strconv"
-	"strings"
-	"time"
 )
 
 var _ core.Plugin = (*Feishu)(nil)
@@ -43,7 +44,6 @@
 func (plugin Feishu) Execute(options map[string]interface{}, progress chan<- float32, ctx context.Context) error {
 	logger.Print("start feishu plugin execution")
 
-	// 需要收集多久的数据
 	// how long do you want to collect
 	numOfDaysToCollect, ok := options["numOfDaysToCollect"]
 	if !ok {
@@ -51,15 +51,14 @@
 	}
 	numOfDaysToCollectInt := int(numOfDaysToCollect.(float64))
 
-	// 内部应用 tenant_access_token 管理器
 	// tenant_access_token manager
-	Atm := &feishu.DefaultAccessTokenManager{
+	atm := &feishu.DefaultAccessTokenManager{
 		Id:    `cli_a074eb7697f8d00b`,
 		Cache: file.New(os.TempDir()),
 		GetRefreshRequestFunc: func() *http.Request {
 			payload := `{
-                "app_id":"` + config.V.GetString("FEISHU_APPID") + `",
-                "app_secret":"` + config.V.GetString("FEISHU_APPSCRECT") + `"
+                "app_id":"` + config.GetConfig().GetString("FEISHU_APPID") + `",
+                "app_secret":"` + config.GetConfig().GetString("FEISHU_APPSCRECT") + `"
             }`
 			req, _ := http.NewRequest(http.MethodPost, feishu.ServerUrl+"/open-apis/auth/v3/tenant_access_token/internal/", strings.NewReader(payload))
 			return req
@@ -76,14 +75,13 @@
 		logger.Error("could not create scheduler", false)
 	}
 
-	// 创建 飞书 客户端
 	// create feishu client
 	FeishuClient := feishu.NewClient()
 
 	progress <- 0
-	// 调用 AccessToken api 接口
+
 	// request AccessToken api
-	tenantAccessToken, err := Atm.GetAccessToken()
+	tenantAccessToken, err := atm.GetAccessToken()
 	if err != nil {
 		return err
 	}
diff --git a/plugins/github/api/github_sources.go b/plugins/github/api/github_sources.go
index 75f52d8..6d019c3 100644
--- a/plugins/github/api/github_sources.go
+++ b/plugins/github/api/github_sources.go
@@ -37,15 +37,15 @@
 	if err != nil {
 		return nil, err
 	}
-	V := config.LoadConfigFile()
+	v := config.GetConfig()
 	if githubSource.GITHUB_ENDPOINT != "" {
-		V.Set("GITHUB_ENDPOINT", githubSource.GITHUB_ENDPOINT)
+		v.Set("GITHUB_ENDPOINT", githubSource.GITHUB_ENDPOINT)
 	}
 	if githubSource.GITHUB_AUTH != "" {
-		V.Set("GITHUB_AUTH", githubSource.GITHUB_AUTH)
+		v.Set("GITHUB_AUTH", githubSource.GITHUB_AUTH)
 	}
-	V.Set("GITHUB_PROXY", githubSource.GITHUB_PROXY)
-	err = V.WriteConfig()
+	v.Set("GITHUB_PROXY", githubSource.GITHUB_PROXY)
+	err = v.WriteConfig()
 	if err != nil {
 		return nil, err
 	}
@@ -79,9 +79,9 @@
 }
 
 func GetSourceFromEnv() (*GithubResponse, error) {
-	V := config.LoadConfigFile()
+	v := config.GetConfig()
 	var configJson GithubConfig
-	err := V.Unmarshal(&configJson)
+	err := v.Unmarshal(&configJson)
 	if err != nil {
 		return nil, err
 	}
diff --git a/plugins/github/github.go b/plugins/github/github.go
index b8439c0..9fa7c9e 100644
--- a/plugins/github/github.go
+++ b/plugins/github/github.go
@@ -101,9 +101,10 @@
 		}
 	}
 
+	v := config.GetConfig()
 	// process configuration
-	endpoint := config.V.GetString("GITHUB_ENDPOINT")
-	tokens := strings.Split(config.V.GetString("GITHUB_AUTH"), ",")
+	endpoint := v.GetString("GITHUB_ENDPOINT")
+	tokens := strings.Split(v.GetString("GITHUB_AUTH"), ",")
 	// setup rate limit
 	tokenCount := len(tokens)
 	if tokenCount == 0 {
@@ -120,7 +121,7 @@
 	defer scheduler.Release()
 	// TODO: add endpoind, auth validation
 	apiClient := tasks.NewGithubApiClient(endpoint, tokens, ctx, scheduler)
-	err = apiClient.SetProxy(config.V.GetString("GITHUB_PROXY"))
+	err = apiClient.SetProxy(v.GetString("GITHUB_PROXY"))
 	if err != nil {
 		return err
 	}
@@ -392,11 +393,12 @@
 	}
 	PluginEntry.Init()
 	progress := make(chan float32)
-	endpoint := config.V.GetString("GITHUB_ENDPOINT")
-	configTokensString := config.V.GetString("GITHUB_AUTH")
+	v := config.GetConfig()
+	endpoint := v.GetString("GITHUB_ENDPOINT")
+	configTokensString := v.GetString("GITHUB_AUTH")
 	tokens := strings.Split(configTokensString, ",")
 	githubApiClient := tasks.NewGithubApiClient(endpoint, tokens, nil, nil)
-	_ = githubApiClient.SetProxy(config.V.GetString("GITHUB_PROXY"))
+	_ = githubApiClient.SetProxy(v.GetString("GITHUB_PROXY"))
 	_, collectRepoErr := tasks.CollectRepository(owner, repo, githubApiClient)
 	if collectRepoErr != nil {
 		fmt.Println(fmt.Errorf("Could not collect repositories: %v", collectRepoErr))
diff --git a/plugins/github/tasks/github_issue_enricher.go b/plugins/github/tasks/github_issue_enricher.go
index 2938b7b..6b298ad 100644
--- a/plugins/github/tasks/github_issue_enricher.go
+++ b/plugins/github/tasks/github_issue_enricher.go
@@ -19,12 +19,13 @@
 var issueTypeIncidentRegex *regexp.Regexp
 
 func init() {
-	var issueSeverity = config.V.GetString("GITHUB_ISSUE_SEVERITY")
-	var issueComponent = config.V.GetString("GITHUB_ISSUE_COMPONENT")
-	var issuePriority = config.V.GetString("GITHUB_ISSUE_PRIORITY")
-	var issueTypeBug = config.V.GetString("GITHUB_ISSUE_TYPE_BUG")
-	var issueTypeRequirement = config.V.GetString("GITHUB_ISSUE_TYPE_REQUIREMENT")
-	var issueTypeIncident = config.V.GetString("GITHUB_ISSUE_TYPE_INCIDENT")
+	v := config.GetConfig()
+	var issueSeverity = v.GetString("GITHUB_ISSUE_SEVERITY")
+	var issueComponent = v.GetString("GITHUB_ISSUE_COMPONENT")
+	var issuePriority = v.GetString("GITHUB_ISSUE_PRIORITY")
+	var issueTypeBug = v.GetString("GITHUB_ISSUE_TYPE_BUG")
+	var issueTypeRequirement = v.GetString("GITHUB_ISSUE_TYPE_REQUIREMENT")
+	var issueTypeIncident = v.GetString("GITHUB_ISSUE_TYPE_INCIDENT")
 	if len(issueSeverity) > 0 {
 		issueSeverityRegex = regexp.MustCompile(issueSeverity)
 	}
diff --git a/plugins/github/tasks/github_pull_request_enricher.go b/plugins/github/tasks/github_pull_request_enricher.go
index 1d8b7f8..f886f24 100644
--- a/plugins/github/tasks/github_pull_request_enricher.go
+++ b/plugins/github/tasks/github_pull_request_enricher.go
@@ -14,8 +14,9 @@
 var labelComponentRegex *regexp.Regexp
 
 func init() {
-	var prType = config.V.GetString("GITHUB_PR_TYPE")
-	var prComponent = config.V.GetString("GITHUB_PR_COMPONENT")
+	V := config.GetConfig()
+	var prType = V.GetString("GITHUB_PR_TYPE")
+	var prComponent = V.GetString("GITHUB_PR_COMPONENT")
 	if len(prType) > 0 {
 		labelTypeRegex = regexp.MustCompile(prType)
 	}
diff --git a/plugins/gitlab/api/gitlab_sources.go b/plugins/gitlab/api/gitlab_sources.go
index 600d2a8..e0c2a6a 100644
--- a/plugins/gitlab/api/gitlab_sources.go
+++ b/plugins/gitlab/api/gitlab_sources.go
@@ -37,7 +37,7 @@
 	if err != nil {
 		return nil, err
 	}
-	V := config.LoadConfigFile()
+	V := config.GetConfig()
 	if gitlabSource.GITLAB_ENDPOINT != "" {
 		V.Set("GITLAB_ENDPOINT", gitlabSource.GITLAB_ENDPOINT)
 	}
@@ -81,7 +81,7 @@
 }
 
 func GetSourceFromEnv() (*GitlabResponse, error) {
-	V := config.LoadConfigFile()
+	V := config.GetConfig()
 	var configJson GitlabConfig
 	err := V.Unmarshal(&configJson)
 	if err != nil {
diff --git a/plugins/gitlab/tasks/gitlab_api_client.go b/plugins/gitlab/tasks/gitlab_api_client.go
index 5729855..30a3c07 100644
--- a/plugins/gitlab/tasks/gitlab_api_client.go
+++ b/plugins/gitlab/tasks/gitlab_api_client.go
@@ -20,10 +20,11 @@
 
 func CreateApiClient(scheduler *utils.WorkerScheduler) *GitlabApiClient {
 	gitlabApiClient := &GitlabApiClient{}
+	V := config.GetConfig()
 	gitlabApiClient.Setup(
-		config.V.GetString("GITLAB_ENDPOINT"),
+		V.GetString("GITLAB_ENDPOINT"),
 		map[string]string{
-			"Authorization": fmt.Sprintf("Bearer %v", config.V.GetString("GITLAB_AUTH")),
+			"Authorization": fmt.Sprintf("Bearer %v", V.GetString("GITLAB_AUTH")),
 		},
 		10*time.Second,
 		3,
diff --git a/plugins/jenkins/api/jenkins_sources.go b/plugins/jenkins/api/jenkins_sources.go
index e313537..17a48b1 100644
--- a/plugins/jenkins/api/jenkins_sources.go
+++ b/plugins/jenkins/api/jenkins_sources.go
@@ -51,11 +51,11 @@
 	if err != nil {
 		return nil, err
 	}
-	V := config.LoadConfigFile()
-	V.Set("JENKINS_ENDPOINT", jenkinsSource.JENKINS_ENDPOINT)
-	V.Set("JENKINS_USERNAME", jenkinsSource.JENKINS_USERNAME)
-	V.Set("JENKINS_PASSWORD", jenkinsSource.JENKINS_PASSWORD)
-	err = V.WriteConfig()
+	v := config.GetConfig()
+	v.Set("JENKINS_ENDPOINT", jenkinsSource.JENKINS_ENDPOINT)
+	v.Set("JENKINS_USERNAME", jenkinsSource.JENKINS_USERNAME)
+	v.Set("JENKINS_PASSWORD", jenkinsSource.JENKINS_PASSWORD)
+	err = v.WriteConfig()
 	if err != nil {
 		return nil, err
 	}
@@ -89,14 +89,11 @@
 }
 
 func GetSourceFromEnv() (*JenkinsSource, error) {
-	configJson, err := config.GetConfigJson()
-	if err != nil {
-		return nil, err
-	}
+	v := config.GetConfig()
 	return &JenkinsSource{
-		Endpoint: configJson.JENKINS_ENDPOINT,
-		Username: configJson.JENKINS_USERNAME,
-		Password: configJson.JENKINS_PASSWORD,
+		Endpoint: v.GetString("JENKINS_ENDPOINT"),
+		Username: v.GetString("JENKINS_USERNAME"),
+		Password: v.GetString("JENKINS_PASSWORD"),
 		// The UI relies on a source ID here but we will hardcode it until the sources work is done for Jenkins
 		ID:   1,
 		Name: "Jenkins",
diff --git a/plugins/jenkins/jenkins.go b/plugins/jenkins/jenkins.go
index 7d0a916..bfcf168 100644
--- a/plugins/jenkins/jenkins.go
+++ b/plugins/jenkins/jenkins.go
@@ -3,6 +3,7 @@
 import (
 	"context"
 	"fmt"
+
 	"github.com/merico-dev/lake/config"
 	errors "github.com/merico-dev/lake/errors"
 	"github.com/merico-dev/lake/logger"
@@ -44,10 +45,11 @@
 }
 
 func (j Jenkins) Execute(options map[string]interface{}, progress chan<- float32, ctx context.Context) error {
+	v := config.GetConfig()
 	var op = JenkinsOptions{
-		Host:     config.V.GetString("JENKINS_ENDPOINT"),
-		Username: config.V.GetString("JENKINS_USERNAME"),
-		Password: config.V.GetString("JENKINS_PASSWORD"),
+		Host:     v.GetString("JENKINS_ENDPOINT"),
+		Username: v.GetString("JENKINS_USERNAME"),
+		Password: v.GetString("JENKINS_PASSWORD"),
 	}
 
 	var err = mapstructure.Decode(options, &op)
diff --git a/plugins/plugins.go b/plugins/plugins.go
index 799d57d..1d3f9ab 100644
--- a/plugins/plugins.go
+++ b/plugins/plugins.go
@@ -58,6 +58,6 @@
 }
 
 func PluginDir() string {
-	pluginDir := config.V.GetString("PLUGIN_DIR")
+	pluginDir := config.GetConfig().GetString("PLUGIN_DIR")
 	return pluginDir
 }
diff --git a/services/pipeline.go b/services/pipeline.go
index f92a21c..5dab94d 100644
--- a/services/pipeline.go
+++ b/services/pipeline.go
@@ -22,8 +22,9 @@
 }
 
 func init() {
-	var notificationEndpoint = config.V.GetString("NOTIFICATION_ENDPOINT")
-	var notificationSecret = config.V.GetString("NOTIFICATION_SECRET")
+	v := config.GetConfig()
+	var notificationEndpoint = v.GetString("NOTIFICATION_ENDPOINT")
+	var notificationSecret = v.GetString("NOTIFICATION_SECRET")
 	if strings.TrimSpace(notificationEndpoint) != "" {
 		notificationService = NewNotificationService(notificationEndpoint, notificationSecret)
 	}