Skip to content

Commit c16c2ca

Browse files
committed
Move E2E testing into GH action for Linux
1 parent 351a278 commit c16c2ca

File tree

5 files changed

+163
-69
lines changed

5 files changed

+163
-69
lines changed

.github/workflows/pull_request.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,33 @@ jobs:
5858
path: .build/release/swiftly-*.tar.gz
5959
if-no-files-found: error
6060
retention-days: 1
61+
- name: Upload Tests
62+
uses: actions/upload-artifact@v4
63+
with:
64+
name: swiftly-tests-x86_64
65+
path: .build/debug/test-swiftly-linux-x86_64.tar.gz
66+
if-no-files-found: error
67+
retention-days: 1
68+
69+
releasetest:
70+
name: Test Release
71+
needs: releasebuildcheck
72+
runs-on: ubuntu-latest
73+
container:
74+
image: "ubuntu:24.04"
75+
steps:
76+
- name: Prepare System
77+
run: apt-get update && DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install ca-certificates gpg tzdata
78+
- name: Download Release
79+
uses: actions/download-artifact@v4
80+
with:
81+
name: swiftly-release-x86_64
82+
- name: Download Tests
83+
uses: actions/download-artifact@v4
84+
with:
85+
name: swiftly-tests-x86_64
86+
- name: Extract and Run Workflow Tests
87+
run: cp swiftly-*.tar.gz /root/swiftly.tar.gz && cp test-swiftly-*.tar.gz /root && cd /root && tar zxf test-swiftly.tar.gz && ./test-swiftly -y ./swiftly.tar.gz
6188

6289
formatcheck:
6390
name: Format Check

Package.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ let package = Package(
1212
name: "swiftly",
1313
targets: ["Swiftly"]
1414
),
15+
.executable(
16+
name: "test-swiftly",
17+
targets: ["TestSwiftly"]
18+
),
1519
],
1620
dependencies: [
1721
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.3.0"),
@@ -36,6 +40,15 @@ let package = Package(
3640
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
3741
]
3842
),
43+
.executableTarget(
44+
name: "TestSwiftly",
45+
dependencies: [
46+
.product(name: "ArgumentParser", package: "swift-argument-parser"),
47+
.target(name: "SwiftlyCore"),
48+
.target(name: "LinuxPlatform", condition: .when(platforms: [.linux])),
49+
.target(name: "MacOSPlatform", condition: .when(platforms: [.macOS])),
50+
]
51+
),
3952
.target(
4053
name: "SwiftlyCore",
4154
dependencies: [
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import ArgumentParser
2+
import Foundation
3+
import SwiftlyCore
4+
import System
5+
6+
#if os(Linux)
7+
import LinuxPlatform
8+
#elseif os(macOS)
9+
import MacOSPlatform
10+
#endif
11+
12+
#if os(Linux)
13+
let currentPlatform: Platform = Linux.currentPlatform
14+
#elseif os(macOS)
15+
let currentPlatform: Platform = MacOS.currentPlatform
16+
#else
17+
#error("Unsupported platform")
18+
#endif
19+
20+
@main
21+
struct TestSwiftly: AsyncParsableCommand {
22+
@Flag(name: [.customShort("y"), .long], help: "Disable confirmation prompts by assuming 'yes'")
23+
var assumeYes: Bool = false
24+
25+
@Argument var swiftlyArchive: String? = nil
26+
27+
mutating func run() async throws {
28+
if !self.assumeYes {
29+
print("WARNING: This test will mutate your system to test the swiftly installation end-to-end. Please run this on a fresh system and try again with '--assume-yes'.")
30+
Foundation.exit(2)
31+
}
32+
33+
guard let swiftlyArchive = self.swiftlyArchive else {
34+
print("ERROR: You must provide a swiftly archive path for the test.")
35+
Foundation.exit(2)
36+
}
37+
38+
print("Extracting swiftly release")
39+
#if os(Linux)
40+
try currentPlatform.runProgram("tar", "-zxvf", swiftlyArchive, quiet: false)
41+
#elseif os(macOS)
42+
try currentPlatform.runProgram("installer", "-pkg", swiftlyArchive, "-target", "CurrentUserHomeDirectory", quiet: false)
43+
#endif
44+
45+
print("Running 'swiftly init --assume-yes --verbose' to install swiftly and the latest toolchain")
46+
47+
#if os(Linux)
48+
let extractedSwiftly = "./swiftly"
49+
#elseif os(macOS)
50+
let extractedSwiftly = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(".swiftly/bin/swiftly").path
51+
#endif
52+
53+
try currentPlatform.runProgram(extractedSwiftly, "init", "--assume-yes", quiet: false)
54+
55+
let shell = try await currentPlatform.getShell()
56+
57+
var env = ProcessInfo.processInfo.environment
58+
59+
// Setting this environment helps to ensure that the profile gets sourced with bash, even if it is not in an interactive shell
60+
if shell.hasSuffix("bash") {
61+
env["BASH_ENV"] = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(".profile").path
62+
} else if shell.hasSuffix("zsh") {
63+
env["ZDOTDIR"] = FileManager.default.homeDirectoryForCurrentUser.path
64+
} else if shell.hasSuffix("fish") {
65+
env["XDG_CONFIG_HOME"] = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(".config").path
66+
}
67+
68+
try currentPlatform.runProgram(shell, "-l", "-c", "swiftly install --assume-yes latest --post-install-file=./post-install.sh", quiet: false, env: env)
69+
70+
var swiftReady = false
71+
72+
if NSUserName() == "root" && FileManager.default.fileExists(atPath: "./post-install.sh") {
73+
try currentPlatform.runProgram(shell, "./post-install.sh", quiet: false)
74+
swiftReady = true
75+
} else if FileManager.default.fileExists(atPath: "./post-install.sh") {
76+
print("WARNING: not running as root, so skipping the post installation steps and final swift verification.")
77+
} else {
78+
swiftReady = true
79+
}
80+
81+
if swiftReady {
82+
try currentPlatform.runProgram(shell, "-l", "-c", "swift --version", quiet: false, env: env)
83+
}
84+
}
85+
}

Tests/SwiftlyTests/E2ETests.swift

Lines changed: 0 additions & 65 deletions
This file was deleted.

Tools/build-swiftly-release/BuildSwiftlyRelease.swift

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
164164
var useRhelUbi9: Bool = false
165165
#endif
166166

167+
@Flag(help: "Produce a swiftly-test.tar.gz that has a standalone test suite to test the released bundle.")
168+
var test: Bool = false
169+
167170
@Argument(help: "Version of swiftly to build the release.")
168171
var version: String
169172

@@ -365,7 +368,6 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
365368
FileManager.default.changeCurrentDirectoryPath(cwd)
366369

367370
try runProgram(swift, "build", "--swift-sdk", "\(arch)-swift-linux-musl", "--product=swiftly", "--pkg-config-path=\(pkgConfigPath)/lib/pkgconfig", "--static-swift-stdlib", "--configuration=release")
368-
try runProgram(swift, "sdk", "remove", sdkName)
369371

370372
let releaseDir = cwd + "/.build/release"
371373

@@ -383,6 +385,21 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
383385
try runProgram(tar, "--directory=\(releaseDir)", "-czf", releaseArchive, "swiftly", "LICENSE.txt")
384386

385387
print(releaseArchive)
388+
389+
if self.test {
390+
#if arch(arm64)
391+
let testArchive = "\(releaseDir)/test-swiftly-linux-aarch64.tar.gz"
392+
#else
393+
let testArchive = "\(releaseDir)/test-swiftly-linux-x86_64.tar.gz"
394+
#endif
395+
396+
try runProgram(swift, "build", "--swift-sdk", "\(arch)-swift-linux-musl", "--product=test-swiftly", "--pkg-config-path=\(pkgConfigPath)/lib/pkgconfig", "--static-swift-stdlib", "--configuration=release")
397+
try runProgram(tar, "--directory=\(releaseDir)", "-czf", testArchive, "test-swiftly")
398+
399+
print(testArchive)
400+
}
401+
402+
try runProgram(swift, "sdk", "remove", sdkName)
386403
}
387404

388405
func buildMacOSRelease(cert: String?, identifier: String) async throws {
@@ -397,6 +414,8 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
397414
let pkgbuild = try await self.assertTool("pkgbuild", message: "In order to make pkg installers there needs to be the `pkgbuild` tool that is installed on macOS.")
398415
let strip = try await self.assertTool("strip", message: "In order to strip binaries there needs to be the `strip` tool that is installed on macOS.")
399416

417+
let tar = try await self.assertTool("tar", message: "In order to produce archives there needs to be the `tar` tool that is installed on macOS.")
418+
400419
try runProgram(swift, "package", "clean")
401420

402421
for arch in ["x86_64", "arm64"] {
@@ -415,7 +434,8 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
415434

416435
let cwd = FileManager.default.currentDirectoryPath
417436

418-
let pkgFile = URL(fileURLWithPath: cwd + "/.build/release/swiftly-\(self.version).pkg")
437+
let releaseDir = URL(fileURLWithPath: cwd + "/.build/release")
438+
let pkgFile = releaseDir.appendingPathComponent("/swiftly-\(self.version).pkg")
419439

420440
if let cert {
421441
try runProgram(
@@ -450,8 +470,8 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
450470
// Re-configure the pkg to prefer installs into the current user's home directory with the help of productbuild.
451471
// Note that command-line installs can override this preference, but the GUI install will limit the choices.
452472

453-
let pkgFileReconfigured = URL(fileURLWithPath: cwd + "/.build/release/swiftly-\(self.version)-reconfigured.pkg")
454-
let distFile = URL(fileURLWithPath: cwd + "/.build/release/distribution.plist")
473+
let pkgFileReconfigured = releaseDir.appendingPathComponent("swiftly-\(self.version)-reconfigured.pkg")
474+
let distFile = releaseDir.appendingPathComponent("distribution.plist")
455475

456476
try runProgram("productbuild", "--synthesize", "--package", pkgFile.path, distFile.path)
457477

@@ -466,5 +486,19 @@ struct BuildSwiftlyRelease: AsyncParsableCommand {
466486
}
467487
try FileManager.default.removeItem(at: pkgFile)
468488
try FileManager.default.copyItem(atPath: pkgFileReconfigured.path, toPath: pkgFile.path)
489+
490+
print(pkgFile.path)
491+
492+
if self.test {
493+
for arch in ["x86_64", "arm64"] {
494+
try runProgram(swift, "build", "--product=test-swiftly", "--configuration=release", "--arch=\(arch)")
495+
try runProgram(strip, ".build/\(arch)-apple-macosx/release/swiftly")
496+
}
497+
498+
let testArchive = releaseDir.appendingPathComponent("test-swiftly-macos.tar.gz")
499+
500+
try runProgram(lipo, ".build/x86_64-apple-macosx/release/test-swiftly", ".build/arm64-apple-macosx/release/test-swiftly", "-create", "-o", "\(swiftlyBinDir)/swiftly")
501+
try runProgram(tar, "--directory=\(swiftlyBinDir)", "-czf", testArchive.path, "test-swiftly")
502+
}
469503
}
470504
}

0 commit comments

Comments
 (0)