Skip to content

Commit 4aa62a9

Browse files
committed
RUM-7285 Address CR + split commands + add tests
1 parent 5790ee8 commit 4aa62a9

File tree

7 files changed

+287
-113
lines changed

7 files changed

+287
-113
lines changed

.gitlab-ci.yml

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,7 @@ Lint:
9191
- make clean repo-setup ENV=ci
9292
- make lint license-check
9393
- make rum-models-verify sr-models-verify
94-
- make api-surface ENV=ci
95-
- if ! diff api-surface-swift api-surface-swift-generated; then
96-
echo "❌ Swift API surface mismatch";
97-
echo "👉 Run \`make api-surface\` locally to update \`api-surface-swift\` and commit the changes.";
98-
exit 1;
99-
fi
100-
- if ! diff api-surface-objc api-surface-objc-generated; then
101-
echo "❌ Objective-C API surface mismatch";
102-
echo "👉 Run \`make api-surface\` locally to update \`api-surface-objc\` and commit the changes.";
103-
exit 1;
104-
fi
94+
- make api-surface-verify
10595

10696
Unit Tests (iOS):
10797
stage: test

DatadogSessionReplay/Sources/SessionReplayConfiguration.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ extension SessionReplay {
8585
/// - startRecordingImmediately: If the recording should start automatically. When `true`, the recording starts automatically; when `false` it doesn't, and the recording will need to be started manually. Default: `true`.
8686
/// - customEndpoint: Custom server url for sending replay data. Default: `nil`.
8787
/// - featureFlags: Experimental feature flags.
88-
public init( // swiftlint:disable:this function_default_parameter_at_end
88+
// swiftlint:disable function_default_parameter_at_end
89+
public init(
8990
replaySampleRate: Float = 100,
9091
textAndInputPrivacyLevel: TextAndInputPrivacyLevel,
9192
imagePrivacyLevel: ImagePrivacyLevel,
@@ -102,6 +103,7 @@ extension SessionReplay {
102103
self.customEndpoint = customEndpoint
103104
self.featureFlags = featureFlags
104105
}
106+
// swiftlint:enable function_default_parameter_at_end
105107

106108
/// Creates Session Replay configuration.
107109
/// - Parameters:

Makefile

Lines changed: 64 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,18 @@ export DD_SDK_DATADOG_XCCONFIG_CI
5858
# Installs tools and dependencies with homebrew.
5959
# Do not call 'brew update' and instead let Bitrise use its own brew bottle mirror.
6060
dependencies:
61-
@echo "⚙️ Installing dependencies..."
62-
@bundle install
63-
@brew list swiftlint &>/dev/null || brew install swiftlint
64-
@brew upgrade carthage
65-
@carthage bootstrap --platform iOS,tvOS --use-xcframeworks
66-
@echo $$DD_SDK_BASE_XCCONFIG > xcconfigs/Base.local.xcconfig;
67-
@brew list gh &>/dev/null || brew install gh
61+
@echo "⚙️ Installing dependencies..."
62+
@bundle install
63+
@brew list swiftlint &>/dev/null || brew install swiftlint
64+
@brew upgrade carthage
65+
@carthage bootstrap --platform iOS,tvOS --use-xcframeworks
66+
@echo $$DD_SDK_BASE_XCCONFIG > xcconfigs/Base.local.xcconfig;
67+
@brew list gh &>/dev/null || brew install gh
6868
ifeq (${ci}, true)
69-
@echo $$DD_SDK_BASE_XCCONFIG_CI >> xcconfigs/Base.local.xcconfig;
70-
@echo $$DD_SDK_DATADOG_XCCONFIG_CI > xcconfigs/Datadog.local.xcconfig;
69+
@echo $$DD_SDK_BASE_XCCONFIG_CI >> xcconfigs/Base.local.xcconfig;
70+
@echo $$DD_SDK_DATADOG_XCCONFIG_CI > xcconfigs/Datadog.local.xcconfig;
7171
ifndef DD_DISABLE_TEST_INSTRUMENTING
72-
@echo $$DD_SDK_TESTING_XCCONFIG_CI > xcconfigs/DatadogSDKTesting.local.xcconfig;
72+
@echo $$DD_SDK_TESTING_XCCONFIG_CI > xcconfigs/DatadogSDKTesting.local.xcconfig;
7373
endif
7474

7575
endif
@@ -356,50 +356,64 @@ sr-snapshot-tests-open:
356356
@$(ECHO_TITLE) "make sr-snapshot-tests-open"
357357
./tools/sr-snapshot-test.sh --open-project
358358

359-
# Define default paths for API output files
360-
SWIFT_OUTPUT_PATH ?= api-surface-swift
361-
OBJC_OUTPUT_PATH ?= api-surface-objc
362-
363-
# Use different paths when running in CI
364-
ifeq ($(ENV),ci)
365-
SWIFT_OUTPUT_PATH := api-surface-swift-generated
366-
OBJC_OUTPUT_PATH := api-surface-objc-generated
367-
endif
368-
369-
# Generate api-surface files for Datadog and DatadogObjc.
359+
# Generate api-surface files for Datadog and DatadogObjc
370360
api-surface:
371-
@echo "Generating api-surface-swift"
372-
@cd tools/api-surface && \
373-
swift run api-surface spm \
374-
--path ../../ \
375-
--library-name DatadogCore \
376-
--library-name DatadogLogs \
377-
--library-name DatadogTrace \
378-
--library-name DatadogRUM \
379-
--library-name DatadogCrashReporting \
380-
--library-name DatadogWebViewTracking \
381-
--library-name DatadogSessionReplay \
382-
> ../../$(SWIFT_OUTPUT_PATH) && \
383-
cd -
384-
385-
@echo "Generating api-surface-objc"
386-
@cd tools/api-surface && \
387-
swift run api-surface spm \
388-
--path ../../ \
389-
--library-name DatadogObjc \
390-
> ../../$(OBJC_OUTPUT_PATH) && \
391-
cd -
361+
@$(ECHO_TITLE) "make api-surface"
362+
@echo "Generating api-surface-swift"
363+
@cd tools/api-surface && \
364+
swift run api-surface generate \
365+
--path ../../ \
366+
--library-name DatadogCore \
367+
--library-name DatadogLogs \
368+
--library-name DatadogTrace \
369+
--library-name DatadogRUM \
370+
--library-name DatadogCrashReporting \
371+
--library-name DatadogWebViewTracking \
372+
--library-name DatadogSessionReplay \
373+
--output-file ../../api-surface-swift
374+
375+
@echo "Generating api-surface-objc"
376+
@cd tools/api-surface && \
377+
swift run api-surface generate \
378+
--path ../../ \
379+
--library-name DatadogObjc \
380+
--output-file ../../api-surface-objc
381+
382+
# Verify API surface files for Datadog and DatadogObjc
383+
api-surface-verify:
384+
@$(ECHO_TITLE) "make api-surface-verify"
385+
@echo "Verifying api-surface-swift"
386+
@cd tools/api-surface && \
387+
swift run api-surface verify \
388+
--path ../../ \
389+
--library-name DatadogCore \
390+
--library-name DatadogLogs \
391+
--library-name DatadogTrace \
392+
--library-name DatadogRUM \
393+
--library-name DatadogCrashReporting \
394+
--library-name DatadogWebViewTracking \
395+
--library-name DatadogSessionReplay \
396+
--output-file /tmp/api-surface-swift-generated \
397+
../../api-surface-swift
398+
399+
@echo "Verifying api-surface-objc"
400+
@cd tools/api-surface && \
401+
swift run api-surface verify \
402+
--path ../../ \
403+
--library-name DatadogObjc \
404+
--output-file /tmp/api-surface-objc-generated \
405+
../../api-surface-objc
392406

393407
# Generate Datadog monitors terraform definition for E2E tests:
394408
e2e-monitors-generate:
395-
@echo "Deleting previous 'main.tf as it will be soon generated."
396-
@rm -f tools/nightly-e2e-tests/monitors-gen/main.tf
397-
@echo "Deleting previous Terraform state and backup as we don't need to track it."
398-
@rm -f tools/nightly-e2e-tests/monitors-gen/terraform.tfstate
399-
@rm -f tools/nightly-e2e-tests/monitors-gen/terraform.tfstate.backup
400-
@echo "⚙️ Generating 'main.tf':"
401-
@./tools/nightly-e2e-tests/nightly_e2e.py generate-tf --tests-dir ../../Datadog/E2ETests
402-
@echo "⚠️ Remember to delete all iOS monitors manually from Mobile-Integration org before running 'terraform apply'."
409+
@echo "Deleting previous 'main.tf as it will be soon generated."
410+
@rm -f tools/nightly-e2e-tests/monitors-gen/main.tf
411+
@echo "Deleting previous Terraform state and backup as we don't need to track it."
412+
@rm -f tools/nightly-e2e-tests/monitors-gen/terraform.tfstate
413+
@rm -f tools/nightly-e2e-tests/monitors-gen/terraform.tfstate.backup
414+
@echo "⚙️ Generating 'main.tf':"
415+
@./tools/nightly-e2e-tests/nightly_e2e.py generate-tf --tests-dir ../../Datadog/E2ETests
416+
@echo "⚠️ Remember to delete all iOS monitors manually from Mobile-Integration org before running 'terraform apply'."
403417

404418
# Creates dogfooding PR in shopist-ios
405419
dogfood-shopist:

api-surface-swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ public enum Datadog
5353
public static func stopInstance(named instanceName: String = CoreRegistry.defaultInstanceName)
5454
public static func initialize(with configuration: Configuration,trackingConsent: TrackingConsent,instanceName: String = CoreRegistry.defaultInstanceName) -> DatadogCoreProtocol
5555

56-
5756
# ----------------------------------
5857
# API surface for DatadogLogs:
5958
# ----------------------------------
@@ -182,7 +181,6 @@ public enum Logs
182181
public protocol LogEventMapper
183182
func map(event: LogEvent, callback: @escaping (LogEvent) -> Void)
184183

185-
186184
# ----------------------------------
187185
# API surface for DatadogTrace:
188186
# ----------------------------------
@@ -337,7 +335,6 @@ public enum SpanTags
337335
public class Tracer
338336
public static func shared(in core: DatadogCoreProtocol = CoreRegistry.default) -> OTTracer
339337

340-
341338
# ----------------------------------
342339
# API surface for DatadogRUM:
343340
# ----------------------------------
@@ -1790,7 +1787,6 @@ public enum PerformanceMetric
17901787
case flutterRasterTime
17911788
case jsFrameTimeSeconds
17921789

1793-
17941790
# ----------------------------------
17951791
# API surface for DatadogCrashReporting:
17961792
# ----------------------------------
@@ -1799,7 +1795,6 @@ public final class CrashReporting
17991795
public static func enable(in core: DatadogCoreProtocol = CoreRegistry.default)
18001796
public static func enable()
18011797

1802-
18031798
# ----------------------------------
18041799
# API surface for DatadogWebViewTracking:
18051800
# ----------------------------------
@@ -1815,7 +1810,6 @@ public enum WebViewTracking
18151810
public func send(body: Any, slotId: String? = nil)
18161811
public static func messageEmitter(in core: DatadogCoreProtocol,logsSampleRate: Float = 100) -> AbstractMessageEmitter
18171812

1818-
18191813
# ----------------------------------
18201814
# API surface for DatadogSessionReplay:
18211815
# ----------------------------------
@@ -2222,9 +2216,17 @@ public enum SessionReplay
22222216
public var touchPrivacyLevel: TouchPrivacyLevel
22232217
public var startRecordingImmediately: Bool
22242218
public var customEndpoint: URL?
2225-
public init( // swiftlint:disable:this function_default_parameter_at_endreplaySampleRate: Float = 100,textAndInputPrivacyLevel: TextAndInputPrivacyLevel,imagePrivacyLevel: ImagePrivacyLevel,touchPrivacyLevel: TouchPrivacyLevel,startRecordingImmediately: Bool = true,customEndpoint: URL? = nil)
2219+
public var featureFlags: FeatureFlags
2220+
public init(replaySampleRate: Float = 100,textAndInputPrivacyLevel: TextAndInputPrivacyLevel,imagePrivacyLevel: ImagePrivacyLevel,touchPrivacyLevel: TouchPrivacyLevel,startRecordingImmediately: Bool = true,customEndpoint: URL? = nil,featureFlags: FeatureFlags = .defaults)
22262221
public init(replaySampleRate: Float = 100,defaultPrivacyLevel: SessionReplayPrivacyLevel = .mask,startRecordingImmediately: Bool = true,customEndpoint: URL? = nil)
22272222
public mutating func setAdditionalNodeRecorders(_ additionalNodeRecorders: [SessionReplayNodeRecorder])
2223+
[?] extension SessionReplay.Configuration
2224+
public typealias FeatureFlags = [FeatureFlag: Bool]
2225+
public enum FeatureFlag
2226+
case swiftui
2227+
[?] extension SessionReplay.Configuration.FeatureFlags
2228+
public static var defaults: Self
2229+
public subscript(flag: Key) -> Bool
22282230
public enum objc_TextAndInputPrivacyLevelOverride: Int
22292231
case none
22302232
case maskSensitiveInputs

tools/api-surface/Sources/APISurfaceCore/Commands.swift

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@
77
import Foundation
88
import ArgumentParser
99

10-
public var printFunction: (String) -> Void = { print($0) }
11-
12-
public struct SPMLibrarySurfaceCommand: ParsableCommand {
10+
public struct GenerateCommand: ParsableCommand {
1311
public static let configuration = CommandConfiguration(
14-
commandName: "spm",
15-
abstract: "Prints API surface for given SPM library or list of libraries."
12+
commandName: "generate",
13+
abstract: "Generate API surface files for given SPM library or list of libraries."
1614
)
1715

1816
@Option(help: "Specify a library name (use this option multiple times to provide list of libraries).")
@@ -21,23 +19,106 @@ public struct SPMLibrarySurfaceCommand: ParsableCommand {
2119
@Option(help: "The path to the folder containing `Package.swift`.")
2220
var path: String
2321

22+
@Option(help: "The file to which the generated API surface should be written.")
23+
var outputFile: String
24+
25+
public init() {}
26+
27+
public func run() throws {
28+
try generateAPISurface(
29+
libraryName: libraryName,
30+
path: path,
31+
outputFile: outputFile
32+
)
33+
}
34+
}
35+
36+
public struct VerifyCommand: ParsableCommand {
37+
public static let configuration = CommandConfiguration(
38+
commandName: "verify",
39+
abstract: "Verify that a generated API surface matches the reference file."
40+
)
41+
42+
@Option(help: "Specify a library name (use this option multiple times to provide a list of libraries).")
43+
var libraryName: [String]
44+
45+
@Option(help: "The path to the folder containing `Package.swift`.")
46+
var path: String
47+
48+
@Option(help: "The temporary file to which the generated API surface should be written.")
49+
var outputFile: String
50+
51+
@Argument(help: "Path to the reference API surface file to compare against.")
52+
var referencePath: String
53+
2454
public init() {}
2555

2656
public func run() throws {
27-
var printSeparator = false
28-
for libraryName in libraryName {
29-
let surface = try APISurface(spmLibraryName: libraryName, inPath: path)
57+
try generateAPISurface(
58+
libraryName: libraryName,
59+
path: path,
60+
outputFile: outputFile
61+
)
62+
63+
// Compare the generated files with the reference files
64+
let diff = try compareFiles(reference: referencePath, generated: outputFile)
65+
66+
if !diff.isEmpty {
67+
throw ValidationError("""
68+
❌ API surface mismatch detected!
69+
Run `make api-surface` locally to update reference files and commit the changes.
70+
""")
71+
}
72+
73+
print("✅ API surface files are up-to-date.")
74+
}
75+
76+
private func compareFiles(reference: String, generated: String) throws -> String {
77+
let referenceContent = try String(contentsOfFile: reference)
78+
let generatedContent = try String(contentsOfFile: generated)
79+
80+
return referenceContent == generatedContent ? "" : "Difference in \(reference)"
81+
}
82+
}
83+
84+
private func generateAPISurface(
85+
libraryName: [String],
86+
path: String,
87+
outputFile: String
88+
) throws {
89+
var output = ""
90+
var printSeparator = false
91+
92+
for library in libraryName {
93+
do {
94+
let surface = try APISurface(spmLibraryName: library, inPath: path)
3095
if printSeparator {
31-
printFunction("\n")
96+
output.append("\n")
3297
}
33-
printFunction("""
98+
99+
output.append("""
34100
# ----------------------------------
35-
# API surface for \(libraryName):
101+
# API surface for \(library):
36102
# ----------------------------------
37103
38104
""")
39-
printFunction(try surface.print())
105+
106+
output.append("\n")
107+
output.append(try surface.print() + "\n")
108+
40109
printSeparator = true
110+
} catch {
111+
print("❌ Error generating API surface for library \(library): \(error)")
112+
throw error
41113
}
42114
}
115+
116+
// Write the output to the specified file
117+
do {
118+
try output.write(toFile: outputFile, atomically: true, encoding: .utf8)
119+
print("✅ API surface written to \(outputFile)")
120+
} catch {
121+
print("❌ Error writing API surface to \(outputFile): \(error)")
122+
throw error
123+
}
43124
}

tools/api-surface/Sources/api-surface/main.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ import APISurfaceCore
99

1010
private struct RootCommand: ParsableCommand {
1111
static let configuration = CommandConfiguration(
12-
commandName: "api-surface",
13-
abstract: "Prints API surface for given module.",
12+
abstract: "A tool to manage API surface files.",
1413
subcommands: [
15-
SPMLibrarySurfaceCommand.self
16-
]
14+
GenerateCommand.self,
15+
VerifyCommand.self
16+
],
17+
defaultSubcommand: GenerateCommand.self
1718
)
1819
}
1920

0 commit comments

Comments
 (0)