Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[iOS Dev UK 23] Making developer tools with Swift

[iOS Dev UK 23] Making developer tools with Swift

Pol Piella Abadia

September 05, 2023
Tweet

More Decks by Pol Piella Abadia

Other Decks in Programming

Transcript

  1. Making developer tools with Swift Pol Piella Abadia Senior iOS

    Developer, BBC iPlayer iOS Dev UK · Aberystwyth, Wales 10:20 Great Hall
  2. # ! /usr/bin/env swift import Foundation let commitMessageFile = CommandLine.arguments[1]

    guard let data = FileManager.default.contents(atPath: commitMessageFile), let commitMessage = String(data: data, encoding: .utf8) else { exit(1) } let gitBranchName = shell("git rev-parse -- abbrev-ref HEAD") .trimmingCharacters(in: .newlines) let regex = try! NSRegularExpression(pattern: #"(\w+-\d+)"#, options: .anchorsMatchLines) let stringRange = NSRange(location: 0, length: gitBranchName.utf16.count) guard let match = regex.firstMatch(in: gitBranchName, range: stringRange) else { exit(0) } let range = match.range(at: 1) guard !NSEqualRanges(range, NSMakeRange(NSNotFound, 0)) else { exit(1) } let ticketNumber = (gitBranchName as NSString) .substring(with: range) .trimmingCharacters(in: .newlines) if !commitMessage.contains(ticketNumber) { do { try "\(commitMessage.trimmingCharacters(in:.newlines))\n\n\(ticketNumber)" .write(toFile: commitMessageFile, atomically: true, encoding: .utf8) } catch { print("Could not write to file \(commitMessageFile)") } }
  3. # ! /usr/bin/env swift import Foundation let commitMessageFile = CommandLine.arguments[1]

    guard let data = FileManager.default.contents(atPath: commitMessageFile), let commitMessage = String(data: data, encoding: .utf8) else { exit(1) } let gitBranchName = shell("git rev-parse -- abbrev-ref HEAD") .trimmingCharacters(in: .newlines) let regex = try! NSRegularExpression(pattern: #"(\w+-\d+)"#, options: .anchorsMatchLines) let stringRange = NSRange(location: 0, length: gitBranchName.utf16.count) guard let match = regex.firstMatch(in: gitBranchName, range: stringRange) else { exit(0) } let range = match.range(at: 1) guard !NSEqualRanges(range, NSMakeRange(NSNotFound, 0)) else { exit(1) } let ticketNumber = (gitBranchName as NSString) .substring(with: range) .trimmingCharacters(in: .newlines) if !commitMessage.contains(ticketNumber) { do { try "\(commitMessage.trimmingCharacters(in:.newlines))\n\n\(ticketNumber)" .write(toFile: commitMessageFile, atomically: true, encoding: .utf8) } catch { print("Could not write to file \(commitMessageFile)") } }
  4. # ! /usr/bin/env swift-sh import Foundation let commitMessageFile = CommandLine.arguments[1]

    guard let data = FileManager.default.contents(atPath: commitMessageFile), let commitMessage = String(data: data, encoding: .utf8) else { exit(1) } let gitBranchName = shell("git rev-parse -- abbrev-ref HEAD") .trimmingCharacters(in: .newlines) let regex = try! NSRegularExpression(pattern: #"(\w+-\d+)"#, options: .anchorsMatchLines) let stringRange = NSRange(location: 0, length: gitBranchName.utf16.count) guard let match = regex.firstMatch(in: gitBranchName, range: stringRange) else { exit(0) } let range = match.range(at: 1) guard !NSEqualRanges(range, NSMakeRange(NSNotFound, 0)) else { exit(1) } let ticketNumber = (gitBranchName as NSString) .substring(with: range) .trimmingCharacters(in: .newlines) if !commitMessage.contains(ticketNumber) { do { try "\(commitMessage.trimmingCharacters(in:.newlines))\n\n\(ticketNumber)" .write(toFile: commitMessageFile, atomically: true, encoding: .utf8) } catch { print("Could not write to file \(commitMessageFile)") } }
  5. # ! /usr/bin/env swift-sh import Foundation import SourceKittenFramework // @jpsim

    ~> 0.34.1 let commitMessageFile = CommandLine.arguments[1] guard let data = FileManager.default.contents(atPath: commitMessageFile), let commitMessage = String(data: data, encoding: .utf8) else { exit(1) } let gitBranchName = shell("git rev-parse -- abbrev-ref HEAD") .trimmingCharacters(in: .newlines) let regex = try! NSRegularExpression(pattern: #"(\w+-\d+)"#, options: .anchorsMatchLines) let stringRange = NSRange(location: 0, length: gitBranchName.utf16.count) guard let match = regex.firstMatch(in: gitBranchName, range: stringRange) else { exit(0) } let range = match.range(at: 1) guard !NSEqualRanges(range, NSMakeRange(NSNotFound, 0)) else { exit(1) } let ticketNumber = (gitBranchName as NSString) .substring(with: range) .trimmingCharacters(in: .newlines) if !commitMessage.contains(ticketNumber) { do { try "\(commitMessage.trimmingCharacters(in:.newlines))\n\n\(ticketNumber)" .write(toFile: commitMessageFile, atomically: true, encoding: .utf8) } catch { print("Could not write to file \(commitMessageFile)") } }
  6. // swift-tools-version: 5.9 import PackageDescription let package = Package( name:

    "GitHookExecutable", dependencies: [ ], targets: [ .executableTarget( name: "GitHookExecutable", dependencies: [ ] ), ] )
  7. // swift-tools-version: 5.9 import PackageDescription let package = Package( name:

    "GitHookExecutable", dependencies: [ .package(url: "https: // github.com/apple/swift-argument-parser.git", exact: "1.2.3") ], targets: [ .executableTarget( name: "GitHookExecutable", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser") ] ), ] )
  8. import ArgumentParser @main struct GitHookExecutable: ParsableCommand { @Argument(help: "The path

    to the commit message file") var commitMessagePath: String func run() throws { let commitMessage = try String(contentsOfFile: commitMessagePath) // . .. } }
  9. // swift-tools-version:5.7 import PackageDescription let package = Package( name: "SwiftLint",

    platforms: [.macOS(.v12)], products: [ .plugin(name: "SwiftLintPlugin", targets: ["SwiftLintPlugin"]) ], dependencies: [ / / .. . ], targets: [ .plugin( name: "SwiftLintPlugin", capability: .buildTool(), dependencies: [ .target(name: "SwiftLintBinary", condition: .when(platforms: [.macOS])), .target(name: "swiftlint", condition: .when(platforms: [.linux])) ] ), .executableTarget( name: "swiftlint", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "CollectionConcurrencyKit", "SwiftLintFramework", "SwiftyTextTable", ] ), .binaryTarget( name: "SwiftLintBinary", url: "https: // github.com/realm/SwiftLint/releases/download/0.52.4/SwiftLintBinary-macos.artifactbundle.zip", checksum: "8a8095e6235a07d00f34a9e500e7568b359f6f66a249f36d12cd846017a8c6f5" ) ] ) https://github.com/realm/SwiftLint/blob/main/Package.swift
  10. // swift-tools-version:5.7 import PackageDescription let package = Package( name: "SwiftLint",

    platforms: [.macOS(.v12)], products: [ .plugin(name: "SwiftLintPlugin", targets: ["SwiftLintPlugin"]) ], dependencies: [ / / .. . ], targets: [ .plugin( name: "SwiftLintPlugin", capability: .buildTool(), dependencies: [ .target(name: "SwiftLintBinary", condition: .when(platforms: [.macOS])), .target(name: "swiftlint", condition: .when(platforms: [.linux])) ] ), .executableTarget( name: "swiftlint", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "CollectionConcurrencyKit", "SwiftLintFramework", "SwiftyTextTable", ] ), .binaryTarget( name: "SwiftLintBinary", url: "https: // github.com/realm/SwiftLint/releases/download/0.52.4/SwiftLintBinary-macos.artifactbundle.zip", checksum: "8a8095e6235a07d00f34a9e500e7568b359f6f66a249f36d12cd846017a8c6f5" ) ] ) https://github.com/realm/SwiftLint/blob/main/Package.swift
  11. // swift-tools-version:5.7 import PackageDescription let package = Package( name: "SwiftLint",

    platforms: [.macOS(.v12)], products: [ .plugin(name: "SwiftLintPlugin", targets: ["SwiftLintPlugin"]) ], dependencies: [ / / .. . ], targets: [ .plugin( name: "SwiftLintPlugin", capability: .buildTool(), dependencies: [ .target(name: "SwiftLintBinary", condition: .when(platforms: [.macOS])), .target(name: "swiftlint", condition: .when(platforms: [.linux])) ] ), .executableTarget( name: "swiftlint", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "CollectionConcurrencyKit", "SwiftLintFramework", "SwiftyTextTable", ] ), .binaryTarget( name: "SwiftLintBinary", url: "https: // github.com/realm/SwiftLint/releases/download/0.52.4/SwiftLintBinary-macos.artifactbundle.zip", checksum: "8a8095e6235a07d00f34a9e500e7568b359f6f66a249f36d12cd846017a8c6f5" ) ] ) https://github.com/realm/SwiftLint/blob/main/Package.swift
  12. // swift-tools-version:5.7 import PackageDescription let package = Package( name: "SwiftLint",

    platforms: [.macOS(.v12)], products: [ .plugin(name: "SwiftLintPlugin", targets: ["SwiftLintPlugin"]) ], dependencies: [ / / .. . ], targets: [ .plugin( name: "SwiftLintPlugin", capability: .buildTool(), dependencies: [ .target(name: "SwiftLintBinary", condition: .when(platforms: [.macOS])), .target(name: "swiftlint", condition: .when(platforms: [.linux])) ] ), .executableTarget( name: "swiftlint", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "CollectionConcurrencyKit", "SwiftLintFramework", "SwiftyTextTable", ] ), .binaryTarget( name: "SwiftLintBinary", url: "https: // github.com/realm/SwiftLint/releases/download/0.52.4/SwiftLintBinary-macos.artifactbundle.zip", checksum: "8a8095e6235a07d00f34a9e500e7568b359f6f66a249f36d12cd846017a8c6f5" ) ] ) https://github.com/realm/SwiftLint/blob/main/Package.swift
  13. // swift-tools-version:5.7 import PackageDescription let package = Package( name: "SwiftLint",

    platforms: [.macOS(.v12)], products: [ .plugin(name: "SwiftLintPlugin", targets: ["SwiftLintPlugin"]) ], dependencies: [ / / .. . ], targets: [ .plugin( name: "SwiftLintPlugin", capability: .buildTool(), dependencies: [ .target(name: "SwiftLintBinary", condition: .when(platforms: [.macOS])), .target(name: "swiftlint", condition: .when(platforms: [.linux])) ] ), .executableTarget( name: "swiftlint", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "CollectionConcurrencyKit", "SwiftLintFramework", "SwiftyTextTable", ] ), .binaryTarget( name: "SwiftLintBinary", url: "https: // github.com/realm/SwiftLint/releases/download/0.52.4/SwiftLintBinary-macos.artifactbundle.zip", checksum: "8a8095e6235a07d00f34a9e500e7568b359f6f66a249f36d12cd846017a8c6f5" ) ] ) https://github.com/realm/SwiftLint/blob/main/Package.swift
  14. import Foundation import PackagePlugin @main struct SwiftLintPlugin: BuildToolPlugin { func

    createBuildCommands(context: PluginContext, target: Target) async throws - > [Command] { guard let sourceTarget = target as? SourceModuleTarget else { return [] } return createBuildCommands( inputFiles: sourceTarget.sourceFiles(withSuffix: "swift").map(\.path), packageDirectory: context.package.directory, workingDirectory: context.pluginWorkDirectory, tool: try context.tool(named: "swiftlint") ) } private func createBuildCommands( inputFiles: [Path], packageDirectory: Path, workingDirectory: Path, tool: PluginContext.Tool ) -> [Command] { // . .. return [ .prebuildCommand( displayName: "SwiftLint", executable: tool.path, arguments: arguments, outputFilesDirectory: outputFilesDirectory ) ] } } https://github.com/realm/SwiftLint/blob/main/Plugins/SwiftLintPlugin/SwiftLintPlugin.swift
  15. import Foundation import PackagePlugin @main struct SwiftLintPlugin: BuildToolPlugin { func

    createBuildCommands(context: PluginContext, target: Target) async throws - > [Command] { guard let sourceTarget = target as? SourceModuleTarget else { return [] } return createBuildCommands( inputFiles: sourceTarget.sourceFiles(withSuffix: "swift").map(\.path), packageDirectory: context.package.directory, workingDirectory: context.pluginWorkDirectory, tool: try context.tool(named: "swiftlint") ) } private func createBuildCommands( inputFiles: [Path], packageDirectory: Path, workingDirectory: Path, tool: PluginContext.Tool ) -> [Command] { // . .. return [ .prebuildCommand( displayName: "SwiftLint", executable: tool.path, arguments: arguments, outputFilesDirectory: outputFilesDirectory ) ] } } https://github.com/realm/SwiftLint/blob/main/Plugins/SwiftLintPlugin/SwiftLintPlugin.swift
  16. import Foundation import PackagePlugin @main struct SwiftLintPlugin: BuildToolPlugin { func

    createBuildCommands(context: PluginContext, target: Target) async throws - > [Command] { guard let sourceTarget = target as? SourceModuleTarget else { return [] } return createBuildCommands( inputFiles: sourceTarget.sourceFiles(withSuffix: "swift").map(\.path), packageDirectory: context.package.directory, workingDirectory: context.pluginWorkDirectory, tool: try context.tool(named: "swiftlint") ) } private func createBuildCommands( inputFiles: [Path], packageDirectory: Path, workingDirectory: Path, tool: PluginContext.Tool ) -> [Command] { // . .. return [ .prebuildCommand( displayName: "SwiftLint", executable: tool.path, arguments: arguments, outputFilesDirectory: outputFilesDirectory ) ] } } https://github.com/realm/SwiftLint/blob/main/Plugins/SwiftLintPlugin/SwiftLintPlugin.swift
  17. import Foundation import PackagePlugin @main struct SwiftLintPlugin: BuildToolPlugin { func

    createBuildCommands(context: PluginContext, target: Target) async throws - > [Command] { guard let sourceTarget = target as? SourceModuleTarget else { return [] } return createBuildCommands( inputFiles: sourceTarget.sourceFiles(withSuffix: "swift").map(\.path), packageDirectory: context.package.directory, workingDirectory: context.pluginWorkDirectory, tool: try context.tool(named: "swiftlint") ) } private func createBuildCommands( inputFiles: [Path], packageDirectory: Path, workingDirectory: Path, tool: PluginContext.Tool ) -> [Command] { // . .. return [ .prebuildCommand( displayName: "SwiftLint", executable: tool.path, arguments: arguments, outputFilesDirectory: outputFilesDirectory ) ] } } https://github.com/realm/SwiftLint/blob/main/Plugins/SwiftLintPlugin/SwiftLintPlugin.swift
  18. // swift-tools-version: 5.9 import PackageDescription let package = Package( name:

    "DemoSwiftPackage", products: [ .library( name: "DemoSwiftPackage", targets: ["DemoSwiftPackage"] ), ], dependencies: [ .package(url: "https: // github.com/realm/SwiftLint.git", exact: "0.52.4") ], targets: [ .target( name: "DemoSwiftPackage", plugins: [ .plugin(name: "SwiftLintPlugin", package: "SwiftLint") ] ) ] )
  19. // swift-tools-version: 5.9 import PackageDescription let package = Package( name:

    "DemoSwiftPackage", products: [ .library( name: "DemoSwiftPackage", targets: ["DemoSwiftPackage"] ), ], dependencies: [ .package(url: "https: // github.com/realm/SwiftLint.git", exact: "0.52.4") ], targets: [ .target( name: "DemoSwiftPackage", plugins: [ .plugin(name: "SwiftLintPlugin", package: "SwiftLint") ] ) ] )
  20. import Foundation import PackagePlugin #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension SwiftLintPlugin:

    XcodeBuildToolPlugin { func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws - > [Command] { let inputFilePaths = target.inputFiles .filter { $0.type == .source && $0.path.extension == "swift" } .map(\.path) return createBuildCommands( inputFiles: inputFilePaths, packageDirectory: context.xcodeProject.directory, workingDirectory: context.pluginWorkDirectory, tool: try context.tool(named: "swiftlint") ) } } #endif https://github.com/realm/SwiftLint/blob/main/Plugins/SwiftLintPlugin/SwiftLintPlugin.swift
  21. import UIKit public protocol Camera { func start() func stop()

    func capture(_ completion: @escaping (UIImage?) -> Void) func rotate() }
  22. import UIKit // Protocol to be matched protocol AutoMockable {}

    public protocol Camera: AutoMockable { func start() func stop() func capture(_ completion: @escaping (UIImage?) -> Void) func rotate() }
  23. // Generated using Sourcery 1.8.2 — https: // github.com/krzysztofzablocki/Sourcery //

    DO NOT EDIT // swiftlint:disable line_length // swiftlint:disable variable_name import Foundation #if os(iOS) || os(tvOS) || os(watchOS) import UIKit #elseif os(OSX) import AppKit #endif class CameraMock: Camera { // MARK: - start var startCallsCount = 0 var startCalled: Bool { return startCallsCount > 0 } var startClosure: (() -> Void)? func start() { startCallsCount += 1 startClosure?() } //
  24. / / swift-tools-version:5.6 import PackageDescription import Foundation let package =

    Package( name: "Sourcery", platforms: [ .macOS(.v12) ], products: [ .plugin(name: "SourceryCommandPlugin", targets: ["SourceryCommandPlugin"]) ], dependencies: [], targets: [ .executableTarget( name: "SourceryExecutable", dependencies: ["SourceryLib"], path: "SourceryExecutable", exclude: [ "Info.plist" ] ), .plugin( name: "SourceryCommandPlugin", capability: .command( intent: .custom( verb: "sourcery-command", description: "Sourcery command plugin for code generation" ), permissions: [ .writeToPackageDirectory(reason: "Need permission to write generated files to package directory") ] ), dependencies: ["SourceryExecutable"] ) ] ) https://github.com/krzysztofzablocki/Sourcery/blob/master/Package.swift
  25. / / swift-tools-version:5.6 import PackageDescription import Foundation let package =

    Package( name: "Sourcery", platforms: [ .macOS(.v12) ], products: [ .plugin(name: "SourceryCommandPlugin", targets: ["SourceryCommandPlugin"]) ], dependencies: [], targets: [ .executableTarget( name: "SourceryExecutable", dependencies: ["SourceryLib"], path: "SourceryExecutable", exclude: [ "Info.plist" ] ), .plugin( name: "SourceryCommandPlugin", capability: .command( intent: .custom( verb: "sourcery-command", description: "Sourcery command plugin for code generation" ), permissions: [ .writeToPackageDirectory(reason: "Need permission to write generated files to package directory") ] ), dependencies: ["SourceryExecutable"] ) ] ) https://github.com/krzysztofzablocki/Sourcery/blob/master/Package.swift
  26. / / swift-tools-version:5.6 import PackageDescription import Foundation let package =

    Package( name: "Sourcery", platforms: [ .macOS(.v12) ], products: [ .plugin(name: "SourceryCommandPlugin", targets: ["SourceryCommandPlugin"]) ], dependencies: [], targets: [ .executableTarget( name: "SourceryExecutable", dependencies: ["SourceryLib"], path: "SourceryExecutable", exclude: [ "Info.plist" ] ), .plugin( name: "SourceryCommandPlugin", capability: .command( intent: .custom( verb: "sourcery-command", description: "Sourcery command plugin for code generation" ), permissions: [ .writeToPackageDirectory(reason: "Need permission to write generated files to package directory") ] ), dependencies: ["SourceryExecutable"] ) ] ) https://github.com/krzysztofzablocki/Sourcery/blob/master/Package.swift
  27. import PackagePlugin import Foundation @main struct SourceryCommandPlugin: CommandPlugin { func

    performCommand(context: PluginContext, arguments: [String]) async throws { / / Run one per target for target in context.package.targets { let configFilePath = target.directory.appending(subpath: ".sourcery.yml").string let sourcery = try context.tool(named: "SourceryExecutable").path.string guard FileManager.default.fileExists(atPath: configFilePath) else { Diagnostics.warning("⚠ Could not find `.sourcery.yml` for target \(target.name)") continue } let sourceryURL = URL(fileURLWithPath: sourcery) let process = Process() process.executableURL = sourceryURL process.arguments = [ " - - config", configFilePath, " - - cacheBasePath", context.pluginWorkDirectory.string ] try process.run() process.waitUntilExit() let gracefulExit = process.terminationReason = = .exit && process.terminationStatus == 0 if !gracefulExit { throw "🛑 The plugin execution failed with reason: \(process.terminationReason.rawValue) and status: \(process.terminationStatus) " } } } } https://github.com/krzysztofzablocki/Sourcery/blob/master/Plugins/SourceryCommandPlugin/SourceryCommandPlugin.swift
  28. // swift-tools-version: 5.9 import PackageDescription let package = Package( name:

    "GitHookExecutable", dependencies: [ .package(url: "https: // github.com/apple/swift-argument-parser.git", exact: "1.2.3") ], targets: [ .executableTarget( name: "GitHookExecutable", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser") ] ), ] )
  29. // swift-tools-version: 5.9 import PackageDescription let package = Package( name:

    "GitHookExecutable", dependencies: [ .package(url: "https: // github.com/apple/swift-argument-parser.git", exact: "1.2.3"), .package(url: "https: // github.com/krzysztofzablocki/Sourcery.git", exact: "2.0.3") ], targets: [ .executableTarget( name: "GitHookExecutable", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser") ] ), ] )
  30. #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension SourceryCommandPlugin: XcodeCommandPlugin { func performCommand(context:

    XcodePluginContext, arguments: [String]) throws { for target in context.xcodeProject.targets { guard let configFilePath = target .inputFiles .filter({ $0.path.lastComponent == ".sourcery.yml" }) .first? .path .string else { Diagnostics.warning("⚠ Could not find `.sourcery.yml` in Xcode's input file list") return } let sourcery = try context.tool(named: "SourceryExecutable").path.string try run(sourcery, withConfig: configFilePath, cacheBasePath: context.pluginWorkDirectory.string) } } } #endif https://github.com/krzysztofzablocki/Sourcery/blob/master/Plugins/SourceryCommandPlugin/SourceryCommandPlugin.swift
  31. import AWSLambdaRuntime import AWSLambdaEvents @main struct UploadToTestFlightWebhook: SimpleLambdaHandler { let

    snakeCaseDecoder: JSONDecoder init() { let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase snakeCaseDecoder = decoder } func handle(_ request: APIGatewayV2Request, context: LambdaContext) async throws -> APIGatewayV2Response { guard let body = request.body, let bodyData = body.data(using: .utf8), let request = try? snakeCaseDecoder.decode(GithubWebhookData.self, from: bodyData) else { return .init(statusCode: .badRequest, body: "Could not parse the request content ... ") } guard request.action == "created", request.comment.body.lowercased() == "upload to testflight" else { return .init(statusCode: .ok, body: "Not handling the event ... ") } // ... } }
  32. #! /bin/bash product=Webhook docker run \ -- rm \ --

    volume "$(pwd)/:/src" \ -- workdir "/src/" \ swift:5.8-amazonlinux2 \ swift build -- product $product -c release -Xswiftc -static-stdlib target=.build/lambda/$product rm -rf "$target" mkdir -p "$target" cp ".build/release/$product" "$target/" cd "$target" ln -s "$product" "bootstrap" zip -- symlinks lambda.zip * https://fabianfett.dev/getting-started-with-swift-aws-lambda-runtime
  33. #! /bin/bash swift package \ -- disable-sandbox archive \ --

    swift-version 5.8 \ -- output-path . \ -- products Webhook
  34. #! /bin/bash swift package \ -- disable-sandbox archive \ --

    swift-version 5.8 \ -- output-path . \ -- products Webhook
  35. service: upload-to-testflight-webhook frameworkVersion: "3" configValidationMode: warn package: artifact: build/Products/Webhook.zip provider:

    name: aws region: eu-west-1 httpApi: payload: "2.0" cors: true runtime: provided.al2 architecture: arm64 functions: webhook: handler: webhook memorySize: 256 description: "[${sls:stage}] Upload" events: - httpApi: path: /upload method: post Serverless framework https://www.serverless.com
  36. name: Deploy the serverless lambda to AWS on: push: branches:

    - main jobs: deploy: runs-on: ubuntu-latest container: image: swift:5.8-amazonlinux2 steps: - uses: actions/checkout@v3 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v2 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: eu-west-2 - name: Install zip run: | yum install -y zip - name: Install awscli run: | yum install -y awscli - name: Archive the lambda run: | ./package.sh Webhook - name: Deploy to AWS run: | aws lambda update-function-code \ - - function-name webhook \ - - zip-file fileb: // .build/lambda/Webhook/Webhook.zip CI/CD workflow https://www.polpiella.dev/automatic-deployment-of-swift-aws-lambdas-on-ci-cd