Skip to content

Commit 923f3cf

Browse files
committed
initial definition of extension manifest
1 parent a42e0d9 commit 923f3cf

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

dsc_lib/locales/en-us.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ diffMissingItem = "diff: actual array missing expected item"
160160
resourceManifestSchemaTitle = "Resource manifest schema URI"
161161
resourceManifestSchemaDescription = "Defines the JSON Schema the resource manifest adheres to."
162162

163+
[extensions.extension_manifest]
164+
extensionManifestSchemaTitle = "Extension manifest schema URI"
165+
extensionManifestSchemaDescription = "Defines the JSON Schema the extension manifest adheres to."
166+
163167
[functions]
164168
invalidArgType = "Invalid argument type"
165169
invalidArguments = "Invalid argument(s)"
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
use crate::dscresources::resource_manifest::ArgKind;
5+
use rust_i18n::t;
6+
use schemars::JsonSchema;
7+
use semver::Version;
8+
use serde::{Deserialize, Serialize};
9+
use serde_json::Value;
10+
use std::collections::HashMap;
11+
12+
use crate::{dscerror::DscError, schemas::DscRepoSchema};
13+
14+
#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
15+
#[serde(deny_unknown_fields)]
16+
pub struct ExtensionManifest {
17+
/// The version of the resource manifest schema.
18+
#[serde(rename = "$schema")]
19+
#[schemars(schema_with = "ExtensionManifest::recognized_schema_uris_subschema")]
20+
pub schema_version: String,
21+
/// The namespaced name of the extension.
22+
#[serde(rename = "type")]
23+
pub r#type: String,
24+
/// The version of the resource using semantic versioning.
25+
pub version: String,
26+
/// The description of the resource.
27+
pub description: Option<String>,
28+
/// Tags for the resource.
29+
pub tags: Option<Vec<String>>,
30+
/// Details how to call the Discover method of the resource.
31+
pub discover: Option<DiscoverMethod>,
32+
/// Mapping of exit codes to descriptions. Zero is always success and non-zero is always failure.
33+
#[serde(rename = "exitCodes", skip_serializing_if = "Option::is_none")]
34+
pub exit_codes: Option<HashMap<i32, String>>,
35+
}
36+
37+
#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
38+
pub struct DiscoverMethod {
39+
/// The command to run to get the state of the resource.
40+
pub executable: String,
41+
/// The arguments to pass to the command to perform a Get.
42+
pub args: Option<Vec<ArgKind>>,
43+
}
44+
45+
impl DscRepoSchema for ExtensionManifest {
46+
const SCHEMA_FILE_BASE_NAME: &'static str = "manifest";
47+
const SCHEMA_FOLDER_PATH: &'static str = "extension";
48+
const SCHEMA_SHOULD_BUNDLE: bool = true;
49+
50+
fn schema_metadata() -> schemars::schema::Metadata {
51+
schemars::schema::Metadata {
52+
title: Some(t!("extensions.extension_manifest.extensionManifestSchemaTitle").into()),
53+
description: Some(t!("extensions.extension_manifest.extensioneManifestSchemaDescription").into()),
54+
..Default::default()
55+
}
56+
}
57+
58+
fn validate_schema_uri(&self) -> Result<(), DscError> {
59+
if Self::is_recognized_schema_uri(&self.schema_version) {
60+
Ok(())
61+
} else {
62+
Err(DscError::UnrecognizedSchemaUri(
63+
self.schema_version.clone(),
64+
Self::recognized_schema_uris(),
65+
))
66+
}
67+
}
68+
}
69+
70+
/// Import a resource manifest from a JSON value.
71+
///
72+
/// # Arguments
73+
///
74+
/// * `manifest` - The JSON value to import.
75+
///
76+
/// # Returns
77+
///
78+
/// * `Result<ResourceManifest, DscError>` - The imported resource manifest.
79+
///
80+
/// # Errors
81+
///
82+
/// * `DscError` - The JSON value is invalid or the schema version is not supported.
83+
pub fn import_manifest(manifest: Value) -> Result<ExtensionManifest, DscError> {
84+
// TODO: enable schema version validation, if not provided, use the latest
85+
let manifest = serde_json::from_value::<ExtensionManifest>(manifest)?;
86+
Ok(manifest)
87+
}
88+
89+
/// Validate a semantic version string.
90+
///
91+
/// # Arguments
92+
///
93+
/// * `version` - The semantic version string to validate.
94+
///
95+
/// # Returns
96+
///
97+
/// * `Result<(), Error>` - The result of the validation.
98+
///
99+
/// # Errors
100+
///
101+
/// * `Error` - The version string is not a valid semantic version.
102+
pub fn validate_semver(version: &str) -> Result<(), semver::Error> {
103+
Version::parse(version)?;
104+
Ok(())
105+
}
106+
107+
#[cfg(test)]
108+
mod test {
109+
use crate::{
110+
dscerror::DscError,
111+
dscresources::resource_manifest::ResourceManifest,
112+
schemas::DscRepoSchema
113+
};
114+
115+
#[test]
116+
fn test_validate_schema_uri_with_invalid_uri() {
117+
let invalid_uri = "https://invalid.schema.uri".to_string();
118+
119+
let manifest = ResourceManifest{
120+
schema_version: invalid_uri.clone(),
121+
resource_type: "Microsoft.Dsc.Test/InvalidSchemaUri".to_string(),
122+
version: "0.1.0".to_string(),
123+
..Default::default()
124+
};
125+
126+
let ref result = manifest.validate_schema_uri();
127+
128+
assert!(result.as_ref().is_err());
129+
130+
match result.as_ref().unwrap_err() {
131+
DscError::UnrecognizedSchemaUri(actual, recognized) => {
132+
assert_eq!(actual, &invalid_uri);
133+
assert_eq!(recognized, &ResourceManifest::recognized_schema_uris())
134+
},
135+
_ => {
136+
panic!("Expected validate_schema_uri() to error on unrecognized schema uri, but was {:?}", result.as_ref().unwrap_err())
137+
}
138+
}
139+
}
140+
141+
#[test]
142+
fn test_validate_schema_uri_with_valid_uri() {
143+
let manifest = ResourceManifest{
144+
schema_version: ResourceManifest::default_schema_id_uri(),
145+
resource_type: "Microsoft.Dsc.Test/ValidSchemaUri".to_string(),
146+
version: "0.1.0".to_string(),
147+
..Default::default()
148+
};
149+
150+
let result = manifest.validate_schema_uri();
151+
152+
assert!(result.is_ok());
153+
}
154+
}

0 commit comments

Comments
 (0)