From 94274ef09435e1e9aab756c0190fa8b0de7acbd3 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 11 Nov 2024 19:21:35 +0100 Subject: [PATCH] chore(lint): Add swiftlint (#4259) * chore(lint): Add swiftlint * add swift lint and fix package scripts * fix swift lint --- .swiftlint.yml | 104 ++++++++++++++++++ package.json | 8 +- .../core/RNSentryCocoaTester/.swiftlint.yml | 11 ++ .../RNSentryBreadcrumbTests.swift | 2 +- ...SentryReplayBreadcrumbConverterTests.swift | 28 ++--- .../RNSentryReplayOptionsTests.swift | 18 +-- scripts/swiftlint.sh | 30 +++++ yarn.lock | 10 ++ 8 files changed, 185 insertions(+), 26 deletions(-) create mode 100755 .swiftlint.yml create mode 100644 packages/core/RNSentryCocoaTester/.swiftlint.yml create mode 100755 scripts/swiftlint.sh diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100755 index 0000000000..efdb728bf9 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,104 @@ +# We have to narrow down the included files to avoid minutes long lint runs due to node_modules +included: + - 'samples/react-native/ios/**' + - 'packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/**' + - 'packages/core/ios/**' + - 'performance-tests/TestAppPlain/ios/**' + - 'performance-tests/TestAppSentry/ios/**' + +excluded: + - 'samples/react-native/ios/Pods' + - 'samples/react-native/ios/build' + - 'performance-tests/TestAppPlain/ios/Pods' + - 'performance-tests/TestAppPlain/ios/build' + - 'performance-tests/TestAppSentry/ios/Pods' + - 'performance-tests/TestAppSentry/ios/build' + +only_rules: + - class_delegate_protocol + - closing_brace + - closure_end_indentation + - closure_parameter_position + - closure_spacing + - colon + - comma + - compiler_protocol_init + - control_statement + - custom_rules + - cyclomatic_complexity + - dynamic_inline + - empty_parameters + - empty_parentheses_with_trailing_closure + - explicit_init + - file_length + - first_where + - force_cast + - force_try + - force_unwrapping + - function_body_length + - generic_type_name + - implicit_getter + - large_tuple + - leading_whitespace + - legacy_cggeometry_functions + - legacy_constant + - legacy_constructor + - legacy_nsgeometry_functions + - line_length + - mark + - nimble_operator + - number_separator + - opening_brace + - operator_usage_whitespace + - operator_whitespace + - overridden_super_call + - private_outlet + - private_unit_test + - prohibited_super_call + - redundant_nil_coalescing + - redundant_optional_initialization + - redundant_string_enum_value + - redundant_void_return + - return_arrow_whitespace + - shorthand_operator + - sorted_imports + - statement_position + - syntactic_sugar + - todo + - trailing_comma + - trailing_newline + - trailing_semicolon + - type_body_length + - type_name + - unused_closure_parameter + - unused_enumerated + - unused_optional_binding + - valid_ibinspectable + - identifier_name + - vertical_parameter_alignment + - vertical_whitespace + - void_return + - weak_delegate + - yoda_condition + +identifier_name: + allowed_symbols: + - i + - _ + min_length: + - 1 + max_length: + warning: 50 + error: 50 + +line_length: + - 1000 +type_name: + min_length: + - 2 + - 1 + max_length: + warning: 50 + error: 50 +large_tuple: + - 3 diff --git a/package.json b/package.json index b78d286bc5..520c33b0c4 100644 --- a/package.json +++ b/package.json @@ -7,22 +7,26 @@ "clean": "lerna run clean", "circularDepCheck": "lerna run circularDepCheck", "test": "lerna run test", - "fix": "run-s fix:lerna fix:android fix:clang", + "fix": "run-s fix:lerna fix:android fix:clang fix:swift", "fix:lerna": "lerna run fix", "fix:android": "run-s 'java:format fix' java:pmd", "fix:clang": "run-s 'clang:format fix'", - "lint": "run-s lint:lerna lint:android lint:clang", + "fix:swift": "run-s 'swift:lint fix'", + "lint": "run-s lint:lerna lint:android lint:clang lint:swift", "lint:lerna": "lerna run lint", "lint:android": "run-s 'java:format lint' java:pmd", "lint:clang": "run-s 'clang:format lint'", + "lint:swift": "run-s 'swift:lint lint'", "java:format": "./scripts/google-java-format.sh", "java:pmd": "./scripts/pmd.sh", "clang:format": "./scripts/clang-format.sh", + "swift:lint": "./scripts/swiftlint.sh", "run-ios": "cd samples/react-native && yarn react-native run-ios", "run-android": "cd samples/react-native && yarn react-native run-android", "set-version-samples": "lerna run set-version" }, "devDependencies": { + "@expo/swiftlint": "^0.57.1", "@sentry/cli": "2.38.2", "clang-format": "^1.8.0", "downlevel-dts": "^0.11.0", diff --git a/packages/core/RNSentryCocoaTester/.swiftlint.yml b/packages/core/RNSentryCocoaTester/.swiftlint.yml new file mode 100644 index 0000000000..2022134b93 --- /dev/null +++ b/packages/core/RNSentryCocoaTester/.swiftlint.yml @@ -0,0 +1,11 @@ +parent_config: ../../../.swiftlint.yml + +disabled_rules: + - force_cast + - force_try + - force_unwrapping + - function_body_length + - identifier_name + - large_tuple + - type_body_length + - weak_delegate diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryBreadcrumbTests.swift b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryBreadcrumbTests.swift index f4bd3ce8e9..d58931b295 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryBreadcrumbTests.swift +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryBreadcrumbTests.swift @@ -1,5 +1,5 @@ -import XCTest import Sentry +import XCTest class RNSentryBreadcrumbTests: XCTestCase { diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayBreadcrumbConverterTests.swift b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayBreadcrumbConverterTests.swift index 85f4376e6f..00e543aad5 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayBreadcrumbConverterTests.swift +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayBreadcrumbConverterTests.swift @@ -1,5 +1,5 @@ -import XCTest import Sentry +import XCTest final class RNSentryReplayBreadcrumbConverterTests: XCTestCase { @@ -12,7 +12,7 @@ final class RNSentryReplayBreadcrumbConverterTests: XCTestCase { testBreadcrumb.category = "navigation" testBreadcrumb.data = [ "from": "HomeScreen", - "to": "ProfileScreen", + "to": "ProfileScreen" ] let actual = converter.convert(from: testBreadcrumb) @@ -36,7 +36,7 @@ final class RNSentryReplayBreadcrumbConverterTests: XCTestCase { testBreadcrumb.type = "navigation" testBreadcrumb.category = "navigation" testBreadcrumb.data = [ - "to": "ProfileScreen", + "to": "ProfileScreen" ] let actual = converter.convert(from: testBreadcrumb) @@ -48,7 +48,7 @@ final class RNSentryReplayBreadcrumbConverterTests: XCTestCase { assertRRWebBreadcrumbDefaults(actual: event) XCTAssertEqual("info", payload["level"] as! String) XCTAssertEqual("navigation", payload["category"] as! String) - XCTAssertNil(payloadData["from"] ?? nil) + XCTAssertNil(payloadData["from"]) XCTAssertEqual("ProfileScreen", payloadData["to"] as! String) } @@ -63,7 +63,7 @@ final class RNSentryReplayBreadcrumbConverterTests: XCTestCase { XCTAssertNotNil(actual) let event = actual!.serialize() let data = event["data"] as! [String: Any?] - let payload = data["payload"] as! [String: Any?]; + let payload = data["payload"] as! [String: Any?] assertRRWebBreadcrumbDefaults(actual: event) XCTAssertEqual(payload["category"] as! String, "app.foreground") } @@ -79,7 +79,7 @@ final class RNSentryReplayBreadcrumbConverterTests: XCTestCase { XCTAssertNotNil(actual) let event = actual!.serialize() let data = event["data"] as! [String: Any?] - let payload = data["payload"] as! [String: Any?]; + let payload = data["payload"] as! [String: Any?] assertRRWebBreadcrumbDefaults(actual: event) XCTAssertEqual(payload["category"] as! String, "app.background") } @@ -132,18 +132,18 @@ final class RNSentryReplayBreadcrumbConverterTests: XCTestCase { func testTouchMessageReturnsNilOnEmptyArray() throws { let actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(from: []) - XCTAssertEqual(actual, nil); + XCTAssertEqual(actual, nil) } func testTouchMessageReturnsNilOnNilArray() throws { let actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(from: nil as [Any]?) - XCTAssertEqual(actual, nil); + XCTAssertEqual(actual, nil) } func testTouchMessageReturnsNilOnMissingNameAndLevel() throws { let testPath: [Any?] = [["element": "element4", "file": "file4"]] let actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(from: testPath as [Any]) - XCTAssertEqual(actual, nil); + XCTAssertEqual(actual, nil) } func testTouchMessageReturnsMessageOnValidPathExample1() throws { @@ -153,10 +153,10 @@ final class RNSentryReplayBreadcrumbConverterTests: XCTestCase { ["name": "item2", "label": "label2"], ["name": "item3", "label": "label3", "element": "element3"], ["name": "item4", "label": "label4", "file": "file4"], - ["name": "item5", "label": "label5", "element": "element5", "file": "file5"], + ["name": "item5", "label": "label5", "element": "element5", "file": "file5"] ] let actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(from: testPath as [Any]) - XCTAssertEqual(actual, "label3(element3) > label2 > name1 > label0"); + XCTAssertEqual(actual, "label3(element3) > label2 > name1 > label0") } func testTouchMessageReturnsMessageOnValidPathExample2() throws { @@ -166,17 +166,17 @@ final class RNSentryReplayBreadcrumbConverterTests: XCTestCase { ["name": "item4", "label": "label4", "file": "file4"], ["name": "item5", "label": "label5", "element": "element5", "file": "file5"], ["label": "label6"], - ["name": "name7"], + ["name": "name7"] ] let actual = RNSentryReplayBreadcrumbConverter.getTouchPathMessage(from: testPath as [Any]) - XCTAssertEqual(actual, "label5(element5, file5) > label4(file4) > label3(element3) > label2"); + XCTAssertEqual(actual, "label5(element5, file5) > label4(file4) > label3(element3) > label2") } private func assertRRWebBreadcrumbDefaults(actual: [String: Any?]) { let data = actual["data"] as! [String: Any?] let payload = data["payload"] as! [String: Any?] XCTAssertEqual("default", payload["type"] as! String) - XCTAssertEqual((payload["timestamp"] as! Double) * 1000.0, Double(actual["timestamp"] as! Int), accuracy: 1.0) + XCTAssertEqual((payload["timestamp"] as! Double) * 1_000.0, Double(actual["timestamp"] as! Int), accuracy: 1.0) XCTAssertTrue(payload["timestamp"] as! Double > 0.0) } diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift index de21603af8..04a825c682 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift @@ -1,5 +1,5 @@ -import XCTest import Sentry +import XCTest final class RNSentryReplayOptions: XCTestCase { @@ -26,8 +26,8 @@ final class RNSentryReplayOptions: XCTestCase { ] as NSDictionary).mutableCopy() as! NSMutableDictionary RNSentryReplay.updateOptions(optionsDict) - let experimental = optionsDict["experimental"] as! [String:Any] - let sessionReplay = experimental["sessionReplay"] as! [String:Any] + let experimental = optionsDict["experimental"] as! [String: Any] + let sessionReplay = experimental["sessionReplay"] as! [String: Any] assertAllDefaultReplayOptionsAreNotNil(replayOptions: sessionReplay) } @@ -41,8 +41,8 @@ final class RNSentryReplayOptions: XCTestCase { ] as NSDictionary).mutableCopy() as! NSMutableDictionary RNSentryReplay.updateOptions(optionsDict) - let experimental = optionsDict["experimental"] as! [String:Any] - let sessionReplay = experimental["sessionReplay"] as! [String:Any] + let experimental = optionsDict["experimental"] as! [String: Any] + let sessionReplay = experimental["sessionReplay"] as! [String: Any] assertAllDefaultReplayOptionsAreNotNil(replayOptions: sessionReplay) } @@ -57,8 +57,8 @@ final class RNSentryReplayOptions: XCTestCase { ] as NSDictionary).mutableCopy() as! NSMutableDictionary RNSentryReplay.updateOptions(optionsDict) - let experimental = optionsDict["experimental"] as! [String:Any] - let sessionReplay = experimental["sessionReplay"] as! [String:Any] + let experimental = optionsDict["experimental"] as! [String: Any] + let sessionReplay = experimental["sessionReplay"] as! [String: Any] assertAllDefaultReplayOptionsAreNotNil(replayOptions: sessionReplay) } @@ -105,8 +105,8 @@ final class RNSentryReplayOptions: XCTestCase { XCTAssertEqual(optionsDict.count, 3) - let experimental = optionsDict["experimental"] as! [String:Any] - let sessionReplay = experimental["sessionReplay"] as! [String:Any] + let experimental = optionsDict["experimental"] as! [String: Any] + let sessionReplay = experimental["sessionReplay"] as! [String: Any] let maskedViewClasses = sessionReplay["maskedViewClasses"] as! [String] XCTAssertEqual(maskedViewClasses.count, 1) diff --git a/scripts/swiftlint.sh b/scripts/swiftlint.sh new file mode 100755 index 0000000000..9c7b2ec5a8 --- /dev/null +++ b/scripts/swiftlint.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +set -eo pipefail + +# Check if an argument is provided +if [ $# -eq 0 ]; then + echo "Usage: $0 " + exit 1 +fi + +# Set the mode based on the first argument +mode=$1 + +DARWIN_PATH="$(dirname "$0")/../node_modules/@expo/swiftlint/bin/darwin-arm64/swiftlint" +LINUX_PATH="$(dirname "$0")/../node_modules/@expo/swiftlint/bin/linux-x64/swiftlint" + +if [[ "$OSTYPE" == "darwin"* ]]; then + CMD="$DARWIN_PATH" +else + CMD="$LINUX_PATH" +fi + +if [ "$mode" = "fix" ]; then + $CMD --fix +elif [ "$mode" = "lint" ]; then + $CMD --strict +else + echo "Invalid mode. Use 'fix' or 'lint'." + exit 1 +fi diff --git a/yarn.lock b/yarn.lock index 722915a3da..0eb5eee14a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3176,6 +3176,15 @@ __metadata: languageName: node linkType: hard +"@expo/swiftlint@npm:^0.57.1": + version: 0.57.1 + resolution: "@expo/swiftlint@npm:0.57.1" + dependencies: + "@expo/spawn-async": ^1.5.0 + checksum: 87f744bb45cc3a4aa2a40424d21995547c138eef4d4918a3990859c9f143acd3ce463ff3f0c421c0b3e95a694abf7d8fcb8c8545dbe00d81767fc461a68c8378 + languageName: node + linkType: hard + "@expo/vector-icons@npm:^14.0.0": version: 14.0.2 resolution: "@expo/vector-icons@npm:14.0.2" @@ -22891,6 +22900,7 @@ __metadata: version: 0.0.0-use.local resolution: "sentry-react-native@workspace:." dependencies: + "@expo/swiftlint": ^0.57.1 "@sentry/cli": 2.38.2 clang-format: ^1.8.0 downlevel-dts: ^0.11.0