-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add variables support #511
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json | ||
parameters: | ||
myParameter: | ||
type: string | ||
# the use of `concat()` here is just an example of using an expression for a defaultValue | ||
defaultValue: "[concat('world','!')]" | ||
variables: | ||
myOutput: "[concat('Hello ', parameters('myParameter'))]" | ||
myObject: | ||
test: baz | ||
resources: | ||
- name: test | ||
type: Test/Echo | ||
properties: | ||
output: "[concat('myOutput is: ', variables('myOutput'), ', myObject is: ', variables('myObject').test)]" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Copyright (c) Microsoft Corporation. | ||
# Licensed under the MIT License. | ||
|
||
Describe 'Configruation variables tests' { | ||
It 'Variables example config works' { | ||
$configFile = "$PSSCriptRoot/../examples/variables.dsc.yaml" | ||
$out = dsc config get -p $configFile | ConvertFrom-Json | ||
$LASTEXITCODE | Should -Be 0 | ||
$out.results[0].result.actualState.output | Should -BeExactly 'myOutput is: Hello world!, myObject is: baz' | ||
} | ||
|
||
It 'Duplicated variable takes last value' { | ||
$configYaml = @' | ||
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json | ||
variables: | ||
myVariable: foo | ||
myVariable: bar | ||
resources: | ||
- name: test | ||
type: Test/Echo | ||
properties: | ||
output: "[variables('myVariable')]" | ||
'@ | ||
$out = dsc config get -d $configYaml | ConvertFrom-Json | ||
Write-Verbose -Verbose $out | ||
$LASTEXITCODE | Should -Be 0 | ||
$out.results[0].result.actualState.output | Should -Be 'bar' | ||
} | ||
|
||
It 'Missing variable returns error' { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The essence of a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are correct, but that's not how it's used in an ARM template |
||
$configYaml = @' | ||
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json | ||
variables: | ||
hello: world | ||
resources: | ||
- name: test | ||
type: Test/Echo | ||
properties: | ||
output: "[variables('myVariable')]" | ||
'@ | ||
$out = dsc config get -d $configYaml 2>&1 | Out-String | ||
Write-Verbose -Verbose $out | ||
$LASTEXITCODE | Should -Be 2 | ||
$out | Should -BeLike "*Variable 'myVariable' does not exist or has not been initialized yet*" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
use crate::DscError; | ||
use crate::configure::context::Context; | ||
use crate::functions::{AcceptedArgKind, Function}; | ||
use serde_json::Value; | ||
use tracing::debug; | ||
|
||
#[derive(Debug, Default)] | ||
pub struct Variables {} | ||
|
||
impl Function for Variables { | ||
fn min_args(&self) -> usize { | ||
1 | ||
} | ||
|
||
fn max_args(&self) -> usize { | ||
1 | ||
} | ||
|
||
fn accepted_arg_types(&self) -> Vec<AcceptedArgKind> { | ||
vec![AcceptedArgKind::String] | ||
} | ||
|
||
fn invoke(&self, args: &[Value], context: &Context) -> Result<Value, DscError> { | ||
debug!("variables function"); | ||
if let Some(key) = args[0].as_str() { | ||
if context.variables.contains_key(key) { | ||
Ok(context.variables[key].clone()) | ||
} else { | ||
Err(DscError::Parser(format!("Variable '{key}' does not exist or has not been initialized yet"))) | ||
} | ||
} else { | ||
Err(DscError::Parser("Invalid argument".to_string())) | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::configure::context::Context; | ||
use crate::parser::Statement; | ||
|
||
#[test] | ||
fn valid_variable() { | ||
let mut parser = Statement::new().unwrap(); | ||
let mut context = Context::new(); | ||
context.variables.insert("hello".to_string(), "world".into()); | ||
let result = parser.parse_and_execute("[variables('hello')]", &context).unwrap(); | ||
assert_eq!(result, "world"); | ||
} | ||
|
||
#[test] | ||
fn invalid_resourceid() { | ||
let mut parser = Statement::new().unwrap(); | ||
let result = parser.parse_and_execute("[variables('foo')]", &Context::new()); | ||
assert!(result.is_err()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a difference between parameters and variables:
parameters have 2 subfields:
type
anddefaultValue
,but looks like variables have just implied
defaultValue
and type is implicitly derived.Should this be consistent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took this directly from ARM.
variables
are intended to just be used to keep values that get reused multiple times within the config and typically constructed from params based on examples I saw.