Skip to content

Commit 53cc8c9

Browse files
committed
Refactor plugin config -> envar generation
I was in this code investigating an escalation, and found it quite hard to parse out what was going on, so i did a couple of light refactors to make it a little easier to follow
1 parent e9435e0 commit 53cc8c9

File tree

1 file changed

+38
-48
lines changed

1 file changed

+38
-48
lines changed

agent/plugin/plugin.go

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -222,17 +222,17 @@ func formatEnvKey(key string) string {
222222
return hypenOrSpaceRE.ReplaceAllString(newKey, "_")
223223
}
224224

225-
func walkConfigValues(prefix string, v any, into *[]string) error {
225+
func flattenConfigToEnvMap(into map[string]string, v any, envPrefix string) error {
226226
switch vv := v.(type) {
227227
// handles all of our primitive types, golang provides a good string representation
228228
case string, bool, json.Number:
229-
*into = append(*into, fmt.Sprintf("%s=%v", prefix, vv))
229+
into[envPrefix] = fmt.Sprintf("%v", vv)
230230
return nil
231231

232232
// handle lists of things, which get a KEY_N prefix depending on the index
233233
case []any:
234-
for i := range vv {
235-
if err := walkConfigValues(fmt.Sprintf("%s_%d", prefix, i), vv[i], into); err != nil {
234+
for i, item := range vv {
235+
if err := flattenConfigToEnvMap(into, item, fmt.Sprintf("%s_%d", envPrefix, i)); err != nil {
236236
return err
237237
}
238238
}
@@ -241,72 +241,62 @@ func walkConfigValues(prefix string, v any, into *[]string) error {
241241
// handle maps of things, which get a KEY_SUBKEY prefix depending on the map keys
242242
case map[string]any:
243243
for k, vvv := range vv {
244-
if err := walkConfigValues(fmt.Sprintf("%s_%s", prefix, formatEnvKey(k)), vvv, into); err != nil {
244+
if err := flattenConfigToEnvMap(into, vvv, fmt.Sprintf("%s_%s", envPrefix, formatEnvKey(k))); err != nil {
245245
return err
246246
}
247247
}
248248
return nil
249-
}
250249

251-
return fmt.Errorf("Unknown type %T %v", v, v)
250+
default:
251+
return fmt.Errorf("Unknown type %T %v", v, v)
252+
}
252253
}
253254

254-
// The input should be a slice of Env Variables of the form `k=v` where `k` is the variable name
255-
// and `v` is its value. If it can be determined that any of the env variables names is part of a
256-
// deprecation, either as the deprecated variable name or its replacement, append both to the
257-
// returned slice, and also append a deprecation error to the error value. If there are no
258-
// deprecations, the error value is guaranteed to be nil.
259-
func fanOutDeprecatedEnvVarNames(envSlice []string) ([]string, error) {
260-
envSliceAfter := envSlice
261-
262-
var dnerrs *DeprecatedNameErrors
263-
for _, kv := range envSlice {
264-
k, v, ok := strings.Cut(kv, "=")
265-
if !ok { // this is impossible if the precondition is met
266-
continue
267-
}
268-
255+
// addDeprecatedEnvVarAliases provides backward compatibility for environment variable names.
256+
//
257+
// Before v3.48.0 (https://github.com/buildkite/agent/pull/2116), consecutive underscores in
258+
// derived env var names were collapsed (e.g., "some--key__name" → SOME_KEY_NAME).
259+
// Since v3.48.0, consecutive underscores are preserved (e.g., SOME__KEY__NAME).
260+
//
261+
// For compatibility, this function adds the collapsed form for any key containing consecutive
262+
// underscores and returns deprecation errors listing the affected variables.
263+
func addDeprecatedEnvVarAliases(envMap map[string]string) error {
264+
var errs *DeprecatedNameErrors
265+
for k, v := range envMap {
269266
// the form with consecutive underscores is replacing the form without, but the replacement
270-
// is what is expected to be in input slice
271-
noConsecutiveUnderScoreKey := consecutiveUnderscoreRE.ReplaceAllString(k, "_")
272-
if k != noConsecutiveUnderScoreKey {
273-
envSliceAfter = append(envSliceAfter, fmt.Sprintf("%s=%s", noConsecutiveUnderScoreKey, v))
274-
dnerrs = dnerrs.Append(DeprecatedNameError{old: noConsecutiveUnderScoreKey, new: k})
267+
// is what is expected to be in input map
268+
withoutConsecutiveUnderscores := consecutiveUnderscoreRE.ReplaceAllString(k, "_")
269+
if k != withoutConsecutiveUnderscores {
270+
envMap[withoutConsecutiveUnderscores] = v
271+
errs = errs.Append(DeprecatedNameError{old: withoutConsecutiveUnderscores, new: k})
275272
}
276273
}
277274

278-
// guarantee that the error value is nil if there are no deprecations
279-
if !dnerrs.IsEmpty() {
280-
return envSliceAfter, dnerrs
275+
if !errs.IsEmpty() {
276+
return errs
281277
}
282-
return envSliceAfter, nil
278+
279+
return nil
283280
}
284281

285-
// ConfigurationToEnvironment converts the plugin configuration values to
286-
// environment variables.
282+
// ConfigurationToEnvironment converts the plugin configuration values to environment variables.
287283
func (p *Plugin) ConfigurationToEnvironment() (*env.Environment, error) {
288-
envSlice := []string{}
289-
envPrefix := fmt.Sprintf("BUILDKITE_PLUGIN_%s", formatEnvKey(p.Name()))
290-
291-
// Append current plugin name
292-
envSlice = append(envSlice, fmt.Sprintf("BUILDKITE_PLUGIN_NAME=%s", formatEnvKey(p.Name())))
293-
294-
// Append current plugin configuration as JSON
295284
configJSON, err := json.Marshal(p.Configuration)
296285
if err != nil {
297286
return env.New(), err
298287
}
299-
envSlice = append(envSlice, fmt.Sprintf("BUILDKITE_PLUGIN_CONFIGURATION=%s", configJSON))
300288

301-
for k, v := range p.Configuration {
302-
configPrefix := fmt.Sprintf("%s_%s", envPrefix, formatEnvKey(k))
303-
if err := walkConfigValues(configPrefix, v, &envSlice); err != nil {
304-
return env.New(), err
305-
}
289+
envMap := make(map[string]string)
290+
envMap["BUILDKITE_PLUGIN_NAME"] = formatEnvKey(p.Name())
291+
envMap["BUILDKITE_PLUGIN_CONFIGURATION"] = string(configJSON)
292+
293+
envPrefix := fmt.Sprintf("BUILDKITE_PLUGIN_%s", formatEnvKey(p.Name()))
294+
if err := flattenConfigToEnvMap(envMap, p.Configuration, envPrefix); err != nil {
295+
return env.New(), err
306296
}
307297

308-
envSlice, err = fanOutDeprecatedEnvVarNames(envSlice)
309-
return env.FromSlice(envSlice), err
298+
err = addDeprecatedEnvVarAliases(envMap)
299+
return env.FromMap(envMap), err
310300
}
311301

312302
// Label returns a pretty name for the plugin.

0 commit comments

Comments
 (0)