From c73112efc0c915acae7a60ac1a24ba9176b163c6 Mon Sep 17 00:00:00 2001 From: Rick Newton-Rogers Date: Mon, 28 Oct 2024 09:51:24 +0000 Subject: [PATCH] Migrate CI to use GitHub Actions. (#213) ### Motivation: To migrate to GitHub actions and centralised infrastructure. ### Modifications: Changes of note: * Adopt swift-format using rules from SwiftNIO. Modified so that it ignores `NoAssignmentInExpressions` in some `XCTAssert` functions. * Remove scripts and docker files which are no longer needed ### Result: Feature parity with old CI. --- .github/workflows/main.yml | 24 +++ .github/workflows/pull_request.yml | 30 +++ .github/workflows/pull_request_label.yml | 18 ++ .github/workflows/scheduled.yml | 24 +++ .licenseignore | 49 +++++ .swift-format | 68 +++++++ CONTRIBUTING.md | 5 + Package.swift | 14 +- Sources/NIOTSHTTPServer/main.swift | 7 +- .../NIOTransportServices/AcceptHandler.swift | 17 +- .../Datagram/NIOTSDatagramBootstrap.swift | 18 +- .../Datagram/NIOTSDatagramChannel.swift | 81 ++++---- .../Datagram/NIOTSDatagramListener.swift | 75 +++++--- .../NIOTSDatagramListenerChannel.swift | 79 ++++---- .../NIOFilterEmptyWritesHandler.swift | 43 ++--- .../NIOTSBootstraps.swift | 2 +- .../NIOTSChannelOptions.swift | 27 ++- .../NIOTSConnectionBootstrap.swift | 52 +++-- .../NIOTSConnectionChannel.swift | 97 +++++----- .../NIOTransportServices/NIOTSErrors.swift | 20 +- .../NIOTransportServices/NIOTSEventLoop.swift | 39 ++-- .../NIOTSEventLoopGroup.swift | 7 +- .../NIOTSListenerBootstrap.swift | 57 ++++-- .../NIOTSListenerChannel.swift | 79 ++++---- .../NIOTSNetworkEvents.swift | 16 +- .../NIOTSSingletons.swift | 25 ++- .../SocketAddress+NWEndpoint.swift | 2 +- .../StateManagedChannel.swift | 20 +- .../StateManagedListenerChannel.swift | 56 +++--- .../StateManagedNWConnectionChannel.swift | 62 ++++-- .../NIOFilterEmptyWritesHandlerTests.swift | 57 +++--- .../NIOTSAsyncBootstrapTests.swift | 91 ++++++--- .../NIOTSBootstrapTests.swift | 180 +++++++++++------- .../NIOTSChannelMetadataTests.swift | 10 +- .../NIOTSChannelOptionsTests.swift | 38 ++-- .../NIOTSConnectionChannelTests.swift | 114 +++++++---- .../NIOTSDatagramConnectionChannelTests.swift | 26 ++- .../NIOTSEndToEndTests.swift | 80 ++++---- .../NIOTSEventLoopTests.swift | 40 ++-- .../NIOTSListenerChannelTests.swift | 28 +-- .../NIOTSSocketOptionTests.swift | 159 ++++++++++------ .../NIOTSSocketOptionsOnChannelTests.swift | 130 ++++++++++--- docker/Dockerfile | 22 --- docker/docker-compose.2204.510.yaml | 19 -- docker/docker-compose.2204.58.yaml | 19 -- docker/docker-compose.2204.59.yaml | 19 -- docker/docker-compose.2204.main.yaml | 19 -- docker/docker-compose.yaml | 41 ---- scripts/check-docs.sh | 26 --- scripts/soundness.sh | 142 -------------- 50 files changed, 1340 insertions(+), 1033 deletions(-) create mode 100644 .github/workflows/main.yml create mode 100644 .github/workflows/pull_request.yml create mode 100644 .github/workflows/pull_request_label.yml create mode 100644 .github/workflows/scheduled.yml create mode 100644 .licenseignore create mode 100644 .swift-format delete mode 100644 docker/Dockerfile delete mode 100644 docker/docker-compose.2204.510.yaml delete mode 100644 docker/docker-compose.2204.58.yaml delete mode 100644 docker/docker-compose.2204.59.yaml delete mode 100644 docker/docker-compose.2204.main.yaml delete mode 100644 docker/docker-compose.yaml delete mode 100755 scripts/check-docs.sh delete mode 100755 scripts/soundness.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..28ffd1c --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,24 @@ +name: Main + +on: + push: + branches: [main] + +jobs: + unit-tests: + name: Unit tests + uses: apple/swift-nio/.github/workflows/unit_tests.yml@main + with: + linux_5_8_enabled: false + 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" + + integration-tests: + name: Integration test + uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main + with: + name: "Integration test" + matrix_linux_command: "apt-get update -yq && apt-get install -yq lsof dnsutils netcat-openbsd net-tools expect curl jq && ./scripts/integration_tests.sh" diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..1335ed2 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,30 @@ +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: "SwiftNIO" + 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" + + cxx-interop: + name: Cxx interop + uses: apple/swift-nio/.github/workflows/cxx_interop.yml@main + + swift-6-language-mode: + name: Swift 6 Language Mode + uses: apple/swift-nio/.github/workflows/swift_6_language_mode.yml@main + if: false # Disabled for now. diff --git a/.github/workflows/pull_request_label.yml b/.github/workflows/pull_request_label.yml new file mode 100644 index 0000000..86f199f --- /dev/null +++ b/.github/workflows/pull_request_label.yml @@ -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 diff --git a/.github/workflows/scheduled.yml b/.github/workflows/scheduled.yml new file mode 100644 index 0000000..831f166 --- /dev/null +++ b/.github/workflows/scheduled.yml @@ -0,0 +1,24 @@ +name: Scheduled + +on: + schedule: + - cron: "0 8,20 * * *" + +jobs: + unit-tests: + name: Unit tests + uses: apple/swift-nio/.github/workflows/unit_tests.yml@main + with: + linux_5_8_enabled: false + 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" + + integration-tests: + name: Integration test + uses: apple/swift-nio/.github/workflows/swift_matrix.yml@main + with: + name: "Integration test" + matrix_linux_command: "apt-get update -yq && apt-get install -yq lsof dnsutils netcat-openbsd net-tools expect curl jq && ./scripts/integration_tests.sh" diff --git a/.licenseignore b/.licenseignore new file mode 100644 index 0000000..27dc3cc --- /dev/null +++ b/.licenseignore @@ -0,0 +1,49 @@ +.gitignore +**/.gitignore +.licenseignore +.gitattributes +.git-blame-ignore-revs +.mailfilter +.mailmap +.spi.yml +.swift-format +.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/* +Sources/CNIOAtomics/src/cpp_magic.h +Sources/CNIOLLHTTP/LICENSE-MIT +Sources/CNIOLLHTTP/c_nio_api.c +Sources/CNIOLLHTTP/c_nio_http.c +Sources/CNIOLLHTTP/c_nio_llhttp.c +Sources/CNIOLLHTTP/include/c_nio_llhttp.h +Sources/CNIOSHA1/c_nio_sha1.c +Sources/CNIOSHA1/include/CNIOSHA1.h +dev/alloc-limits-from-test-output +dev/boxed-existentials.d +dev/git.commit.template +dev/lldb-smoker +dev/make-single-file-spm +dev/malloc-aggregation.d +dev/update-alloc-limits-to-last-completed-ci-build +scripts/nio-diagnose diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..7e8ae73 --- /dev/null +++ b/.swift-format @@ -0,0 +1,68 @@ +{ + "version" : 1, + "indentation" : { + "spaces" : 4 + }, + "tabWidth" : 4, + "fileScopedDeclarationPrivacy" : { + "accessLevel" : "private" + }, + "spacesAroundRangeFormationOperators" : false, + "indentConditionalCompilationBlocks" : false, + "indentSwitchCaseLabels" : false, + "lineBreakAroundMultilineExpressionChainComponents" : false, + "lineBreakBeforeControlFlowKeywords" : false, + "lineBreakBeforeEachArgument" : true, + "lineBreakBeforeEachGenericRequirement" : true, + "lineLength" : 120, + "maximumBlankLines" : 1, + "respectsExistingLineBreaks" : true, + "prioritizeKeepingFunctionOutputTogether" : true, + "noAssignmentInExpressions" : { + "allowedFunctions" : [ + "XCTAssertNoThrow", + "XCTAssertThrowsError" + ] + }, + "rules" : { + "AllPublicDeclarationsHaveDocumentation" : false, + "AlwaysUseLiteralForEmptyCollectionInit" : false, + "AlwaysUseLowerCamelCase" : false, + "AmbiguousTrailingClosureOverload" : true, + "BeginDocumentationCommentWithOneLineSummary" : false, + "DoNotUseSemicolons" : true, + "DontRepeatTypeInStaticProperties" : true, + "FileScopedDeclarationPrivacy" : true, + "FullyIndirectEnum" : true, + "GroupNumericLiterals" : true, + "IdentifiersMustBeASCII" : true, + "NeverForceUnwrap" : false, + "NeverUseForceTry" : false, + "NeverUseImplicitlyUnwrappedOptionals" : false, + "NoAccessLevelOnExtensionDeclaration" : true, + "NoAssignmentInExpressions" : true, + "NoBlockComments" : true, + "NoCasesWithOnlyFallthrough" : true, + "NoEmptyTrailingClosureParentheses" : true, + "NoLabelsInCasePatterns" : true, + "NoLeadingUnderscores" : false, + "NoParensAroundConditions" : true, + "NoVoidReturnOnFunctionSignature" : true, + "OmitExplicitReturns" : true, + "OneCasePerLine" : true, + "OneVariableDeclarationPerLine" : true, + "OnlyOneTrailingClosureArgument" : true, + "OrderedImports" : true, + "ReplaceForEachWithForLoop" : true, + "ReturnVoidInsteadOfEmptyTuple" : true, + "UseEarlyExits" : false, + "UseExplicitNilCheckInConditions" : false, + "UseLetInEveryBoundCaseVariable" : false, + "UseShorthandTypeNames" : true, + "UseSingleLinePropertyGetter" : false, + "UseSynthesizedInitializer" : false, + "UseTripleSlashForDocumentationComments" : true, + "UseWhereClausesInForLoops" : false, + "ValidateDocumentationComments" : false + } +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 40ebb08..1d78896 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,6 +59,11 @@ We require that your commit messages match our template. The easiest way to do t git config commit.template dev/git.commit.template +### Run CI checks locally + +You can run the Github Actions workflows locally using [act](https://github.com/nektos/act). For detailed steps on how to do this please see [https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally](https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally). + + ## How to contribute your work Please open a pull request at https://github.com/apple/swift-nio-transport-services. Make sure the CI passes, and then wait for code review. diff --git a/Package.swift b/Package.swift index c2d0a0e..f203576 100644 --- a/Package.swift +++ b/Package.swift @@ -18,7 +18,7 @@ import PackageDescription let package = Package( name: "swift-nio-transport-services", products: [ - .library(name: "NIOTransportServices", targets: ["NIOTransportServices"]), + .library(name: "NIOTransportServices", targets: ["NIOTransportServices"]) ], dependencies: [ .package(url: "https://github.com/apple/swift-nio.git", from: "2.62.0"), @@ -33,21 +33,24 @@ let package = Package( .product(name: "NIOFoundationCompat", package: "swift-nio"), .product(name: "NIOTLS", package: "swift-nio"), .product(name: "Atomics", package: "swift-atomics"), - ]), + ] + ), .executableTarget( name: "NIOTSHTTPClient", dependencies: [ "NIOTransportServices", .product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOHTTP1", package: "swift-nio"), - ]), + ] + ), .executableTarget( name: "NIOTSHTTPServer", dependencies: [ "NIOTransportServices", .product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOHTTP1", package: "swift-nio"), - ]), + ] + ), .testTarget( name: "NIOTransportServicesTests", dependencies: [ @@ -55,6 +58,7 @@ let package = Package( .product(name: "NIOCore", package: "swift-nio"), .product(name: "NIOEmbedded", package: "swift-nio"), .product(name: "Atomics", package: "swift-atomics"), - ]), + ] + ), ] ) diff --git a/Sources/NIOTSHTTPServer/main.swift b/Sources/NIOTSHTTPServer/main.swift index 93f8d02..81793ff 100644 --- a/Sources/NIOTSHTTPServer/main.swift +++ b/Sources/NIOTSHTTPServer/main.swift @@ -41,9 +41,10 @@ if #available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *) { let group = NIOTSEventLoopGroup() let channel = try! NIOTSListenerBootstrap(group: group) .childChannelInitializer { channel in - channel.pipeline.configureHTTPServerPipeline(withPipeliningAssistance: true, withErrorHandling: true).flatMap { - channel.pipeline.addHandler(HTTP1ServerHandler()) - } + channel.pipeline.configureHTTPServerPipeline(withPipeliningAssistance: true, withErrorHandling: true) + .flatMap { + channel.pipeline.addHandler(HTTP1ServerHandler()) + } }.bind(host: "127.0.0.1", port: 8888).wait() print("Server listening on \(channel.localAddress!)") diff --git a/Sources/NIOTransportServices/AcceptHandler.swift b/Sources/NIOTransportServices/AcceptHandler.swift index 8ca75e7..9ee19ef 100644 --- a/Sources/NIOTransportServices/AcceptHandler.swift +++ b/Sources/NIOTransportServices/AcceptHandler.swift @@ -23,8 +23,10 @@ internal class AcceptHandler: ChannelInboundHandler { private let childChannelInitializer: ((Channel) -> EventLoopFuture)? private let childChannelOptions: ChannelOptions.Storage - init(childChannelInitializer: ((Channel) -> EventLoopFuture)?, - childChannelOptions: ChannelOptions.Storage) { + init( + childChannelInitializer: ((Channel) -> EventLoopFuture)?, + childChannelOptions: ChannelOptions.Storage + ) { self.childChannelInitializer = childChannelInitializer self.childChannelOptions = childChannelOptions } @@ -35,10 +37,9 @@ internal class AcceptHandler: ChannelInboundHandler { let ctxEventLoop = context.eventLoop let childInitializer = self.childChannelInitializer ?? { _ in childLoop.makeSucceededFuture(()) } - @inline(__always) func setupChildChannel() -> EventLoopFuture { - return self.childChannelOptions.applyAllChannelOptions(to: newChannel).flatMap { () -> EventLoopFuture in + self.childChannelOptions.applyAllChannelOptions(to: newChannel).flatMap { () -> EventLoopFuture in childLoop.assertInEventLoop() return childInitializer(newChannel) } @@ -66,9 +67,11 @@ internal class AcceptHandler: ChannelInboundHandler { if childLoop === ctxEventLoop { fireThroughPipeline(setupChildChannel()) } else { - fireThroughPipeline(childLoop.flatSubmit { - return setupChildChannel() - }.hop(to: ctxEventLoop)) + fireThroughPipeline( + childLoop.flatSubmit { + setupChildChannel() + }.hop(to: ctxEventLoop) + ) } } } diff --git a/Sources/NIOTransportServices/Datagram/NIOTSDatagramBootstrap.swift b/Sources/NIOTransportServices/Datagram/NIOTSDatagramBootstrap.swift index 514b611..47b4789 100644 --- a/Sources/NIOTransportServices/Datagram/NIOTSDatagramBootstrap.swift +++ b/Sources/NIOTransportServices/Datagram/NIOTSDatagramBootstrap.swift @@ -69,7 +69,7 @@ public final class NIOTSDatagramBootstrap { /// - parameters: /// - group: The `NIOTSEventLoopGroup` to use. public convenience init(group: NIOTSEventLoopGroup) { - self.init(group: group as EventLoopGroup) + self.init(group: group as EventLoopGroup) } /// Initialize the connected `NIOTSDatagramConnectionChannel` with `initializer`. The most common task in initializer is to add @@ -151,7 +151,7 @@ public final class NIOTSDatagramBootstrap { /// - address: The address to connect to. /// - returns: An `EventLoopFuture` to deliver the `Channel` when connected. public func connect(to address: SocketAddress) -> EventLoopFuture { - return self.connect0 { channel, promise in + self.connect0 { channel, promise in channel.connect(to: address, promise: promise) } } @@ -172,7 +172,7 @@ public final class NIOTSDatagramBootstrap { /// Specify the `endpoint` to connect to for the UDP `Channel` that will be established. public func connect(endpoint: NWEndpoint) -> EventLoopFuture { - return self.connect0 { channel, promise in + self.connect0 { channel, promise in channel.triggerUserOutboundEvent( NIOTSNetworkEvents.ConnectToNWEndpoint(endpoint: endpoint), promise: promise @@ -181,15 +181,17 @@ public final class NIOTSDatagramBootstrap { } private func connect0(_ binder: @escaping (Channel, EventLoopPromise) -> Void) -> EventLoopFuture { - let conn: Channel = NIOTSDatagramChannel(eventLoop: self.group.next() as! NIOTSEventLoop, - qos: self.qos, - udpOptions: self.udpOptions, - tlsOptions: self.tlsOptions) + let conn: Channel = NIOTSDatagramChannel( + eventLoop: self.group.next() as! NIOTSEventLoop, + qos: self.qos, + udpOptions: self.udpOptions, + tlsOptions: self.tlsOptions + ) let initializer = self.channelInitializer ?? { _ in conn.eventLoop.makeSucceededFuture(()) } let channelOptions = self.channelOptions return conn.eventLoop.submit { - return channelOptions.applyAllChannelOptions(to: conn).flatMap { + channelOptions.applyAllChannelOptions(to: conn).flatMap { initializer(conn) }.flatMap { conn.eventLoop.assertInEventLoop() diff --git a/Sources/NIOTransportServices/Datagram/NIOTSDatagramChannel.swift b/Sources/NIOTransportServices/Datagram/NIOTSDatagramChannel.swift index cfc98ad..28c9783 100644 --- a/Sources/NIOTransportServices/Datagram/NIOTSDatagramChannel.swift +++ b/Sources/NIOTransportServices/Datagram/NIOTSDatagramChannel.swift @@ -29,15 +29,15 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel { enum UDPSubstate: NWConnectionSubstate { case open, closed - + init() { self = .open } - + static func closeInput(state: inout ChannelState) throws { throw NIOTSErrors.InvalidChannelStateTransition() } - + static func closeOutput(state: inout ChannelState) throws { throw NIOTSErrors.InvalidChannelStateTransition() } @@ -45,13 +45,13 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel { /// The kinds of channel activation this channel supports internal let supportedActivationType: ActivationType = .connect - + /// The `ByteBufferAllocator` for this `Channel`. public let allocator = ByteBufferAllocator() /// An `EventLoopFuture` that will complete when this channel is finally closed. public var closeFuture: EventLoopFuture { - return self.closePromise.futureResult + self.closePromise.futureResult } /// The parent `Channel` for this one, if any. @@ -60,7 +60,9 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel { /// The `EventLoop` this `Channel` belongs to. internal let tsEventLoop: NIOTSEventLoop - private(set) var _pipeline: ChannelPipeline! = nil // this is really a constant (set in .init) but needs `self` to be constructed and therefore a `var`. Do not change as this needs to accessed from arbitrary threads. + // This is really a constant (set in .init) but needs `self` to be constructed and therefore a `var`. + // *Do not change* as this needs to accessed from arbitrary threads. + private(set) var _pipeline: ChannelPipeline! = nil internal let closePromise: EventLoopPromise @@ -121,8 +123,8 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel { internal var addressCache: AddressCache { get { - return self._addressCacheLock.withLock { - return self._addressCache + self._addressCacheLock.withLock { + self._addressCache } } set { @@ -137,11 +139,11 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel { internal var allowLocalEndpointReuse = false internal var multipathServiceType: NWParameters.MultipathServiceType = .disabled - + var parameters: NWParameters { NWParameters(dtls: self.tlsOptions, udp: self.udpOptions) } - + var _inboundStreamOpen: Bool { switch self.state { case .active(.open): @@ -151,11 +153,12 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel { } } - func setChannelSpecificOption0