diff --git a/melos_openapi_generator_dart.iml b/melos_openapi_generator_dart.iml
index a84ffe6..ef116cd 100644
--- a/melos_openapi_generator_dart.iml
+++ b/melos_openapi_generator_dart.iml
@@ -10,9 +10,12 @@
+
+
+
-
+
\ No newline at end of file
diff --git a/openapi-generator-cli/bin/main.dart b/openapi-generator-cli/bin/main.dart
index e6deb32..4162f15 100644
--- a/openapi-generator-cli/bin/main.dart
+++ b/openapi-generator-cli/bin/main.dart
@@ -3,31 +3,12 @@ import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
+import 'package:openapi_generator_cli/src/models.dart';
import 'package:path/path.dart' as p;
const baseDownloadUrl =
'https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli';
-/// Default configuration values
-class ConfigDefaults {
- static const openapiGeneratorVersion = '7.9.0';
- static const additionalCommands = '';
- static const downloadUrlOverride = null;
- static const jarCacheDir = '.dart_tool/openapi_generator_cache';
- static const customGeneratorUrls = [
- 'https://repo1.maven.org/maven2/com/bluetrainsoftware/maven/openapi-dart-generator/7.2/openapi-dart-generator-7.2.jar'
- ];
-}
-
-/// Configuration keys as static constants
-class ConfigKeys {
- static const openapiGeneratorVersion = 'openapiGeneratorVersion';
- static const additionalCommands = 'additionalCommands';
- static const downloadUrlOverride = 'downloadUrlOverride';
- static const jarCachePath = 'jarCacheDir';
- static const customGeneratorUrls = 'customGeneratorUrls';
-}
-
/// Resolves a given path to an absolute path, handling both relative and absolute inputs
String resolvePath(String path) {
return p.isAbsolute(path) ? path : p.absolute(Directory.current.path, path);
diff --git a/openapi-generator-cli/lib/src/generate_command.dart b/openapi-generator-cli/lib/src/generate_command.dart
new file mode 100644
index 0000000..1206a50
--- /dev/null
+++ b/openapi-generator-cli/lib/src/generate_command.dart
@@ -0,0 +1,41 @@
+import 'package:args/command_runner.dart';
+import 'package:openapi_generator_cli/src/models.dart';
+
+class GenerateCommand extends Command {
+ // The [name] and [description] properties must be defined by every
+ // subclass.
+ final name = "generate";
+ final description = "Record changes to the repository.";
+
+ CommitCommand() {
+ // Add options based on ConfigDefaults and ConfigKeys
+ argParser.addOption(ConfigKeys.openapiGeneratorVersion,
+ help: 'The version of the OpenAPI generator to use.',
+ defaultsTo: ConfigDefaults.openapiGeneratorVersion);
+
+ argParser.addOption(ConfigKeys.additionalCommands,
+ help:
+ 'Additional commands to pass to the generator. This command will be appended at the end of the commands pas',
+ defaultsTo: ConfigDefaults.additionalCommands);
+
+ argParser.addOption(ConfigKeys.downloadUrlOverride,
+ help: 'A custom URL to override the default download location.',
+ defaultsTo: ConfigDefaults.downloadUrlOverride);
+
+ argParser.addOption(ConfigKeys.jarCachePath,
+ help: 'The directory where the JAR cache will be stored.',
+ defaultsTo: ConfigDefaults.jarCacheDir);
+
+ argParser.addMultiOption(ConfigKeys.customGeneratorUrls,
+ help:
+ 'Urls for the jars of additional OpenAPI generators to combine with the official one.',
+ defaultsTo: ConfigDefaults.customGeneratorUrls);
+ }
+
+ // [run] may also return a Future.
+ void run() {
+ // [argResults] is set before [run()] is called and contains the flags/options
+ // passed to this command.
+ print(argResults?.option('all'));
+ }
+}
diff --git a/openapi-generator-cli/lib/src/models.dart b/openapi-generator-cli/lib/src/models.dart
new file mode 100644
index 0000000..daca4f8
--- /dev/null
+++ b/openapi-generator-cli/lib/src/models.dart
@@ -0,0 +1,19 @@
+/// Default configuration values
+class ConfigDefaults {
+ static const openapiGeneratorVersion = '7.9.0';
+ static const additionalCommands = '';
+ static const downloadUrlOverride = null;
+ static const jarCacheDir = '.dart_tool/openapi_generator_cache';
+ static const customGeneratorUrls = [
+ 'https://repo1.maven.org/maven2/com/bluetrainsoftware/maven/openapi-dart-generator/7.2/openapi-dart-generator-7.2.jar'
+ ];
+}
+
+/// Configuration keys as static constants
+class ConfigKeys {
+ static const openapiGeneratorVersion = 'openapiGeneratorVersion';
+ static const additionalCommands = 'additionalCommands';
+ static const downloadUrlOverride = 'downloadUrlOverride';
+ static const jarCachePath = 'jarCacheDir';
+ static const customGeneratorUrls = 'customGeneratorUrls';
+}
diff --git a/openapi-generator-cli/pubspec.yaml b/openapi-generator-cli/pubspec.yaml
index 96600b0..a2898df 100644
--- a/openapi-generator-cli/pubspec.yaml
+++ b/openapi-generator-cli/pubspec.yaml
@@ -9,6 +9,8 @@ environment:
dependencies:
http: '>=1.2.2 <=2.0.0'
path: '>=1.9.0 <=2.0.0'
+ args: '>=2.6.0 <3.0.0'
+ cli_launcher: ^0.3.1
dev_dependencies:
pedantic:
diff --git a/openapi-generator-cli/test/openapi_generator_cli_test.dart b/openapi-generator-cli/test/openapi_generator_cli_test.dart
index f71f878..a3c7142 100644
--- a/openapi-generator-cli/test/openapi_generator_cli_test.dart
+++ b/openapi-generator-cli/test/openapi_generator_cli_test.dart
@@ -2,6 +2,7 @@ import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
+import 'package:openapi_generator_cli/src/models.dart';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
diff --git a/openapi-generator/lib/src/openapi_generator_runner.dart b/openapi-generator/lib/src/openapi_generator_runner.dart
index e8480e7..a310fbb 100755
--- a/openapi-generator/lib/src/openapi_generator_runner.dart
+++ b/openapi-generator/lib/src/openapi_generator_runner.dart
@@ -12,6 +12,7 @@ import 'package:openapi_generator/src/process_runner.dart';
import 'package:openapi_generator/src/utils.dart';
import 'package:openapi_generator_annotations/openapi_generator_annotations.dart'
as annots;
+import 'package:path/path.dart' as path;
import 'package:source_gen/source_gen.dart';
import 'models/command.dart';
@@ -131,7 +132,21 @@ class OpenapiGenerator extends GeneratorForAnnotation {
workingDirectory: Directory.current.path,
runInShell: Platform.isWindows,
);
-
+ var outputDir = path.isRelative(arguments.outputDirectory!)
+ ? path.normalize(
+ path.join(Directory.current.path, arguments.outputDirectory!))
+ : path.normalize(arguments.outputDirectory!);
+ var outputFolderExists = Directory(outputDir).existsSync();
+ if (!outputFolderExists) {
+ logOutputMessage(
+ log: log,
+ communication: OutputMessage(
+ message: [
+ '\n::::::::::::::::::::::::\n:: Seems the code may not have been generated. If you do not find more info in the logs, set debugLogging to true on your annotation and try again.\n::::::::::::::::::::::::',
+ ].join('\n'),
+ ),
+ );
+ }
if (result.exitCode != 0) {
return Future.error(
OutputMessage(
diff --git a/openapi-generator/melos_openapi_generator.iml b/openapi-generator/melos_openapi_generator.iml
index b855938..3b42791 100644
--- a/openapi-generator/melos_openapi_generator.iml
+++ b/openapi-generator/melos_openapi_generator.iml
@@ -23,6 +23,9 @@
+
+
+
diff --git a/openapi-generator/test/github_issues_test.dart b/openapi-generator/test/github_issues_test.dart
index 4944bde..6e6e1cb 100644
--- a/openapi-generator/test/github_issues_test.dart
+++ b/openapi-generator/test/github_issues_test.dart
@@ -10,9 +10,11 @@ import 'utils.dart';
/// We test the build runner by mocking the specs and then checking the output
/// content for the expected generate command.
+///
+/// we do not use mock process runner for github issues because we want to test
+/// that generated code compiles.
+/// If you do not want to generate the actual code, then you can initialise [MockProcessRunner] in the test
void main() {
- // we do not use mock process runner for github issues because we want to test
- // that generated code compiles
var processRunner = ProcessRunner();
group('Github Issues', () {
// setUpAll(() {
@@ -58,11 +60,8 @@ void main() {
process: processRunner,
);
- expect(generatedOutput,
- contains('Skipping source gen because generator does not need it.'),
- reason: generatedOutput);
- expect(generatedOutput, contains('Successfully formatted code.'),
- reason: generatedOutput);
+ expectSourceGenSkipped(generatedOutput);
+ expectCodeFormattedSuccessfully(generatedOutput);
var analyzeResult = await Process.run(
'dart',
['analyze'],
@@ -101,11 +100,9 @@ void main() {
annotatedFileContent.replaceAll('{{issueNumber}}', issueNumber),
);
- expect(generatedOutput,
- contains('Skipping source gen because generator does not need it.'),
- reason: generatedOutput);
- expect(generatedOutput, contains('Successfully formatted code.'),
- reason: generatedOutput);
+ expectSourceGenSkipped(generatedOutput);
+ expectCodeFormattedSuccessfully(generatedOutput);
+
var analyzeResult = await Process.run(
'dart',
['analyze', '--no-fatal-warnings'],
@@ -133,13 +130,8 @@ void main() {
annotatedFileContent.replaceAll('{{issueNumber}}', issueNumber),
);
- expect(
- generatedOutput,
- contains(
- 'pub run build_runner build --delete-conflicting-outputs'),
- reason: generatedOutput);
- expect(generatedOutput, contains('Successfully formatted code.'),
- reason: generatedOutput);
+ expectSourceGenRun(generatedOutput);
+ expectCodeFormattedSuccessfully(generatedOutput);
var workingDirectory = path.join(parentFolder, 'output');
var analyzeResult = await Process.run(
'dart',
@@ -180,11 +172,8 @@ void main() {
annotatedFileContent.replaceAll('{{issueNumber}}', issueNumber),
);
- expect(generatedOutput,
- contains('Skipping source gen because generator does not need it.'),
- reason: generatedOutput);
- expect(generatedOutput, contains('Successfully formatted code.'),
- reason: generatedOutput);
+ expectSourceGenSkipped(generatedOutput);
+ expectCodeFormattedSuccessfully(generatedOutput);
var analyzeResult = await Process.run(
'dart',
['analyze', '--fatal-warnings'],
@@ -212,13 +201,8 @@ void main() {
annotatedFileContent.replaceAll('{{issueNumber}}', issueNumber),
);
- expect(
- generatedOutput,
- contains(
- 'pub run build_runner build --delete-conflicting-outputs'),
- reason: generatedOutput);
- expect(generatedOutput, contains('Successfully formatted code.'),
- reason: generatedOutput);
+ expectSourceGenRun(generatedOutput);
+ expectCodeFormattedSuccessfully(generatedOutput);
var workingDirectory = path.join(parentFolder, 'output');
await Process.run(
'dart',
@@ -257,11 +241,8 @@ void main() {
var generatedOutput = await generateFromPath(annotatedFile.path,
process: processRunner, openapiSpecFilePath: inputSpecFile.path);
- expect(generatedOutput,
- contains('Skipping source gen because generator does not need it.'),
- reason: generatedOutput);
- expect(generatedOutput, contains('Successfully formatted code.'),
- reason: generatedOutput);
+ expectSourceGenSkipped(generatedOutput);
+ expectCodeFormattedSuccessfully(generatedOutput);
var analyzeResult = await Process.run(
'dart',
['analyze', '--no-fatal-warnings'],
@@ -282,8 +263,7 @@ void main() {
var generatedOutput = await generateFromPath(annotatedFile.path,
process: processRunner, openapiSpecFilePath: inputSpecFile.path);
- expect(generatedOutput, contains('Successfully formatted code.'),
- reason: generatedOutput);
+ expectCodeFormattedSuccessfully(generatedOutput);
var workingDirectory = path.join(parentFolder, 'output');
var analyzeResult = await Process.run(
'dart',
@@ -333,5 +313,90 @@ void main() {
cleanup(workingDirectory);
}, skip: true);
});
+
+ group('#164', () {
+ var issueNumber = '164';
+ var parentFolder = path.join(testSpecPath, 'issue', issueNumber);
+ var workingDirectory = path.join(parentFolder, 'output');
+ setUpAll(
+ () {
+ var workingDirectory = path.join(parentFolder, 'output');
+ cleanup(workingDirectory);
+ },
+ );
+ test('[dio] Test that generation does not fail', () async {
+ var generatedOutput = await generateFromAnnotation(
+ Openapi(
+ additionalProperties: DioProperties(
+ pubName: 'petstore_api', pubAuthor: 'Johnny_dep'),
+ inputSpec: RemoteSpec(
+ path: 'https://petstore3.swagger.io/api/v3/openapi.json'),
+ typeMappings: {'Pet': 'ExamplePet'},
+ generatorName: Generator.dio,
+ runSourceGenOnOutput: true,
+ skipIfSpecIsUnchanged: false,
+ cleanSubOutputDirectory: [
+ './test/specs/issue/$issueNumber/output'
+ ],
+ outputDirectory: './test/specs/issue/$issueNumber/output'),
+ process: processRunner,
+ );
+
+ expectSourceGenRun(generatedOutput);
+ expectCodeFormattedSuccessfully(generatedOutput);
+ var analyzeResult = await Process.run(
+ 'dart',
+ ['analyze', '--no-fatal-warnings'],
+ workingDirectory: workingDirectory,
+ );
+ expect(analyzeResult.exitCode, 0,
+ reason: '${analyzeResult.stdout}\n\n${analyzeResult.stderr}');
+ cleanup(workingDirectory);
+ });
+ });
+
+ group('#167', () {
+ var issueNumber = '167';
+ var parentFolder = path.join(testSpecPath, 'issue', issueNumber);
+ var workingDirectory = path.join(parentFolder, 'output');
+ setUpAll(
+ () {
+ var workingDirectory = path.join(parentFolder, 'output');
+ cleanup(workingDirectory);
+ },
+ );
+ test('[dio] Test that generation does not fail', () async {
+ var generatedOutput = await generateFromAnnotation(
+ Openapi(
+ additionalProperties: DioAltProperties(
+ pubName: 'issue_api',
+ ),
+ inputSpec: InputSpec(
+ path:
+ './test/specs/issue/$issueNumber/github_issue_#167.yaml'),
+ generatorName: Generator.dio,
+ runSourceGenOnOutput: true,
+ typeMappings: {'Pet': 'ExamplePet', 'Test': 'ExampleTest'},
+ skipIfSpecIsUnchanged: false,
+ cleanSubOutputDirectory: [
+ './test/specs/issue/$issueNumber/output'
+ ],
+ outputDirectory: './test/specs/issue/$issueNumber/output'),
+ process: processRunner,
+ );
+
+ expectSourceGenRun(generatedOutput);
+ expectCodeFormattedSuccessfully(generatedOutput);
+ var analyzeResult = await Process.run(
+ 'dart',
+ ['analyze', '--no-fatal-warnings'],
+ workingDirectory: workingDirectory,
+ );
+ expect(analyzeResult.exitCode, 0,
+ reason: '${analyzeResult.stdout}\n\n${analyzeResult.stderr}');
+
+ cleanup(workingDirectory);
+ });
+ });
});
}
diff --git a/openapi-generator/test/specs/issue/167/a.yml b/openapi-generator/test/specs/issue/167/a.yml
new file mode 100644
index 0000000..552843f
--- /dev/null
+++ b/openapi-generator/test/specs/issue/167/a.yml
@@ -0,0 +1,4 @@
+type: object
+properties:
+ optionA1:
+ type: string
diff --git a/openapi-generator/test/specs/issue/167/b.yml b/openapi-generator/test/specs/issue/167/b.yml
new file mode 100644
index 0000000..9c2e983
--- /dev/null
+++ b/openapi-generator/test/specs/issue/167/b.yml
@@ -0,0 +1,4 @@
+type: object
+properties:
+ optionB1:
+ type: string
diff --git a/openapi-generator/test/specs/issue/167/github_issue_#167.yaml b/openapi-generator/test/specs/issue/167/github_issue_#167.yaml
new file mode 100644
index 0000000..b02d975
--- /dev/null
+++ b/openapi-generator/test/specs/issue/167/github_issue_#167.yaml
@@ -0,0 +1,15 @@
+openapi: 3.0.3
+info:
+ version: '1.0'
+ title: Test
+paths:
+ /test:
+ get:
+ operationId: test
+ responses:
+ '200':
+ description: response
+ content:
+ application/json:
+ schema:
+ $ref: "./test.yml"
diff --git a/openapi-generator/test/specs/issue/167/test.yml b/openapi-generator/test/specs/issue/167/test.yml
new file mode 100644
index 0000000..cd51db1
--- /dev/null
+++ b/openapi-generator/test/specs/issue/167/test.yml
@@ -0,0 +1,11 @@
+type: object
+oneOf:
+ - $ref: './a.yml'
+ - $ref: './b.yml'
+discriminator:
+ propertyName: type
+required:
+ - type
+properties:
+ type:
+ $ref: './testType.yml'
diff --git a/openapi-generator/test/specs/issue/167/testType.yml b/openapi-generator/test/specs/issue/167/testType.yml
new file mode 100644
index 0000000..c752ecc
--- /dev/null
+++ b/openapi-generator/test/specs/issue/167/testType.yml
@@ -0,0 +1,4 @@
+type: string
+enum:
+ - a
+ - b
diff --git a/openapi-generator/test/utils.dart b/openapi-generator/test/utils.dart
index 17ab961..f971841 100644
--- a/openapi-generator/test/utils.dart
+++ b/openapi-generator/test/utils.dart
@@ -197,3 +197,21 @@ void cleanup(String path) async {
print('Folder does not exist.');
}
}
+
+// Test Expectations
+void expectSourceGenSkipped(String generatedOutput) {
+ return expect(generatedOutput,
+ contains('Skipping source gen because generator does not need it.'),
+ reason: generatedOutput);
+}
+
+void expectCodeFormattedSuccessfully(String generatedOutput) {
+ expect(generatedOutput, contains('Successfully formatted code.'),
+ reason: generatedOutput);
+}
+
+void expectSourceGenRun(String generatedOutput) {
+ return expect(generatedOutput,
+ contains('pub run build_runner build --delete-conflicting-outputs'),
+ reason: generatedOutput);
+}