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

Source Retently - Add Feedback, NPS Score, Campaigns streams #19381

Merged
merged 8 commits into from
Dec 16, 2022

Conversation

schlattk
Copy link
Contributor

@schlattk schlattk commented Nov 14, 2022

What

Added streams for source retently: feedback, nps score, campaigns
fixed failing connection check on Companies stream

How

added streams to source.py as well as new schemas
changed check_connection to use customers stream

Recommended reading order

  1. x.java
  2. y.python

🚨 User Impact 🚨

User has access to more streams, check_connection fails when companies stream is empty so changed it to use customer stream which will always have data.

Pre-merge Checklist

Expand the relevant checklist and delete the others.

New Connector

Community member or Airbyter

  • Community member? Grant edit access to maintainers (instructions)
  • Secrets in the connector's spec are annotated with airbyte_secret
  • Unit & integration tests added and passing. Community members, please provide proof of success locally e.g: screenshot or copy-paste unit, integration, and acceptance test output. To run acceptance tests for a Python connector, follow instructions in the README. For java connectors run ./gradlew :airbyte-integrations:connectors:<name>:integrationTest.
  • Code reviews completed
  • Documentation updated
    • Connector's README.md
    • Connector's bootstrap.md. See description and examples
    • docs/integrations/<source or destination>/<name>.md including changelog. See changelog example
    • docs/integrations/README.md
    • airbyte-integrations/builds.md
  • PR name follows PR naming conventions

Airbyter

If this is a community PR, the Airbyte engineer reviewing this PR is responsible for the below items.

  • Create a non-forked branch based on this PR and test the below items on it
  • Build is successful
  • If new credentials are required for use in CI, add them to GSM. Instructions.
  • /test connector=connectors/<name> command is passing
  • New Connector version released on Dockerhub by running the /publish command described here
  • After the connector is published, connector added to connector index as described here
  • Seed specs have been re-generated by building the platform and committing the changes to the seed spec files, as described here
Updating a connector

Community member or Airbyter

  • Grant edit access to maintainers (instructions)
  • Secrets in the connector's spec are annotated with airbyte_secret
  • Unit & integration tests added and passing. Community members, please provide proof of success locally e.g: screenshot or copy-paste unit, integration, and acceptance test output. To run acceptance tests for a Python connector, follow instructions in the README. For java connectors run ./gradlew :airbyte-integrations:connectors:<name>:integrationTest.
  • Code reviews completed
  • Documentation updated
    • Connector's README.md
    • Connector's bootstrap.md. See description and examples
    • Changelog updated in docs/integrations/<source or destination>/<name>.md including changelog. See changelog example
  • PR name follows PR naming conventions

Airbyter

If this is a community PR, the Airbyte engineer reviewing this PR is responsible for the below items.

  • Create a non-forked branch based on this PR and test the below items on it
  • Build is successful
  • If new credentials are required for use in CI, add them to GSM. Instructions.
  • /test connector=connectors/<name> command is passing
  • New Connector version released on Dockerhub and connector version bumped by running the /publish command described here
Connector Generator
  • Issue acceptance criteria met
  • PR name follows PR naming conventions
  • If adding a new generator, add it to the list of scaffold modules being tested
  • The generator test modules (all connectors with -scaffold in their name) have been updated with the latest scaffold by running ./gradlew :airbyte-integrations:connector-templates:generator:testScaffoldTemplates then checking in your changes
  • Documentation which references the generator is updated as needed

Tests

Unit

Put your unit tests output here.

Test session starts (platform: darwin, Python 3.9.7, pytest 6.2.5, pytest-sugar 0.9.6)
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/Users/konrad/retently-fork/airbyte/airbyte-integrations/connectors/source-retently/.hypothesis/examples')
rootdir: /Users/konrad/retently-fork/airbyte, configfile: pytest.ini
plugins: hypothesis-6.54.6, requests-mock-1.9.3, mock-3.6.1, sugar-0.9.6, timeout-1.4.2, cov-3.0.0
collecting ...
airbyte-integrations/connectors/source-retently/unit_tests/test_source.py::test_check_connection ✓ 8% ▉
airbyte-integrations/connectors/source-retently/unit_tests/test_source.py::test_streams ✓ 17% █▋
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py::test_request_params ✓ 25% ██▌
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py::test_next_page_token ✓ 33% ███▍
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py::test_parse_response ✓ 42% ████▎
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py::test_request_headers ✓ 50% █████
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py::test_http_method ✓ 58% █████▉
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py::test_should_retry[HTTPStatus.OK-False] ✓ 67% ██████▋
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py::test_should_retry[HTTPStatus.BAD_REQUEST-False] ✓ 75% ███████▌
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py::test_should_retry[HTTPStatus.TOO_MANY_REQUESTS-True] ✓ 83% ████████▍
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py::test_should_retry[HTTPStatus.INTERNAL_SERVER_ERROR-True] ✓ 92% █████████▎
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py::test_backoff_time ✓ 100% ██████████
================================================================================== warnings summary ===================================================================================
airbyte-integrations/connectors/source-retently/unit_tests/test_source.py::test_check_connection
airbyte-integrations/connectors/source-retently/unit_tests/test_source.py::test_streams
/Users/konrad/retently-fork/airbyte/airbyte-integrations/connectors/source-retently/source_retently/source.py:33: DeprecationWarning: Call to deprecated class TokenAuthenticator. (Use airbyte_cdk.sources.streams.http.requests_native_auth.TokenAuthenticator instead) -- Deprecated since version 0.1.20.
return TokenAuthenticator(token="", auth_method=auth_method)

airbyte-integrations/connectors/source-retently/unit_tests/test_source.py: 9 warnings
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py: 10 warnings
/Users/konrad/retently-fork/airbyte/airbyte-integrations/connectors/source-retently/.venv/lib/python3.9/site-packages/deprecated/classic.py:173: DeprecationWarning: Call to deprecated class HttpAuthenticator. (Use requests.auth.AuthBase instead) -- Deprecated since version 0.1.20.
return old_new1(cls, *args, **kwargs)

airbyte-integrations/connectors/source-retently/unit_tests/test_source.py: 7 warnings
airbyte-integrations/connectors/source-retently/unit_tests/test_streams.py: 10 warnings
/Users/konrad/retently-fork/airbyte/airbyte-integrations/connectors/source-retently/.venv/lib/python3.9/site-packages/airbyte_cdk/sources/streams/http/http.py:43: DeprecationWarning: Call to deprecated class NoAuth. (Set authenticator=None instead) -- Deprecated since version 0.1.20.
self._authenticator: HttpAuthenticator = NoAuth()

-- Docs: https://docs.pytest.org/en/stable/warnings.html

Results (0.77s):
12 passed

Integration

Put your integration tests output here.

Acceptance

Put your acceptance tests output here.

@sajarin sajarin changed the title add streams to source retently Source Retently - Add Feedback, NPS Score, Campaigns streams Nov 18, 2022
@sajarin sajarin added the bounty-M Maintainer program: claimable medium bounty PR label Nov 18, 2022
@marcosmarxm
Copy link
Member

Hello 👋, first thank you for this amazing contribution.

We really appreciate the effort you've made to improve the project.
We ask you patience for the code review. Last month our team was focused on Hacktoberfest event and that probably left some PR without the proper feedback. And this week, due to the Thanksgiving US Holiday, most our team is out of office with their families. Another important piece of information why code won't be merge this week is: as a safety measure the core team has decided to freeze merging code to main branch to keep the release stable. Next week we'll return to you with the proper code review and update the status of your contribution.

If you have any questions feel free to send me a message in Slack!
Thanks!

@cptjacky
Copy link
Contributor

cptjacky commented Nov 28, 2022

Hello @schlattk and thank you for this contribution!

I will be reviewing your PR tomorrow!

(cc @sajarin)

Copy link
Contributor

@cptjacky cptjacky left a comment

Choose a reason for hiding this comment

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

Hello @schlattk, I am sorry for the delay!

Thank you again for your contribution.

I made a couple of comments on your PR, feel free to come back to and/or challenge me if something is unclear!

Also, could you post a screenshot of the acceptance tests' output after your changes?

if stream_data:
for d in stream_data:
yield d
data = response.json().get("data") or response.json()
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be better to be explicit depending on the stream, and therefore surcharge the parse_response when the expected response differs.

It should make potential errors easier to spot!

yield d
data = response.json().get("data") or response.json()
stream_data = data.get(self.json_path) if self.json_path else data
if type(stream_data) == list :
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as above: since it seems that this is for only one specific stream (nps), I think it would be better to override the parse_response method of that specific stream.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks @cptjacky
do you mean to do it in the parse_response method something like if self.name == nps yield x else yield y?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hey @schlattk, I meant defining a different parse_response method on the NpsStream class itself (no if required in that situation)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cptjacky do you have an example of another source where it is done in this way?

Copy link
Contributor

@cptjacky cptjacky Dec 7, 2022

Choose a reason for hiding this comment

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

@schlattk https://github.com/airbytehq/airbyte/blob/master/airbyte-integrations/connectors/source-intercom/source_intercom/source.py#L342, the main class has a default parse_response, and then other streams define another parse_response with a different logic

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok @cptjacky I have implemented this now but some of the acceptance tests are failing not sure why as it doesn't seem to relate to changes I made. Would be interesting to see whether they also fail with the Airbyte test account credentials. Happy to run it if you can share the credentials

Results (333.83s): 23 passed 6 failed - airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:109 TestSpec.test_match_expected[inputs0] - airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:121 TestSpec.test_enum_usage[inputs0] - airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:135 TestSpec.test_oneof_usage[inputs0] - airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:313 TestSpec.test_additional_properties_is_true[inputs0] - airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:330 TestConnection.test_check[inputs2] - airbyte-integrations/bases/source-acceptance-test/source_acceptance_test/tests/test_core.py:638 TestBasicRead.test_read[inputs0]

@cptjacky
Copy link
Contributor

cptjacky commented Dec 8, 2022

Hey @schlattk, for some of these errors (the ones I can run without credentials), it seems to be because new versions of the acceptance-tests are more rigid about deprecated keys.

In our specific case, I think we need to take a look at the spec.json file.

diff --git a/airbyte-integrations/connectors/source-retently/source_retently/spec.json b/airbyte-integrations/connectors/source-retently/source_retently/spec.json
index 56042fff6d..59b7f34080 100644
--- a/airbyte-integrations/connectors/source-retently/source_retently/spec.json
+++ b/airbyte-integrations/connectors/source-retently/source_retently/spec.json
@@ -20,8 +20,6 @@
               "auth_type": {
                 "type": "string",
                 "const": "Client",
-                "enum": ["Client"],
-                "default": "Client",
                 "order": 0
               },
               "client_id": {
@@ -52,8 +50,6 @@
               "auth_type": {
                 "type": "string",
                 "const": "Token",
-                "enum": ["Token"],
-                "default": "Token",
                 "order": 0
               },
               "api_key": {

This diff should fix at least 2 or 3 errors. Can you try it and send me a screenshot of the acceptance tests?

If there is still errors, could you also paste the errors here?

Thank you!

@schlattk
Copy link
Contributor Author

schlattk commented Dec 9, 2022

@cptjacky errors are still the same - any chance we can run this with test credentials?

@sajarin
Copy link
Contributor

sajarin commented Dec 9, 2022

/test connector=connectors/source-retently

🕑 connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3657667587
❌ connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3657667587
🐛

@schlattk
Copy link
Contributor Author

schlattk commented Dec 9, 2022

@sajarin @cptjacky where can I find the test output?

@sajarin
Copy link
Contributor

sajarin commented Dec 12, 2022

/test connector=connectors/source-retently

🕑 connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3677560520
❌ connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3677560520
🐛

@sajarin
Copy link
Contributor

sajarin commented Dec 12, 2022

@schlattk can you rebase on master? The CI was breaking before and we fixed it on master but it's not being reflected on your branch.

@sajarin
Copy link
Contributor

sajarin commented Dec 13, 2022

/test connector=connectors/source-retently

🕑 connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3687825961
❌ connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3687825961
🐛 https://gradle.com/s/cef6i2coeozwq

Build Failed

Test summary info:

=========================== short test summary info ============================
FAILED test_core.py::TestSpec::test_oneof_usage[inputs0] - AssertionError: Th...
FAILED test_core.py::TestBasicRead::test_read[inputs0] - AttributeError: 'lis...
SKIPPED [1] ../usr/local/lib/python3.9/site-packages/source_acceptance_test/plugin.py:63: Skipping TestFullRefresh.test_sequential_reads: not found in the config.
SKIPPED [1] ../usr/local/lib/python3.9/site-packages/source_acceptance_test/plugin.py:63: Skipping TestIncremental.test_two_sequential_reads: not found in the config.
============ 2 failed, 27 passed, 2 skipped, 29 warnings in 29.57s =============

@cptjacky
Copy link
Contributor

cptjacky commented Dec 13, 2022

Hey @schlattk, the two fails here should be fixed by the diff I proposed earlier, can you apply it to this PR?

@schlattk
Copy link
Contributor Author

Hi @cptjacky, I have made those changes - can you run tests again please

@sajarin
Copy link
Contributor

sajarin commented Dec 14, 2022

/test connector=connectors/source-retently

🕑 connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3693815623
❌ connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3693815623
🐛 https://gradle.com/s/ulu5mmer5s35g

Build Failed

Test summary info:

=========================== short test summary info ============================
FAILED test_core.py::TestSpec::test_additional_properties_is_true[inputs0] - ...
FAILED test_core.py::TestBasicRead::test_read[inputs0] - AttributeError: 'lis...
SKIPPED [1] ../usr/local/lib/python3.9/site-packages/source_acceptance_test/plugin.py:63: Skipping TestFullRefresh.test_sequential_reads: not found in the config.
SKIPPED [1] ../usr/local/lib/python3.9/site-packages/source_acceptance_test/plugin.py:63: Skipping TestIncremental.test_two_sequential_reads: not found in the config.
============ 2 failed, 27 passed, 2 skipped, 29 warnings in 33.01s =============

@schlattk
Copy link
Contributor Author

Hi @cptjacky We have still two failing tests not sure I understand why. Are they passing if you run them on the current version?

Copy link
Contributor

@cptjacky cptjacky left a comment

Choose a reason for hiding this comment

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

Hey @schlattk, I added a comment I think is responsible for one fail. You should also re-set the additionalProperties to true like it was before your last commit I think

Comment on lines 28 to 30
"additionalQuestions": [],
"feedbackTags": [],
"notes": [],
Copy link
Contributor

Choose a reason for hiding this comment

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

I think these fields in the schema are not valid. Their definition should be an object, not an empty list

@sajarin
Copy link
Contributor

sajarin commented Dec 15, 2022

@schlattk just bumping this, are you able to address the comments above? We're trying to get this merged before the end of the week. Otherwise it might get even more delayed because of the upcoming holidays. We're fairly close to finishing the review here. Let me know what I can do to help.

@schlattk
Copy link
Contributor Author

@sajarin changes made

@sajarin
Copy link
Contributor

sajarin commented Dec 15, 2022

/test connector=connectors/source-retently

🕑 connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3704361307
❌ connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3704361307
🐛 https://gradle.com/s/peusw3v6cyrim

Build Failed

Test summary info:

=========================== short test summary info ============================
FAILED test_core.py::TestBasicRead::test_read[inputs0] - Failed: Please check...
SKIPPED [1] ../usr/local/lib/python3.9/site-packages/source_acceptance_test/plugin.py:63: Skipping TestFullRefresh.test_sequential_reads: not found in the config.
SKIPPED [1] ../usr/local/lib/python3.9/site-packages/source_acceptance_test/plugin.py:63: Skipping TestIncremental.test_two_sequential_reads: not found in the config.
============ 1 failed, 28 passed, 2 skipped, 29 warnings in 31.30s =============

@sajarin
Copy link
Contributor

sajarin commented Dec 15, 2022

@schlattk @cptjacky take a look at the above test run, looks like there are some issues with the schema.

Copy link
Contributor

@cptjacky cptjacky left a comment

Choose a reason for hiding this comment

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

Hey @schlattk, please see my latest comments on the schema

@sajarin
Copy link
Contributor

sajarin commented Dec 15, 2022

/test connector=connectors/source-retently

🕑 connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3705240249
✅ connectors/source-retently https://github.com/airbytehq/airbyte/actions/runs/3705240249
Python tests coverage:

Name                          Stmts   Miss  Cover
-------------------------------------------------
source_retently/__init__.py       2      0   100%
source_retently/source.py        94     18    81%
-------------------------------------------------
TOTAL                            96     18    81%
	 Name                                                 Stmts   Miss  Cover   Missing
	 ----------------------------------------------------------------------------------
	 source_acceptance_test/base.py                          12      4    67%   16-19
	 source_acceptance_test/config.py                       140      5    96%   87, 93, 238, 242-243
	 source_acceptance_test/conftest.py                     208     92    56%   36, 42-44, 49, 54, 77, 83, 89-91, 110, 115-117, 123-125, 131-132, 137-138, 143, 149, 158-167, 173-178, 193, 217, 248, 254, 262-267, 275-280, 288-301, 306-312, 319-330, 337-353
	 source_acceptance_test/plugin.py                        69     25    64%   22-23, 31, 36, 120-140, 144-148
	 source_acceptance_test/tests/test_core.py              398    111    72%   53, 58, 87-95, 100-107, 111-112, 116-117, 299, 337-354, 363-371, 375-380, 386, 419-424, 462-469, 512-514, 517, 582-590, 602-605, 610, 666-667, 673, 676, 712-722, 735-760
	 source_acceptance_test/tests/test_incremental.py       158     14    91%   52-59, 64-77, 240
	 source_acceptance_test/utils/asserts.py                 39      2    95%   62-63
	 source_acceptance_test/utils/common.py                  94     10    89%   16-17, 32-38, 72, 75
	 source_acceptance_test/utils/compare.py                 62     23    63%   21-51, 68, 97-99
	 source_acceptance_test/utils/connector_runner.py       133     33    75%   24-27, 46-47, 50-54, 57-58, 73-75, 78-80, 83-85, 88-90, 93-95, 124-125, 159-161, 208
	 source_acceptance_test/utils/json_schema_helper.py     107     13    88%   30-31, 38, 41, 65-68, 96, 120, 192-194
	 ----------------------------------------------------------------------------------
	 TOTAL                                                 1599    332    79%

Build Passed

Test summary info:

=========================== short test summary info ============================
SKIPPED [1] ../usr/local/lib/python3.9/site-packages/source_acceptance_test/plugin.py:63: Skipping TestFullRefresh.test_sequential_reads: not found in the config.
SKIPPED [1] ../usr/local/lib/python3.9/site-packages/source_acceptance_test/plugin.py:63: Skipping TestIncremental.test_two_sequential_reads: not found in the config.
================= 29 passed, 2 skipped, 29 warnings in 35.81s ==================

@sajarin sajarin self-requested a review December 15, 2022 15:32
@sajarin
Copy link
Contributor

sajarin commented Dec 15, 2022

/publish connector=connectors/source-retently

🕑 Publishing the following connectors:
connectors/source-retently
https://github.com/airbytehq/airbyte/actions/runs/3705566689


Connector Did it publish? Were definitions generated?
connectors/source-retently

if you have connectors that successfully published but failed definition generation, follow step 4 here ▶️

@cptjacky
Copy link
Contributor

I'm sorry, it looks like we forgot to bump the version in the Dockerfile!

@schlattk or @sajarin if one of you could bump it 🙏

@schlattk
Copy link
Contributor Author

@cptjacky ok to level 0.1.3?

@sajarin
Copy link
Contributor

sajarin commented Dec 15, 2022

Should be good to publish and merge soon, just waiting on an issue on master to clear up before triggering the CI again

@sajarin
Copy link
Contributor

sajarin commented Dec 16, 2022

/publish connector=connectors/source-retently

🕑 Publishing the following connectors:
connectors/source-retently
https://github.com/airbytehq/airbyte/actions/runs/3708985429


Connector Did it publish? Were definitions generated?
connectors/source-retently

if you have connectors that successfully published but failed definition generation, follow step 4 here ▶️

@schlattk
Copy link
Contributor Author

@sajarin @cptjacky let me know if there's anything I can do on those fails

@sajarin
Copy link
Contributor

sajarin commented Dec 16, 2022

Hey @schlattk the CI failed to generate definitions because it couldn't commit to your branch.

Could you bump the source-retently version in airbyte-config/init/src/main/resources/seed/source_definitions.yaml
and then run the ./gradlew :airbyte-config:init:processResources command in the root airbyte folder and then commit the changes?

Let me know if you run into any issues

@schlattk
Copy link
Contributor Author

I'm having some issues running gradle command

@sajarin
Copy link
Contributor

sajarin commented Dec 16, 2022

what's the issue? Can you post logs/screenshots?

@schlattk
Copy link
Contributor Author

@sajarin I'm on mac - getting this although jdk is installed
`org.gradle.api.internal.catalog.GeneratedClassCompilationException: No Java compiler found, please ensure you are running Gradle with a JDK

No Java compiler found, please ensure you are running Gradle with a JDK`

@sajarin
Copy link
Contributor

sajarin commented Dec 16, 2022

I'll merge this and then generate the definitions in a separate PR. Thanks for your contribution @schlattk and thanks for the review @cptjacky!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/connectors Connector related issues bounty bounty-M Maintainer program: claimable medium bounty PR community connectors/source/retently
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

5 participants