diff --git a/Package.swift b/Package.swift index 1256d4e..e598772 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.6 +// swift-tools-version:6.0 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // Created by Sam Deane on 04/07/22. diff --git a/Sources/ActionBuilderCore/Compiler.swift b/Sources/ActionBuilderCore/Compiler.swift index 08a3755..36f78cc 100644 --- a/Sources/ActionBuilderCore/Compiler.swift +++ b/Sources/ActionBuilderCore/Compiler.swift @@ -5,72 +5,94 @@ import Foundation -public class Compiler: Identifiable { - public enum XcodeMode { - case xcode(version: String, image: String = "macos-latest") - case toolchain(version: String, branch: String, image: String = "macos-latest") - } - - public let id: ID - let name: String - let short: String - let linux: String - let mac: XcodeMode - - public init(_ id: ID, name: String, short: String, linux: String, mac: XcodeMode) { - self.id = id - self.name = name - self.short = short - self.linux = linux - self.mac = mac - } - - func supportsTesting(on platform: Platform.ID) -> Bool { - // no Xcode version supports watchOS testing - if platform == .watchOS { - return false - } +public final class Compiler: Identifiable, Sendable { + public enum XcodeMode: Sendable { + case xcode(version: String, image: String = "macos-latest") + case toolchain(version: String, branch: String, image: String = "macos-latest") + } + + public let id: ID + let name: String + let short: String + let linux: String + let mac: XcodeMode - // macOS toolchain builds can't support testing on iOS/tvOS as they don't include the simulator - if platform != .macOS, case .toolchain = mac { - return false - } - - return true + public init(_ id: ID, name: String, short: String, linux: String, mac: XcodeMode) { + self.id = id + self.name = name + self.short = short + self.linux = linux + self.mac = mac + } + + func supportsTesting(on platform: Platform.ID) -> Bool { + // no Xcode version supports watchOS testing + if platform == .watchOS { + return false } - - public enum ID: String, Equatable, CaseIterable, Codable { - case swift50 - case swift51 - case swift52 - case swift53 - case swift54 - case swift55 - case swift56 - case swift57 - - case swiftLatest - case swiftNightly - - static let latestRelease = Self.swift57 + + // macOS toolchain builds can't support testing on iOS/tvOS as they don't include the simulator + if platform != .macOS, case .toolchain = mac { + return false } - - public static let compilers: [Compiler] = [ - // See https://github.com/actions/virtual-environments for available Xcode versions. - // See https://swiftly.dev/swift-versions for Xcode/Swift version mapping. - - Compiler(.swift50, name: "Swift 5.0", short: "5.0", linux: "swift:5.0", mac: .xcode(version: "11.2.1", image: "macos-10.15")), - Compiler(.swift51, name: "Swift 5.1", short: "5.1", linux: "swift:5.1", mac: .xcode(version: "11.3.1", image: "macos-10.15")), - Compiler(.swift52, name: "Swift 5.2", short: "5.2", linux: "swift:5.2.3-bionic", mac: .xcode(version: "11.7", image: "macos-11")), - Compiler(.swift53, name: "Swift 5.3", short: "5.3", linux: "swift:5.3.3-bionic", mac: .xcode(version: "12.4", image: "macos-11")), - Compiler(.swift54, name: "Swift 5.4", short: "5.4", linux: "swift:5.4.2-bionic", mac: .xcode(version: "12.5.1", image: "macos-11")), - Compiler(.swift55, name: "Swift 5.5", short: "5.5", linux: "swift:5.5.3-bionic", mac: .xcode(version: "13.0", image: "macos-11")), - Compiler(.swift56, name: "Swift 5.6", short: "5.6", linux: "swift:5.6.2-bionic", mac: .xcode(version: "13.4.1", image: "macos-12")), - // https://download.swift.org/development/xcode/swift-5.7-DEVELOPMENT-SNAPSHOT-2022-06-26-a/swift-5.7-DEVELOPMENT-SNAPSHOT-2022-06-26-a-osx.pkg - Compiler(.swift57, name: "Swift 5.7", short: "5.7", linux: "swiftlang/swift:nightly-5.7-bionic", mac: .toolchain(version: "13.4.1", branch: "swift-5.7-branch", image: "macos-12")), + return true + } + + public enum ID: String, Equatable, CaseIterable, Codable, Sendable { + case swift50 + case swift51 + case swift52 + case swift53 + case swift54 + case swift55 + case swift56 + case swift57 + case swift58 + case swift59 + case swift60 + + case swiftLatest + case swiftNightly + + static let latestRelease = Self.swift60 + } + + public static let compilers: [Compiler] = [ + // See https://github.com/actions/virtual-environments for available Xcode versions. + // See https://swiftly.dev/swift-versions for Xcode/Swift version mapping. + + Compiler( + .swift50, name: "Swift 5.0", short: "5.0", linux: "swift:5.0", + mac: .xcode(version: "11.2.1", image: "macos-10.15")), + Compiler( + .swift51, name: "Swift 5.1", short: "5.1", linux: "swift:5.1", + mac: .xcode(version: "11.3.1", image: "macos-10.15")), + Compiler( + .swift52, name: "Swift 5.2", short: "5.2", linux: "swift:5.2.3-bionic", + mac: .xcode(version: "11.7", image: "macos-11")), + Compiler( + .swift53, name: "Swift 5.3", short: "5.3", linux: "swift:5.3.3-bionic", + mac: .xcode(version: "12.4", image: "macos-11")), + Compiler( + .swift54, name: "Swift 5.4", short: "5.4", linux: "swift:5.4.2-bionic", + mac: .xcode(version: "12.5.1", image: "macos-11")), + Compiler( + .swift55, name: "Swift 5.5", short: "5.5", linux: "swift:5.5.3-bionic", + mac: .xcode(version: "13.0", image: "macos-11")), + Compiler( + .swift56, name: "Swift 5.6", short: "5.6", linux: "swift:5.6.2-bionic", + mac: .xcode(version: "13.4.1", image: "macos-12")), + + // https://download.swift.org/development/xcode/swift-5.7-DEVELOPMENT-SNAPSHOT-2022-06-26-a/swift-5.7-DEVELOPMENT-SNAPSHOT-2022-06-26-a-osx.pkg + Compiler( + .swift57, name: "Swift 5.7", short: "5.7", linux: "swiftlang/swift:nightly-5.7-bionic", + mac: .toolchain(version: "13.4.1", branch: "swift-5.7-branch", image: "macos-12")), - // https://download.swift.org/development/xcode/swift-DEVELOPMENT-SNAPSHOT-2022-03-22-a/swift-DEVELOPMENT-SNAPSHOT-2022-03-22-a-osx.pkg - Compiler(.swiftNightly, name: "Swift Development Nightly", short: "dev", linux: "swiftlang/swift:nightly", mac: .toolchain(version: "13.4.1", branch: "development", image: "macos-12")), - ] + // https://download.swift.org/development/xcode/swift-DEVELOPMENT-SNAPSHOT-2022-03-22-a/swift-DEVELOPMENT-SNAPSHOT-2022-03-22-a-osx.pkg + Compiler( + .swiftNightly, name: "Swift Development Nightly", short: "dev", + linux: "swiftlang/swift:nightly", + mac: .toolchain(version: "13.4.1", branch: "development", image: "macos-12")), + ] } diff --git a/Sources/ActionBuilderCore/Configuration.swift b/Sources/ActionBuilderCore/Configuration.swift index 2ec6a34..aa2611f 100644 --- a/Sources/ActionBuilderCore/Configuration.swift +++ b/Sources/ActionBuilderCore/Configuration.swift @@ -5,15 +5,15 @@ import Foundation -public enum Configuration: String, Codable, CaseIterable { - case debug - case release +public enum Configuration: String, Codable, CaseIterable, Sendable { + case debug + case release - public var name: String { - return rawValue.capitalized - } - - public var xcodeID: String { - return rawValue.capitalized - } + public var name: String { + return rawValue.capitalized + } + + public var xcodeID: String { + return rawValue.capitalized + } } diff --git a/Sources/ActionBuilderCore/Platform.swift b/Sources/ActionBuilderCore/Platform.swift index 7e34866..7757d0e 100644 --- a/Sources/ActionBuilderCore/Platform.swift +++ b/Sources/ActionBuilderCore/Platform.swift @@ -3,352 +3,361 @@ // All code (c) 2020 - present day, Elegant Chaos Limited. // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +public final class Platform: Identifiable, Sendable { + public let id: ID + public let name: String + public let subPlatforms: [Platform] + public let xcodeDestination: String? -public class Platform: Identifiable { - public let id: ID - public let name: String - public let subPlatforms: [Platform] - public let xcodeDestination: String? - - public enum ID: String, Codable, CaseInsensitiveRawRepresentable { - case macOS - case iOS - case tvOS - case watchOS - case catalyst - case linux - case xcode - } - - public static let platforms = [ - Platform(.macOS, name: "macOS"), - Platform(.iOS, name: "iOS", xcodeDestination: "iPhone 11"), - Platform(.tvOS, name: "tvOS", xcodeDestination: "Apple TV"), - Platform(.watchOS, name: "watchOS", xcodeDestination: "Apple Watch Series 5 - 44mm"), - Platform(.linux, name: "Linux"), - ] - - - public init(_ id: ID, name: String, xcodeDestination: String? = nil, subPlatforms: [Platform] = []) { - self.id = id - self.name = name - self.xcodeDestination = xcodeDestination - self.subPlatforms = subPlatforms - } + public enum ID: String, Codable, CaseInsensitiveRawRepresentable, Sendable { + case macOS + case iOS + case tvOS + case watchOS + case catalyst + case linux + case xcode + } - public var label: String { - if xcodeDestination == nil { - return name - } else { - return "\(name)" - } - } - - public func jobName(with compiler: Compiler) -> String { - if !subPlatforms.isEmpty { - switch compiler.mac { - case .xcode(let version, _), .toolchain(let version, _, _): - return "\(name) (\(compiler.name), Xcode \(version))" - } - } + public static let platforms = [ + Platform(.macOS, name: "macOS"), + Platform(.iOS, name: "iOS", xcodeDestination: "iPhone 11"), + Platform(.tvOS, name: "tvOS", xcodeDestination: "Apple TV"), + Platform(.watchOS, name: "watchOS", xcodeDestination: "Apple Watch Series 5 - 44mm"), + Platform(.linux, name: "Linux"), + ] + + public init( + _ id: ID, name: String, xcodeDestination: String? = nil, subPlatforms: [Platform] = [] + ) { + self.id = id + self.name = name + self.xcodeDestination = xcodeDestination + self.subPlatforms = subPlatforms + } - return "\(name) (\(compiler.name))" + public var label: String { + if xcodeDestination == nil { + return name + } else { + return "\(name)" } + } - public func yaml(repo: Repo, compilers: [Compiler], configurations: [Configuration]) -> String { - let package = repo.name - let shouldTest = repo.testMode != .build - - var yaml = "" - var xcodeToolchain: String? = nil - var xcodeVersion: String? = nil - - for compiler in compilers { - var job = - """ - - \(id)-\(compiler.id): - name: \(jobName(with: compiler)) - """ - - containerYAML(&job, compiler, &xcodeToolchain, &xcodeVersion) - commonYAML(&job) - - if let branch = xcodeToolchain, let version = xcodeVersion { - toolchainYAML(&job, branch, version) - } else if let version = xcodeVersion { - xcodeYAML(&job, version) - } else { - - } - - if subPlatforms.isEmpty { - job.append(swiftYAML(configurations: configurations, test: shouldTest, customToolchain: xcodeToolchain != nil, compiler: compiler)) - } else { - job.append(xcodebuildCommonYAML()) - for platform in subPlatforms { - job.append(platform.xcodebuildYAML(configurations: configurations, package: package, test: shouldTest, compiler: compiler)) - } - } - - if repo.uploadLogs { - uploadYAML(&job) - } - - if repo.postSlackNotification { - job.append(notifyYAML(compiler: compiler)) - } - - yaml.append("\(job)\n\n") - } - - return yaml + public func jobName(with compiler: Compiler) -> String { + if !subPlatforms.isEmpty { + switch compiler.mac { + case .xcode(let version, _), .toolchain(let version, _, _): + return "\(name) (\(compiler.name), Xcode \(version))" + } } - fileprivate func swiftYAML(configurations: [Configuration], test: Bool, customToolchain: Bool, compiler: Compiler) -> String { - var yaml = """ - - - name: Swift Version - run: swift --version - """ - - let pathFix = customToolchain ? "export PATH=\"swift-latest:$PATH\"; " : "" - if test { - for config in configurations { - let isRelease = config == .release - var enableDiscovery: [Compiler.ID] = [.swift52, .swift53, .swift54, .swift55] - if !isRelease { enableDiscovery.append(.swift51) } - let buildForTestingFlag = isRelease ? " -Xswiftc -enable-testing" : "" - let discoveryFlag = enableDiscovery.contains(compiler.id) ? " --enable-test-discovery" : "" - yaml.append( - """ - - - name: Test (\(config)) - run: \(pathFix)swift test --configuration \(config)\(buildForTestingFlag)\(discoveryFlag) - """ - ) - } - } else { - for config in configurations { - yaml.append( - """ - - - name: Build (\(config)) - run: \(pathFix)swift build -c \(config) - """ - ) - } + return "\(name) (\(compiler.name))" + } + + public func yaml(repo: Repo, compilers: [Compiler], configurations: [Configuration]) -> String { + let package = repo.name + let shouldTest = repo.testMode != .build + + var yaml = "" + var xcodeToolchain: String? = nil + var xcodeVersion: String? = nil + + for compiler in compilers { + var job = + """ + + \(id)-\(compiler.id): + name: \(jobName(with: compiler)) + """ + + containerYAML(&job, compiler, &xcodeToolchain, &xcodeVersion) + commonYAML(&job) + + if let branch = xcodeToolchain, let version = xcodeVersion { + toolchainYAML(&job, branch, version) + } else if let version = xcodeVersion { + xcodeYAML(&job, version) + } else { + + } + + if subPlatforms.isEmpty { + job.append( + swiftYAML( + configurations: configurations, test: shouldTest, + customToolchain: xcodeToolchain != nil, compiler: compiler)) + } else { + job.append(xcodebuildCommonYAML()) + for platform in subPlatforms { + job.append( + platform.xcodebuildYAML( + configurations: configurations, package: package, test: shouldTest, compiler: compiler + )) } + } - return yaml - } + if repo.uploadLogs { + uploadYAML(&job) + } - fileprivate func xcodebuildCommonYAML() -> String { - var yaml = "" - yaml.append( - """ - - - name: XC Pretty - run: sudo gem install xcpretty-travis-formatter - """ - ) - return yaml + if repo.postSlackNotification { + job.append(notifyYAML(compiler: compiler)) + } + + yaml.append("\(job)\n\n") } - fileprivate func xcodebuildYAML(configurations: [Configuration], package: String, test: Bool, compiler: Compiler) -> String { - var yaml = "" - let destinationName = xcodeDestination ?? "" - let destination = destinationName.isEmpty ? "" : "-destination \"name=\(destinationName)\"" + return yaml + } + + fileprivate func swiftYAML( + configurations: [Configuration], test: Bool, customToolchain: Bool, compiler: Compiler + ) -> String { + var yaml = """ + + - name: Swift Version + run: swift --version + """ + + let pathFix = customToolchain ? "export PATH=\"swift-latest:$PATH\"; " : "" + if test { + for config in configurations { + let isRelease = config == .release + var enableDiscovery: [Compiler.ID] = [.swift52, .swift53, .swift54, .swift55] + if !isRelease { enableDiscovery.append(.swift51) } + let buildForTestingFlag = isRelease ? " -Xswiftc -enable-testing" : "" + let discoveryFlag = enableDiscovery.contains(compiler.id) ? " --enable-test-discovery" : "" yaml.append( - """ - - - name: Detect Workspace & Scheme (\(name)) - run: | - WORKSPACE="\(package).xcworkspace" - if [[ ! -e "$WORKSPACE" ]] - then - WORKSPACE="." - GOTPACKAGE=$(xcodebuild -workspace . -list | (grep \(package)-Package || true)) - if [[ $GOTPACKAGE != "" ]] - then - SCHEME="\(package)-Package" - else - SCHEME="\(package)" - fi - else - SCHEME="\(package)-\(name)" - fi - echo "set -o pipefail; export PATH='swift-latest:$PATH'; WORKSPACE='$WORKSPACE'; SCHEME='$SCHEME'" > setup.sh - """ + """ + + - name: Test (\(config)) + run: \(pathFix)swift test --configuration \(config)\(buildForTestingFlag)\(discoveryFlag) + """ ) - - if test && compiler.supportsTesting(on: id) { - for config in configurations { - let extraArgs = config == .release ? "ENABLE_TESTABILITY=YES" : "" - yaml.append( - """ - - - name: Test (\(name) \(config.name)) - run: | - source "setup.sh" - echo "Testing workspace $WORKSPACE scheme $SCHEME." - xcodebuild test -workspace "$WORKSPACE" -scheme "$SCHEME" \(destination) -configuration \(config.xcodeID) CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO \(extraArgs) | tee logs/xcodebuild-\(id)-test-\(config).log | xcpretty - """ - ) - } - } else { - for config in configurations { - let extraArgs = config == .release ? "ENABLE_TESTABILITY=YES" : "" - yaml.append( - """ - - - name: Build (\(name) \(config)) - run: | - source "setup.sh" - echo "Building workspace $WORKSPACE scheme $SCHEME." - xcodebuild clean build -workspace "$WORKSPACE" -scheme "$SCHEME" \(destination) -configuration \(config.xcodeID) CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO \(extraArgs) | tee logs/xcodebuild-\(id)-build-\(config).log | xcpretty - """ - ) - } - } - + } + } else { + for config in configurations { + yaml.append( + """ - - return yaml + - name: Build (\(config)) + run: \(pathFix)swift build -c \(config) + """ + ) + } } - - fileprivate func uploadYAML(_ yaml: inout String) { + + return yaml + } + + fileprivate func xcodebuildCommonYAML() -> String { + var yaml = "" + yaml.append( + """ + + - name: XC Pretty + run: sudo gem install xcpretty-travis-formatter + """ + ) + return yaml + } + + fileprivate func xcodebuildYAML( + configurations: [Configuration], package: String, test: Bool, compiler: Compiler + ) -> String { + var yaml = "" + let destinationName = xcodeDestination ?? "" + let destination = destinationName.isEmpty ? "" : "-destination \"name=\(destinationName)\"" + yaml.append( + """ + + - name: Detect Workspace & Scheme (\(name)) + run: | + WORKSPACE="\(package).xcworkspace" + if [[ ! -e "$WORKSPACE" ]] + then + WORKSPACE="." + GOTPACKAGE=$(xcodebuild -workspace . -list | (grep \(package)-Package || true)) + if [[ $GOTPACKAGE != "" ]] + then + SCHEME="\(package)-Package" + else + SCHEME="\(package)" + fi + else + SCHEME="\(package)-\(name)" + fi + echo "set -o pipefail; export PATH='swift-latest:$PATH'; WORKSPACE='$WORKSPACE'; SCHEME='$SCHEME'" > setup.sh + """ + ) + + if test && compiler.supportsTesting(on: id) { + for config in configurations { + let extraArgs = config == .release ? "ENABLE_TESTABILITY=YES" : "" yaml.append( - """ - - - name: Upload Logs - uses: actions/upload-artifact@v1 - if: always() - with: - name: logs - path: logs - """ + """ + + - name: Test (\(name) \(config.name)) + run: | + source "setup.sh" + echo "Testing workspace $WORKSPACE scheme $SCHEME." + xcodebuild test -workspace "$WORKSPACE" -scheme "$SCHEME" \(destination) -configuration \(config.xcodeID) CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO \(extraArgs) | tee logs/xcodebuild-\(id)-test-\(config).log | xcpretty + """ ) - } - - fileprivate func notifyYAML(compiler: Compiler) -> String { - var yaml = "" + } + } else { + for config in configurations { + let extraArgs = config == .release ? "ENABLE_TESTABILITY=YES" : "" yaml.append( - """ - - - name: Slack Notification - uses: elegantchaos/slatify@master - if: always() - with: - type: ${{ job.status }} - job_name: '\(name) (\(compiler.name))' - mention_if: 'failure' - url: ${{ secrets.SLACK_WEBHOOK }} - """ + """ + + - name: Build (\(name) \(config)) + run: | + source "setup.sh" + echo "Building workspace $WORKSPACE scheme $SCHEME." + xcodebuild clean build -workspace "$WORKSPACE" -scheme "$SCHEME" \(destination) -configuration \(config.xcodeID) CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO \(extraArgs) | tee logs/xcodebuild-\(id)-build-\(config).log | xcpretty + """ ) - return yaml + } } - - fileprivate func toolchainYAML(_ yaml: inout String, _ branch: String, _ version: String) { - let download = + return yaml + } + + fileprivate func uploadYAML(_ yaml: inout String) { + yaml.append( + """ + + - name: Upload Logs + uses: actions/upload-artifact@v1 + if: always() + with: + name: logs + path: logs + """ + ) + } + + fileprivate func notifyYAML(compiler: Compiler) -> String { + var yaml = "" + yaml.append( + """ + + - name: Slack Notification + uses: elegantchaos/slatify@master + if: always() + with: + type: ${{ job.status }} + job_name: '\(name) (\(compiler.name))' + mention_if: 'failure' + url: ${{ secrets.SLACK_WEBHOOK }} + """ + ) + return yaml + } + + fileprivate func toolchainYAML(_ yaml: inout String, _ branch: String, _ version: String) { + let download = + """ + branch="\(branch)" + wget --quiet https://download.swift.org/$branch/xcode/latest-build.yml + grep "download:" < latest-build.yml > filtered.yml + sed -e 's/-osx.pkg//g' filtered.yml > stripped.yml + sed -e 's/:[^:\\/\\/]/YML="/g;s/$/"/g;s/ *=/=/g' stripped.yml > snapshot.sh + source snapshot.sh + echo "Installing Toolchain: $downloadYML" + wget --quiet https://swift.org/builds/$branch/xcode/$downloadYML/$downloadYML-osx.pkg + sudo installer -pkg $downloadYML-osx.pkg -target / + ln -s "/Library/Developer/Toolchains/$downloadYML.xctoolchain/usr/bin" swift-latest + """ + + yaml.append( + """ + + - name: Install Toolchain + run: | + \(download) + ls -d /Applications/Xcode* + sudo xcode-select -s /Applications/Xcode_\(version).app + swift --version + - name: Xcode Version + run: | + xcodebuild -version + xcrun swift --version + """ + ) + } + + fileprivate func xcodeYAML(_ yaml: inout String, _ version: String) { + yaml.append( + """ + + - name: Xcode Version + run: | + ls -d /Applications/Xcode* + sudo xcode-select -s /Applications/Xcode_\(version).app + xcodebuild -version + swift --version + """ + ) + } + + fileprivate func containerYAML( + _ yaml: inout String, _ compiler: Compiler, _ xcodeToolchain: inout String?, + _ xcodeVersion: inout String? + ) { + switch id { + case .linux: + yaml.append( """ - branch="\(branch)" - wget --quiet https://download.swift.org/$branch/xcode/latest-build.yml - grep "download:" < latest-build.yml > filtered.yml - sed -e 's/-osx.pkg//g' filtered.yml > stripped.yml - sed -e 's/:[^:\\/\\/]/YML="/g;s/$/"/g;s/ *=/=/g' stripped.yml > snapshot.sh - source snapshot.sh - echo "Installing Toolchain: $downloadYML" - wget --quiet https://swift.org/builds/$branch/xcode/$downloadYML/$downloadYML-osx.pkg - sudo installer -pkg $downloadYML-osx.pkg -target / - ln -s "/Library/Developer/Toolchains/$downloadYML.xctoolchain/usr/bin" swift-latest + + runs-on: ubuntu-18.04 + container: \(compiler.linux) """ + ) - yaml.append( - """ - - - name: Install Toolchain - run: | - \(download) - ls -d /Applications/Xcode* - sudo xcode-select -s /Applications/Xcode_\(version).app - swift --version - - name: Xcode Version - run: | - xcodebuild -version - xcrun swift --version - """ - ) - } + default: + let macosImage: String + switch compiler.mac { + case .xcode(let version, let image): + xcodeVersion = version + macosImage = image - fileprivate func xcodeYAML(_ yaml: inout String, _ version: String) { + case .toolchain(let version, let branch, let image): + xcodeVersion = version + xcodeToolchain = branch + macosImage = image yaml.append( - """ - - - name: Xcode Version - run: | - ls -d /Applications/Xcode* - sudo xcode-select -s /Applications/Xcode_\(version).app - xcodebuild -version - swift --version - """ - ) - } + """ - fileprivate func containerYAML(_ yaml: inout String, _ compiler: Compiler, _ xcodeToolchain: inout String?, _ xcodeVersion: inout String?) { - switch id { - case .linux: - yaml.append( - """ - - runs-on: ubuntu-18.04 - container: \(compiler.linux) - """ - ) - - default: - let macosImage: String - switch compiler.mac { - case .xcode(let version, let image): - xcodeVersion = version - macosImage = image - - case .toolchain(let version, let branch, let image): - xcodeVersion = version - xcodeToolchain = branch - macosImage = image - yaml.append( - """ - - env: - TOOLCHAINS: swift - """ - ) - } - - yaml.append( - """ - - runs-on: \(macosImage) - """ - ) - - } - } - - fileprivate func commonYAML(_ yaml: inout String) { - yaml.append( - """ - - steps: - - name: Checkout - uses: actions/checkout@v1 - - name: Make Logs Directory - run: mkdir logs - """ + env: + TOOLCHAINS: swift + """ ) + } + + yaml.append( + """ + + runs-on: \(macosImage) + """ + ) + } + } -} + fileprivate func commonYAML(_ yaml: inout String) { + yaml.append( + """ + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Make Logs Directory + run: mkdir logs + """ + ) + } + +} diff --git a/Sources/ActionBuilderCore/Repo.swift b/Sources/ActionBuilderCore/Repo.swift index 767b78d..320316a 100644 --- a/Sources/ActionBuilderCore/Repo.swift +++ b/Sources/ActionBuilderCore/Repo.swift @@ -5,118 +5,125 @@ import Foundation -public struct Repo: Equatable { - public static let defaultOwner = "Unknown" - public static let defaultWorkflow = "Tests" - public static let defaultTest = TestMode.auto - public static let defaultFirstLast = true - public static let defaultPostSlackNotification = false - public static let defaultUploadLogs = true - public static let defaultHeader = true - public static let defaultConfigurations: [Configuration] = [.release] - - public let name: String - public let owner: String - public let workflow: String - public var platforms: Set - public var compilers: Set - public var configurations: Set - public var testMode: TestMode - public let firstlast: Bool - public let postSlackNotification: Bool - public let uploadLogs: Bool - public let header: Bool +public struct Repo: Equatable, Sendable { + public static let defaultOwner = "Unknown" + public static let defaultWorkflow = "Tests" + public static let defaultTest = TestMode.auto + public static let defaultFirstLast = true + public static let defaultPostSlackNotification = false + public static let defaultUploadLogs = true + public static let defaultHeader = true + public static let defaultConfigurations: [Configuration] = [.release] - /// Initialise explicitly. - public init(name: String, owner: String, workflow: String = "Tests", platforms: [Platform.ID] = [], compilers: [Compiler.ID] = [], configurations: [Configuration] = Self.defaultConfigurations, testMode: TestMode = Self.defaultTest, firstlast: Bool = Self.defaultFirstLast, postSlackNotification: Bool = Self.defaultPostSlackNotification, upload: Bool = Self.defaultUploadLogs, header: Bool = Self.defaultHeader) { - self.name = name - self.owner = owner - self.workflow = workflow - self.platforms = Set(platforms) - self.compilers = Set(compilers) - self.configurations = Set(configurations) - self.testMode = testMode - self.firstlast = firstlast - self.postSlackNotification = postSlackNotification - self.uploadLogs = upload - self.header = header - } - - /// Initialise from settings - public init(settings: Settings?, defaultName: String, defaultOwner: String = Self.defaultOwner) { - self.owner = settings?.owner ?? defaultOwner - self.name = settings?.name ?? defaultName - self.workflow = settings?.workflow ?? Self.defaultWorkflow - self.platforms = settings?.platforms ?? [] - self.compilers = settings?.compilers ?? [] - self.configurations = settings?.configurations ?? Set(Self.defaultConfigurations) - self.testMode = TestMode(settings?.test) - self.firstlast = settings?.firstlast ?? Self.defaultFirstLast - self.uploadLogs = settings?.uploadLogs ?? Self.defaultUploadLogs - self.header = settings?.header ?? Self.defaultHeader - self.postSlackNotification = settings?.postSlackNotification ?? Self.defaultPostSlackNotification - } + public let name: String + public let owner: String + public let workflow: String + public var platforms: Set + public var compilers: Set + public var configurations: Set + public var testMode: TestMode + public let firstlast: Bool + public let postSlackNotification: Bool + public let uploadLogs: Bool + public let header: Bool - var enabledPlatforms: [Platform] { - return Platform.platforms - .filter { platforms.contains($0.id) } - .sorted { $0.name < $1.name } - } + /// Initialise explicitly. + public init( + name: String, owner: String, workflow: String = "Tests", platforms: [Platform.ID] = [], + compilers: [Compiler.ID] = [], configurations: [Configuration] = Self.defaultConfigurations, + testMode: TestMode = Self.defaultTest, firstlast: Bool = Self.defaultFirstLast, + postSlackNotification: Bool = Self.defaultPostSlackNotification, + upload: Bool = Self.defaultUploadLogs, header: Bool = Self.defaultHeader + ) { + self.name = name + self.owner = owner + self.workflow = workflow + self.platforms = Set(platforms) + self.compilers = Set(compilers) + self.configurations = Set(configurations) + self.testMode = testMode + self.firstlast = firstlast + self.postSlackNotification = postSlackNotification + self.uploadLogs = upload + self.header = header + } + + /// Initialise from settings + public init(settings: Settings?, defaultName: String, defaultOwner: String = Self.defaultOwner) { + self.owner = settings?.owner ?? defaultOwner + self.name = settings?.name ?? defaultName + self.workflow = settings?.workflow ?? Self.defaultWorkflow + self.platforms = settings?.platforms ?? [] + self.compilers = settings?.compilers ?? [] + self.configurations = settings?.configurations ?? Set(Self.defaultConfigurations) + self.testMode = TestMode(settings?.test) + self.firstlast = settings?.firstlast ?? Self.defaultFirstLast + self.uploadLogs = settings?.uploadLogs ?? Self.defaultUploadLogs + self.header = settings?.header ?? Self.defaultHeader + self.postSlackNotification = + settings?.postSlackNotification ?? Self.defaultPostSlackNotification + } + + var enabledPlatforms: [Platform] { + return Platform.platforms + .filter { platforms.contains($0.id) } + .sorted { $0.name < $1.name } + } - var enabledCompilers: [Compiler] { - var enabledIDs = self.compilers - if enabledIDs.contains(.swiftLatest) { - enabledIDs.remove(.swiftLatest) - enabledIDs.insert(.latestRelease) - } - - let sorted = Compiler.compilers - .filter { enabledIDs.contains($0.id) } - .sorted { $0.id < $1.id } - - return sorted + var enabledCompilers: [Compiler] { + var enabledIDs = self.compilers + if enabledIDs.contains(.swiftLatest) { + enabledIDs.remove(.swiftLatest) + enabledIDs.insert(.latestRelease) } - - var enabledConfigs: [Configuration] { - return Configuration.allCases - .filter { configurations.contains($0) } - .sorted { $0.rawValue < $1.rawValue } + + let sorted = Compiler.compilers + .filter { enabledIDs.contains($0.id) } + .sorted { $0.id < $1.id } + + return sorted + } + + var enabledConfigs: [Configuration] { + return Configuration.allCases + .filter { configurations.contains($0) } + .sorted { $0.rawValue < $1.rawValue } + } + + var compilersToTest: [Compiler] { + let supportedCompilers = enabledCompilers + if firstlast && (supportedCompilers.count > 0) { + let first = supportedCompilers.first! + let last = supportedCompilers.last! + if first.id != last.id { + return [first, last] + } else { + return [first] + } + } else { + return supportedCompilers } + } + + public enum TestMode: Sendable { + case build + case test + case auto - var compilersToTest: [Compiler] { - let supportedCompilers = enabledCompilers - if firstlast && (supportedCompilers.count > 0) { - let first = supportedCompilers.first! - let last = supportedCompilers.last! - if first.id != last.id { - return [first, last] - } else { - return [first] - } - } else { - return supportedCompilers - } + init(_ shouldTest: Bool?) { + switch shouldTest { + case false: self = .build + case true: self = .test + default: self = .auto + } } - public enum TestMode { - case build - case test - case auto - - init(_ shouldTest: Bool?) { - switch shouldTest { - case false: self = .build - case true: self = .test - default: self = .auto - } - } - - var asBool: Bool? { - switch self { - case .test: return true - case .build: return false - case .auto: return nil - } - } + var asBool: Bool? { + switch self { + case .test: return true + case .build: return false + case .auto: return nil + } } + } } diff --git a/Tests/ActionBuilderCoreTests/ActionBuilderCoreTests.swift b/Tests/ActionBuilderCoreTests/ActionBuilderCoreTests.swift index e5c6846..c501ffa 100644 --- a/Tests/ActionBuilderCoreTests/ActionBuilderCoreTests.swift +++ b/Tests/ActionBuilderCoreTests/ActionBuilderCoreTests.swift @@ -1,15 +1,16 @@ import ChaosTesting +import Foundation import Testing @testable import ActionBuilderCore -// final class ActionBuilderCoreTests: XCTestCase { -// func testParsingPackageMacPlatform() throws { -// let examplePackage = Bundle.module.url(forResource: "Example-mac", withExtension: "package")! -// let repo = try Repo(forPackage: examplePackage) -// XCTAssertEqual(repo.enabledCompilers.map { $0.id }, [.swift56, .swift57 ]) -// XCTAssertEqual(repo.enabledPlatforms.map { $0.id }, [.linux, .macOS]) -// } +@Test +func testParsingPackageMacPlatform() async throws { + let examplePackage = Bundle.module.url(forResource: "Example-mac", withExtension: "package")! + let repo = try await Repo(forPackage: examplePackage) + #expect(repo.enabledCompilers.map { $0.id } == [.swift56, .swift57]) + #expect(repo.enabledPlatforms.map { $0.id } == [.linux, .macOS]) +} // func testParsingPackageMultiPlatform() throws { // let examplePackage = Bundle.module.url(forResource: "Example-multi", withExtension: "package")!