Skip to content

Commit

Permalink
Strict Concurrency Support (#10)
Browse files Browse the repository at this point in the history
* Declare Sendable conformances

* Enable strict concurrency checking

* Address Sendable warnings

* Fix warning

* Upgrade AWS SDK

* Replace use of ISO8601DateFormatter

* Replace SwiftLint plugin with Danger Swift

* SwiftLint fixes

* Remove macOS  directive

* Update toolchain

* Replace @retroactive with fully qualified names
  • Loading branch information
mgacy authored Oct 22, 2024
1 parent e0a4d3b commit e13c1d6
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 135 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/danger.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Run Danger
on:
workflow_dispatch:
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review

jobs:
build:
if: github.event.pull_request.draft == false
name: Run Danger
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
steps:
- name: Git checkout
uses: actions/checkout@v4
- name: Danger
uses: 417-72KI/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
15 changes: 15 additions & 0 deletions Dangerfile.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Danger

extension String: Error {}

let danger = Danger()

if danger.github.pullRequest.body == nil {
danger.fail("Please add a description to this Pull Request")
}

SwiftLint
.lint(
.all(directory: nil),
configFile: ".swiftlint.yml"
)
111 changes: 6 additions & 105 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,71 +5,26 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/awslabs/aws-crt-swift",
"state" : {
"revision" : "fd1756b6e5c9fd1a906edfb743f7cb64c2c98639",
"version" : "0.17.0"
"revision" : "7b42e0343f28b3451aab20840dc670abd12790bd",
"version" : "0.36.0"
}
},
{
"identity" : "aws-sdk-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/awslabs/aws-sdk-swift",
"state" : {
"revision" : "3d2cfde16273c8fabd02416647d88e2824bded90",
"version" : "0.32.0"
}
},
{
"identity" : "collectionconcurrencykit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git",
"state" : {
"revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95",
"version" : "0.2.0"
}
},
{
"identity" : "cryptoswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"state" : {
"revision" : "db51c407d3be4a051484a141bf0bff36c43d3b1e",
"version" : "1.8.0"
"revision" : "57b74dba32d24e52d07953a2ce5f9d3d27cbc975",
"version" : "1.0.24"
}
},
{
"identity" : "smithy-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/smithy-lang/smithy-swift",
"state" : {
"revision" : "ca28bf2c2b44ceb8c60b1e72b08f63aebc9b68b6",
"version" : "0.36.0"
}
},
{
"identity" : "sourcekitten",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/SourceKitten.git",
"state" : {
"revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56",
"version" : "0.34.1"
}
},
{
"identity" : "swift-argument-parser",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"state" : {
"revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531",
"version" : "1.2.3"
}
},
{
"identity" : "swift-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections",
"state" : {
"revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307",
"version" : "1.0.5"
"revision" : "041be5fd2755309fb3132fffc43b12a26c8bf6a8",
"version" : "0.82.0"
}
},
{
Expand All @@ -80,60 +35,6 @@
"revision" : "532d8b529501fb73a2455b179e0bbb6d49b652ed",
"version" : "1.5.3"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
"version" : "509.0.2"
}
},
{
"identity" : "swiftlint",
"kind" : "remoteSourceControl",
"location" : "https://github.com/realm/SwiftLint.git",
"state" : {
"revision" : "f17a4f9dfb6a6afb0408426354e4180daaf49cee",
"version" : "0.54.0"
}
},
{
"identity" : "swiftytexttable",
"kind" : "remoteSourceControl",
"location" : "https://github.com/scottrhoyt/SwiftyTextTable.git",
"state" : {
"revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3",
"version" : "0.9.0"
}
},
{
"identity" : "swxmlhash",
"kind" : "remoteSourceControl",
"location" : "https://github.com/drmohundro/SWXMLHash.git",
"state" : {
"revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f",
"version" : "7.0.2"
}
},
{
"identity" : "xmlcoder",
"kind" : "remoteSourceControl",
"location" : "https://github.com/MaxDesiatov/XMLCoder.git",
"state" : {
"revision" : "80b4a1646399b8e4e0ce80711653476a85bd5e37",
"version" : "0.17.0"
}
},
{
"identity" : "yams",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams.git",
"state" : {
"revision" : "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3",
"version" : "5.0.6"
}
}
],
"version" : 2
Expand Down
15 changes: 6 additions & 9 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version: 5.7
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription
Expand All @@ -12,7 +12,7 @@ let package = Package(
.library(name: "Secrets", targets: ["Secrets"])
],
dependencies: [
.package(url: "https://github.com/awslabs/aws-sdk-swift.git", from: "0.19.0")
.package(url: "https://github.com/awslabs/aws-sdk-swift.git", from: "1.0.0")
],
targets: [
.testTarget(
Expand All @@ -30,7 +30,7 @@ let package = Package(
]
)

let genericTargets: [Target] = [
let regularTargets: [Target] = [
.target(
name: "EmailSender",
dependencies: [
Expand All @@ -51,11 +51,8 @@ let genericTargets: [Target] = [
)
]

#if os(macOS)
package.dependencies.append(.package(url: "https://github.com/realm/SwiftLint.git", exact: "0.54.0"))
for target in genericTargets {
target.plugins = [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")]
for target in regularTargets {
target.swiftSettings = [.enableExperimentalFeature("StrictConcurrency")]
}
#endif

package.targets.append(contentsOf: genericTargets)
package.targets.append(contentsOf: regularTargets)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Swifty helpers for working with the Swift [AWS SDK](https://github.com/awslabs/a

## 📱 Requirements

Swift 5.7 toolchain with Swift Package Manager.
Swift 5.9 toolchain with Swift Package Manager.

## 🖥 Installation

Expand Down
4 changes: 2 additions & 2 deletions Sources/EmailSender/EmailSender.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
// Created by Mathew Gacy on 12/8/23.
//

import AWSSES
@preconcurrency import AWSSES
import Foundation

/// A type that sends emails.
public struct EmailSender {
public struct EmailSender: Sendable {
/// A closure returning a message ID after sending an email.
public var send: @Sendable (Recipients, Sender, Subject, Body) async throws -> MessageID?

Expand Down
6 changes: 3 additions & 3 deletions Sources/Persistence/Persistence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Created by Mathew Gacy on 12/8/23.
//

import AWSDynamoDB
@preconcurrency import AWSDynamoDB
import Foundation

/// Represents the data for an attribute. Each attribute value is described as a name-value pair.
Expand All @@ -15,7 +15,7 @@ import Foundation
public typealias AttributeValue = DynamoDBClientTypes.AttributeValue

/// A type that persists collections of attributes.
public struct Persistence {
public struct Persistence: Sendable {
/// A closure to modify the attributes of persisted values.
///
/// Use this to add additional attributes like a timestamp or to perform validation of all
Expand Down Expand Up @@ -67,7 +67,7 @@ public extension Persistence {
}

/// A type that creates ``Persistence`` instances.
public struct PersistenceFactory {
public struct PersistenceFactory: Sendable {
/// The region where the table is located.
public typealias Region = String

Expand Down
25 changes: 16 additions & 9 deletions Sources/Persistence/TimestampProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,28 @@
import Foundation

/// A class of types providing user-readable representations of dates.
public protocol DateFormatting {
public protocol DateFormatting: Sendable {
/// Returns a string representation of the specified date.
///
/// - Parameter date: The date to be represented.
/// - Returns: A user-readable string representing the date.
func string(from date: Date) -> String
}

extension DateFormatter: DateFormatting {}

extension ISO8601DateFormatter: DateFormatting {}
extension DateFormatter: DateFormatting {
public static let iso8601: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
}

/// A type to provide timestamps.
public struct TimestampProvider {
private let dateProvider: () -> Date
public struct TimestampProvider: Sendable {
private let dateProvider: @Sendable () -> Date
private let formatter: any DateFormatting

/// Creates an instance.
Expand All @@ -31,7 +38,7 @@ public struct TimestampProvider {
/// - dateProvider: A closure returning the current date.
/// - formatter: The date formatter to use to format the current date.
public init(
dateProvider: @escaping () -> Date,
dateProvider: @escaping @Sendable () -> Date,
formatter: DateFormatting
) {
self.dateProvider = dateProvider
Expand All @@ -48,7 +55,7 @@ public extension TimestampProvider {
/// A live implementation.
static var live: Self {
.init(
dateProvider: Date.init,
formatter: ISO8601DateFormatter())
dateProvider: { Date() },
formatter: DateFormatter.iso8601)
}
}
16 changes: 16 additions & 0 deletions Sources/Secrets/SecretValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ protocol SecretValue: Equatable {
var secretString: String? { get }
}

extension AWSSecretsManager.GetSecretValueOutput: Swift.Equatable {
public static func == (lhs: GetSecretValueOutput, rhs: GetSecretValueOutput) -> Bool {
lhs.arn == rhs.arn
&& lhs.name == rhs.name
&& lhs.secretBinary == rhs.secretBinary
&& lhs.secretString == rhs.secretString
}
}
extension GetSecretValueOutput: SecretValue {}

extension AWSSecretsManager.SecretsManagerClientTypes.SecretValueEntry: Swift.Equatable {
public static func == (lhs: SecretsManagerClientTypes.SecretValueEntry, rhs: SecretsManagerClientTypes.SecretValueEntry) -> Bool {
lhs.arn == rhs.arn
&& lhs.name == rhs.name
&& lhs.secretBinary == rhs.secretBinary
&& lhs.secretString == rhs.secretString
}
}
extension SecretsManagerClientTypes.SecretValueEntry: SecretValue {}
2 changes: 1 addition & 1 deletion Sources/Secrets/Secrets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Created by Mathew Gacy on 12/22/23.
//

import AWSSecretsManager
@preconcurrency import AWSSecretsManager
import Foundation

/// A secret stored by AWS Secrets Manager.
Expand Down
4 changes: 2 additions & 2 deletions Tests/PersistenceTests/PersistenceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ final class PersistenceTests: XCTestCase {
}
}

let timeoutInterval: TimeInterval = 0.1
let timeoutInterval: TimeInterval = 0.1

func testPersistence() async throws {
let expected: [String: AttributeValue] = [
Expand All @@ -35,7 +35,7 @@ final class PersistenceTests: XCTestCase {

let timestampProvider = TimestampProvider(
dateProvider: { Date(timeIntervalSince1970: 0) },
formatter: ISO8601DateFormatter())
formatter: DateFormatter.iso8601)

let expectation = expectation(description: "Model persisted")
let sut = Persistence.addingTimestamp(named: "CreatedAt", from: timestampProvider) { actual in
Expand Down
4 changes: 1 addition & 3 deletions Tests/PersistenceTests/TimestampProviderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
// Created by Mathew Gacy on 12/8/23.
//

import Foundation

@testable import Persistence
import Foundation
import XCTest
Expand All @@ -17,7 +15,7 @@ final class TimestampProviderTests: XCTestCase {

let sut = TimestampProvider(
dateProvider: { Date(timeIntervalSince1970: 0) },
formatter: ISO8601DateFormatter())
formatter: DateFormatter.iso8601)
let actual = sut.timestamp()
XCTAssertEqual(actual, expected)
}
Expand Down

0 comments on commit e13c1d6

Please sign in to comment.