Skip to content

Preserve custom metadata when exporting config #679

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

Merged
merged 3 commits into from
Mar 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions dsc/tests/dsc_export.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,22 @@ Describe 'resource export tests' {
$config_with_process_list.'resources' | Should -Not -BeNullOrEmpty
$config_with_process_list.resources.count | Should -BeGreaterThan 1
}

It 'Export for config preserves metadata' {
$yaml = @'
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
metadata:
winget:
processor: dscv3
hello: world
resources:
- name: OS
type: Microsoft/OSInfo
'@
$out = $yaml | dsc config export -f - | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0
$out.metadata.winget.processor | Should -BeExactly 'dscv3'
$out.metadata.hello | Should -BeExactly 'world'
$out.metadata.'Microsoft.DSC'.operation | Should -BeExactly 'export'
}
}
8 changes: 5 additions & 3 deletions dsc_lib/src/configure/config_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ pub struct MicrosoftDscMetadata {
pub struct Metadata {
#[serde(rename = "Microsoft.DSC", skip_serializing_if = "Option::is_none")]
pub microsoft: Option<MicrosoftDscMetadata>,
#[serde(flatten)]
pub other: Map<String, Value>,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
Expand All @@ -85,7 +87,7 @@ pub struct Configuration {
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<HashMap<String, Parameter>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub variables: Option<HashMap<String, Value>>,
pub variables: Option<Map<String, Value>>,
pub resources: Vec<Resource>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<Metadata>,
Expand All @@ -110,7 +112,7 @@ pub struct Parameter {
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
pub metadata: Option<Map<String, Value>>,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
Expand Down Expand Up @@ -144,7 +146,7 @@ pub struct Resource {
#[serde(skip_serializing_if = "Option::is_none")]
pub properties: Option<Map<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Value>>,
pub metadata: Option<Map<String, Value>>,
}

impl Default for Configuration {
Expand Down
10 changes: 5 additions & 5 deletions dsc_lib/src/configure/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
use chrono::{DateTime, Local};
use crate::configure::config_doc::ExecutionKind;
use security_context_lib::{get_security_context, SecurityContext};
use serde_json::Value;
use serde_json::{Map, Value};
use std::{collections::HashMap, path::PathBuf};

use super::config_doc::{DataType, SecurityContextKind};

pub struct Context {
pub execution_type: ExecutionKind,
pub references: HashMap<String, Value>,
pub references: Map<String, Value>,
pub system_root: PathBuf,
pub parameters: HashMap<String, (Value, DataType)>,
pub security_context: SecurityContextKind,
pub variables: HashMap<String, Value>,
pub variables: Map<String, Value>,
pub start_datetime: DateTime<Local>,
}

Expand All @@ -24,14 +24,14 @@ impl Context {
pub fn new() -> Self {
Self {
execution_type: ExecutionKind::Actual,
references: HashMap::new(),
references: Map::new(),
system_root: get_default_os_system_root(),
parameters: HashMap::new(),
security_context: match get_security_context() {
SecurityContext::Admin => SecurityContextKind::Elevated,
SecurityContext::User => SecurityContextKind::Restricted,
},
variables: HashMap::new(),
variables: Map::new(),
start_datetime: chrono::Local::now(),
}
}
Expand Down
25 changes: 20 additions & 5 deletions dsc_lib/src/configure/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@ impl Configurator {
duration: Some(end_datetime.signed_duration_since(start_datetime).to_string()),
..Default::default()
}
)
),
other: Map::new(),
}
),
name: resource.name.clone(),
Expand Down Expand Up @@ -426,7 +427,8 @@ impl Configurator {
duration: Some(end_datetime.signed_duration_since(start_datetime).to_string()),
..Default::default()
}
)
),
other: Map::new(),
}
),
name: resource.name.clone(),
Expand Down Expand Up @@ -497,7 +499,8 @@ impl Configurator {
duration: Some(end_datetime.signed_duration_since(start_datetime).to_string()),
..Default::default()
}
)
),
other: Map::new(),
}
),
name: resource.name.clone(),
Expand Down Expand Up @@ -527,6 +530,7 @@ impl Configurator {
pub fn invoke_export(&mut self) -> Result<ConfigurationExportResult, DscError> {
let mut result = ConfigurationExportResult::new();
let mut conf = config_doc::Configuration::new();
conf.metadata.clone_from(&self.config.metadata);

let mut progress = ProgressBar::new(self.config.resources.len() as u64, self.progress_format)?;
let resources = self.config.resources.clone();
Expand All @@ -552,7 +556,17 @@ impl Configurator {
progress.write_increment(1);
}

conf.metadata = Some(self.get_result_metadata(Operation::Export));
let export_metadata = self.get_result_metadata(Operation::Export);
match conf.metadata {
Some(mut metadata) => {
metadata.microsoft = export_metadata.microsoft;
conf.metadata = Some(metadata);
},
_ => {
conf.metadata = Some(export_metadata);
},
}

result.result = Some(conf);
Ok(result)
}
Expand Down Expand Up @@ -685,7 +699,8 @@ impl Configurator {
duration: Some(end_datetime.signed_duration_since(self.context.start_datetime).to_string()),
security_context: Some(self.context.security_context.clone()),
}
)
),
other: Map::new(),
}
}

Expand Down