Skip to content

Commit

Permalink
improvement(config): allow chained conditionals in template strings
Browse files Browse the repository at this point in the history
For example: ${key || other-key || still-nothing || "default"}
  • Loading branch information
edvald committed Jun 22, 2019
1 parent 193f2cc commit 095e943
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 6 deletions.
13 changes: 13 additions & 0 deletions docs/reference/template-strings.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,19 @@ lookups of keys. However, it is possible to do nested templating. For a somewhat
There the name of the module is pulled from the project/environment configuration, and used to find the
appropriate key under the `modules` configuration context.

You can also do conditional statements, using the `||` operator. For example:

```yaml
# ...
variables:
log-level: ${local.env.LOG_LEVEL || "info"}
namespace: ${local.env.CI_BRANCH || local.username || "default"}
```

This allows you to easily set default values when certain template keys are not available, and to configure your
project based on varying context.


## Reference

### Project configuration context
Expand Down
13 changes: 13 additions & 0 deletions garden-service/src/docs/templates/template-strings.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,19 @@ lookups of keys. However, it is possible to do nested templating. For a somewhat
There the name of the module is pulled from the project/environment configuration, and used to find the
appropriate key under the `modules` configuration context.

You can also do conditional statements, using the `||` operator. For example:

```yaml
# ...
variables:
log-level: ${local.env.LOG_LEVEL || "info"}
namespace: ${local.env.CI_BRANCH || local.username || "default"}
```

This allows you to easily set default values when certain template keys are not available, and to configure your
project based on varying context.


## Reference

### Project configuration context
Expand Down
22 changes: 17 additions & 5 deletions garden-service/src/template-string-parser.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,24 @@ FormatString
= FormatStart key:Key FormatEnd {
return options.getKey(key)
}
/ FormatStart a:Key Or b:Key FormatEnd {
return options.getKey(a, { allowUndefined: true })
.then(result => {
return result || options.getKey(b, { allowUndefined: false })
/ FormatStart head:Key tail:(Or (Key / StringLiteral))+ FormatEnd {
const keys = [head, ...tail.map(t => t[1])]

// Resolve all the keys
return Promise.all(keys.map(key =>
typeof key === "string" ? key : options.getKey(key, { allowUndefined: true })
))
.then(candidates => {
// Return the first non-undefined value
for (const value of candidates) {
if (value !== undefined) {
return value
}
}

throw new options.ConfigurationError("None of the keys could be resolved in the conditional: " + text())
})
}
}
/ FormatStart a:Key Or b:StringLiteral FormatEnd {
return options.getKey(a, { allowUndefined: true })
.then(result => {
Expand Down
3 changes: 2 additions & 1 deletion garden-service/src/template-string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import Bluebird = require("bluebird")
import { asyncDeepMap } from "./util/util"
import { GardenBaseError } from "./exceptions"
import { GardenBaseError, ConfigurationError } from "./exceptions"
import { ConfigContext, ContextResolveOpts, ContextResolveParams } from "./config/config-context"
import { KeyedSet } from "./util/keyed-set"
import { uniq } from "lodash"
Expand Down Expand Up @@ -48,6 +48,7 @@ export async function resolveTemplateString(string: string, context: ConfigConte
const s = (await Bluebird.all(parts)).join("")
return resolveTemplateString(`\$\{${s}\}`, context, { ...opts, ...resolveOpts || {} })
},
ConfigurationError,
TemplateStringError,
})

Expand Down
8 changes: 8 additions & 0 deletions garden-service/test/unit/src/template-string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,14 @@ describe("resolveTemplateString", async () => {
expect(res).to.equal("foo")
})

it("should handle chained conditional with string fallback", async () => {
const res = await resolveTemplateString(
"${a.b || c.d || e.f || 'foo'}",
new TestContext({ a: {}, c: {}, e: {} }),
)
expect(res).to.equal("foo")
})

it("should handle a conditional between two identifiers without spaces with first value set", async () => {
const res = await resolveTemplateString(
"${a||b}",
Expand Down

0 comments on commit 095e943

Please sign in to comment.