From 5cca0687aa068d32d656dacc12d698aaf1f85160 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Tue, 30 Jan 2024 09:49:50 +0100 Subject: [PATCH] airbyte-ci: Switch to prod pypi (#34606) --- .github/actions/run-airbyte-ci/action.yml | 5 ++ .../publish-airbyte-lib-command-manually.yml | 4 +- airbyte-ci/connectors/pipelines/README.md | 47 ++++++++++++------- .../airbyte_ci/connectors/publish/commands.py | 19 +++++++- .../airbyte_ci/connectors/publish/context.py | 4 ++ .../airbyte_ci/connectors/publish/pipeline.py | 10 ++++ .../airbyte_ci/poetry/publish/commands.py | 7 +-- .../airbyte_ci/steps/python_registry.py | 8 +++- .../connectors/pipelines/pipelines/consts.py | 2 +- .../contexts/python_registry_publish.py | 5 +- .../connectors/pipelines/pyproject.toml | 2 +- .../pipelines/tests/test_publish.py | 22 +++++---- 12 files changed, 95 insertions(+), 40 deletions(-) diff --git a/.github/actions/run-airbyte-ci/action.yml b/.github/actions/run-airbyte-ci/action.yml index 45e8262a5837..753c041727e7 100644 --- a/.github/actions/run-airbyte-ci/action.yml +++ b/.github/actions/run-airbyte-ci/action.yml @@ -79,6 +79,10 @@ inputs: python_registry_token: description: "Python registry API token to publish python package" required: false + python_registry_url: + description: "Python registry URL to publish python package" + default: "https://upload.pypi.org/legacy/" + required: false runs: using: "composite" @@ -135,6 +139,7 @@ runs: PRODUCTION: ${{ inputs.production }} PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} PYTHON_REGISTRY_TOKEN: ${{ inputs.python_registry_token }} + PYTHON_REGISTRY_URL: ${{ inputs.python_registry_url }} S3_BUILD_CACHE_ACCESS_KEY_ID: ${{ inputs.s3_build_cache_access_key_id }} S3_BUILD_CACHE_SECRET_KEY: ${{ inputs.s3_build_cache_secret_key }} SENTRY_DSN: ${{ inputs.sentry_dsn }} diff --git a/.github/workflows/publish-airbyte-lib-command-manually.yml b/.github/workflows/publish-airbyte-lib-command-manually.yml index a4fbfbc81495..e596444414d3 100644 --- a/.github/workflows/publish-airbyte-lib-command-manually.yml +++ b/.github/workflows/publish-airbyte-lib-command-manually.yml @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v3 - name: Publish id: publish-airbyte-lib - uses: ./.github/actions/run-dagger-pipeline + uses: ./.github/actions/run-airbyte-ci with: context: "manual" dagger_cloud_token: ${{ secrets.DAGGER_CLOUD_TOKEN }} @@ -53,5 +53,5 @@ jobs: s3_build_cache_access_key_id: ${{ secrets.SELF_RUNNER_AWS_ACCESS_KEY_ID }} s3_build_cache_secret_key: ${{ secrets.SELF_RUNNER_AWS_SECRET_ACCESS_KEY }} tailscale_auth_key: ${{ secrets.TAILSCALE_AUTH_KEY }} - subcommand: 'poetry --package-path=airbyte-lib publish --registry-url="https://test.pypi.org/legacy/"' + subcommand: "poetry --package-path=airbyte-lib publish" python_registry_token: ${{ secrets.PYPI_TOKEN }} diff --git a/airbyte-ci/connectors/pipelines/README.md b/airbyte-ci/connectors/pipelines/README.md index 263333e3f15e..3e8ccd074580 100644 --- a/airbyte-ci/connectors/pipelines/README.md +++ b/airbyte-ci/connectors/pipelines/README.md @@ -385,16 +385,18 @@ Publish all connectors modified in the head commit: `airbyte-ci connectors --mod ### Options -| Option | Required | Default | Mapped environment variable | Description | -| ------------------------------------ | -------- | --------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--pre-release/--main-release` | False | `--pre-release` | | Whether to publish the pre-release or the main release version of a connector. Defaults to pre-release. For main release you have to set the credentials to interact with the GCS bucket. | -| `--spec-cache-gcs-credentials` | False | | `SPEC_CACHE_GCS_CREDENTIALS` | The service account key to upload files to the GCS bucket hosting spec cache. | -| `--spec-cache-bucket-name` | False | | `SPEC_CACHE_BUCKET_NAME` | The name of the GCS bucket where specs will be cached. | -| `--metadata-service-gcs-credentials` | False | | `METADATA_SERVICE_GCS_CREDENTIALS` | The service account key to upload files to the GCS bucket hosting the metadata files. | -| `--metadata-service-bucket-name` | False | | `METADATA_SERVICE_BUCKET_NAME` | The name of the GCS bucket where metadata files will be uploaded. | -| `--slack-webhook` | False | | `SLACK_WEBHOOK` | The Slack webhook URL to send notifications to. | -| `--slack-channel` | False | | `SLACK_CHANNEL` | The Slack channel name to send notifications to. | -| `--ci-requirements` | False | | | Output the CI requirements as a JSON payload. It is used to determine the CI runner to use. | +| Option | Required | Default | Mapped environment variable | Description | +| ------------------------------------ | -------- | ------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--pre-release/--main-release` | False | `--pre-release` | | Whether to publish the pre-release or the main release version of a connector. Defaults to pre-release. For main release you have to set the credentials to interact with the GCS bucket. | +| `--spec-cache-gcs-credentials` | False | | `SPEC_CACHE_GCS_CREDENTIALS` | The service account key to upload files to the GCS bucket hosting spec cache. | +| `--spec-cache-bucket-name` | False | | `SPEC_CACHE_BUCKET_NAME` | The name of the GCS bucket where specs will be cached. | +| `--metadata-service-gcs-credentials` | False | | `METADATA_SERVICE_GCS_CREDENTIALS` | The service account key to upload files to the GCS bucket hosting the metadata files. | +| `--metadata-service-bucket-name` | False | | `METADATA_SERVICE_BUCKET_NAME` | The name of the GCS bucket where metadata files will be uploaded. | +| `--slack-webhook` | False | | `SLACK_WEBHOOK` | The Slack webhook URL to send notifications to. | +| `--slack-channel` | False | | `SLACK_CHANNEL` | The Slack channel name to send notifications to. | +| `--ci-requirements` | False | | | Output the CI requirements as a JSON payload. It is used to determine the CI runner to use. | +| `--python-registry-token` | False | | `PYTHON_REGISTRY_TOKEN` | The API token to authenticate with the registry. For pypi, the `pypi-` prefix needs to be specified | +| `--python-registry-url` | False | https://upload.pypi.org/legacy/ | `PYTHON_REGISTRY_URL` | The python registry to publish to. Defaults to main pypi | I've added an empty "Default" column, and you can fill in the default values as needed. @@ -406,14 +408,24 @@ flowchart TD validate[Validate the metadata file] check[Check if the connector image already exists] build[Build the connector image for all platform variants] + publish_to_python_registry[Push the connector image to the python registry if enabled] upload_spec[Upload connector spec to the spec cache bucket] push[Push the connector image from DockerHub, with platform variants] pull[Pull the connector image from DockerHub to check SPEC can be run and the image layers are healthy] upload_metadata[Upload its metadata file to the metadata service bucket] - validate-->check-->build-->upload_spec-->push-->pull-->upload_metadata + validate-->check-->build-->upload_spec-->publish_to_python_registry-->push-->pull-->upload_metadata ``` +#### Python registry publishing + +If `remoteRegistries.pypi.enabled` in the connector metadata is set to `true`, the connector will be published to the python registry. +To do so, the `--python-registry-token` and `--python-registry-url` options are used to authenticate with the registry and publish the connector. +If the current version of the connector is already published to the registry, the publish will be skipped. + +On a pre-release, the connector will be published as a `.dev` version. + + ### `connectors bump_version` command Bump the version of the selected connectors. @@ -534,12 +546,12 @@ For poetry packages, the package name and version can be taken from the `pyproje #### Options -| Option | Required | Default | Mapped environment variable | Description | -| ------------------------- | -------- | ----------------------- | --------------------------- | -------------------------------------------------------------------------------------------------------- | -| `--publish-name` | False | | | The name of the package. Not required for poetry packages that define it in the `pyproject.toml` file | -| `--publish-version` | False | | | The version of the package. Not required for poetry packages that define it in the `pyproject.toml` file | -| `--python-registry-token` | True | | PYTHON_REGISTRY_TOKEN | The API token to authenticate with the registry. For pypi, the `pypi-` prefix needs to be specified | -| `--registry-url` | False | https://pypi.org/simple | | The python registry to publish to. Defaults to main pypi | +| Option | Required | Default | Mapped environment variable | Description | +| ------------------------- | -------- | ------------------------------- | --------------------------- | -------------------------------------------------------------------------------------------------------- | +| `--publish-name` | False | | | The name of the package. Not required for poetry packages that define it in the `pyproject.toml` file | +| `--publish-version` | False | | | The version of the package. Not required for poetry packages that define it in the `pyproject.toml` file | +| `--python-registry-token` | True | | PYTHON_REGISTRY_TOKEN | The API token to authenticate with the registry. For pypi, the `pypi-` prefix needs to be specified | +| `--python-registry-url` | False | https://upload.pypi.org/legacy/ | PYTHON_REGISTRY_URL | The python registry to publish to. Defaults to main pypi | ### `metadata` command subgroup @@ -597,6 +609,7 @@ E.G.: running `pytest` on a specific test folder: | Version | PR | Description | | ------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| 3.9.0 | [#34606](https://github.com/airbytehq/airbyte/pull/34606) | Allow configuration of python registry URL via environment variable. | | 3.8.1 | [#34607](https://github.com/airbytehq/airbyte/pull/34607) | Improve gradle dependency cache volume protection. | | 3.8.0 | [#34316](https://github.com/airbytehq/airbyte/pull/34316) | Expose Dagger engine image name in `--ci-requirements` and add `--ci-requirements` to the `airbyte-ci` root command group. | | 3.7.3 | [#34560](https://github.com/airbytehq/airbyte/pull/34560) | Simplify Gradle task execution framework by removing local maven repo support. | diff --git a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/commands.py b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/commands.py index 0de1d7a2032f..c5fbfc414486 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/commands.py +++ b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/commands.py @@ -11,7 +11,7 @@ from pipelines.cli.click_decorators import click_ci_requirements_option from pipelines.cli.confirm_prompt import confirm from pipelines.cli.dagger_pipeline_command import DaggerPipelineCommand -from pipelines.consts import ContextState +from pipelines.consts import DEFAULT_PYTHON_PACKAGE_REGISTRY_URL, ContextState from pipelines.helpers.utils import fail_if_missing_docker_hub_creds @@ -59,6 +59,19 @@ envvar="SLACK_CHANNEL", default="#connector-publish-updates", ) +@click.option( + "--python-registry-token", + help="Access token for python registry", + type=click.STRING, + envvar="PYTHON_REGISTRY_TOKEN", +) +@click.option( + "--python-registry-url", + help="Which python registry registry to publish to. If not set, the default pypi is used. For test pypi, use https://test.pypi.org/legacy/", + type=click.STRING, + default=DEFAULT_PYTHON_PACKAGE_REGISTRY_URL, + envvar="PYTHON_REGISTRY_URL", +) @click.pass_context async def publish( ctx: click.Context, @@ -69,6 +82,8 @@ async def publish( metadata_service_gcs_credentials: str, slack_webhook: str, slack_channel: str, + python_registry_token: str, + python_registry_url: str, ) -> bool: ctx.obj["spec_cache_gcs_credentials"] = spec_cache_gcs_credentials ctx.obj["spec_cache_bucket_name"] = spec_cache_bucket_name @@ -109,6 +124,8 @@ async def publish( s3_build_cache_access_key_id=ctx.obj.get("s3_build_cache_access_key_id"), s3_build_cache_secret_key=ctx.obj.get("s3_build_cache_secret_key"), use_local_cdk=ctx.obj.get("use_local_cdk"), + python_registry_token=python_registry_token, + python_registry_url=python_registry_url, ) for connector in ctx.obj["selected_connectors_with_modified_files"] ] diff --git a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/context.py b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/context.py index 829ab07b4e0a..55136809d8ce 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/context.py +++ b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/context.py @@ -46,12 +46,16 @@ def __init__( s3_build_cache_access_key_id: Optional[str] = None, s3_build_cache_secret_key: Optional[str] = None, use_local_cdk: bool = False, + python_registry_token: Optional[str] = None, + python_registry_url: Optional[str] = None, ) -> None: self.pre_release = pre_release self.spec_cache_bucket_name = spec_cache_bucket_name self.metadata_bucket_name = metadata_bucket_name self.spec_cache_gcs_credentials = sanitize_gcs_credentials(spec_cache_gcs_credentials) self.metadata_service_gcs_credentials = sanitize_gcs_credentials(metadata_service_gcs_credentials) + self.python_registry_token = python_registry_token + self.python_registry_url = python_registry_url pipeline_name = f"Publish {connector.technical_name}" pipeline_name = pipeline_name + " (pre-release)" if pre_release else pipeline_name diff --git a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/pipeline.py b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/pipeline.py index c6e4002829c3..ac7514439cb0 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/pipeline.py +++ b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/pipeline.py @@ -352,6 +352,16 @@ async def _run_python_registry_publish_pipeline(context: PublishConnectorContext if not python_registry_context: return results, False + if not context.python_registry_token or not context.python_registry_url: + # If the python registry token or url are not set, we can't publish to the python registry - stop the pipeline. + return [ + StepResult( + PublishToPythonRegistry(python_registry_context), + status=StepStatus.FAILURE, + stderr="Pypi publishing is enabled, but python registry token or url are not set.", + ) + ], True + check_python_registry_package_exists_results = await CheckPythonRegistryPackageDoesNotExist(python_registry_context).run() results.append(check_python_registry_package_exists_results) if check_python_registry_package_exists_results.status is StepStatus.SKIPPED: diff --git a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/poetry/publish/commands.py b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/poetry/publish/commands.py index 29785f831266..16bded0b0c34 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/poetry/publish/commands.py +++ b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/poetry/publish/commands.py @@ -47,10 +47,11 @@ def _validate_python_version(_ctx: dict, _param: dict, value: Optional[str]) -> envvar="PYTHON_REGISTRY_TOKEN", ) @click.option( - "--registry-url", + "--python-registry-url", help="Which registry to publish to. If not set, the default pypi is used. For test pypi, use https://test.pypi.org/legacy/", type=click.STRING, default=DEFAULT_PYTHON_PACKAGE_REGISTRY_URL, + envvar="PYTHON_REGISTRY_URL", ) @click.option( "--publish-name", @@ -69,7 +70,7 @@ async def publish( ctx: click.Context, click_pipeline_context: ClickPipelineContext, python_registry_token: str, - registry_url: str, + python_registry_url: str, publish_name: Optional[str], publish_version: Optional[str], ) -> bool: @@ -85,7 +86,7 @@ async def publish( ci_context=ctx.obj.get("ci_context"), ci_gcs_credentials=ctx.obj["ci_gcs_credentials"], python_registry_token=python_registry_token, - registry=registry_url, + registry=python_registry_url, package_path=ctx.obj["package_path"], package_name=publish_name, version=publish_version, diff --git a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/steps/python_registry.py b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/steps/python_registry.py index aec2e30bb3da..2bfebec127b5 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/steps/python_registry.py +++ b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/steps/python_registry.py @@ -116,9 +116,11 @@ async def _poetry_publish(self, package_dir_to_publish: Directory) -> StepResult .with_directory("package", package_dir_to_publish) .with_workdir("package") .with_new_file(PYPROJECT_TOML_FILE_PATH, contents=tomli_w.dumps(contents)) + # Make sure these steps are always executed and not cached as they are triggering a side-effect (calling the registry) + # Env var setting needs to be in this block as well to make sure a change of the env var will be propagated correctly + .with_env_variable("CACHEBUSTER", str(uuid.uuid4())) .with_exec(["poetry", "config", "repositories.mypypi", self.context.registry]) .with_exec(sh_dash_c(["poetry config pypi-token.mypypi $PYTHON_REGISTRY_TOKEN"])) - .with_env_variable("CACHEBUSTER", str(uuid.uuid4())) .with_exec(sh_dash_c(["poetry publish --build --repository mypypi -vvv --no-interaction"])) ) @@ -156,9 +158,11 @@ async def _pip_publish(self, package_dir_to_publish: Directory) -> StepResult: .with_new_file("setup.cfg", contents=setup_cfg) .with_exec(["pip", "install", "--upgrade", "setuptools", "wheel"]) .with_exec(["python", SETUP_PY_FILE_PATH, "sdist", "bdist_wheel"]) + # Make sure these steps are always executed and not cached as they are triggering a side-effect (calling the registry) + # Env var setting needs to be in this block as well to make sure a change of the env var will be propagated correctly + .with_env_variable("CACHEBUSTER", str(uuid.uuid4())) .with_secret_variable("TWINE_USERNAME", pypi_username) .with_secret_variable("TWINE_PASSWORD", pypi_password) - .with_env_variable("CACHEBUSTER", str(uuid.uuid4())) .with_exec(["twine", "upload", "--verbose", "--repository-url", self.context.registry, "dist/*"]) ) diff --git a/airbyte-ci/connectors/pipelines/pipelines/consts.py b/airbyte-ci/connectors/pipelines/pipelines/consts.py index 203b320bb6fc..966c484b15f1 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/consts.py +++ b/airbyte-ci/connectors/pipelines/pipelines/consts.py @@ -60,7 +60,7 @@ POETRY_CACHE_PATH = "/root/.cache/pypoetry" STORAGE_DRIVER = "fuse-overlayfs" SETUP_PY_FILE_PATH = "setup.py" -DEFAULT_PYTHON_PACKAGE_REGISTRY_URL = "https://pypi.org/simple" +DEFAULT_PYTHON_PACKAGE_REGISTRY_URL = "https://upload.pypi.org/legacy/" class CIContext(str, Enum): diff --git a/airbyte-ci/connectors/pipelines/pipelines/models/contexts/python_registry_publish.py b/airbyte-ci/connectors/pipelines/pipelines/models/contexts/python_registry_publish.py index ee45760d2f9d..a189b476b892 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/models/contexts/python_registry_publish.py +++ b/airbyte-ci/connectors/pipelines/pipelines/models/contexts/python_registry_publish.py @@ -2,7 +2,6 @@ # Copyright (c) 2023 Airbyte, Inc., all rights reserved. # -import os from dataclasses import dataclass from datetime import datetime from typing import Optional, Type @@ -86,8 +85,8 @@ async def from_publish_connector_context( version = f"{version}.dev{release_candidate_tag}" pypi_context = cls( - python_registry_token=os.environ["PYTHON_REGISTRY_TOKEN"], - registry="https://test.pypi.org/legacy/", # TODO: go live + python_registry_token=str(connector_context.python_registry_token), + registry=str(connector_context.python_registry_url), package_path=str(connector_context.connector.code_directory), package_name=current_metadata["remoteRegistries"]["pypi"]["packageName"], version=version, diff --git a/airbyte-ci/connectors/pipelines/pyproject.toml b/airbyte-ci/connectors/pipelines/pyproject.toml index d3dca0a54f60..8828208d99dd 100644 --- a/airbyte-ci/connectors/pipelines/pyproject.toml +++ b/airbyte-ci/connectors/pipelines/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "pipelines" -version = "3.8.1" +version = "3.9.0" description = "Packaged maintained by the connector operations team to perform CI for connectors' pipelines" authors = ["Airbyte "] diff --git a/airbyte-ci/connectors/pipelines/tests/test_publish.py b/airbyte-ci/connectors/pipelines/tests/test_publish.py index ce8913e648ab..471c89ae6ece 100644 --- a/airbyte-ci/connectors/pipelines/tests/test_publish.py +++ b/airbyte-ci/connectors/pipelines/tests/test_publish.py @@ -5,7 +5,6 @@ import os import random from typing import List -from unittest.mock import patch import anyio import pytest @@ -339,13 +338,14 @@ async def test_run_connector_publish_pipeline_when_image_does_not_exist( @pytest.mark.parametrize( - "pypi_enabled, pypi_package_does_not_exist_status, publish_step_status, expect_publish_to_pypi_called, expect_build_connector_called", + "pypi_enabled, pypi_package_does_not_exist_status, publish_step_status, expect_publish_to_pypi_called, expect_build_connector_called,api_token", [ - pytest.param(True, StepStatus.SUCCESS, StepStatus.SUCCESS, True, True, id="happy_path"), - pytest.param(False, StepStatus.SUCCESS, StepStatus.SUCCESS, False, True, id="pypi_disabled, skip all pypi steps"), - pytest.param(True, StepStatus.SKIPPED, StepStatus.SUCCESS, False, True, id="pypi_package_exists, skip publish_to_pypi"), - pytest.param(True, StepStatus.SUCCESS, StepStatus.FAILURE, True, False, id="publish_step_fails, abort"), - pytest.param(True, StepStatus.FAILURE, StepStatus.FAILURE, False, False, id="pypi_package_does_not_exist_fails, abort"), + pytest.param(True, StepStatus.SUCCESS, StepStatus.SUCCESS, True, True, "test", id="happy_path"), + pytest.param(False, StepStatus.SUCCESS, StepStatus.SUCCESS, False, True, "test", id="pypi_disabled, skip all pypi steps"), + pytest.param(True, StepStatus.SKIPPED, StepStatus.SUCCESS, False, True, "test", id="pypi_package_exists, skip publish_to_pypi"), + pytest.param(True, StepStatus.SUCCESS, StepStatus.FAILURE, True, False, "test", id="publish_step_fails, abort"), + pytest.param(True, StepStatus.FAILURE, StepStatus.FAILURE, False, False, "test", id="pypi_package_does_not_exist_fails, abort"), + pytest.param(True, StepStatus.SUCCESS, StepStatus.SUCCESS, False, False, None, id="no_api_token, abort"), ], ) async def test_run_connector_python_registry_publish_pipeline( @@ -355,6 +355,7 @@ async def test_run_connector_python_registry_publish_pipeline( publish_step_status, expect_publish_to_pypi_called, expect_build_connector_called, + api_token, ): for module, to_mock in STEPS_TO_PATCH: @@ -389,14 +390,15 @@ async def test_run_connector_python_registry_publish_pipeline( code_directory="path/to/connector", metadata={"dockerImageTag": "1.2.3", "remoteRegistries": {"pypi": {"enabled": pypi_enabled, "packageName": "test"}}}, ), + python_registry_token=api_token, + python_registry_url="https://test.pypi.org/legacy/", ) semaphore = anyio.Semaphore(1) - with patch.dict(os.environ, {"PYTHON_REGISTRY_TOKEN": "test"}): - await publish_pipeline.run_connector_publish_pipeline(context, semaphore) + await publish_pipeline.run_connector_publish_pipeline(context, semaphore) if expect_publish_to_pypi_called: mocked_publish_to_python_registry.return_value.run.assert_called_once() # assert that the first argument passed to mocked_publish_to_pypi contains the things from the context - assert mocked_publish_to_python_registry.call_args.args[0].python_registry_token == "test" + assert mocked_publish_to_python_registry.call_args.args[0].python_registry_token == api_token assert mocked_publish_to_python_registry.call_args.args[0].package_metadata.name == "test" assert mocked_publish_to_python_registry.call_args.args[0].package_metadata.version == "1.2.3" assert mocked_publish_to_python_registry.call_args.args[0].registry == "https://test.pypi.org/legacy/"