mirror of
https://github.com/mikefarah/yq.git
synced 2025-01-23 06:05:40 +00:00
Add a new envsubst
operator to replace environment variables in strings (#1082)
This commit is contained in:
parent
9b1a7bf451
commit
8195ff8b9b
1
go.mod
1
go.mod
@ -1,6 +1,7 @@
|
|||||||
module github.com/mikefarah/yq/v4
|
module github.com/mikefarah/yq/v4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/a8m/envsubst v1.2.0
|
||||||
github.com/elliotchance/orderedmap v1.4.0
|
github.com/elliotchance/orderedmap v1.4.0
|
||||||
github.com/fatih/color v1.13.0
|
github.com/fatih/color v1.13.0
|
||||||
github.com/goccy/go-yaml v1.9.5
|
github.com/goccy/go-yaml v1.9.5
|
||||||
|
2
go.sum
2
go.sum
@ -50,6 +50,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
|||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/a8m/envsubst v1.2.0 h1:yvzAhJD2QKdo35Ut03wIfXQmg+ta3wC/1bskfZynz+Q=
|
||||||
|
github.com/a8m/envsubst v1.2.0/go.mod h1:PpvLvNWa+Rvu/10qXmFbFiGICIU5hZvFJNPCCkUaObg=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
55
pkg/yqlib/doc/operators/envsubst.md
Normal file
55
pkg/yqlib/doc/operators/envsubst.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Envsubst
|
||||||
|
|
||||||
|
This operator is used to replace environment variables in strings using [envsubst](https://github.com/a8m/envsubst).
|
||||||
|
|
||||||
|
To replace environment variables across all values in a document, this can be used with the recursive descent operator
|
||||||
|
as follows:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yq eval '(.. | select(tag == "!!str)) |= envsubst' file.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Replace strings with envsubst
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="cat" yq eval --null-input '"the ${myenv} meows" | envsubst'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
the cat meows
|
||||||
|
```
|
||||||
|
|
||||||
|
## Replace strings with envsubst, missing variables
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="cat" yq eval --null-input '"the ${myenvnonexisting} meows" | envsubst'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
the meows
|
||||||
|
```
|
||||||
|
|
||||||
|
## Replace strings with envsubst, missing variables with defaults
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="cat" yq eval --null-input '"the ${myenvnonexisting-dog} meows" | envsubst'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
the dog meows
|
||||||
|
```
|
||||||
|
|
||||||
|
## Replace string environment variable in document
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
v: ${myenv}
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
myenv="cat meow" yq eval '.v |= envsubst' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
v: cat meow
|
||||||
|
```
|
||||||
|
|
10
pkg/yqlib/doc/operators/headers/envsubst.md
Normal file
10
pkg/yqlib/doc/operators/headers/envsubst.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Envsubst
|
||||||
|
|
||||||
|
This operator is used to replace environment variables in strings using [envsubst](https://github.com/a8m/envsubst).
|
||||||
|
|
||||||
|
To replace environment variables across all values in a document, this can be used with the recursive descent operator
|
||||||
|
as follows:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yq eval '(.. | select(tag == "!!str")) |= envsubst' file.yaml
|
||||||
|
```
|
@ -472,6 +472,8 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`strenv\([^\)]+\)`), envOp(true))
|
lexer.Add([]byte(`strenv\([^\)]+\)`), envOp(true))
|
||||||
lexer.Add([]byte(`env\([^\)]+\)`), envOp(false))
|
lexer.Add([]byte(`env\([^\)]+\)`), envOp(false))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`envsubst`), opToken(envsubstOpType))
|
||||||
|
|
||||||
lexer.Add([]byte(`\[`), literalToken(openCollect, false))
|
lexer.Add([]byte(`\[`), literalToken(openCollect, false))
|
||||||
lexer.Add([]byte(`\]\??`), literalToken(closeCollect, true))
|
lexer.Add([]byte(`\]\??`), literalToken(closeCollect, true))
|
||||||
lexer.Add([]byte(`\{`), literalToken(openCollectObject, false))
|
lexer.Add([]byte(`\{`), literalToken(openCollectObject, false))
|
||||||
|
@ -131,6 +131,8 @@ var envOpType = &operationType{Type: "ENV", NumArgs: 0, Precedence: 50, Handler:
|
|||||||
var notOpType = &operationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: notOperator}
|
var notOpType = &operationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: notOperator}
|
||||||
var emptyOpType = &operationType{Type: "EMPTY", Precedence: 50, Handler: emptyOperator}
|
var emptyOpType = &operationType{Type: "EMPTY", Precedence: 50, Handler: emptyOperator}
|
||||||
|
|
||||||
|
var envsubstOpType = &operationType{Type: "ENVSUBST", NumArgs: 0, Precedence: 50, Handler: envsubstOperator}
|
||||||
|
|
||||||
var recursiveDescentOpType = &operationType{Type: "RECURSIVE_DESCENT", NumArgs: 0, Precedence: 50, Handler: recursiveDescentOperator}
|
var recursiveDescentOpType = &operationType{Type: "RECURSIVE_DESCENT", NumArgs: 0, Precedence: 50, Handler: recursiveDescentOperator}
|
||||||
|
|
||||||
var selectOpType = &operationType{Type: "SELECT", NumArgs: 1, Precedence: 50, Handler: selectOperator}
|
var selectOpType = &operationType{Type: "SELECT", NumArgs: 1, Precedence: 50, Handler: selectOperator}
|
||||||
|
32
pkg/yqlib/operator_envsubst.go
Normal file
32
pkg/yqlib/operator_envsubst.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
envsubst "github.com/a8m/envsubst"
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func envsubstOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
|
var results = list.New()
|
||||||
|
|
||||||
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
node := unwrapDoc(candidate.Node)
|
||||||
|
if node.Tag != "!!str" {
|
||||||
|
log.Warning("EnvSubstOperator, env name:", node.Tag, node.Value)
|
||||||
|
return Context{}, fmt.Errorf("cannot substitute with %v, can only substitute strings. Hint: Most often you'll want to use '|=' over '=' for this operation", node.Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := envsubst.String(node.Value)
|
||||||
|
if err != nil {
|
||||||
|
return Context{}, err
|
||||||
|
}
|
||||||
|
targetNode := &yaml.Node{Kind: yaml.ScalarNode, Value: value, Tag: "!!str"}
|
||||||
|
result := candidate.CreateReplacement(targetNode)
|
||||||
|
results.PushBack(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.ChildContext(results), nil
|
||||||
|
}
|
48
pkg/yqlib/operator_envsubst_test.go
Normal file
48
pkg/yqlib/operator_envsubst_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var envsubstOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Replace strings with envsubst",
|
||||||
|
environmentVariable: "cat",
|
||||||
|
expression: `"the ${myenv} meows" | envsubst`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!str)::the cat meows\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Replace strings with envsubst, missing variables",
|
||||||
|
environmentVariable: "cat",
|
||||||
|
expression: `"the ${myenvnonexisting} meows" | envsubst`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!str)::the meows\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Replace strings with envsubst, missing variables with defaults",
|
||||||
|
environmentVariable: "cat",
|
||||||
|
expression: `"the ${myenvnonexisting-dog} meows" | envsubst`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!str)::the dog meows\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Replace string environment variable in document",
|
||||||
|
environmentVariable: "cat meow",
|
||||||
|
document: "{v: \"${myenv}\"}",
|
||||||
|
expression: `.v |= envsubst`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{v: \"cat meow\"}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvSubstOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range envsubstOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentOperatorScenarios(t, "envsubst", envsubstOperatorScenarios)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user