Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3b59a3d
Add automated namespace approval workflow for spec PRs
samvaity Jun 18, 2026
4f28a24
Address review feedback: unlabeled guard, remove C++/Rust
samvaity Jun 22, 2026
37aa3d1
Add unit tests and namespace format validation
samvaity Jun 22, 2026
67ed6c8
Address review: split workflow, use repo helpers, add zod schema
samvaity Jun 23, 2026
01ea7c6
Fix CI: prettier formatting and cspell word
samvaity Jun 23, 2026
cf496ef
Fix: use sparse-checkout add instead of git checkout for hydration
samvaity Jun 24, 2026
c11675f
Parse tspconfig.yaml directly, add commit status gate, fix plane dete…
samvaity Jun 24, 2026
1b9a3b6
Split status workflow into separate files following repo convention
samvaity Jun 24, 2026
02ccf7e
Fix: deduplicate job name in code workflow to match repo convention
samvaity Jun 25, 2026
a55968c
Address review: add else fallback in status check, fix check name in …
samvaity Jun 29, 2026
bb3a30c
Add Namespace Approval to summarize-checks for Next Steps to Merge
samvaity Jun 29, 2026
9dc65fd
Add Java Maven artifact dual namespace, selective reset, lint and typ…
samvaity Jul 1, 2026
849da69
Fix namespace approval TS type errors
samvaity Jul 1, 2026
843da16
Address review feedback: error handling, shared helpers, and cleanup
samvaity Jul 2, 2026
9f03703
Fix CodeQL ReDoS alert: replace regex with string methods in tspconfi…
samvaity Jul 2, 2026
759d377
Add coverage test for tspconfig filter in changed-files
samvaity Jul 2, 2026
2a9c182
Fix namespace-approval TypeScript null and env typing errors
samvaity Jul 2, 2026
7cead2e
Address review issues: shared approvers, pagination, async format, ti…
samvaity Jul 6, 2026
93c8ba4
Prevent duplicate 'Namespace Approved' comments on concurrent label e…
samvaity Jul 6, 2026
54ea1e9
Rename labels to namespace-<lang>-*, add @handles, integrate with NSTM
samvaity Jul 6, 2026
05b0587
Extract shared labels helper, remove createLabel, clarify plane detec…
samvaity Jul 6, 2026
b430ea0
Fix NSTM: clarify namespace-approved-all is mgmt-plane only
samvaity Jul 7, 2026
c890e3e
changed-files helper cleanup
mikeharder Jul 8, 2026
3a7483f
Merge branch 'main' into namespace-approval
mikeharder Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/namespace-approvers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# cspell:words jsquire alzimmermsft xirzec kashifkhan maorleger jhendrixMSFT ArthurMa1978
# Namespace Approvers Configuration
# This file defines who can approve namespace changes per language.
# To update, submit a PR to this file. In the future, this may be
# synced automatically from ARCHITECTS files in each language repo.

data-plane:
dotnet:
- jsquire
- m-nash
java:
- JonathanGiles
- alzimmermsft
python:
- xirzec
- kashifkhan
typescript:
- xirzec
- maorleger
go:
- jhendrixMSFT

management-plane:
all:
- ArthurMa1978
- m-nash
31 changes: 31 additions & 0 deletions .github/namespace-format-rules.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Namespace Format Rules
# These regex patterns validate namespace/package naming conventions per language.
# Namespaces that fail validation are flagged in the bot comment before manual review.
#
# To update: submit a PR modifying the patterns below.
# Each language can have one rule or multiple rules (array).
# Each rule has a `pattern` (regex) and optional `description`.
#
# Maintainer: @ArthurMa1978

dotnet:
pattern: '^Azure\.ResourceManager\.(?:[A-Z][a-zA-Z0-9]*)(?:\.[A-Z][a-zA-Z0-9]*)?$'
description: "Azure.ResourceManager.{Name} or Azure.ResourceManager.{SuperService}.{Name} (PascalCase)"

java:
- pattern: "^azure-resourcemanager-[a-z0-9]+(?:-[a-z0-9]+)?$"
description: "Maven artifact: azure-resourcemanager-{name} (lowercase)"
- pattern: '^com\.azure\.resourcemanager\.[a-z0-9]+(?:\.[a-z0-9]+)?$'
description: "Java package: com.azure.resourcemanager.{name} (lowercase)"

go:
pattern: "^sdk/resourcemanager/(?:[a-z0-9]+)/(?:arm[a-z0-9]+)$"
description: "sdk/resourcemanager/{name}/arm{name} (lowercase)"

typescript:
pattern: "^@azure/arm-[a-z0-9]+$"
description: "@azure/arm-{name} (lowercase)"

python:
pattern: "^azure-mgmt-[a-z0-9]+$"
description: "azure-mgmt-{name} (lowercase)"
8 changes: 8 additions & 0 deletions .github/shared/src/changed-files.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import debug from "debug";
import { simpleGit } from "simple-git";
import { KeyedCache } from "./cache.js";
Expand Down Expand Up @@ -281,6 +281,14 @@
);
}

/**
Comment thread
mikeharder marked this conversation as resolved.
Resolved
* @param {string} file
* @returns {boolean}
*/
export function tspconfig(file) {
return typeof file === "string" && /specification\/.*\/tspconfig\.yaml$/.test(file);
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
}

/**
* @param {string} [file]
* @returns {boolean}
Expand Down
41 changes: 41 additions & 0 deletions .github/workflows/namespace-approval-code.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: "Namespace Approval - Analyze Code"

on:
pull_request:
types:
- opened
- synchronize
- reopened
- edited

permissions:
contents: read

jobs:
detect-namespaces:
name: Analyze Code
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 2

- name: Setup Node and install dependencies
uses: ./.github/actions/setup-node-install-deps

- name: Detect namespace changes
id: detect
uses: actions/github-script@v8
with:
script: |
const { default: detectNamespaces } =
await import('${{ github.workspace }}/.github/workflows/src/namespace-approval/detect-namespaces.js');
await detectNamespaces({ github, context, core });

- name: Upload namespace results
if: always() && steps.detect.outputs.results
uses: actions/upload-artifact@v7
with:
name: namespace-results
path: ${{ steps.detect.outputs.results_path }}
if-no-files-found: ignore
41 changes: 41 additions & 0 deletions .github/workflows/namespace-approval-status.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: "Namespace Approval - Set Status"

on:
workflow_run:
workflows: ["Namespace Approval - Analyze Code"]
types: [completed]

permissions:
actions: read
contents: read
pull-requests: write
statuses: write

jobs:
post-results:
name: Post Namespace Results
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with:
sparse-checkout: |
.github/

- name: Install dependencies for github-script actions
uses: ./.github/actions/install-deps-github-script

- name: Post namespace review comment
uses: actions/github-script@v8
with:
script: |
const { default: postResults } =
await import('${{ github.workspace }}/.github/workflows/src/namespace-approval/post-results.js');
await postResults({ github, context, core });

- name: Set namespace approval status
uses: actions/github-script@v8
with:
script: |
const { default: statusCheck } =
await import('${{ github.workspace }}/.github/workflows/src/namespace-approval/status-check.js');
await statusCheck({ github, context, core });
43 changes: 43 additions & 0 deletions .github/workflows/namespace-approval-validation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: "Namespace Approval - Validate Labels"

on:
pull_request_target:
types:
- labeled
- unlabeled

permissions:
contents: read
pull-requests: write
statuses: write

jobs:
validate-approval:
name: Validate Namespace Approval
runs-on: ubuntu-24.04
steps:
# IMPORTANT: This workflow uses pull_request_target, which runs with repo write permissions.
# Only base-branch code is checked out below. Do NOT checkout or run code from the PR head.
- uses: actions/checkout@v6
with:
sparse-checkout: |
.github/
Comment thread
samvaity marked this conversation as resolved.
Resolved

- name: Install dependencies for github-script actions
uses: ./.github/actions/install-deps-github-script

- name: Validate namespace approval label
uses: actions/github-script@v8
with:
script: |
const { default: validateApproval } =
await import('${{ github.workspace }}/.github/workflows/src/namespace-approval/validate-approval.js');
await validateApproval({ github, context, core });

- name: Update namespace approval status
uses: actions/github-script@v8
with:
script: |
const { default: statusCheck } =
await import('${{ github.workspace }}/.github/workflows/src/namespace-approval/status-check.js');
await statusCheck({ github, context, core });
105 changes: 105 additions & 0 deletions .github/workflows/src/namespace-approval/NAMESPACE-REVIEW-PROCESS.md
Comment thread
mikeharder marked this conversation as resolved.
Resolved
Comment thread
samvaity marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Namespace Approval Process

## Overview

When a service team adds or modifies SDK namespace configuration in their `tspconfig.yaml`, the namespace must be approved by authorized architects before the spec PR can merge.
Comment thread
samvaity marked this conversation as resolved.
Resolved

This process is automated via GitHub Actions on this repository.

## How It Works

### Detection

When a PR modifies any `tspconfig.yaml` file, the analyze-code workflow:
Comment thread
samvaity marked this conversation as resolved.
Resolved

1. Identifies which languages have namespace/package-name configuration
2. Extracts namespaces by parsing `tspconfig.yaml` emitter options directly
3. Determines if the service is data-plane or management-plane (via path and linter config)
Comment thread
samvaity marked this conversation as resolved.
Resolved
4. For management-plane PRs, validates namespace format against language-specific naming rules (defined in `.github/namespace-format-rules.yml`)
5. Uploads namespace results for the status workflow

### Status + Approval

The status workflow posts the namespace review comment, applies `<lang>-namespace-pending` labels, and validates architect approval labels.

- **Data plane:** Each language architect approves their language by applying `<lang>-namespace-approved`
- **Management plane:** ArthurMa1978 or m-nash can apply `namespace-approved-all` to approve all languages at once

### Status Check

A required status check (`Namespace Approval`) blocks merge until all pending namespaces are approved. The check:

- ✅ Passes when all `*-namespace-pending` labels have corresponding `*-namespace-approved` labels
Comment thread
samvaity marked this conversation as resolved.
Resolved
- ❌ Fails when any pending namespace lacks approval
- ⏭️ Skipped when the PR doesn't modify tspconfig.yaml (no namespace changes)

### Reset on Change

If a service team pushes a commit that changes namespace configuration, only the **affected languages** are reset:

- Only languages whose namespace actually changed have their `<lang>-namespace-approved` label removed
- Languages with unchanged namespaces keep their approval
- The `<lang>-namespace-pending` label is re-applied for reset languages
- The status check fails again until re-approved
- The bot comment names which specific languages were reset

## Labels

| Label | Applied by | Meaning |
| --------------------------- | ---------------- | ---------------------------------------------- |
| `namespace-review-required` | Bot | PR has namespaces that need architect approval |
| `<lang>-namespace-pending` | Bot | Namespace detected, awaiting approval |
| `<lang>-namespace-approved` | Architect | Namespace approved for this language |
| `namespace-approved-all` | Architect (mgmt) | Shortcut: approves all pending languages |
| `namespace-approved` | Bot | All languages approved |
| `Mgmt` | Bot | PR is management plane |
| `data-plane` | Bot | PR is data plane |

Where `<lang>` is one of: `dotnet`, `java`, `python`, `typescript`, `go`, `rust`

## Authorized Approvers

Defined in [`.github/namespace-approvers.yml`](../../../namespace-approvers.yml):

<!-- cspell:disable -->

| Scope | Approvers |
| -------------------- | ----------------------------- |
| .NET | @jsquire, @m-nash |
| Java | @JonathanGiles, @alzimmermsft |
| Python | @xirzec, @kashifkhan |
| TypeScript | @xirzec, @maorleger |
| Go | @jhendrixMSFT |
| Mgmt (all languages) | @ArthurMa1978, @m-nash |

<!-- cspell:enable -->

## For Service Teams

No action needed beyond your normal workflow:
Comment thread
samvaity marked this conversation as resolved.
Resolved

1. Add or modify namespace in your `tspconfig.yaml`
2. Open a PR as usual
3. The bot posts a status table and applies pending labels
4. Wait for architects to approve
5. Once approved, the status check passes and the PR can merge

Comment thread
samvaity marked this conversation as resolved.
Resolved
## For Architects

1. Watch for PRs with `<lang>-namespace-pending` labels
2. Review the proposed namespace in the PR diff
3. If acceptable, apply `<lang>-namespace-approved` label
4. For management plane PRs, you can use `namespace-approved-all` to approve all at once

## Configuration

To update approvers, submit a PR modifying `.github/namespace-approvers.yml`. Changes take effect immediately on merge.

## Relationship to API Review

Namespace approval is **separate from API review**:

- **Namespace approval** (this repo): gates spec PR merge, ensures library naming is correct
- **API review** (azure-sdk repo): reviews API surface design (methods, models, parameters)

A new service typically needs namespace approval first (on their spec PR), then API review later (when SDK is built).
Loading
Loading