Skip to content

Commit b9376b7

Browse files
feat: use an enum and fix schema for entry/entrypoint
1 parent 3cfbf69 commit b9376b7

10 files changed

Lines changed: 219 additions & 177 deletions

File tree

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ tokio-util = "0.7.16"
3737
md5 = "0.7.0"
3838
base64 = "0.21.0"
3939
async-compression = { version = "0.4.5", features = ["tokio", "gzip"] }
40-
schemars = "0.8"
40+
schemars = "1.2.1"
4141
simplelog = { version = "0.12.1", default-features = false, features = [
4242
"termcolor",
4343
] }

schemas/codspeed.schema.json

Lines changed: 87 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,56 @@
11
{
2-
"$schema": "http://json-schema.org/draft-07/schema#",
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
33
"title": "ProjectConfig",
4-
"description": "Project-level configuration from codspeed.yaml file\n\nThis configuration provides default options for the run and exec commands. CLI arguments always take precedence over config file values.",
4+
"description": "Project-level configuration from codspeed.yaml file\n\nThis configuration provides default options for the run and exec commands.\nCLI arguments always take precedence over config file values.",
55
"type": "object",
66
"properties": {
7-
"benchmarks": {
8-
"description": "List of benchmark targets to execute",
9-
"type": [
10-
"array",
11-
"null"
12-
],
13-
"items": {
14-
"$ref": "#/definitions/Target"
15-
}
16-
},
177
"options": {
188
"description": "Default options to apply to all benchmark runs",
19-
"anyOf": [
9+
"oneOf": [
2010
{
21-
"$ref": "#/definitions/ProjectOptions"
11+
"$ref": "#/$defs/ProjectOptions"
2212
},
2313
{
2414
"type": "null"
2515
}
2616
]
17+
},
18+
"benchmarks": {
19+
"description": "List of benchmark targets to execute",
20+
"type": [
21+
"array",
22+
"null"
23+
],
24+
"items": {
25+
"$ref": "#/$defs/Target"
26+
}
2727
}
2828
},
29-
"definitions": {
29+
"$defs": {
3030
"ProjectOptions": {
3131
"description": "Root-level options that apply to all benchmark runs unless overridden by CLI",
3232
"type": "object",
3333
"properties": {
34-
"max-rounds": {
35-
"description": "Maximum number of rounds",
34+
"working-directory": {
35+
"description": "Working directory where commands will be executed (relative to config file)",
3636
"type": [
37-
"integer",
37+
"string",
3838
"null"
39-
],
40-
"format": "uint64",
41-
"minimum": 0.0
39+
]
4240
},
43-
"max-time": {
44-
"description": "Maximum total execution time",
41+
"warmup-time": {
42+
"description": "Duration of warmup phase (e.g., \"1s\", \"500ms\")",
4543
"type": [
4644
"string",
4745
"null"
4846
]
4947
},
50-
"min-rounds": {
51-
"description": "Minimum number of rounds",
48+
"max-time": {
49+
"description": "Maximum total execution time",
5250
"type": [
53-
"integer",
51+
"string",
5452
"null"
55-
],
56-
"format": "uint64",
57-
"minimum": 0.0
53+
]
5854
},
5955
"min-time": {
6056
"description": "Minimum total execution time",
@@ -63,35 +59,32 @@
6359
"null"
6460
]
6561
},
66-
"warmup-time": {
67-
"description": "Duration of warmup phase (e.g., \"1s\", \"500ms\")",
62+
"max-rounds": {
63+
"description": "Maximum number of rounds",
6864
"type": [
69-
"string",
65+
"integer",
7066
"null"
71-
]
67+
],
68+
"format": "uint64",
69+
"minimum": 0
7270
},
73-
"working-directory": {
74-
"description": "Working directory where commands will be executed (relative to config file)",
71+
"min-rounds": {
72+
"description": "Minimum number of rounds",
7573
"type": [
76-
"string",
74+
"integer",
7775
"null"
78-
]
76+
],
77+
"format": "uint64",
78+
"minimum": 0
7979
}
8080
}
8181
},
8282
"Target": {
8383
"description": "A benchmark target to execute.\n\nEither `exec` or `entrypoint` must be specified (mutually exclusive).",
8484
"type": "object",
8585
"properties": {
86-
"entrypoint": {
87-
"description": "Command with built-in benchmark harness (mutually exclusive with `exec`)",
88-
"type": [
89-
"string",
90-
"null"
91-
]
92-
},
93-
"exec": {
94-
"description": "Command measured by exec-harness (mutually exclusive with `entrypoint`)",
86+
"name": {
87+
"description": "Optional name for this target (display purposes only)",
9588
"type": [
9689
"string",
9790
"null"
@@ -104,38 +97,55 @@
10497
"null"
10598
]
10699
},
107-
"name": {
108-
"description": "Optional name for this target (display purposes only)",
109-
"type": [
110-
"string",
111-
"null"
112-
]
113-
},
114100
"options": {
115101
"description": "Target-specific options",
116-
"anyOf": [
102+
"oneOf": [
117103
{
118-
"$ref": "#/definitions/TargetOptions"
104+
"$ref": "#/$defs/TargetOptions"
119105
},
120106
{
121107
"type": "null"
122108
}
123109
]
124110
}
125-
}
111+
},
112+
"oneOf": [
113+
{
114+
"description": "Command measured by exec-harness",
115+
"type": "object",
116+
"properties": {
117+
"exec": {
118+
"type": "string"
119+
}
120+
},
121+
"required": [
122+
"exec"
123+
]
124+
},
125+
{
126+
"description": "Command with built-in benchmark harness",
127+
"type": "object",
128+
"properties": {
129+
"entrypoint": {
130+
"type": "string"
131+
}
132+
},
133+
"required": [
134+
"entrypoint"
135+
]
136+
}
137+
]
126138
},
127139
"TargetOptions": {
128140
"description": "Walltime execution options matching WalltimeExecutionArgs structure",
129141
"type": "object",
130142
"properties": {
131-
"max-rounds": {
132-
"description": "Maximum number of rounds",
143+
"warmup-time": {
144+
"description": "Duration of warmup phase (e.g., \"1s\", \"500ms\")",
133145
"type": [
134-
"integer",
146+
"string",
135147
"null"
136-
],
137-
"format": "uint64",
138-
"minimum": 0.0
148+
]
139149
},
140150
"max-time": {
141151
"description": "Maximum total execution time",
@@ -144,28 +154,30 @@
144154
"null"
145155
]
146156
},
147-
"min-rounds": {
148-
"description": "Minimum number of rounds",
149-
"type": [
150-
"integer",
151-
"null"
152-
],
153-
"format": "uint64",
154-
"minimum": 0.0
155-
},
156157
"min-time": {
157158
"description": "Minimum total execution time",
158159
"type": [
159160
"string",
160161
"null"
161162
]
162163
},
163-
"warmup-time": {
164-
"description": "Duration of warmup phase (e.g., \"1s\", \"500ms\")",
164+
"max-rounds": {
165+
"description": "Maximum number of rounds",
165166
"type": [
166-
"string",
167+
"integer",
167168
"null"
168-
]
169+
],
170+
"format": "uint64",
171+
"minimum": 0
172+
},
173+
"min-rounds": {
174+
"description": "Minimum number of rounds",
175+
"type": [
176+
"integer",
177+
"null"
178+
],
179+
"format": "uint64",
180+
"minimum": 0
169181
}
170182
}
171183
}

src/bin/generate_config_schema.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,31 @@
88
use std::fs;
99

1010
use codspeed_runner::ProjectConfig;
11-
use schemars::schema_for;
11+
use schemars::Schema;
12+
use schemars::generate::SchemaSettings;
13+
use schemars::transform::{Transform, transform_subschemas};
1214

1315
const OUTPUT_FILE: &str = "schemas/codspeed.schema.json";
1416

17+
/// Rewrites `anyOf` to `oneOf` in all schemas (used for untagged enums
18+
/// where variants are mutually exclusive).
19+
#[derive(Clone)]
20+
struct AnyOfToOneOf;
21+
22+
impl Transform for AnyOfToOneOf {
23+
fn transform(&mut self, schema: &mut Schema) {
24+
if let Some(any_of) = schema.remove("anyOf") {
25+
schema.insert("oneOf".to_string(), any_of);
26+
}
27+
transform_subschemas(self, schema);
28+
}
29+
}
30+
1531
fn main() {
16-
let schema = schema_for!(ProjectConfig);
32+
let generator = SchemaSettings::default()
33+
.with_transform(AnyOfToOneOf)
34+
.into_generator();
35+
let schema = generator.into_root_schema_for::<ProjectConfig>();
1736
let schema_json = serde_json::to_string_pretty(&schema).expect("Failed to serialize schema");
1837
let output_file_path = std::path::Path::new(OUTPUT_FILE);
1938
fs::create_dir_all(output_file_path.parent().unwrap())

src/cli/exec/mod.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,6 @@ pub const DEFAULT_REPOSITORY_NAME: &str = "local-runs";
2121
pub const EXEC_HARNESS_COMMAND: &str = "exec-harness";
2222
pub const EXEC_HARNESS_VERSION: &str = "1.2.0";
2323

24-
#[cfg(test)]
25-
pub fn wrap_with_exec_harness(
26-
walltime_args: &exec_harness::walltime::WalltimeExecutionArgs,
27-
command: &[String],
28-
) -> String {
29-
shell_words::join(
30-
std::iter::once(EXEC_HARNESS_COMMAND)
31-
.chain(walltime_args.to_cli_args().iter().map(|s| s.as_str()))
32-
.chain(command.iter().map(|s| s.as_str())),
33-
)
34-
}
35-
3624
#[derive(Args, Debug)]
3725
pub struct ExecArgs {
3826
#[command(flatten)]

0 commit comments

Comments
 (0)