Skip to content

Commit 57ab737

Browse files
committed
Merge branch 'main' into pnilan/feat/in-line-validation-strategy
2 parents c10c497 + 9b2de4f commit 57ab737

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+3139
-861
lines changed

.github/workflows/connector-tests.yml

Lines changed: 76 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -72,28 +72,23 @@ jobs:
7272
cdk_extra: n/a
7373
- connector: source-shopify
7474
cdk_extra: n/a
75-
# Chargebee is being flaky:
76-
# - connector: source-chargebee
77-
# cdk_extra: n/a
78-
# This one is behind in CDK updates and can't be used as tests until it is updated:
79-
# - connector: destination-pinecone
80-
# cdk_extra: vector-db-based
8175
- connector: source-google-drive
8276
cdk_extra: file-based
8377
- connector: destination-motherduck
8478
cdk_extra: sql
85-
# ZenDesk currently failing (as of 2024-12-02)
86-
# TODO: Re-enable once fixed
87-
# - connector: source-zendesk-support
88-
# cdk_extra: n/a
89-
# TODO: These are manifest connectors and won't work as expected until we
90-
# add `--use-local-cdk` support for manifest connectors.
9179
- connector: source-amplitude
9280
cdk_extra: n/a
81+
- connector: source-intercom
82+
cdk_extra: n/a
9383
- connector: source-pokeapi
9484
cdk_extra: n/a
9585

96-
name: "Check: '${{matrix.connector}}' (skip=${{needs.cdk_changes.outputs['src'] == 'false' || needs.cdk_changes.outputs[matrix.cdk_extra] == 'false'}})"
86+
# CDK Tests cannot build the Connector object (constructor args not optional).
87+
# - connector: source-zendesk-support
88+
# cdk_extra: n/a
89+
90+
name: "${{ needs.cdk_changes.outputs[matrix.cdk_extra] == 'false' && 'Skipped Check' || 'Check' }}: ${{matrix.connector}}"
91+
if: needs.cdk_changes.outputs['src'] == 'true'
9792
permissions:
9893
checks: write
9994
contents: write # Required for creating commit statuses
@@ -125,110 +120,89 @@ jobs:
125120
repository: airbytehq/airbyte
126121
ref: master
127122
path: airbyte
123+
128124
- name: Set up Python
125+
if: steps.no_changes.outputs.status != 'cancelled'
129126
uses: actions/setup-python@v5
130127
with:
131128
python-version: "3.11"
132-
# Create initial pending status for test report
133-
- name: Create Pending Test Report Status
129+
130+
- name: Set up `uv`
131+
if: steps.no_changes.outputs.status != 'cancelled'
132+
uses: astral-sh/[email protected]
133+
134+
- name: Set up `poe`
135+
if: steps.no_changes.outputs.status != 'cancelled'
136+
run: |
137+
uv tool install poethepoet
138+
139+
- name: Set up Poetry
140+
if: steps.no_changes.outputs.status != 'cancelled'
141+
uses: Gr1N/setup-poetry@v9
142+
with:
143+
poetry-version: "2.0.1"
144+
145+
- name: Get Connector Language
146+
if: steps.no_changes.outputs.status != 'cancelled'
147+
working-directory: airbyte/airbyte-integrations/connectors/${{ matrix.connector }}
148+
run: |
149+
# Get the language of the connector from the metadata file
150+
CONNECTOR_LANGUAGE=$(poe -qq get-language)
151+
echo "CONNECTOR_LANGUAGE=$CONNECTOR_LANGUAGE" | tee -a $GITHUB_ENV
152+
153+
- name: Install CDK with Poetry
134154
if: steps.no_changes.outputs.status != 'cancelled'
135-
env:
136-
GH_TOKEN: ${{ secrets.GH_PAT_MAINTENANCE_OCTAVIA }}
137155
run: |
138-
HEAD_SHA="${{ github.event.pull_request.head.sha || github.sha }}"
139-
gh api \
140-
--method POST \
141-
-H "Accept: application/vnd.github+json" \
142-
-H "X-GitHub-Api-Version: 2022-11-28" \
143-
repos/${{ github.repository }}/statuses/$HEAD_SHA \
144-
-f state="pending" \
145-
-f description="Running connector tests..." \
146-
-f context="${{ matrix.connector }} Test Report"
147-
148-
- name: Test Connector
156+
cd airbyte-python-cdk
157+
poetry install --all-extras
158+
159+
- name: Fetch Connector Secrets
149160
if: steps.no_changes.outputs.status != 'cancelled'
150161
timeout-minutes: 90
162+
working-directory: airbyte-python-cdk
151163
env:
152164
GCP_GSM_CREDENTIALS: ${{ secrets.GCP_GSM_CREDENTIALS }}
153165
POETRY_DYNAMIC_VERSIONING_BYPASS: "0.0.0"
154166
run: |
155-
cd airbyte
156-
make tools.airbyte-ci.install
157-
airbyte-ci \
158-
--ci-report-bucket-name=airbyte-ci-reports-multi \
159-
connectors \
160-
--name ${{matrix.connector}} \
161-
--use-local-cdk \
162-
test \
163-
--fail-fast \
164-
--skip-step qa_checks \
165-
--skip-step connector_live_tests
166-
167-
- name: Evaluate Test
168-
id: evaluate_output
169-
if: always() && steps.no_changes.outputs.status != 'cancelled'
167+
poetry run airbyte-cdk secrets fetch ${{ matrix.connector }}
168+
169+
- name: Bump to Dev Branch CDK [Python Connectors]
170+
if: env.CONNECTOR_LANGUAGE == 'python'
171+
working-directory: airbyte/airbyte-integrations/connectors/${{ matrix.connector }}
170172
run: |
171-
# save job output json file as ci step output
172-
json_output_file=$(find airbyte/airbyte-ci/connectors/pipelines/pipeline_reports -name 'output.json' -print -quit)
173-
job_output=$(cat ${json_output_file})
174-
success=$(echo ${job_output} | jq -r '.success')
175-
failed_step=$(echo ${job_output} | jq -r '.failed_steps | select(length > 0) | .[0] // "None"')
176-
run_duration=$(echo ${job_output} | jq -r '.run_duration')
177-
html_report_url=$(echo ${job_output} | jq -r '.html_report_url')
178-
echo "## Job Output for ${{matrix.connector}}" >> $GITHUB_STEP_SUMMARY
179-
echo "- [HTML Report](${html_report_url})" >> $GITHUB_STEP_SUMMARY
180-
echo "- Success: ${success}" >> $GITHUB_STEP_SUMMARY
181-
echo "- Test Duration: $(printf "%.0f" ${run_duration})s" >> $GITHUB_STEP_SUMMARY
182-
if [ "${success}" != "true" ]; then
183-
echo "- Failed Step: ${failed_step}" >> $GITHUB_STEP_SUMMARY
184-
fi
185-
echo -e "\n[Download Job Output](${{steps.upload_job_output.outputs.artifact-url}})" >> $GITHUB_STEP_SUMMARY
186-
if [ "${success}" != "true" ]; then
187-
echo "::error::Test failed for connector '${{ matrix.connector }}' on step '${failed_step}'. "
188-
exit 1
189-
fi
190-
echo "See the execution report for details: ${html_report_url}"
191-
echo "success=${success}" >> $GITHUB_OUTPUT
192-
echo "html_report_url=${html_report_url}" >> $GITHUB_OUTPUT
173+
echo "Using CDK ref ${{ github.event.pull_request.head.sha || github.sha }}"
174+
poe use-cdk-branch ${{ github.event.pull_request.head.sha || github.sha }}
175+
poetry install --all-extras
176+
177+
- name: Run Unit Tests [Python Connectors]
178+
if: env.CONNECTOR_LANGUAGE == 'python'
179+
working-directory: airbyte/airbyte-integrations/connectors/${{ matrix.connector }}
180+
run: |
181+
poe test-unit-tests
182+
183+
- name: Run FAST Standard Tests [Python Connectors]
184+
if: env.CONNECTOR_LANGUAGE == 'python'
185+
working-directory: airbyte/airbyte-integrations/connectors/${{ matrix.connector }}
186+
env:
187+
GCP_GSM_CREDENTIALS: ${{ secrets.GCP_GSM_CREDENTIALS }}
188+
POETRY_DYNAMIC_VERSIONING_BYPASS: "0.0.0"
189+
run: |
190+
poetry run airbyte-cdk connector test
193191
194-
# Update the test report status with results
195-
- name: Update Test Report Status
196-
if: always() && steps.no_changes.outputs.status != 'cancelled' && steps.evaluate_output.outcome == 'success'
192+
- name: Run FAST Standard Tests [Manifest-Only Connectors]
193+
if: env.CONNECTOR_LANGUAGE == 'manifest-only'
194+
working-directory: airbyte-python-cdk
197195
env:
198-
GH_TOKEN: ${{ secrets.GH_PAT_MAINTENANCE_OCTAVIA }}
196+
GCP_GSM_CREDENTIALS: ${{ secrets.GCP_GSM_CREDENTIALS }}
197+
POETRY_DYNAMIC_VERSIONING_BYPASS: "0.0.0"
199198
run: |
200-
HEAD_SHA="${{ github.event.pull_request.head.sha || github.sha }}"
201-
gh api \
202-
--method POST \
203-
-H "Accept: application/vnd.github+json" \
204-
-H "X-GitHub-Api-Version: 2022-11-28" \
205-
repos/${{ github.repository }}/statuses/$HEAD_SHA \
206-
-f state="${{ steps.evaluate_output.outputs.success == 'true' && 'success' || 'failure' }}" \
207-
-f target_url="${{ steps.evaluate_output.outputs.html_report_url }}" \
208-
-f description="Click Details to view the test report" \
209-
-f context="${{ matrix.connector }} Test Report"
210-
211-
# Create failure status if report generation failed
212-
- name: Create Report Generation Failed Status
213-
if: always() && steps.no_changes.outputs.status != 'cancelled' && steps.evaluate_output.outcome != 'success'
199+
poetry run airbyte-cdk connector test ${{ matrix.connector }}
200+
201+
- name: Container Build and Test [All Connectors]
202+
if: steps.no_changes.outputs.status != 'cancelled'
203+
working-directory: airbyte-python-cdk
214204
env:
215-
GH_TOKEN: ${{ secrets.GH_PAT_MAINTENANCE_OCTAVIA }}
205+
GCP_GSM_CREDENTIALS: ${{ secrets.GCP_GSM_CREDENTIALS }}
206+
POETRY_DYNAMIC_VERSIONING_BYPASS: "0.0.0"
216207
run: |
217-
HEAD_SHA="${{ github.event.pull_request.head.sha || github.sha }}"
218-
gh api \
219-
--method POST \
220-
-H "Accept: application/vnd.github+json" \
221-
-H "X-GitHub-Api-Version: 2022-11-28" \
222-
repos/${{ github.repository }}/statuses/$HEAD_SHA \
223-
-f state="failure" \
224-
-f description="Failed to run connector tests." \
225-
-f context="${{ matrix.connector }} Test Report"
226-
227-
# Upload the job output to the artifacts
228-
- name: Upload Job Output
229-
id: upload_job_output
230-
if: always() && steps.no_changes.outputs.status != 'cancelled'
231-
uses: actions/upload-artifact@v4
232-
with:
233-
name: ${{matrix.connector}}-job-output
234-
path: airbyte/airbyte-ci/connectors/pipelines/pipeline_reports
208+
poetry run airbyte-cdk image test ${{ matrix.connector }}

.github/workflows/pytest_fast.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ jobs:
7070
poetry run coverage html -d htmlcov
7171
poetry run coverage xml -o htmlcov/coverage.xml
7272
73+
- name: Publish Test Results
74+
uses: EnricoMi/publish-unit-test-result-action@v2
75+
if: always() && !cancelled()
76+
continue-on-error: true
77+
with:
78+
check_name: "PyTest Results (Fast)"
79+
large_files: true
80+
files: |
81+
build/test-results/**/*.xml
7382
- name: Upload coverage to GitHub Artifacts
7483
if: always()
7584
uses: actions/upload-artifact@v4

.github/workflows/pytest_matrix.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ jobs:
9393
poetry run coverage html -d htmlcov
9494
poetry run coverage xml -o htmlcov/coverage.xml
9595
96+
- name: Publish Test Results
97+
uses: EnricoMi/publish-unit-test-result-action@v2
98+
if: always() && !cancelled() && steps.changes.outputs.src == 'true' && matrix.python-version == '3.11'
99+
continue-on-error: true
100+
with:
101+
check_name: "PyTest Results (Full)"
102+
large_files: true
103+
files: |
104+
build/test-results/**/*.xml
96105
- name: Upload coverage to GitHub Artifacts
97106
if: always() && steps.changes.outputs.src == 'true'
98107
uses: actions/upload-artifact@v4

.github/workflows/test-command.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ jobs:
113113
--verbose
114114
-m "flaky and not super_slow"
115115
116+
- name: Publish Test Results
117+
uses: EnricoMi/publish-unit-test-result-action@v2
118+
if: always() && !cancelled() && matrix.python-version == '3.11'
119+
continue-on-error: true
120+
with:
121+
check_name: "PyTest Results (On-Demand)"
122+
large_files: true
123+
files: |
124+
build/test-results/**/*.xml
116125
- name: Post CI Success to GitHub
117126
run: |
118127
curl --request POST \

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Build and test results
2+
build
3+
test-results
4+
15
# Node artifacts
26
node_modules
37

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,4 @@ repos:
7474
args: [--config-file=mypy.ini, --show-column-numbers]
7575
files: ^airbyte_cdk/
7676
pass_filenames: true
77+
additional_dependencies: ["types-requests", "types-PyYAML"]

airbyte_cdk/cli/airbyte_cdk/_connector.py

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ def connector_cli_group() -> None:
101101
pass
102102

103103

104-
@connector_cli_group.command()
104+
@connector_cli_group.command("test")
105105
@click.argument(
106106
"connector",
107107
required=False,
@@ -114,10 +114,18 @@ def connector_cli_group() -> None:
114114
default=False,
115115
help="Only collect tests, do not run them.",
116116
)
117-
def test(
117+
@click.option(
118+
"--pytest-arg",
119+
"pytest_args", # ← map --pytest-arg into pytest_args
120+
type=str,
121+
multiple=True,
122+
help="Additional argument(s) to pass to pytest. Can be specified multiple times.",
123+
)
124+
def connector_test(
118125
connector: str | Path | None = None,
119126
*,
120127
collect_only: bool = False,
128+
pytest_args: list[str] | None = None,
121129
) -> None:
122130
"""Run connector tests.
123131
@@ -130,19 +138,36 @@ def test(
130138
directory. If the current working directory is not a connector directory (e.g. starting
131139
with 'source-') and no connector name or path is provided, the process will fail.
132140
"""
141+
click.echo("Connector test command executed.")
142+
connector_name, connector_directory = resolve_connector_name_and_directory(connector)
143+
144+
pytest_args = pytest_args or []
145+
if collect_only:
146+
pytest_args.append("--collect-only")
147+
148+
run_connector_tests(
149+
connector_name=connector_name,
150+
connector_directory=connector_directory,
151+
extra_pytest_args=pytest_args,
152+
)
153+
154+
155+
def run_connector_tests(
156+
connector_name: str,
157+
connector_directory: Path,
158+
extra_pytest_args: list[str],
159+
) -> None:
133160
if pytest is None:
134161
raise ImportError(
135162
"pytest is not installed. Please install pytest to run the connector tests."
136163
)
137-
click.echo("Connector test command executed.")
138-
connector_name, connector_directory = resolve_connector_name_and_directory(connector)
139164

140165
connector_test_suite = create_connector_test_suite(
141166
connector_name=connector_name if not connector_directory else None,
142167
connector_directory=connector_directory,
143168
)
144169

145-
pytest_args: list[str] = []
170+
pytest_args: list[str] = ["-p", "airbyte_cdk.test.standard_tests.pytest_hooks"]
146171
if connector_directory:
147172
pytest_args.append(f"--rootdir={connector_directory}")
148173
os.chdir(str(connector_directory))
@@ -158,13 +183,18 @@ def test(
158183
test_file_path.parent.mkdir(parents=True, exist_ok=True)
159184
test_file_path.write_text(file_text)
160185

161-
if collect_only:
162-
pytest_args.append("--collect-only")
186+
if extra_pytest_args:
187+
pytest_args.extend(extra_pytest_args)
163188

164189
pytest_args.append(str(test_file_path))
190+
191+
test_results_dir = connector_directory / "build" / "test-results"
192+
test_results_dir.mkdir(parents=True, exist_ok=True)
193+
junit_xml_path = test_results_dir / "standard-tests-junit.xml"
194+
pytest_args.extend(["--junitxml", str(junit_xml_path)])
195+
165196
click.echo(f"Running tests from connector directory: {connector_directory}...")
166197
click.echo(f"Test file: {test_file_path}")
167-
click.echo(f"Collect only: {collect_only}")
168198
click.echo(f"Pytest args: {pytest_args}")
169199
click.echo("Invoking Pytest...")
170200
exit_code = pytest.main(

0 commit comments

Comments
 (0)