diff --git a/airbyte-integrations/connectors/source-productboard/README.md b/airbyte-integrations/connectors/source-productboard/README.md new file mode 100644 index 0000000000000..e968fba99eb63 --- /dev/null +++ b/airbyte-integrations/connectors/source-productboard/README.md @@ -0,0 +1,39 @@ +# Productboard +This directory contains the manifest-only connector for `source-productboard`. +https://www.productboard.com/ + +## Documentation reference: +Visit https://developer.productboard.com/reference/ for API documentation + +## Authentication setup +`source-productboard` uses API Token authentication. +Visit https://developer.productboard.com/reference/authentication#public-api-access-token for steps to generate an access token. + +## Usage +There are multiple ways to use this connector: +- You can use this connector as any other connector in Airbyte Marketplace. +- You can load this connector in `pyairbyte` using `get_source`! +- You can open this connector in Connector Builder, edit it, and publish to your workspaces. + +Please refer to the manifest-only connector documentation for more details. + +## Local Development +We recommend you use the Connector Builder to edit this connector. + +But, if you want to develop this connector locally, you can use the following steps. + +### Environment Setup +You will need `airbyte-ci` installed. You can find the documentation [here](/~https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md). + +### Build +This will create a dev image (`source-productboard:dev`) that you can use to test the connector locally. +```bash +airbyte-ci connectors --name=source-productboard build +``` + +### Test +This will run the acceptance tests for the connector. +```bash +airbyte-ci connectors --name=source-productboard test +``` + diff --git a/airbyte-integrations/connectors/source-productboard/acceptance-test-config.yml b/airbyte-integrations/connectors/source-productboard/acceptance-test-config.yml new file mode 100644 index 0000000000000..abfd947cc9443 --- /dev/null +++ b/airbyte-integrations/connectors/source-productboard/acceptance-test-config.yml @@ -0,0 +1,17 @@ +# See [Connector Acceptance Tests](https://docs.airbyte.com/connector-development/testing-connectors/connector-acceptance-tests-reference) +# for more information about how to configure these tests +connector_image: airbyte/source-productboard:dev +acceptance_tests: + spec: + tests: + - spec_path: "manifest.yaml" + connection: + bypass_reason: "This is a builder contribution, and we do not have secrets at this time" + discovery: + bypass_reason: "This is a builder contribution, and we do not have secrets at this time" + basic_read: + bypass_reason: "This is a builder contribution, and we do not have secrets at this time" + incremental: + bypass_reason: "This is a builder contribution, and we do not have secrets at this time" + full_refresh: + bypass_reason: "This is a builder contribution, and we do not have secrets at this time" diff --git a/airbyte-integrations/connectors/source-productboard/icon.svg b/airbyte-integrations/connectors/source-productboard/icon.svg new file mode 100644 index 0000000000000..d3330ff220afc --- /dev/null +++ b/airbyte-integrations/connectors/source-productboard/icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/airbyte-integrations/connectors/source-productboard/manifest.yaml b/airbyte-integrations/connectors/source-productboard/manifest.yaml new file mode 100644 index 0000000000000..0dd83252bbcf8 --- /dev/null +++ b/airbyte-integrations/connectors/source-productboard/manifest.yaml @@ -0,0 +1,1896 @@ +version: 4.6.2 + +type: DeclarativeSource + +description: A manifest only source for Productboard. https://www.productboard.com/ + +check: + type: CheckStream + stream_names: + - products + +definitions: + streams: + products: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /products + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: products + primary_key: + - id + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/products" + features: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /features + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: features + primary_key: + - id + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/features" + components: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /components + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: components + primary_key: + - id + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/components" + feature-statuses: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /feature-statuses + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: feature-statuses + primary_key: + - id + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/feature-statuses" + notes: + type: DeclarativeStream + name: notes + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /notes + http_method: GET + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestOption + inject_into: request_parameter + field_name: pageCursor + pagination_strategy: + type: CursorPagination + cursor_value: "{{ response.get('pageCursor') }}" + stop_condition: "{{ not response.get('pageCursor') }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updatedAt + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%S.%fZ" + datetime_format: "%Y-%m-%d" + start_datetime: + type: MinMaxDatetime + datetime: '{{ config["start_date"] }}' + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + inject_into: request_parameter + field_name: updatedFrom + end_time_option: + type: RequestOption + inject_into: request_parameter + field_name: updatedTo + end_datetime: + type: MinMaxDatetime + datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + step: P1M + cursor_granularity: PT0.000001S + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/notes" + tags: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /notes/{{ stream_partition['id'] }}/tags + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + partition_router: + type: SubstreamPartitionRouter + parent_stream_configs: + - type: ParentStreamConfig + parent_key: id + partition_field: id + stream: + $ref: "#/definitions/streams/notes" + name: tags + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/tags" + links: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /notes/{{ stream_partition['id'] }}/links + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + partition_router: + type: SubstreamPartitionRouter + parent_stream_configs: + - type: ParentStreamConfig + parent_key: id + partition_field: id + stream: + $ref: "#/definitions/streams/notes" + name: links + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/links" + feedback-form-configurations: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /feedback-form-configurations + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: feedback-form-configurations + primary_key: + - id + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/feedback-form-configurations" + companies: + type: DeclarativeStream + name: companies + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /companies + http_method: GET + request_headers: + X-Version: "1" + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/companies" + company-custom-fields: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /companies/custom-fields + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: company-custom-fields + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/company-custom-fields" + users: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /users + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: users + primary_key: + - id + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/users" + custom-fields: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /hierarchy-entities/custom-fields + http_method: GET + request_parameters: + type: text,custom-description,number,dropdown,multi-dropdown,member + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: custom-fields + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/custom-fields" + custom-fields-values: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /hierarchy-entities/custom-fields-values + http_method: GET + request_parameters: + type: text,custom-description,number,dropdown,multi-dropdown,member + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: custom-fields-values + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/custom-fields-values" + release-groups: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /release-groups + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: release-groups + primary_key: + - id + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/release-groups" + releases: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /releases + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: releases + primary_key: + - id + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/releases" + feature-release-assignments: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /feature-release-assignments + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: feature-release-assignments + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/feature-release-assignments" + objectives: + type: DeclarativeStream + state_migrations: [] + retriever: + type: SimpleRetriever + ignore_stream_slicer_parameters_on_paginated_requests: false + requester: + use_cache: false + $ref: "#/definitions/base_requester" + path: /objectives + http_method: GET + request_headers: + X-Version: "1" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: ConstantBackoffStrategy + backoff_time_in_seconds: 1 + response_filters: + - type: HttpResponseFilter + action: RATE_LIMITED + http_codes: + - 429 + error_message: There is a rate limit of 50 requests per second. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - data + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 100 + cursor_value: "{{ response.get('links', {}).get('next') }}" + stop_condition: "{{ not response.get('links', {}).get('next') }}" + name: objectives + primary_key: + - id + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/objectives" + base_requester: + type: HttpRequester + url_base: https://api.productboard.com + authenticator: + type: BearerAuthenticator + api_token: '{{ config["access_token"] }}' + +streams: + - $ref: "#/definitions/streams/products" + - $ref: "#/definitions/streams/features" + - $ref: "#/definitions/streams/components" + - $ref: "#/definitions/streams/feature-statuses" + - $ref: "#/definitions/streams/notes" + - $ref: "#/definitions/streams/tags" + - $ref: "#/definitions/streams/links" + - $ref: "#/definitions/streams/feedback-form-configurations" + - $ref: "#/definitions/streams/companies" + - $ref: "#/definitions/streams/company-custom-fields" + - $ref: "#/definitions/streams/users" + - $ref: "#/definitions/streams/custom-fields" + - $ref: "#/definitions/streams/custom-fields-values" + - $ref: "#/definitions/streams/release-groups" + - $ref: "#/definitions/streams/releases" + - $ref: "#/definitions/streams/feature-release-assignments" + - $ref: "#/definitions/streams/objectives" + +spec: + type: Spec + connection_specification: + type: object + $schema: http://json-schema.org/draft-07/schema# + required: + - access_token + - start_date + properties: + access_token: + type: string + description: >- + Your Productboard access token. See + https://developer.productboard.com/reference/authentication for steps + to generate one. + name: api_key + order: 0 + title: Access Token + airbyte_secret: true + start_date: + type: string + title: Start date + format: date-time + pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ + order: 1 + additionalProperties: true + +metadata: + autoImportSchema: + products: true + features: true + components: true + feature-statuses: true + notes: false + tags: true + links: true + feedback-form-configurations: true + companies: false + company-custom-fields: true + users: true + custom-fields: true + custom-fields-values: true + release-groups: true + releases: true + feature-release-assignments: true + objectives: true + testedStreams: + products: + streamHash: 0ef1677727273b0901125aca5496ce538dbb1449 + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + features: + streamHash: 75ff41bc04b99f12eca2053527efb5e9bb0b7922 + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + components: + streamHash: 51c161a8cc8737a4f8d1a80963d4176e2ba8dfd4 + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + feature-statuses: + streamHash: 7cccf074935774669cc74e54143daf2f59cefa5a + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + notes: + streamHash: b5547a5fc6e7042b6ec2a521f785de9053d5614d + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + tags: + streamHash: ce46258fb3966662f0eeb3bc7b853ce27451fb62 + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + links: + streamHash: f95376cf296b9abf858bc76b60aeca01c9eff135 + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + feedback-form-configurations: + streamHash: bcf4e8ef077d6de328d6fdcd21c63fe64d66bdd5 + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + companies: + streamHash: 705a20315866dead141c9c5fbc78f5d327239c07 + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + company-custom-fields: + streamHash: 66736f2604eeb224dca56555dd9fd3b205dc159f + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + users: + streamHash: a556de54f00483d518b437c7e291e255624fbb81 + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + custom-fields: + streamHash: 9e045f83a05bedaab0681288e284fd868d45e679 + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + custom-fields-values: + streamHash: b490a98b1b5e1eba607b779d336bc6ef496d2d25 + hasResponse: true + responsesAreSuccessful: true + hasRecords: true + primaryKeysArePresent: true + primaryKeysAreUnique: true + release-groups: + hasRecords: true + streamHash: d6a48b9c4585c9f7b9fda5b5f3e07ea41cef4312 + hasResponse: true + primaryKeysAreUnique: true + primaryKeysArePresent: true + responsesAreSuccessful: true + releases: + hasRecords: true + streamHash: 0b8fa3777a2792dda2c1c2c5fb2c14228d2286b2 + hasResponse: true + primaryKeysAreUnique: true + primaryKeysArePresent: true + responsesAreSuccessful: true + feature-release-assignments: + hasRecords: true + streamHash: 4c289ba68f50c55ce33e2c437f8ad8493dea4e4f + hasResponse: true + primaryKeysAreUnique: true + primaryKeysArePresent: true + responsesAreSuccessful: true + objectives: + hasRecords: true + streamHash: c84a6a62f8fd60b848358fc9552c8074c4dd3451 + hasResponse: true + primaryKeysAreUnique: true + primaryKeysArePresent: true + responsesAreSuccessful: true + assist: + docsUrl: https://developer.productboard.com/reference/ + +schemas: + products: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + description: + type: + - string + - "null" + createdAt: + type: + - string + - "null" + id: + type: string + links: + type: + - object + - "null" + properties: + html: + type: + - string + - "null" + self: + type: + - string + - "null" + name: + type: + - string + - "null" + owner: + type: + - object + - "null" + properties: + email: + type: + - string + - "null" + updatedAt: + type: + - string + - "null" + required: + - id + features: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + type: + type: + - string + - "null" + description: + type: + - string + - "null" + archived: + type: + - boolean + - "null" + createdAt: + type: + - string + - "null" + id: + type: string + links: + type: + - object + - "null" + properties: + html: + type: + - string + - "null" + self: + type: + - string + - "null" + name: + type: + - string + - "null" + owner: + type: + - object + - "null" + properties: + email: + type: + - string + - "null" + parent: + type: + - object + - "null" + properties: + component: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + feature: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + status: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + name: + type: + - string + - "null" + timeframe: + type: + - object + - "null" + properties: + endDate: + type: + - string + - "null" + granularity: + type: + - string + - "null" + startDate: + type: + - string + - "null" + updatedAt: + type: + - string + - "null" + required: + - id + components: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + description: + type: + - string + - "null" + createdAt: + type: + - string + - "null" + id: + type: string + links: + type: + - object + - "null" + properties: + html: + type: + - string + - "null" + self: + type: + - string + - "null" + name: + type: + - string + - "null" + owner: + type: + - object + - "null" + properties: + email: + type: + - string + - "null" + parent: + type: + - object + - "null" + properties: + product: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + updatedAt: + type: + - string + - "null" + required: + - id + feature-statuses: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + completed: + type: + - boolean + - "null" + id: + type: string + name: + type: + - string + - "null" + required: + - id + notes: + type: object + $schema: http://json-schema.org/schema# + properties: + company: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + content: + type: + - string + - "null" + createdAt: + type: + - string + - "null" + createdBy: + type: + - object + - "null" + properties: + email: + type: + - string + - "null" + id: + type: + - string + - "null" + name: + type: + - string + - "null" + displayUrl: + type: + - string + - "null" + externalDisplayUrl: + type: + - string + - "null" + features: + type: + - array + - "null" + items: + type: + - object + - "null" + properties: + type: + type: + - string + - "null" + id: + type: + - string + - "null" + importance: + type: + - number + - "null" + followers: + type: + - array + - "null" + items: + type: + - object + - "null" + properties: + memberEmail: + type: + - string + - "null" + memberId: + type: + - string + - "null" + memberName: + type: + - string + - "null" + id: + type: string + owner: + type: + - object + - "null" + properties: + email: + type: + - string + - "null" + name: + type: + - string + - "null" + source: + type: + - object + - "null" + properties: + origin: + type: + - string + - "null" + state: + type: + - string + - "null" + tags: + type: + - array + - "null" + items: + type: + - string + - "null" + title: + type: + - string + - "null" + updatedAt: + type: string + user: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + required: + - id + - updatedAt + additionalProperties: true + tags: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + tags: + type: + - array + - "null" + items: + type: + - string + - "null" + links: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + type: + type: + - string + - "null" + id: + type: + - string + - "null" + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + feedback-form-configurations: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + createdAt: + type: + - string + - "null" + fields: + type: + - array + - "null" + items: + type: + - object + - "null" + properties: + fieldType: + type: + - string + - "null" + id: + type: + - string + - "null" + isRequired: + type: + - boolean + - "null" + name: + type: + - string + - "null" + id: + type: string + name: + type: + - string + - "null" + owner: + type: + - object + - "null" + properties: + email: + type: + - string + - "null" + updatedAt: + type: + - string + - "null" + required: + - id + companies: + type: object + $schema: http://json-schema.org/schema# + properties: + description: + type: + - string + - "null" + domain: + type: + - string + - "null" + id: + type: string + name: + type: + - string + - "null" + sourceOrigin: + type: + - string + - "null" + sourceRecordId: + type: + - string + - "null" + required: + - id + additionalProperties: true + company-custom-fields: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + type: + type: + - string + - "null" + id: + type: + - string + - "null" + name: + type: + - string + - "null" + users: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + companyId: + type: + - string + - "null" + id: + type: string + name: + type: + - string + - "null" + required: + - id + custom-fields: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + type: + type: + - string + - "null" + description: + type: + - string + - "null" + id: + type: + - string + - "null" + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + name: + type: + - string + - "null" + options: + type: + - array + - "null" + items: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + label: + type: + - string + - "null" + custom-fields-values: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + type: + type: + - string + - "null" + customField: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + hierarchyEntity: + type: + - object + - "null" + properties: + type: + type: + - string + - "null" + id: + type: + - string + - "null" + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + value: + anyOf: + - type: + - number + - string + - type: object + properties: + email: + type: string + id: + type: string + label: + type: string + release-groups: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + description: + type: + - string + - "null" + archived: + type: + - boolean + - "null" + id: + type: string + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + name: + type: + - string + - "null" + required: + - id + releases: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + description: + type: + - string + - "null" + archived: + type: + - boolean + - "null" + id: + type: string + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + name: + type: + - string + - "null" + releaseGroup: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + state: + type: + - string + - "null" + timeframe: + type: + - object + - "null" + properties: + endDate: + type: + - string + - "null" + granularity: + type: + - string + - "null" + startDate: + type: + - string + - "null" + required: + - id + feature-release-assignments: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + assigned: + type: + - boolean + - "null" + feature: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + release: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + links: + type: + - object + - "null" + properties: + self: + type: + - string + - "null" + objectives: + type: object + $schema: http://json-schema.org/schema# + additionalProperties: true + properties: + description: + type: + - string + - "null" + archived: + type: + - boolean + - "null" + createdAt: + type: + - string + - "null" + id: + type: string + links: + type: + - object + - "null" + properties: + html: + type: + - string + - "null" + self: + type: + - string + - "null" + name: + type: + - string + - "null" + owner: + type: + - object + - "null" + properties: + email: + type: + - string + - "null" + status: + type: + - object + - "null" + properties: + id: + type: + - string + - "null" + name: + type: + - string + - "null" + timeframe: + type: + - object + - "null" + properties: + endDate: + type: + - string + - "null" + granularity: + type: + - string + - "null" + startDate: + type: + - string + - "null" + updatedAt: + type: + - string + - "null" + required: + - id diff --git a/airbyte-integrations/connectors/source-productboard/metadata.yaml b/airbyte-integrations/connectors/source-productboard/metadata.yaml new file mode 100644 index 0000000000000..348672e59881b --- /dev/null +++ b/airbyte-integrations/connectors/source-productboard/metadata.yaml @@ -0,0 +1,35 @@ +metadataSpecVersion: "1.0" +data: + allowedHosts: + hosts: + - "api.productboard.com" + registryOverrides: + oss: + enabled: true + cloud: + enabled: true + remoteRegistries: + pypi: + enabled: false + packageName: airbyte-source-productboard + connectorBuildOptions: + baseImage: docker.io/airbyte/source-declarative-manifest:4.6.2@sha256:f5fcd3d4703b7590b6166a7853c5ed1686731607cd30a159a8c24e2fe2c1ee98 + connectorSubtype: api + connectorType: source + definitionId: 43ae66ee-e3df-4fb7-bff5-9625d25cdc14 + dockerImageTag: 0.0.1 + dockerRepository: airbyte/source-productboard + githubIssueLabel: source-productboard + icon: icon.svg + license: MIT + name: Productboard + releaseDate: 2024-09-13 + releaseStage: alpha + supportLevel: community + documentationUrl: https://docs.airbyte.com/integrations/sources/productboard + tags: + - language:manifest-only + - cdk:low-code + ab_internal: + ql: 100 + sl: 100 diff --git a/docs/integrations/sources/productboard.md b/docs/integrations/sources/productboard.md new file mode 100644 index 0000000000000..ea2476d3d7cee --- /dev/null +++ b/docs/integrations/sources/productboard.md @@ -0,0 +1,41 @@ +# Productboard +A manifest only source for Productboard. https://www.productboard.com/ + +## Configuration + +| Input | Type | Description | Default Value | +|-------|------|-------------|---------------| +| `access_token` | `string` | Access Token. Your Productboard access token. See https://developer.productboard.com/reference/authentication for steps to generate one. | | +| `start_date` | `string` | Start date. | | + +## Streams +| Stream Name | Primary Key | Pagination | Supports Full Sync | Supports Incremental | +|-------------|-------------|------------|---------------------|----------------------| +| products | id | DefaultPaginator | ✅ | ❌ | +| features | id | DefaultPaginator | ✅ | ❌ | +| components | id | DefaultPaginator | ✅ | ❌ | +| feature-statuses | id | DefaultPaginator | ✅ | ❌ | +| notes | id | DefaultPaginator | ✅ | ✅ | +| tags | | No pagination | ✅ | ❌ | +| links | | No pagination | ✅ | ❌ | +| feedback-form-configurations | id | DefaultPaginator | ✅ | ❌ | +| companies | id | DefaultPaginator | ✅ | ❌ | +| company-custom-fields | | DefaultPaginator | ✅ | ❌ | +| users | id | DefaultPaginator | ✅ | ❌ | +| custom-fields | | DefaultPaginator | ✅ | ❌ | +| custom-fields-values | | DefaultPaginator | ✅ | ❌ | +| release-groups | id | DefaultPaginator | ✅ | ❌ | +| releases | id | DefaultPaginator | ✅ | ❌ | +| feature-release-assignments | | DefaultPaginator | ✅ | ❌ | +| objectives | id | DefaultPaginator | ✅ | ❌ | + +## Changelog + +
+ Expand to review + +| Version | Date | Pull Request | Subject | +|---------|------------|----------------------------------------------------------|-------------------------------------------------------------------------------------------| +| 0.0.1 | 2024-09-13 | [45449](/~https://github.com/airbytehq/airbyte/pull/45449) | Initial release by [@pabloescoder](/~https://github.com/pabloescoder) via Connector Builder | + +
\ No newline at end of file