-
Notifications
You must be signed in to change notification settings - Fork 10
/
config.go
146 lines (130 loc) · 4.46 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package config
import (
"os"
"path/filepath"
"emperror.dev/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
type GitHub struct {
// The GitHub API token to use for authenticating to the GitHub API.
Token string
// The base URL of the GitHub instance to use.
// This should only be set for GitHub Enterprise Server (GHES) instances.
// For example, "https://github.mycompany.com/" (without a "/api/v3" or
// "/api/graphql" suffix).
BaseURL string
}
type PullRequest struct {
Draft bool
OpenBrowser bool
// If true, the pull request will be converted to a draft if the base branch
// needs to be changed after the pull request has been changed. This avoids
// accidentally adding lots of unnecessary auto-added reviewers (via GitHub's
// CODEOWNERS feature) to the pull request while the PR is in a transient
// state.
// If not set, the value should be considered true iff there is a CODEOWNERS
// file in the repository.
RebaseWithDraft *bool
// By default, when the pull request title contains "WIP", it automatically sets the PR as
// a draft PR. Setting this to true suppresses this behavior.
NoWIPDetection bool
// Branch prefix to use for creating new branches.
BranchNamePrefix string
// If true, the CLI will automatically add/update a comment to all PRs linking other PRs in the stack.
// False by default, since Aviator's MergeQueue also adds a similar comment.
WriteStack bool
}
type Aviator struct {
// The base URL of the Aviator API to use.
// By default, this is https://aviator.co, but for on-prem installations
// this can be changed (e.g., https://aviator.mycompany.com).
// It should not include a trailing slash or any path components.
APIHost string
// The API token to use for authenticating to the Aviator API.
APIToken string
}
var Av = struct {
PullRequest PullRequest
GitHub GitHub
Aviator Aviator
}{
Aviator: Aviator{
APIHost: "https://api.aviator.co",
},
PullRequest: PullRequest{
OpenBrowser: true,
},
GitHub: GitHub{},
}
// Load initializes the configuration values.
//
// This takes an optional repository config directory, which, when exists, overrides the default
// config.
func Load(repoConfigDir string) error {
if err := loadFromFile(repoConfigDir); err != nil {
return err
}
if err := loadFromEnv(); err != nil {
return err
}
return nil
}
func loadFromFile(repoConfigDir string) error {
config := viper.New()
// The base filename of the config files.
config.SetConfigName("config")
// With config.ReadInConfig, Viper looks for a file with `config.$EXT` where $EXT is
// viper.SupportedExts. It tries to find the file in the following directories in this
// order (e.g. $XDG_CONFIG_HOME/av/config.yaml first).
//
// Note that Viper will find only one file in these directories, so if there are multiple,
// only one is read.
config.AddConfigPath("$XDG_CONFIG_HOME/av")
config.AddConfigPath("$HOME/.config/av")
config.AddConfigPath("$HOME/.av")
config.AddConfigPath("$AV_HOME")
if err := config.ReadInConfig(); err != nil {
// We can ignore config file not exist case.
if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
return err
}
} else {
logrus.WithField("config_file", config.ConfigFileUsed()).Debug("loaded config file")
}
// As stated above, Viper will read only one file from the above paths. However, we want to
// support per-repo configuration that overrides the global configuration. Here, we mimic
// the behavior of Viper by looking for the per-repo config file and merge it.
for _, ext := range viper.SupportedExts {
fp := filepath.Join(repoConfigDir, "config."+ext)
if stat, err := os.Stat(fp); err == nil {
if !stat.IsDir() {
config.SetConfigFile(fp)
if err := config.MergeInConfig(); err != nil {
return errors.Wrapf(err, "failed to read %s", fp)
}
logrus.WithField("config_file", fp).Debug("loaded config file")
break
}
}
}
if err := config.Unmarshal(&Av); err != nil {
return errors.Wrap(err, "failed to read av configs")
}
return nil
}
func loadFromEnv() error {
// TODO: integrate this better with cobra/viper/whatever
if githubToken := os.Getenv("AV_GITHUB_TOKEN"); githubToken != "" {
Av.GitHub.Token = githubToken
} else if githubToken := os.Getenv("GITHUB_TOKEN"); githubToken != "" {
Av.GitHub.Token = githubToken
}
if apiToken := os.Getenv("AV_API_TOKEN"); apiToken != "" {
Av.Aviator.APIToken = apiToken
}
if apiHost := os.Getenv("AV_API_HOST"); apiHost != "" {
Av.Aviator.APIHost = apiHost
}
return nil
}