diff --git a/aqueduct/CHANGELOG.md b/aqueduct/CHANGELOG.md index 4a16d48b5..50f0d29db 100644 --- a/aqueduct/CHANGELOG.md +++ b/aqueduct/CHANGELOG.md @@ -2,6 +2,8 @@ - `Controller` is now an abstract class that requires implementing `handle`. This is a minor breaking change that should not have an impact. - 'Serializable' can now implement static 'document' method to override component documentation behavior +- Removes `aqueduct setup --heroku=` and instead points to documentation. +- Fixes issue ORM had with transformed values (e.g. enums) and nullable columns ## 3.0.0 diff --git a/aqueduct/lib/src/cli/commands/setup.dart b/aqueduct/lib/src/cli/commands/setup.dart index a91e7ebcf..94a5df190 100644 --- a/aqueduct/lib/src/cli/commands/setup.dart +++ b/aqueduct/lib/src/cli/commands/setup.dart @@ -10,8 +10,7 @@ class CLISetup extends CLICommand with CLIProject { @Option("heroku", help: - "Sets up the project in the current directory for deplying to Heroku.", - valueHelp: "The name of the Heroku application.") + "DEPRECATED. Please see https://aqueduct.io/docs/deploy/deploy_heroku/.") String get herokuName => decode("heroku"); @Flag("tests", @@ -35,73 +34,15 @@ class CLISetup extends CLICommand with CLIProject { @override Future handle() async { if (shouldSetupHeroku) { - return setupHerokuProject(); + displayInfo("This option has been deprecated."); + displayProgress("Please see https://aqueduct.io/docs/deploy/deploy_heroku/ for instructions."); + return 0; } else /*if (shouldSetupTests*/ { return setupTestEnvironment(); } } - bool get hasGitCLI => isExecutableInShellPath("git"); bool get hasPSQLCLI => isExecutableInShellPath("psql"); - bool get hasHerokuCLI => isExecutableInShellPath("heroku"); - - Future setupHerokuProject() async { - if (!hasHerokuCLI) { - displayError("The application 'heroku' was not found in \$PATH."); - displayProgress( - "Install 'heroku' from https://devcenter.heroku.com/articles/heroku-cli."); - return -1; - } - - if (!hasGitCLI) { - displayError("The application 'git' was not found in \$PATH."); - displayProgress("Install 'git' from https://git-scm.com/downloads."); - } - - displayInfo("Setting up Heroku for $herokuName"); - - var commands = [ - ["git:remote", "-a", herokuName], - [ - "config:set", - "DART_SDK_URL=https://storage.googleapis.com/dart-archive/channels/stable/release/latest/sdk/dartsdk-linux-x64-release.zip" - ], - [ - "config:add", - "BUILDPACK_URL=https://github.com/stablekernel/heroku-buildpack-dart.git" - ], - [ - "config:set", - "PATH=/app/bin:/usr/local/bin:/usr/bin:/bin:/app/.pub-cache/bin:/app/dart-sdk/bin" - ], - ["config:set", "PUB_CACHE=/app/pub-cache"], - ]; - - for (var cmd in commands) { - displayProgress( - "Running heroku ${cmd.join(" ")} in ${projectDirectory.path}"); - var result = await Process.run("heroku", cmd, - workingDirectory: projectDirectory.path); - if (result.exitCode != 0) { - throw CLIException("Heroku command failed", - instructions: ["${result.stdout} ${result.stderr}"]); - } - } - - displayProgress("Removing config.yaml from .gitignore"); - var gitIgnore = fileInProjectDirectory(".gitignore"); - var contents = - gitIgnore.readAsStringSync().replaceAll(RegExp("config.yaml\\n"), ""); - gitIgnore.writeAsStringSync(contents); - - var procFile = fileInProjectDirectory("Procfile"); - procFile.writeAsStringSync(""" -release: /app/dart-sdk/bin/pub global run aqueduct:aqueduct db upgrade --connect \$DATABASE_URL -web: /app/dart-sdk/bin/pub global run aqueduct:aqueduct serve --port \$PORT --no-monitor - """); - - return 0; - } Future setupTestEnvironment() async { if (!hasPSQLCLI) { diff --git a/aqueduct/lib/src/http/resource_controller.dart b/aqueduct/lib/src/http/resource_controller.dart index 1dc4faae6..235160f51 100644 --- a/aqueduct/lib/src/http/resource_controller.dart +++ b/aqueduct/lib/src/http/resource_controller.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'dart:mirrors'; import 'package:aqueduct/src/auth/objects.dart'; -import 'package:aqueduct/src/db/managed/entity_mirrors.dart'; import 'package:aqueduct/src/openapi/openapi.dart'; import 'package:aqueduct/src/utilities/documented_element.dart'; import 'package:aqueduct/src/utilities/mirror_helpers.dart'; diff --git a/aqueduct/test/http/content_negotiation_test.dart b/aqueduct/test/http/content_negotiation_test.dart index 18b4ec381..7faa22416 100644 --- a/aqueduct/test/http/content_negotiation_test.dart +++ b/aqueduct/test/http/content_negotiation_test.dart @@ -5,31 +5,18 @@ import 'package:aqueduct/aqueduct.dart'; import 'package:test/test.dart'; void main() { - HttpServer server; - Request request; - HttpClient client; - - setUpAll(() { - client = HttpClient(); - }); - - tearDownAll(() async { - client.close(force: true); - }); + ClientServer clientServer = ClientServer(); setUp(() async { - server = await HttpServer.bind(InternetAddress.loopbackIPv4, 8123); + await clientServer.open(); }); tearDown(() async { - await request?.raw?.response?.close(); - await server?.close(force: true); + await clientServer.close(); }); test("No accept header returns [], all are allowed", () async { - // ignore: unawaited_futures - getWithTypes(client, null); - request = Request(await server.first); + final request = await clientServer.getWithTypes(null); expect(request.acceptableContentTypes, []); expect(request.acceptsContentType(ContentType.json), true); expect(request.acceptsContentType(ContentType.html), true); @@ -37,10 +24,7 @@ void main() { }); test("Empty Accept header returns [], all are allowed", () async { - // ignore: unawaited_futures - getWithTypes(client, []); - request = Request(await server.first); - + final request = await clientServer.getWithTypes([]); expect(request.acceptableContentTypes.isEmpty, true); expect(request.acceptsContentType(ContentType.json), true); expect(request.acceptsContentType(ContentType.html), true); @@ -50,9 +34,8 @@ void main() { test( "Two implicitly equal q-values order is defined by their position in request", () async { - // ignore: unawaited_futures - getWithTypes(client, ["text/plain", "text/html"]); - request = Request(await server.first); + final request = + await clientServer.getWithTypes(["text/plain", "text/html"]); expect( request.acceptableContentTypes .any((ct) => ct.primaryType == "text" && ct.subType == "plain"), @@ -70,9 +53,9 @@ void main() { test( "Two explicitly equal q-values order is defined by their position in request", () async { - // ignore: unawaited_futures - getWithTypes(client, ["text/plain; q=1.0", "text/html; q=1.0"]); - request = Request(await server.first); + final request = await clientServer + .getWithTypes(["text/plain; q=1.0", "text/html; q=1.0"]); + expect( request.acceptableContentTypes.first.primaryType == "text" && request.acceptableContentTypes.first.subType == "plain", @@ -88,9 +71,8 @@ void main() { }); test("Q-value with explicit 1 (not 1.0) is interpreted as 1.0", () async { - // ignore: unawaited_futures - getWithTypes(client, ["text/plain; q=1.0", "text/html; q=1"]); - request = Request(await server.first); + final request = await clientServer + .getWithTypes(["text/plain; q=1.0", "text/html; q=1"]); expect( request.acceptableContentTypes.first.primaryType == "text" && request.acceptableContentTypes.first.subType == "plain", @@ -107,9 +89,7 @@ void main() { test("Two equal q-values but primary type is * prefers to other type", () async { - // ignore: unawaited_futures - getWithTypes(client, ["*/*", "text/html"]); - request = Request(await server.first); + final request = await clientServer.getWithTypes(["*/*", "text/html"]); expect( request.acceptableContentTypes.first.primaryType == "text" && request.acceptableContentTypes.first.subType == "html", @@ -125,9 +105,7 @@ void main() { }); test("Two equal q-values but subtype is * prefers to other type", () async { - // ignore: unawaited_futures - getWithTypes(client, ["text/*", "text/html"]); - request = Request(await server.first); + final request = await clientServer.getWithTypes(["text/*", "text/html"]); expect( request.acceptableContentTypes.first.primaryType == "text" && request.acceptableContentTypes.first.subType == "html", @@ -143,13 +121,12 @@ void main() { }); test("Sorted by q-value if all content-types are fully defined", () async { - // ignore: unawaited_futures - getWithTypes(client, [ + final request = await clientServer.getWithTypes([ "text/plain; q=0.4", "text/html; q=0.8", "application/json; charset=utf-8" ]); - request = Request(await server.first); + expect( request.acceptableContentTypes.first.primaryType == "application" && request.acceptableContentTypes.first.subType == "json", @@ -169,16 +146,44 @@ void main() { }); } -Future getWithTypes(HttpClient client, List contentTypeStrings) async { - var req = await client.openUrl("GET", Uri.parse("http://localhost:8123")); - if (contentTypeStrings != null) { - if (contentTypeStrings.isEmpty) { - req.headers.set(HttpHeaders.acceptHeader, ""); - } else { - req.headers.add(HttpHeaders.acceptHeader, contentTypeStrings.join(", ")); - } +class ClientServer { + HttpServer server; + HttpClient client; + + List _requests = []; + + Future open() async { + client = HttpClient(); + server = await HttpServer.bind(InternetAddress.loopbackIPv4, 8123); + server.map((r) => Request(r)).listen((r) { + _requests.add(r); + r.raw.response.statusCode = 200; + r.raw.response.close(); + }); } - var response = await req.close(); - return response.drain(); + Future close() async { + _requests = []; + client.close(force: true); + await server.close(); + } + + Future getWithTypes(List contentTypeStrings) async { + assert(_requests.isEmpty); + + var req = await client.openUrl("GET", Uri.parse("http://localhost:8123")); + if (contentTypeStrings != null) { + if (contentTypeStrings.isEmpty) { + req.headers.set(HttpHeaders.acceptHeader, ""); + } else { + req.headers + .add(HttpHeaders.acceptHeader, contentTypeStrings.join(", ")); + } + } + + var response = await req.close(); + await response.drain(); + + return _requests.removeAt(0); + } }