Skip to content

Commit dd250a4

Browse files
committed
airbyte-ci: run live tests on PRs
1 parent c9f45a0 commit dd250a4

File tree

10 files changed

+65
-16
lines changed

10 files changed

+65
-16
lines changed

.github/actions/run-airbyte-ci/action.yml

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ inputs:
1010
github_token:
1111
description: "GitHub token"
1212
required: false
13+
github_maintenance_token:
14+
description: "GitHub maintenance token"
15+
required: false
1316
dagger_cloud_token:
1417
description: "Dagger Cloud token"
1518
required: false
@@ -121,6 +124,7 @@ runs:
121124
CI_GIT_REPO_URL: ${{ inputs.git_repo_url }}
122125
CI_GIT_REVISION: ${{ inputs.git_revision || github.sha }}
123126
CI_GITHUB_ACCESS_TOKEN: ${{ inputs.github_token }}
127+
CI_GITHUB_MAINTENANCE_TOKEN: ${{ inputs.github_maintenance_token }}
124128
CI_JOB_KEY: ${{ inputs.ci_job_key }}
125129
CI_REPORT_BUCKET_NAME: ${{ inputs.report_bucket_name }}
126130
DAGGER_CLOUD_TOKEN: "${{ inputs.dagger_cloud_token }}"

.github/workflows/connectors_tests.yml

+2
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,12 @@ jobs:
126126
docker_hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }}
127127
docker_hub_username: ${{ secrets.DOCKER_HUB_USERNAME }}
128128
gcp_gsm_credentials: ${{ secrets.GCP_GSM_CREDENTIALS }}
129+
gcp_integration_tester_credentials: ${{ secrets.GCLOUD_INTEGRATION_TESTER }}
129130
sentry_dsn: ${{ secrets.SENTRY_AIRBYTE_CI_DSN }}
130131
git_branch: ${{ github.head_ref }}
131132
git_revision: ${{ steps.fetch_last_commit_id_pr.outputs.commit_id }}
132133
github_token: ${{ env.PAT }}
134+
github_maintenance_token: ${{ secrets.GH_PAT_MAINTENANCE_OSS }}
133135
s3_build_cache_access_key_id: ${{ secrets.SELF_RUNNER_AWS_ACCESS_KEY_ID }}
134136
s3_build_cache_secret_key: ${{ secrets.SELF_RUNNER_AWS_SECRET_ACCESS_KEY }}
135137
# A connector test can't take more than 5 hours to run (5 * 60 * 60 = 18000 seconds)

airbyte-ci/connectors/pipelines/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,7 @@ E.G.: running Poe tasks on the modified internal packages of the current branch:
773773

774774
| Version | PR | Description |
775775
| ------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
776+
| 4.27.0 | [#42574](https://github.com/airbytehq/airbyte/pull/42574) | Live tests: run from connectors test pipeline for connectors with sandbox connections |
776777
| 4.26.0 | [#42849](https://github.com/airbytehq/airbyte/pull/42849) | Send publish failures messages to `#connector-publish-failures` |
777778
| 4.25.4 | [#42463](https://github.com/airbytehq/airbyte/pull/42463) | Add validation before live test runs |
778779
| 4.25.3 | [#42437](https://github.com/airbytehq/airbyte/pull/42437) | Ugrade-cdk: Update to work with Python connectors using poetry |

airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/context.py

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def __init__(
5050
ci_gcp_credentials: Optional[Secret] = None,
5151
ci_git_user: Optional[str] = None,
5252
ci_github_access_token: Optional[Secret] = None,
53+
ci_github_maintenance_token: Optional[Secret] = None,
5354
connector_acceptance_test_image: str = DEFAULT_CONNECTOR_ACCEPTANCE_TEST_IMAGE,
5455
gha_workflow_run_url: Optional[str] = None,
5556
dagger_logs_url: Optional[str] = None,
@@ -134,6 +135,7 @@ def __init__(
134135
ci_gcp_credentials=ci_gcp_credentials,
135136
ci_git_user=ci_git_user,
136137
ci_github_access_token=ci_github_access_token,
138+
ci_github_maintenance_token=ci_github_maintenance_token,
137139
run_step_options=run_step_options,
138140
enable_report_auto_open=enable_report_auto_open,
139141
secret_stores=secret_stores,

airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/commands.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@
2626
GITHUB_GLOBAL_CONTEXT_FOR_TESTS = "Connectors CI tests"
2727
GITHUB_GLOBAL_DESCRIPTION_FOR_TESTS = "Running connectors tests"
2828
REGRESSION_TEST_MANUAL_APPROVAL_CONTEXT = "Regression Test Results Reviewed and Approved"
29-
TESTS_SKIPPED_BY_DEFAULT = [
30-
CONNECTOR_TEST_STEP_ID.CONNECTOR_LIVE_TESTS,
31-
]
3229

3330

3431
@click.command(
@@ -120,7 +117,6 @@ async def test(
120117
raise click.UsageError("Cannot use both --only-step and --skip-step at the same time.")
121118
if not only_steps:
122119
skip_steps = list(skip_steps)
123-
skip_steps += TESTS_SKIPPED_BY_DEFAULT
124120
if ctx.obj["is_ci"]:
125121
fail_if_missing_docker_hub_creds(ctx)
126122

@@ -150,6 +146,7 @@ async def test(
150146
git_repo_url=ctx.obj["git_repo_url"],
151147
ci_git_user=ctx.obj["ci_git_user"],
152148
ci_github_access_token=ctx.obj["ci_github_access_token"],
149+
ci_github_maintenance_token=ctx.obj["ci_github_maintenance_token"],
153150
ci_report_bucket=ctx.obj["ci_report_bucket_name"],
154151
report_output_prefix=ctx.obj["report_output_prefix"],
155152
gha_workflow_run_url=ctx.obj.get("gha_workflow_run_url"),

airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/context.py

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"unitTests": CONNECTOR_TEST_STEP_ID.UNIT,
2020
"integrationTests": CONNECTOR_TEST_STEP_ID.INTEGRATION,
2121
"acceptanceTests": CONNECTOR_TEST_STEP_ID.ACCEPTANCE,
22+
"liveTests": CONNECTOR_TEST_STEP_ID.CONNECTOR_LIVE_TESTS,
2223
}
2324

2425

airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/common.py

+50-11
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from functools import cached_property
1414
from pathlib import Path
1515
from textwrap import dedent
16-
from typing import ClassVar, List, Optional, Set
16+
from typing import Any, ClassVar, Dict, List, Optional, Set
1717

1818
import requests # type: ignore
1919
import semver
@@ -445,7 +445,7 @@ async def _run(self, current_acceptance_tests_result: StepResult) -> StepResult:
445445

446446

447447
class LiveTestSuite(Enum):
448-
ALL = "all"
448+
ALL = "live"
449449
REGRESSION = "regression"
450450
VALIDATION = "validation"
451451

@@ -557,13 +557,10 @@ def __init__(self, context: ConnectorContext) -> None:
557557
self.connector_image = context.docker_image.split(":")[0]
558558
options = self.context.run_step_options.step_params.get(CONNECTOR_TEST_STEP_ID.CONNECTOR_LIVE_TESTS, {})
559559

560-
self.connection_id = self.context.run_step_options.get_item_or_default(options, "connection-id", None)
561-
self.pr_url = self.context.run_step_options.get_item_or_default(options, "pr-url", None)
562-
563-
if not self.connection_id and self.pr_url:
564-
raise ValueError("`connection-id` and `pr-url` are required to run live tests.")
565-
566560
self.test_suite = self.context.run_step_options.get_item_or_default(options, "test-suite", LiveTestSuite.ALL.value)
561+
self.connection_id = self._get_connection_id(options)
562+
self.pr_url = self._get_pr_url(options)
563+
567564
self.test_dir = self.test_suite_to_dir[LiveTestSuite(self.test_suite)]
568565
self.control_version = self.context.run_step_options.get_item_or_default(options, "control-version", None)
569566
self.target_version = self.context.run_step_options.get_item_or_default(options, "target-version", "dev")
@@ -573,7 +570,30 @@ def __init__(self, context: ConnectorContext) -> None:
573570
self.connection_subset = self.context.run_step_options.get_item_or_default(options, "connection-subset", "sandboxes")
574571
self.run_id = os.getenv("GITHUB_RUN_ID") or str(int(time.time()))
575572

573+
def _get_connection_id(self, options: Dict[str, List[Any]]) -> Optional[str]:
574+
if self.context.is_pr:
575+
connection_id = self._get_connection_from_connection_options()
576+
self.logger.info(
577+
f"Context is {self.context.ci_context}; got connection_id={connection_id} from metadata.yaml liveTests connectionOptions."
578+
)
579+
else:
580+
connection_id = self.context.run_step_options.get_item_or_default(options, "connection-id", None)
581+
self.logger.info(f"Context is {self.context.ci_context}; got connection_id={connection_id} from input options.")
582+
return connection_id
583+
584+
def _get_pr_url(self, options: Dict[str, List[Any]]) -> Optional[str]:
585+
if self.context.is_pr:
586+
pull_request = self.context.pull_request.url if self.context.pull_request else None
587+
self.logger.info(f"Context is {self.context.ci_context}; got pull_request={pull_request} from context.")
588+
else:
589+
pull_request = self.context.run_step_options.get_item_or_default(options, "pr-url", None)
590+
self.logger.info(f"Context is {self.context.ci_context}; got pull_request={pull_request} from input options.")
591+
return pull_request
592+
576593
def _validate_job_can_run(self) -> None:
594+
assert self.connection_id, "`connection-id` is required to run live tests."
595+
assert self.pr_url, "`pr_url` is required to run live tests."
596+
577597
connector_type = self.context.connector.metadata.get("connectorType")
578598
connector_subtype = self.context.connector.metadata.get("connectorSubtype")
579599
assert connector_type == "source", f"Live tests can only run against source connectors, got `connectorType={connector_type}`."
@@ -582,6 +602,24 @@ def _validate_job_can_run(self) -> None:
582602
self.connection_subset == "sandboxes"
583603
), f"Live tests for database sources may only be run against sandbox connections, got `connection_subset={self.connection_subset}`."
584604

605+
if self.context.is_pr:
606+
connection_id_is_valid = False
607+
for test_suite in self.context.connector.metadata.get("connectorTestSuitesOptions", []):
608+
if test_suite["suite"] == "liveTests":
609+
assert self.connection_id in [option["connectionId"] for option in test_suite.get("connectionOptions", [])]
610+
connection_id_is_valid = True
611+
break
612+
assert connection_id_is_valid, f"Connection ID {self.connection_id} is not a valid sandbox connection ID."
613+
614+
def _get_connection_from_connection_options(self) -> Optional[str]:
615+
for test_suite in self.context.connector.metadata.get("connectorTestSuitesOptions", []):
616+
if test_suite["suite"] == "liveTests":
617+
for option in test_suite.get("connectionOptions", []):
618+
connection_id = option["connectionId"]
619+
connection_name = option["connectionName"]
620+
self.logger.info(f"Using connection {connection_name}; connectionId={connection_id}")
621+
return connection_id
622+
585623
async def _run(self, connector_under_test_container: Container) -> StepResult:
586624
"""Run the regression test suite.
587625
@@ -676,16 +714,17 @@ async def _build_test_container(self, target_container_id: str) -> Container:
676714
]
677715
)
678716
.with_secret_variable(
679-
"CI_GITHUB_ACCESS_TOKEN",
717+
"CI_GITHUB_MAINTENANCE_TOKEN",
680718
self.context.dagger_client.set_secret(
681-
"CI_GITHUB_ACCESS_TOKEN", self.context.ci_github_access_token.value if self.context.ci_github_access_token else ""
719+
"CI_GITHUB_MAINTENANCE_TOKEN",
720+
self.context.ci_github_maintenance_token.value if self.context.ci_github_maintenance_token else "",
682721
),
683722
)
684723
.with_exec(
685724
[
686725
"/bin/sh",
687726
"-c",
688-
f"poetry config http-basic.airbyte-platform-internal-source {self.github_user} $CI_GITHUB_ACCESS_TOKEN",
727+
f"poetry config http-basic.airbyte-platform-internal-source {self.github_user} $CI_GITHUB_MAINTENANCE_TOKEN",
689728
]
690729
)
691730
# Add GCP credentials from the environment and point google to their location (also required for connection-retriever)

airbyte-ci/connectors/pipelines/pipelines/cli/airbyte_ci.py

+1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ def is_current_process_wrapped_by_dagger_run() -> bool:
164164
@click.option("--pull-request-number", envvar="PULL_REQUEST_NUMBER", type=int)
165165
@click.option("--ci-git-user", default="octavia-squidington-iii", envvar="CI_GIT_USER", type=str)
166166
@click.option("--ci-github-access-token", envvar="CI_GITHUB_ACCESS_TOKEN", type=str, callback=wrap_in_secret)
167+
@click.option("--ci-github-maintenance-token", envvar="CI_GITHUB_MAINTENANCE_TOKEN", type=str, callback=wrap_in_secret)
167168
@click.option("--ci-report-bucket-name", envvar="CI_REPORT_BUCKET_NAME", type=str)
168169
@click.option("--ci-artifact-bucket-name", envvar="CI_ARTIFACT_BUCKET_NAME", type=str)
169170
@click.option(

airbyte-ci/connectors/pipelines/pipelines/models/contexts/pipeline_context.py

+2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def __init__(
8383
ci_gcp_credentials: Optional[Secret] = None,
8484
ci_git_user: Optional[str] = None,
8585
ci_github_access_token: Optional[Secret] = None,
86+
ci_github_maintenance_token: Optional[Secret] = None,
8687
run_step_options: RunStepOptions = RunStepOptions(),
8788
enable_report_auto_open: bool = True,
8889
secret_stores: Dict[str, SecretStore] | None = None,
@@ -129,6 +130,7 @@ def __init__(
129130
self.ci_report_bucket = ci_report_bucket
130131
self.ci_git_user = ci_git_user
131132
self.ci_github_access_token = ci_github_access_token
133+
self.ci_github_maintenance_token = ci_github_maintenance_token
132134
self.started_at = None
133135
self.stopped_at = None
134136
self.secrets_to_mask = []

airbyte-ci/connectors/pipelines/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "pipelines"
7-
version = "4.26.0"
7+
version = "4.27.0"
88
description = "Packaged maintained by the connector operations team to perform CI for connectors' pipelines"
99
authors = ["Airbyte <[email protected]>"]
1010

0 commit comments

Comments
 (0)