-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
🎉 New Source Chargify: first connector #10853
🎉 New Source Chargify: first connector #10853
Conversation
…airbyte into feature/chargify-connector
Hey @Javier162380, thanks for this contrib! Is this ready for review? (The PR title is a bit misleading as you wrote it's a draft). If it's still WIP please convert the PR to draft 🙏 . |
Hey, thanks for the answer @alafanechere! The connector is ready to be reviewed!. Sadly I can not add integration tests, but the unit test code coverage covers almost all the edge cases 😊. Shall I remove all this all this files from the PR or shall I leave them there |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Javier162380 I went for a first review.
I made small suggestions about your current implementation, mainly to ease readability.
I'd also ask you to edit the following files:
airbyte-config/init/src/main/resources/seed/source_definitions.yaml
to add your connector. Please locally generate a UUID (in bash:uuidgen | tr "[:upper:]" "[:lower:]"
) and use this as you definition id.- Add your connector to
airbyte-integrations/builds.md
(just copy another URL and edit it to usesource-chargify
- Could you please add a documentation for this connector in
docs/integrations/sources/chargify.md
Could you explain why you can't run the acceptance tests?
We need to have a way to run these in our CI. We usually create sandbox account with the source service, but I discovered that Chargify exposes a mock server for API testing that we could use if you change the connector config a little bit (using a domain parameter rather than a subdomain).
# TODO uncomment this block to specify that the tests should assert the connector outputs the records provided in the input file a file | ||
# expect_records: | ||
# path: "integration_tests/expected_records.txt" | ||
# extra_fields: no | ||
# exact_order: no | ||
# extra_records: yes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please implement or remove all the remaining #TODO
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
# extra_fields: no | ||
# exact_order: no | ||
# extra_records: yes | ||
incremental: # TODO if your connector does not implement incremental sync, remove this block |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your connector does not have incremental sync, please remove this test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
@@ -0,0 +1,5 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your connector does not implement incremental sync, please remove this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
@@ -0,0 +1,39 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fill this file according to the output of running discover
on the connector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
@@ -0,0 +1,3 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fill this file according to a valid config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change I use the spotlight endpoint f493f40
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
if next_page_token is None and self.is_first_requests is True: | ||
self.is_first_requests == False | ||
return {"page": self._page, "per_page": self._per_page} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think self.is_first_requests
is an useful attribute. next_page_token == None
means you're making the first request. Moreover, changing a property value could lead to unexpected behavior. If you want to keep is_first_request
please declare this attribute in the constructor, not in a property.
if next_page_token is None and self.is_first_requests is True: | |
self.is_first_requests == False | |
return {"page": self._page, "per_page": self._per_page} | |
if next_page_token is None: | |
return {"page": self._page, "per_page": self._per_page} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More clear sure! changes applied!
TODO: Override this method to define how a response is parsed. | ||
:return an iterable containing each record in the response | ||
""" | ||
yield {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to implement this method to extract records from your response object, otherwise, I think the connector won't output any data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so this interface it is a base stream, I am using a custom logic per object to parse the response and in those interfaces it is where I implement this method.
converted_args = self.convert_config2stream_args(config) | ||
customers_gen = Customers(authenticator=auth, **converted_args).read_records(sync_mode=SyncMode.full_refresh) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
converted_args = self.convert_config2stream_args(config) | |
customers_gen = Customers(authenticator=auth, **converted_args).read_records(sync_mode=SyncMode.full_refresh) | |
customers_gen = Customers(authenticator=auth, subdomain=config["subdomain"]).read_records(sync_mode=SyncMode.full_refresh) |
I don't think convert_config2stream_args
. is useful here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you also try to read records from both streams in the check connection? To make sure we can read all the streams defined in the connector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah make sense I erase the method 2420d9b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Method erase 2420d9b, I can read records from both streams
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're still calling it on line 105
source = SourceChargify() | ||
config_mock = {"subdomain": "tst", "page": 1, "per_page": 200} | ||
streams_config = source.convert_config2stream_args(config_mock) | ||
assert streams_config == {"subdomain":"tst", "page": 1, "per_page": 200} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing new line at the end of the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have a python linter for the project?
"description": "Chargify API Key.", | ||
"airbyte_secret": true | ||
}, | ||
"subdomain": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think you could change this to domain
? It will allow us to use Chargify's mock server to run our acceptance tests:
curl --request GET \
--url https://stoplight.io/mocks/chargify/api-docs/14108261/customers.json \
--header 'Authorization: Basic undefined' \
--header 'Content-Type: application/json'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I change the attribute to use the domain
Hi @alafanechere, Thanks for you review! I applied the changes you mention and I test locally the connector using the Chargify mock instance. It works as expected, let me know if more work it is required |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes! I still spotted some formatting issues. Could you please run ./gradlew format
?
Could you please also share the output of the acceptance tests?
"description": "Chargify API Key.", | ||
"airbyte_secret": true | ||
}, | ||
"domain": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"domain": { | |
"server": { |
The API doc uses the word server
not domain 😄
Hey @Javier162380 , I made some quick changes to make this move forward (formatting mainly). {
"api_key": "undefined",
"domain": "stoplight.io/mocks/chargify/api-docs/14108261/"
} I think one of your unit test is failing too. Please fix the acceptance and unit tests and ping me for another review. |
/test connector=connectors/source-chargify
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Javier162380 I made some small changes to make the acceptance pass and for your PR to be ready for merge. You copied the doc from the greenhouse connector so I wrote a simple one myself for Chargify. Please check my changes and feel free to add more details to the documentation.
Acceptance tests are passing locally for me, I'll run them in the CI and merge once they pass.
Hi @alafanechere , Sorry I was away for a couple of days!! Your changes look good to me!!. I will love to see this connector publish 🤟 |
/publish connector=connectors/source-chargify run-tests=false
|
@Javier162380 thank you for this new connector! |
thanks for your help @alafanechere!! |
What
First Draft of a Chargify connector for subscriptions and customers objects
How
I use the Python Http template API, for developing the skeleton of the connector, and also I take to the Greenhouse and Zendesk sources
Recommended reading order
y.python
🚨 User Impact 🚨
No breaking changes it is a new connector.
Pre-merge Checklist
Expand the relevant checklist and delete the others.
New Connector
Community member or Airbyter
airbyte_secret
./gradlew :airbyte-integrations:connectors:<name>:integrationTest
.README.md
bootstrap.md
. See description and examplesdocs/SUMMARY.md
docs/integrations/<source or destination>/<name>.md
including changelog. See changelog exampledocs/integrations/README.md
airbyte-integrations/builds.md
Airbyter
If this is a community PR, the Airbyte engineer reviewing this PR is responsible for the below items.
/test connector=connectors/<name>
command is passing/publish
command described hereUpdating a connector
Community member or Airbyter
airbyte_secret
./gradlew :airbyte-integrations:connectors:<name>:integrationTest
.README.md
bootstrap.md
. See description and examplesdocs/integrations/<source or destination>/<name>.md
including changelog. See changelog exampleAirbyter
If this is a community PR, the Airbyte engineer reviewing this PR is responsible for the below items.
/test connector=connectors/<name>
command is passing/publish
command described hereConnector Generator
-scaffold
in their name) have been updated with the latest scaffold by running./gradlew :airbyte-integrations:connector-templates:generator:testScaffoldTemplates
then checking in your changesTests
Unit
Put your unit tests output here.
Integration
Put your integration tests output here.
Acceptance
Put your acceptance tests output here.