diff --git a/airbyte-integrations/connectors/source-google-sheets/Dockerfile b/airbyte-integrations/connectors/source-google-sheets/Dockerfile index 1e434a095a61..b70826942cf1 100644 --- a/airbyte-integrations/connectors/source-google-sheets/Dockerfile +++ b/airbyte-integrations/connectors/source-google-sheets/Dockerfile @@ -36,5 +36,5 @@ COPY source_google_sheets ./source_google_sheets ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.3.2 +LABEL io.airbyte.version=0.3.3 LABEL io.airbyte.name=airbyte/source-google-sheets diff --git a/airbyte-integrations/connectors/source-google-sheets/metadata.yaml b/airbyte-integrations/connectors/source-google-sheets/metadata.yaml index eaf1683c3c80..c40f7afeebbd 100644 --- a/airbyte-integrations/connectors/source-google-sheets/metadata.yaml +++ b/airbyte-integrations/connectors/source-google-sheets/metadata.yaml @@ -5,7 +5,7 @@ data: connectorSubtype: file connectorType: source definitionId: 71607ba1-c0ac-4799-8049-7f4b90dd50f7 - dockerImageTag: 0.3.2 + dockerImageTag: 0.3.3 dockerRepository: airbyte/source-google-sheets githubIssueLabel: source-google-sheets icon: google-sheets.svg diff --git a/airbyte-integrations/connectors/source-google-sheets/source_google_sheets/source.py b/airbyte-integrations/connectors/source-google-sheets/source_google_sheets/source.py index e948b6da29eb..8e0edca55e3c 100644 --- a/airbyte-integrations/connectors/source-google-sheets/source_google_sheets/source.py +++ b/airbyte-integrations/connectors/source-google-sheets/source_google_sheets/source.py @@ -132,8 +132,21 @@ def discover(self, logger: AirbyteLogger, config: json) -> AirbyteCatalog: except errors.HttpError as err: reason = str(err) - if err.resp.status == status_codes.NOT_FOUND: - reason = "Requested spreadsheet was not found." + config_error_status_codes = [status_codes.NOT_FOUND, status_codes.FORBIDDEN] + if err.resp.status in config_error_status_codes: + if err.resp.status == status_codes.NOT_FOUND: + reason = f"Requested spreadsheet with id {spreadsheet_id} was not found" + if err.resp.status == status_codes.FORBIDDEN: + reason = f"Forbidden when requesting spreadsheet with id {spreadsheet_id}" + message = ( + f"{reason}. {err.reason}. See docs for more details here: " + f"https://cloud.google.com/service-infrastructure/docs/service-control/reference/rpc/google.api/servicecontrol.v1#code" + ) + raise AirbyteTracedException( + message=message, + internal_message=message, + failure_type=FailureType.config_error, + ) from err raise Exception(f"Could not run discovery: {reason}") def read( diff --git a/airbyte-integrations/connectors/source-google-sheets/unit_tests/test_stream.py b/airbyte-integrations/connectors/source-google-sheets/unit_tests/test_stream.py index a219f40a3323..ab87f0fff9df 100644 --- a/airbyte-integrations/connectors/source-google-sheets/unit_tests/test_stream.py +++ b/airbyte-integrations/connectors/source-google-sheets/unit_tests/test_stream.py @@ -28,3 +28,33 @@ def test_invalid_link_error_message(mocker, invalid_config): source.check(logger=None, config=invalid_config) expected_message = 'Config error: The spreadsheet link is not valid. Enter the URL of the Google spreadsheet you want to sync.' assert e.value.args[0] == expected_message + + +def test_discover_404_error(mocker, invalid_config): + source = SourceGoogleSheets() + resp = requests.Response() + resp.status = 404 + resp.reason = "Requested entity was not found" + mocker.patch.object(GoogleSheetsClient, "__init__", lambda s, credentials, scopes=SCOPES: None) + mocker.patch.object(GoogleSheetsClient, "get", side_effect=errors.HttpError(resp=resp, content=b'')) + + with pytest.raises(AirbyteTracedException) as e: + source.discover(logger=mocker.MagicMock(), config=invalid_config) + expected_message = ("Requested spreadsheet with id invalid_spreadsheet_id was not found. Requested entity was not found. " + "See docs for more details here: https://cloud.google.com/service-infrastructure/docs/service-control/reference/rpc/google.api/servicecontrol.v1#code") + assert e.value.args[0] == expected_message + + +def test_discover_403_error(mocker, invalid_config): + source = SourceGoogleSheets() + resp = requests.Response() + resp.status = 403 + resp.reason = "The caller does not have right permissions" + mocker.patch.object(GoogleSheetsClient, "__init__", lambda s, credentials, scopes=SCOPES: None) + mocker.patch.object(GoogleSheetsClient, "get", side_effect=errors.HttpError(resp=resp, content=b'')) + + with pytest.raises(AirbyteTracedException) as e: + source.discover(logger=mocker.MagicMock(), config=invalid_config) + expected_message = ("Forbidden when requesting spreadsheet with id invalid_spreadsheet_id. The caller does not have right permissions. " + "See docs for more details here: https://cloud.google.com/service-infrastructure/docs/service-control/reference/rpc/google.api/servicecontrol.v1#code") + assert e.value.args[0] == expected_message diff --git a/docs/integrations/sources/google-sheets.md b/docs/integrations/sources/google-sheets.md index eebc08711005..06923fefe37b 100644 --- a/docs/integrations/sources/google-sheets.md +++ b/docs/integrations/sources/google-sheets.md @@ -76,6 +76,7 @@ The [Google API rate limit](https://developers.google.com/sheets/api/limits) is | Version | Date | Pull Request | Subject | |---------|------------|----------------------------------------------------------|-----------------------------------------------------------------------------------| +| 0.3.3 | 2023-08-10 | [29327](https://github.com/airbytehq/airbyte/pull/29327) | Add user-friendly error message for 404 and 403 error while discover | | 0.3.2 | 2023-08-09 | [29246](https://github.com/airbytehq/airbyte/pull/29246) | Add checking while reading to skip modified sheets | | 0.3.1 | 2023-07-06 | [28033](https://github.com/airbytehq/airbyte/pull/28033) | Fixed several reported vulnerabilities (25 total), CVE-2022-37434, CVE-2022-42898 | | 0.3.0 | 2023-06-26 | [27738](https://github.com/airbytehq/airbyte/pull/27738) | License Update: Elv2 |