Skip to content

Commit 129a0e4

Browse files
committed
Add endsWith, startsWith, utcNow, and uniqueString functions
1 parent 2c87561 commit 129a0e4

File tree

13 files changed

+653
-41
lines changed

13 files changed

+653
-41
lines changed

dsc/Cargo.lock

Lines changed: 70 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dsc/tests/dsc_functions.tests.ps1

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,77 @@ Describe 'tests for function expressions' {
244244
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log -Raw)
245245
($out.results[0].result.actualState.output | Out-String) | Should -BeExactly ($expected | Out-String)
246246
}
247+
248+
It 'utcNow function works for: utcNow(<format>)' -TestCases @(
249+
@{ format = $null}
250+
@{ format = "yyyy-MM-dd"}
251+
@{ format = "yyyy-MM-ddTHH:mm:ss"}
252+
@{ format = "yyyy-MM-ddTHH:mm:ss.fffZ"}
253+
@{ format = "MMM dd, yyyy HH:mm"}
254+
@{ format = "yy-MMMM-dddd H:m tt" }
255+
@{ format = "MMM ddd zzz" }
256+
) {
257+
param($format)
258+
259+
if ($null -eq $format) {
260+
$expected = (Get-Date -AsUTC).ToString("o")
261+
} else {
262+
$expected = (Get-Date -AsUTC).ToString($format)
263+
$format = "'$format'"
264+
}
265+
266+
$config_yaml = @"
267+
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
268+
parameters:
269+
test:
270+
type: string
271+
defaultValue: "[utcNow($format)]"
272+
resources:
273+
- name: Echo
274+
type: Microsoft.DSC.Debug/Echo
275+
properties:
276+
output: "[parameters('test')]"
277+
"@
278+
$out = dsc -l trace config get -i $config_yaml 2>$TestDrive/error.log | ConvertFrom-Json -DateKind String
279+
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log -Raw)
280+
$actual = $out.results[0].result.actualState.output
281+
# since the datetimes might slightly differ, we remove the seconds and milliseconds
282+
$expected = $expected -replace ':\d+\.\d+Z$', 'Z'
283+
$actual = $actual -replace ':\d+\.\d+Z$', 'Z'
284+
$actual | Should -BeExactly $expected -Because "Expected: '$expected', Actual: '$actual'"
285+
}
286+
287+
It 'utcNow errors if used not as a parameter default' {
288+
$config_yaml = @"
289+
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
290+
resources:
291+
- name: Echo
292+
type: Microsoft.DSC.Debug/Echo
293+
properties:
294+
output: "[utcNow()]"
295+
"@
296+
$out = dsc -l trace config get -i $config_yaml 2>$TestDrive/error.log | ConvertFrom-Json
297+
$LASTEXITCODE | Should -Be 2 -Because (Get-Content $TestDrive/error.log -Raw)
298+
(Get-Content $TestDrive/error.log -Raw) | Should -Match 'utcNow function can only be used as a parameter default'
299+
}
300+
301+
It 'uniqueString function works for: <expression>' -TestCases @(
302+
@{ expression = "[uniqueString('a')]" ; expected = 'cfvwxu6sc4lqo' }
303+
@{ expression = "[uniqueString('a', 'b', 'c')]" ; expected = 'bhw7m6t6ntwd6' }
304+
@{ expression = "[uniqueString('a', 'b', 'c', 'd')]" ; expected = 'yxzg7ur4qetcy' }
305+
) {
306+
param($expression, $expected)
307+
308+
$config_yaml = @"
309+
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
310+
resources:
311+
- name: Echo
312+
type: Microsoft.DSC.Debug/Echo
313+
properties:
314+
output: "$expression"
315+
"@
316+
$out = dsc -l trace config get -i $config_yaml 2>$TestDrive/error.log | ConvertFrom-Json
317+
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log -Raw)
318+
$out.results[0].result.actualState.output | Should -BeExactly $expected
319+
}
247320
}

dsc_lib/Cargo.lock

Lines changed: 70 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dsc_lib/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ split-debuginfo = "packed" # generates a seperate *.dwp/*.dSYM so the binary ca
1313
strip = "symbols" # See split-debuginfo - allows us to drop the size by ~65%
1414

1515
[dependencies]
16+
base32 = "0.5"
1617
base64 = "0.22"
17-
chrono = "0.4"
18+
chrono = { version = "0.4", features = ["alloc"] }
1819
clap = { version = "4.5", features = ["derive"] }
1920
derive_builder ="0.20"
2021
indicatif = "0.18"
2122
jsonschema = { version = "0.30", default-features = false }
2223
linked-hash-map = "0.5"
24+
murmurhash64 = "0.3"
2325
num-traits = "0.2"
2426
path-absolutize = { version = "3.1" }
2527
regex = "1.11"

dsc_lib/locales/en-us.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ description = "Checks if an array, object, or string is empty"
265265
invoked = "empty function"
266266
invalidArgType = "Invalid argument type, argument must be an array, object, or string"
267267

268+
[functions.endsWith]
269+
description = "Checks if a string ends with a specific suffix"
270+
invoked = "endsWith function"
271+
268272
[functions.envvar]
269273
description = "Retrieves the value of an environment variable"
270274
notFound = "Environment variable not found"
@@ -381,6 +385,10 @@ extensionReturnedError = "Extension '%{extension}': %{error}"
381385
noExtensions = "No extensions supporting secrets was found"
382386
secretNotFound = "Secret '%{name}' not found"
383387

388+
[functions.startsWith]
389+
description = "Checks if a string starts with a specific prefix"
390+
invoked = "startsWith function"
391+
384392
[functions.sub]
385393
description = "Subtracts the second number from the first"
386394
invoked = "sub function"
@@ -398,6 +406,15 @@ description = "Returns a single array or object with all elements from the param
398406
invoked = "union function"
399407
invalidArgType = "All arguments must either be arrays or objects"
400408

409+
[functions.uniqueString]
410+
description = "Returns a deterministic unique string from the given strings"
411+
invoked = "uniqueString function"
412+
413+
[functions.utcNow]
414+
description = "Returns the current UTC time"
415+
invoked = "utcNow function"
416+
onlyUsedAsParameterDefault = "utcNow function can only be used as a parameter default"
417+
401418
[functions.variables]
402419
description = "Retrieves the value of a variable"
403420
invoked = "variables function"

dsc_lib/src/configure/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub struct Context {
2020
pub start_datetime: DateTime<Local>,
2121
pub restart_required: Option<Vec<RestartRequired>>,
2222
pub process_expressions: bool,
23+
pub processing_parameter_defaults: bool,
2324
}
2425

2526
impl Context {
@@ -39,6 +40,7 @@ impl Context {
3940
start_datetime: chrono::Local::now(),
4041
restart_required: None,
4142
process_expressions: true,
43+
processing_parameter_defaults: false,
4244
}
4345
}
4446
}

dsc_lib/src/configure/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,10 @@ impl Configurator {
722722
// default values can be expressions
723723
let value = if default_value.is_string() {
724724
if let Some(value) = default_value.as_str() {
725-
self.statement_parser.parse_and_execute(value, &self.context)?
725+
self.context.processing_parameter_defaults = true;
726+
let result = self.statement_parser.parse_and_execute(value, &self.context)?;
727+
self.context.processing_parameter_defaults = false;
728+
result
726729
} else {
727730
return Err(DscError::Parser(t!("configure.mod.defaultStringNotDefined").to_string()));
728731
}

0 commit comments

Comments
 (0)