Skip to content

Commit

Permalink
MIgrate to GH actions (#22)
Browse files Browse the repository at this point in the history
* Add GH action files from swift-server/swift-openapi-async-http-client

* Remove scripts

* Revert unintended TaskLocal changes

* Disable license header check (It adds Apple to the license)

* swift-format

* yml format

* format Package.swift

* Try license header template
  • Loading branch information
adam-fowler authored Nov 20, 2024
1 parent 47ebf5b commit 4e86cce
Show file tree
Hide file tree
Showing 23 changed files with 160 additions and 598 deletions.
8 changes: 8 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
root = true

[*]
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
18 changes: 18 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Main

on:
push:
branches: [main]
schedule:
- cron: "0 8,20 * * *"

jobs:
unit-tests:
name: Unit tests
uses: apple/swift-nio/.github/workflows/unit_tests.yml@main
with:
linux_5_9_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error"
linux_5_10_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error"
linux_6_0_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
28 changes: 28 additions & 0 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: PR

on:
pull_request:
types: [opened, reopened, synchronize]

jobs:
soundness:
name: Soundness
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
with:
license_header_check_project_name: "Hummingbird server framework"


unit-tests:
name: Unit tests
uses: apple/swift-nio/.github/workflows/unit_tests.yml@main
with:
linux_5_9_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -strict-concurrency=complete"
# TODO: `enable -Xswiftc -strict-concurrency=complete`
linux_5_10_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error"
linux_6_0_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable -Xswiftc -strict-concurrency=complete"
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"

cxx-interop:
name: Cxx interop
uses: apple/swift-nio/.github/workflows/cxx_interop.yml@main
18 changes: 18 additions & 0 deletions .github/workflows/pull_request_label.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: PR label

on:
pull_request:
types: [labeled, unlabeled, opened, reopened, synchronize]

jobs:
semver-label-check:
name: Semantic version label check
runs-on: ubuntu-latest
timeout-minutes: 1
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Check for Semantic Version label
uses: apple/swift-nio/.github/actions/pull_request_semver_label_checker@main
13 changes: 13 additions & 0 deletions .license_header_template
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@@===----------------------------------------------------------------------===@@
@@
@@ This source file is part of the Hummingbird server framework project
@@
@@ Copyright (c) YEARS the Hummingbird authors
@@ Licensed under Apache License v2.0
@@
@@ See LICENSE.txt for license information
@@ See CONTRIBUTORS.txt for the list of Hummingbird authors
@@
@@ SPDX-License-Identifier: Apache-2.0
@@
@@===----------------------------------------------------------------------===@@
36 changes: 36 additions & 0 deletions .licenseignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.gitignore
**/.gitignore
.licenseignore
.gitattributes
.git-blame-ignore-revs
.mailfilter
.mailmap
.spi.yml
.swift-format
.swiftformatignore
.editorconfig
.github/*
*.md
*.txt
*.yml
*.yaml
*.json
Package.swift
**/Package.swift
Package@-*.swift
**/Package@-*.swift
Package.resolved
**/Package.resolved
Makefile
*.modulemap
**/*.modulemap
**/*.docc/*
*.xcprivacy
**/*.xcprivacy
*.symlink
**/*.symlink
Dockerfile
**/Dockerfile
Snippets/*
dev/git.commit.template
.unacceptablelanguageignore
5 changes: 5 additions & 0 deletions .spi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
version: 1
builder:
configs:
- documentation_targets:
- OpenAPIHummingbird
8 changes: 4 additions & 4 deletions .swift-format
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
"lineLength" : 120,
"maximumBlankLines" : 1,
"prioritizeKeepingFunctionOutputTogether" : false,
"respectsExistingLineBreaks" : true,
"respectsExistingLineBreaks" : false,
"rules" : {
"AllPublicDeclarationsHaveDocumentation" : false,
"AllPublicDeclarationsHaveDocumentation" : true,
"AlwaysUseLowerCamelCase" : false,
"AmbiguousTrailingClosureOverload" : true,
"BeginDocumentationCommentWithOneLineSummary" : false,
Expand Down Expand Up @@ -50,9 +50,9 @@
"UseSynthesizedInitializer" : true,
"UseTripleSlashForDocumentationComments" : true,
"UseWhereClausesInForLoops" : false,
"ValidateDocumentationComments" : false
"ValidateDocumentationComments" : true
},
"spacesAroundRangeFormationOperators" : false,
"tabWidth" : 8,
"version" : 1
}
}
13 changes: 3 additions & 10 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@ import PackageDescription

let package = Package(
name: "swift-openapi-hummingbird",
platforms: [
.macOS(.v14), .iOS(.v17), .tvOS(.v17), .watchOS(.v10),
],
products: [
.library(name: "OpenAPIHummingbird", targets: ["OpenAPIHummingbird"]),
],
platforms: [.macOS(.v14), .iOS(.v17), .tvOS(.v17), .watchOS(.v10)],
products: [.library(name: "OpenAPIHummingbird", targets: ["OpenAPIHummingbird"])],
dependencies: [
.package(url: "https://github.com/apple/swift-openapi-runtime.git", from: "1.0.0"),
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0"),
Expand All @@ -25,10 +21,7 @@ let package = Package(
),
.testTarget(
name: "OpenAPIHummingbirdTests",
dependencies: [
"OpenAPIHummingbird",
.product(name: "HummingbirdTesting", package: "hummingbird"),
]
dependencies: ["OpenAPIHummingbird", .product(name: "HummingbirdTesting", package: "hummingbird")]
),
]
)
48 changes: 17 additions & 31 deletions Sources/OpenAPIHummingbird/OpenAPITransport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,21 @@ extension RouterMethods {
/// - handler: A handler to be invoked when an HTTP request is received.
/// - method: An HTTP request method.
/// - path: The URL path components, for example `["pets", ":petId"]`.
/// - queryItemNames: The names of query items to be extracted
/// from the request URL that matches the provided HTTP operation.
public func register(
_ handler: @escaping @Sendable (HTTPRequest, HTTPBody?, ServerRequestMetadata) async throws -> (
HTTPResponse, HTTPBody?
),
method: HTTPRequest.Method,
path: String
) throws {
self.on(
.init(path),
method: method
) { request, context in
) {
self.on(.init(path), method: method) { request, context in
let (openAPIRequest, openAPIRequestBody) = try request.makeOpenAPIRequest(context: context)
let openAPIRequestMetadata = context.makeOpenAPIRequestMetadata()
let (openAPIResponse, openAPIResponseBody) = try await handler(openAPIRequest, openAPIRequestBody, openAPIRequestMetadata)
let (openAPIResponse, openAPIResponseBody) = try await handler(
openAPIRequest,
openAPIRequestBody,
openAPIRequestMetadata
)
return Response(openAPIResponse, body: openAPIResponseBody)
}
}
Expand All @@ -50,16 +49,11 @@ extension Request {
func makeOpenAPIRequest<Context: RequestContext>(context: Context) throws -> (HTTPRequest, HTTPBody?) {
let request = self.head
// extract length from content-length header
let length = if let contentLengthHeader = self.headers[.contentLength], let contentLength = Int(contentLengthHeader) {
HTTPBody.Length.known(numericCast(contentLength))
} else {
HTTPBody.Length.unknown
}
let body = HTTPBody(
self.body.map { [UInt8](buffer: $0) },
length: length,
iterationBehavior: .single
)
let length =
if let contentLengthHeader = self.headers[.contentLength], let contentLength = Int(contentLengthHeader) {
HTTPBody.Length.known(numericCast(contentLength))
} else { HTTPBody.Length.unknown }
let body = HTTPBody(self.body.map { [UInt8](buffer: $0) }, length: length, iterationBehavior: .single)
return (request, body)
}
}
Expand All @@ -69,22 +63,18 @@ extension RequestContext {
func makeOpenAPIRequestMetadata() -> ServerRequestMetadata {
let keyAndValues = self.parameters.map { (key: String($0.0), value: $0.1) }
let openAPIParameters = [String: Substring](keyAndValues) { first, _ in first }
return .init(
pathParameters: openAPIParameters
)
return .init(pathParameters: openAPIParameters)
}
}

extension Response {
init(_ response: HTTPResponse, body: HTTPBody?) {
let responseBody: ResponseBody
if let body = body {
let bufferSequence = body.map { ByteBuffer(bytes: $0)}
let bufferSequence = body.map { ByteBuffer(bytes: $0) }
if case .known(let length) = body.length {
responseBody = .init(contentLength: numericCast(length)) { writer in
for try await buffer in bufferSequence {
try await writer.write(buffer)
}
for try await buffer in bufferSequence { try await writer.write(buffer) }
try await writer.finish(nil)
}
} else {
Expand All @@ -94,11 +84,7 @@ extension Response {
responseBody = .init(byteBuffer: ByteBuffer())
}

self.init(
status: response.status,
headers: response.headerFields,
body: responseBody
)
self.init(status: response.status, headers: response.headerFields, body: responseBody)
}
}

Expand All @@ -110,4 +96,4 @@ extension RouteCollection: @retroactive ServerTransport {}
extension Router: ServerTransport {}
extension RouterGroup: ServerTransport {}
extension RouteCollection: ServerTransport {}
#endif
#endif
41 changes: 10 additions & 31 deletions Tests/OpenAPIHummingbirdTests/OpenAPITransportTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,9 @@ final class HBOpenAPITransportTests: XCTestCase {
scheme: "http",
authority: "localhost",
path: "/hello/Maria?greeting=Howdy",
headerFields: [
.xMumble: "mumble",
.connection: "keep-alive",
.contentLength: "4",
]
)
let expectedRequestMetadata = ServerRequestMetadata(
pathParameters: ["name": "Maria"]
headerFields: [.xMumble: "mumble", .connection: "keep-alive", .contentLength: "4"]
)
let expectedRequestMetadata = ServerRequestMetadata(pathParameters: ["name": "Maria"])
let (request, body) = try hbRequest.makeOpenAPIRequest(context: context)
let collectedBody: [UInt8]
if let body = body {
Expand All @@ -71,9 +65,7 @@ final class HBOpenAPITransportTests: XCTestCase {
try await client.execute(
uri: "/hello/Maria?greeting=Howdy",
method: .post,
headers: [
.xMumble: "mumble",
],
headers: [.xMumble: "mumble"],
body: ByteBuffer(string: "👋")
) { hbResponse in
// Check the HBResponse (created from the Response) is what meets expectations.
Expand All @@ -87,7 +79,7 @@ final class HBOpenAPITransportTests: XCTestCase {

func test_largeBody() async throws {
let router = Router()
let bytes = (0..<1_000_000).map { _ in UInt8.random(in: 0...255)}
let bytes = (0..<1_000_000).map { _ in UInt8.random(in: 0...255) }
let byteBuffer = ByteBuffer(bytes: bytes)

router.post("/hello/:name") { hbRequest, context -> Response in
Expand All @@ -97,14 +89,9 @@ final class HBOpenAPITransportTests: XCTestCase {
scheme: "http",
authority: "localhost",
path: "/hello/Maria?greeting=Howdy",
headerFields: [
.connection: "keep-alive",
.contentLength: "1000000",
]
)
let expectedRequestMetadata = ServerRequestMetadata(
pathParameters: ["name": "Maria"]
headerFields: [.connection: "keep-alive", .contentLength: "1000000"]
)
let expectedRequestMetadata = ServerRequestMetadata(pathParameters: ["name": "Maria"])
let (request, body) = try hbRequest.makeOpenAPIRequest(context: context)
XCTAssertEqual(request, expectedRequest)
XCTAssertEqual(context.makeOpenAPIRequestMetadata(), expectedRequestMetadata)
Expand All @@ -116,19 +103,12 @@ final class HBOpenAPITransportTests: XCTestCase {

let app = Application(
router: router,
server: .http1(
additionalChannelHandlers: [
BreakupHTTPBodyChannelHandler()
]
)
server: .http1(additionalChannelHandlers: [BreakupHTTPBodyChannelHandler()])
)

try await app.test(.live) { client in
try await client.execute(
uri: "/hello/Maria?greeting=Howdy",
method: .post,
body: byteBuffer
) { hbResponse in
try await client.execute(uri: "/hello/Maria?greeting=Howdy", method: .post, body: byteBuffer) {
hbResponse in
// Check the Response (created from the Response) is what meets expectations.
XCTAssertEqual(hbResponse.status, .ok)
XCTAssertEqual(byteBuffer, hbResponse.body)
Expand All @@ -147,8 +127,7 @@ class BreakupHTTPBodyChannelHandler: ChannelInboundHandler, RemovableChannelHand
let part = unwrapInboundIn(data)

switch part {
case .head, .end:
context.fireChannelRead(data)
case .head, .end: context.fireChannelRead(data)
case .body(var buffer):
while buffer.readableBytes > 0 {
let size = min(32768, buffer.readableBytes)
Expand Down
23 changes: 0 additions & 23 deletions docker/Dockerfile

This file was deleted.

Loading

0 comments on commit 4e86cce

Please sign in to comment.