Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
189 changes: 189 additions & 0 deletions check_mgmt_sdk_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
#!/usr/bin/env python
"""Check management SDK package and TypeSpec metadata from data.txt.

Quick usage from the azure-sdk-for-python repo root:

python .\\check_mgmt_sdk_data.py <path-to-azure-rest-api-specs>

By default this reads ./data.txt, checks SDK packages under ./sdk, and writes
./result.md. Use --data, --sdk-repo, or --output to override those paths.
"""

from __future__ import annotations

import argparse
import re
import shlex
from dataclasses import dataclass
from pathlib import Path
from typing import Iterable, Sequence


SDK_NAME_PATTERN = re.compile(r"\bazure-mgmt-[A-Za-z0-9][A-Za-z0-9_-]*")


@dataclass(frozen=True)
class DataRow:
service_folder_1: str
service_folder_2: str
sdk_name: str = ""


@dataclass(frozen=True)
class ResultRow:
row_id: int
service_folder_1: str
service_folder_2: str
sdk_name: str
path_exists: bool | None
tsp_file_exists: bool | None


def parse_data_file(data_file: Path) -> list[DataRow]:
rows: list[DataRow] = []
for line in data_file.read_text(encoding="utf-8").splitlines():
stripped = line.strip()
if not stripped:
continue

parts = shlex.split(stripped)
if len(parts) < 2 or "service" in stripped.lower() and "folder" in stripped.lower():
continue

rows.append(DataRow(parts[0], parts[1], parts[2] if len(parts) > 2 else ""))
return rows


def candidate_tsp_roots(rest_repo: Path, service_folder_1: str, service_folder_2: str) -> list[Path]:
service_folder_2_parts = Path(service_folder_2).parts
roots = [
rest_repo / service_folder_1 / service_folder_2,
rest_repo / "specification" / service_folder_1 / service_folder_2,
]

if service_folder_2_parts:
spec_root = rest_repo / "specification" / service_folder_2_parts[0] / "resource-manager"
service_remainder = Path(*service_folder_2_parts[1:]) if len(service_folder_2_parts) > 1 else Path()
if service_remainder.parts and service_remainder.parts[0].lower() == service_folder_1.lower():
roots.append(spec_root / service_remainder)
else:
roots.append(spec_root / service_folder_1 / service_remainder)
roots.append(rest_repo / "specification" / service_folder_2_parts[0])

return roots


def iter_tspconfigs(root: Path) -> Iterable[Path]:
direct_tspconfig = root / "tspconfig.yaml"
if direct_tspconfig.is_file():
yield direct_tspconfig

if root.is_dir():
for tspconfig in sorted(root.rglob("tspconfig.yaml")):
if tspconfig != direct_tspconfig:
yield tspconfig


def find_sdk_name_from_tspconfig(rest_repo: Path, service_folder_1: str, service_folder_2: str) -> str:
seen: set[Path] = set()
for root in candidate_tsp_roots(rest_repo, service_folder_1, service_folder_2):
for tspconfig in iter_tspconfigs(root):
if tspconfig in seen:
continue
seen.add(tspconfig)
match = SDK_NAME_PATTERN.search(tspconfig.read_text(encoding="utf-8"))
if match:
return match.group(0)
return ""


def sdk_package_paths(sdk_repo: Path, sdk_name: str) -> list[Path]:
if not sdk_name:
return []
return sorted(path for path in (sdk_repo / "sdk").glob(f"*/{sdk_name}") if path.is_dir())


def build_results(data_rows: Sequence[DataRow], rest_repo: Path, sdk_repo: Path) -> list[ResultRow]:
results: list[ResultRow] = []
for row_id, row in enumerate(data_rows, start=1):
sdk_name = row.sdk_name or find_sdk_name_from_tspconfig(rest_repo, row.service_folder_1, row.service_folder_2)
if row.sdk_name and not SDK_NAME_PATTERN.fullmatch(row.sdk_name):
results.append(
ResultRow(
row_id=row_id,
service_folder_1=row.service_folder_1,
service_folder_2=row.service_folder_2,
sdk_name=sdk_name,
path_exists=None,
tsp_file_exists=None,
)
)
continue

package_paths = sdk_package_paths(sdk_repo, sdk_name)
results.append(
ResultRow(
row_id=row_id,
service_folder_1=row.service_folder_1,
service_folder_2=row.service_folder_2,
sdk_name=sdk_name,
path_exists=bool(package_paths),
tsp_file_exists=any((package_path / "tsp-location.yaml").is_file() for package_path in package_paths),
)
)
return results


def table_value(value: object) -> str:
return str(value).replace("|", "\\|")


def check_value(value: bool | None) -> str:
if value is None:
return "-"
return "Y" if value else "N"


def write_result_markdown(results: Sequence[ResultRow], output_file: Path) -> None:
lines = [
"| id | service folder 1 | service folder 2 | sdk name (azure-mgmt-*) | path exist (Y/N) | tsp file (Y/N) |",
"| --- | --- | --- | --- | --- | --- |",
]
for result in results:
lines.append(
"| "
+ " | ".join(
[
table_value(result.row_id),
table_value(result.service_folder_1),
table_value(result.service_folder_2),
table_value(result.sdk_name),
check_value(result.path_exists),
check_value(result.tsp_file_exists),
]
)
+ " |"
)

output_file.write_text("\n".join(lines) + "\n", encoding="utf-8")


def parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Check management SDK packages listed in data.txt.")
parser.add_argument("rest_repo", type=Path, help="Path to the azure-rest-api-specs repository.")
parser.add_argument("--data", type=Path, default=Path("data.txt"), help="Input data file. Defaults to data.txt.")
parser.add_argument("--output", type=Path, default=Path("result.md"), help="Output markdown file. Defaults to result.md.")
parser.add_argument("--sdk-repo", type=Path, default=Path(__file__).resolve().parent, help="Path to this SDK repository.")
return parser.parse_args(argv)


def main(argv: Sequence[str] | None = None) -> int:
args = parse_args(argv)
data_rows = parse_data_file(args.data)
results = build_results(data_rows, args.rest_repo, args.sdk_repo)
write_result_markdown(results, args.output)
return 0


if __name__ == "__main__":
raise SystemExit(main())
137 changes: 137 additions & 0 deletions data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
"serivce folder 1" "service folder 2" sdk_name
Microsoft.StorageActions storageactions
Microsoft.Bing bing "no specs"
Microsoft.BillingBenefits billingbenefits
Microsoft.Devices deviceprovisioningservices
Microsoft.Network dns
Microsoft.EdgeOrder edgeorder
Microsoft.ElasticSan elasticsan
Microsoft.GuestConfiguration guestconfiguration
Microsoft.HardwareSecurityModules hardwaresecuritymodules
Microsoft.Help help
Microsoft.Kubernetes hybridkubernetes
Microsoft.Maintenance maintenance
Microsoft.NotificationHubs notificationhubs
Microsoft.Network privatedns
Microsoft.SqlVirtualMachine sqlvirtualmachine
Microsoft.Confluent confluent
Microsoft.BotService botservice
Microsoft.PowerBIdedicated powerbidedicated
Microsoft.Advisor advisor
Microsoft.Cdn cdn
Microsoft.ConfidentialLedger confidentialledger
microsoft.databox databox
microsoft.datadog datadog
Microsoft.DataProtection dataprotection
Microsoft.DevCenter devcenter
Microsoft.Network dnsresolver
Microsoft.Elastic elastic
Microsoft.HealthBot healthbot
Microsoft.KeyVault keyvault
microsoft.managedidentity msi
microsoft.dbformysql mysql azure-mgmt-mysqlflexibleservers
nginx.nginxplus nginx
microsoft.dbforpostgresql postgresqlhsc
Microsoft.Quota quota
microsoft.recoveryservices recoveryservicesbackup
microsoft.cache redis
microsoft.relay relay
microsoft.servicebus servicebus
Microsoft.SignalRService signalr
microsoft.storage storage
Microsoft.StorageMover storagemover
microsoft.storagesync storagesync
microsoft.support support
Microsoft.SignalRService webpubsub
Microsoft.Compute compute/Recommender
dynatrace.observability dynatrace
Microsoft.AppConfiguration appconfiguration
microsoft.consumption consumption
microsoft.costmanagement cost-management azure-mgmt-costmanagement
microsoft.databoxedge databoxedge
Microsoft.EventHub eventhub
Microsoft.NetApp netapp
Microsoft.NetworkCloud networkcloud
NewRelic.Observability newrelic
PaloAltoNetworks.Cloudngfw paloaltonetworks
microsoft.dbforpostgresql postgresql
Microsoft.ResourceConnector resourceconnector
Microsoft.Network trafficmanager
microsoft.apimanagement apimanagement
Microsoft.Attestation attestation
Microsoft.Batch batch
Microsoft.CognitiveServices cognitiveservices
Microsoft.ContainerRegistry containerregistry
Microsoft.Dashboard dashboard
Microsoft.HybridNetwork hybridnetwork "no specs"
Microsoft.MachineLearningServices machinelearningservices "be part of data-plane package"
Microsoft.Management management/Microsoft.Management/ManagementGroups azure-mgmt-managementgroups
Microsoft.Peering peering
Microsoft.ProviderHub providerhub
Microsoft.Cache redisenterprise
Microsoft.Authorization resources/Microsoft.Authorization/policy
Microsoft.SecurityInsights securityinsights
microsoft.web web
microsoft.web web/certificationregistration azure-mgmt-certificateregistration
microsoft.web web/domainregistration azure-mgmt-domainregistration
Microsoft.AlertsManagement alertsmanagement azure-mgmt-alertsmanagement
Microsoft.AzureStackHCI azurestackhci
Microsoft.Commerce commerce
Microsoft.Communication communication
Microsoft.ContainerService containerservice azure-mgmt-containerservice
Microsoft.DocumentDB cosmos-db
Microsoft.DataFactory datafactory
Microsoft.EventGrid eventgrid
Microsoft.KubernetesConfiguration kubernetesconfiguration
Microsoft.KubernetesConfiguration kubernetesconfiguration
Microsoft.Maps maps
Microsoft.Marketplace marketplace
Microsoft.Purview purview
Microsoft.RecoveryServices recoveryservicessiterecovery
Microsoft.Search search
Microsoft.Network frontdoor
Microsoft.NetworkFunction networkfunction
Microsoft.ServiceFabric servicefabric
Microsoft.ServiceFabric servicefabricmanagedclusters
Microsoft.App app
Microsoft.Insights applicationinsights
Microsoft.Authorization authorization
Microsoft.Automation automation
Microsoft.Kusto azure-kusto
Microsoft.Billing billing
Microsoft.ContainerInstance containerinstance
Microsoft.DataMigration datamigration
Microsoft.HDInsight hdinsight
Microsoft.HealthcareApis healthcareapis
Microsoft.HybridCompute hybridcompute
Microsoft.Insights monitor/Microsoft.Insights azure-mgmt-monitor
Microsoft.OperationalInsights operationalinsights
Microsoft.PolicyInsights policyinsights
Microsoft.Capacity reservations
Microsoft.ResourceGraph resourcegraph
Microsoft.ResourceHealth resourcehealth
Microsoft.Security security
Microsoft.Sql sql
Microsoft.StorageCache storagecache
Microsoft.Subscription subscription
Microsoft.Resources resources/Microsoft.Resources/resources
Microsoft.AzureArcData azurearcdata
Microsoft.Databricks databricks
Microsoft.DevHub developerhub
Microsoft.AAD domainservices
Microsoft.Education education
Microsoft.HanaOnAzure hanaonazure
Microsoft.VirtualMachineImages imagebuilder
Microsoft.OffAzure migrate/resource-manager/Microsoft.OffAzure "no specs"
Microsoft.PowerPlatform powerplatform
Microsoft.RedHatOpenshift redhatopenshift
Microsoft.SerialConsole serialconsole
Microsoft.Solutions solutions
Microsoft.Resources resources/Microsoft.Resources/deployments
Microsoft.Resources resources/Microsoft.Resources/databoundaries
Microsoft.Resources resources/Microsoft.Resources/subscriptions
Microsoft.Resources resources/Microsoft.Resources/bicep
Microsoft.Resources resources/Microsoft.Resources/deploymentstakcs
Microsoft.Management management/Microsoft.Management/ServiceGroups
Microsoft.ExtendedLocation extendedlocation
Microsoft.Devices iothub
Loading
Loading