Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(feedback): initial release #4874

Open
wants to merge 19 commits into
base: armcknight/feat(feedback)/final-fixes
Choose a base branch
from

Conversation

armcknight
Copy link
Member

@armcknight armcknight commented Feb 19, 2025

Publicly exposes the feature. For #4709

TODO:

@armcknight armcknight changed the base branch from main to armcknight/feat(feedback)/final-fixes February 19, 2025 23:37
Copy link

github-actions bot commented Feb 19, 2025

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 5024f37

Copy link

codecov bot commented Feb 19, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 92.310%. Comparing base (2ef90a3) to head (5024f37).
Report is 4 commits behind head on armcknight/feat(feedback)/final-fixes.

Additional details and impacted files

Impacted file tree graph

@@                             Coverage Diff                              @@
##           armcknight/feat(feedback)/final-fixes     #4874        +/-   ##
============================================================================
+ Coverage                                  9.094%   92.310%   +83.215%     
============================================================================
  Files                                        350       659       +309     
  Lines                                      24970     77407     +52437     
  Branches                                      94     28024     +27930     
============================================================================
+ Hits                                        2271     71455     +69184     
+ Misses                                     22699      5853     -16846     
- Partials                                       0        99        +99     
Files with missing lines Coverage Δ
SentryTestUtils/TestClient.swift 85.714% <100.000%> (ø)
SentryTestUtils/TestTransportAdapter.swift 84.210% <ø> (ø)
Sources/Sentry/SentryClient.m 98.309% <100.000%> (+88.587%) ⬆️
Sources/Sentry/SentryTransportAdapter.m 100.000% <ø> (+83.076%) ⬆️
Sources/Sentry/SentryUserFeedback.m 100.000% <ø> (+100.000%) ⬆️
...ift/Integrations/UserFeedback/SentryFeedback.swift 72.727% <100.000%> (+72.727%) ⬆️
...ts/Integrations/Feedback/SentryFeedbackTests.swift 97.633% <100.000%> (ø)
...tryTests/Networking/SentryHttpTransportTests.swift 97.250% <100.000%> (ø)
...Tests/Networking/SentryTransportAdapterTests.swift 100.000% <ø> (ø)
...sts/SentryTests/Protocol/SentryEnvelopeTests.swift 96.024% <100.000%> (ø)
... and 4 more

... and 637 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2ef90a3...5024f37. Read the comment docs.

Copy link

github-actions bot commented Feb 19, 2025

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1227.55 ms 1244.76 ms 17.20 ms
Size 22.31 KiB 821.70 KiB 799.39 KiB

Baseline results on branch: armcknight/feat(feedback)/final-fixes

Startup times

Revision Plain With Sentry Diff
f09e892 1220.22 ms 1238.80 ms 18.57 ms
38ae188 1221.04 ms 1246.91 ms 25.87 ms
cc14e49 1209.31 ms 1231.54 ms 22.24 ms

App size

Revision Plain With Sentry Diff
f09e892 22.31 KiB 820.98 KiB 798.67 KiB
38ae188 22.31 KiB 820.94 KiB 798.63 KiB
cc14e49 22.31 KiB 821.57 KiB 799.26 KiB

Previous results on branch: armcknight/feat(feedback)/initial-release

Startup times

Revision Plain With Sentry Diff
331f1be 1197.30 ms 1229.26 ms 31.96 ms
588c9d0 1243.65 ms 1258.61 ms 14.96 ms
2b6f0d6 1221.55 ms 1234.17 ms 12.62 ms

App size

Revision Plain With Sentry Diff
331f1be 22.31 KiB 821.88 KiB 799.56 KiB
588c9d0 22.31 KiB 821.59 KiB 799.28 KiB
2b6f0d6 22.31 KiB 821.70 KiB 799.39 KiB

@armcknight armcknight force-pushed the armcknight/feat(feedback)/initial-release branch from 4957680 to e474fea Compare February 20, 2025 03:01
@armcknight armcknight force-pushed the armcknight/feat(feedback)/initial-release branch from e474fea to 5957494 Compare February 20, 2025 03:16
Comment on lines +1517 to +1521
func testCaptureFeedback_WithEmptyEventId() {
let sut = fixture.getSut()
XCTAssertTrue(fixture.transportAdapter.sendEventWithTraceStateInvocations.isEmpty)
sut.capture(feedback: fixture.feedback, scope: fixture.scope)
XCTAssertFalse(fixture.transportAdapter.sendEventWithTraceStateInvocations.isEmpty)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@philipphofmann LMK what you think of this test. I debugged and traced execution to something I could check, which turned out to be the transport adapter, so just used that. I do see other test cases using sendEventWithTraceStateInvocations as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK to do it like that, and the test should assert some properties of the recorded event. Now it only asserts that there was an event recorded but not that the contents of the event are correct.

@armcknight armcknight marked this pull request as ready for review February 20, 2025 23:33
Copy link
Contributor

@philprime philprime left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a couple of comments, but other than that LGTM

* submits calling the new method @c SentrySDK.captureFeedback (see
* https://docs.sentry.io/platforms/apple/user-feedback/configuration/).
*/
@property (nonatomic, copy, nullable)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Is there any value in not configuring this in the root options, but instead moving it to something like options.userFeedback.configure { ... }, implementing the nested options in Swift instead? Similar to the experimental options

@@ -56,7 +56,7 @@ extension SentryFeedback: SentrySerializable {
if let associatedEventId = associatedEventId {
dict["associated_event_id"] = associatedEventId.sentryIdString
}
dict["source"] = source.rawValue
dict["source"] = source.description
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Just want to point out that in most cases it is bad practice to use description in any serialization, because if the implementation of description in line 7 is removed, the Swift compiler could still synthesize the CustomStringConvertible, and it's not guaranteed to match the raw string value (could include information like Optional<String>)

let sut = SentryFeedback(message: "Test feedback message", name: "Test feedback provider", email: "[email protected]", source: .custom, attachments: [Data()])

let serialization = sut.serialize()
XCTAssertEqual(try XCTUnwrap(serialization["message"] as? String), "Test feedback message")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Why the nesting of XCTUnwrap and XCTAssertEqual? AFAIK the XCTUnwrap is unnecessary, because we can compare serialization["message"] as? String directly to Test feedback message

Copy link
Member

@philipphofmann philipphofmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, with a couple of things to improve, but nothing blocking.

@@ -78,6 +78,28 @@ - (IBAction)captureUserFeedback:(id)sender
[SentrySDK captureUserFeedback:userFeedback];
}

- (IBAction)captureNewUserFeedback:(id)sender
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Using V2 instead of new for naming is usually better. What if we have user feedback V3? Are we going to call it newnew then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah, we talked about this before with the profiling stuff 🤣 I'll change it to V2

Comment on lines +775 to +776
typedef void (^SentryUserFeedbackConfigurationBlock)(
SentryUserFeedbackConfiguration *_Nonnull configuration);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: We have all the other typedefs for the callbacks in the options in SentryDefines.h. You could move it there for consistency.

Comment on lines +781 to +782
* @note This is unrelated to @c SentrySDK.captureUserFeedback which is the old method of submitting
* user feedback you've already gathered via your own UI
Copy link
Member

@philipphofmann philipphofmann Feb 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: I would write about deprecated instead of old.

Suggested change
* @note This is unrelated to @c SentrySDK.captureUserFeedback which is the old method of submitting
* user feedback you've already gathered via your own UI
* @note This is unrelated to @c SentrySDK.captureUserFeedback , which is the deprecated method of submitting
* user feedback you've already gathered via your own UI

Comment on lines +783 to +784
* (see https://docs.sentry.io/platforms/apple/user-feedback/#user-feedback-api). The new method
* uses either this block to configure and a widget and UI form to gather feedback, or directly
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l:

Suggested change
* (see https://docs.sentry.io/platforms/apple/user-feedback/#user-feedback-api). The new method
* uses either this block to configure and a widget and UI form to gather feedback, or directly
* (see https://docs.sentry.io/platforms/apple/user-feedback/#user-feedback-api). This method
* uses either this block to configure and a widget and UI form to gather feedback, or directly

assertNothingSent()
}

@available(*, deprecated, message: "This is only marked as deprecated because assertNothingSent is marked as deprecated, due to it using a deprecated property inside it. When that property usage is removed, this deprecation annotation can go away.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my god this repetition is very annoying 🤦. We will fix it later.

Comment on lines +1517 to +1521
func testCaptureFeedback_WithEmptyEventId() {
let sut = fixture.getSut()
XCTAssertTrue(fixture.transportAdapter.sendEventWithTraceStateInvocations.isEmpty)
sut.capture(feedback: fixture.feedback, scope: fixture.scope)
XCTAssertFalse(fixture.transportAdapter.sendEventWithTraceStateInvocations.isEmpty)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK to do it like that, and the test should assert some properties of the recorded event. Now it only asserts that there was an event recorded but not that the contents of the event are correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants