diff --git a/.github/workflows/deploy-all-lambdas.yml b/.github/workflows/deploy-all-lambdas.yml index 4b556175..46dbad05 100644 --- a/.github/workflows/deploy-all-lambdas.yml +++ b/.github/workflows/deploy-all-lambdas.yml @@ -8,7 +8,7 @@ on: jobs: deploy-lambdas: runs-on: ubuntu-latest - container: swift:5.8-amazonlinux2 + container: swift:5.9-amazonlinux2 env: AWS_DEFAULT_REGION: eu-west-1 AWS_ACCESS_KEY_ID: ${{ secrets.DEPLOYER_ACCESS_KEY_ID }} diff --git a/Dockerfile b/Dockerfile index f0bf1c85..954715a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # ================================ # Build image # ================================ -FROM swift:5.8-jammy as build +FROM swift:5.9-jammy as build # Install updates RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ diff --git a/Lambdas/GHOAuth/Models/GHOAuthPayload.swift b/Lambdas/GHOAuth/Models/GHOAuthPayload.swift index 2cb70828..de08f637 100644 --- a/Lambdas/GHOAuth/Models/GHOAuthPayload.swift +++ b/Lambdas/GHOAuth/Models/GHOAuthPayload.swift @@ -3,11 +3,12 @@ import JWTKit /// This Payload will get sent along with the OAuth redirect to the GitHub OAuth page, /// specifically inside the `state` query parameter. -/// This is used to verify the user's identity when they come back from GitHub -/// and that the request is not forged. public struct GHOAuthPayload: JWTPayload { + /// Used to verify the user's identity when they come back from GitHub. public let discordID: UserSnowflake + /// The interaction token to respond back to user on Discord with and notify of the result. public let interactionToken: String + /// Expiration time of the token. public let expiration: ExpirationClaim public init(discordID: UserSnowflake, interactionToken: String) { @@ -19,4 +20,4 @@ public struct GHOAuthPayload: JWTPayload { public func verify(using signer: JWTSigner) throws { try self.expiration.verifyNotExpired() } -} \ No newline at end of file +} diff --git a/Package.swift b/Package.swift index 027e612b..632b5611 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.8 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -29,16 +29,22 @@ let upcomingFeaturesSwiftSettings: [SwiftSetting] = [ ] let targetsSwiftSettings: [SwiftSetting] = upcomingFeaturesSwiftSettings + [ - /// https://github.com/apple/swift/issues/67214 - .unsafeFlags(["-Xllvm", "-vectorize-slp=false"], .when(platforms: [.linux], configuration: .release)), + /// https://github.com/apple/swift/issues/67214 + .unsafeFlags(["-Xllvm", "-vectorize-slp=false"], .when(platforms: [.linux], configuration: .release)), - /// `minimal` / `targeted` / `complete` - .unsafeFlags(["-strict-concurrency=complete"]), - ] + /// https://github.com/apple/swift/pull/68671 + .unsafeFlags( + ["-Xlinker", "-u", "-Xlinker", "_swift_backtrace_isThunkFunction"], + .when(platforms: [.linux], configuration: .release) + ), + + /// `minimal` / `targeted` / `complete` + .enableExperimentalFeature("StrictConcurrency=complete"), +] let testsSwiftSettings: [SwiftSetting] = upcomingFeaturesSwiftSettings + [ /// `minimal` / `targeted` / `complete` - .unsafeFlags(["-strict-concurrency=targeted"]) + .enableExperimentalFeature("StrictConcurrency=targeted"), ] extension PackageDescription.Target { @@ -74,7 +80,6 @@ let package = Package( .package(url: "https://github.com/apple/swift-nio.git", from: "2.57.0"), .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.9.0"), .package(url: "https://github.com/apple/swift-crypto.git", from: "2.0.0"), - .package(url: "https://github.com/swift-server/swift-backtrace.git", from: "1.3.1"), .package(url: "https://github.com/apple/swift-collections.git", from: "1.0.0"), .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.0"), .package(url: "https://github.com/apple/swift-atomics.git", from: "1.1.0"), @@ -116,7 +121,6 @@ let package = Package( .executableTarget( name: "Penny", dependencies: [ - .product(name: "Backtrace", package: "swift-backtrace"), .product(name: "DiscordBM", package: "DiscordBM"), .product(name: "DiscordLogger", package: "DiscordLogger"), .product(name: "AsyncHTTPClient", package: "async-http-client"), @@ -254,11 +258,24 @@ let package = Package( name: "Fake", dependencies: [ .product(name: "SotoDynamoDB", package: "soto"), + .product(name: "SotoS3", package: "soto"), .product(name: "SotoCore", package: "soto-core"), .product(name: "DiscordBM", package: "DiscordBM"), + .product(name: "LeafKit", package: "leaf-kit"), + .product(name: "Markdown", package: "swift-markdown"), + .product(name: "SwiftSemver", package: "swift-semver"), + .product(name: "DiscordLogger", package: "DiscordLogger"), + .product(name: "JWTKit", package: "jwt-kit"), + .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), + .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), .product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"), - .target(name: "GHHooksLambda"), + .target(name: "GitHubAPI"), + .target(name: "LambdasShared"), + .target(name: "Shared"), + .target(name: "Rendering"), + .target(name: "Models"), .target(name: "Penny"), + .target(name: "GHHooksLambda"), ], path: "./Tests/Fake", swiftSettings: testsSwiftSettings @@ -267,7 +284,20 @@ let package = Package( name: "PennyTests", dependencies: [ .product(name: "SotoDynamoDB", package: "soto"), + .product(name: "SotoS3", package: "soto"), .product(name: "SotoCore", package: "soto-core"), + .product(name: "LeafKit", package: "leaf-kit"), + .product(name: "Markdown", package: "swift-markdown"), + .product(name: "SwiftSemver", package: "swift-semver"), + .product(name: "DiscordLogger", package: "DiscordLogger"), + .product(name: "JWTKit", package: "jwt-kit"), + .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"), + .product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"), + .target(name: "GitHubAPI"), + .target(name: "LambdasShared"), + .target(name: "Shared"), + .target(name: "Rendering"), + .target(name: "Models"), .target(name: "Penny"), .target(name: "GHHooksLambda"), .target(name: "Fake"), diff --git a/README.md b/README.md index e0b06bb9..9281c73e 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,14 @@ Penny is a Swift bot that works for the [Vapor](https://vapor.codes) community. Deploy Penny CI - Swift 5.8 + Swift 5.9

### Features * [x] Give coins to the members when they're "thanked". * [x] Automatically ping members based on the ping-words they have set up. - * Implemented as `/auto-pings` slash command. + * Implemented as `/auto-pings` slash command. * [x] Respond to certain command-texts with predefined answers. * Implemented as `/faqs` slash command. * [x] Automatically respond to commonly asked questions. diff --git a/Sources/Penny/Constants.swift b/Sources/Penny/Constants.swift index ba39ad60..3b540c03 100644 --- a/Sources/Penny/Constants.swift +++ b/Sources/Penny/Constants.swift @@ -21,6 +21,15 @@ enum Constants { static let ghOAuthClientID = env("GH_OAUTH_CLIENT_ID") static let accountLinkOAuthPrivKey = env("ACCOUNT_LINKING_OAUTH_FLOW_PRIV_KEY") + /// U+1F3FB EMOJI MODIFIER FITZPATRICK TYPE-1-2...TYPE-6 + static var emojiSkins: [String] { + ["", "\u{1f3fb}", "\u{1f3fc}", "\u{1f3fd}", "\u{1f3fe}", "\u{1f3ff}"] + } + /// U+2640 FEMALE SIGN, U+2642 MALE SIGN, U+200D ZWJ, U+FE0F VARIATION SELECTOR 16 + static var emojiGenders: [String] { + ["", "\u{200d}\u{2640}\u{fe0f}", "\u{200d}\u{2642}\u{fe0f}"] + } + enum ServerEmojis { case coin case vapor diff --git a/Sources/Penny/Handlers/CoinFinder.swift b/Sources/Penny/Handlers/CoinFinder.swift index 3af35217..719e2ec3 100644 --- a/Sources/Penny/Handlers/CoinFinder.swift +++ b/Sources/Penny/Handlers/CoinFinder.swift @@ -7,19 +7,17 @@ struct CoinFinder { /// All coin signs must be lowercased. /// Add a test when you add a coin sign. static let coinSigns = [ - "๐Ÿ™Œ", "๐Ÿ™Œ๐Ÿป", "๐Ÿ™Œ๐Ÿผ", "๐Ÿ™Œ๐Ÿฝ", "๐Ÿ™Œ๐Ÿพ", "๐Ÿ™Œ๐Ÿฟ", - "๐Ÿ™", "๐Ÿ™๐Ÿป", "๐Ÿ™๐Ÿผ", "๐Ÿ™๐Ÿฝ", "๐Ÿ™๐Ÿพ", "๐Ÿ™๐Ÿฟ", - "๐Ÿ‘Œ", "๐Ÿ‘Œ๐Ÿป", "๐Ÿ‘Œ๐Ÿผ", "๐Ÿ‘Œ๐Ÿฝ", "๐Ÿ‘Œ๐Ÿพ", "๐Ÿ‘Œ๐Ÿฟ", - "๐Ÿ‘", "๐Ÿ‘๐Ÿป", "๐Ÿ‘๐Ÿผ", "๐Ÿ‘๐Ÿฝ", "๐Ÿ‘๐Ÿพ", "๐Ÿ‘๐Ÿฟ", - "๐Ÿช™", Constants.ServerEmojis.coin.emoji, - "๐Ÿš€", "๐ŸŽ‰", "๐Ÿ’ฏ", + Constants.ServerEmojis.love.emoji, + "๐Ÿš€", "๐ŸŽ‰", "๐Ÿ’ฏ", "๐Ÿช™", "thx", "thanks", "thank you", "thanks a lot", "thanks a bunch", "thanks so much", "thank you a lot", "thank you a bunch", "thank you so much", "thanks for the help", "thanks for your help", "+= 1", "+ 1" ] + + Constants.emojiSkins.map { "๐Ÿ™Œ\($0)" } + + Constants.emojiSkins.map { "๐Ÿ™\($0)" } /// Two or more of these characters, like `++` or `++++++++++++`. static let twoOrMore_coinSigns: [Character] = ["+"] diff --git a/Sources/Penny/Handlers/ReactionHandler/ReactionHandler.swift b/Sources/Penny/Handlers/ReactionHandler/ReactionHandler.swift index 44282718..0d4017f0 100644 --- a/Sources/Penny/Handlers/ReactionHandler/ReactionHandler.swift +++ b/Sources/Penny/Handlers/ReactionHandler/ReactionHandler.swift @@ -6,15 +6,6 @@ import Foundation struct ReactionHandler { enum Configuration { - /// U+1F3FB EMOJI MODIFIER FITZPATRICK TYPE-1-2...TYPE-6 - private static var emojiSkins: [String] { - ["","\u{1f3fb}","\u{1f3fc}","\u{1f3fd}","\u{1f3fe}","\u{1f3ff}"] - } - /// U+2640 FEMALE SIGN, U+2642 MALE SIGN, U+200D ZWJ, U+FE0F VARIATION SELECTOR 16 - private static var emojiGenders: [String] { - ["", "\u{200d}\u{2640}\u{fe0f}", "\u{200d}\u{2642}\u{fe0f}"] - } - static let coinSignEmojis: Set = [ Constants.ServerEmojis.love.name, Constants.ServerEmojis.vapor.name, @@ -24,9 +15,9 @@ struct ReactionHandler { "โค๏ธ", "๐Ÿ’™", "๐Ÿ’œ", "๐Ÿค", "๐ŸคŽ", "๐Ÿ–ค", "๐Ÿ’›", "๐Ÿ’š", "๐Ÿงก", "๐Ÿฉท", "๐Ÿฉถ", "๐Ÿฉต", "๐Ÿ’—", "๐Ÿ’•", "๐Ÿ˜", "๐Ÿ˜ป", "๐ŸŽ‰", "๐Ÿ’ฏ", ] - + emojiSkins.map { "๐Ÿ™Œ\($0)" } - + emojiSkins.map { "๐Ÿ™\($0)" } - + emojiSkins.flatMap { s in emojiGenders.map { g in "๐Ÿ™‡\(s)\(g)" } } + + Constants.emojiSkins.map { "๐Ÿ™Œ\($0)" } + + Constants.emojiSkins.map { "๐Ÿ™\($0)" } + + Constants.emojiSkins.flatMap { s in Constants.emojiGenders.map { g in "๐Ÿ™‡\(s)\(g)" } } } let event: Gateway.MessageReactionAdd diff --git a/Sources/Penny/Penny.swift b/Sources/Penny/Penny.swift index bfbbf08d..814bc67f 100644 --- a/Sources/Penny/Penny.swift +++ b/Sources/Penny/Penny.swift @@ -1,7 +1,6 @@ import NIOPosix import AsyncHTTPClient import SotoS3 -import Backtrace @main struct Penny { @@ -10,8 +9,6 @@ struct Penny { } static func start(mainService: any MainService) async throws { - Backtrace.install() - /// Use `1` instead of `System.coreCount`. /// This is preferred for apps that primarily use structured concurrency. let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) diff --git a/Sources/Penny/ProposalsChecker.swift b/Sources/Penny/ProposalsChecker.swift index 6879d066..66dafc60 100644 --- a/Sources/Penny/ProposalsChecker.swift +++ b/Sources/Penny/ProposalsChecker.swift @@ -420,7 +420,7 @@ struct ReviewLinksFinder: MarkupWalker { } // MARK: - QueuedProposal -struct QueuedProposal: Codable { +struct QueuedProposal: Sendable, Codable { let uuid: UUID let firstKnownStateBeforeQueue: Proposal.Status.State? var updatedAt: Date