mirror of
https://github.com/mikefarah/yq.git
synced 2026-09-01 14:14:52 +08:00
Add a new envsubst operator to replace environment variables in strings (#1082)
This commit is contained in:
@@ -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
|
||||
```
|
||||
|
||||
@@ -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(`env\([^\)]+\)`), envOp(false))
|
||||
|
||||
lexer.Add([]byte(`envsubst`), opToken(envsubstOpType))
|
||||
|
||||
lexer.Add([]byte(`\[`), literalToken(openCollect, false))
|
||||
lexer.Add([]byte(`\]\??`), literalToken(closeCollect, true))
|
||||
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 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 selectOpType = &operationType{Type: "SELECT", NumArgs: 1, Precedence: 50, Handler: selectOperator}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user