Python POC for GitHub-based API Reviews#47203
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new repo script (scripts/generate_api_text.py) to generate a package-level API.md by building a wheel, running apiview-stub-generator (apistub) to produce the token JSON, and converting that JSON to markdown via Export-APIViewMarkdown.ps1. This is repo tooling intended to streamline API review artifact generation.
Changes:
- Introduces
scripts/generate_api_text.pyto locate a package undersdk/*/, build a wheel, runapistub, and emitAPI.mdinto the package directory. - Adds logic to install
eng/apiview_reqs.txtand (optionally) upgradeapiview-stub-generatorfrom the Azure SDK package index. - Uses
eng/common/scripts/Export-APIViewMarkdown.ps1to convert the generated*_python.jsontoken file into markdown.
7c45b15 to
b9dc383
Compare
b9dc383 to
ebb3870
Compare
f320bdb to
e4b2876
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 26 out of 26 changed files in this pull request and generated 9 comments.
Comments suppressed due to low confidence (1)
eng/tools/azure-sdk-tools/azpysdk/apistub.py:158
--dest-dirnow writes outputs directly into the destination directory for every targeted package. When multiple packages are targeted in a singleazpysdk apistubinvocation, later packages can overwrite earlier ones (e.g., genericapi.md/API.metadata.yml), causing incorrect/stale results.
dest_dir = getattr(args, "dest_dir", None)
if dest_dir:
out_token_path = os.path.abspath(dest_dir)
os.makedirs(out_token_path, exist_ok=True)
else:
out_token_path = os.path.abspath(staging_directory)
580208a to
4b6f18e
Compare
4b6f18e to
9d8137c
Compare
6d81d65 to
818a5ee
Compare
818a5ee to
778edda
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 30 changed files in this pull request and generated 6 comments.
Comments suppressed due to low confidence (1)
scripts/api_md_workflow/README.md:112
- Same issue later in the README: the printed regeneration command uses
--dest-dir .and omits--install-deps, which won’t reproduce the CI behavior and will write files to the wrong directory when run from the repo root. This should point--dest-dirat the package directory and include--install-deps.
4. `regenerate.js` rebuilds `api.md` for those packages.
5. `find_mismatches.js` records any `api.md` drift, including missing or untracked `api.md` files.
6. If drift is found, the workflow fails and prints the affected packages plus the `azpysdk apistub --md --extract-metadata <package-name> --dest-dir .` command to regenerate each `api.md` file locally from the repository root.
778edda to
a82a7ee
Compare
804d5e8 to
8d07492
Compare
| const packageDir = apiFile.replace(/\/(api\.md|api\.metadata\.yml)$/, ""); | ||
| const packageName = path.basename(packageDir); | ||
| lines.push(`- ${packageDir}`); | ||
| lines.push(` API file: ${apiFile}`); | ||
| lines.push(` Regenerate: azpysdk apistub --md --extract-metadata ${packageName} --dest-dir .`); | ||
| } |
| - Detects affected package directories from the PR diff. | ||
| - Regenerates `api.md` for those packages. | ||
| - Fails if the generated files differ from the committed files. | ||
| - Fails if an affected package does not have a committed `api.md`. | ||
| - Prints the mismatched or missing packages and the `azpysdk apistub --md --extract-metadata <package-name> --dest-dir .` command needed to regenerate each `api.md` file from the repository root. | ||
|
|
| 1. A PR changes files under `sdk/**`. | ||
| 2. `consistency.yml` runs. | ||
| 3. `find_affected.js` determines which packages were touched. | ||
| 4. `regenerate.js` rebuilds `api.md` for those packages. | ||
| 5. `find_mismatches.js` records any `api.md` drift, including missing or untracked `api.md` files. | ||
| 6. If drift is found, the workflow fails and prints the affected packages plus the `azpysdk apistub --md --extract-metadata <package-name> --dest-dir .` command to regenerate each `api.md` file locally from the repository root. |
| function isPackageDir(repoRoot, packageDirRelative) { | ||
| const candidate = path.join(repoRoot, packageDirRelative); | ||
| if (!fs.existsSync(candidate) || !fs.statSync(candidate).isDirectory()) { | ||
| return false; | ||
| } | ||
|
|
||
| return fs.existsSync(path.join(candidate, "pyproject.toml")) || fs.existsSync(path.join(candidate, "setup.py")); | ||
| } |
There was a problem hiding this comment.
we will need to either add a package-lock.json file, or add the necessary deps to another package.json already in the repo
| const path = require("path"); | ||
| const { spawnSync } = require("child_process"); | ||
|
|
||
| function runNode(scriptRelativePath, workspace, core) { |
There was a problem hiding this comment.
use a helper from exec.js, or we can add another helper if needed. we have a helper to run an arbitary file, or a helper to run "npm", but not a helper to run "node" itself (though we could add one).
Summary
Adds tooling for GitHub-native API reviews for the Python SDK, enabling API surface tracking and review via GitHub PRs and CI. Based on this proposal: Proposal: API Reviews via GitHub (azure-sdk-tools#15789).
What's Included
1. CI Consistency Check (
.github/workflows/api-consistency.yml)A GitHub Actions workflow that enforces
API.mdconsistency on every PR that touchessdk/**:find_affected.js— diffs the PR against the base branch to find changed packagesregenerate.js— runsazpysdk apistub --md --extract-metadatafor each affected packagefind_mismatches.js— compares the regeneratedAPI.mdto the committed version and validates select metadata fields2. API Review PR Creator (
create_api_review_pr.js)A CLI tool to create dedicated API review PRs:
API.mdfor both the base tag and target branch3. Language Adapter Pattern (
scripts/api_md_workflow/)Core orchestration is language-agnostic. A per-repo adapter (
adapters/python.js) implements the language-specific logic (isPackageDir,findPackageDir,readVersion,generateApiForPackage). This allows the same framework to be ported to other Azure SDK language repos.4. Shared Utility Layer (
.github/shared/)Common ESM modules for subprocess execution, logging, path manipulation, and GitHub API interactions — shared across workflow scripts.
Examples
Auto Reviews
PR Review