Skip to content

[breaking change detector] APIStub produces empty changelog when local and PyPI versions match #48565

Description

@msyyc

Description

azpysdk breaking . --changelog --use-apistub --latest-pypi-version can produce an empty changelog in SDK generation when the newly generated local package has the same distribution version as the latest package on PyPI. Running the same command after automation bumps the local version produces the expected changelog.

Observed while generating azure-mgmt-relationships in pipeline build 6696107:

Reproduction

  1. Start with a published package such as azure-mgmt-relationships==1.0.0b1.
  2. Generate a changed local package that still declares version 1.0.0b1.
  3. Run:
azpysdk breaking . --changelog --use-apistub --latest-pypi-version

The pipeline output includes:

Downloading azure-mgmt-relationships==1.0.0b1 from PyPI.
azure-mgmt-relationships is already installed with the same version as the provided wheel. Use --force-reinstall to force an installation of the wheel.
===== changelog start =====
===== changelog end =====

After the package version is updated locally to 1.0.0b2, the same command correctly reports the added APIs and breaking changes relative to PyPI 1.0.0b1.

Root cause

The APIStub changelog path generates the current report first and the stable PyPI report second. Both APIStub invocations use the same Python environment. The current invocation installs the local package. When the PyPI baseline has the same distribution name and version, pip skips installing the downloaded wheel, so the stable report is also generated from the local package. Comparing the two reports therefore yields an empty changelog.

The SDK generation workflow cannot simply bump the version first because the next version is calculated from the changelog result.

Suggested fix

Before APIStub processes a --generate-from-pypi wheel, uninstall the currently installed distribution using the same Python executable:

if generate_from_pypi:
    pkg_path = self.download_pypi_wheel(
        executable, package_name, generate_from_pypi, staging_directory
    )
    self.run_venv_command(
        executable,
        ["-m", "pip", "uninstall", "-y", package_name],
        cwd=staging_directory,
        check=False,
        immediately_dump=True,
    )

This keeps the existing generation/version workflow, avoids the overhead of separate virtual environments, and ensures the downloaded baseline wheel is installed even when its version matches the local package. Alternatively, the APIStub installer could use pip install --force-reinstall.

Expected behavior

The current API report must always come from local source and the stable API report must always come from the requested PyPI wheel, regardless of whether their declared versions are equal.

Test coverage

Add a regression test where local source and the baseline wheel use the same package name and version but expose different APIs. Verify that the generated changelog is non-empty and that uninstall/reinstallation occurs only for the PyPI path.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions