mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Add independent beta release for the Python SDK (#24828)
## Why `openai-codex` needs a beta release lifecycle without requiring beta releases of its pinned runtime package. Previously, SDK staging rewrote its runtime dependency to the SDK version, which made an SDK-only beta impossible. ## What changed - Set the initial SDK beta version to `0.1.0b1` and pin it to published stable `openai-codex-cli-bin==0.132.0`. - Decoupled SDK release staging from runtime versioning so it preserves the reviewed exact runtime pin. - Added a `python-v*` tag workflow that builds and publishes only `openai-codex` through PyPI trusted publishing. - Removed the Beta classifier from runtime package metadata for future runtime publications. - Regenerated protocol-derived SDK models from the selected stable runtime package. `0.132.0` is the newest stable runtime admitted by the checked-in dependency date fence and retains the Linux wheel family currently used by SDK CI. ## Release setup Before pushing `python-v0.1.0b1`, configure PyPI trusted publishing for the `openai-codex` project with workflow `python-sdk-release.yml`, environment `pypi`, and job `publish-python-sdk`. ## Validation - `uv run --frozen --extra dev ruff check src/openai_codex scripts examples tests` - Parsed `.github/workflows/python-sdk-release.yml` with PyYAML. - Built staged release artifacts locally: `openai_codex-0.1.0b1-py3-none-any.whl` and `openai_codex-0.1.0b1.tar.gz`. - Verified wheel metadata pins `openai-codex-cli-bin==0.132.0`. - Tests are deferred to online CI for this PR.
This commit is contained in:
committed by
GitHub
Unverified
parent
304d15cab0
commit
4d0c4cd058
@@ -158,8 +158,8 @@ def test_schema_normalization_only_flattens_string_literal_oneofs(
|
||||
"AuthMode",
|
||||
"InputModality",
|
||||
"ExperimentalFeatureStage",
|
||||
"CommandExecOutputStream",
|
||||
"ProcessOutputStream",
|
||||
"CommandExecOutputStream",
|
||||
]
|
||||
|
||||
|
||||
@@ -249,11 +249,11 @@ def test_source_sdk_package_pins_published_runtime() -> None:
|
||||
"runtime_pin": script.pinned_runtime_version(),
|
||||
"dependencies": pyproject["project"]["dependencies"],
|
||||
} == {
|
||||
"sdk_version": "0.131.0a4",
|
||||
"runtime_pin": "0.131.0a4",
|
||||
"sdk_version": "0.1.0b1",
|
||||
"runtime_pin": "0.132.0",
|
||||
"dependencies": [
|
||||
"pydantic>=2.12",
|
||||
"openai-codex-cli-bin==0.131.0a4",
|
||||
"openai-codex-cli-bin==0.132.0",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -284,19 +284,26 @@ def test_release_metadata_retries_without_invalid_auth(
|
||||
assert authorizations == ["Bearer invalid-token", None]
|
||||
|
||||
|
||||
def test_runtime_setup_uses_pep440_package_version_and_codex_release_tags() -> None:
|
||||
"""The SDK uses PEP 440 package pins and converts only when fetching releases."""
|
||||
def test_runtime_setup_reads_independent_runtime_pin_and_release_tags() -> None:
|
||||
"""Runtime package pins remain independent of the SDK beta version."""
|
||||
runtime_setup = _load_runtime_setup_module()
|
||||
pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text())
|
||||
|
||||
assert runtime_setup.PACKAGE_NAME == "openai-codex-cli-bin"
|
||||
assert runtime_setup.pinned_runtime_version() == pyproject["project"]["version"]
|
||||
assert (
|
||||
f"{runtime_setup.PACKAGE_NAME}=={pyproject['project']['version']}"
|
||||
in pyproject["project"]["dependencies"]
|
||||
)
|
||||
assert runtime_setup._normalized_package_version("rust-v0.116.0-alpha.1") == "0.116.0a1"
|
||||
assert runtime_setup._release_tag("0.116.0a1") == "rust-v0.116.0-alpha.1"
|
||||
assert {
|
||||
"package_name": runtime_setup.PACKAGE_NAME,
|
||||
"sdk_version": pyproject["project"]["version"],
|
||||
"runtime_pin": runtime_setup.pinned_runtime_version(),
|
||||
"normalized_release_version": runtime_setup._normalized_package_version(
|
||||
"rust-v0.116.0-alpha.1"
|
||||
),
|
||||
"release_tag": runtime_setup._release_tag("0.116.0a1"),
|
||||
} == {
|
||||
"package_name": "openai-codex-cli-bin",
|
||||
"sdk_version": "0.1.0b1",
|
||||
"runtime_pin": "0.132.0",
|
||||
"normalized_release_version": "0.116.0a1",
|
||||
"release_tag": "rust-v0.116.0-alpha.1",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -491,23 +498,32 @@ def test_runtime_package_layout_is_included_by_wheel_config(
|
||||
]
|
||||
|
||||
|
||||
def test_stage_sdk_release_injects_exact_runtime_pin(tmp_path: Path) -> None:
|
||||
def test_stage_sdk_release_preserves_reviewed_runtime_pin(tmp_path: Path) -> None:
|
||||
script = _load_update_script_module()
|
||||
staged = script.stage_python_sdk_package(
|
||||
tmp_path / "sdk-stage",
|
||||
"rust-v0.116.0-alpha.1",
|
||||
"0.1.0b1",
|
||||
)
|
||||
|
||||
pyproject = (staged / "pyproject.toml").read_text()
|
||||
assert 'name = "openai-codex"' in pyproject
|
||||
assert 'version = "0.116.0a1"' in pyproject
|
||||
assert '"openai-codex-cli-bin==0.116.0a1"' in pyproject
|
||||
pyproject = tomllib.loads((staged / "pyproject.toml").read_text())
|
||||
assert {
|
||||
"name": pyproject["project"]["name"],
|
||||
"version": pyproject["project"]["version"],
|
||||
"dependencies": pyproject["project"]["dependencies"],
|
||||
} == {
|
||||
"name": "openai-codex",
|
||||
"version": "0.1.0b1",
|
||||
"dependencies": [
|
||||
"pydantic>=2.12",
|
||||
"openai-codex-cli-bin==0.132.0",
|
||||
],
|
||||
}
|
||||
assert (
|
||||
'__version__ = "0.116.0a1"'
|
||||
'__version__ = "0.1.0b1"'
|
||||
not in (staged / "src" / "openai_codex" / "__init__.py").read_text()
|
||||
)
|
||||
assert (
|
||||
'client_version: str = "0.116.0a1"'
|
||||
'client_version: str = "0.1.0b1"'
|
||||
not in (staged / "src" / "openai_codex" / "client.py").read_text()
|
||||
)
|
||||
assert not any((staged / "src" / "openai_codex").glob("bin/**"))
|
||||
@@ -520,34 +536,41 @@ def test_stage_sdk_release_replaces_existing_staging_dir(tmp_path: Path) -> None
|
||||
old_file.parent.mkdir(parents=True)
|
||||
old_file.write_text("stale")
|
||||
|
||||
staged = script.stage_python_sdk_package(staging_dir, "0.116.0a1")
|
||||
staged = script.stage_python_sdk_package(staging_dir, "0.1.0b1")
|
||||
|
||||
assert staged == staging_dir
|
||||
assert not old_file.exists()
|
||||
|
||||
|
||||
def test_staged_sdk_and_runtime_versions_match(tmp_path: Path) -> None:
|
||||
def test_sdk_beta_release_can_pin_stable_runtime(tmp_path: Path) -> None:
|
||||
script = _load_update_script_module()
|
||||
package_archive = _write_fake_codex_package_archive(tmp_path, script)
|
||||
|
||||
sdk_stage = script.stage_python_sdk_package(
|
||||
tmp_path / "sdk-stage",
|
||||
"rust-v0.116.0-alpha.1",
|
||||
"0.1.0b1",
|
||||
)
|
||||
runtime_stage = script.stage_python_runtime_package(
|
||||
tmp_path / "runtime-stage",
|
||||
"rust-v0.116.0-alpha.1",
|
||||
"0.132.0",
|
||||
package_archive,
|
||||
)
|
||||
|
||||
sdk_pyproject = tomllib.loads((sdk_stage / "pyproject.toml").read_text())
|
||||
runtime_pyproject = tomllib.loads((runtime_stage / "pyproject.toml").read_text())
|
||||
|
||||
assert sdk_pyproject["project"]["version"] == runtime_pyproject["project"]["version"]
|
||||
assert sdk_pyproject["project"]["dependencies"] == [
|
||||
"pydantic>=2.12",
|
||||
"openai-codex-cli-bin==0.116.0a1",
|
||||
]
|
||||
assert {
|
||||
"sdk_version": sdk_pyproject["project"]["version"],
|
||||
"runtime_version": runtime_pyproject["project"]["version"],
|
||||
"sdk_dependencies": sdk_pyproject["project"]["dependencies"],
|
||||
} == {
|
||||
"sdk_version": "0.1.0b1",
|
||||
"runtime_version": "0.132.0",
|
||||
"sdk_dependencies": [
|
||||
"pydantic>=2.12",
|
||||
"openai-codex-cli-bin==0.132.0",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def test_stage_sdk_runs_type_generation_before_staging(tmp_path: Path) -> None:
|
||||
@@ -557,16 +580,16 @@ def test_stage_sdk_runs_type_generation_before_staging(tmp_path: Path) -> None:
|
||||
[
|
||||
"stage-sdk",
|
||||
str(tmp_path / "sdk-stage"),
|
||||
"--codex-version",
|
||||
"rust-v0.116.0-alpha.1",
|
||||
"--sdk-version",
|
||||
"0.1.0b1",
|
||||
]
|
||||
)
|
||||
|
||||
def fake_generate_types() -> None:
|
||||
calls.append("generate_types")
|
||||
|
||||
def fake_stage_sdk_package(_staging_dir: Path, codex_version: str) -> Path:
|
||||
calls.append(f"stage_sdk:{codex_version}")
|
||||
def fake_stage_sdk_package(_staging_dir: Path, sdk_version: str) -> Path:
|
||||
calls.append(f"stage_sdk:{sdk_version}")
|
||||
return tmp_path / "sdk-stage"
|
||||
|
||||
def fake_stage_runtime_package(
|
||||
@@ -589,26 +612,7 @@ def test_stage_sdk_runs_type_generation_before_staging(tmp_path: Path) -> None:
|
||||
|
||||
script.run_command(args, ops)
|
||||
|
||||
assert calls == ["generate_types", "stage_sdk:0.116.0a1"]
|
||||
|
||||
|
||||
def test_stage_sdk_rejects_mismatched_legacy_versions(tmp_path: Path) -> None:
|
||||
script = _load_update_script_module()
|
||||
args = script.parse_args(
|
||||
[
|
||||
"stage-sdk",
|
||||
str(tmp_path / "sdk-stage"),
|
||||
"--codex-version",
|
||||
"0.116.0a1",
|
||||
"--runtime-version",
|
||||
"0.116.0a1",
|
||||
"--sdk-version",
|
||||
"0.115.0",
|
||||
]
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError, match="versions must match"):
|
||||
script.run_command(args, script.default_cli_ops())
|
||||
assert calls == ["generate_types", "stage_sdk:0.1.0b1"]
|
||||
|
||||
|
||||
def test_stage_runtime_stages_package_without_type_generation(tmp_path: Path) -> None:
|
||||
|
||||
@@ -40,7 +40,7 @@ def test_generated_files_are_up_to_date():
|
||||
|
||||
# Regenerate contract artifacts via the pinned runtime package, not a local
|
||||
# app-server binary from the checkout or CI environment.
|
||||
assert importlib.metadata.version("openai-codex-cli-bin") == "0.131.0a4"
|
||||
assert importlib.metadata.version("openai-codex-cli-bin") == "0.132.0"
|
||||
env = os.environ.copy()
|
||||
env.pop("CODEX_EXEC_PATH", None)
|
||||
python_bin = str(Path(sys.executable).parent)
|
||||
|
||||
Reference in New Issue
Block a user