Skip to content

Commit

Permalink
Adopt swift-format, update to SendGridKit v3 and Swift Testing
Browse files Browse the repository at this point in the history
  • Loading branch information
fpseverino committed Oct 5, 2024
1 parent 66be154 commit 9f6f453
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 62 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ on:
jobs:
unit-tests:
uses: vapor/ci/.github/workflows/run-unit-tests.yml@main
with:
with_linting: true
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
3 changes: 2 additions & 1 deletion .spi.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
version: 1
builder:
configs:
- documentation_targets: [SendGrid]
- documentation_targets: [SendGrid]
swift_version: 6.0
21 changes: 9 additions & 12 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// swift-tools-version:5.10
// swift-tools-version:6.0
import PackageDescription

let package = Package(
name: "sendgrid",
platforms: [
.macOS(.v13)
.macOS(.v14)
],
products: [
.library(name: "SendGrid", targets: ["SendGrid"])
],
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"),
.package(url: "https://github.com/vapor-community/sendgrid-kit.git", from: "2.0.0"),
.package(url: "https://github.com/vapor-community/sendgrid-kit.git", from: "3.0.0-rc.1"),
],
targets: [
.target(
Expand All @@ -29,15 +29,12 @@ let package = Package(
.product(name: "XCTVapor", package: "vapor"),
],
swiftSettings: swiftSettings
)
),
]
)

var swiftSettings: [SwiftSetting] { [
.enableUpcomingFeature("ExistentialAny"),
.enableUpcomingFeature("ConciseMagicFile"),
.enableUpcomingFeature("ForwardTrailingClosures"),
.enableUpcomingFeature("DisableOutwardActorInference"),
.enableUpcomingFeature("StrictConcurrency"),
.enableExperimentalFeature("StrictConcurrency=complete"),
] }
var swiftSettings: [SwiftSetting] {
[
.enableUpcomingFeature("ExistentialAny")
]
}
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
<img src="https://img.shields.io/codecov/c/github/vapor-community/sendgrid?style=plastic&logo=codecov&label=codecov">
</a>
<a href="https://swift.org">
<img src="https://design.vapor.codes/images/swift510up.svg" alt="Swift 5.10+">
<img src="https://design.vapor.codes/images/swift60up.svg" alt="Swift 6.0+">
</a>
</div>
<br>

📧 SendGrid library for the Vapor web framework.
📧 SendGrid library for the Vapor web framework, based on [SendGridKit](https://github.com/vapor-community/sendgrid-kit).

Send simple emails, or leverage the full capabilities of SendGrid's V3 API.
Send simple emails, or leverage the full capabilities of [SendGrid's V3 API](https://www.twilio.com/docs/sendgrid/api-reference/mail-send/mail-send).

### Getting Started

Expand All @@ -36,12 +36,12 @@ and add it to your target's dependencies:
.product(name: "SendGrid", package: "sendgrid")
```

## Overview

> [!NOTE]
> Make sure that the `SENDGRID_API_KEY` variable is set in your environment.
This can be set in the Xcode scheme, or specified in your `docker-compose.yml`, or even provided as part of a `swift run` command.

## Overview

### Using the API

You can use all of the available parameters here to build your `SendGridEmail`.
Expand All @@ -65,6 +65,6 @@ Simply ensure you catch errors thrown like any other throwing function.
do {
try await req.sendgrid.client.send(email)
} catch let error as SendGridError {
req.logger.error("\(error)")
req.logger.error("\(error.errors)")
}
```
16 changes: 8 additions & 8 deletions Sources/SendGrid/Application+SendGrid.swift
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import Vapor
import SendGridKit
import NIOConcurrencyHelpers
import SendGridKit
import Vapor

public extension Application {
var sendgrid: Sendgrid {
extension Application {
public var sendgrid: Sendgrid {
.init(application: self)
}

struct Sendgrid: Sendable {
public struct Sendgrid: Sendable {
private final class Storage: Sendable {
private struct SendableBox: Sendable {
var client: SendGridClient
}

private let sendableBox: NIOLockedValueBox<SendableBox>

var client: SendGridClient {
get {
self.sendableBox.withLockedValue { box in
Expand All @@ -27,7 +27,7 @@ public extension Application {
}
}
}

init(httpClient: HTTPClient, apiKey: String) {
let box = SendableBox(client: .init(httpClient: httpClient, apiKey: apiKey))
self.sendableBox = .init(box)
Expand Down
2 changes: 1 addition & 1 deletion Sources/SendGrid/Request+SendGrid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ extension Request {
public var sendgrid: Application.Sendgrid {
.init(application: self.application)
}
}
}
4 changes: 2 additions & 2 deletions Sources/SendGrid/SendGrid.docc/SendGrid.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ``SendGrid``

📧 SendGrid library for the Vapor web framework.
📧 SendGrid library for the Vapor web framework, based on SendGridKit.

## Overview

Expand Down Expand Up @@ -29,6 +29,6 @@ Simply ensure you catch errors thrown like any other throwing function.
do {
try await req.sendgrid.client.send(email)
} catch let error as SendGridError {
req.logger.error("\(error)")
req.logger.error("\(error.errors)")
}
```
10 changes: 10 additions & 0 deletions Tests/SendGridTests/Helpers/isLoggingConfigured.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Vapor

let isLoggingConfigured: Bool = {
LoggingSystem.bootstrap { label in
var handler = StreamLogHandler.standardOutput(label: label)
handler.logLevel = .debug
return handler
}
return true
}()
9 changes: 9 additions & 0 deletions Tests/SendGridTests/Helpers/withApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Testing
import Vapor

func withApp(_ body: (Application) async throws -> Void) async throws {
let app = try await Application.make(.testing)
try #require(isLoggingConfigured == true)
try await body(app)
try await app.asyncShutdown()
}
63 changes: 31 additions & 32 deletions Tests/SendGridTests/SendGridTests.swift
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
import XCTVapor
import SendGrid
import Testing
import XCTVapor

class SendGridTests: XCTestCase {
var app: Application!

override func setUp() async throws {
self.app = try await Application.make(.testing)
}

override func tearDown() async throws {
try await app.asyncShutdown()
}

func testApplication() async throws {
// TODO: Replace from addresses and to addresses
let email = SendGridEmail(
personalizations: [Personalization(to: ["TO-ADDRESS"])],
from: "FROM-ADDRESS",
subject: "Test Email",
content: ["This email was sent using SendGridKit!"]
)

do {
try await app.sendgrid.client.send(email: email)
} catch {}
}

func testRequest() async throws {
app.get("test") { req async throws -> Response in
struct SendGridTests {
@Test func application() async throws {
try await withApp { app in
// TODO: Replace from addresses and to addresses
let email = SendGridEmail(
personalizations: [Personalization(to: ["TO-ADDRESS"])],
from: "FROM-ADDRESS",
subject: "Test Email",
content: ["This email was sent using SendGridKit!"]
)
try await req.sendgrid.client.send(email: email)
return Response(status: .ok)

try await withKnownIssue {
try await app.sendgrid.client.send(email: email)
} when: {
// TODO: Replace with `false` when you have a valid API key
true
}
}
}

@Test func request() async throws {
try await withApp { app in
app.get("test") { req async throws -> Response in
// TODO: Replace from addresses and to addresses
let email = SendGridEmail(
personalizations: [Personalization(to: ["TO-ADDRESS"])],
from: "FROM-ADDRESS",
subject: "Test Email",
content: ["This email was sent using SendGridKit!"]
)
try await req.sendgrid.client.send(email: email)
return Response(status: .ok)
}

try await app.test(.GET, "test") { res async throws in
XCTAssertEqual(res.status, .internalServerError)
try await app.test(.GET, "test") { res async throws in
// TODO: Replace with `.ok` when you have a valid API key
#expect(res.status == .internalServerError)
}
}
}
}

0 comments on commit 9f6f453

Please sign in to comment.