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 Intercom: Update Intercom API to version 2.5 #15681

Merged
merged 6 commits into from
Aug 18, 2022

Conversation

alex-gron
Copy link
Contributor

@alex-gron alex-gron commented Aug 16, 2022

What

Upgrade Intercom API from v2.2 to v2.5
Primary use case is to pull in custom_attributes on the Conversation object
Closes #15141

How

Increment API version to 2.5
Update schema.json to include custom_attributes

🚨 User Impact 🚨

Backwards compatible with earlier API versions

Pre-merge Checklist

Expand the relevant checklist and delete the others.

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

Tests

Unit

See below

Integration

See below

Acceptance

See below

@alex-gron
Copy link
Contributor Author

Unit Tests:

(.venv) alexgronemeyer@Alexs-MacBook-Pro source-intercom % python -m pytest unit_tests                                       
Test session starts (platform: darwin, Python 3.9.11, pytest 6.1.2, pytest-sugar 0.9.5)
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/.hypothesis/examples')
rootdir: /Users/alexgronemeyer/src/airbyte, configfile: pytest.ini
plugins: sugar-0.9.5, requests-mock-1.9.3, mock-3.6.1, hypothesis-6.54.3, timeout-1.4.2, cov-3.0.0
collecting ... 
 airbyte-integrations/connectors/source-intercom/unit_tests/test_cached_stream_state.py::test_full_refresh[Sync Started. Parent.] ✓                             3% ▍         
 airbyte-integrations/connectors/source-intercom/unit_tests/test_cached_stream_state.py::test_full_refresh[Sync Started. Child.] ✓                              6% ▋         
 airbyte-integrations/connectors/source-intercom/unit_tests/test_cached_stream_state.py::test_incremental_sync[Sync Started. Parent] ✓                          9% ▉         
 airbyte-integrations/connectors/source-intercom/unit_tests/test_cached_stream_state.py::test_incremental_sync[Sync Started. Child] ✓                          12% █▍        
 airbyte-integrations/connectors/source-intercom/unit_tests/test_cached_stream_state.py::test_incremental_sync[Sync in progress. Parent] ✓                     16% █▋        
 airbyte-integrations/connectors/source-intercom/unit_tests/test_cached_stream_state.py::test_incremental_sync[Sync in progress. Child] ✓                      19% █▉        
 airbyte-integrations/connectors/source-intercom/unit_tests/test_control_rate_limit.py::test_with_unknown_load[On UNKNOWN load] ✓                              22% ██▎       
 airbyte-integrations/connectors/source-intercom/unit_tests/test_control_rate_limit.py::test_with_unknown_load[On Low Load] ✓                                  25% ██▌       
 airbyte-integrations/connectors/source-intercom/unit_tests/test_control_rate_limit.py::test_with_unknown_load[On Mid Load] ✓                                  28% ██▊       
 airbyte-integrations/connectors/source-intercom/unit_tests/test_control_rate_limit.py::test_with_unknown_load[On High Load] ✓                                 31% ███▎      
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_get_next_page_token[base pagination] ✓                                          34% ███▌      
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_get_next_page_token[companies pagination] ✓                                     38% ███▊      
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_get_next_page_token[contacts pagination] ✓                                      41% ████▏     {"type": "LOG", "log": {"level": "INFO", "message": "Backing off _send(...) for 0.0s (airbyte_cdk.sources.streams.http.exceptions.UserDefinedBackoffException: Request URL: https://api.intercom.io/companies/scroll?per_page=50&scroll_param=expired_scroll_param, Response Code: 404, Response Text: {\"errors\": [{\"code\": \"not_found\", \"message\": \"scroll parameter not found\"}]})"}}
{"type": "LOG", "log": {"level": "INFO", "message": "Retrying. Sleeping for 0.01 seconds"}}
{"type": "LOG", "log": {"level": "ERROR", "message": "Can't create a new scroll request within an minute or scroll param was expired. Let's try to use a standard non-scroll endpoint."}}

 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_switch_to_standard_endpoint_if_scroll_expired ✓                                 44% ████▍     
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_check_connection_ok ✓                                                           47% ████▊     
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_check_connection_empty_config ✓                                                 50% █████     
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_check_connection_invalid_config ✓                                               53% █████▍    
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_check_connection_exception ✓                                                    56% █████▋    {"type": "LOG", "log": {"level": "INFO", "message": "Using start_date: 1647752400.0"}}

 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_streams ✓                                                                       59% █████▉    
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[Admins-GET-/admins-response0-expected0] ✓                                  62% ██████▍   
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[Companies-GET-/companies/scroll-response1-expected1] ✓                     66% ██████▋   
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[CompanySegments-GET-/companies/id/segments-response2-expected2] ✓          69% ██████▉   
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[Contacts-POST-/contacts/search-response3-expected3] ✓                      72% ███████▎  
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[Conversations-POST-/conversations/search-response4-expected4] ✓            75% ███████▌  
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[ConversationParts-GET-/conversations/id-response5-expected5] ✓             78% ███████▊  
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[CompanyAttributes-GET-/data_attributes-response6-expected6] ✓              81% ████████▎ 
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[ContactAttributes-GET-/data_attributes-response7-expected7] ✓              84% ████████▌ 
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[Segments-GET-/segments-response8-expected8] ✓                              88% ████████▊ 
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[Tags-GET-/tags-response9-expected9] ✓                                      91% █████████▏
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_read[Teams-GET-/teams-response10-expected10] ✓                                  94% █████████▍
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_conversation_part_has_conversation_id ✓                                         97% █████████▊
 airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_conversation_part_filtering_based_on_conversation ✓                            100% ██████████
============================================================================= warnings summary ==============================================================================
unit_tests/test_cached_stream_state.py:12
  /Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/unit_tests/test_cached_stream_state.py:12: DeprecationWarning: Call to deprecated class NoAuth. (Set `authenticator=None` instead) -- Deprecated since version 0.1.20.
    INTERCOM_STREAM = Conversations(authenticator=NoAuth(), start_date=0)

.venv/lib/python3.9/site-packages/deprecated/classic.py:173: 4 warnings
airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py: 54 warnings
  /Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/.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)

.venv/lib/python3.9/site-packages/airbyte_cdk/sources/streams/http/http.py:41: 2 warnings
airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py: 40 warnings
  /Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/.venv/lib/python3.9/site-packages/airbyte_cdk/sources/streams/http/http.py:41: DeprecationWarning: Call to deprecated class NoAuth. (Set `authenticator=None` instead) -- Deprecated since version 0.1.20.
    self._authenticator: HttpAuthenticator = NoAuth()

unit_tests/test_cached_stream_state.py:13
  /Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/unit_tests/test_cached_stream_state.py:13: DeprecationWarning: Call to deprecated class NoAuth. (Set `authenticator=None` instead) -- Deprecated since version 0.1.20.
    INTERCOM_SUB_STREAM = ConversationParts(authenticator=NoAuth(), start_date=0)

unit_tests/unit_test.py:27
  /Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py:27: DeprecationWarning: Call to deprecated class AirbyteLogger. (Use logging.getLogger('airbyte') instead) -- Deprecated since version 0.1.47.
    logger = AirbyteLogger()

airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_switch_to_standard_endpoint_if_scroll_expired
  /Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py:87: DeprecationWarning: Call to deprecated class NoAuth. (Set `authenticator=None` instead) -- Deprecated since version 0.1.20.
    stream1 = Companies(authenticator=NoAuth())

airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_streams
  /Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/source_intercom/source.py:526: DeprecationWarning: Call to deprecated class AirbyteLogger. (Use logging.getLogger('airbyte') instead) -- Deprecated since version 0.1.47.
    AirbyteLogger().log("INFO", f"Using start_date: {config['start_date']}")

airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py: 11 warnings
  /Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py:210: DeprecationWarning: Call to deprecated class NoAuth. (Set `authenticator=None` instead) -- Deprecated since version 0.1.20.
    stream = stream(authenticator=NoAuth(), start_date=0)

airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_conversation_part_has_conversation_id
  /Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py:309: DeprecationWarning: Call to deprecated class NoAuth. (Set `authenticator=None` instead) -- Deprecated since version 0.1.20.
    conversation_parts = ConversationParts(authenticator=NoAuth())

airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py::test_conversation_part_filtering_based_on_conversation
  /Users/alexgronemeyer/src/airbyte/airbyte-integrations/connectors/source-intercom/unit_tests/unit_test.py:335: DeprecationWarning: Call to deprecated class NoAuth. (Set `authenticator=None` instead) -- Deprecated since version 0.1.20.
    conversation_parts = ConversationParts(authenticator=NoAuth(), start_date=0)

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

Results (21.03s):
      32 passed

@alex-gron alex-gron changed the title Alex/update intercom api v25 Source Intercom: Update Intercom API to version 2.5 Aug 16, 2022
@ChristopheDuong
Copy link
Contributor

ChristopheDuong commented Aug 16, 2022

/test connector=connectors/source-intercom

🕑 connectors/source-intercom https://github.com/airbytehq/airbyte/actions/runs/2868967996
❌ connectors/source-intercom https://github.com/airbytehq/airbyte/actions/runs/2868967996
🐛 https://gradle.com/s/b56jbpiycjwz2

Build Failed

Test summary info:

	 =========================== short test summary info ============================
	 SKIPPED [9] integration_tests/integration_test.py:33: need to refresh this test, it is very slow
	 �[33m============= �[32m2 passed�[0m, �[33m�[1m9 skipped�[0m, �[33m�[1m27 warnings�[0m�[33m in 71.28s (0:01:11)�[0m�[33m =============�[0m
=========================== short test summary info ============================
FAILED test_core.py::TestBasicRead::test_read[inputs0] - Failed: Stream conve...
=================== 1 failed, 28 passed in 85.31s (0:01:25) ====================

🕑 connectors/source-intercom https://github.com/airbytehq/airbyte/actions/runs/2868967996
❌ connectors/source-intercom https://github.com/airbytehq/airbyte/actions/runs/2868967996
🐛 https://gradle.com/s/agtksux4pam6e

Build Failed

Test summary info:

	 =========================== short test summary info ============================
	 SKIPPED [9] integration_tests/integration_test.py:33: need to refresh this test, it is very slow
	 �[33m============= �[32m2 passed�[0m, �[33m�[1m9 skipped�[0m, �[33m�[1m27 warnings�[0m�[33m in 69.45s (0:01:09)�[0m�[33m =============�[0m
=========================== short test summary info ============================
FAILED test_core.py::TestBasicRead::test_read[inputs0] - Failed: Stream conve...
=================== 1 failed, 28 passed in 90.01s (0:01:30) ====================

@@ -119,7 +119,9 @@
}
}
},
"priority": {
"custom_attributes": {
"type": ["null", "object"]
Copy link
Contributor

@ChristopheDuong ChristopheDuong Aug 17, 2022

Choose a reason for hiding this comment

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

Would we want to optionally specify in the connector spec (configuration) the custom JSON Schema for that field though? If left empty, it could default to object.

But if the user is able to describe what kind of data is being recorded there in the source API, then normalization would be able to handle the extra data in a more well-structured manner...

Is that worth exposing to the connector configuration?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The ultimate goal is to bring in in all of the custom_attributes that are configured in Intercom (similar to how the Salesforce connector works to bring in all custom fields).

The data is stored as "key:value" in Intercom (source), so I don't think we need to allow for JSON in the config since it is relatively simple.

Let me know if I am misunderstanding here though!

Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible for you to share an example of a record from intercom that includes data in the "custom_attributes" column?

Here in the test / expected results from this PR, it's left empty:

"custom_attributes": {},

So it's not super insightful on how it'd be presented and used by users afterwards

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes - we don't have any custom attributes created on our Test Intercom account, so that is why they are empty in the example and integration test.

Here is an example result from the prod Intercom account:

"custom_attributes":{"Needed Escalation":false,"Follow Up Required":false,"Chat Closed Reason":"Alpha Connector Issue"}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It ends up in the database as a json column where you can extract the keys/values as follows:

select 
    json_extract_scalar(custom_attributes, "$.Needed Escalation") as needed_escalation,
    json_extract_scalar(custom_attributes, "$.Follow Up Required") as follow_up_required,
    json_extract_scalar(custom_attributes, "$.Chat Closed Reason") as chat_closed_reason
from conversations

Copy link
Contributor

@ChristopheDuong ChristopheDuong Aug 18, 2022

Choose a reason for hiding this comment

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

yes, so when running the discover command, if the catalog would be able to contain:

"custom_attributes": {
      "type": ["null", "object"]
      "properties": {
            "Needed Escalation": {
                    "type": ["null", "string"]
            },
            "Follow Up Required": {
                    "type": ["null", "string"]
            },
            "Chat Closed Reason": {
                    "type": ["null", "string"]
            }
      } 
}

then normalization would be able to generate the json_extract lines that you linked automatically too

Of course, just having the json column custom_attributes is already a good move forward already!

Copy link
Collaborator

@bazarnov bazarnov Aug 18, 2022

Choose a reason for hiding this comment

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

The logic for custom_attributes should be applied, we need to nest all keys into "key" and all the value into "value", than modify the json_schema with this change and it will work correctly for all possible key:value pairs custom_attributes holds.

We can do this now or later on, if we move with the change like in this PR - it's totally ok, but there is a right way to do it, so probably we will make it in the future updates.

@alex-gron
Copy link
Contributor Author

alex-gron commented Aug 18, 2022

/test connector=connectors/source-intercom

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

Name                          Stmts   Miss  Cover
-------------------------------------------------
source_intercom/__init__.py       2      0   100%
source_intercom/utils.py         60      8    87%
source_intercom/source.py       256     42    84%
-------------------------------------------------
TOTAL                           318     50    84%
Name                          Stmts   Miss  Cover
-------------------------------------------------
source_intercom/__init__.py       2      0   100%
source_intercom/utils.py         60      1    98%
source_intercom/source.py       256     21    92%
-------------------------------------------------
TOTAL                           318     22    93%
	 Name                                                 Stmts   Miss  Cover   Missing
	 ----------------------------------------------------------------------------------
	 source_acceptance_test/base.py                          10      4    60%   15-18
	 source_acceptance_test/config.py                        83      6    93%   78-80, 84-86
	 source_acceptance_test/conftest.py                     164    164     0%   6-282
	 source_acceptance_test/plugin.py                        48     48     0%   6-104
	 source_acceptance_test/tests/test_core.py              329    111    66%   39, 50-58, 63-70, 74-75, 79-80, 164, 202-219, 228-236, 240-245, 251, 284-289, 327-334, 374-376, 379, 439-448, 477-478, 484, 487, 520-530, 543-568, 573-577
	 source_acceptance_test/tests/test_full_refresh.py       52      2    96%   34, 65
	 source_acceptance_test/tests/test_incremental.py       121     25    79%   21-23, 29-31, 36-43, 48-61, 208-216
	 source_acceptance_test/utils/asserts.py                 37      2    95%   57-58
	 source_acceptance_test/utils/common.py                  77     17    78%   15-16, 24-30, 47-54, 64, 67
	 source_acceptance_test/utils/compare.py                 62     23    63%   21-51, 68, 97-99
	 source_acceptance_test/utils/connector_runner.py       110     48    56%   23-26, 32, 36, 39-64, 67-69, 72-74, 77-79, 82-84, 87-89, 92-110, 144-146
	 source_acceptance_test/utils/json_schema_helper.py     105     13    88%   30-31, 38, 41, 65-68, 96, 120, 190-192
	 ----------------------------------------------------------------------------------
	 TOTAL                                                 1321    463    65%

Build Passed

Test summary info:

	 =========================== short test summary info ============================
	 SKIPPED [9] integration_tests/integration_test.py:33: need to refresh this test, it is very slow
	 �[33m============= �[32m2 passed�[0m, �[33m�[1m9 skipped�[0m, �[33m�[1m27 warnings�[0m�[33m in 69.41s (0:01:09)�[0m�[33m =============�[0m

Copy link
Contributor

@ChristopheDuong ChristopheDuong left a comment

Choose a reason for hiding this comment

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

I'm not blocking this PR but I had a question on the json schema for the new field (could be re-worked later too but we'd have to make sure to file an issue for it)

Before merging, it still need to publish and update changelog of the connector btw

Copy link
Collaborator

@bazarnov bazarnov left a comment

Choose a reason for hiding this comment

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

LGTM, but the change log should be updated, make sure you've done that.

@github-actions github-actions bot added the area/documentation Improvements or additions to documentation label Aug 18, 2022
@alex-gron
Copy link
Contributor Author

alex-gron commented Aug 18, 2022

/publish connector=connectors/source-intercom

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


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

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

@alex-gron alex-gron changed the title Source Intercom: Update Intercom API to version 2.5 🎉 Source Intercom: Update Intercom API to version 2.5 Aug 18, 2022
@alex-gron alex-gron merged commit 94fcf0d into master Aug 18, 2022
@alex-gron alex-gron deleted the alex/update_intercom_api_v25 branch August 18, 2022 20:06
rodireich pushed a commit that referenced this pull request Aug 25, 2022
* upgrade intercom API to v2.5

* update conversations schema

* update expected records

* update change log

* fix doc formatting

* auto-bump connector version [ci skip]

Co-authored-by: Octavia Squidington III <octavia-squidington-iii@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/connectors Connector related issues area/documentation Improvements or additions to documentation connectors/source/intercom
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Source Intercom: Add custom_attributs in conversation schema
4 participants