Skip to content

Commit fdfb9b1

Browse files
committed
add separate command for merging openapi specs
1 parent d3d8974 commit fdfb9b1

File tree

3 files changed

+61
-22
lines changed

3 files changed

+61
-22
lines changed

src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ use openapiv3::OpenAPI;
1818
use std::path::Path;
1919
use std::result;
2020

21-
mod merger;
21+
pub(crate) mod merger;
2222
pub(crate) mod printer;
2323
mod rust;
2424
mod toml;
2525

26+
pub use merger::merge_all_openapi_specs;
27+
2628
#[derive(Debug, Clone)]
2729
pub enum Error {
2830
Unexpected { message: String },
@@ -56,7 +58,7 @@ impl Error {
5658
pub type Result<T> = result::Result<T, Error>;
5759

5860
pub fn gen(openapi_specs: Vec<OpenAPI>, target: &Path, name: &str, version: &str) -> Result<()> {
59-
let open_api = merger::merge_all_openapi_specs(openapi_specs)?;
61+
let open_api = merge_all_openapi_specs(openapi_specs)?;
6062

6163
let src = target.join("src");
6264
let api = src.join("api");

src/main.rs

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use clap::Parser;
15+
use clap::{Args, Parser};
1616
use golem_openapi_client_generator::gen;
1717
use openapiv3::OpenAPI;
1818
use std::fs::File;
@@ -21,7 +21,15 @@ use std::path::PathBuf;
2121

2222
#[derive(Parser, Debug)]
2323
#[command(author, version, about, long_about = None, rename_all = "kebab-case")]
24-
struct Command {
24+
enum Cli {
25+
/// Generate a client from an OpenAPI spec
26+
Generate(GenerateArgs),
27+
/// Merge multiple OpenAPI specs into a single one
28+
Merge(MergeArgs),
29+
}
30+
31+
#[derive(Debug, Args)]
32+
struct GenerateArgs {
2533
#[arg(short, long, value_name = "spec", value_hint = clap::ValueHint::FilePath, num_args = 1.., required = true)]
2634
spec_yaml: Vec<PathBuf>,
2735

@@ -35,26 +43,46 @@ struct Command {
3543
name: String,
3644
}
3745

46+
#[derive(Debug, Args)]
47+
struct MergeArgs {
48+
#[arg(short, long, value_name = "specs", value_hint = clap::ValueHint::FilePath, num_args = 1.., required = true)]
49+
spec_yaml: Vec<PathBuf>,
50+
#[arg(short, long, value_name = "output", value_hint = clap::ValueHint::FilePath)]
51+
output_file: PathBuf,
52+
}
53+
3854
fn main() {
39-
let command = Command::parse();
55+
let command = Cli::parse();
56+
57+
match command {
58+
Cli::Generate(args) => {
59+
let openapi_specs = parse_openapi_specs(&args.spec_yaml);
60+
gen(
61+
openapi_specs,
62+
&args.output_directory,
63+
&args.name,
64+
&args.client_version,
65+
)
66+
.unwrap();
67+
}
68+
Cli::Merge(args) => {
69+
let openapi_specs = parse_openapi_specs(&args.spec_yaml);
70+
let openapi =
71+
golem_openapi_client_generator::merge_all_openapi_specs(openapi_specs).unwrap();
72+
let file = File::create(&args.output_file).unwrap();
73+
serde_yaml::to_writer(file, &openapi).unwrap();
74+
}
75+
}
76+
}
4077

41-
let openapi_specs = command
42-
.spec_yaml
43-
.into_iter()
78+
fn parse_openapi_specs(spec: &Vec<PathBuf>) -> Vec<OpenAPI> {
79+
spec.into_iter()
4480
.map(|spec| {
4581
let file = File::open(&spec).unwrap();
4682
let reader = BufReader::new(file);
4783
let openapi: OpenAPI = serde_yaml::from_reader(reader)
4884
.expect(format!("Could not deserialize input: {:?}", spec).as_str());
4985
openapi
5086
})
51-
.collect::<Vec<_>>();
52-
53-
gen(
54-
openapi_specs,
55-
&command.output_directory,
56-
&command.name,
57-
&command.client_version,
58-
)
59-
.unwrap();
87+
.collect::<Vec<_>>()
6088
}

src/merger.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use openapiv3::{Components, ExternalDocumentation, OpenAPI, Paths};
44
use crate::Error;
55
use crate::Result;
66

7-
pub(crate) fn merge_all_openapi_specs(openapi_specs: Vec<OpenAPI>) -> Result<OpenAPI> {
7+
pub fn merge_all_openapi_specs(openapi_specs: Vec<OpenAPI>) -> Result<OpenAPI> {
88
if openapi_specs.is_empty() {
99
Err(Error::unexpected("No OpenAPI specs provided"))
1010
} else if openapi_specs.len() == 1 {
@@ -46,10 +46,19 @@ fn merge_openapi_specs(a: OpenAPI, b: OpenAPI) -> Result<OpenAPI> {
4646
};
4747

4848
let all_tags = {
49-
let mut tags = a.tags;
50-
let mut b_tags = b.tags;
51-
tags.append(&mut b_tags);
52-
tags
49+
let a_tags_map = a
50+
.tags
51+
.into_iter()
52+
.map(|tag| (tag.name.clone(), tag))
53+
.collect::<IndexMap<_, _>>();
54+
let b_tags_map = b
55+
.tags
56+
.into_iter()
57+
.map(|tag| (tag.name.clone(), tag))
58+
.collect::<IndexMap<_, _>>();
59+
let merged = merge_unique(a_tags_map, b_tags_map)?;
60+
61+
merged.into_values().collect::<Vec<_>>()
5362
};
5463

5564
let all_paths = {

0 commit comments

Comments
 (0)