From 07827a2fe256744f4c95cb5181995a96391e40ec Mon Sep 17 00:00:00 2001 From: Microsoft Graph DevX Tooling Date: Wed, 29 Jul 2026 12:20:21 -0700 Subject: [PATCH 1/2] Split doc generation pipeline into parallel v1.0 and beta stages Adds a -GraphProfileFilter parameter (v1.0/beta/both, default both) to the generation and post-processing scripts so each profile can be generated independently, and splits powershell-docs.yml into two parallel stages (GenerateV1, GenerateBeta) via a new reusable common-templates/generate-docs-steps.yml. Each stage generates a single profile, commits to its own branch, and opens its own PR. Built on top of the mass-deletion, idempotency and encoding fixes from ramsess/revert-generation-changes; StabilizeMsDate is intentionally not included as it was removed on that branch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4d27d82f-3809-40d2-b4e7-6623436ff2ef --- .../common-templates/generate-docs-steps.yml | 165 ++++++++++++++++++ azure-pipelines/powershell-docs.yml | 161 +++-------------- scripts/CorrectRelatedLinks-AllFiles.ps1 | 1 + scripts/EscapeDisallowedHtmlTags.ps1 | 7 +- scripts/GenerateAliasedDocs.ps1 | 9 +- scripts/GenerateMarkDown.ps1 | 21 ++- scripts/GeneratePermissionsTable.ps1 | 5 +- scripts/MsSubserviceUpdate.ps1 | 5 +- scripts/RemoveBoilerPlateCode.ps1 | 25 +-- scripts/RemoveInvalidFullStops.ps1 | 7 +- .../RepairExamplesDescriptionsAndTitle.ps1 | 5 +- scripts/UpdateLinks.ps1 | 13 +- 12 files changed, 260 insertions(+), 164 deletions(-) create mode 100644 azure-pipelines/common-templates/generate-docs-steps.yml diff --git a/azure-pipelines/common-templates/generate-docs-steps.yml b/azure-pipelines/common-templates/generate-docs-steps.yml new file mode 100644 index 0000000000000..362ff563c6579 --- /dev/null +++ b/azure-pipelines/common-templates/generate-docs-steps.yml @@ -0,0 +1,165 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# +# Reusable steps that generate the Microsoft Graph PowerShell reference docs for a +# single SDK profile (v1.0 or beta), commit the result to a dedicated branch and +# open a pull request for that profile. Consumed by the parallel stages in +# powershell-docs.yml so that v1.0 and beta each produce an independent PR. + +parameters: + - name: GraphProfileFilter + type: string + values: + - v1.0 + - beta + - name: BranchPrefix + type: string + - name: PrTitle + type: string + - name: PrBody + type: string + default: "This pull request was automatically created by Azure Pipelines. **Important** Check for unexpected deletions or changes in this PR." + +steps: + - template: ../update-template.yml + - task: PowerShell@2 + name: "ComputeBranch" + displayName: 'Compute Branch Name' + inputs: + targetType: 'inline' + script: | + git submodule update --init --recursive + $branch = "{0}_{1}" -f "${{ parameters.BranchPrefix }}", (Get-Date -Format yyyyMMddHHmm) + Write-Host "Compute branch: $branch" + Write-Host "##vso[task.setvariable variable=WeeklyReferenceDocsBranch;isOutput=true]$branch" + - task: Bash@3 + displayName: "Create weekly refresh branch" + inputs: + targetType: inline + script: | + git status + git branch $(ComputeBranch.WeeklyReferenceDocsBranch) + git checkout $(ComputeBranch.WeeklyReferenceDocsBranch) + git status + - task: PowerShell@2 + displayName: 'Create missing external docs folder' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/CreateExternalDocsFolder.ps1 + - task: PowerShell@2 + displayName: 'Generate markdown files from PowerShell help files' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/GenerateMarkDown.ps1 + arguments: -GraphProfileFilter '${{ parameters.GraphProfileFilter }}' + - task: PowerShell@2 + displayName: 'Escape disallowed html tags' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/EscapeDisallowedHtmlTags.ps1 + arguments: -GraphProfileFilter '${{ parameters.GraphProfileFilter }}' + - task: PowerShell@2 + displayName: 'Update metadata header' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/MsSubserviceUpdate.ps1 + arguments: -GraphProfileFilter '${{ parameters.GraphProfileFilter }}' + - task: PowerShell@2 + displayName: 'Generate permissions table' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/GeneratePermissionsTable.ps1 + arguments: -GraphProfileFilter '${{ parameters.GraphProfileFilter }}' + - task: PowerShell@2 + displayName: 'Update Links' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/UpdateLinks.ps1 + arguments: -GraphProfileFilter '${{ parameters.GraphProfileFilter }}' + errorActionPreference: 'stop' + - task: PowerShell@2 + displayName: 'Repair Examples and Descriptions and Title' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/RepairExamplesDescriptionsAndTitle.ps1 + arguments: -GraphProfileFilter '${{ parameters.GraphProfileFilter }}' + - task: PowerShell@2 + displayName: 'Remove boiler plate code' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/RemoveBoilerPlateCode.ps1 + arguments: -GraphProfileFilter '${{ parameters.GraphProfileFilter }}' + - task: PowerShell@2 + displayName: 'Remove invalid fullstops' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/RemoveInvalidFullStops.ps1 + arguments: -GraphProfileFilter '${{ parameters.GraphProfileFilter }}' + - task: PowerShell@2 + displayName: 'Generate missing docs for aliased cmdlets' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/GenerateAliasedDocs.ps1 + arguments: -GraphProfileFilter '${{ parameters.GraphProfileFilter }}' + - task: PowerShell@2 + displayName: 'Correct related links section' + continueOnError: false + inputs: + targetType: 'filePath' + pwsh: true + filePath: scripts/CorrectRelatedLinks-AllFiles.ps1 + arguments: -GraphProfileFilter '${{ parameters.GraphProfileFilter }}' + - task: AzureKeyVault@2 + displayName: "Azure Key Vault: Get GitHub App secrets" + inputs: + azureSubscription: "Federated AKV Managed Identity Connection" + KeyVaultName: akv-prod-eastus + SecretsFilter: "microsoft-graph-devx-bot-appid,microsoft-graph-devx-bot-privatekey" + - task: PowerShell@2 + displayName: Pushing to github + env: + GhAppId: $(microsoft-graph-devx-bot-appid) + GhAppKey: $(microsoft-graph-devx-bot-privatekey) + inputs: + targetType: inline + pwsh: true + script: | + git config --global user.email "GraphTooling@service.microsoft.com" + git config --global user.name "Microsoft Graph DevX Tooling" + git config --system core.longpaths true + # The microsoft-graph-devx-bot GitHub App must have contents:write on this repo. + $token = & "$(Build.SourcesDirectory)/scripts/Generate-Github-Token.ps1" -AppClientId $env:GhAppId -AppPrivateKeyContents $env:GhAppKey -Repository "MicrosoftDocs/microsoftgraph-docs-powershell" + if ([string]::IsNullOrWhiteSpace($token)) { throw "Failed to generate GitHub App installation token." } + # Mask the token so it is never surfaced in pipeline logs. + Write-Host "##vso[task.setsecret]$token" + git status + git add . + git commit -m "Updating reference docs" + git push --set-upstream "******github.com/MicrosoftDocs/microsoftgraph-docs-powershell.git" $(ComputeBranch.WeeklyReferenceDocsBranch) + git status + - template: create-pr.yml + parameters: + BaseBranch: "main" + TargetBranch: $(ComputeBranch.WeeklyReferenceDocsBranch) + Title: "${{ parameters.PrTitle }}" + Body: "${{ parameters.PrBody }}" diff --git a/azure-pipelines/powershell-docs.yml b/azure-pipelines/powershell-docs.yml index 603004858ab45..1d52b4b6c4cb9 100644 --- a/azure-pipelines/powershell-docs.yml +++ b/azure-pipelines/powershell-docs.yml @@ -47,148 +47,39 @@ extends: customBuildTags: - ES365AIMigrationTooling stages: - - stage: stage + - stage: GenerateV1 + dependsOn: [] jobs: - - job: PowerShellDocsUpdate + - job: GenerateV1Docs timeoutInMinutes: ${{ parameters.PipelineTimeout }} templateContext: outputs: - output: pipelineArtifact displayName: 'Publish Examples to be reviewed as artifact' targetPath: missingexternaldocsurl - artifactName: 'MissingExternalDocs' + artifactName: 'MissingExternalDocs-v1.0' publishLocation: 'Container' steps: - - template: azure-pipelines/update-template.yml@self - - task : PowerShell@2 - name: "ComputeBranch" - displayName: 'Compute Branch Name' - inputs: - targetType: 'inline' - script: | - git submodule update --init --recursive - $branch = "{0}_{1}" -f "WeeklyReferenceDocsUpdate", (Get-Date -Format yyyyMMddHHmm) - Write-Host "Compute branch: $branch" - Write-Host "##vso[task.setvariable variable=WeeklyReferenceDocsBranch;isOutput=true]$branch" - - task: Bash@3 - displayName: "Create weekly refresh branch" - inputs: - targetType: inline - script: | - git status - git branch $(ComputeBranch.WeeklyReferenceDocsBranch) - git checkout $(ComputeBranch.WeeklyReferenceDocsBranch) - git status - - task: PowerShell@2 - displayName: 'Create missing external docs folder' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/CreateExternalDocsFolder.ps1 - - - task: PowerShell@2 - displayName: 'Generate markdown files from PowerShell help files' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/GenerateMarkDown.ps1 - - task: PowerShell@2 - displayName: 'Escape disallowed html tags' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/EscapeDisallowedHtmlTags.ps1 - - task: PowerShell@2 - displayName: 'Update metadata header' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/MsSubserviceUpdate.ps1 - - task: PowerShell@2 - displayName: 'Generate permissions table' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/GeneratePermissionsTable.ps1 - - task: PowerShell@2 - displayName: 'Update Links' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/UpdateLinks.ps1 - errorActionPreference: 'stop' - - task: PowerShell@2 - displayName: 'Repair Examples and Descriptions and Title' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/RepairExamplesDescriptionsAndTitle.ps1 - - task: PowerShell@2 - displayName: 'Remove boiler plate code' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/RemoveBoilerPlateCode.ps1 - - task: PowerShell@2 - displayName: 'Remove invalid fullstops' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/RemoveInvalidFullStops.ps1 - - task: PowerShell@2 - displayName: 'Generate missing docs for aliased cmdlets' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/GenerateAliasedDocs.ps1 - - task: PowerShell@2 - displayName: 'Correct related links section' - continueOnError: false - inputs: - targetType: 'filePath' - pwsh: true - filePath: scripts/CorrectRelatedLinks-AllFiles.ps1 - - task: AzureKeyVault@2 - displayName: "Azure Key Vault: Get GitHub App secrets" - inputs: - azureSubscription: "Federated AKV Managed Identity Connection" - KeyVaultName: akv-prod-eastus - SecretsFilter: "microsoft-graph-devx-bot-appid,microsoft-graph-devx-bot-privatekey" - - task: PowerShell@2 - displayName: Pushing to github - env: - GhAppId: $(microsoft-graph-devx-bot-appid) - GhAppKey: $(microsoft-graph-devx-bot-privatekey) - inputs: - targetType: inline - pwsh: true - script: | - git config --global user.email "GraphTooling@service.microsoft.com" - git config --global user.name "Microsoft Graph DevX Tooling" - git config --system core.longpaths true - # The microsoft-graph-devx-bot GitHub App must have contents:write on this repo. - $token = & "$(Build.SourcesDirectory)/scripts/Generate-Github-Token.ps1" -AppClientId $env:GhAppId -AppPrivateKeyContents $env:GhAppKey -Repository "MicrosoftDocs/microsoftgraph-docs-powershell" - if ([string]::IsNullOrWhiteSpace($token)) { throw "Failed to generate GitHub App installation token." } - # Mask the token so it is never surfaced in pipeline logs. - Write-Host "##vso[task.setsecret]$token" - git status - git add . - git commit -m "Updating reference docs" - git push --set-upstream "https://x-access-token:$token@github.com/MicrosoftDocs/microsoftgraph-docs-powershell.git" $(ComputeBranch.WeeklyReferenceDocsBranch) - git status - - template: azure-pipelines/common-templates/create-pr.yml@self + - template: azure-pipelines/common-templates/generate-docs-steps.yml@self parameters: - BaseBranch: "main" - TargetBranch: $(ComputeBranch.WeeklyReferenceDocsBranch) - Title: "Weekly PowerShell Microsoft Graph Reference Docs Refresh" - Body: "This pull request was automatically created by Azure Pipelines. **Important** Check for unexpected deletions or changes in this PR." \ No newline at end of file + GraphProfileFilter: 'v1.0' + BranchPrefix: 'WeeklyReferenceDocsUpdate-V1' + PrTitle: 'Weekly PowerShell Microsoft Graph v1.0 Reference Docs Refresh' + - stage: GenerateBeta + dependsOn: [] + jobs: + - job: GenerateBetaDocs + timeoutInMinutes: ${{ parameters.PipelineTimeout }} + templateContext: + outputs: + - output: pipelineArtifact + displayName: 'Publish Examples to be reviewed as artifact' + targetPath: missingexternaldocsurl + artifactName: 'MissingExternalDocs-beta' + publishLocation: 'Container' + steps: + - template: azure-pipelines/common-templates/generate-docs-steps.yml@self + parameters: + GraphProfileFilter: 'beta' + BranchPrefix: 'WeeklyReferenceDocsUpdate-Beta' + PrTitle: 'Weekly PowerShell Microsoft Graph beta Reference Docs Refresh' diff --git a/scripts/CorrectRelatedLinks-AllFiles.ps1 b/scripts/CorrectRelatedLinks-AllFiles.ps1 index 3f6a71383b9e6..4fb92908cac64 100644 --- a/scripts/CorrectRelatedLinks-AllFiles.ps1 +++ b/scripts/CorrectRelatedLinks-AllFiles.ps1 @@ -19,6 +19,7 @@ param( [Parameter(Mandatory = $false)] [ValidateSet("v1.0", "beta", "both")] + [Alias("GraphProfileFilter")] [string]$GraphProfile = "both" ) diff --git a/scripts/EscapeDisallowedHtmlTags.ps1 b/scripts/EscapeDisallowedHtmlTags.ps1 index 597d7a5633f81..e70a982d19d1e 100644 --- a/scripts/EscapeDisallowedHtmlTags.ps1 +++ b/scripts/EscapeDisallowedHtmlTags.ps1 @@ -2,7 +2,9 @@ # Licensed under the MIT License. Param( $ModulesToGenerate = @(), - [string] $ModuleMappingConfigPath = (Join-Path $PSScriptRoot "../microsoftgraph/config/ModulesMapping.jsonc") + [string] $ModuleMappingConfigPath = (Join-Path $PSScriptRoot "../microsoftgraph/config/ModulesMapping.jsonc"), + [ValidateSet("v1.0", "beta", "both")] + [string] $GraphProfileFilter = "both" ) function Get-GraphMapping { $graphMapping = @{} @@ -18,7 +20,8 @@ function EscapeDisallowedHtmlTags { $ModulePrefix = "Microsoft.Graph" $GraphMapping = Get-GraphMapping - $GraphMapping.Keys | ForEach-Object { + $profilesToProcess = if ($GraphProfileFilter -eq 'both') { $GraphMapping.Keys } else { @($GraphProfileFilter) } + $profilesToProcess | ForEach-Object { $graphProfile = $_ Get-FilesByProfile -GraphProfile $graphProfile -GraphProfilePath $GraphMapping[$graphProfile] -ModulePrefix $ModulePrefix -ModulesToGenerate $ModulesToGenerate } diff --git a/scripts/GenerateAliasedDocs.ps1 b/scripts/GenerateAliasedDocs.ps1 index 97eba9685354d..23052eb40eff2 100644 --- a/scripts/GenerateAliasedDocs.ps1 +++ b/scripts/GenerateAliasedDocs.ps1 @@ -6,12 +6,17 @@ See related PR for more information. #> +param( + [ValidateSet("v1.0", "beta", "both")] + [string]$GraphProfileFilter = "both" +) + function Start-GenerateAliasedDocs { $BreakingChangeReportV1Report = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell/docs/PowerShellBreakingChanges-V1.0.csv") $BreakingChangeReportBetaReport = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell/docs/PowerShellBreakingChanges-beta.csv") $Reports = @() - $Reports += $BreakingChangeReportV1Report - $Reports += $BreakingChangeReportBetaReport + if ($GraphProfileFilter -ne 'beta') { $Reports += $BreakingChangeReportV1Report } + if ($GraphProfileFilter -ne 'v1.0') { $Reports += $BreakingChangeReportBetaReport } foreach ($BreakingChangeReport in $Reports) { Import-Csv $BreakingChangeReport | ForEach-Object { $Command = $_."NewCmdlet" diff --git a/scripts/GenerateMarkDown.ps1 b/scripts/GenerateMarkDown.ps1 index 0d5a062bef429..1294772badf29 100644 --- a/scripts/GenerateMarkDown.ps1 +++ b/scripts/GenerateMarkDown.ps1 @@ -5,7 +5,9 @@ Param( $ModulesToGenerate = @(), [string] $ModuleMappingConfigPath = (Join-Path $PSScriptRoot "../microsoftgraph/config\ModulesMapping.jsonc"), [string] $WorkLoadDocsPath = (Join-Path $PSScriptRoot "../microsoftgraph"), - [string] $CmdletMetadataPath = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell/src/Authentication/Authentication/custom/common/MgCommandMetadata.json") + [string] $CmdletMetadataPath = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell/src/Authentication/Authentication/custom/common/MgCommandMetadata.json"), + [ValidateSet("v1.0", "beta", "both")] + [string] $GraphProfileFilter = "both" ) function Get-GraphMapping { $graphMapping = @{} @@ -64,17 +66,24 @@ function Start-GraphHelp { throw "Microsoft.Graph.Authentication module is not available. Aborting generation to avoid deleting existing documentation." } Import-Module Microsoft.Graph.Authentication -Force -Global -ErrorAction Stop - Get-ChildItem -Path $AuthDestination * -File -Recurse | foreach { $_.Delete() } $GraphMapping = Get-GraphMapping - $GraphMapping.Keys | ForEach-Object { + $profilesToProcess = if ($GraphProfileFilter -eq 'both') { $GraphMapping.Keys } else { @($GraphProfileFilter) } + + # Authentication docs live only under graph-powershell-1.0, so (re)generate them + # only when the v1.0 profile is in scope. When generating beta on its own the auth + # docs are left untouched. + if ($GraphProfileFilter -ne 'beta') { + Get-ChildItem -Path $AuthDestination * -File -Recurse | foreach { $_.Delete() } + $AuthenticationDocsPath = Join-Path $PSScriptRoot "..\microsoftgraph\graph-powershell-1.0" + Set-Help -ModuleDocsPath $AuthenticationDocsPath -Command "Connect-MgGraph" -Module "Microsoft.Graph.Authentication" + } + + $profilesToProcess | ForEach-Object { $graphProfile = $_ $profilePath = "graph-powershell-1.0" if ($graphProfile -eq "beta") { $profilePath = "graph-powershell-beta" } - - $AuthenticationDocsPath = Join-Path $PSScriptRoot "..\microsoftgraph\graph-powershell-1.0" - Set-Help -ModuleDocsPath $AuthenticationDocsPath -Command "Connect-MgGraph" -Module "Microsoft.Graph.Authentication" Get-FolderByProfile -GraphProfile $graphProfile -GraphProfilePath $profilePath -ModulePrefix $ModulePrefix -ModulesToGenerate $ModulesToGenerate } git config --global user.email "GraphTooling@service.microsoft.com" diff --git a/scripts/GeneratePermissionsTable.ps1 b/scripts/GeneratePermissionsTable.ps1 index 47e90ae3698f8..11251fdf28c89 100644 --- a/scripts/GeneratePermissionsTable.ps1 +++ b/scripts/GeneratePermissionsTable.ps1 @@ -1,6 +1,8 @@ param( [string]$MgCommandMetadatJsonFile = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell/src/Authentication/Authentication/custom/common/MgCommandMetadata.json"), - [string[]]$CmdList = @() + [string[]]$CmdList = @(), + [ValidateSet("v1.0", "beta", "both")] + [string]$GraphProfileFilter = "both" ) function Start-Generator { @@ -11,6 +13,7 @@ function Start-Generator { $CommandName = $_.Command; $ApiVersion = $_.ApiVersion $Module = $_.Module; + if ($GraphProfileFilter -ne 'both' -and $ApiVersion -ne $GraphProfileFilter) { return } #Array for DelegatedWork Permissions $DelegatedWorkPermissions = @(); #Array for Application Permissions diff --git a/scripts/MsSubserviceUpdate.ps1 b/scripts/MsSubserviceUpdate.ps1 index d9bbd826afe67..85cdacda82fbe 100644 --- a/scripts/MsSubserviceUpdate.ps1 +++ b/scripts/MsSubserviceUpdate.ps1 @@ -5,7 +5,9 @@ Param( [string] $SDKDocsPath = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell/src"), [string] $SDKOpenApiPath = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell"), [string] $WorkLoadDocsPath = (Join-Path $PSScriptRoot "../microsoftgraph"), - [string] $MissingMsSubserviceHeaderPath = (Join-Path $PSScriptRoot "../missingexternaldocsurl") + [string] $MissingMsSubserviceHeaderPath = (Join-Path $PSScriptRoot "../missingexternaldocsurl"), + [ValidateSet("v1.0", "beta", "both")] + [string] $GraphProfileFilter = "both" ) function Start-Generator { if (Test-Path $CommandMetadataPath) { @@ -14,6 +16,7 @@ function Start-Generator { $ModuleName = $_.Module $GraphProfile = $_.ApiVersion $Command = $_.Command + if ($GraphProfileFilter -ne 'both' -and $GraphProfile -ne $GraphProfileFilter) { return } $ExternalDocUrl = $_.ApiReferenceLink $GraphProfilePath = "graph-powershell-1.0" $ModulePrefix = "Microsoft.Graph" diff --git a/scripts/RemoveBoilerPlateCode.ps1 b/scripts/RemoveBoilerPlateCode.ps1 index 246e79ba3febe..14e5aadca8c4c 100644 --- a/scripts/RemoveBoilerPlateCode.ps1 +++ b/scripts/RemoveBoilerPlateCode.ps1 @@ -4,7 +4,9 @@ Param( $ModulesToGenerate = @(), [string] $ModuleMappingConfigPath = (Join-Path $PSScriptRoot "../microsoftgraph/config/ModulesMapping.jsonc"), [string] $WorkLoadDocsPath = (Join-Path $PSScriptRoot "../microsoftgraph"), - [string] $AuthLoadDocsPath = (Join-Path $PSScriptRoot "../microsoftgraph/graph-powershell-1.0/Microsoft.Graph.Authentication") + [string] $AuthLoadDocsPath = (Join-Path $PSScriptRoot "../microsoftgraph/graph-powershell-1.0/Microsoft.Graph.Authentication"), + [ValidateSet("v1.0", "beta", "both")] + [string] $GraphProfileFilter = "both" ) function Get-GraphMapping { $graphMapping = @{} @@ -19,18 +21,21 @@ function Start-Repair { $ModulesToGenerate = @() ) - #Cleanup Authentication Module first - $files = Get-ChildItem -Path $AuthLoadDocsPath -Filter *.md -Recurse - foreach ($file in $files) { - $content = Get-Content -Path $file.FullName - # Remove lines that contain '{{ Fill in the Description }}' or '### This' or '### *' or '### have' or '### certain' or '### the' - $cleanedContent = $content | Where-Object { $_ -notmatch '^\s*{{ Fill in the Description }}|^\s*### This|^\s*### \*|^\s*### have|^\s*### certain|^\s*### the' } - # Write the cleaned content back to the file - $cleanedContent | Set-Content -Path $file.FullName + #Cleanup Authentication Module first (Authentication docs live under the v1.0 folder) + if ($GraphProfileFilter -ne 'beta') { + $files = Get-ChildItem -Path $AuthLoadDocsPath -Filter *.md -Recurse + foreach ($file in $files) { + $content = Get-Content -Path $file.FullName + # Remove lines that contain '{{ Fill in the Description }}' or '### This' or '### *' or '### have' or '### certain' or '### the' + $cleanedContent = $content | Where-Object { $_ -notmatch '^\s*{{ Fill in the Description }}|^\s*### This|^\s*### \*|^\s*### have|^\s*### certain|^\s*### the' } + # Write the cleaned content back to the file + $cleanedContent | Set-Content -Path $file.FullName + } } $ModulePrefix = "Microsoft.Graph" $GraphMapping = Get-GraphMapping - $GraphMapping.Keys | ForEach-Object { + $profilesToProcess = if ($GraphProfileFilter -eq 'both') { $GraphMapping.Keys } else { @($GraphProfileFilter) } + $profilesToProcess | ForEach-Object { $graphProfile = $_ $profilePath = "graph-powershell-1.0" if ($graphProfile -eq "beta") { diff --git a/scripts/RemoveInvalidFullStops.ps1 b/scripts/RemoveInvalidFullStops.ps1 index db34789d58025..9aa576d88f934 100644 --- a/scripts/RemoveInvalidFullStops.ps1 +++ b/scripts/RemoveInvalidFullStops.ps1 @@ -2,7 +2,9 @@ # Licensed under the MIT License. Param( $ModulesToGenerate = @(), - [string] $ModuleMappingConfigPath = (Join-Path $PSScriptRoot "../microsoftgraph/config/ModulesMapping.jsonc") + [string] $ModuleMappingConfigPath = (Join-Path $PSScriptRoot "../microsoftgraph/config/ModulesMapping.jsonc"), + [ValidateSet("v1.0", "beta", "both")] + [string] $GraphProfileFilter = "both" ) function Get-GraphMapping { $graphMapping = @{} @@ -18,7 +20,8 @@ function Remove-InvalidFullStops { $ModulePrefix = "Microsoft.Graph" $GraphMapping = Get-GraphMapping - $GraphMapping.Keys | ForEach-Object { + $profilesToProcess = if ($GraphProfileFilter -eq 'both') { $GraphMapping.Keys } else { @($GraphProfileFilter) } + $profilesToProcess | ForEach-Object { $graphProfile = $_ Get-FilesByProfile -GraphProfile $graphProfile -GraphProfilePath $GraphMapping[$graphProfile] -ModulePrefix $ModulePrefix -ModulesToGenerate $ModulesToGenerate } diff --git a/scripts/RepairExamplesDescriptionsAndTitle.ps1 b/scripts/RepairExamplesDescriptionsAndTitle.ps1 index c8e3c74074799..f104cb92d2595 100644 --- a/scripts/RepairExamplesDescriptionsAndTitle.ps1 +++ b/scripts/RepairExamplesDescriptionsAndTitle.ps1 @@ -4,7 +4,9 @@ Param( $ModulesToGenerate = @(), [string] $SDKDocsPath = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell/src"), [string] $WorkLoadDocsPath = (Join-Path $PSScriptRoot "../microsoftgraph"), - [string] $CommandMetadataPath = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell/src/Authentication/Authentication/custom/common/MgCommandMetadata.json") + [string] $CommandMetadataPath = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell/src/Authentication/Authentication/custom/common/MgCommandMetadata.json"), + [ValidateSet("v1.0", "beta", "both")] + [string] $GraphProfileFilter = "both" ) function Start-Copy { @@ -15,6 +17,7 @@ function Start-Copy { $ModuleName = $_.Module $GraphProfile = $_.ApiVersion $Command = $_.Command + if ($GraphProfileFilter -ne 'both' -and $GraphProfile -ne $GraphProfileFilter) { return } $GraphProfilePath = "graph-powershell-1.0" $ModulePrefix = "Microsoft.Graph" if ($GraphProfile -eq "beta") { diff --git a/scripts/UpdateLinks.ps1 b/scripts/UpdateLinks.ps1 index fcc8d8e2253b2..17d9106d7d14a 100644 --- a/scripts/UpdateLinks.ps1 +++ b/scripts/UpdateLinks.ps1 @@ -4,7 +4,9 @@ Param( $ModulesToGenerate = @(), [string] $ModuleMappingConfigPath = (Join-Path $PSScriptRoot "../microsoftgraph/config/ModulesMapping.jsonc"), [string] $SDKDocsPath = (Join-Path $PSScriptRoot "../msgraph-sdk-powershell/src"), - [string] $WorkLoadDocsPath = (Join-Path $PSScriptRoot "../microsoftgraph") + [string] $WorkLoadDocsPath = (Join-Path $PSScriptRoot "../microsoftgraph"), + [ValidateSet("v1.0", "beta", "both")] + [string] $GraphProfileFilter = "both" ) function Get-GraphMapping { $graphMapping = @{} @@ -20,7 +22,8 @@ function Start-Update { $ModulePrefix = "Microsoft.Graph" $GraphMapping = Get-GraphMapping - $GraphMapping.Keys | ForEach-Object { + $profilesToProcess = if ($GraphProfileFilter -eq 'both') { $GraphMapping.Keys } else { @($GraphProfileFilter) } + $profilesToProcess | ForEach-Object { $GraphProfile = $_ $profilePath = "graph-powershell-1.0" if ($GraphProfile -eq "beta") { @@ -116,7 +119,8 @@ function Construct-Path { $BetaFilePath = Join-Path $WorkLoadDocsPath "graph-powershell-beta" "Microsoft.Graph.Beta.$Module" "$Command.md" $V1FilePath = Join-Path $WorkLoadDocsPath "graph-powershell-1.0" "Microsoft.Graph.$Module" "$Command.md" - if (Test-Path $BetaFilePath) { + # Adds the cross-profile note into the beta doc (skip when generating v1.0 only). + if ((Test-Path $BetaFilePath) -and ($GraphProfileFilter -ne 'v1.0')) { $V1Command = $Command.Replace("-MgBeta", "-Mg") $ConfirmV1Path = Join-Path $WorkLoadDocsPath "graph-powershell-1.0" "Microsoft.Graph.$Module" "$V1Command.md" if (Test-Path $ConfirmV1Path) { @@ -124,7 +128,8 @@ function Construct-Path { } } - if (Test-Path $V1FilePath) { + # Adds the cross-profile note into the v1.0 doc (skip when generating beta only). + if ((Test-Path $V1FilePath) -and ($GraphProfileFilter -ne 'beta')) { $BetaCommand = $Command.Replace("-Mg", "-MgBeta") $ConfirmBetaPath = Join-Path $WorkLoadDocsPath "graph-powershell-beta" "Microsoft.Graph.Beta.$Module" "$BetaCommand.md" if (Test-Path $ConfirmBetaPath) { From d4725c25c9788755839c5ec79c2d0b1ea10b39f0 Mon Sep 17 00:00:00 2001 From: Microsoft Graph DevX Tooling Date: Wed, 29 Jul 2026 16:10:47 -0700 Subject: [PATCH 2/2] Guard against empty commits in doc generation scripts In the split pipeline each profile stage generates a single profile, so a post-processing step can legitimately produce no changes for that profile. A bare 'git commit' exits 1 ('nothing to commit') and, as the last native command in the step, fails the task even though nothing is wrong. Apply the 'commit only if staged changes exist' guard (already present in CorrectRelatedLinks/UpdateLinks/MsSubserviceUpdate) to the remaining scripts: GenerateMarkDown, EscapeDisallowedHtmlTags, GeneratePermissionsTable, RemoveBoilerPlateCode, RemoveInvalidFullStops, RepairExamplesDescriptionsAndTitle. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4d27d82f-3809-40d2-b4e7-6623436ff2ef --- scripts/EscapeDisallowedHtmlTags.ps1 | 13 ++++++++++++- scripts/GenerateMarkDown.ps1 | 13 ++++++++++++- scripts/GeneratePermissionsTable.ps1 | 13 ++++++++++++- scripts/RemoveBoilerPlateCode.ps1 | 13 ++++++++++++- scripts/RemoveInvalidFullStops.ps1 | 13 ++++++++++++- scripts/RepairExamplesDescriptionsAndTitle.ps1 | 13 ++++++++++++- 6 files changed, 72 insertions(+), 6 deletions(-) diff --git a/scripts/EscapeDisallowedHtmlTags.ps1 b/scripts/EscapeDisallowedHtmlTags.ps1 index e70a982d19d1e..531dded7a72b4 100644 --- a/scripts/EscapeDisallowedHtmlTags.ps1 +++ b/scripts/EscapeDisallowedHtmlTags.ps1 @@ -29,7 +29,18 @@ function EscapeDisallowedHtmlTags { git config --global user.email "GraphTooling@service.microsoft.com" git config --global user.name "Microsoft Graph DevX Tooling" git add . - git commit -m "Escaped disallowed html tags" + + # Check for staged changes; commit only if any exist + $pending = git status --porcelain + if (-not [string]::IsNullOrWhiteSpace($pending)) { + git commit -m "Escaped disallowed html tags" + Write-Host "Committed escaping of disallowed html tags." + } + else { + Write-Host "Nothing to commit; skipping commit step." + # Ensure a clean exit code even if earlier native commands returned 1 + $global:LASTEXITCODE = 0 + } } function Get-FilesByProfile { Param( diff --git a/scripts/GenerateMarkDown.ps1 b/scripts/GenerateMarkDown.ps1 index 1294772badf29..4a6c0ba3cfa17 100644 --- a/scripts/GenerateMarkDown.ps1 +++ b/scripts/GenerateMarkDown.ps1 @@ -89,7 +89,18 @@ function Start-GraphHelp { git config --global user.email "GraphTooling@service.microsoft.com" git config --global user.name "Microsoft Graph DevX Tooling" git add . - git commit -m "Updated markdown help" + + # Check for staged changes; commit only if any exist + $pending = git status --porcelain + if (-not [string]::IsNullOrWhiteSpace($pending)) { + git commit -m "Updated markdown help" + Write-Host "Committed updated markdown help." + } + else { + Write-Host "Nothing to commit; skipping commit step." + # Ensure a clean exit code even if earlier native commands returned 1 + $global:LASTEXITCODE = 0 + } } function Get-FolderByProfile { diff --git a/scripts/GeneratePermissionsTable.ps1 b/scripts/GeneratePermissionsTable.ps1 index 11251fdf28c89..cbec7ef95418c 100644 --- a/scripts/GeneratePermissionsTable.ps1 +++ b/scripts/GeneratePermissionsTable.ps1 @@ -73,7 +73,18 @@ function Start-Generator { git config --global user.email "GraphTooling@service.microsoft.com" git config --global user.name "Microsoft Graph DevX Tooling" git add . - git commit -m "Inserted permissions Table" + + # Check for staged changes; commit only if any exist + $pending = git status --porcelain + if (-not [string]::IsNullOrWhiteSpace($pending)) { + git commit -m "Inserted permissions Table" + Write-Host "Committed permissions table." + } + else { + Write-Host "Nothing to commit; skipping commit step." + # Ensure a clean exit code even if earlier native commands returned 1 + $global:LASTEXITCODE = 0 + } } catch { Write-Host "Error in $_"; diff --git a/scripts/RemoveBoilerPlateCode.ps1 b/scripts/RemoveBoilerPlateCode.ps1 index 14e5aadca8c4c..a677f75f07dd2 100644 --- a/scripts/RemoveBoilerPlateCode.ps1 +++ b/scripts/RemoveBoilerPlateCode.ps1 @@ -46,7 +46,18 @@ function Start-Repair { git config --global user.email "GraphTooling@service.microsoft.com" git config --global user.name "Microsoft Graph DevX Tooling" git add . - git commit -m "Remove boiler plate code injected by Autorest" + + # Check for staged changes; commit only if any exist + $pending = git status --porcelain + if (-not [string]::IsNullOrWhiteSpace($pending)) { + git commit -m "Remove boiler plate code injected by Autorest" + Write-Host "Committed removal of boiler plate code." + } + else { + Write-Host "Nothing to commit; skipping commit step." + # Ensure a clean exit code even if earlier native commands returned 1 + $global:LASTEXITCODE = 0 + } } function Get-FilesByProfile { Param( diff --git a/scripts/RemoveInvalidFullStops.ps1 b/scripts/RemoveInvalidFullStops.ps1 index 9aa576d88f934..707f5c0969c4f 100644 --- a/scripts/RemoveInvalidFullStops.ps1 +++ b/scripts/RemoveInvalidFullStops.ps1 @@ -29,7 +29,18 @@ function Remove-InvalidFullStops { git config --global user.email "GraphTooling@service.microsoft.com" git config --global user.name "Microsoft Graph DevX Tooling" git add . - git commit -m "Removed invalid full stops from the beginning of lines" + + # Check for staged changes; commit only if any exist + $pending = git status --porcelain + if (-not [string]::IsNullOrWhiteSpace($pending)) { + git commit -m "Removed invalid full stops from the beginning of lines" + Write-Host "Committed removal of invalid full stops." + } + else { + Write-Host "Nothing to commit; skipping commit step." + # Ensure a clean exit code even if earlier native commands returned 1 + $global:LASTEXITCODE = 0 + } } function Get-FilesByProfile { Param( diff --git a/scripts/RepairExamplesDescriptionsAndTitle.ps1 b/scripts/RepairExamplesDescriptionsAndTitle.ps1 index f104cb92d2595..06eba0fcbbe2e 100644 --- a/scripts/RepairExamplesDescriptionsAndTitle.ps1 +++ b/scripts/RepairExamplesDescriptionsAndTitle.ps1 @@ -41,7 +41,18 @@ function Start-Copy { git config --global user.email "GraphTooling@service.microsoft.com" git config --global user.name "Microsoft Graph DevX Tooling" git add . - git commit -m "Repaired examples and descriptions" + + # Check for staged changes; commit only if any exist + $pending = git status --porcelain + if (-not [string]::IsNullOrWhiteSpace($pending)) { + git commit -m "Repaired examples and descriptions" + Write-Host "Committed repaired examples and descriptions." + } + else { + Write-Host "Nothing to commit; skipping commit step." + # Ensure a clean exit code even if earlier native commands returned 1 + $global:LASTEXITCODE = 0 + } }