Skip to content

Commit 78ade99

Browse files
jkmasselclaude
andauthored
Add cross-platform Swift package tests for macOS (#25344)
* Add cross-platform Package.swift for macOS testing Defines a subset of modules that build and test on macOS without Xcode, enabling `swift test` from the repo root. Modules can be incrementally added here as they become cross-platform. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add WordPressKitObjCUtils, WordPressKitModels, and WordPressKitObjC to cross-platform package Replace unnecessary UIKit imports with Foundation in Obj-C headers that only use Foundation types. Remove stale UIKit import from FeatureFlagRemote.swift. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Split WordPressShared into cross-platform and UIKit-only modules Create WordPressSharedObjCUI and WordPressSharedUI for UIKit-dependent code, keeping WordPressSharedObjC and WordPressShared cross-platform. Update all import statements across the codebase accordingly. * Decouple WordPressKit from UIKit Introduce DeviceInformation struct to replace direct UIDevice usage in NotificationSettingsServiceRemote. Use ProcessInfo for OS version in SessionDetails. Guard UIKit-only code with #if canImport(UIKit) in HTTPAuthenticationAlertController, UIDevice+Extensions, NSMutableParagraphStyle+extensions, GravatarServiceRemote (upload), PluginDirectoryEntry (HTML text extraction), and SiteDesignServiceRemote (screen scale). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add WordPressShared and WordPressKit to cross-platform package Add WordPressSharedObjC, WordPressShared, WordPressKit, and WordPressSharedTests to the root Package.swift for macOS testing. Fix cross-platform build issues: remove unused MobileCoreServices import from URL+Helpers, guard String.accessibilityLabel usage in Double+Stats with #if canImport(UIKit), and remove unused WordPressSharedObjC import from String+RemovingMatches. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add Buildkite job to run cross-platform Swift package tests Runs `swift test` from the repository root to verify that cross-platform modules build and pass tests on macOS without Xcode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Reconcile cross-platform module split with trunk Rebasing onto trunk surfaced drift in the module graph the split targets. The app builds unchanged; these adapt the split + cross-platform package to 302 commits of trunk evolution. Module graph: - Root Package.swift: drop the removed WordPressKitObjCUtils target/deps (folded into WordPressSharedObjC on trunk); align WordPressShared deps with trunk (BuildSettingsKit/Logging/SwiftSoup, no Reachability pod); bump wordpress-rs to 0.6.0 to match the WordPressAPI surface trunk's WordPressCore now uses; exclude JetpackStatsWidgetsCore's iOS-only AppIntents (SelectSiteIntent/SiteEntity) and its test from the macOS build. - Modules/Package.swift: graft WordPressSharedUI/WordPressSharedObjCUI targets and wire them into consumers that gained WordPressSharedUI usage (AztecExtensions, FormattableContentKit, JetpackStats, WordPressReader, JetpackSocial, WordPressData, App/Keystone, Share/Draft extensions, tests). Imports: - Add `import WordPressSharedUI` to trunk-added callers of WPUserAgent (WordPressData Blog, JetpackSocial) and the reachability alert helpers (Jetpack Restore/Backup options). - Add explicit `@import WordPressSharedObjC` to WordPressKitObjC files using `wp_map:` — the ObjC-side transitive re-export through WordPressShared no longer resolves once it also re-exports WordPressSharedObjCUI. - Replace a stray `#import <UIKit/UIKit.h>` with Foundation in NSString+WPKitNumericValueHack.h (Foundation-only header) so WordPressKitObjC builds on macOS. - Make the keychain logger label nil-safe: `Bundle.main.bundleIdentifier` is nil in the SPM test runner and crashed the cross-platform test suite. Verified: `swift build` + `swift test` (macOS cross-platform package, all tests pass) and the full WordPress iOS app + Share/Draft/NotificationService extensions build. * Reference the Modules package instead of re-declaring cross-platform targets The cross-platform Package.swift re-declared 14 targets that already live in Modules/Package.swift, differing only in their macOS-stripped dependency lists — a standing source of drift. Depend on the Modules package and reference its products instead, so each target is defined once. This requires Modules to be macOS-aware: - Add a .macOS(.v14) floor, which satisfies the highest dependency floors (GutenbergKit 14, WordPressAPI 13, Gravatar 12) and clears platform-floor validation for the whole graph. - Gate the WordPressShared -> WordPressSharedObjCUI edge to non-macOS platforms; it is UIKit-only. - Wrap JetpackStatsWidgetsCore's iOS-only AppIntents in #if os(iOS). The root manifest drops from 149 to 51 lines and now inherits Modules' dependency changes automatically. Trade-off: `swift test` resolves the full Modules dependency graph (40 packages) rather than a curated 5. Verified: swift build + swift test on macOS (77 tests) and the WordPress iOS app build. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0463d83 commit 78ade99

165 files changed

Lines changed: 764 additions & 89 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/bash -eu
2+
3+
if "$(dirname "${BASH_SOURCE[0]}")/should-skip-job.sh" --job-type validation; then
4+
exit 0
5+
fi
6+
7+
echo "--- :swift: Running cross-platform Swift package tests"
8+
swift test

.buildkite/pipeline.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ steps:
8080
- group: "🔬 Unit Tests"
8181
key: unit_tests_group
8282
steps:
83+
- label: "🔬 :swift: Swift Package Tests"
84+
command: .buildkite/commands/run-swift-package-tests.sh
85+
plugins: [$CI_TOOLKIT_PLUGIN]
86+
notify:
87+
- github_commit_status:
88+
context: "Swift Package Tests"
89+
8390
- label: "🔬 :wordpress: Unit Tests"
8491
command: ".buildkite/commands/run-unit-tests.sh"
8592
depends_on: "build_wordpress"

Modules/Package.swift

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import PackageDescription
55
let package = Package(
66
name: "Modules",
77
platforms: [
8-
.iOS(.v17)
8+
.iOS(.v17),
9+
.macOS(.v14)
910
],
1011
products: XcodeSupport.products + [
1112
.library(name: "AsyncImageKit", targets: ["AsyncImageKit"]),
@@ -84,6 +85,7 @@ let package = Package(
8485
name: "AztecExtensions",
8586
dependencies: [
8687
"WordPressShared",
88+
"WordPressSharedUI",
8789
.product(name: "Gridicons", package: "Gridicons-iOS"),
8890
.product(name: "Aztec", package: "AztecEditor-iOS")
8991
],
@@ -103,6 +105,7 @@ let package = Package(
103105
name: "FormattableContentKit",
104106
dependencies: [
105107
"WordPressShared",
108+
"WordPressSharedUI",
106109
"WordPressUI",
107110
// TODO: Remove — It's here just for a NSMutableParagraphStyle init helper
108111
"WordPressKit",
@@ -116,7 +119,8 @@ let package = Package(
116119
dependencies: [
117120
"WordPressUI",
118121
"WordPressKit",
119-
"WordPressShared"
122+
"WordPressShared",
123+
"WordPressSharedUI"
120124
],
121125
resources: [.process("Resources")]
122126
),
@@ -131,6 +135,7 @@ let package = Package(
131135
"AsyncImageKit",
132136
"DesignSystem",
133137
"WordPressShared",
138+
"WordPressSharedUI",
134139
"WordPressUI",
135140
"WordPressCore",
136141
.product(name: "WordPressAPI", package: "wordpress-rs"),
@@ -227,7 +232,13 @@ let package = Package(
227232
.target(name: "WordPressLegacy", dependencies: ["DesignSystem", "WordPressShared"]),
228233
.target(
229234
name: "WordPressSharedObjC",
235+
swiftSettings: [.swiftLanguageMode(.v5)]
236+
),
237+
.target(
238+
name: "WordPressSharedObjCUI",
239+
dependencies: ["WordPressSharedObjC"],
230240
resources: [.process("Resources")],
241+
publicHeadersPath: "include",
231242
swiftSettings: [.swiftLanguageMode(.v5)]
232243
),
233244
.target(
@@ -237,11 +248,24 @@ let package = Package(
237248
.product(name: "Logging", package: "swift-log"),
238249
.product(name: "SwiftSoup", package: "SwiftSoup"),
239250
.target(name: "SFHFKeychainUtils"),
240-
.target(name: "WordPressSharedObjC")
251+
.target(name: "WordPressSharedObjC"),
252+
// UIKit-only; drop on macOS so WordPressShared builds cross-platform.
253+
.target(
254+
name: "WordPressSharedObjCUI",
255+
condition: .when(platforms: [.iOS, .macCatalyst, .tvOS, .watchOS, .visionOS])
256+
)
241257
],
242258
resources: [.process("Resources")],
243259
swiftSettings: [.swiftLanguageMode(.v5)]
244260
),
261+
.target(
262+
name: "WordPressSharedUI",
263+
dependencies: [
264+
"WordPressShared",
265+
"WordPressSharedObjCUI"
266+
],
267+
swiftSettings: [.swiftLanguageMode(.v5)]
268+
),
245269
.target(name: "WordPressTesting", resources: [.process("Resources")]),
246270
.target(
247271
name: "WordPressUI",
@@ -293,6 +317,7 @@ let package = Package(
293317
"FormattableContentKit",
294318
"SFHFKeychainUtils",
295319
"WordPressShared",
320+
"WordPressSharedUI",
296321
"WordPressKit",
297322
"WordPressUI",
298323
.product(name: "CocoaLumberjack", package: "CocoaLumberjack"),
@@ -315,6 +340,7 @@ let package = Package(
315340
"AsyncImageKit",
316341
"WordPressUI",
317342
"WordPressShared",
343+
"WordPressSharedUI",
318344
.product(name: "SwiftSoup", package: "SwiftSoup")
319345
],
320346
resources: [.process("Resources")]
@@ -346,7 +372,7 @@ let package = Package(
346372
),
347373
.testTarget(
348374
name: "WordPressSharedTests",
349-
dependencies: [.target(name: "WordPressShared")],
375+
dependencies: [.target(name: "WordPressShared"), .target(name: "WordPressSharedUI")],
350376
swiftSettings: [.swiftLanguageMode(.v5)]
351377
),
352378
.testTarget(
@@ -361,12 +387,15 @@ let package = Package(
361387
),
362388
.testTarget(
363389
name: "WordPressSharedObjCTests",
364-
dependencies: [.target(name: "WordPressShared"), .target(name: "WordPressTesting")],
390+
dependencies: [
391+
.target(name: "WordPressShared"), .target(name: "WordPressSharedObjCUI"),
392+
.target(name: "WordPressTesting")
393+
],
365394
swiftSettings: [.swiftLanguageMode(.v5)]
366395
),
367396
.testTarget(
368397
name: "WordPressUIUnitTests",
369-
dependencies: [.target(name: "WordPressUI")],
398+
dependencies: [.target(name: "WordPressUI"), .target(name: "WordPressSharedUI")],
370399
swiftSettings: [.swiftLanguageMode(.v5)]
371400
),
372401
.testTarget(name: "WordPressCoreTests", dependencies: [.target(name: "WordPressCore")]),
@@ -420,6 +449,7 @@ enum XcodeSupport {
420449
"SFHFKeychainUtils",
421450
"ShareExtensionCore",
422451
"WordPressShared",
452+
"WordPressSharedUI",
423453
"WordPressUI",
424454
"TextBundle",
425455
"TracksMini",
@@ -464,6 +494,8 @@ enum XcodeSupport {
464494
"WordPressFlux",
465495
"WordPressIntelligence",
466496
"WordPressShared",
497+
"WordPressSharedUI",
498+
"WordPressSharedObjCUI",
467499
"WordPressLegacy",
468500
"WordPressMediaLibrary",
469501
"WordPressReader",
@@ -514,6 +546,7 @@ enum XcodeSupport {
514546
"WordPressData",
515547
"WordPressKit",
516548
"WordPressShared",
549+
"WordPressSharedUI",
517550
"WordPressUI",
518551
.product(name: "Gravatar", package: "Gravatar-SDK-iOS"),
519552
.product(name: "WordPressAPI", package: "wordpress-rs")

Modules/Sources/AztecExtensions/Header+WordPress.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Foundation
22
import Aztec
33
import Gridicons
44
import WordPressShared
5+
import WordPressSharedUI
56

67
// MARK: - Header and List presentation extensions
78
//

Modules/Sources/FormattableContentKit/Styles/SnippetsContentStyles.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import WordPressShared
2+
import WordPressSharedUI
23

34
public class SnippetsContentStyles: FormattableContentStyles {
45
public var attributes: [NSAttributedString.Key: Any] {

Modules/Sources/FormattableContentKit/Styles/SubjectContentStyles.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import WordPressShared
2+
import WordPressSharedUI
23

34
public class SubjectContentStyles: FormattableContentStyles {
45
public var attributes: [NSAttributedString.Key: Any] {

Modules/Sources/FormattableContentKit/Styles/WPStyleGuide+Notifications.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Foundation
33
import Gridicons
44
import UIKit
55
import WordPressShared
6+
import WordPressSharedUI
67
import WordPressKit // FIXME: Here just for the NSMutableParagraphStyle custom init
78
import WordPressUI
89

Modules/Sources/JetpackSocial/Views/SocialOAuthWebViewController.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Logging
22
import UIKit
33
@preconcurrency import WebKit
44
import WordPressShared
5+
import WordPressSharedUI
56

67
/// A minimal `WKWebView` host for the Publicize OAuth kick-off flow.
78
///

Modules/Sources/JetpackStats/StatsRouter.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import SwiftUI
22
import UIKit
33
import SafariServices
44
import WordPressShared
5+
import WordPressSharedUI
56

67
@MainActor
78
public protocol StatsRouterScreenFactory: AnyObject {

Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SelectSiteIntent.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#if os(iOS)
12
import AppIntents
23

34
/// The widget configuration intent that lets the user pick which site a stats widget shows.
@@ -34,3 +35,4 @@ public struct SelectSiteIntent: WidgetConfigurationIntent, CustomIntentMigratedA
3435

3536
public init() {}
3637
}
38+
#endif

0 commit comments

Comments
 (0)