Skip to content

Commit 23ffb62

Browse files
committed
fix schemas
1 parent fd51580 commit 23ffb62

7 files changed

Lines changed: 57 additions & 23 deletions

File tree

examples/circleci_rails/config.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
$schema: ../../schemas/v1/config-schema.json
2-
31
# CI provider to target
42
provider: circleci
53
output_path: ./build

examples/circleci_rails/workflows/setup/config.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
$schema: ../../../schemas/v1/workflow-config-schema.json
2-
31
# This is a static workflow that generates the dynamic config.
42
dynamic: false
53

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
$schema: ../../../schemas/v1/workflow-config-schema.json
2-
31
dynamic: true

schemas/v1/config-base-schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
"title": "CIGen Configuration Base Schema",
44
"description": "Base schema for cigen configuration fragments - allows any subset of properties",
55
"type": "object",
6-
"$ref": "https://cigen.dev/schemas/v1/definitions.json#/definitions/configProperties",
6+
"$ref": "./definitions.json#/definitions/configProperties",
77
"additionalProperties": false
88
}

schemas/v1/workflow-config-schema.json

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,22 @@
33
"title": "CIGen Workflow Configuration Schema",
44
"description": "Schema for workflow-level configuration files",
55
"type": "object",
6-
"allOf": [
7-
{
8-
"$ref": "https://cigen.dev/schemas/v1/definitions.json#/definitions/configProperties"
9-
}
10-
],
116
"properties": {
127
"dynamic": {
138
"type": "boolean",
149
"description": "Whether this workflow uses dynamic job skipping based on file changes",
1510
"default": false
11+
},
12+
"output_path": {
13+
"type": "string",
14+
"description": "Path where generated CI config will be written",
15+
"default": "./build"
16+
},
17+
"output_filename": {
18+
"type": "string",
19+
"description": "Filename for the generated CI config (useful when splitting workflows)",
20+
"pattern": "^[^/\\\\]+\\.yml$"
1621
}
17-
}
22+
},
23+
"additionalProperties": false
1824
}

src/validation/config.rs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,46 @@ use super::schemas::{
1111
SchemaRetriever, get_config_base_schema, get_config_schema, get_workflow_config_schema,
1212
};
1313

14+
// Use JSON Schema draft-07 for validation (stable and well-tested)
15+
// TODO: Upgrade to draft 2020-12 once we update our schemas
16+
use jsonschema::draft7 as schema_draft;
17+
1418
pub struct ConfigValidator;
1519

1620
impl ConfigValidator {
1721
pub fn new() -> Self {
1822
Self
1923
}
2024

25+
/// Extract a more specific instance path for certain validation errors
26+
fn refine_instance_path(error: &jsonschema::ValidationError) -> String {
27+
let error_msg = error.to_string();
28+
29+
// For "additional properties" errors, extract the property name and append to path
30+
if error_msg.contains("Additional properties are not allowed") {
31+
// Extract property names from error message like "('asdf' was unexpected)"
32+
if let Some(start) = error_msg.find("('") {
33+
if let Some(end) = error_msg[start + 2..].find("'") {
34+
let prop_name = &error_msg[start + 2..start + 2 + end];
35+
return if error.instance_path.to_string().is_empty() {
36+
format!("/{prop_name}")
37+
} else {
38+
format!("{}/{prop_name}", error.instance_path)
39+
};
40+
}
41+
}
42+
}
43+
44+
error.instance_path.to_string()
45+
}
46+
2147
pub fn validate_config(&self, config_path: &Path) -> Result<()> {
2248
// 1. Schema validation with beautiful miette error reporting
2349
let spanned_validator = SpannedValidator::new(config_path)
2450
.map_err(|e| anyhow::anyhow!("Failed to parse YAML from {config_path:?}: {e}"))?;
2551

2652
let schema = get_config_schema().context("Failed to parse config schema")?;
27-
let validator = jsonschema::draft7::options()
53+
let validator = schema_draft::options()
2854
.with_retriever(SchemaRetriever)
2955
.build(&schema)
3056
.context("Failed to compile config schema")?;
@@ -36,8 +62,9 @@ impl ConfigValidator {
3662
if !errors.is_empty() {
3763
eprintln!(); // Add newline before first error
3864
for error in &errors {
39-
let validation_error = spanned_validator
40-
.create_error(&error.instance_path.to_string(), error.to_string());
65+
let instance_path = Self::refine_instance_path(error);
66+
let validation_error =
67+
spanned_validator.create_error(&instance_path, error.to_string());
4168
eprintln!("{:?}", Report::new(validation_error));
4269
}
4370
anyhow::bail!(
@@ -65,7 +92,7 @@ impl ConfigValidator {
6592
.with_context(|| format!("Failed to parse rendered YAML from: {source_path:?}"))?;
6693

6794
let schema = get_config_schema().context("Failed to parse config schema")?;
68-
let validator = jsonschema::draft7::options()
95+
let validator = schema_draft::options()
6996
.with_retriever(SchemaRetriever)
7097
.build(&schema)
7198
.context("Failed to compile config schema")?;
@@ -94,7 +121,7 @@ impl ConfigValidator {
94121
// Use base schema for fragments (allows any subset of properties)
95122
let schema = get_config_base_schema().context("Failed to parse config base schema")?;
96123

97-
let validator = jsonschema::draft7::options()
124+
let validator = schema_draft::options()
98125
.with_retriever(SchemaRetriever)
99126
.build(&schema)
100127
.context("Failed to compile config base schema")?;
@@ -122,7 +149,7 @@ impl ConfigValidator {
122149

123150
// Use base schema for fragments (allows any subset of properties)
124151
let schema = get_config_base_schema().context("Failed to parse config base schema")?;
125-
let validator = jsonschema::draft7::options()
152+
let validator = schema_draft::options()
126153
.with_retriever(SchemaRetriever)
127154
.build(&schema)
128155
.context("Failed to compile config base schema")?;
@@ -148,7 +175,7 @@ impl ConfigValidator {
148175

149176
let schema =
150177
get_workflow_config_schema().context("Failed to parse workflow config schema")?;
151-
let validator = jsonschema::draft7::options()
178+
let validator = schema_draft::options()
152179
.with_retriever(SchemaRetriever)
153180
.build(&schema)
154181
.context("Failed to compile workflow config schema")?;
@@ -160,8 +187,9 @@ impl ConfigValidator {
160187
if !errors.is_empty() {
161188
eprintln!(); // Add newline before first error
162189
for error in &errors {
163-
let validation_error = spanned_validator
164-
.create_error(&error.instance_path.to_string(), error.to_string());
190+
let instance_path = Self::refine_instance_path(error);
191+
let validation_error =
192+
spanned_validator.create_error(&instance_path, error.to_string());
165193
eprintln!("{:?}", Report::new(validation_error));
166194
}
167195
anyhow::bail!(
@@ -179,7 +207,7 @@ impl ConfigValidator {
179207
// Validate against the full schema
180208
let schema = get_config_schema().context("Failed to parse config schema")?;
181209

182-
let validator = jsonschema::draft7::options()
210+
let validator = schema_draft::options()
183211
.with_retriever(SchemaRetriever)
184212
.build(&schema)
185213
.context("Failed to compile config schema")?;

src/validation/schemas.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ impl Retrieve for SchemaRetriever {
3838
"https://cigen.dev/schemas/v1/definitions.json" => {
3939
Ok(serde_json::from_str(DEFINITIONS_SCHEMA)?)
4040
}
41+
// Handle the relative reference with fragment
42+
"./definitions.json#/definitions/configProperties" => {
43+
Ok(serde_json::from_str(DEFINITIONS_SCHEMA)?)
44+
}
45+
// Handle json-schema URI scheme
46+
"json-schema:///definitions.json" => Ok(serde_json::from_str(DEFINITIONS_SCHEMA)?),
4147
"https://json-schema.org/draft-07/schema"
4248
| "https://json-schema.org/draft-07/schema#"
4349
| "http://json-schema.org/draft-07/schema"

0 commit comments

Comments
 (0)