jf-ingest 0.0.151.dev0__tar.gz → 0.0.152.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/PKG-INFO +1 -1
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/adaptive_throttler.py +15 -6
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/clients/github.py +7 -5
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/telemetry/metrics.py +15 -7
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest.egg-info/PKG-INFO +1 -1
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/github/test_github_gql_client.py +56 -16
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.github/CODEOWNERS +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.github/workflows/semgrep.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.gitignore +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.pre-commit-config.yaml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/README.md +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/jellyfish.python.django.security.audit.xss.var-in-script-tag.var-in-script-tag.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/jellyfish.python.django.security.injection.open-redirect.open-redirect.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/jellyfish.python.django.security.nan-injection.nan-injection.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/jellyfish.python.django.security.passwords.use-none-for-password-default.use-none-for-password-default.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.django.security.audit.avoid-insecure-deserialization.avoid-insecure-deserialization.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.django.security.globals-as-template-context.globals-as-template-context.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.django.security.injection.command.command-injection-os-system.command-injection-os-system.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.django.security.injection.command.subprocess-injection.subprocess-injection.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.django.security.injection.csv-writer-injection.csv-writer-injection.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.django.security.injection.ssrf.ssrf-injection-requests.ssrf-injection-requests.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.django.security.injection.ssrf.ssrf-injection-urllib.ssrf-injection-urllib.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.django.security.injection.tainted-sql-string.tainted-sql-string.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.django.security.locals-as-template-context.locals-as-template-context.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.django.security.passwords.password-empty-string.password-empty-string.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/.semgrep_rules/registry/python.lang.security.audit.eval-detected.eval-detected.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/LICENSE +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/MANIFEST.in +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/README.md +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/example.yml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/config.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/constants.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/jira/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/jira/adapters/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/jira/adapters/jira_cloud.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/jira/adapters/manifest_adapter.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/jira/generator.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/jira/manifest_base.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/manifest_base.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/diagnostics.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/events/models.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/events/utils.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/file_operations.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/graphql_utils.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/harness.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/adapters/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/adapters/azure_devops.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/adapters/github.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/adapters/gitlab.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/clients/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/clients/azure_devops.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/clients/gitlab.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/exceptions.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_git/standardized_models.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_jira/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_jira/auth.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_jira/custom_fields.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_jira/downloaders.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_jira/exceptions.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/jf_jira/utils.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/logging_helper.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/name_redactor.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/regression_detector.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/telemetry/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/telemetry/tracing.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/utils.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/validation.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest.egg-info/SOURCES.txt +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest.egg-info/dependency_links.txt +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest.egg-info/requires.txt +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest.egg-info/top_level.txt +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/mypy.ini +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/pdm.lock +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/pyproject.toml +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/run-black +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/run-isort +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/run-mypy +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/setup.cfg +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/data_manifests/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/data_manifests/jira/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/data_manifests/jira/test_generator.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_branches.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_commits.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_diff.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_graph_teams.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_graph_users.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_iterations.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_prs.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_repos.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_threads.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/test_ado_adapter.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/test_ado_client.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/test_smoke_test_ado_adapter.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/utils.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/gitlab/fixtures/raw_organization_from_rest_api.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/gitlab/fixtures/raw_organizations_page_1.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/gitlab/fixtures/raw_organizations_page_2.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/gitlab/test_gitlab_adapter.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/gitlab/test_gitlab_client.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/gitlab/utils.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/test_git_adapter.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/boards.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/boards_empty_agile_payload.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/boards_sprints_for_board_1.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/boards_sprints_for_board_1_links.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/boards_sprints_not_supported.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/fields.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/issueLinkType.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/issues.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/issues_for_custom_fields.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/issuetype.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/priority.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/project.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/project_components_OJ.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/project_versions_JFR.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/project_versions_OJ.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/resolution.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/status.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/worklog_deleted.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/worklog_list.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/worklog_updated.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/jellyfish_custom_fields.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/jellyfish_custom_fields_empty_response.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/jellyfish_issue_metadata.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/results/project_version_component.json +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_custom_fields_comparison.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_custom_fields_jellyfish_retrieval.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_auth.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_boards_and_sprints.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_fields.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_issuelinktype.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_issuetype.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_priority.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_projects_and_versions.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_resolutions.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_status.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_users.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_issues.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_worklogs.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/utils.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/test_adaptive_throttler.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/test_file_operations.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/utils/__init__.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/utils/test_diagnostics.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/utils/test_logging_helper.py +0 -0
- {jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/utils/test_util_functions.py +0 -0
|
@@ -219,7 +219,8 @@ class AdaptiveThrottler:
|
|
|
219
219
|
|
|
220
220
|
with self._lock:
|
|
221
221
|
self._response_time_histogram.measure(
|
|
222
|
-
value=response_time,
|
|
222
|
+
value=response_time,
|
|
223
|
+
attributes=self.metrics_attrs,
|
|
223
224
|
)
|
|
224
225
|
self._total_requests_counter.add(amount=1, attributes=self.metrics_attrs)
|
|
225
226
|
|
|
@@ -248,10 +249,14 @@ class AdaptiveThrottler:
|
|
|
248
249
|
)
|
|
249
250
|
|
|
250
251
|
self._request_rate_gauge.measure(
|
|
251
|
-
value=self._request_rate,
|
|
252
|
+
value=self._request_rate,
|
|
253
|
+
attributes=self.metrics_attrs,
|
|
254
|
+
record_immediate=True,
|
|
252
255
|
)
|
|
253
|
-
self._backoff_counter.add(
|
|
254
|
-
|
|
256
|
+
self._backoff_counter.add(
|
|
257
|
+
amount=1, attributes=self.metrics_attrs, record_immediate=True
|
|
258
|
+
)
|
|
259
|
+
self._backoff_time_histogram.measure(value=backoff_time, record_immediate=True)
|
|
255
260
|
|
|
256
261
|
time.sleep(backoff_time)
|
|
257
262
|
elif self._request_rate < self._initial_request_rate:
|
|
@@ -272,9 +277,13 @@ class AdaptiveThrottler:
|
|
|
272
277
|
self._response_within_threshold_counter = 0
|
|
273
278
|
|
|
274
279
|
self._request_rate_gauge.measure(
|
|
275
|
-
value=self._request_rate,
|
|
280
|
+
value=self._request_rate,
|
|
281
|
+
attributes=self.metrics_attrs,
|
|
282
|
+
record_immediate=True,
|
|
283
|
+
)
|
|
284
|
+
self._reverse_backoff_counter.add(
|
|
285
|
+
amount=1, attributes=self.metrics_attrs, record_immediate=True
|
|
276
286
|
)
|
|
277
|
-
self._reverse_backoff_counter.add(amount=1, attributes=self.metrics_attrs)
|
|
278
287
|
|
|
279
288
|
send_to_agent_log_file(
|
|
280
289
|
f"Request rate increased to {self._request_rate:.4f} rps",
|
|
@@ -34,6 +34,8 @@ GIT_DEFAULT_API_ENDPOINT = 'https://api.github.com'
|
|
|
34
34
|
|
|
35
35
|
GQL_RATE_LIMIT_QUERY_BLOCK = "rateLimit {remaining, resetAt}"
|
|
36
36
|
|
|
37
|
+
GITHUB_STATUSES_TO_RETRY_ON = tuple(list(DEFAULT_HTTP_CODES_TO_RETRY_ON) + [403])
|
|
38
|
+
|
|
37
39
|
|
|
38
40
|
def parse_date(dt):
|
|
39
41
|
if dt is None:
|
|
@@ -237,10 +239,10 @@ class GithubClient:
|
|
|
237
239
|
if e.response.status_code == 401:
|
|
238
240
|
self._update_token()
|
|
239
241
|
continue
|
|
240
|
-
# We can get transient
|
|
242
|
+
# We can get transient errors that have to do with rate limiting,
|
|
241
243
|
# but aren't directly related to the above GqlRateLimitedExceptionInner logic.
|
|
242
244
|
# Do a simple retry loop here
|
|
243
|
-
elif e.response.status_code
|
|
245
|
+
elif e.response.status_code in GITHUB_STATUSES_TO_RETRY_ON:
|
|
244
246
|
pass
|
|
245
247
|
else:
|
|
246
248
|
raise
|
|
@@ -452,7 +454,7 @@ class GithubClient:
|
|
|
452
454
|
# HACK: A 403 appears to happen after we have been
|
|
453
455
|
# rate-limited when hitting certain URLs. Add 403s
|
|
454
456
|
# to HTTP Codes to retry
|
|
455
|
-
statuses_to_retry =
|
|
457
|
+
statuses_to_retry = GITHUB_STATUSES_TO_RETRY_ON
|
|
456
458
|
result = retry_for_status(self.session.get, url, statuses_to_retry=statuses_to_retry)
|
|
457
459
|
result.raise_for_status()
|
|
458
460
|
return result.json()
|
|
@@ -471,7 +473,7 @@ class GithubClient:
|
|
|
471
473
|
# HACK: A 403 appears to happen after we have been
|
|
472
474
|
# rate-limited when hitting certain URLs. Add 403s
|
|
473
475
|
# to HTTP Codes to retry
|
|
474
|
-
statuses_to_retry =
|
|
476
|
+
statuses_to_retry = GITHUB_STATUSES_TO_RETRY_ON
|
|
475
477
|
result: requests.Response = retry_for_status(
|
|
476
478
|
self.session.get, url, statuses_to_retry=statuses_to_retry
|
|
477
479
|
)
|
|
@@ -495,7 +497,7 @@ class GithubClient:
|
|
|
495
497
|
# HACK: A 403 appears to happen after we have been
|
|
496
498
|
# rate-limited when hitting certain URLs. Add 403s
|
|
497
499
|
# to HTTP Codes to retry
|
|
498
|
-
statuses_to_retry =
|
|
500
|
+
statuses_to_retry = GITHUB_STATUSES_TO_RETRY_ON
|
|
499
501
|
while True:
|
|
500
502
|
url = f'{self.rest_api_url}/repos/{org_login}/{repo_name}/labels?per_page={page_size}&page={page_number}'
|
|
501
503
|
result = retry_for_status(self.session.get, url, statuses_to_retry=statuses_to_retry)
|
|
@@ -42,19 +42,28 @@ class JellyMetricBase:
|
|
|
42
42
|
if not _METRIC_EXPORTER:
|
|
43
43
|
logger.info("No exporter configured. Using ConsoleMetricExporter for NoOp metrics.")
|
|
44
44
|
self._reader = PeriodicExportingMetricReader(ConsoleMetricExporter())
|
|
45
|
-
self._provider
|
|
45
|
+
self._provider = NoOpMeterProvider()
|
|
46
46
|
else:
|
|
47
47
|
self._reader = PeriodicExportingMetricReader(_METRIC_EXPORTER)
|
|
48
48
|
self._provider = MeterProvider(metric_readers=[self._reader])
|
|
49
49
|
|
|
50
|
-
atexit.register(self.
|
|
50
|
+
atexit.register(self.shutdown_reader)
|
|
51
51
|
|
|
52
52
|
def _get_meter(self):
|
|
53
53
|
return self._provider.get_meter(__name__)
|
|
54
54
|
|
|
55
|
-
def
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
def shutdown_reader(self):
|
|
56
|
+
"""Ensures the reader is flushed and shutdown at exit."""
|
|
57
|
+
current_log_level = logger.level
|
|
58
|
+
|
|
59
|
+
# The OTel library will log a warning message if .shutdown is called on a shutdown reader, but there isn't any
|
|
60
|
+
# way to check if the reader is already shutdown. This is a workaround to suppress the warning message.
|
|
61
|
+
try:
|
|
62
|
+
logger.setLevel(logging.ERROR)
|
|
63
|
+
self._reader.force_flush()
|
|
64
|
+
self._reader.shutdown()
|
|
65
|
+
finally:
|
|
66
|
+
logger.setLevel(current_log_level)
|
|
58
67
|
|
|
59
68
|
|
|
60
69
|
class JellyGauge(JellyMetricBase):
|
|
@@ -98,7 +107,6 @@ class JellyGauge(JellyMetricBase):
|
|
|
98
107
|
Set record_immediate to be true if you want to immediately flush the reader after this metric is collected -- should only
|
|
99
108
|
be used in short-lived process situations.
|
|
100
109
|
"""
|
|
101
|
-
|
|
102
110
|
logger.debug(
|
|
103
111
|
f"Received measure call for {self._name}, reporting measurement {value}, {attributes}"
|
|
104
112
|
)
|
|
@@ -108,6 +116,7 @@ class JellyGauge(JellyMetricBase):
|
|
|
108
116
|
self._internal_gauge = self._meter.create_observable_gauge(
|
|
109
117
|
name=self._name, callbacks=[self._callback]
|
|
110
118
|
)
|
|
119
|
+
|
|
111
120
|
if record_immediate:
|
|
112
121
|
self._reader.collect()
|
|
113
122
|
|
|
@@ -115,7 +124,6 @@ class JellyGauge(JellyMetricBase):
|
|
|
115
124
|
"""
|
|
116
125
|
Callback function for async gauge. Clears the observations as they're reported.
|
|
117
126
|
"""
|
|
118
|
-
|
|
119
127
|
logger.debug(
|
|
120
128
|
f"Received callback function call for {self._name}, reporting observations {self._observations}"
|
|
121
129
|
)
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/github/test_github_gql_client.py
RENAMED
|
@@ -21,6 +21,13 @@ TEST_BASE_URL = 'https://gav.com/gql'
|
|
|
21
21
|
GQL_DATETIME_STR = "2024-12-29T12:00:58Z"
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
@pytest.fixture()
|
|
25
|
+
def client() -> GithubClient:
|
|
26
|
+
# Mock out a Github GQL Client
|
|
27
|
+
github_auth_config = GithubAuthConfig(company_slug='a company', base_url=TEST_BASE_URL, token='test')
|
|
28
|
+
return GithubClient(github_auth_config)
|
|
29
|
+
|
|
30
|
+
|
|
24
31
|
def test_gql_page_results_block():
|
|
25
32
|
"""This is a sanity check that the GQL_PAGE_INFO_BLOCK and GQL_RATE_LIMIT_QUERY_BLOCK
|
|
26
33
|
are valid. This are pretty vague smoke tests... it's unlikely anybody would mess with
|
|
@@ -53,12 +60,9 @@ def test_git_auth_config_base_url():
|
|
|
53
60
|
assert client.rest_api_url == github_api_url
|
|
54
61
|
assert client.gql_base_url == f'{github_api_url}/graphql'
|
|
55
62
|
|
|
56
|
-
def test_get_rate_limit(requests_mock: requests_mock.Mocker):
|
|
63
|
+
def test_get_rate_limit(requests_mock: requests_mock.Mocker, client: GithubClient):
|
|
57
64
|
# Mock classes/data
|
|
58
65
|
session = requests.Session()
|
|
59
|
-
# Mock out a Github GQL Client
|
|
60
|
-
github_auth_config = GithubAuthConfig(company_slug='a company', base_url=TEST_BASE_URL, session=session, token='test')
|
|
61
|
-
client = GithubClient(github_auth_config)
|
|
62
66
|
client.session = session
|
|
63
67
|
|
|
64
68
|
def _test_get_rate_limit_inner(remaining_rate_limit: int, reset_at_rate_limit_str: str):
|
|
@@ -89,7 +93,7 @@ def test_get_rate_limit(requests_mock: requests_mock.Mocker):
|
|
|
89
93
|
_test_get_rate_limit_inner('cat', GQL_DATETIME_STR)
|
|
90
94
|
|
|
91
95
|
|
|
92
|
-
def test_get_raw_gql_result_simple(requests_mock: requests_mock.Mocker):
|
|
96
|
+
def test_get_raw_gql_result_simple(requests_mock: requests_mock.Mocker, client: GithubClient):
|
|
93
97
|
# Test Data
|
|
94
98
|
test_query_body = "test_query_body"
|
|
95
99
|
# Mock classes/data
|
|
@@ -97,9 +101,6 @@ def test_get_raw_gql_result_simple(requests_mock: requests_mock.Mocker):
|
|
|
97
101
|
session_mock_caller_data = {'query': test_query_body}
|
|
98
102
|
session_mock_return_data = {'data': {'test': {'remaining': 'test', 'resetAt': 'test'}}}
|
|
99
103
|
requests_mock.post(url=f'{TEST_BASE_URL}/graphql', json=session_mock_return_data)
|
|
100
|
-
# Mock out a Github GQL Client
|
|
101
|
-
github_auth_config = GithubAuthConfig(company_slug='a company', base_url=TEST_BASE_URL, session=session, token='test')
|
|
102
|
-
client = GithubClient(github_auth_config)
|
|
103
104
|
client.session = session
|
|
104
105
|
|
|
105
106
|
# call function
|
|
@@ -109,13 +110,10 @@ def test_get_raw_gql_result_simple(requests_mock: requests_mock.Mocker):
|
|
|
109
110
|
assert requests_mock.last_request.json() == session_mock_caller_data
|
|
110
111
|
|
|
111
112
|
|
|
112
|
-
def test_get_raw_gql_result_force_error_raise(mocker, requests_mock: requests_mock.Mocker):
|
|
113
|
+
def test_get_raw_gql_result_force_error_raise(mocker, requests_mock: requests_mock.Mocker, client: GithubClient):
|
|
113
114
|
mocker.patch('time.sleep', return_value=None)
|
|
114
115
|
# Mock classes/data
|
|
115
116
|
session = requests.Session()
|
|
116
|
-
# Mock out a Github GQL Client
|
|
117
|
-
github_auth_config = GithubAuthConfig(company_slug='A Company', base_url=TEST_BASE_URL, session=session, token='test')
|
|
118
|
-
client = GithubClient(github_auth_config)
|
|
119
117
|
client.session = session
|
|
120
118
|
|
|
121
119
|
requests_mock.post(
|
|
@@ -153,7 +151,7 @@ def test_get_raw_gql_result_force_error_raise(mocker, requests_mock: requests_mo
|
|
|
153
151
|
client.get_raw_result(query_body='', max_attempts=2)
|
|
154
152
|
|
|
155
153
|
|
|
156
|
-
def test_get_raw_gql_result_successful_retry(mocker, requests_mock: requests_mock.Mocker):
|
|
154
|
+
def test_get_raw_gql_result_successful_retry(mocker, requests_mock: requests_mock.Mocker, client: GithubClient):
|
|
157
155
|
mocker.patch('time.sleep', return_value=None)
|
|
158
156
|
session = requests.Session()
|
|
159
157
|
successful_data = {'success': True}
|
|
@@ -169,15 +167,57 @@ def test_get_raw_gql_result_successful_retry(mocker, requests_mock: requests_moc
|
|
|
169
167
|
],
|
|
170
168
|
)
|
|
171
169
|
|
|
172
|
-
# Mock out a Github GQL Client
|
|
173
|
-
github_auth_config = GithubAuthConfig(company_slug='A Company', base_url=TEST_BASE_URL, session=session, token='test')
|
|
174
|
-
client = GithubClient(github_auth_config)
|
|
175
170
|
client.session = session
|
|
176
171
|
|
|
177
172
|
data = client.get_raw_result(query_body='', max_attempts=10)
|
|
178
173
|
assert data == successful_data
|
|
179
174
|
|
|
180
175
|
|
|
176
|
+
def test_github_client_error_raise_403(mocker, requests_mock: requests_mock.Mocker, client: GithubClient):
|
|
177
|
+
mocker.patch('time.sleep', return_value=None)
|
|
178
|
+
session = requests.Session()
|
|
179
|
+
successful_data = {'success': True}
|
|
180
|
+
requests_mock.post(
|
|
181
|
+
url=f'{TEST_BASE_URL}/graphql',
|
|
182
|
+
response_list=[
|
|
183
|
+
{'status_code': 403},
|
|
184
|
+
],
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Mock out a Github GQL Client
|
|
188
|
+
client.session = session
|
|
189
|
+
|
|
190
|
+
retry_count = 10
|
|
191
|
+
with pytest.raises(requests.HTTPError):
|
|
192
|
+
client.get_raw_result(query_body='', max_attempts=retry_count)
|
|
193
|
+
assert requests_mock.call_count == retry_count
|
|
194
|
+
|
|
195
|
+
def test_github_client_error_resolves_after_retry(mocker, requests_mock: requests_mock.Mocker, client: GithubClient):
|
|
196
|
+
mocker.patch('time.sleep', return_value=None)
|
|
197
|
+
session = requests.Session()
|
|
198
|
+
successful_data = {'mantra': 'never give UP!'}
|
|
199
|
+
response_list = [
|
|
200
|
+
# A Beautiful Error Medley
|
|
201
|
+
{'status_code': 403},
|
|
202
|
+
{'status_code': 429},
|
|
203
|
+
{'status_code': 500},
|
|
204
|
+
{'status_code': 502},
|
|
205
|
+
{'status_code': 503},
|
|
206
|
+
{'status_code': 504},
|
|
207
|
+
{'json': successful_data}
|
|
208
|
+
]
|
|
209
|
+
retry_count = len(response_list)
|
|
210
|
+
requests_mock.post(
|
|
211
|
+
url=f'{TEST_BASE_URL}/graphql',
|
|
212
|
+
response_list=response_list,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Mock out a Github GQL Client
|
|
216
|
+
client.session = session
|
|
217
|
+
|
|
218
|
+
assert client.get_raw_result(query_body='', max_attempts=retry_count) == successful_data
|
|
219
|
+
assert requests_mock.call_count == retry_count
|
|
220
|
+
|
|
181
221
|
def test_page_results_gql(mocker, requests_mock: requests_mock.Mocker):
|
|
182
222
|
session = requests.Session()
|
|
183
223
|
# Mock out a Github GQL Client
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/jira/adapters/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/jira/generator.py
RENAMED
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/jf_ingest/data_manifests/jira/manifest_base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/data_manifests/jira/test_generator.py
RENAMED
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_branches.json
RENAMED
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_commits.json
RENAMED
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_graph_teams.json
RENAMED
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_graph_users.json
RENAMED
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_iterations.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/fixtures/raw_threads.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/ado/test_smoke_test_ado_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_git/gitlab/test_gitlab_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/boards.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/fields.json
RENAMED
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/issues.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/priority.json
RENAMED
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/project.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/fixtures/api_responses/status.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_custom_fields_comparison.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_fields.py
RENAMED
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_issuelinktype.py
RENAMED
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_issuetype.py
RENAMED
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_priority.py
RENAMED
|
File without changes
|
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_resolutions.py
RENAMED
|
File without changes
|
{jf_ingest-0.0.151.dev0 → jf_ingest-0.0.152.dev0}/tests/jf_jira/test_jira_download_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|