Repository navigation
API Review Hub Onboarding
Use this guide to connect an SDK language repository to API Review Hub (ARH), implement its artifact-generation templates, and test the integration.
You need:
- A fork or branch of the language repository.
- A branch of
Azure/azure-sdk-toolswhen the shared dispatcher or base templates must change. - Access to the
azure-sdk-engineering-systemGitHub organization.
You only need to do this if working on a fork of a repo. If working on the Azure-owned repo, this should already be done for you.
Open the Azure SDK Engineering System GitHub App settings and install both apps in the repository:
- API Review Hub coordinates API reviews and approval labels.
- Azure SDK Automation performs repository actions for the review process.
For a Microsoft-owned repository, follow the GitHub App approval process. A fork owner can normally approve installation under Settings > GitHub Apps.
Contact trprescott@microsoft.com if approval or installation is blocked.
Ask the ARH maintainers to register the repository. Provide:
-
Repository full name, such as
Azure/azure-sdk-for-python. -
GitHub repository ID:
gh api repos/{OWNER}/{REPO} --jq .id -
Approval inheritance policy:
- Pre-release to pre-release (default: yes).
- Patch update (default: yes).
- Pre-release to stable (default: no).
- Minor update (default: no).
- Major update (default: no).
-
Review policy:
- Data-plane first beta release (default: no).
- Data-plane subsequent beta release (default: no).
- Data-plane stable release (default: yes).
- Management-plane first beta release (default: no).
- Management-plane subsequent beta release (default: no).
- Management-plane stable release (default: no).
As part of registration, the ARH maintainers update eng/pipelines/handle-apireview-hub-request.yml in Azure/azure-sdk-tools to:
- Add the language to the
languageparameter values, if needed. - Add the language repository resource.
As a maintainer webhook check:
- Create or open an issue in the repository.
- Add
sdk-api-review-approved. - Confirm Azure SDK Automation removes the label and explains that ARH controls it.
If the check fails, the maintainers should verify both GitHub App installations, repository registration, and webhook delivery.
ARH uses .github/ARCHITECTS to determine who may approve an API review. The file follows CODEOWNERS pattern syntax.
# Catch all SDK packages
/sdk/ @your-github-team-or-user
Commit the file to the repository's default branch. See the Python ARCHITECTS file for a larger example.
ARH queues eng/pipelines/handle-apireview-hub-request.yml from Azure/azure-sdk-tools. The dispatcher builds a self-contained tooling artifact once, then runs independent base and target artifact-generation jobs. Each generation job clones only the requested package source ref and downloads the same bin artifact.
The language repository owns:
- One required build-tools wrapper that packages all required tooling and scripts into
$(BinOutputDirectory). - One required artifact-generation wrapper which will be used on the base and target refs.
The shared base templates own checkouts, artifact transfer, publishing, and ARH callbacks. Language templates must not duplicate that orchestration.
%%{init: {"flowchart": {"defaultRenderer": "elk"}}}%%
flowchart LR
subgraph Build["Build Tools Job"]
direction TB
BT["apireview-hub-build-tools-{language}.yml"]
BTB["apireview-hub-build-tools-base.yml"]
BIN[("bin artifacts")]
BT -->|"wraps and supplies<br/>build steps"| BTB
BTB -->|"publishes"| BIN
end
subgraph Generate["Generate Artifacts Job"]
direction TB
AG["apireview-hub-generate-artifact-{language}.yml"]
AGB["apireview-hub-generate-artifact-base.yml"]
AG -->|"wraps and supplies<br/>generation steps"| AGB
end
BT --> AG
BIN -->|"used by"| AGB
classDef language fill:#0ea5e9,stroke:#075985,color:#ffffff
classDef shared fill:#ea6a2a,stroke:#9a3412,color:#ffffff
classDef artifact fill:#0e7490,stroke:#164e63,color:#ffffff
class BT,AG language
class BTB,AGB shared
class BIN artifact
style Build fill:transparent,stroke:#0070c0,stroke-width:3px
style Generate fill:transparent,stroke:#3f7f35,stroke-width:3px
Create:
eng/pipelines/templates/jobs/apireview-hub-build-tools-{language}.yml
Declare and explicitly forward the shared parameters:
parameters:
- name: languageRepoResource
type: string
- name: toolsRef
type: string
- name: languageToolsRef
type: string
jobs:
- template: /eng/common/pipelines/templates/jobs/apireview-hub-build-tools-base.yml
parameters:
languageRepoResource: ${{ parameters.languageRepoResource }}
toolsRef: ${{ parameters.toolsRef }}
languageToolsRef: ${{ parameters.languageToolsRef }}
stepList:
# Language-owned build steps.Declare and forward any supported pool or image override in the same way.
The language-specific build steps have these directories available:
-
$(ToolsSourceDirectory): sharedazure-sdk-tools/engsources attoolsRef. -
$(LanguageToolsSourceDirectory): language repository sources atlanguageToolsRef; also, an alias of$(Build.SourcesDirectory)and$(Pipeline.Workspace)/s. -
$(BinOutputDirectory): destination for every script, binary, configuration file, and other tool required by generation jobs.
The custom stepList may install a runtime, restore dependencies, compile tools, or package tools. Copy all required tooling and script files into $(BinOutputDirectory); generation jobs cannot rely on either source checkout. Do not publish artifacts or write generated output outside $(BinOutputDirectory).
Create:
eng/pipelines/templates/jobs/apireview-hub-generate-artifact-{language}.yml
For example, the Python wrapper declares and forwards:
parameters:
- name: kind
type: string
- name: repositoryOwner
type: string
default: Azure
- name: ref
type: string
- name: packageName
type: string
- name: operationId
type: string
jobs:
- template: /eng/common/pipelines/templates/jobs/apireview-hub-generate-artifact-base.yml
parameters:
kind: ${{ parameters.kind }}
language: python
repositoryFullName: ${{ format('{0}/{1}', parameters.repositoryOwner, 'azure-sdk-for-python') }}
ref: ${{ parameters.ref }}
packageName: ${{ parameters.packageName }}
operationId: ${{ parameters.operationId }}
stepList:
# Language-owned generation steps.Use your language's fixed language and repository names. Declare and forward any supported pool or image override in the same way.
The shared base template provides:
-
$(Build.SourcesDirectory): language source repository at the requested base or target ref. -
$(BinDirectory): the self-contained tooling directory downloaded from the build-tools job. -
$(ArtifactOutputDirectory): destination for the generated review bundle.
Generation steps must:
- Install or activate tooling from
$(BinDirectory). - Locate
packageNameunder$(Build.SourcesDirectory). - Build the package when required.
- Generate the API review files.
- Copy
api.md,api.metadata.yml, and any additional supplemental files into$(ArtifactOutputDirectory).
Do not clone repositories, switch refs, check out tooling sources, download or publish pipeline artifacts, call ARH, or fetch a different tooling revision.
Each base or target bundle must contain:
-
api.md: the generated API surface. -
api.metadata.yml: metadata describing the package and API surface.
api.metadata.yml requires these non-empty fields:
apiHash: 607621e4437753200b71dcdcddaddcabeaf41944273a4600713b004471117189
packageVersion: 1.2.0
packageRelativePath: sdk/example/example-package-
apiHashis calculated using the language's configured hash algorithm and input files, typically including at leastapi.mdand optionally other files. ARH treats it as an opaque, non-empty string and persists it unchanged without recalculating or verifying it. -
packageVersionis the version read from the checked-out package source. -
packageRelativePathis the package path relative to$(Build.SourcesDirectory), using/separators.
Expose the same hash calculation for reuse during the release pipeline, using the same algorithm and input-file selection. A reusable script or template is recommended so artifact generation and release checks cannot drift.
Additional language-specific metadata, such as runtime or generator versions, is allowed. Supplemental review files may also be included in the bundle.
Place the complete bundle in $(ArtifactOutputDirectory); the shared template handles validation, publishing, and notifying ARH.
Develop the dispatcher, shared templates, and language templates on branches.
Pass the development refs in the create-review request, most commonly using the AzSDK CLI:
-
pipelineRef:azure-sdk-toolsref containing the dispatcher to queue. Set environment variable:AZSDK_API_REVIEW_PIPELINE_REF -
toolsRef:azure-sdk-toolsref containing shared tools and base templates. Set environment variable:AZSDK_API_REVIEW_TOOLS_REF -
languageToolsRef: language repository ref containing its tools and wrappers. Set environment variable:AZSDK_API_REVIEW_LANGUAGE_TOOLS_REF
Any omitted ref defaults to main.
These refs are independent of the package source refs. baseTag and targetBranch.name select the package revisions; the three tooling refs select the pipeline and tooling used to generate both bundles.
Example request body:
{
"language": "python",
"packageName": "azure-keyvault-keys",
"packageType": "data",
"baseTag": "azure-keyvault-keys_4.10.0",
"targetBranch": {
"owner": "your-fork",
"repo": "azure-sdk-for-python",
"name": "feature/api-change"
},
"pipelineRef": "feature/arh-language-onboarding",
"toolsRef": "feature/arh-language-onboarding",
"languageToolsRef": "feature/arh-language-onboarding"
}Use the equivalent options when invoking azsdk api-review create directly or through the Azure SDK CLI. Confirm that the proposed command includes the three development refs before approving it.
For an existing package, packageType may be omitted. A new package must provide it. If supplied for an existing package, it must match the registered value.
Request a review using the development refs from Step 6 and confirm that ARH successfully creates the review pull request with the expected API changes. If it fails, share the operation ID with the ARH maintainers.
Merge the language-repository templates and any required azure-sdk-tools dispatcher or base-template changes. Then repeat the create-review test without pipelineRef, toolsRef, or languageToolsRef; all three default to main.
No shared configuration change or temporary dispatcher edit needs to be reverted.
Use the following shared step templates from Azure/azure-sdk-tools. They are synced into each language repository, so reference the local /eng/common paths, without an @azure-sdk-tools repository alias.
| Template | Purpose | Placement |
|---|---|---|
| create-apiview-revision.yml | Creates APIView revisions only; does not check release approval. | After generating the package artifacts and package-info files. |
| get-package-approval-status.yml | Calls azsdk package get-approval-status and fails when the overall approval result does not permit release. |
Before publishing packages. |
| mark-package-released.yml | Calls azsdk package mark-released to record successful publishing through ARH and report the CLI's backend results. |
After packages have been successfully published. |
Update existing release pipelines that relied on APIView revision creation to also check approval. Revision creation is not a release gate, and marking a package released is not an approval check.
- Sync the templates and their supporting scripts and CLI installer into the language repository before referencing them.
- Make the package artifacts and package-info JSON files available in the job that uses each template. Download them explicitly when crossing jobs or stages.
- Each package-info file must contain
Name,Version, and, for ARH,ApiHash. PopulateApiHashusing the same calculation and input files used for the review bundle in Step 5. The templates read package-info JSON, notapi.metadata.yml. - Pass explicit file paths in the
PackageInfoFileslist; do not pass a directory or glob. Absolute paths avoid ambiguity because the ARH scripts run from$(Pipeline.Workspace). - Both ARH templates require the Azure SDK Tools CLI installed in the calling job. Use
/eng/common/pipelines/templates/steps/install-azsdk-cli.yml, which sets$(AZSDK), or provide that variable yourself. Use a CLI release supporting both API and package name approval results; the scripts currently enforce a minimum version of0.6.38. - Authorize the ADO to ARH Service Connection service connection for the consuming pipeline. Coordinate its identity and ARH access with the maintainers. APIView revision creation separately uses APIView prod deployment.
- The scripts derive the language from the repository's shared language settings.
RepoOwneris optional; set it when targeting a registered fork rather than the default owner.SourceRootPathdefaults to$(Build.SourcesDirectory)and must point at the language checkout containingeng/common, especially in multi-checkout jobs.
Example package-info content, using the actual package name, release version, and generated hash:
{
"Name": "azure-example",
"Version": "1.2.0",
"ApiHash": "607621e4437753200b71dcdcddaddcabeaf41944273a4600713b004471117189"
}Keep or add this step in the artifact-generation/build job after the package-info file and artifacts exist. The example assumes artifacts are staged under $(Build.ArtifactStagingDirectory); adapt the paths to the language pipeline.
steps:
# Existing steps build and stage the package and its package-info file.
- template: /eng/common/pipelines/templates/steps/create-apiview-revision.yml
parameters:
ArtifactPath: $(Build.ArtifactStagingDirectory)
ConfigFileDir: $(Build.ArtifactStagingDirectory)/PackageInfo
PackageInfoFiles:
- $(Build.ArtifactStagingDirectory)/PackageInfo/azure-example.json
SourceRootPath: $(Build.SourcesDirectory)Preserve existing language-specific Artifacts, ArtifactName, or PackageName parameters when already configured. GenerateApiReviewForManualOnly: true restricts revision creation to manual runs. The template itself limits the APIView task to internal, non-PR runs outside -pr repositories; it does not authorize publishing.
Insert the following steps into the release job before its existing publishing steps, after resolving or downloading the package-info files:
steps:
- template: /eng/common/pipelines/templates/steps/install-azsdk-cli.yml
parameters:
SourceRootPath: $(Build.SourcesDirectory)
- template: /eng/common/pipelines/templates/steps/get-package-approval-status.yml
parameters:
PackageInfoFiles:
- $(Build.ArtifactStagingDirectory)/PackageInfo/azure-example.json
SourceRootPath: $(Build.SourcesDirectory)
# RepoOwner: your-fork-ownerGate every package being published, including packages whose API review policy does not require architect review. For ARH-managed packages, package name approval is always required: reviewNotRequired applies only to API review and cannot bypass missing package name approval. Release may proceed only when the overall result is approved.
Keep publishing dependent on successful completion of the check. Do not use continueOnError or publishing conditions such as always() or succeededOrFailed() that let approval failures through. If the check and publishing are in different jobs or stages, add explicit dependencies and require success.
Check the template's run condition against the language's release triggers. The current approval task runs only in the internal project, after preceding steps succeed, for manual runs (or an empty build reason), or for IndividualCI on refs/heads/main. Other triggers can skip the task without failing the job. If the language publishes under another trigger, coordinate a shared-template condition update before enabling that release path. Releases from other refs still require package name approval; a skipped task is not approval.
The approval script ignores approval-check failures for package-info entries with ReleaseStatus: "Unreleased". Do not mark a package Unreleased if the pipeline will publish it; pass the intended release candidates and accurate metadata.
Insert this step after successful publishing, using the same package coordinates and API hash that were checked. Pass only package-info files for packages actually published.
steps:
# Append after the existing successful publishing steps.
- template: /eng/common/pipelines/templates/steps/mark-package-released.yml
parameters:
PackageInfoFiles:
- $(Build.ArtifactStagingDirectory)/PackageInfo/azure-example.json
SourceRootPath: $(Build.SourcesDirectory)
# RepoOwner: your-fork-ownerWhen release recording is in a separate job, install the CLI there too, download the same metadata, and require the publishing job to succeed. Do not include this template in build-only, validation-only, or dry-run paths: it records a real release. For multi-package publishing, record only successful publications; do not submit a batch containing unpublished packages.
The templates recognize separate authorized skip controls: Skip.CreateApiReview, Skip.CheckPackageApproval, and Skip.MarkPackageReleased, each paired with IsRequesterAuthorizedToSkipApiReview: true. Keep the existing authorization mechanism; do not set these variables simply to onboard a language or bypass missing approvals.
Before enabling production publishing, confirm:
- The local synced templates resolve, metadata files are available, and both service connections are authorized.
- An unapproved ARH package blocks publishing, even when API review is optional.
- An approved package passes with the release artifact's exact version and API hash.
- Every supported release trigger actually executes the approval check rather than skipping it.
- Build-only and dry-run paths do not mark packages released.
- A successful controlled publication records the release, and a recording failure remains visible for repair without republishing the package.