Skip to content

Commit 1113332

Browse files
authored
Add ability to load config from the environment (#20)
In certain platforms, setting application secrets is easier with environment variables. Add a new function that can use environment variables to override configuration values loaded from other places, like a file.
1 parent 21f792e commit 1113332

File tree

2 files changed

+166
-0
lines changed

2 files changed

+166
-0
lines changed

githubapp/config.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414

1515
package githubapp
1616

17+
import (
18+
"os"
19+
"strconv"
20+
)
21+
1722
type Config struct {
1823
WebURL string `yaml:"web_url" json:"webUrl"`
1924
V3APIURL string `yaml:"v3_api_url" json:"v3ApiUrl"`
@@ -30,3 +35,33 @@ type Config struct {
3035
ClientSecret string `yaml:"client_secret" json:"clientSecret"`
3136
} `yaml:"oauth" json:"oauth"`
3237
}
38+
39+
// SetValuesFromEnv sets values in the configuration from coresponding
40+
// environment variables, if they exist. The optional prefix is added to the
41+
// start of the environment variable names.
42+
func (c *Config) SetValuesFromEnv(prefix string) {
43+
setStringFromEnv("GITHUB_WEB_URL", prefix, &c.WebURL)
44+
setStringFromEnv("GITHUB_V3_API_URL", prefix, &c.V3APIURL)
45+
setStringFromEnv("GITHUB_V4_API_URL", prefix, &c.V4APIURL)
46+
47+
setIntFromEnv("GITHUB_APP_INTEGRATION_ID", prefix, &c.App.IntegrationID)
48+
setStringFromEnv("GITHUB_APP_WEBHOOK_SECRET", prefix, &c.App.WebhookSecret)
49+
setStringFromEnv("GITHUB_APP_PRIVATE_KEY", prefix, &c.App.PrivateKey)
50+
51+
setStringFromEnv("GITHUB_OAUTH_CLIENT_ID", prefix, &c.OAuth.ClientID)
52+
setStringFromEnv("GITHUB_OAUTH_CLIENT_SECRET", prefix, &c.OAuth.ClientSecret)
53+
}
54+
55+
func setStringFromEnv(key, prefix string, value *string) {
56+
if v, ok := os.LookupEnv(prefix + key); ok {
57+
*value = v
58+
}
59+
}
60+
61+
func setIntFromEnv(key, prefix string, value *int) {
62+
if v, ok := os.LookupEnv(prefix + key); ok {
63+
if i, err := strconv.Atoi(v); err == nil {
64+
*value = i
65+
}
66+
}
67+
}

githubapp/config_test.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright 2019 Palantir Technologies, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package githubapp
16+
17+
import (
18+
"os"
19+
"reflect"
20+
"testing"
21+
)
22+
23+
func TestSetValuesFromEnv(t *testing.T) {
24+
tests := map[string]struct {
25+
Input func(*Config)
26+
Prefix string
27+
Variables map[string]string
28+
Output func(*Config)
29+
}{
30+
"noVariables": {
31+
Input: func(c *Config) {
32+
c.WebURL = "https://github.com"
33+
c.App.WebhookSecret = "secrethookvalue"
34+
},
35+
Output: func(c *Config) {
36+
c.WebURL = "https://github.com"
37+
c.App.WebhookSecret = "secrethookvalue"
38+
},
39+
},
40+
"overwriteExisting": {
41+
Input: func(c *Config) {
42+
c.WebURL = "https://github.com"
43+
},
44+
Variables: map[string]string{
45+
"GITHUB_WEB_URL": "https://github.company.domain",
46+
},
47+
Output: func(c *Config) {
48+
c.WebURL = "https://github.company.domain"
49+
},
50+
},
51+
"allVariables": {
52+
Variables: map[string]string{
53+
"GITHUB_WEB_URL": "https://github.company.domain",
54+
"GITHUB_V3_API_URL": "https://github.company.domain/api/v3",
55+
"GITHUB_V4_API_URL": "https://github.company.domain/api/graphql",
56+
"GITHUB_APP_INTEGRATION_ID": "4",
57+
"GITHUB_APP_WEBHOOK_SECRET": "secrethookvalue",
58+
"GITHUB_APP_PRIVATE_KEY": "-----BEGIN RSA PRIVATE KEY-----\nxxx\nxxx\nxxx\n-----END RSA PRIVATE KEY-----",
59+
"GITHUB_OAUTH_CLIENT_ID": "92faf4b9146f3278",
60+
"GITHUB_OAUTH_CLIENT_SECRET": "b00f7ea6d59dd5c9578c48f9391e71db",
61+
},
62+
Output: func(c *Config) {
63+
c.WebURL = "https://github.company.domain"
64+
c.V3APIURL = "https://github.company.domain/api/v3"
65+
c.V4APIURL = "https://github.company.domain/api/graphql"
66+
c.App.IntegrationID = 4
67+
c.App.WebhookSecret = "secrethookvalue"
68+
c.App.PrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nxxx\nxxx\nxxx\n-----END RSA PRIVATE KEY-----"
69+
c.OAuth.ClientID = "92faf4b9146f3278"
70+
c.OAuth.ClientSecret = "b00f7ea6d59dd5c9578c48f9391e71db"
71+
},
72+
},
73+
"withPrefix": {
74+
Input: func(c *Config) {
75+
c.WebURL = "https://github.com"
76+
},
77+
Prefix: "TEST_",
78+
Variables: map[string]string{
79+
"TEST_GITHUB_WEB_URL": "https://github.company.domain",
80+
},
81+
Output: func(c *Config) {
82+
c.WebURL = "https://github.company.domain"
83+
},
84+
},
85+
"emptyValues": {
86+
Input: func(c *Config) {
87+
c.WebURL = "https://github.com"
88+
},
89+
Variables: map[string]string{
90+
"GITHUB_WEB_URL": "",
91+
},
92+
Output: func(c *Config) {
93+
c.WebURL = ""
94+
},
95+
},
96+
}
97+
98+
for name, test := range tests {
99+
t.Run(name, func(t *testing.T) {
100+
for k, v := range test.Variables {
101+
if err := os.Setenv(k, v); err != nil {
102+
t.Fatalf("failed to set environment variable: %s: %v", k, err)
103+
}
104+
}
105+
106+
defer func() {
107+
for k := range test.Variables {
108+
if err := os.Unsetenv(k); err != nil {
109+
t.Fatalf("failed to clear environment variable: %s: %v", k, err)
110+
}
111+
}
112+
}()
113+
114+
var in Config
115+
if test.Input != nil {
116+
test.Input(&in)
117+
}
118+
119+
var out Config
120+
if test.Output != nil {
121+
test.Output(&out)
122+
}
123+
124+
in.SetValuesFromEnv(test.Prefix)
125+
126+
if !reflect.DeepEqual(out, in) {
127+
t.Errorf("incorrect configuration\nexpected: %+v\n actual: %+v", out, in)
128+
}
129+
})
130+
}
131+
}

0 commit comments

Comments
 (0)