From ae7f849949471e82e978332d0fbef598700dfc85 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 13 Nov 2025 13:44:07 -0800 Subject: [PATCH 001/127] [release/v7.6] Add network isolation policy parameter to vPack pipeline (#26444) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .pipelines/PowerShell-vPack-Official.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index f110ff0366a..2c6ec989ee5 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -23,6 +23,14 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: 'Enable debug output' type: boolean default: false +- name: netiso + displayName: "Network Isolation Policy" + type: string + values: + - KS4 + - R1 + - Netlock + default: "R1" name: vPack_$(Build.SourceBranchName)_Prod.${{ parameters.OfficialBuild }}_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) @@ -53,6 +61,8 @@ variables: value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@onebranchTemplates', 'v2/Microsoft.NonOfficial.yml@onebranchTemplates' ) }} - group: DotNetPrivateBuildAccess - group: certificate_logical_to_actual + - name: netiso + value: ${{ parameters.netiso }} # We shouldn't be using PATs anymore # - group: mscodehub-feed-read-general @@ -69,6 +79,11 @@ extends: platform: name: 'windows_undocked' # windows undocked + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: ${{ variables.netiso }} + cloudvault: enabled: false From dee5188f750eca2bdf98755266aec00a851540f8 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 13 Nov 2025 14:15:10 -0800 Subject: [PATCH 002/127] [release/v7.6] Add markdown link verification for PRs (#26445) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: xtqqczze <45661989+xtqqczze@users.noreply.github.com> --- .../markdownlinks/Parse-MarkdownLink.ps1 | 182 ++++++++++ .../infrastructure/markdownlinks/README.md | 177 ++++++++++ .../markdownlinks/Verify-MarkdownLinks.ps1 | 317 ++++++++++++++++++ .../infrastructure/markdownlinks/action.yml | 139 ++++++++ ...owershell-parameter-naming.instructions.md | 69 ++++ .github/workflows/verify-markdown-links.yml | 32 ++ 6 files changed, 916 insertions(+) create mode 100644 .github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 create mode 100644 .github/actions/infrastructure/markdownlinks/README.md create mode 100644 .github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 create mode 100644 .github/actions/infrastructure/markdownlinks/action.yml create mode 100644 .github/instructions/powershell-parameter-naming.instructions.md create mode 100644 .github/workflows/verify-markdown-links.yml diff --git a/.github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 b/.github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 new file mode 100644 index 00000000000..a56d696eb6e --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/Parse-MarkdownLink.ps1 @@ -0,0 +1,182 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +#requires -version 7 +# Markdig is always available in PowerShell 7 +<# +.SYNOPSIS + Parse CHANGELOG files using Markdig to extract links. + +.DESCRIPTION + This script uses Markdig.Markdown.Parse to parse all markdown files in the CHANGELOG directory + and extract different types of links (inline links, reference links, etc.). + +.PARAMETER ChangelogPath + Path to the CHANGELOG directory. Defaults to ./CHANGELOG + +.PARAMETER LinkType + Filter by link type: All, Inline, Reference, AutoLink. Defaults to All. + +.EXAMPLE + .\Parse-MarkdownLink.ps1 + +.EXAMPLE + .\Parse-MarkdownLink.ps1 -LinkType Reference +#> + +param( + [string]$ChangelogPath = "./CHANGELOG", + [ValidateSet("All", "Inline", "Reference", "AutoLink")] + [string]$LinkType = "All" +) + +Write-Verbose "Using built-in Markdig functionality to parse markdown files" + +function Get-LinksFromMarkdownAst { + param( + [Parameter(Mandatory)] + [object]$Node, + [Parameter(Mandatory)] + [string]$FileName, + [System.Collections.ArrayList]$Links + ) + + if ($null -eq $Links) { + return + } + + # Check if current node is a link + if ($Node -is [Markdig.Syntax.Inlines.LinkInline]) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $Node.Line + 1 # Convert to 1-based line numbering + Column = $Node.Column + 1 # Convert to 1-based column numbering + Url = $Node.Url ?? "" + Text = $Node.FirstChild?.ToString() ?? "" + Type = "Inline" + IsImage = $Node.IsImage + } + [void]$Links.Add($linkInfo) + } + elseif ($Node -is [Markdig.Syntax.Inlines.AutolinkInline]) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $Node.Line + 1 + Column = $Node.Column + 1 + Url = $Node.Url ?? "" + Text = $Node.Url ?? "" + Type = "AutoLink" + IsImage = $false + } + [void]$Links.Add($linkInfo) + } + elseif ($Node -is [Markdig.Syntax.LinkReferenceDefinitionGroup]) { + foreach ($refDef in $Node) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $refDef.Line + 1 + Column = $refDef.Column + 1 + Url = $refDef.Url ?? "" + Text = $refDef.Label ?? "" + Type = "Reference" + IsImage = $false + } + [void]$Links.Add($linkInfo) + } + } + elseif ($Node -is [Markdig.Syntax.LinkReferenceDefinition]) { + $linkInfo = [PSCustomObject]@{ + Path = $FileName + Line = $Node.Line + 1 + Column = $Node.Column + 1 + Url = $Node.Url ?? "" + Text = $Node.Label ?? "" + Type = "Reference" + IsImage = $false + } + [void]$Links.Add($linkInfo) + } + + # For MarkdownDocument (root), iterate through all blocks + if ($Node -is [Markdig.Syntax.MarkdownDocument]) { + foreach ($block in $Node) { + Get-LinksFromMarkdownAst -Node $block -FileName $FileName -Links $Links + } + } + # For block containers, iterate through children + elseif ($Node -is [Markdig.Syntax.ContainerBlock]) { + foreach ($child in $Node) { + Get-LinksFromMarkdownAst -Node $child -FileName $FileName -Links $Links + } + } + # For leaf blocks with inlines, process the inline content + elseif ($Node -is [Markdig.Syntax.LeafBlock] -and $Node.Inline) { + Get-LinksFromMarkdownAst -Node $Node.Inline -FileName $FileName -Links $Links + } + # For inline containers, process all child inlines + elseif ($Node -is [Markdig.Syntax.Inlines.ContainerInline]) { + $child = $Node.FirstChild + while ($child) { + Get-LinksFromMarkdownAst -Node $child -FileName $FileName -Links $Links + $child = $child.NextSibling + } + } + # For other inline elements that might have children + elseif ($Node.PSObject.Properties.Name -contains "FirstChild" -and $Node.FirstChild) { + $child = $Node.FirstChild + while ($child) { + Get-LinksFromMarkdownAst -Node $child -FileName $FileName -Links $Links + $child = $child.NextSibling + } + } +} + +function Parse-ChangelogFiles { + param( + [string]$Path + ) + + if (-not (Test-Path $Path)) { + Write-Error "CHANGELOG directory not found: $Path" + return + } + + $markdownFiles = Get-ChildItem -Path $Path -Filter "*.md" -File + + if ($markdownFiles.Count -eq 0) { + Write-Warning "No markdown files found in $Path" + return + } + + $allLinks = [System.Collections.ArrayList]::new() + + foreach ($file in $markdownFiles) { + Write-Verbose "Processing file: $($file.Name)" + + try { + $content = Get-Content -Path $file.FullName -Raw -Encoding UTF8 + + # Parse the markdown content using Markdig + $document = [Markdig.Markdown]::Parse($content, [Markdig.MarkdownPipelineBuilder]::new()) + + # Extract links from the AST + Get-LinksFromMarkdownAst -Node $document -FileName $file.FullName -Links $allLinks + + } catch { + Write-Warning "Error processing file $($file.Name): $($_.Exception.Message)" + } + } + + # Filter by link type if specified + if ($LinkType -ne "All") { + $allLinks = $allLinks | Where-Object { $_.Type -eq $LinkType } + } + + return $allLinks +} + +# Main execution +$links = Parse-ChangelogFiles -Path $ChangelogPath + +# Output PowerShell objects +$links diff --git a/.github/actions/infrastructure/markdownlinks/README.md b/.github/actions/infrastructure/markdownlinks/README.md new file mode 100644 index 00000000000..e566ec2bcc3 --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/README.md @@ -0,0 +1,177 @@ +# Verify Markdown Links Action + +A GitHub composite action that verifies all links in markdown files using PowerShell and Markdig. + +## Features + +- ✅ Parses markdown files using Markdig (built into PowerShell 7) +- ✅ Extracts all link types: inline links, reference links, and autolinks +- ✅ Verifies HTTP/HTTPS links with configurable timeouts and retries +- ✅ Validates local file references +- ✅ Supports excluding specific URL patterns +- ✅ Provides detailed error reporting with file locations +- ✅ Outputs metrics for CI/CD integration + +## Usage + +### Basic Usage + +```yaml +- name: Verify Markdown Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './CHANGELOG' +``` + +### Advanced Usage + +```yaml +- name: Verify Markdown Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './docs' + fail-on-error: 'true' + timeout: 30 + max-retries: 2 + exclude-patterns: '*.example.com/*,*://localhost/*' +``` + +### With Outputs + +```yaml +- name: Verify Markdown Links + id: verify-links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './CHANGELOG' + fail-on-error: 'false' + +- name: Display Results + run: | + echo "Total links: ${{ steps.verify-links.outputs.total-links }}" + echo "Passed: ${{ steps.verify-links.outputs.passed-links }}" + echo "Failed: ${{ steps.verify-links.outputs.failed-links }}" + echo "Skipped: ${{ steps.verify-links.outputs.skipped-links }}" +``` + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `path` | Path to the directory containing markdown files to verify | No | `./CHANGELOG` | +| `exclude-patterns` | Comma-separated list of URL patterns to exclude from verification | No | `''` | +| `fail-on-error` | Whether to fail the action if any links are broken | No | `true` | +| `timeout` | Timeout in seconds for HTTP requests | No | `30` | +| `max-retries` | Maximum number of retries for failed requests | No | `2` | + +## Outputs + +| Output | Description | +|--------|-------------| +| `total-links` | Total number of unique links checked | +| `passed-links` | Number of links that passed verification | +| `failed-links` | Number of links that failed verification | +| `skipped-links` | Number of links that were skipped | + +## Excluded Link Types + +The action automatically skips the following link types: + +- **Anchor links** (`#section-name`) - Would require full markdown parsing +- **Email links** (`mailto:user@example.com`) - Cannot be verified without sending email + +## GitHub Workflow Test + +This section provides a workflow example and instructions for testing the link verification action. + +### Testing the Workflow + +To test that the workflow properly detects broken links: + +1. Make change to this file (e.g., this README.md file already contains one in the [Broken Link Test](#broken-link-test) section) +1. The workflow will run and should fail, reporting the broken link(s) +1. Revert your change to this file +1. Push again to verify the workflow passes + +### Example Workflow Configuration + +```yaml +name: Verify Links + +on: + push: + branches: [ main ] + paths: + - '**/*.md' + pull_request: + branches: [ main ] + paths: + - '**/*.md' + schedule: + # Run weekly to catch external link rot + - cron: '0 0 * * 0' + +jobs: + verify-links: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Verify CHANGELOG Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './CHANGELOG' + fail-on-error: 'true' + + - name: Verify Documentation Links + uses: ./.github/actions/infrastructure/markdownlinks + with: + path: './docs' + fail-on-error: 'false' + exclude-patterns: '*.internal.example.com/*' +``` + +## How It Works + +1. **Parse Markdown**: Uses `Parse-MarkdownLink.ps1` to extract all links from markdown files using Markdig +2. **Deduplicate**: Groups links by URL to avoid checking the same link multiple times +3. **Verify Links**: + - HTTP/HTTPS links: Makes HEAD/GET requests with configurable timeout and retries + - Local file references: Checks if the file exists relative to the markdown file + - Excluded patterns: Skips links matching the exclude patterns +4. **Report Results**: Displays detailed results with file locations for failed links +5. **Set Outputs**: Provides metrics for downstream steps + +## Error Output Example + +``` +✗ FAILED: https://example.com/broken-link - HTTP 404 + Found in: /path/to/file.md:42:15 + Found in: /path/to/other.md:100:20 + +Link Verification Summary +============================================================ +Total URLs checked: 150 +Passed: 145 +Failed: 2 +Skipped: 3 + +Failed Links: + • https://example.com/broken-link + Error: HTTP 404 + Occurrences: 2 +``` + +## Requirements + +- PowerShell 7+ (includes Markdig) +- Runs on: `ubuntu-latest`, `windows-latest`, `macos-latest` + +## Broken Link Test + +- [Broken Link](https://github.com/PowerShell/PowerShell/wiki/NonExistentPage404) + +## License + +Same as the PowerShell repository. diff --git a/.github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 b/.github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 new file mode 100644 index 00000000000..f50ab1590b9 --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/Verify-MarkdownLinks.ps1 @@ -0,0 +1,317 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +#Requires -Version 7.0 + +<# +.SYNOPSIS + Verify all links in markdown files. + +.DESCRIPTION + This script parses markdown files to extract links and verifies their accessibility. + It supports HTTP/HTTPS links and local file references. + +.PARAMETER Path + Path to the directory containing markdown files. Defaults to current directory. + +.PARAMETER File + Array of specific markdown files to verify. If provided, Path parameter is ignored. + +.PARAMETER TimeoutSec + Timeout in seconds for HTTP requests. Defaults to 30. + +.PARAMETER MaximumRetryCount + Maximum number of retries for failed requests. Defaults to 2. + +.PARAMETER RetryIntervalSec + Interval in seconds between retry attempts. Defaults to 2. + +.EXAMPLE + .\Verify-MarkdownLinks.ps1 -Path ./CHANGELOG + +.EXAMPLE + .\Verify-MarkdownLinks.ps1 -Path ./docs -FailOnError + +.EXAMPLE + .\Verify-MarkdownLinks.ps1 -File @('CHANGELOG/7.5.md', 'README.md') +#> + +param( + [Parameter(ParameterSetName = 'ByPath', Mandatory)] + [string]$Path = "Q:\src\git\powershell\docs\git", + [Parameter(ParameterSetName = 'ByFile', Mandatory)] + [string[]]$File = @(), + [int]$TimeoutSec = 30, + [int]$MaximumRetryCount = 2, + [int]$RetryIntervalSec = 2 +) + +$ErrorActionPreference = 'Stop' + +# Get the script directory +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path + +# Determine what to process: specific files or directory +if ($File.Count -gt 0) { + Write-Host "Extracting links from $($File.Count) specified markdown file(s)" -ForegroundColor Cyan + + # Process each file individually + $allLinks = @() + $parseScriptPath = Join-Path $scriptDir "Parse-MarkdownLink.ps1" + + foreach ($filePath in $File) { + if (Test-Path $filePath) { + Write-Verbose "Processing: $filePath" + $fileLinks = & $parseScriptPath -ChangelogPath $filePath + $allLinks += $fileLinks + } + else { + Write-Warning "File not found: $filePath" + } + } +} +else { + Write-Host "Extracting links from markdown files in: $Path" -ForegroundColor Cyan + + # Get all links from markdown files using the Parse-ChangelogLinks script + $parseScriptPath = Join-Path $scriptDir "Parse-MarkdownLink.ps1" + $allLinks = & $parseScriptPath -ChangelogPath $Path +} + +if ($allLinks.Count -eq 0) { + Write-Host "No links found in markdown files." -ForegroundColor Yellow + exit 0 +} + +Write-Host "Found $($allLinks.Count) links to verify" -ForegroundColor Green + +# Group links by URL to avoid duplicate checks +$uniqueLinks = $allLinks | Group-Object -Property Url + +Write-Host "Unique URLs to verify: $($uniqueLinks.Count)" -ForegroundColor Cyan + +$results = @{ + Total = $uniqueLinks.Count + Passed = 0 + Failed = 0 + Skipped = 0 + Errors = [System.Collections.ArrayList]::new() +} + +function Test-HttpLink { + param( + [string]$Url + ) + + try { + # Try HEAD request first (faster, doesn't download content) + $response = Invoke-WebRequest -Uri $Url ` + -Method Head ` + -TimeoutSec $TimeoutSec ` + -MaximumRetryCount $MaximumRetryCount ` + -RetryIntervalSec $RetryIntervalSec ` + -UserAgent "Mozilla/5.0 (compatible; GitHubActions/1.0; +https://github.com/PowerShell/PowerShell)" ` + -SkipHttpErrorCheck + + # If HEAD fails with 404 or 405, retry with GET (some servers don't support HEAD) + if ($response.StatusCode -eq 404 -or $response.StatusCode -eq 405) { + Write-Verbose "HEAD request failed with $($response.StatusCode), retrying with GET for: $Url" + $response = Invoke-WebRequest -Uri $Url ` + -Method Get ` + -TimeoutSec $TimeoutSec ` + -MaximumRetryCount $MaximumRetryCount ` + -RetryIntervalSec $RetryIntervalSec ` + -UserAgent "Mozilla/5.0 (compatible; GitHubActions/1.0; +https://github.com)" ` + -SkipHttpErrorCheck + } + + if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 400) { + return @{ Success = $true; StatusCode = $response.StatusCode } + } + else { + return @{ Success = $false; StatusCode = $response.StatusCode; Error = "HTTP $($response.StatusCode)" } + } + } + catch { + return @{ Success = $false; StatusCode = 0; Error = $_.Exception.Message } + } +} + +function Test-LocalLink { + param( + [string]$Url, + [string]$BasePath + ) + + # Strip query parameters (e.g., ?sanitize=true) and anchors (e.g., #section) + $cleanUrl = $Url -replace '\?.*$', '' -replace '#.*$', '' + + # Handle relative paths + $targetPath = Join-Path $BasePath $cleanUrl + + if (Test-Path $targetPath) { + return @{ Success = $true } + } + else { + return @{ Success = $false; Error = "File not found: $targetPath" } + } +} + +# Verify each unique link +$progressCount = 0 +foreach ($linkGroup in $uniqueLinks) { + $progressCount++ + $url = $linkGroup.Name + $occurrences = $linkGroup.Group + Write-Verbose -Verbose "[$progressCount/$($uniqueLinks.Count)] Checking: $url" + + # Determine link type and verify + $verifyResult = $null + if ($url -match '^https?://') { + $verifyResult = Test-HttpLink -Url $url + } + elseif ($url -match '^#') { + Write-Verbose -Verbose "Skipping anchor link: $url" + $results.Skipped++ + continue + } + elseif ($url -match '^mailto:') { + Write-Verbose -Verbose "Skipping mailto link: $url" + $results.Skipped++ + continue + } + else { + $basePath = Split-Path -Parent $occurrences[0].Path + $verifyResult = Test-LocalLink -Url $url -BasePath $basePath + } + if ($verifyResult.Success) { + Write-Host "✓ OK: $url" -ForegroundColor Green + $results.Passed++ + } + else { + $errorMsg = if ($verifyResult.StatusCode) { + "HTTP $($verifyResult.StatusCode)" + } + else { + $verifyResult.Error + } + + # Determine if this status code should be ignored or treated as failure + # Ignore: 401 (Unauthorized), 403 (Forbidden), 429 (Too Many Requests - already retried) + # Fail: 404 (Not Found), 410 (Gone), 406 (Not Acceptable) - these indicate broken links + $shouldIgnore = $false + $ignoreReason = "" + + switch ($verifyResult.StatusCode) { + 401 { + $shouldIgnore = $true + $ignoreReason = "authentication required" + } + 403 { + $shouldIgnore = $true + $ignoreReason = "access forbidden" + } + 429 { + $shouldIgnore = $true + $ignoreReason = "rate limited (already retried)" + } + } + + if ($shouldIgnore) { + Write-Host "⊘ IGNORED: $url - $errorMsg ($ignoreReason)" -ForegroundColor Yellow + Write-Verbose -Verbose "Ignored error details for $url - Status: $($verifyResult.StatusCode) - $ignoreReason" + foreach ($occurrence in $occurrences) { + Write-Verbose -Verbose " Found in: $($occurrence.Path):$($occurrence.Line):$($occurrence.Column)" + } + $results.Skipped++ + } + else { + Write-Host "✗ FAILED: $url - $errorMsg" -ForegroundColor Red + foreach ($occurrence in $occurrences) { + Write-Host " Found in: $($occurrence.Path):$($occurrence.Line):$($occurrence.Column)" -ForegroundColor DarkGray + } + $results.Failed++ + [void]$results.Errors.Add(@{ + Url = $url + Error = $errorMsg + Occurrences = $occurrences + }) + } + } + } + +# Print summary +Write-Host "`n" + ("=" * 60) -ForegroundColor Cyan +Write-Host "Link Verification Summary" -ForegroundColor Cyan +Write-Host ("=" * 60) -ForegroundColor Cyan +Write-Host "Total URLs checked: $($results.Total)" -ForegroundColor White +Write-Host "Passed: $($results.Passed)" -ForegroundColor Green +Write-Host "Failed: $($results.Failed)" -ForegroundColor $(if ($results.Failed -gt 0) { "Red" } else { "Green" }) +Write-Host "Skipped: $($results.Skipped)" -ForegroundColor Gray + +if ($results.Failed -gt 0) { + Write-Host "`nFailed Links:" -ForegroundColor Red + foreach ($failedLink in $results.Errors) { + Write-Host " • $($failedLink.Url)" -ForegroundColor Red + Write-Host " Error: $($failedLink.Error)" -ForegroundColor DarkGray + Write-Host " Occurrences: $($failedLink.Occurrences.Count)" -ForegroundColor DarkGray + } + + Write-Host "`n❌ Link verification failed!" -ForegroundColor Red + exit 1 +} +else { + Write-Host "`n✅ All links verified successfully!" -ForegroundColor Green +} + +# Write to GitHub Actions step summary if running in a workflow +if ($env:GITHUB_STEP_SUMMARY) { + $summaryContent = @" + +# Markdown Link Verification Results + +## Summary +- **Total URLs checked:** $($results.Total) +- **Passed:** ✅ $($results.Passed) +- **Failed:** $(if ($results.Failed -gt 0) { "❌" } else { "✅" }) $($results.Failed) +- **Skipped:** $($results.Skipped) + +"@ + + if ($results.Failed -gt 0) { + $summaryContent += @" + +## Failed Links + +| URL | Error | Occurrences | +|-----|-------|-------------| + +"@ + foreach ($failedLink in $results.Errors) { + $summaryContent += "| $($failedLink.Url) | $($failedLink.Error) | $($failedLink.Occurrences.Count) |`n" + } + + $summaryContent += @" + +
+Click to see all failed link locations + +"@ + foreach ($failedLink in $results.Errors) { + $summaryContent += "`n### $($failedLink.Url)`n" + $summaryContent += "**Error:** $($failedLink.Error)`n`n" + foreach ($occurrence in $failedLink.Occurrences) { + $summaryContent += "- `$($occurrence.Path):$($occurrence.Line):$($occurrence.Column)`n" + } + } + $summaryContent += "`n
`n" + } + else { + $summaryContent += "`n## ✅ All links verified successfully!`n" + } + + Write-Verbose -Verbose "Writing `n $summaryContent `n to ${env:GITHUB_STEP_SUMMARY}" + $summaryContent | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append + Write-Verbose -Verbose "Summary written to GitHub Actions step summary" +} + diff --git a/.github/actions/infrastructure/markdownlinks/action.yml b/.github/actions/infrastructure/markdownlinks/action.yml new file mode 100644 index 00000000000..1d6d0864784 --- /dev/null +++ b/.github/actions/infrastructure/markdownlinks/action.yml @@ -0,0 +1,139 @@ +name: 'Verify Markdown Links' +description: 'Verify all links in markdown files using PowerShell and Markdig' +author: 'PowerShell Team' + +inputs: + timeout-sec: + description: 'Timeout in seconds for HTTP requests' + required: false + default: '30' + maximum-retry-count: + description: 'Maximum number of retries for failed requests' + required: false + default: '2' + +outputs: + total-links: + description: 'Total number of unique links checked' + value: ${{ steps.verify.outputs.total }} + passed-links: + description: 'Number of links that passed verification' + value: ${{ steps.verify.outputs.passed }} + failed-links: + description: 'Number of links that failed verification' + value: ${{ steps.verify.outputs.failed }} + skipped-links: + description: 'Number of links that were skipped' + value: ${{ steps.verify.outputs.skipped }} + +runs: + using: 'composite' + steps: + - name: Get changed markdown files + id: changed-files + uses: actions/github-script@v7 + with: + script: | + let changedMarkdownFiles = []; + + if (context.eventName === 'pull_request') { + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + }); + + changedMarkdownFiles = files + .filter(file => file.filename.endsWith('.md')) + .map(file => file.filename); + } else if (context.eventName === 'push') { + const { data: comparison } = await github.rest.repos.compareCommits({ + owner: context.repo.owner, + repo: context.repo.repo, + base: context.payload.before, + head: context.payload.after, + }); + + changedMarkdownFiles = comparison.files + .filter(file => file.filename.endsWith('.md')) + .map(file => file.filename); + } else { + core.setFailed(`Unsupported event type: ${context.eventName}. This action only supports 'pull_request' and 'push' events.`); + return; + } + + console.log('Changed markdown files:', changedMarkdownFiles); + core.setOutput('files', JSON.stringify(changedMarkdownFiles)); + core.setOutput('count', changedMarkdownFiles.length); + return changedMarkdownFiles; + + - name: Verify markdown links + id: verify + shell: pwsh + run: | + Write-Host "Starting markdown link verification..." -ForegroundColor Cyan + + # Get changed markdown files from previous step + $changedFilesJson = '${{ steps.changed-files.outputs.files }}' + $changedFiles = $changedFilesJson | ConvertFrom-Json + + if ($changedFiles.Count -eq 0) { + Write-Host "No markdown files changed, skipping verification" -ForegroundColor Yellow + "total=0" >> $env:GITHUB_OUTPUT + "passed=0" >> $env:GITHUB_OUTPUT + "failed=0" >> $env:GITHUB_OUTPUT + "skipped=0" >> $env:GITHUB_OUTPUT + exit 0 + } + + Write-Host "Changed markdown files: $($changedFiles.Count)" -ForegroundColor Cyan + $changedFiles | ForEach-Object { Write-Host " - $_" -ForegroundColor Gray } + + # Build parameters for each file + $params = @{ + File = $changedFiles + TimeoutSec = [int]'${{ inputs.timeout-sec }}' + MaximumRetryCount = [int]'${{ inputs.maximum-retry-count }}' + } + + # Run the verification script + $scriptPath = Join-Path '${{ github.action_path }}' 'Verify-MarkdownLinks.ps1' + + # Capture output and parse results + $output = & $scriptPath @params 2>&1 | Tee-Object -Variable capturedOutput + + # Try to extract metrics from output + $totalLinks = 0 + $passedLinks = 0 + $failedLinks = 0 + $skippedLinks = 0 + + foreach ($line in $capturedOutput) { + if ($line -match 'Total URLs checked: (\d+)') { + $totalLinks = $Matches[1] + } + elseif ($line -match 'Passed: (\d+)') { + $passedLinks = $Matches[1] + } + elseif ($line -match 'Failed: (\d+)') { + $failedLinks = $Matches[1] + } + elseif ($line -match 'Skipped: (\d+)') { + $skippedLinks = $Matches[1] + } + } + + # Set outputs + "total=$totalLinks" >> $env:GITHUB_OUTPUT + "passed=$passedLinks" >> $env:GITHUB_OUTPUT + "failed=$failedLinks" >> $env:GITHUB_OUTPUT + "skipped=$skippedLinks" >> $env:GITHUB_OUTPUT + + Write-Host "Action completed" -ForegroundColor Cyan + + # Exit with the same code as the verification script + exit $LASTEXITCODE + +branding: + icon: 'link' + color: 'blue' diff --git a/.github/instructions/powershell-parameter-naming.instructions.md b/.github/instructions/powershell-parameter-naming.instructions.md new file mode 100644 index 00000000000..155fd1a85c3 --- /dev/null +++ b/.github/instructions/powershell-parameter-naming.instructions.md @@ -0,0 +1,69 @@ +--- +applyTo: '**/*.ps1, **/*.psm1' +description: Naming conventions for PowerShell parameters +--- + +# PowerShell Parameter Naming Conventions + +## Purpose + +This instruction defines the naming conventions for parameters in PowerShell scripts and modules. Consistent parameter naming improves code readability, maintainability, and usability for users of PowerShell cmdlets and functions. + +## Parameter Naming Rules + +### General Conventions +- **Singular Nouns**: Use singular nouns for parameter names even if the parameter is expected to handle multiple values (e.g., `File` instead of `Files`). +- **Use PascalCase**: Parameter names must use PascalCase (e.g., `ParameterName`). +- **Descriptive Names**: Parameter names should be descriptive and convey their purpose clearly (e.g., `FilePath`, `UserName`). +- **Avoid Abbreviations**: Avoid using abbreviations unless they are widely recognized (e.g., `ID` for Identifier). +- **Avoid Reserved Words**: Do not use PowerShell reserved words as parameter names (e.g., `if`, `else`, `function`). + +### Units and Precision +- **Include Units in Parameter Names**: When a parameter represents a value with units, include the unit in the parameter name for clarity: + - `TimeoutSec` instead of `Timeout` + - `RetryIntervalSec` instead of `RetryInterval` + - `MaxSizeBytes` instead of `MaxSize` +- **Use Full Words for Clarity**: Spell out common terms to match PowerShell conventions: + - `MaximumRetryCount` instead of `MaxRetries` + - `MinimumLength` instead of `MinLength` + +### Alignment with Built-in Cmdlets +- **Follow Existing PowerShell Conventions**: When your parameter serves a similar purpose to a built-in cmdlet parameter, use the same or similar naming: + - Match `Invoke-WebRequest` parameters when making HTTP requests: `TimeoutSec`, `MaximumRetryCount`, `RetryIntervalSec` + - Follow common parameter patterns like `Path`, `Force`, `Recurse`, `WhatIf`, `Confirm` +- **Consistency Within Scripts**: If multiple parameters relate to the same concept, use consistent naming patterns (e.g., `TimeoutSec`, `RetryIntervalSec` both use `Sec` suffix). + +## Examples + +### Good Parameter Names +```powershell +param( + [string[]]$File, # Singular, even though it accepts arrays + [int]$TimeoutSec = 30, # Unit included + [int]$MaximumRetryCount = 2, # Full word "Maximum" + [int]$RetryIntervalSec = 2, # Consistent with TimeoutSec + [string]$Path, # Standard PowerShell convention + [switch]$Force # Common PowerShell parameter +) +``` + +### Names to Avoid +```powershell +param( + [string[]]$Files, # Should be singular: File + [int]$Timeout = 30, # Missing unit: TimeoutSec + [int]$MaxRetries = 2, # Should be: MaximumRetryCount + [int]$RetryInterval = 2, # Missing unit: RetryIntervalSec + [string]$FileLoc, # Avoid abbreviations: FilePath + [int]$Max # Ambiguous: MaximumWhat? +) +``` + +## Exceptions +- **Common Terms**: Some common terms may be used in plural form if they are widely accepted in the context (e.g., `Credentials`, `Permissions`). +- **Legacy Code**: Existing code that does not follow these conventions may be exempted to avoid breaking changes, but new code should adhere to these guidelines. +- **Well Established Naming Patterns**: If a naming pattern is well established in the PowerShell community, it may be used even if it does not strictly adhere to these guidelines. + +## References +- [PowerShell Cmdlet Design Guidelines](https://learn.microsoft.com/powershell/scripting/developer/cmdlet/strongly-encouraged-development-guidelines) +- [About Parameters - PowerShell Documentation](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_parameters) diff --git a/.github/workflows/verify-markdown-links.yml b/.github/workflows/verify-markdown-links.yml new file mode 100644 index 00000000000..713160dea21 --- /dev/null +++ b/.github/workflows/verify-markdown-links.yml @@ -0,0 +1,32 @@ +name: Verify Markdown Links + +on: + push: + branches: [ main, master, release/v7.6 ] + paths: + - '**/*.md' + - '.github/workflows/verify-markdown-links.yml' + - '.github/actions/infrastructure/markdownlinks/**' + pull_request: + branches: [ main, master, release/v7.6 ] + paths: + - '**/*.md' + schedule: + # Run weekly on Sundays at midnight UTC to catch external link rot + - cron: '0 0 * * 0' + workflow_dispatch: + +jobs: + verify-markdown-links: + name: Verify Markdown Links + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Verify markdown links + id: verify + uses: ./.github/actions/infrastructure/markdownlinks + with: + timeout-sec: 30 + maximum-retry-count: 2 From 38b8e5425b9ace4e1312f45b7f6073a25ac838ab Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 13 Nov 2025 14:16:40 -0800 Subject: [PATCH 003/127] [release/v7.6] Update PSReadLine to v2.4.5 (#26446) Co-authored-by: Dongbo Wang --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 327c293e72c..6cec561a07a 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -15,7 +15,7 @@ - + From 5b45b835ece5943b31297c3b35b5feebc33b2641 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 13 Nov 2025 14:55:36 -0800 Subject: [PATCH 004/127] [release/v7.6] Update PSResourceGet package version to preview4 (#26438) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 6cec561a07a..d2a49e26d2a 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + From 168482463dc5bd26e1e938b137c67bedfc4b432a Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 13 Nov 2025 15:02:24 -0800 Subject: [PATCH 005/127] [release/v7.6] DSC v3 resource for Powershell Profile (#26447) Co-authored-by: Aditya Patwardhan --- .github/actions/test/nix/action.yml | 42 ++++ .github/actions/test/windows/action.yml | 20 ++ dsc/pwsh.profile.dsc.resource.json | 126 +++++++++++ dsc/pwsh.profile.resource.ps1 | 179 +++++++++++++++ experimental-feature-linux.json | 1 + experimental-feature-windows.json | 1 + .../ExperimentalFeature.cs | 5 + src/powershell-unix/powershell-unix.csproj | 4 + .../powershell-win-core.csproj | 4 + .../dsc/dsc.profileresource.Tests.ps1 | 204 ++++++++++++++++++ .../dsc/psprofile_alluser_allhost.dsc.yaml | 9 + .../psprofile_allusers_currenthost.dsc.yaml | 9 + .../psprofile_currentuser_allhosts.dsc.yaml | 9 + ...psprofile_currentuser_currenthost.dsc.yaml | 9 + ..._currentuser_currenthost_emptycontent.yaml | 9 + test/powershell/dsc/psprofile_export.dsc.yaml | 5 + tools/packaging/boms/linux.json | 10 + tools/packaging/boms/mac.json | 10 + tools/packaging/boms/windows.json | 10 + 19 files changed, 666 insertions(+) create mode 100644 dsc/pwsh.profile.dsc.resource.json create mode 100644 dsc/pwsh.profile.resource.ps1 create mode 100644 test/powershell/dsc/dsc.profileresource.Tests.ps1 create mode 100644 test/powershell/dsc/psprofile_alluser_allhost.dsc.yaml create mode 100644 test/powershell/dsc/psprofile_allusers_currenthost.dsc.yaml create mode 100644 test/powershell/dsc/psprofile_currentuser_allhosts.dsc.yaml create mode 100644 test/powershell/dsc/psprofile_currentuser_currenthost.dsc.yaml create mode 100644 test/powershell/dsc/psprofile_currentuser_currenthost_emptycontent.yaml create mode 100644 test/powershell/dsc/psprofile_export.dsc.yaml diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index b338c398340..89c11d59ccc 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -45,6 +45,48 @@ runs: with: global-json-file: ./global.json + - name: Set Package Name by Platform + id: set_package_name + shell: pwsh + run: |- + Import-Module ./.github/workflows/GHWorkflowHelper/GHWorkflowHelper.psm1 + $platform = $env:RUNNER_OS + Write-Host "Runner platform: $platform" + if ($platform -eq 'Linux') { + $packageName = 'DSC-*-x86_64-linux.tar.gz' + } elseif ($platform -eq 'macOS') { + $packageName = 'DSC-*-x86_64-apple-darwin.tar.gz' + } else { + throw "Unsupported platform: $platform" + } + + Set-GWVariable -Name "DSC_PACKAGE_NAME" -Value $packageName + + - name: Get Latest DSC Package Version + shell: pwsh + run: |- + Import-Module ./.github/workflows/GHWorkflowHelper/GHWorkflowHelper.psm1 + $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" + $latestRelease = $releases | Where-Object { $v = $_.name.trim("v"); $semVer = [System.Management.Automation.SemanticVersion]::new($v); if ($semVer.Major -eq 3 -and $semVer.Minor -ge 2) { $_ } } | Select-Object -First 1 + $latestVersion = $latestRelease.tag_name.TrimStart("v") + Write-Host "Latest DSC Version: $latestVersion" + + $packageName = "$env:DSC_PACKAGE_NAME" + + Write-Host "Package Name: $packageName" + + $downloadUrl = $latestRelease.assets | Where-Object { $_.name -like "*$packageName*" } | Select-Object -First 1 | Select-Object -ExpandProperty browser_download_url + Write-Host "Download URL: $downloadUrl" + + $tempPath = Get-GWTempPath + + Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath/DSC.tar.gz" -Verbose + New-Item -ItemType Directory -Path "$tempPath/DSC" -Force -Verbose + tar xvf "$tempPath/DSC.tar.gz" -C "$tempPath/DSC" + $dscRoot = "$tempPath/DSC" + Write-Host "DSC Root: $dscRoot" + Set-GWVariable -Name "DSC_ROOT" -Value $dscRoot + - name: Bootstrap shell: pwsh run: |- diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index 734e30208f0..1b2f6c56a6d 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -45,6 +45,26 @@ runs: with: global-json-file: .\global.json + - name: Get Latest DSC Package Version + shell: pwsh + run: |- + Import-Module .\.github\workflows\GHWorkflowHelper\GHWorkflowHelper.psm1 + $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" + $latestRelease = $releases | Where-Object { $v = $_.name.trim("v"); $semVer = [System.Management.Automation.SemanticVersion]::new($v); if ($semVer.Major -eq 3 -and $semVer.Minor -ge 2) { $_ } } | Select-Object -First 1 + $latestVersion = $latestRelease.tag_name.TrimStart("v") + Write-Host "Latest DSC Version: $latestVersion" + + $downloadUrl = $latestRelease.assets | Where-Object { $_.name -like "DSC-*-x86_64-pc-windows-msvc.zip" } | Select-Object -First 1 | Select-Object -ExpandProperty browser_download_url + Write-Host "Download URL: $downloadUrl" + $tempPath = Get-GWTempPath + Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath\DSC.zip" + + $null = New-Item -ItemType Directory -Path "$tempPath\DSC" -Force + Expand-Archive -Path "$tempPath\DSC.zip" -DestinationPath "$tempPath\DSC" -Force + $dscRoot = "$tempPath\DSC" + Write-Host "DSC Root: $dscRoot" + Set-GWVariable -Name "DSC_ROOT" -Value $dscRoot + - name: Bootstrap shell: powershell run: |- diff --git a/dsc/pwsh.profile.dsc.resource.json b/dsc/pwsh.profile.dsc.resource.json new file mode 100644 index 00000000000..cd18e94eec6 --- /dev/null +++ b/dsc/pwsh.profile.dsc.resource.json @@ -0,0 +1,126 @@ +{ + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "description": "Manage PowerShell profiles.", + "tags": [ + "Linux", + "Windows", + "macOS", + "PowerShell" + ], + "type": "Microsoft.PowerShell/Profile", + "version": "0.1.0", + "get": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "./pwsh.profile.resource.ps1", + "-operation", + "get" + ], + "input": "stdin" + }, + "set": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "./pwsh.profile.resource.ps1", + "-operation", + "set" + ], + "input": "stdin" + }, + "export": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + "./pwsh.profile.resource.ps1", + "-operation", + "export" + ], + "input": "stdin" + }, + "exitCodes": { + "0": "Success", + "1": "Error", + "2": "Input not supported for export operation" + }, + "schema": { + "embedded": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Profile", + "description": "Manage PowerShell profiles.", + "type": "object", + "unevaluatedProperties": false, + "required": [ + "profileType" + ], + "properties": { + "profileType": { + "type": "string", + "title": "Profile Type", + "description": "Defines which profile to manage. Valid values are: 'AllUsersCurrentHost', 'AllUsersAllHosts', 'CurrentUserAllHosts', and 'CurrentUserCurrentHost'.", + "enum": [ + "AllUsersCurrentHost", + "AllUsersAllHosts", + "CurrentUserAllHosts", + "CurrentUserCurrentHost" + ] + }, + "profilePath": { + "title": "Profile Path", + "description": "The full path to the profile file.", + "type": "string", + "readOnly": true + }, + "content": { + "title": "Content", + "description": "Defines the content of the profile. If you don't specify this property, the resource doesn't manage the file contents. If you specify this property as an empty string, the resource removes all content from the file. If you specify this property as a non-empty string, the resource sets the file contents to the specified string. The resources retains newlines from this property without any modification.", + "type": "string" + }, + "_exist": { + "$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json" + }, + "_name": { + "$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/name.json" + } + }, + "$defs": { + "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json", + "title": "Instance should exist", + "description": "Indicates whether the DSC resource instance should exist.", + "type": "boolean", + "default": true, + "enum": [ + false, + true + ] + }, + "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/name.json": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/name.json", + "title": "Exported instance name", + "description": "Returns a generated name for the resource instance from an export operation.", + "readOnly": true, + "type": "string" + } + } + } + } +} diff --git a/dsc/pwsh.profile.resource.ps1 b/dsc/pwsh.profile.resource.ps1 new file mode 100644 index 00000000000..ad9cfa4a63a --- /dev/null +++ b/dsc/pwsh.profile.resource.ps1 @@ -0,0 +1,179 @@ +## Copyright (c) Microsoft Corporation. All rights reserved. +## Licensed under the MIT License. + +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)] + [ValidateSet('get', 'set', 'export')] + [string]$Operation, + [Parameter(ValueFromPipeline)] + [string[]]$UserInput +) + +Begin { + enum ProfileType { + AllUsersCurrentHost + AllUsersAllHosts + CurrentUserAllHosts + CurrentUserCurrentHost + } + + function New-PwshResource { + param( + [Parameter(Mandatory = $true)] + [ProfileType] $ProfileType, + + [Parameter(ParameterSetName = 'WithContent')] + [string] $Content, + + [Parameter(ParameterSetName = 'WithContent')] + [bool] $Exist + ) + + # Create the PSCustomObject with properties + $resource = [PSCustomObject]@{ + profileType = $ProfileType + content = $null + profilePath = GetProfilePath -profileType $ProfileType + _exist = $false + } + + # Add ToJson method + $resource | Add-Member -MemberType ScriptMethod -Name 'ToJson' -Value { + return ([ordered] @{ + profileType = $this.profileType + content = $this.content + profilePath = $this.profilePath + _exist = $this._exist + }) | ConvertTo-Json -Compress -EnumsAsStrings + } + + # Constructor logic - if Content and Exist parameters are provided (WithContent parameter set) + if ($PSCmdlet.ParameterSetName -eq 'WithContent') { + $resource.content = $Content + $resource._exist = $Exist + } else { + # Default constructor logic - read from file system + $fileExists = Test-Path $resource.profilePath + if ($fileExists) { + $resource.content = Get-Content -Path $resource.profilePath + } else { + $resource.content = $null + } + $resource._exist = $fileExists + } + + return $resource + } + + function GetProfilePath { + param ( + [ProfileType] $profileType + ) + + $path = switch ($profileType) { + 'AllUsersCurrentHost' { $PROFILE.AllUsersCurrentHost } + 'AllUsersAllHosts' { $PROFILE.AllUsersAllHosts } + 'CurrentUserAllHosts' { $PROFILE.CurrentUserAllHosts } + 'CurrentUserCurrentHost' { $PROFILE.CurrentUserCurrentHost } + } + + return $path + } + + function ExportOperation { + $allUserCurrentHost = New-PwshResource -ProfileType 'AllUsersCurrentHost' + $allUsersAllHost = New-PwshResource -ProfileType 'AllUsersAllHosts' + $currentUserAllHost = New-PwshResource -ProfileType 'CurrentUserAllHosts' + $currentUserCurrentHost = New-PwshResource -ProfileType 'CurrentUserCurrentHost' + + # Cannot use the ToJson() method here as we are adding a note property + $allUserCurrentHost | Add-Member -NotePropertyName '_name' -NotePropertyValue 'AllUsersCurrentHost' -PassThru | ConvertTo-Json -Compress -EnumsAsStrings + $allUsersAllHost | Add-Member -NotePropertyName '_name' -NotePropertyValue 'AllUsersAllHosts' -PassThru | ConvertTo-Json -Compress -EnumsAsStrings + $currentUserAllHost | Add-Member -NotePropertyName '_name' -NotePropertyValue 'CurrentUserAllHosts' -PassThru | ConvertTo-Json -Compress -EnumsAsStrings + $currentUserCurrentHost | Add-Member -NotePropertyName '_name' -NotePropertyValue 'CurrentUserCurrentHost' -PassThru | ConvertTo-Json -Compress -EnumsAsStrings + } + + function GetOperation { + param ( + [Parameter(Mandatory = $true)] + $InputResource, + [Parameter()] + [switch] $AsJson + ) + + $profilePath = GetProfilePath -profileType $InputResource.profileType.ToString() + + $actualState = New-PwshResource -ProfileType $InputResource.profileType + + $actualState.profilePath = $profilePath + + $exists = Test-Path $profilePath + + if ($InputResource._exist -and $exists) { + $content = Get-Content -Path $profilePath + $actualState.Content = $content + } elseif ($InputResource._exist -and -not $exists) { + $actualState.Content = $null + $actualState._exist = $false + } elseif (-not $InputResource._exist -and $exists) { + $actualState.Content = Get-Content -Path $profilePath + $actualState._exist = $true + } else { + $actualState.Content = $null + $actualState._exist = $false + } + + if ($AsJson) { + return $actualState.ToJson() + } else { + return $actualState + } + } + + function SetOperation { + param ( + $InputResource + ) + + $actualState = GetOperation -InputResource $InputResource + + if ($InputResource._exist) { + if (-not $actualState._exist) { + $null = New-Item -Path $actualState.profilePath -ItemType File -Force + } + + if ($null -ne $InputResource.content) { + Set-Content -Path $actualState.profilePath -Value $InputResource.content + } + } elseif ($actualState._exist) { + Remove-Item -Path $actualState.profilePath -Force + } + } +} +End { + $inputJson = $input | ConvertFrom-Json + + if ($inputJson) { + $InputResource = New-PwshResource -ProfileType $inputJson.profileType -Content $inputJson.content -Exist $inputJson._exist + } + + switch ($Operation) { + 'get' { + GetOperation -InputResource $InputResource -AsJson + } + 'set' { + SetOperation -InputResource $InputResource + } + 'export' { + if ($inputJson) { + Write-Error "Input not supported for export operation" + exit 2 + } + + ExportOperation + } + } + + exit 0 +} diff --git a/experimental-feature-linux.json b/experimental-feature-linux.json index ca5b49878a4..31f7b965a5b 100644 --- a/experimental-feature-linux.json +++ b/experimental-feature-linux.json @@ -2,6 +2,7 @@ "PSFeedbackProvider", "PSLoadAssemblyFromNativeCode", "PSNativeWindowsTildeExpansion", + "PSProfileDSCResource", "PSSerializeJSONLongEnumAsNumber", "PSRedirectToVariable", "PSSubsystemPluginModel" diff --git a/experimental-feature-windows.json b/experimental-feature-windows.json index ca5b49878a4..31f7b965a5b 100644 --- a/experimental-feature-windows.json +++ b/experimental-feature-windows.json @@ -2,6 +2,7 @@ "PSFeedbackProvider", "PSLoadAssemblyFromNativeCode", "PSNativeWindowsTildeExpansion", + "PSProfileDSCResource", "PSSerializeJSONLongEnumAsNumber", "PSRedirectToVariable", "PSSubsystemPluginModel" diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs index dd26e609641..60d6b238065 100644 --- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs +++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs @@ -25,6 +25,7 @@ public class ExperimentalFeature internal const string PSNativeWindowsTildeExpansion = nameof(PSNativeWindowsTildeExpansion); internal const string PSRedirectToVariable = "PSRedirectToVariable"; internal const string PSSerializeJSONLongEnumAsNumber = nameof(PSSerializeJSONLongEnumAsNumber); + internal const string PSProfileDSCResource = "PSProfileDSCResource"; #endregion @@ -125,6 +126,10 @@ static ExperimentalFeature() new ExperimentalFeature( name: PSSerializeJSONLongEnumAsNumber, description: "Serialize enums based on long or ulong as an numeric value rather than the string representation when using ConvertTo-Json." + ), + new ExperimentalFeature( + name: PSProfileDSCResource, + description: "DSC v3 resources for managing PowerShell profile." ) }; diff --git a/src/powershell-unix/powershell-unix.csproj b/src/powershell-unix/powershell-unix.csproj index 802acf05e3a..20c61247d24 100644 --- a/src/powershell-unix/powershell-unix.csproj +++ b/src/powershell-unix/powershell-unix.csproj @@ -37,6 +37,10 @@ PreserveNewest PreserveNewest + + PreserveNewest + PreserveNewest + diff --git a/src/powershell-win-core/powershell-win-core.csproj b/src/powershell-win-core/powershell-win-core.csproj index 5368518dd3c..e6efeac10f0 100644 --- a/src/powershell-win-core/powershell-win-core.csproj +++ b/src/powershell-win-core/powershell-win-core.csproj @@ -29,6 +29,10 @@ PreserveNewest PreserveNewest + + PreserveNewest + PreserveNewest + PreserveNewest PreserveNewest diff --git a/test/powershell/dsc/dsc.profileresource.Tests.ps1 b/test/powershell/dsc/dsc.profileresource.Tests.ps1 new file mode 100644 index 00000000000..f361e67ea8e --- /dev/null +++ b/test/powershell/dsc/dsc.profileresource.Tests.ps1 @@ -0,0 +1,204 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { + BeforeAll { + $DSC_ROOT = $env:DSC_ROOT + + if (-not (Test-Path -Path $DSC_ROOT)) { + throw "DSC_ROOT environment variable is not set or path does not exist." + } + + Write-Verbose "DSC_ROOT is set to $DSC_ROOT" -Verbose + + $originalPath = $env:PATH + + $pathSeparator = [System.IO.Path]::PathSeparator + $env:PATH += "$pathSeparator$DSC_ROOT" + $env:PATH += "$pathSeparator$PSHome" + + Write-Verbose "Updated PATH to include DSC_ROOT: $env:PATH" -Verbose + + # Ensure DSC v3 is available + if (-not (Get-Command -name dsc -CommandType Application -ErrorAction SilentlyContinue)) { + Get-ChildItem $DSC_ROOT -Recurse 'dsc' | ForEach-Object { + Write-Verbose "Found DSC executable at $($_.FullName)" -Verbose + } + throw "DSC v3 is not installed" + } + + $dscExe = Get-Command -name dsc -CommandType Application | Select-Object -First 1 + + $testProfileContent = "# Test profile content currentuser currenthost" + $testProfilePathCurrentUserCurrentHost = $PROFILE.CurrentUserCurrentHost + Copy-Item -Path $testProfilePathCurrentUserCurrentHost -Destination "$TestDrive/currentuser-currenthost-profile.bak" -Force -ErrorAction SilentlyContinue + New-Item -Path $testProfilePathCurrentUserCurrentHost -Value $testProfileContent -Force -ItemType File + + $testProfileContent = "# Test profile content currentuser allhosts" + $testProfilePathCurrentUserAllHosts = $PROFILE.CurrentUserAllHosts + Copy-Item -Path $testProfilePathCurrentUserAllHosts -Destination "$TestDrive/currentuser-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue + New-Item -Path $testProfilePathCurrentUserAllHosts -Value $testProfileContent -Force -ItemType File + } + AfterAll { + # Restore original profile + $testProfilePathCurrentUserCurrentHost = $PROFILE.CurrentUserCurrentHost + if (Test-Path "$TestDrive/currentuser-currenthost-profile.bak") { + Copy-Item -Path "$TestDrive/currentuser-currenthost-profile.bak" -Destination $testProfilePathCurrentUserCurrentHost -Force -ErrorAction SilentlyContinue + } + else { + Remove-Item $testProfilePathCurrentUserCurrentHost -Force -ErrorAction SilentlyContinue + } + + $testProfilePathCurrentUserAllHosts = $PROFILE.CurrentUserAllHosts + if (Test-Path "$TestDrive/currentuser-allhosts-profile.bak") { + Copy-Item -Path "$TestDrive/currentuser-allhosts-profile.bak" -Destination $testProfilePathCurrentUserAllHosts -Force -ErrorAction SilentlyContinue + } + else { + Remove-Item $testProfilePathCurrentUserAllHosts -Force -ErrorAction SilentlyContinue + } + + $env:PATH = $originalPath + Remove-Item -Path "$TestDrive/currentuser-currenthost-profile.bak" -Force -ErrorAction SilentlyContinue + Remove-Item -Path "$TestDrive/currentuser-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue + } + + It 'DSC resource is located at $PSHome' { + $resourceFile = Join-Path -Path $PSHome -ChildPath 'pwsh.profile.resource.ps1' + $resourceFile | Should -Exist + + $resourceManifest = Join-Path -Path $PSHome -ChildPath 'pwsh.profile.dsc.resource.json' + $resourceManifest | Should -Exist + } + + It 'DSC resource can be found' { + (& $dscExe resource list -o json | ConvertFrom-Json | Select-Object -Property type).type | Should -Contain 'Microsoft.PowerShell/Profile' + } + + It 'DSC resource can set current user current host profile' { + $setOutput = (& $dscExe config set --file $PSScriptRoot/psprofile_currentuser_currenthost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - CurrentUserCurrentHost!'" + $setOutput.results.result.afterState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can get current user current host profile' { + $getOutput = (& $dscExe config get --file $PSScriptRoot/psprofile_currentuser_currenthost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - CurrentUserCurrentHost!'" + $getOutput.results.result.actualState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can set content as empty for current user current host profile' -Pending { + $setOutput = (& $dscExe config set --file $PSScriptRoot/psprofile_currentuser_currenthost_emptycontent.dsc.yaml -o json) | ConvertFrom-Json + $setOutput.results.result.afterState.content | Should -BeExactly '' + } + + It 'DSC resource can set current user all hosts profile' { + $setOutput = (& $dscExe config set --file $PSScriptRoot/psprofile_currentuser_allhosts.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - CurrentUserAllHosts!'" + $setOutput.results.result.afterState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can get current user all hosts profile' { + $getOutput = (& $dscExe config get --file $PSScriptRoot/psprofile_currentuser_allhosts.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - CurrentUserAllHosts!'" + $getOutput.results.result.actualState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can export all profiles' { + $exportOutput = (& $dscExe config export --file $PSScriptRoot/psprofile_export.dsc.yaml -o json) | ConvertFrom-Json + + $exportOutput.resources | Should -HaveCount 4 + + $exportOutput.resources | ForEach-Object { + $_.type | Should -Be 'Microsoft.PowerShell/Profile' + $_.name | Should -BeIn @('AllUsersCurrentHost', 'AllUsersAllHosts', 'CurrentUserCurrentHost', 'CurrentUserAllHosts') + } + } +} + +Describe "DSC PowerShell Profile resource elevated tests" -Tag "CI", 'RequireAdminOnWindows', 'RequireSudoOnUnix' { + BeforeAll { + $DSC_ROOT = $env:DSC_ROOT + + if (-not (Test-Path -Path $DSC_ROOT)) { + throw "DSC_ROOT environment variable is not set or path does not exist." + } + + Write-Verbose "DSC_ROOT is set to $DSC_ROOT" -Verbose + $pathSeparator = [System.IO.Path]::PathSeparator + + $env:PATH += "$pathSeparator$DSC_ROOT" + + $env:PATH += "$pathSeparator$PSHome" + + Write-Verbose "Updated PATH to include DSC_ROOT: $env:PATH" -Verbose + + # Ensure DSC v3 is available + if (-not (Get-Command -name dsc -CommandType Application -ErrorAction SilentlyContinue)) { + Get-ChildItem $DSC_ROOT -Recurse 'dsc' | ForEach-Object { + Write-Verbose "Found DSC executable at $($_.FullName)" -Verbose + } + throw "DSC v3 is not installed" + } + + $dscExe = Get-Command -name dsc -CommandType Application | Select-Object -First 1 + + $testProfileContent = "# Test profile content allusers currenthost" + $testProfilePathAllUsersCurrentHost = $PROFILE.AllUsersCurrentHost + Copy-Item -Path $testProfilePathAllUsersCurrentHost -Destination "$TestDrive/allusers-currenthost-profile.bak" -Force -ErrorAction SilentlyContinue + New-Item -Path $testProfilePathAllUsersCurrentHost -Value $testProfileContent -Force -ItemType File + + $testProfileContent = "# Test profile content allusers allhosts" + $testProfilePathAllUsersAllHosts = $PROFILE.AllUsersAllHosts + Copy-Item -Path $testProfilePathAllUsersAllHosts -Destination "$TestDrive/allusers-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue + New-Item -Path $testProfilePathAllUsersAllHosts -Value $testProfileContent -Force -ItemType File + + $originalPath = $env:PATH + $env:PATH += "$pathSeparator$PSHome" + } + AfterAll { + $env:PATH = $originalPath + + $testProfilePathAllUsersCurrentHost = $PROFILE.AllUsersCurrentHost + if (Test-Path "$TestDrive/allusers-currenthost-profile.bak") { + Copy-Item -Path "$TestDrive/allusers-currenthost-profile.bak" -Destination $testProfilePathAllUsersCurrentHost -Force -ErrorAction SilentlyContinue + } + else { + Remove-Item $testProfilePathAllUsersCurrentHost -Force -ErrorAction SilentlyContinue + } + + $testProfilePathAllUsersAllHosts = $PROFILE.AllUsersAllHosts + if (Test-Path "$TestDrive/allusers-allhosts-profile.bak") { + Copy-Item -Path "$TestDrive/allusers-allhosts-profile.bak" -Destination $testProfilePathAllUsersAllHosts -Force -ErrorAction SilentlyContinue + } + else { + Remove-Item $testProfilePathAllUsersAllHosts -Force -ErrorAction SilentlyContinue + } + + Remove-Item -Path "$TestDrive/currentuser-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue + Remove-Item -Path "$TestDrive/allusers-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue + } + + It 'DSC resource can set all users all hosts profile' { + $setOutput = (& $dscExe config set --file $PSScriptRoot/psprofile_alluser_allhost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - AllUsersAllHosts!'" + $setOutput.results.result.afterState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can get all users all hosts profile' { + $getOutput = (& $dscExe config get --file $PSScriptRoot/psprofile_alluser_allhost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - AllUsersAllHosts!'" + $getOutput.results.result.actualState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can set all users current hosts profile' { + $setOutput = (& $dscExe config set --file $PSScriptRoot/psprofile_allusers_currenthost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - AllUsersCurrentHost!'" + $setOutput.results.result.afterState.content | Should -BeExactly $expectedContent + } + + It 'DSC resource can get all users current hosts profile' { + $getOutput = (& $dscExe config get --file $PSScriptRoot/psprofile_allusers_currenthost.dsc.yaml -o json) | ConvertFrom-Json + $expectedContent = "Write-Host 'Welcome to your PowerShell profile - AllUsersCurrentHost!'" + $getOutput.results.result.actualState.content | Should -BeExactly $expectedContent + } +} diff --git a/test/powershell/dsc/psprofile_alluser_allhost.dsc.yaml b/test/powershell/dsc/psprofile_alluser_allhost.dsc.yaml new file mode 100644 index 00000000000..356119826c3 --- /dev/null +++ b/test/powershell/dsc/psprofile_alluser_allhost.dsc.yaml @@ -0,0 +1,9 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile + properties: + profileType: AllUsersAllHosts + content: "Write-Host 'Welcome to your PowerShell profile - AllUsersAllHosts!'" + _exist: true diff --git a/test/powershell/dsc/psprofile_allusers_currenthost.dsc.yaml b/test/powershell/dsc/psprofile_allusers_currenthost.dsc.yaml new file mode 100644 index 00000000000..bc51f0a4392 --- /dev/null +++ b/test/powershell/dsc/psprofile_allusers_currenthost.dsc.yaml @@ -0,0 +1,9 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile + properties: + profileType: AllUsersCurrentHost + content: "Write-Host 'Welcome to your PowerShell profile - AllUsersCurrentHost!'" + _exist: true diff --git a/test/powershell/dsc/psprofile_currentuser_allhosts.dsc.yaml b/test/powershell/dsc/psprofile_currentuser_allhosts.dsc.yaml new file mode 100644 index 00000000000..8ed8d98c3ab --- /dev/null +++ b/test/powershell/dsc/psprofile_currentuser_allhosts.dsc.yaml @@ -0,0 +1,9 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile + properties: + profileType: CurrentUserAllHosts + content: "Write-Host 'Welcome to your PowerShell profile - CurrentUserAllHosts!'" + _exist: true diff --git a/test/powershell/dsc/psprofile_currentuser_currenthost.dsc.yaml b/test/powershell/dsc/psprofile_currentuser_currenthost.dsc.yaml new file mode 100644 index 00000000000..5a42c28eb96 --- /dev/null +++ b/test/powershell/dsc/psprofile_currentuser_currenthost.dsc.yaml @@ -0,0 +1,9 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile + properties: + profileType: CurrentUserCurrentHost + content: "Write-Host 'Welcome to your PowerShell profile - CurrentUserCurrentHost!'" + _exist: true diff --git a/test/powershell/dsc/psprofile_currentuser_currenthost_emptycontent.yaml b/test/powershell/dsc/psprofile_currentuser_currenthost_emptycontent.yaml new file mode 100644 index 00000000000..76439387d2e --- /dev/null +++ b/test/powershell/dsc/psprofile_currentuser_currenthost_emptycontent.yaml @@ -0,0 +1,9 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile + properties: + profileType: CurrentUserCurrentHost + content: '' + _exist: true diff --git a/test/powershell/dsc/psprofile_export.dsc.yaml b/test/powershell/dsc/psprofile_export.dsc.yaml new file mode 100644 index 00000000000..cf7881b5df8 --- /dev/null +++ b/test/powershell/dsc/psprofile_export.dsc.yaml @@ -0,0 +1,5 @@ +# Set PowerShell profile content +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: +- name: PSProfile + type: Microsoft.PowerShell/Profile diff --git a/tools/packaging/boms/linux.json b/tools/packaging/boms/linux.json index 9f5f886a4ca..db29e47a290 100644 --- a/tools/packaging/boms/linux.json +++ b/tools/packaging/boms/linux.json @@ -2442,5 +2442,15 @@ { "Pattern": "System.Management.Automation.dll", "FileType": "Product" + }, + { + "Pattern": "pwsh.profile.dsc.resource.json", + "FileType": "Product", + "Architecture": null + }, + { + "Pattern": "pwsh.profile.resource.ps1", + "FileType": "Product", + "Architecture": null } ] diff --git a/tools/packaging/boms/mac.json b/tools/packaging/boms/mac.json index a4b5bc2bffb..af4fcb0c967 100644 --- a/tools/packaging/boms/mac.json +++ b/tools/packaging/boms/mac.json @@ -2218,5 +2218,15 @@ { "Pattern": "System.Management.Automation.dll", "FileType": "Product" + }, + { + "Pattern": "pwsh.profile.dsc.resource.json", + "FileType": "Product", + "Architecture": null + }, + { + "Pattern": "pwsh.profile.resource.ps1", + "FileType": "Product", + "Architecture": null } ] diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index d8857c71786..af4d1736ed8 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -4425,5 +4425,15 @@ "Pattern": "System.Management.Automation.dll", "FileType": "Product", "Architecture": null + }, + { + "Pattern": "pwsh.profile.dsc.resource.json", + "FileType": "Product", + "Architecture": null + }, + { + "Pattern": "pwsh.profile.resource.ps1", + "FileType": "Product", + "Architecture": null } ] From 44aa7397077e2608a2da2649aa7aa8f13ca182a4 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 13 Nov 2025 15:03:35 -0800 Subject: [PATCH 006/127] [release/v7.6] Github Workflow cleanup (#26439) --- .github/workflows/AssignPrs.yml | 30 --------------- .github/workflows/createReminders.yml | 21 ---------- .github/workflows/markdownLink.yml | 51 ------------------------- .github/workflows/markdownLinkDaily.yml | 33 ---------------- .github/workflows/processReminders.yml | 21 ---------- tools/download.sh | 4 +- tools/install-powershell.sh | 6 ++- 7 files changed, 7 insertions(+), 159 deletions(-) delete mode 100644 .github/workflows/AssignPrs.yml delete mode 100644 .github/workflows/createReminders.yml delete mode 100644 .github/workflows/markdownLink.yml delete mode 100644 .github/workflows/markdownLinkDaily.yml delete mode 100644 .github/workflows/processReminders.yml diff --git a/.github/workflows/AssignPrs.yml b/.github/workflows/AssignPrs.yml deleted file mode 100644 index a01c0bb0950..00000000000 --- a/.github/workflows/AssignPrs.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Auto Assign PR Maintainer -on: - issues: - types: [opened, edited] -permissions: - contents: read - -jobs: - run: - if: github.repository_owner == 'PowerShell' - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - steps: - - uses: wow-actions/auto-assign@67fafa03df61d7e5f201734a2fa60d1ab111880d # v3.0.2 - if: github.event.issue.pull_request - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # using the `org/team_slug` or `/team_slug` syntax to add git team as reviewers - assignees: | - TravisEz13 - daxian-dbw - adityapatwardhan - iSazonov - SeeminglyScience - skipDraft: true - skipKeywords: wip, draft - addReviewers: false - numberOfAssignees: 1 diff --git a/.github/workflows/createReminders.yml b/.github/workflows/createReminders.yml deleted file mode 100644 index bab5342fe0b..00000000000 --- a/.github/workflows/createReminders.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: 'Create reminder' - -on: - issue_comment: - types: [created, edited] - -permissions: - contents: read - -jobs: - reminder: - if: github.repository_owner == 'PowerShell' - - permissions: - issues: write # for agrc/create-reminder-action to set reminders on issues - pull-requests: write # for agrc/create-reminder-action to set reminders on PRs - runs-on: ubuntu-latest - - steps: - - name: check for reminder - uses: agrc/create-reminder-action@30624e347adbc7ff2dd287ad0632499552e048e8 # v1.1.22 diff --git a/.github/workflows/markdownLink.yml b/.github/workflows/markdownLink.yml deleted file mode 100644 index 5ad78cf84d4..00000000000 --- a/.github/workflows/markdownLink.yml +++ /dev/null @@ -1,51 +0,0 @@ -on: - pull_request: - branches: - - master - -name: Check modified markdown files -permissions: - contents: read - -jobs: - markdown-link-check: - runs-on: ubuntu-latest - if: github.repository_owner == 'PowerShell' - - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 - with: - use-quiet-mode: 'yes' - use-verbose-mode: 'yes' - check-modified-files-only: 'yes' - config-file: .github/workflows/markdown-link/config.json - markdown-lint: - permissions: - contents: read - packages: read - statuses: write - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - # Full git history is needed to get a proper - # list of changed files within `super-linter` - fetch-depth: 0 - - name: Load super-linter configuration - # Use grep inverse matching to exclude eventual comments in the .env file - # because the GitHub Actions command to set environment variables doesn't - # support comments. - # Ref: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-environment-variable - run: grep -v '^#' tools/super-linter/config/super-linter.env >> "$GITHUB_ENV" - - name: Lint Markdown - uses: super-linter/super-linter@5119dcd8011e92182ce8219d9e9efc82f16fddb6 # v8.0.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Super-Linter correction instructions - if: failure() - uses: actions/github-script@v8 - with: - script: | - const message = "Super-Linter found issues in the changed files. Please check the logs for details. You can run the linter locally using the command: `./tools/super-lister/super-lister.ps1`."; - core.setFailed(message); diff --git a/.github/workflows/markdownLinkDaily.yml b/.github/workflows/markdownLinkDaily.yml deleted file mode 100644 index 7f5789ed96d..00000000000 --- a/.github/workflows/markdownLinkDaily.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT license. - -name: PowerShell Daily Markdown Link Verification - -on: - workflow_dispatch: - schedule: - # At 13:00 UTC every day. - - cron: '0 13 * * *' - -permissions: - contents: read - -jobs: - markdown-link-check: - runs-on: ubuntu-latest - if: github.repository == 'PowerShell/PowerShell' - steps: - - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: Check Links - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # v1 - with: - use-quiet-mode: 'yes' - use-verbose-mode: 'yes' - config-file: .github/workflows/markdown-link/config.json - - name: Microsoft Teams Notifier - uses: skitionek/notify-microsoft-teams@e7a2493ac87dad8aa7a62f079f295e54ff511d88 # master - if: failure() - with: - webhook_url: ${{ secrets.PS_BUILD_TEAMS_CHANNEL }} - overwrite: "{title: `Failure in .github/markdownLinkDaily.yml validating links. Look at ${workflow_link}`}" diff --git a/.github/workflows/processReminders.yml b/.github/workflows/processReminders.yml deleted file mode 100644 index 18de16159ac..00000000000 --- a/.github/workflows/processReminders.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: 'Process reminders' - -on: - schedule: - - cron: '*/15 * * * *' - workflow_dispatch: - -permissions: - contents: read - -jobs: - reminder: - if: github.repository_owner == 'PowerShell' - permissions: - issues: write # for agrc/reminder-action to set reminders on issues - pull-requests: write # for agrc/reminder-action to set reminders on PRs - runs-on: ubuntu-latest - - steps: - - name: check reminders and notify - uses: agrc/reminder-action@3095f64f8f0c26c751bee802cb1008ece5953078 # v1.0.18 diff --git a/tools/download.sh b/tools/download.sh index 6a6c6436b4b..f1e8c42cdc3 100644 --- a/tools/download.sh +++ b/tools/download.sh @@ -1 +1,3 @@ -bash <(curl -s https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.sh) +# Pin to specific commit for security (OpenSSF Scorecard requirement) +# Pinned commit: 26bb188c8 - "Improve ValidateLength error message consistency and refactor validation tests" (2025-10-12) +bash <(curl -s https://raw.githubusercontent.com/PowerShell/PowerShell/26bb188c8be0cda6cb548ce1a12840ebf67e1331/tools/install-powershell.sh) diff --git a/tools/install-powershell.sh b/tools/install-powershell.sh index 128f5664483..91425c183a8 100755 --- a/tools/install-powershell.sh +++ b/tools/install-powershell.sh @@ -26,7 +26,9 @@ install(){ #gitrepo paths are overrideable to run from your own fork or branch for testing or private distribution local VERSION="1.2.0" - local gitreposubpath="PowerShell/PowerShell/master" + # Pin to specific commit for security (OpenSSF Scorecard requirement) + # Pinned commit: 26bb188c8 - "Improve ValidateLength error message consistency and refactor validation tests" (2025-10-12) + local gitreposubpath="PowerShell/PowerShell/26bb188c8be0cda6cb548ce1a12840ebf67e1331" local gitreposcriptroot="https://raw.githubusercontent.com/$gitreposubpath/tools" local gitscriptname="install-powershell.psh" @@ -125,7 +127,7 @@ install(){ if [[ $osname = *SUSE* ]]; then DistroBasedOn='suse' REV=$(source /etc/os-release; echo $VERSION_ID) - fi + fi OS=$(lowercase $OS) DistroBasedOn=$(lowercase $DistroBasedOn) fi From e9af4e7710501deb6024ee090db01b0165f968ee Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 19 Nov 2025 10:01:24 -0800 Subject: [PATCH 007/127] [release/v7.6] Update outdated package references (#26471) Co-authored-by: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Co-authored-by: Dongbo Wang --- .github/workflows/linux-ci.yml | 119 +++++++++--------- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 5 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../System.Management.Automation.csproj | 12 +- .../nested/Test.Isolated.Nested.csproj | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- test/xUnit/xUnit.tests.csproj | 4 +- tools/cgmanifest.json | 114 +++++++++-------- 14 files changed, 145 insertions(+), 135 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 30f5acd5619..aa517e459c1 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -161,64 +161,65 @@ jobs: - name: Verify xUnit test results uses: "./.github/actions/test/verify_xunit" - analyze: - permissions: - actions: read # for github/codeql-action/init to get workflow details - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/analyze to upload SARIF results - name: Analyze - runs-on: ubuntu-latest - needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} - - strategy: - fail-fast: false - matrix: - # Override automatic language detection by changing the below list - # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['csharp'] - # Learn more... - # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection - - steps: - - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - fetch-depth: '0' - - - uses: actions/setup-dotnet@v5 - with: - global-json-file: ./global.json - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - - run: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - name: Capture Environment - shell: pwsh - - - run: | - Import-Module .\tools\ci.psm1 - Invoke-CIInstall -SkipUser - name: Bootstrap - shell: pwsh - - - run: | - Import-Module .\tools\ci.psm1 - Invoke-CIBuild - name: Build - shell: pwsh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 + ## Temporarily disable the CodeQL analysis on Linux as it doesn't work for .NET SDK 10-rc.2. + # analyze: + # permissions: + # actions: read # for github/codeql-action/init to get workflow details + # contents: read # for actions/checkout to fetch code + # security-events: write # for github/codeql-action/analyze to upload SARIF results + # name: Analyze + # runs-on: ubuntu-latest + # needs: changes + # if: ${{ needs.changes.outputs.source == 'true' }} + # + # strategy: + # fail-fast: false + # matrix: + # # Override automatic language detection by changing the below list + # # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] + # language: ['csharp'] + # # Learn more... + # # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + # + # steps: + # - name: Checkout repository + # uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + # with: + # fetch-depth: '0' + # + # - uses: actions/setup-dotnet@v5 + # with: + # global-json-file: ./global.json + # + # # Initializes the CodeQL tools for scanning. + # - name: Initialize CodeQL + # uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 + # with: + # languages: ${{ matrix.language }} + # # If you wish to specify custom queries, you can do so here or in a config file. + # # By default, queries listed here will override any specified in a config file. + # # Prefix the list here with "+" to use these queries and those in the config file. + # # queries: ./path/to/local/query, your-org/your-repo/queries@main + # + # - run: | + # Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + # name: Capture Environment + # shell: pwsh + # + # - run: | + # Import-Module .\tools\ci.psm1 + # Invoke-CIInstall -SkipUser + # name: Bootstrap + # shell: pwsh + # + # - run: | + # Import-Module .\tools\ci.psm1 + # Invoke-CIBuild + # name: Build + # shell: pwsh + # + # - name: Perform CodeQL Analysis + # uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 ready_to_merge: name: Linux ready to merge @@ -228,7 +229,7 @@ jobs: - linux_test_elevated_others - linux_test_unelevated_ci - linux_test_unelevated_others - - analyze + # - analyze if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: diff --git a/global.json b/global.json index e7cce33e5d9..83e6a8b43e0 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.100-rc.1.25451.107" + "version": "10.0.100-rc.2.25502.107" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 547911668e9..cc3760db39f 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 029571c4145..f5f6fede1af 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index a35f4258e56..da15fe82350 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -8,7 +8,7 @@ - + @@ -33,8 +33,7 @@ - - + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index d60337d5d90..228d6360022 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 2c796312a1a..31c48def673 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,13 +16,13 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 710102ca2fa..bef80519d56 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 033c39034ac..0e435448b5f 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,17 +32,17 @@ - - + + - + - + - - + + diff --git a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj index 10c707c176a..de06b206f37 100644 --- a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj +++ b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index f50e3bccf60..d2004ea2fdd 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 46638197255..056f6810c71 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ - + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 33f0a2dde00..5cb4a1e48d8 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -29,8 +29,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 11c7447ff7d..26936804614 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -65,7 +66,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "0.42.0" + "Version": "0.43.0" } }, "DevelopmentDependency": false @@ -85,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -125,7 +126,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -165,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -175,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -185,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -205,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -215,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -225,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -235,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -245,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -255,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -265,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -275,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -285,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -295,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -305,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -315,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -325,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -335,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -355,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -365,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -375,7 +376,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -435,7 +436,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -445,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -455,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -465,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -475,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -485,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -505,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -515,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -525,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -535,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -545,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -555,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -565,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -575,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -585,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -595,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -615,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -625,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -635,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -645,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -655,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -665,7 +666,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -725,7 +726,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -735,7 +736,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -745,7 +746,17 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.9" + "Version": "9.0.10" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Text.Encoding.CodePages", + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -755,7 +766,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Threading.AccessControl", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false @@ -775,11 +786,10 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.9" + "Version": "9.0.10" } }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } From 22636e047f59144d2d81e11e12ce480eff79e326 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 19 Nov 2025 11:23:35 -0800 Subject: [PATCH 008/127] [release/v7.6] Integrate Windows packaging into windows-ci workflow using reusable workflow (#26468) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .../infrastructure/path-filters/action.yml | 18 ++++ .github/workflows/windows-ci.yml | 10 +++ .../workflows/windows-packaging-reusable.yml | 88 +++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 .github/workflows/windows-packaging-reusable.yml diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index e150b1a9d09..09ed7c22d17 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -26,6 +26,9 @@ outputs: buildModuleChanged: description: 'Build module changes' value: ${{ steps.filter.outputs.buildModuleChanged }} + packagingChanged: + description: 'Packaging related changes' + value: ${{ steps.filter.outputs.packagingChanged }} runs: using: composite steps: @@ -85,6 +88,19 @@ runs: const globalConfigChanged = files.some(file => file.filename.startsWith('.globalconfig')) || files.some(file => file.filename.startsWith('nuget.config')) || files.some(file => file.filename.startsWith('global.json')); + const packagingChanged = files.some(file => + file.filename === '.github/workflows/windows-ci.yml' || + file.filename.startsWith('assets/wix/') || + file.filename === 'PowerShell.Common.props' || + file.filename.match(/^src\/.*\.csproj$/) || + file.filename.startsWith('test/packaging/windows/') || + file.filename.startsWith('tools/packaging/') || + file.filename.startsWith('tools/wix/') + ) || + buildModuleChanged || + globalConfigChanged || + toolsCiPsm1Changed; + const source = mainSourceChanged || toolsChanged || githubChanged || propsChanged || testsChanged || globalConfigChanged; core.setOutput('toolsChanged', toolsChanged); @@ -94,6 +110,7 @@ runs: core.setOutput('mainSourceChanged', mainSourceChanged); core.setOutput('buildModuleChanged', buildModuleChanged); core.setOutput('globalConfigChanged', globalConfigChanged); + core.setOutput('packagingChanged', packagingChanged); core.setOutput('source', source); @@ -106,4 +123,5 @@ runs: Write-Verbose -Verbose "tests: ${{ steps.filter.outputs.testsChanged }}" Write-Verbose -Verbose "mainSource: ${{ steps.filter.outputs.mainSourceChanged }}" Write-Verbose -Verbose "buildModule: ${{ steps.filter.outputs.buildModuleChanged }}" + Write-Verbose -Verbose "packaging: ${{ steps.filter.outputs.packagingChanged }}" shell: pwsh diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 63e6c5ab7a3..64d37eb1ae5 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -41,6 +41,8 @@ env: POWERSHELL_TELEMETRY_OPTOUT: 1 __SuppressAnsiEscapeSequences: 1 nugetMultiFeedWarnLevel: none + SYSTEM_ARTIFACTSDIRECTORY: ${{ github.workspace }}/artifacts + BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts jobs: changes: name: Change Detection @@ -54,6 +56,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout uses: actions/checkout@v5 @@ -158,6 +161,12 @@ jobs: fetch-depth: 1000 - name: Verify xUnit test results uses: "./.github/actions/test/verify_xunit" + windows_packaging: + name: Windows Packaging + needs: + - changes + if: ${{ needs.changes.outputs.packagingChanged == 'true' }} + uses: ./.github/workflows/windows-packaging-reusable.yml ready_to_merge: name: windows ready to merge needs: @@ -166,6 +175,7 @@ jobs: - windows_test_elevated_others - windows_test_unelevated_ci - windows_test_unelevated_others + - windows_packaging if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml new file mode 100644 index 00000000000..5a763544c62 --- /dev/null +++ b/.github/workflows/windows-packaging-reusable.yml @@ -0,0 +1,88 @@ +name: Windows Packaging (Reusable) + +on: + workflow_call: + +env: + GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'" + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + DOTNET_NOLOGO: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + SYSTEM_ARTIFACTSDIRECTORY: ${{ github.workspace }}/artifacts + BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts + +jobs: + package: + name: ${{ matrix.architecture }} - ${{ matrix.channel }} + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + include: + - architecture: x64 + channel: preview + runtimePrefix: win7 + - architecture: x86 + channel: stable + runtimePrefix: win7 + - architecture: x86 + channel: preview + runtimePrefix: win7 + - architecture: arm64 + channel: preview + runtimePrefix: win + + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 1000 + + - name: Capture Environment + if: success() || failure() + run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + shell: pwsh + + - name: Capture PowerShell Version Table + if: success() || failure() + run: | + $PSVersionTable + shell: pwsh + + - name: Switch to Public Feeds + if: success() + run: | + Import-Module .\tools\ci.psm1 + Switch-PSNugetConfig -Source Public + shell: pwsh + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + if: success() + run: | + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + shell: pwsh + + - name: Build and Package + run: | + Import-Module .\tools\ci.psm1 + New-CodeCoverageAndTestPackage + Invoke-CIFinish -Runtime ${{ matrix.runtimePrefix }}-${{ matrix.architecture }} -channel ${{ matrix.channel }} + shell: pwsh + + - name: Upload Build Artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} + path: | + ${{ github.workspace }}/artifacts/**/* + !${{ github.workspace }}/artifacts/**/*.pdb From 46f219cbd008aa77594b41ed9ddbbdd586229023 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 19 Nov 2025 14:55:15 -0800 Subject: [PATCH 009/127] [release/v7.6] Fix build to only enable ready-to-run for the Release configuration (#26481) Co-authored-by: Dongbo Wang --- PowerShell.Common.props | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/PowerShell.Common.props b/PowerShell.Common.props index 91d44c21f03..dfc16f830d7 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -193,12 +193,20 @@ Global + + + + true true AppLocal + + + + true true From 51e4d5c0ba87bd4ee3bd5221ff0e3d4f68e75913 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 19 Nov 2025 14:55:27 -0800 Subject: [PATCH 010/127] [release/v7.6] Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26488) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .github/actions/build/ci/action.yml | 14 --- .github/actions/test/verify_xunit/action.yml | 21 ---- .../instructions/build-configuration-guide.md | 95 +++++++++++++++++++ .../git-requirements-for-builds.md | 71 ++++++++++++++ .github/instructions/start-psbuild-basics.md | 92 ++++++++++++++++++ .../instructions/troubleshooting-builds.md | 92 ++++++++++++++++++ .../instructions/workflow-prerequisites.md | 91 ++++++++++++++++++ .github/workflows/linux-ci.yml | 19 ++-- .github/workflows/macos-ci.yml | 19 ++-- .github/workflows/windows-ci.yml | 19 ++-- .github/workflows/xunit-tests.yml | 53 +++++++++++ 11 files changed, 515 insertions(+), 71 deletions(-) delete mode 100644 .github/actions/test/verify_xunit/action.yml create mode 100644 .github/instructions/build-configuration-guide.md create mode 100644 .github/instructions/git-requirements-for-builds.md create mode 100644 .github/instructions/start-psbuild-basics.md create mode 100644 .github/instructions/troubleshooting-builds.md create mode 100644 .github/instructions/workflow-prerequisites.md create mode 100644 .github/workflows/xunit-tests.yml diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index 93adaf6b17a..997be8b264c 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -31,22 +31,8 @@ runs: Import-Module .\tools\ci.psm1 Invoke-CIBuild shell: pwsh - - name: xUnit Tests - if: success() - continue-on-error: true - run: |- - Write-Verbose -Verbose "Running xUnit tests..." - Import-Module .\tools\ci.psm1 - Restore-PSOptions - Invoke-CIxUnit -SkipFailing - shell: pwsh - name: Upload build artifact uses: actions/upload-artifact@v4 with: name: build path: ${{ runner.workspace }}/build - - name: Upload xunit artifact - uses: actions/upload-artifact@v4 - with: - name: testResults-xunit - path: ${{ runner.workspace }}/xunit diff --git a/.github/actions/test/verify_xunit/action.yml b/.github/actions/test/verify_xunit/action.yml deleted file mode 100644 index fccca27182f..00000000000 --- a/.github/actions/test/verify_xunit/action.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: verify_xunit -description: 'Verify xUnit Results' - -runs: - using: composite - steps: - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - path: "${{ github.workspace }}" - - name: Capture artifacts directory - continue-on-error: true - run: dir "${{ github.workspace }}\testResults-xunit\*" -Recurse - shell: pwsh - - name: Test - if: success() - run: |- - Import-Module .\tools\ci.psm1 - $xUnitTestResultsFile = "${{ github.workspace }}\testResults-xunit\xUnitTestResults.xml" - Test-XUnitTestResults -TestResultsFile $xUnitTestResultsFile - shell: pwsh diff --git a/.github/instructions/build-configuration-guide.md b/.github/instructions/build-configuration-guide.md new file mode 100644 index 00000000000..d082bcbe774 --- /dev/null +++ b/.github/instructions/build-configuration-guide.md @@ -0,0 +1,95 @@ +# Build Configuration Guide + +## Choosing the Right Configuration + +### For Testing + +**Use: Default (Debug)** + +```yaml +- name: Build for Testing + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +**Why Debug:** +- Includes debugging symbols +- Better error messages +- Faster build times +- Suitable for xUnit and Pester tests + +**Do NOT use:** +- `-Configuration 'Release'` (unnecessary for tests) +- `-ReleaseTag` (not needed for tests) +- `-CI` (unless you specifically need Pester module) + +### For Release/Packaging + +**Use: Release with version tag** + +```yaml +- name: Build for Release + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag +``` + +**Why Release:** +- Optimized binaries +- No debug symbols (smaller size) +- Production-ready + +### For Code Coverage + +**Use: CodeCoverage configuration** + +```yaml +- name: Build with Coverage + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild -Configuration 'CodeCoverage' +``` + +## Platform Considerations + +### All Platforms + +Same commands work across Linux, Windows, and macOS: + +```yaml +strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] +runs-on: ${{ matrix.os }} +steps: + - name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +### Output Locations + +**Linux/macOS:** +``` +src/powershell-unix/bin/Debug///publish/ +``` + +**Windows:** +``` +src/powershell-win-core/bin/Debug///publish/ +``` + +## Best Practices + +1. Use default configuration for testing +2. Avoid redundant parameters +3. Match configuration to purpose +4. Use `-CI` only when needed +5. Always specify `-ReleaseTag` for release or packaging builds diff --git a/.github/instructions/git-requirements-for-builds.md b/.github/instructions/git-requirements-for-builds.md new file mode 100644 index 00000000000..3c8cd91e7c7 --- /dev/null +++ b/.github/instructions/git-requirements-for-builds.md @@ -0,0 +1,71 @@ +# Git Requirements for Building PowerShell + +## Fetch Depth + +**Required:** `fetch-depth: 1000` + +The PowerShell build process uses `git describe --abbrev=60 --long` to generate version information. This requires access to git history and tags. + +### Problem + +Without sufficient fetch depth, builds fail with: +``` +error MSB3073: The command "git describe --abbrev=60 --long" exited with code 128. +``` + +### Solution + +Always use `fetch-depth: 1000` in the checkout step: + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 +``` + +## Tag Synchronization + +**Required:** `Sync-PSTags -AddRemoteIfMissing` + +The build process needs git tags to properly version the build. + +### Problem + +Without tag synchronization: +- Version information is incorrect +- Build versioning fails + +### Solution + +Include tag synchronization in the bootstrap step: + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Sync-PSTags -AddRemoteIfMissing +``` + +## Complete Example + +```yaml +steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` diff --git a/.github/instructions/start-psbuild-basics.md b/.github/instructions/start-psbuild-basics.md new file mode 100644 index 00000000000..ae216a1584d --- /dev/null +++ b/.github/instructions/start-psbuild-basics.md @@ -0,0 +1,92 @@ +# Start-PSBuild Basics + +## Purpose + +`Start-PSBuild` builds PowerShell from source. It's defined in `build.psm1` and used in CI/CD workflows. + +## Default Usage + +For most scenarios, use with no parameters: + +```powershell +Import-Module ./tools/ci.psm1 +Start-PSBuild +``` + +**Default behavior:** +- Configuration: `Debug` +- PSModuleRestore: Enabled +- Runtime: Auto-detected for platform + +## Common Configurations + +### Debug Build (Default) + +```powershell +Start-PSBuild +``` + +Use for: +- Testing (xUnit, Pester) +- Development +- Debugging + +### Release Build + +```powershell +Start-PSBuild -Configuration 'Release' +``` + +Use for: +- Production packages +- Distribution +- Performance testing + +### Code Coverage Build + +```powershell +Start-PSBuild -Configuration 'CodeCoverage' +``` + +Use for: +- Code coverage analysis +- Test coverage reports + +## Common Parameters + +### -Configuration + +Values: `Debug`, `Release`, `CodeCoverage`, `StaticAnalysis` + +Default: `Debug` + +### -CI + +Restores Pester module for CI environments. + +```powershell +Start-PSBuild -CI +``` + +### -PSModuleRestore + +Now enabled by default. Use `-NoPSModuleRestore` to skip. + +### -ReleaseTag + +Specifies version tag for release builds: + +```powershell +$releaseTag = Get-ReleaseTag +Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag +``` + +## Workflow Example + +```yaml +- name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` diff --git a/.github/instructions/troubleshooting-builds.md b/.github/instructions/troubleshooting-builds.md new file mode 100644 index 00000000000..37f5df00912 --- /dev/null +++ b/.github/instructions/troubleshooting-builds.md @@ -0,0 +1,92 @@ +# Troubleshooting Build Issues + +## Git Describe Error + +**Error:** +``` +error MSB3073: The command "git describe --abbrev=60 --long" exited with code 128. +``` + +**Cause:** Insufficient git history (shallow clone) + +**Solution:** Add `fetch-depth: 1000` to checkout step + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 +``` + +## Version Information Incorrect + +**Symptom:** Build produces wrong version numbers + +**Cause:** Git tags not synchronized + +**Solution:** Run `Sync-PSTags -AddRemoteIfMissing`: + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` + +## PowerShell Binary Not Built + +**Error:** +``` +Exception: CoreCLR pwsh.exe was not built +``` + +**Causes:** +1. Build failed (check logs) +2. Wrong configuration used +3. Build output location incorrect + +**Solutions:** +1. Check build logs for errors +2. Verify correct configuration for use case +3. Use default parameters: `Start-PSBuild` + +## Module Restore Issues + +**Symptom:** Slow build or module restore failures + +**Causes:** +- Network issues +- Module cache problems +- Package source unavailable + +**Solutions:** +1. Retry the build +2. Check network connectivity +3. Use `-NoPSModuleRestore` if modules not needed +4. Clear package cache if persistent + +## .NET SDK Not Found + +**Symptom:** Build can't find .NET SDK + +**Solution:** Ensure .NET setup step runs first: + +```yaml +- name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json +``` + +## Bootstrap Failures + +**Symptom:** Invoke-CIInstall fails + +**Causes:** +- Missing dependencies +- Network issues +- Platform-specific requirements not met + +**Solution:** Check prerequisites for your platform in build system docs diff --git a/.github/instructions/workflow-prerequisites.md b/.github/instructions/workflow-prerequisites.md new file mode 100644 index 00000000000..fe88abb384f --- /dev/null +++ b/.github/instructions/workflow-prerequisites.md @@ -0,0 +1,91 @@ +# Workflow Prerequisites for Building PowerShell + +## Required Steps Before Start-PSBuild + +These steps must run before calling `Start-PSBuild`: + +### 1. Checkout + +```yaml +- name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 # Required for version generation +``` + +### 2. Setup .NET + +```yaml +- name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json +``` + +### 3. Bootstrap + +```yaml +- name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing +``` + +## Complete Prerequisites Example + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing + + - name: Build PowerShell + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild +``` + +## Why Each Step Matters + +**Checkout with fetch-depth:** +- Build needs git history for versioning +- Without it: `git describe` fails + +**Setup .NET:** +- Provides SDK for building +- Uses version from global.json + +**Bootstrap:** +- Installs dependencies +- Syncs git tags +- Prepares build environment + +## Optional Steps + +### Environment Capture (Debugging) + +```yaml +- name: Capture Environment + run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | Write-Verbose -Verbose + shell: pwsh +``` diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index aa517e459c1..26670f99bdb 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -146,20 +146,15 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v5 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: ubuntu-latest + test_results_artifact_name: testResults-xunit ## Temporarily disable the CodeQL analysis on Linux as it doesn't work for .NET SDK 10-rc.2. # analyze: @@ -224,7 +219,7 @@ jobs: ready_to_merge: name: Linux ready to merge needs: - - verify_xunit + - xunit_tests - linux_test_elevated_ci - linux_test_elevated_others - linux_test_unelevated_ci diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 0007d550f06..7ec1fc6da06 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -143,20 +143,15 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v5 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: macos-15-large + test_results_artifact_name: testResults-xunit PackageMac-macos_packaging: name: macOS packaging (bootstrap only) needs: @@ -176,7 +171,7 @@ jobs: ready_to_merge: name: macos ready to merge needs: - - verify_xunit + - xunit_tests - PackageMac-macos_packaging - macos_test_elevated_ci - macos_test_elevated_others diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 64d37eb1ae5..37470475079 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -147,20 +147,15 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others - verify_xunit: - name: Verify xUnit test results + xunit_tests: + name: xUnit Tests needs: - - ci_build - changes if: ${{ needs.changes.outputs.source == 'true' }} - runs-on: windows-latest - steps: - - name: checkout - uses: actions/checkout@v5 - with: - fetch-depth: 1000 - - name: Verify xUnit test results - uses: "./.github/actions/test/verify_xunit" + uses: ./.github/workflows/xunit-tests.yml + with: + runner_os: windows-latest + test_results_artifact_name: testResults-xunit windows_packaging: name: Windows Packaging needs: @@ -170,7 +165,7 @@ jobs: ready_to_merge: name: windows ready to merge needs: - - verify_xunit + - xunit_tests - windows_test_elevated_ci - windows_test_elevated_others - windows_test_unelevated_ci diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml new file mode 100644 index 00000000000..8bf5fd699d0 --- /dev/null +++ b/.github/workflows/xunit-tests.yml @@ -0,0 +1,53 @@ +name: xUnit Tests (Reusable) + +on: + workflow_call: + inputs: + runner_os: + description: 'Runner OS for xUnit tests' + type: string + required: false + default: ubuntu-latest + test_results_artifact_name: + description: 'Artifact name for xUnit test results directory' + type: string + required: false + default: testResults-xunit + +jobs: + xunit: + name: Run xUnit Tests + runs-on: ${{ inputs.runner_os }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json + + - name: Bootstrap + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Invoke-CIInstall -SkipUser + Sync-PSTags -AddRemoteIfMissing + + - name: Build PowerShell and run xUnit tests + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Start-PSBuild + Write-Host "Running full xUnit test suite (no skipping)..." + Invoke-CIxUnit + Write-Host "Completed xUnit test run." + + - name: Upload xUnit results + uses: actions/upload-artifact@v4 + if: always() + with: + name: ${{ inputs.test_results_artifact_name }} + path: ${{ github.workspace }}/xUnitTestResults.xml From bcf9f890200a87494a2387d10e41b35ce221fed5 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 19 Nov 2025 16:37:11 -0800 Subject: [PATCH 011/127] [release/v7.6] Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26493) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .../actions/test/linux-packaging/action.yml | 112 +++++++++--------- .github/workflows/linux-ci.yml | 32 +++-- build.psm1 | 2 +- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index b4a9c3b55c0..736bddfa7a7 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -1,12 +1,5 @@ name: linux_packaging -description: 'Test very basic Linux packaging' - -# This isn't working yet -# It fails with - -# ERROR: While executing gem ... (Gem::FilePermissionError) -# You don't have write permissions for the /var/lib/gems/2.7.0 directory. -# WARNING: Installation of gem dotenv 2.8.1 failed! Must resolve manually. +description: 'Linux packaging for PowerShell' runs: using: composite @@ -15,58 +8,64 @@ runs: if: success() || failure() run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' shell: pwsh + + - uses: actions/setup-dotnet@v5 + with: + global-json-file: ./global.json + - name: Download Build Artifacts uses: actions/download-artifact@v4 with: - path: "${{ github.workspace }}" + name: build + path: "${{ runner.workspace }}/build" + - name: Capture Artifacts Directory continue-on-error: true - run: Get-ChildItem "${{ github.workspace }}/build/*" -Recurse + run: Get-ChildItem "${{ runner.workspace }}/build/*" -Recurse shell: pwsh - name: Bootstrap run: |- Import-Module ./build.psm1 Start-PSBootstrap -Scenario Package + Write-Verbose -Verbose "Start Sync-PSTags" + Sync-PSTags -AddRemoteIfMissing + Write-Verbose -Verbose "End Sync-PSTags" shell: pwsh - - name: Capture Artifacts Directory - continue-on-error: true - run: Import-Module ./build.psm1 + + - name: Extract Build ZIP + run: |- + $destinationFolder = "${{ runner.workspace }}/bins" + $archiveFile = "${{ runner.workspace }}/build/build.zip" + + Write-Verbose "Extracting $archiveFile to $destinationFolder" -Verbose + New-Item -ItemType Directory -Path $destinationFolder -Force | Out-Null + Expand-Archive -Path $archiveFile -DestinationPath $destinationFolder -Force shell: pwsh - - name: Extract Files - uses: actions/github-script@v7.0.0 - env: - DESTINATION_FOLDER: "${{ github.workspace }}/bins" - ARCHIVE_FILE_PATTERNS: "${{ github.workspace }}/build/build.zip" - with: - script: |- - const fs = require('fs').promises - const path = require('path') - const target = path.resolve(process.env.DESTINATION_FOLDER) - const patterns = process.env.ARCHIVE_FILE_PATTERNS - const globber = await glob.create(patterns) - await io.mkdirP(path.dirname(target)) - for await (const file of globber.globGenerator()) { - if ((await fs.lstat(file)).isDirectory()) continue - await exec.exec(`7z x ${file} -o${target} -aoa`) - } + - name: Fix permissions continue-on-error: true run: |- - find "${{ github.workspace }}/bins" -type d -exec chmod +rwx {} \; - find "${{ github.workspace }}/bins" -type f -exec chmod +rw {} \; + find "${{ runner.workspace }}/bins" -type d -exec chmod +rwx {} \; + find "${{ runner.workspace }}/bins" -type f -exec chmod +rw {} \; shell: bash + - name: Capture Extracted Build ZIP continue-on-error: true - run: Get-ChildItem "${{ github.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue + run: Get-ChildItem "${{ runner.workspace }}/bins/*" -Recurse -ErrorAction SilentlyContinue shell: pwsh - - name: Packaging Tests - if: success() + + - name: Create Packages + env: + BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ runner.workspace }}/packages run: |- + # Create the artifacts staging directory + New-Item -ItemType Directory -Path "$env:BUILD_ARTIFACTSTAGINGDIRECTORY" -Force | Out-Null + Import-Module ./tools/ci.psm1 - Restore-PSOptions -PSOptionsPath '${{ github.workspace }}/build/psoptions.json' + Restore-PSOptions -PSOptionsPath '${{ runner.workspace }}/build/psoptions.json' $options = (Get-PSOptions) - $rootPath = '${{ github.workspace }}/bins' + $rootPath = '${{ runner.workspace }}/bins' $originalRootPath = Split-Path -path $options.Output $path = Join-Path -path $rootPath -ChildPath (split-path -leaf -path $originalRootPath) $pwshPath = Join-Path -path $path -ChildPath 'pwsh' @@ -75,21 +74,24 @@ runs: Set-PSOptions $options Invoke-CIFinish shell: pwsh - - name: Upload packages - run: |- - Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.deb" -Recurse | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=deb;artifactname=deb]$packagePath" - } - Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.rpm" -Recurse | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=rpm;artifactname=rpm]$packagePath" - } - Get-ChildItem "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}/*.tar.gz" -Recurse | ForEach-Object { - $packagePath = $_.FullName - Write-Host "Uploading $packagePath" - Write-Host "##vso[artifact.upload containerfolder=rpm;artifactname=rpm]$packagePath" - } - shell: pwsh + + - name: Upload deb packages + uses: actions/upload-artifact@v4 + with: + name: packages-deb + path: ${{ runner.workspace }}/packages/*.deb + if-no-files-found: ignore + + - name: Upload rpm packages + uses: actions/upload-artifact@v4 + with: + name: packages-rpm + path: ${{ runner.workspace }}/packages/*.rpm + if-no-files-found: ignore + + - name: Upload tar.gz packages + uses: actions/upload-artifact@v4 + with: + name: packages-tar + path: ${{ runner.workspace }}/packages/*.tar.gz + if-no-files-found: ignore diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 26670f99bdb..41f1ffc43cd 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -225,24 +225,22 @@ jobs: - linux_test_unelevated_ci - linux_test_unelevated_others # - analyze + - linux_packaging if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 with: needs_context: ${{ toJson(needs) }} - # TODO: Enable this when we have a Linux packaging workflow - - # ERROR: While executing gem ... (Gem::FilePermissionError) - # You don't have write permissions for the /var/lib/gems/2.7.0 directory. - # WARNING: Installation of gem dotenv 2.8.1 failed! Must resolve manually. - - # linux_packaging: - # name: Attempt Linux Packaging - # needs: ci_build - # runs-on: ubuntu-20.04 - # steps: - # - name: checkout - # uses: actions/checkout@v5 - # with: - # fetch-depth: 1000 - # - name: Verify xUnit test results - # uses: "./.github/actions/test/linux-packaging" + linux_packaging: + name: Linux Packaging + needs: + - ci_build + - changes + if: ${{ needs.changes.outputs.source == 'true' }} + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + - name: Linux Packaging + uses: "./.github/actions/test/linux-packaging" diff --git a/build.psm1 b/build.psm1 index a610c684e2c..98d080ecc99 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2252,7 +2252,7 @@ function Install-GlobalGem { # We cannot guess if the user wants to run gem install as root on linux and windows, # but macOs usually requires sudo $gemsudo = '' - if($environment.IsMacOS -or $env:TF_BUILD) { + if($environment.IsMacOS -or $env:TF_BUILD -or $env:GITHUB_ACTIONS) { $gemsudo = $sudo } From ea0bfb39ac8eb407e65bde642c2e9e8c86567719 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Wed, 19 Nov 2025 16:38:01 -0800 Subject: [PATCH 012/127] [release/v7.6] Fix GitHub API rate limit errors in test actions (#26492) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .github/actions/test/nix/action.yml | 10 ++++++++-- .github/actions/test/windows/action.yml | 10 ++++++++-- .github/workflows/linux-ci.yml | 4 ++++ .github/workflows/macos-ci.yml | 4 ++++ .github/workflows/windows-ci.yml | 4 ++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index 89c11d59ccc..c7e97742694 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -14,6 +14,9 @@ inputs: required: false default: ctrf type: string + GITHUB_TOKEN: + description: 'GitHub token for API authentication' + required: true runs: using: composite @@ -66,7 +69,10 @@ runs: shell: pwsh run: |- Import-Module ./.github/workflows/GHWorkflowHelper/GHWorkflowHelper.psm1 - $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" + $headers = @{ + Authorization = "Bearer ${{ inputs.GITHUB_TOKEN }}" + } + $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" -Headers $headers $latestRelease = $releases | Where-Object { $v = $_.name.trim("v"); $semVer = [System.Management.Automation.SemanticVersion]::new($v); if ($semVer.Major -eq 3 -and $semVer.Minor -ge 2) { $_ } } | Select-Object -First 1 $latestVersion = $latestRelease.tag_name.TrimStart("v") Write-Host "Latest DSC Version: $latestVersion" @@ -80,7 +86,7 @@ runs: $tempPath = Get-GWTempPath - Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath/DSC.tar.gz" -Verbose + Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath/DSC.tar.gz" -Verbose -Headers $headers New-Item -ItemType Directory -Path "$tempPath/DSC" -Force -Verbose tar xvf "$tempPath/DSC.tar.gz" -C "$tempPath/DSC" $dscRoot = "$tempPath/DSC" diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index 1b2f6c56a6d..c2ff1bc8fb6 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -14,6 +14,9 @@ inputs: required: false default: ctrf type: string + GITHUB_TOKEN: + description: 'GitHub token for API authentication' + required: true runs: using: composite @@ -49,7 +52,10 @@ runs: shell: pwsh run: |- Import-Module .\.github\workflows\GHWorkflowHelper\GHWorkflowHelper.psm1 - $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" + $headers = @{ + Authorization = "Bearer ${{ inputs.GITHUB_TOKEN }}" + } + $releases = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/Dsc/releases" -Headers $headers $latestRelease = $releases | Where-Object { $v = $_.name.trim("v"); $semVer = [System.Management.Automation.SemanticVersion]::new($v); if ($semVer.Major -eq 3 -and $semVer.Minor -ge 2) { $_ } } | Select-Object -First 1 $latestVersion = $latestRelease.tag_name.TrimStart("v") Write-Host "Latest DSC Version: $latestVersion" @@ -57,7 +63,7 @@ runs: $downloadUrl = $latestRelease.assets | Where-Object { $_.name -like "DSC-*-x86_64-pc-windows-msvc.zip" } | Select-Object -First 1 | Select-Object -ExpandProperty browser_download_url Write-Host "Download URL: $downloadUrl" $tempPath = Get-GWTempPath - Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath\DSC.zip" + Invoke-RestMethod -Uri $downloadUrl -OutFile "$tempPath\DSC.zip" -Headers $headers $null = New-Item -ItemType Directory -Path "$tempPath\DSC" -Force Expand-Archive -Path "$tempPath\DSC.zip" -DestinationPath "$tempPath\DSC" -Force diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 41f1ffc43cd..b2c6d01f8cb 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -95,6 +95,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} linux_test_elevated_ci: name: Linux Elevated CI needs: @@ -112,6 +113,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} linux_test_unelevated_others: name: Linux Unelevated Others needs: @@ -129,6 +131,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} linux_test_elevated_others: name: Linux Elevated Others needs: @@ -146,6 +149,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} xunit_tests: name: xUnit Tests needs: diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 7ec1fc6da06..d6b333b6d55 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -92,6 +92,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} macos_test_elevated_ci: name: macOS Elevated CI needs: @@ -109,6 +110,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} macos_test_unelevated_others: name: macOS Unelevated Others needs: @@ -126,6 +128,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} macos_test_elevated_others: name: macOS Elevated Others needs: @@ -143,6 +146,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} xunit_tests: name: xUnit Tests needs: diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 37470475079..6b7b8e2d23a 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -96,6 +96,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} windows_test_elevated_ci: name: Windows Elevated CI needs: @@ -113,6 +114,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: CI + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} windows_test_unelevated_others: name: Windows Unelevated Others needs: @@ -130,6 +132,7 @@ jobs: with: purpose: UnelevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} windows_test_elevated_others: name: Windows Elevated Others needs: @@ -147,6 +150,7 @@ jobs: with: purpose: ElevatedPesterTests tagSet: Others + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} xunit_tests: name: xUnit Tests needs: From 3c517873ae532b11acdb14a2e9a169cf871531a4 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 20 Nov 2025 09:04:20 -0800 Subject: [PATCH 013/127] [release/v7.6] Replace fpm with native rpmbuild for RPM package generation (#26441) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../actions/test/linux-packaging/action.yml | 13 + .github/workflows/linux-ci.yml | 3 +- build.psm1 | 21 +- .../linux/package-validation.tests.ps1 | 91 +++++ tools/ci.psm1 | 26 +- tools/packaging/packaging.psm1 | 326 ++++++++++++++++-- 6 files changed, 440 insertions(+), 40 deletions(-) create mode 100644 test/packaging/linux/package-validation.tests.ps1 diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index 736bddfa7a7..b7bbdf37185 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -62,6 +62,9 @@ runs: # Create the artifacts staging directory New-Item -ItemType Directory -Path "$env:BUILD_ARTIFACTSTAGINGDIRECTORY" -Force | Out-Null + # Import packaging module to ensure RPM packaging changes are loaded + Import-Module ./build.psm1 -Force + Import-Module ./tools/packaging/packaging.psm1 -Force Import-Module ./tools/ci.psm1 Restore-PSOptions -PSOptionsPath '${{ runner.workspace }}/build/psoptions.json' $options = (Get-PSOptions) @@ -75,6 +78,16 @@ runs: Invoke-CIFinish shell: pwsh + - name: Validate Package Names + run: |- + # Run Pester tests to validate package names + Import-Module Pester -Force + $testResults = Invoke-Pester -Path ./test/packaging/linux/package-validation.tests.ps1 -PassThru + if ($testResults.FailedCount -gt 0) { + throw "Package validation tests failed" + } + shell: pwsh + - name: Upload deb packages uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index b2c6d01f8cb..78bbc62276d 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -53,6 +53,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout uses: actions/checkout@v5 @@ -239,7 +240,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.packagingChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout diff --git a/build.psm1 b/build.psm1 index 98d080ecc99..88878bdd635 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2401,11 +2401,24 @@ function Start-PSBootstrap { } # Install [fpm](https://github.com/jordansissel/fpm) + # Note: fpm is now only needed for DEB and macOS packages; RPM packages use rpmbuild directly if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { - Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" - Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" - Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" - Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" + # Install fpm on Debian-based systems, macOS, and Mariner (where DEB packages are built) + if (($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) -or $environment.IsMacOS) { + Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" + Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" + Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" + Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" + } + + # For RPM-based systems, ensure rpmbuild is available + if ($environment.IsLinux -and ($environment.IsRedHatFamily -or $environment.IsSUSEFamily -or $environment.IsMariner)) { + Write-Verbose -Verbose "Checking for rpmbuild..." + if (!(Get-Command rpmbuild -ErrorAction SilentlyContinue)) { + Write-Warning "rpmbuild not found. Installing rpm-build package..." + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y rpm-build")) -IgnoreExitcode + } + } } } diff --git a/test/packaging/linux/package-validation.tests.ps1 b/test/packaging/linux/package-validation.tests.ps1 new file mode 100644 index 00000000000..241863de45d --- /dev/null +++ b/test/packaging/linux/package-validation.tests.ps1 @@ -0,0 +1,91 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "Linux Package Name Validation" { + BeforeAll { + # Determine artifacts directory (GitHub Actions or Azure DevOps) + $artifactsDir = if ($env:GITHUB_ACTIONS -eq 'true') { + "$env:GITHUB_WORKSPACE/../packages" + } else { + $env:SYSTEM_ARTIFACTSDIRECTORY + } + + if (-not $artifactsDir) { + throw "Artifacts directory not found. GITHUB_WORKSPACE or SYSTEM_ARTIFACTSDIRECTORY must be set." + } + + Write-Verbose "Artifacts directory: $artifactsDir" -Verbose + } + + Context "RPM Package Names" { + It "Should have valid RPM package names" { + $rpmPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.rpm -ErrorAction SilentlyContinue + + if ($rpmPackages.Count -eq 0) { + Set-ItResult -Skipped -Because "No RPM packages found in artifacts directory" + return + } + + $invalidPackages = @() + # Regex pattern for valid RPM package names. + # Breakdown: + # ^powershell\- : Starts with 'powershell-' + # (preview-|lts-)? : Optionally 'preview-' or 'lts-' + # \d+\.\d+\.\d+ : Version number (e.g., 7.6.0) + # (_[a-z]*\.\d+)? : Optional underscore, letters, dot, and digits (e.g., _alpha.1) + # -1\. : Literal '-1.' + # (preview\.\d+\.)? : Optional 'preview.' and digits, followed by a dot + # (rh|cm)\. : Either 'rh.' or 'cm.' + # (x86_64|aarch64)\.rpm$ : Architecture and file extension + $rpmPackageNamePattern = 'powershell\-(preview-|lts-)?\d+\.\d+\.\d+(_[a-z]*\.\d+)?-1\.(preview\.\d+\.)?(rh|cm)\.(x86_64|aarch64)\.rpm' + + foreach ($package in $rpmPackages) { + if ($package.Name -notmatch $rpmPackageNamePattern) { + $invalidPackages += "$($package.Name) is not a valid RPM package name" + Write-Warning "$($package.Name) is not a valid RPM package name" + } + } + + if ($invalidPackages.Count -gt 0) { + throw ($invalidPackages | Out-String) + } + + $rpmPackages.Count | Should -BeGreaterThan 0 + } + } + + Context "Tar.Gz Package Names" { + It "Should have valid tar.gz package names" { + $tarPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.tar.gz -ErrorAction SilentlyContinue + + if ($tarPackages.Count -eq 0) { + Set-ItResult -Skipped -Because "No tar.gz packages found in artifacts directory" + return + } + + $invalidPackages = @() + foreach ($package in $tarPackages) { + # Pattern matches: powershell-7.6.0-preview.6-linux-x64.tar.gz or powershell-7.6.0-linux-x64.tar.gz + # Also matches various runtime configurations + if ($package.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?(linux|osx|linux-musl)+\-(x64\-fxdependent|x64|arm32|arm64|x64\-musl-noopt\-fxdependent)\.(tar\.gz)') { + $invalidPackages += "$($package.Name) is not a valid tar.gz package name" + Write-Warning "$($package.Name) is not a valid tar.gz package name" + } + } + + if ($invalidPackages.Count -gt 0) { + throw ($invalidPackages | Out-String) + } + + $tarPackages.Count | Should -BeGreaterThan 0 + } + } + + Context "Package Existence" { + It "Should find at least one package in artifacts directory" { + $allPackages = Get-ChildItem -Path $artifactsDir -Recurse -Include *.rpm, *.tar.gz, *.deb -ErrorAction SilentlyContinue + + $allPackages.Count | Should -BeGreaterThan 0 -Because "At least one package should exist in the artifacts directory" + } + } +} diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 7b13ded1811..9e95e68c843 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -874,16 +874,36 @@ function New-LinuxPackage $packageObj = $package } - Write-Log -message "Artifacts directory: ${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" - Copy-Item $packageObj.FullName -Destination "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" -Force + # Determine artifacts directory (GitHub Actions or Azure DevOps) + $artifactsDir = if ($env:GITHUB_ACTIONS -eq 'true') { + "${env:GITHUB_WORKSPACE}/../packages" + } else { + "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" + } + + # Ensure artifacts directory exists + if (-not (Test-Path $artifactsDir)) { + New-Item -ItemType Directory -Path $artifactsDir -Force | Out-Null + } + + Write-Log -message "Artifacts directory: $artifactsDir" + Copy-Item $packageObj.FullName -Destination $artifactsDir -Force } if ($IsLinux) { + # Determine artifacts directory (GitHub Actions or Azure DevOps) + $artifactsDir = if ($env:GITHUB_ACTIONS -eq 'true') { + "${env:GITHUB_WORKSPACE}/../packages" + } else { + "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" + } + # Create and package Raspbian .tgz + # Build must be clean for Raspbian Start-PSBuild -PSModuleRestore -Clean -Runtime linux-arm -Configuration 'Release' $armPackage = Start-PSPackage @packageParams -Type tar-arm -SkipReleaseChecks - Copy-Item $armPackage -Destination "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" -Force + Copy-Item $armPackage -Destination $artifactsDir -Force } } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 8e7fb3c4e08..894323a4b98 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1245,40 +1245,124 @@ function New-UnixPackage { # Setup package dependencies $Dependencies = @(Get-PackageDependencies @packageDependenciesParams) - $Arguments = @() - - - $Arguments += Get-FpmArguments ` - -Name $Name ` - -Version $packageVersion ` - -Iteration $Iteration ` - -Description $Description ` - -Type $Type ` - -Dependencies $Dependencies ` - -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` - -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` - -Staging $Staging ` - -Destination $Destination ` - -ManGzipFile $ManGzipInfo.GzipFile ` - -ManDestination $ManGzipInfo.ManFile ` - -LinkInfo $Links ` - -AppsFolder $AppsFolder ` - -Distribution $DebDistro ` - -HostArchitecture $HostArchitecture ` - -ErrorAction Stop - # Build package try { - if ($PSCmdlet.ShouldProcess("Create $type package")) { - Write-Log "Creating package with fpm $Arguments..." - try { - $Output = Start-NativeExecution { fpm $Arguments } + if ($Type -eq 'rpm') { + # Use rpmbuild directly for RPM packages + if ($PSCmdlet.ShouldProcess("Create RPM package with rpmbuild")) { + Write-Log "Creating RPM package with rpmbuild..." + + # Create rpmbuild directory structure + $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" + $specsDir = Join-Path $rpmBuildRoot "SPECS" + $rpmsDir = Join-Path $rpmBuildRoot "RPMS" + + New-Item -ItemType Directory -Path $specsDir -Force | Out-Null + New-Item -ItemType Directory -Path $rpmsDir -Force | Out-Null + + # Generate RPM spec file + $specContent = New-RpmSpec ` + -Name $Name ` + -Version $packageVersion ` + -Iteration $Iteration ` + -Description $Description ` + -Dependencies $Dependencies ` + -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` + -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` + -Staging $Staging ` + -Destination $Destination ` + -ManGzipFile $ManGzipInfo.GzipFile ` + -ManDestination $ManGzipInfo.ManFile ` + -LinkInfo $Links ` + -Distribution $DebDistro ` + -HostArchitecture $HostArchitecture + + $specFile = Join-Path $specsDir "$Name.spec" + $specContent | Out-File -FilePath $specFile -Encoding ascii + Write-Verbose "Generated spec file: $specFile" -Verbose + + # Log the spec file content + if ($env:GITHUB_ACTIONS -eq 'true') { + Write-Host "::group::RPM Spec File Content" + Write-Host $specContent + Write-Host "::endgroup::" + } else { + Write-Verbose "RPM Spec File Content:`n$specContent" -Verbose + } + + # Build RPM package + try { + # Use bash to properly handle rpmbuild arguments + # Add --target for cross-architecture builds + $targetArch = "" + if ($HostArchitecture -ne "x86_64" -and $HostArchitecture -ne "noarch") { + $targetArch = "--target $HostArchitecture" + } + $buildCmd = "rpmbuild -bb --quiet $targetArch --define '_topdir $rpmBuildRoot' --buildroot '$rpmBuildRoot/BUILDROOT' '$specFile'" + Write-Verbose "Running: $buildCmd" -Verbose + $Output = bash -c $buildCmd 2>&1 + $exitCode = $LASTEXITCODE + + if ($exitCode -ne 0) { + throw "rpmbuild failed with exit code $exitCode" + } + + # Find the generated RPM + $rpmFile = Get-ChildItem -Path (Join-Path $rpmsDir $HostArchitecture) -Filter "*.rpm" -ErrorAction Stop | + Sort-Object -Property LastWriteTime -Descending | + Select-Object -First 1 + + if ($rpmFile) { + # Copy RPM to current location + Copy-Item -Path $rpmFile.FullName -Destination $CurrentLocation -Force + $Output = @("Created package {:path=>""$($rpmFile.Name)""}") + } else { + throw "RPM file not found after build" + } + } + catch { + Write-Verbose -Message "!!!Handling error in rpmbuild!!!" -Verbose -ErrorAction SilentlyContinue + if ($Output) { + Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue + } + Get-Error -InputObject $_ + throw + } } - catch { - Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue - Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue - Get-Error -InputObject $_ - throw + } else { + # Use fpm for DEB and macOS packages + $Arguments = @() + + $Arguments += Get-FpmArguments ` + -Name $Name ` + -Version $packageVersion ` + -Iteration $Iteration ` + -Description $Description ` + -Type $Type ` + -Dependencies $Dependencies ` + -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` + -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` + -Staging $Staging ` + -Destination $Destination ` + -ManGzipFile $ManGzipInfo.GzipFile ` + -ManDestination $ManGzipInfo.ManFile ` + -LinkInfo $Links ` + -AppsFolder $AppsFolder ` + -Distribution $DebDistro ` + -HostArchitecture $HostArchitecture ` + -ErrorAction Stop + + if ($PSCmdlet.ShouldProcess("Create $type package")) { + Write-Log "Creating package with fpm $Arguments..." + try { + $Output = Start-NativeExecution { fpm $Arguments } + } + catch { + Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue + Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue + Get-Error -InputObject $_ + throw + } } } } finally { @@ -1295,6 +1379,16 @@ function New-UnixPackage { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo mv $hack_dest $symlink_dest")) -VerboseOutputOnError } } + + # Clean up rpmbuild directory if it was created + if ($Type -eq 'rpm') { + $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" + if (Test-Path $rpmBuildRoot) { + Write-Verbose "Cleaning up rpmbuild directory: $rpmBuildRoot" -Verbose + Remove-Item -Path $rpmBuildRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + if ($AfterScriptInfo.AfterInstallScript) { Remove-Item -ErrorAction 'silentlycontinue' $AfterScriptInfo.AfterInstallScript -Force } @@ -1439,6 +1533,165 @@ Class LinkInfo [string] $Destination } +function New-RpmSpec +{ + param( + [Parameter(Mandatory,HelpMessage='Package Name')] + [String]$Name, + + [Parameter(Mandatory,HelpMessage='Package Version')] + [String]$Version, + + [Parameter(Mandatory)] + [String]$Iteration, + + [Parameter(Mandatory,HelpMessage='Package description')] + [String]$Description, + + [Parameter(Mandatory,HelpMessage='Staging folder for installation files')] + [String]$Staging, + + [Parameter(Mandatory,HelpMessage='Install path on target machine')] + [String]$Destination, + + [Parameter(Mandatory,HelpMessage='The built and gzipped man file.')] + [String]$ManGzipFile, + + [Parameter(Mandatory,HelpMessage='The destination of the man file')] + [String]$ManDestination, + + [Parameter(Mandatory,HelpMessage='Symlink to powershell executable')] + [LinkInfo[]]$LinkInfo, + + [Parameter(Mandatory,HelpMessage='Packages required to install this package')] + [String[]]$Dependencies, + + [Parameter(Mandatory,HelpMessage='Script to run after the package installation.')] + [String]$AfterInstallScript, + + [Parameter(Mandatory,HelpMessage='Script to run after the package removal.')] + [String]$AfterRemoveScript, + + [String]$Distribution = 'rhel.7', + [string]$HostArchitecture + ) + + # RPM doesn't allow hyphens in version, so convert them to underscores + # e.g., "7.6.0-preview.6" becomes Version: 7.6.0_preview.6 + $rpmVersion = $Version -replace '-', '_' + + # Build Release field with distribution suffix (e.g., "1.cm" or "1.rh") + # Don't use RPM macros - build the full release string in PowerShell + $rpmRelease = "$Iteration.$Distribution" + + $specContent = @" +# RPM spec file for PowerShell +# Generated by PowerShell build system + +Name: $Name +Version: $rpmVersion +Release: $rpmRelease +Summary: PowerShell - Cross-platform automation and configuration tool/framework +License: MIT +URL: https://microsoft.com/powershell +AutoReq: no + +"@ + + # Only add BuildArch if not doing cross-architecture build + # For cross-arch builds, we'll rely on --target option + if ($HostArchitecture -eq "x86_64" -or $HostArchitecture -eq "noarch") { + $specContent += "BuildArch: $HostArchitecture`n`n" + } else { + # For cross-architecture builds, don't specify BuildArch in spec + # The --target option will handle the architecture + + # Disable automatic binary stripping for cross-arch builds + # The native /bin/strip on x86_64 cannot process ARM64 binaries and would fail with: + # "Unable to recognise the format of the input file" + # See: https://rpm-software-management.github.io/rpm/manual/macros.html + # __strip: This macro controls the command used for stripping binaries during the build process. + # /bin/true: A command that does nothing and always exits successfully, effectively bypassing the stripping process. + $specContent += "%define __strip /bin/true`n" + + # Disable debug package generation to prevent strip-related errors + # Debug packages require binary stripping which fails for cross-arch builds + # See: https://rpm-packaging-guide.github.io/#debugging + # See: https://docs.fedoraproject.org/en-US/packaging-guidelines/Debuginfo/#_useless_or_incomplete_debuginfo_packages_due_to_other_reasons + $specContent += "%global debug_package %{nil}`n`n" + } + + # Add dependencies + foreach ($dep in $Dependencies) { + $specContent += "Requires: $dep`n" + } + + $specContent += @" + +%description +$Description + +%prep +# No prep needed - files are already staged + +%build +# No build needed - binaries are pre-built + +%install +rm -rf `$RPM_BUILD_ROOT +mkdir -p `$RPM_BUILD_ROOT$Destination +mkdir -p `$RPM_BUILD_ROOT$(Split-Path -Parent $ManDestination) + +# Copy all files from staging to destination +cp -r $Staging/* `$RPM_BUILD_ROOT$Destination/ + +# Copy man page +cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination + +"@ + + # Add symlinks - we need to get the target of the temp symlink + foreach ($link in $LinkInfo) { + $linkDir = Split-Path -Parent $link.Destination + $specContent += "mkdir -p `$RPM_BUILD_ROOT$linkDir`n" + # For RPM, we copy the symlink itself (which fpm does by including it in the source) + # The symlink at $link.Source points to the actual target, so we'll copy it + # The -P flag preserves symlinks rather than copying their targets, which is critical for this operation. + $specContent += "cp -P $($link.Source) `$RPM_BUILD_ROOT$($link.Destination)`n" + } + + # Post-install script + $postInstallContent = Get-Content -Path $AfterInstallScript -Raw + $specContent += "`n%post`n" + $specContent += $postInstallContent + $specContent += "`n" + + # Post-uninstall script + $postUninstallContent = Get-Content -Path $AfterRemoveScript -Raw + $specContent += "%postun`n" + $specContent += $postUninstallContent + $specContent += "`n" + + # Files section + $specContent += "%files`n" + $specContent += "%defattr(-,root,root,-)`n" + $specContent += "$Destination/*`n" + $specContent += "$ManDestination`n" + + # Add symlinks to files + foreach ($link in $LinkInfo) { + $specContent += "$($link.Destination)`n" + } + + # Changelog with correct date format for RPM + $changelogDate = Get-Date -Format "ddd MMM dd yyyy" + $specContent += "`n%changelog`n" + $specContent += "* $changelogDate PowerShell Team - $rpmVersion-$rpmRelease`n" + $specContent += "- Automated build`n" + + return $specContent +} + function Get-FpmArguments { param( @@ -1651,7 +1904,16 @@ function Get-PackageDependencies function Test-Dependencies { - foreach ($Dependency in "fpm") { + # Note: RPM packages no longer require fpm; they use rpmbuild directly + # DEB packages still use fpm + $Dependencies = @() + + # Only check for fpm on Debian-based systems + if ($Environment.IsDebianFamily) { + $Dependencies += "fpm" + } + + foreach ($Dependency in $Dependencies) { if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { # These tools are not added to the path automatically on OpenSUSE 13.2 # try adding them to the path and re-tesing first From 0e83f60c0e8c57783c809d5e3be0af22073c1253 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 20 Nov 2025 09:04:33 -0800 Subject: [PATCH 014/127] [release/v7.6] Refactor analyze job to reusable workflow and enable on Windows CI (#26494) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .github/workflows/analyze-reusable.yml | 76 ++++++++++++++++++++++++++ .github/workflows/linux-ci.yml | 63 +++------------------ .github/workflows/windows-ci.yml | 12 ++++ tools/ci.psm1 | 7 ++- 4 files changed, 102 insertions(+), 56 deletions(-) create mode 100644 .github/workflows/analyze-reusable.yml diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml new file mode 100644 index 00000000000..1797e2234a6 --- /dev/null +++ b/.github/workflows/analyze-reusable.yml @@ -0,0 +1,76 @@ +name: CodeQL Analysis (Reusable) + +on: + workflow_call: + inputs: + runner_os: + description: 'Runner OS for CodeQL analysis' + type: string + required: false + default: ubuntu-latest + +permissions: + actions: read # for github/codeql-action/init to get workflow details + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/analyze to upload SARIF results + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_NOLOGO: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + __SuppressAnsiEscapeSequences: 1 + nugetMultiFeedWarnLevel: none + +jobs: + analyze: + name: Analyze + runs-on: ${{ inputs.runner_os }} + + strategy: + fail-fast: false + matrix: + # Override automatic language detection by changing the below list + # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] + language: ['csharp'] + # Learn more... + # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection + + steps: + - name: Checkout repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: '0' + + - uses: actions/setup-dotnet@v5 + with: + global-json-file: ./global.json + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + - run: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + name: Capture Environment + shell: pwsh + + - run: | + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + name: Bootstrap + shell: pwsh + + - run: | + Import-Module .\tools\ci.psm1 + Invoke-CIBuild -Configuration 'StaticAnalysis' + name: Build + shell: pwsh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 78bbc62276d..94829ac2a64 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -163,63 +163,16 @@ jobs: ## Temporarily disable the CodeQL analysis on Linux as it doesn't work for .NET SDK 10-rc.2. # analyze: - # permissions: - # actions: read # for github/codeql-action/init to get workflow details - # contents: read # for actions/checkout to fetch code - # security-events: write # for github/codeql-action/analyze to upload SARIF results - # name: Analyze - # runs-on: ubuntu-latest + # name: CodeQL Analysis # needs: changes # if: ${{ needs.changes.outputs.source == 'true' }} - # - # strategy: - # fail-fast: false - # matrix: - # # Override automatic language detection by changing the below list - # # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - # language: ['csharp'] - # # Learn more... - # # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection - # - # steps: - # - name: Checkout repository - # uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - # with: - # fetch-depth: '0' - # - # - uses: actions/setup-dotnet@v5 - # with: - # global-json-file: ./global.json - # - # # Initializes the CodeQL tools for scanning. - # - name: Initialize CodeQL - # uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 - # with: - # languages: ${{ matrix.language }} - # # If you wish to specify custom queries, you can do so here or in a config file. - # # By default, queries listed here will override any specified in a config file. - # # Prefix the list here with "+" to use these queries and those in the config file. - # # queries: ./path/to/local/query, your-org/your-repo/queries@main - # - # - run: | - # Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - # name: Capture Environment - # shell: pwsh - # - # - run: | - # Import-Module .\tools\ci.psm1 - # Invoke-CIInstall -SkipUser - # name: Bootstrap - # shell: pwsh - # - # - run: | - # Import-Module .\tools\ci.psm1 - # Invoke-CIBuild - # name: Build - # shell: pwsh - # - # - name: Perform CodeQL Analysis - # uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 + # uses: ./.github/workflows/analyze-reusable.yml + # permissions: + # actions: read + # contents: read + # security-events: write + # with: + # runner_os: ubuntu-latest ready_to_merge: name: Linux ready to merge diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 6b7b8e2d23a..c21c319ec95 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -160,6 +160,17 @@ jobs: with: runner_os: windows-latest test_results_artifact_name: testResults-xunit + analyze: + name: CodeQL Analysis + needs: changes + if: ${{ needs.changes.outputs.source == 'true' }} + uses: ./.github/workflows/analyze-reusable.yml + permissions: + actions: read + contents: read + security-events: write + with: + runner_os: windows-latest windows_packaging: name: Windows Packaging needs: @@ -174,6 +185,7 @@ jobs: - windows_test_elevated_others - windows_test_unelevated_ci - windows_test_unelevated_others + - analyze - windows_packaging if: always() uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 9e95e68c843..44651c26109 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -101,6 +101,11 @@ function Invoke-CIFull # Implements the CI 'build_script' step function Invoke-CIBuild { + param( + [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis')] + [string]$Configuration = 'Release' + ) + $releaseTag = Get-ReleaseTag # check to be sure our test tags are correct $result = Get-PesterTag @@ -115,7 +120,7 @@ function Invoke-CIBuild Start-PSBuild -Configuration 'CodeCoverage' -PSModuleRestore -CI -ReleaseTag $releaseTag } - Start-PSBuild -PSModuleRestore -Configuration 'Release' -CI -ReleaseTag $releaseTag -UseNuGetOrg + Start-PSBuild -PSModuleRestore -Configuration $Configuration -CI -ReleaseTag $releaseTag -UseNuGetOrg Save-PSOptions $options = (Get-PSOptions) From ce725ce20796ec5ebd5fac9149bc3d7ee1ea898d Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 20 Nov 2025 13:50:38 -0800 Subject: [PATCH 015/127] [release/v7.6] Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26501) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- .../instructions/build-configuration-guide.md | 48 ++- .../start-native-execution.instructions.md | 149 ++++++++ .github/workflows/macos-ci.yml | 55 ++- docs/maintainers/releasing.md | 17 +- tools/packaging/packaging.psm1 | 360 ++++++++++++++---- .../releaseTests/macOSPackage.tests.ps1 | 162 ++++++++ 6 files changed, 705 insertions(+), 86 deletions(-) create mode 100644 .github/instructions/start-native-execution.instructions.md create mode 100644 tools/packaging/releaseTests/macOSPackage.tests.ps1 diff --git a/.github/instructions/build-configuration-guide.md b/.github/instructions/build-configuration-guide.md index d082bcbe774..c31f8139c62 100644 --- a/.github/instructions/build-configuration-guide.md +++ b/.github/instructions/build-configuration-guide.md @@ -27,13 +27,15 @@ ### For Release/Packaging -**Use: Release with version tag** +**Use: Release with version tag and public NuGet feeds** ```yaml - name: Build for Release shell: pwsh run: | + Import-Module ./build.psm1 Import-Module ./tools/ci.psm1 + Switch-PSNugetConfig -Source Public $releaseTag = Get-ReleaseTag Start-PSBuild -Configuration 'Release' -ReleaseTag $releaseTag ``` @@ -43,6 +45,11 @@ - No debug symbols (smaller size) - Production-ready +**Why Switch-PSNugetConfig -Source Public:** +- Switches NuGet package sources to public feeds (nuget.org and public Azure DevOps feeds) +- Required for CI/CD environments that don't have access to private feeds +- Uses publicly available packages instead of Microsoft internal feeds + ### For Code Coverage **Use: CodeCoverage configuration** @@ -93,3 +100,42 @@ src/powershell-win-core/bin/Debug///publish/ 3. Match configuration to purpose 4. Use `-CI` only when needed 5. Always specify `-ReleaseTag` for release or packaging builds +6. Use `Switch-PSNugetConfig -Source Public` in CI/CD for release builds + +## NuGet Feed Configuration + +### Switch-PSNugetConfig + +The `Switch-PSNugetConfig` function in `build.psm1` manages NuGet package source configuration. + +**Available Sources:** + +- **Public**: Uses public feeds (nuget.org and public Azure DevOps feeds) + - Required for: CI/CD environments, public builds, packaging + - Does not require authentication + +- **Private**: Uses internal PowerShell team feeds + - Required for: Internal development with preview packages + - Requires authentication credentials + +- **NuGetOnly**: Uses only nuget.org + - Required for: Minimal dependency scenarios + +**Usage:** + +```powershell +# Switch to public feeds (most common for CI/CD) +Switch-PSNugetConfig -Source Public + +# Switch to private feeds with authentication +Switch-PSNugetConfig -Source Private -UserName $userName -ClearTextPAT $pat + +# Switch to nuget.org only +Switch-PSNugetConfig -Source NuGetOnly +``` + +**When to Use:** + +- **Always use `-Source Public`** before building in CI/CD workflows +- Use before any build that will create packages for distribution +- Use in forks or environments without access to Microsoft internal feeds diff --git a/.github/instructions/start-native-execution.instructions.md b/.github/instructions/start-native-execution.instructions.md new file mode 100644 index 00000000000..347e496b3bf --- /dev/null +++ b/.github/instructions/start-native-execution.instructions.md @@ -0,0 +1,149 @@ +--- +applyTo: + - "**/*.ps1" + - "**/*.psm1" +--- + +# Using Start-NativeExecution for Native Command Execution + +## Purpose + +`Start-NativeExecution` is the standard function for executing native commands (external executables) in PowerShell scripts within this repository. It provides consistent error handling and better diagnostics when native commands fail. + +## When to Use + +Use `Start-NativeExecution` whenever you need to: +- Execute external commands (e.g., `git`, `dotnet`, `pkgbuild`, `productbuild`, `fpm`, `rpmbuild`) +- Ensure proper exit code checking +- Get better error messages with caller information +- Handle verbose output on error + +## Basic Usage + +```powershell +Start-NativeExecution { + git clone https://github.com/PowerShell/PowerShell.git +} +``` + +## With Parameters + +Use backticks for line continuation within the script block: + +```powershell +Start-NativeExecution { + pkgbuild --root $pkgRoot ` + --identifier $pkgIdentifier ` + --version $Version ` + --scripts $scriptsDir ` + $outputPath +} +``` + +## Common Parameters + +### -VerboseOutputOnError + +Captures command output and displays it only if the command fails: + +```powershell +Start-NativeExecution -VerboseOutputOnError { + dotnet build --configuration Release +} +``` + +### -IgnoreExitcode + +Allows the command to fail without throwing an exception: + +```powershell +Start-NativeExecution -IgnoreExitcode { + git diff --exit-code # Returns 1 if differences exist +} +``` + +## Availability + +The function is defined in `tools/buildCommon/startNativeExecution.ps1` and is available in: +- `build.psm1` (dot-sourced automatically) +- `tools/packaging/packaging.psm1` (dot-sourced automatically) +- Test modules that include `HelpersCommon.psm1` + +To use in other scripts, dot-source the function: + +```powershell +. "$PSScriptRoot/../buildCommon/startNativeExecution.ps1" +``` + +## Error Handling + +When a native command fails (non-zero exit code), `Start-NativeExecution`: +1. Captures the exit code +2. Identifies the calling location (file and line number) +3. Throws a descriptive error with full context + +Example error message: +``` +Execution of {git clone ...} by /path/to/script.ps1: line 42 failed with exit code 1 +``` + +## Examples from the Codebase + +### Git Operations +```powershell +Start-NativeExecution { + git fetch --tags --quiet upstream +} +``` + +### Build Operations +```powershell +Start-NativeExecution -VerboseOutputOnError { + dotnet publish --configuration Release +} +``` + +### Packaging Operations +```powershell +Start-NativeExecution -VerboseOutputOnError { + pkgbuild --root $pkgRoot --identifier $pkgId --version $version $outputPath +} +``` + +### Permission Changes +```powershell +Start-NativeExecution { + find $staging -type d | xargs chmod 755 + find $staging -type f | xargs chmod 644 +} +``` + +## Anti-Patterns + +**Don't do this:** +```powershell +& somecommand $args +if ($LASTEXITCODE -ne 0) { + throw "Command failed" +} +``` + +**Do this instead:** +```powershell +Start-NativeExecution { + somecommand $args +} +``` + +## Best Practices + +1. **Always use Start-NativeExecution** for native commands to ensure consistent error handling +2. **Use -VerboseOutputOnError** for commands with useful diagnostic output +3. **Use backticks for readability** when commands have multiple arguments +4. **Don't capture output unnecessarily** - let the function handle it +5. **Use -IgnoreExitcode sparingly** - only when non-zero exit codes are expected and acceptable + +## Related Documentation + +- Source: `tools/buildCommon/startNativeExecution.ps1` +- Blog post: https://mnaoumov.wordpress.com/2015/01/11/execution-of-external-commands-in-powershell-done-right/ diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index d6b333b6d55..847d1e01cd0 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -157,7 +157,7 @@ jobs: runner_os: macos-15-large test_results_artifact_name: testResults-xunit PackageMac-macos_packaging: - name: macOS packaging (bootstrap only) + name: macOS packaging and testing needs: - changes if: ${{ needs.changes.outputs.source == 'true' }} @@ -166,12 +166,63 @@ jobs: steps: - name: checkout uses: actions/checkout@v5 + with: + fetch-depth: 1000 + - uses: actions/setup-dotnet@v4 + with: + global-json-file: ./global.json - name: Bootstrap packaging - if: success() || failure() + if: success() run: |- import-module ./build.psm1 start-psbootstrap -Scenario package shell: pwsh + - name: Build PowerShell and Create macOS package + if: success() + run: |- + import-module ./build.psm1 + import-module ./tools/ci.psm1 + import-module ./tools/packaging/packaging.psm1 + Switch-PSNugetConfig -Source Public + Sync-PSTags -AddRemoteIfMissing + $releaseTag = Get-ReleaseTag + Start-PSBuild -Configuration Release -PSModuleRestore -ReleaseTag $releaseTag + $macOSRuntime = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'osx-arm64' } else { 'osx-x64' } + Start-PSPackage -Type osxpkg -ReleaseTag $releaseTag -MacOSRuntime $macOSRuntime -SkipReleaseChecks + shell: pwsh + - name: Test package contents + if: success() + run: |- + $env:PACKAGE_FOLDER = Get-Location + $testResultsPath = Join-Path $env:RUNNER_WORKSPACE "testResults" + if (-not (Test-Path $testResultsPath)) { + New-Item -ItemType Directory -Path $testResultsPath -Force | Out-Null + } + Import-Module Pester + $pesterConfig = New-PesterConfiguration + $pesterConfig.Run.Path = './tools/packaging/releaseTests/macOSPackage.tests.ps1' + $pesterConfig.Run.PassThru = $true + $pesterConfig.Output.Verbosity = 'Detailed' + $pesterConfig.TestResult.Enabled = $true + $pesterConfig.TestResult.OutputFormat = 'NUnitXml' + $pesterConfig.TestResult.OutputPath = Join-Path $testResultsPath "macOSPackage.xml" + $result = Invoke-Pester -Configuration $pesterConfig + if ($result.FailedCount -gt 0) { + throw "Package validation failed with $($result.FailedCount) failed test(s)" + } + shell: pwsh + - name: Publish and Upload Pester Test Results + if: always() + uses: "./.github/actions/test/process-pester-results" + with: + name: "macOSPackage" + testResultsFolder: "${{ runner.workspace }}/testResults" + - name: Upload package artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: macos-package + path: "*.pkg" ready_to_merge: name: macos ready to merge needs: diff --git a/docs/maintainers/releasing.md b/docs/maintainers/releasing.md index 5aae87582c9..3562962e68f 100644 --- a/docs/maintainers/releasing.md +++ b/docs/maintainers/releasing.md @@ -72,11 +72,18 @@ The output of `Start-PSBuild` includes a `powershell.exe` executable which can s #### Linux / macOS The `Start-PSPackage` function delegates to `New-UnixPackage`. -It relies on the [Effing Package Management][fpm] project, -which makes building packages for any (non-Windows) platform a breeze. -Similarly, the PowerShell man-page is generated from the Markdown-like file + +For **Linux** (Debian-based distributions), it relies on the [Effing Package Management][fpm] project, +which makes building packages a breeze. + +For **macOS**, it uses native packaging tools (`pkgbuild` and `productbuild`) from Xcode Command Line Tools, +eliminating the need for Ruby or fpm. + +For **Linux** (Red Hat-based distributions), it uses `rpmbuild` directly. + +The PowerShell man-page is generated from the Markdown-like file [`assets/pwsh.1.ronn`][man] using [Ronn][]. -The function `Start-PSBootstrap -Package` will install both these tools. +The function `Start-PSBootstrap -Package` will install these tools. To modify any property of the packages, edit the `New-UnixPackage` function. Please also refer to the function for details on the package properties @@ -131,7 +138,7 @@ Without `-Name` specified, the primary `powershell` package will instead be created. [fpm]: https://github.com/jordansissel/fpm -[man]: ../../assets/pwsh.1.ronn +[man]: ../../assets/manpage/pwsh.1.ronn [ronn]: https://github.com/rtomayko/ronn ### Build and Packaging Examples diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 894323a4b98..35ba148face 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. +. "$PSScriptRoot\..\buildCommon\startNativeExecution.ps1" + $Environment = Get-EnvironmentInformation $RepoRoot = (Resolve-Path -Path "$PSScriptRoot/../..").Path @@ -1197,19 +1199,7 @@ function New-UnixPackage { # Generate After Install and After Remove scripts $AfterScriptInfo = New-AfterScripts -Link $Link -Distribution $DebDistro -Destination $Destination - # there is a weird bug in fpm - # if the target of the powershell symlink exists, `fpm` aborts - # with a `utime` error on macOS. - # so we move it to make symlink broken - # refers to executable, does not vary by channel - $symlink_dest = "$Destination/pwsh" - $hack_dest = "./_fpm_symlink_hack_powershell" - if ($Environment.IsMacOS) { - if (Test-Path $symlink_dest) { - Write-Warning "Move $symlink_dest to $hack_dest (fpm utime bug)" - Start-NativeExecution ([ScriptBlock]::Create("$sudo mv $symlink_dest $hack_dest")) - } - } + # Note: The fpm symlink workaround is no longer needed with native macOS packaging tools # Generate gzip of man file $ManGzipInfo = New-ManGzip -IsPreview:$IsPreview -IsLTS:$LTS @@ -1329,8 +1319,38 @@ function New-UnixPackage { throw } } + } elseif ($Type -eq 'osxpkg') { + # Use native macOS packaging tools + if ($PSCmdlet.ShouldProcess("Create macOS package with pkgbuild/productbuild")) { + Write-Log "Creating macOS package with native tools..." + + $macPkgArgs = @{ + Name = $Name + Version = $packageVersion + Iteration = $Iteration + Staging = $Staging + Destination = $Destination + ManGzipFile = $ManGzipInfo.GzipFile + ManDestination = $ManGzipInfo.ManFile + LinkInfo = $Links + AfterInstallScript = $AfterScriptInfo.AfterInstallScript + AppsFolder = $AppsFolder + HostArchitecture = $HostArchitecture + CurrentLocation = $CurrentLocation + } + + try { + $packageFile = New-MacOSPackage @macPkgArgs + $Output = @("Created package {:path=>""$($packageFile.Name)""}") + } + catch { + Write-Verbose -Message "!!!Handling error in macOS packaging!!!" -Verbose -ErrorAction SilentlyContinue + Get-Error -InputObject $_ + throw + } + } } else { - # Use fpm for DEB and macOS packages + # Use fpm for DEB packages $Arguments = @() $Arguments += Get-FpmArguments ` @@ -1372,12 +1392,6 @@ function New-UnixPackage { { Clear-MacOSLauncher } - - # this is continuation of a fpm hack for a weird bug - if (Test-Path $hack_dest) { - Write-Warning "Move $hack_dest to $symlink_dest (fpm utime bug)" - Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo mv $hack_dest $symlink_dest")) -VerboseOutputOnError - } } # Clean up rpmbuild directory if it was created @@ -1401,12 +1415,9 @@ function New-UnixPackage { # Magic to get path output $createdPackage = Get-Item (Join-Path $CurrentLocation (($Output[-1] -split ":path=>")[-1] -replace '["{}]')) - if ($Environment.IsMacOS) { - if ($PSCmdlet.ShouldProcess("Add distribution information and Fix PackageName")) - { - $createdPackage = New-MacOsDistributionPackage -FpmPackage $createdPackage -HostArchitecture $HostArchitecture -IsPreview:$IsPreview - } - } + # For macOS with native tools, the package is already in the correct format + # For macOS with fpm (no longer used), we would need New-MacOsDistributionPackage + # For other platforms, the package name from fpm/rpmbuild is sufficient if (Test-Path $createdPackage) { @@ -1451,14 +1462,27 @@ Function New-LinkInfo function New-MacOsDistributionPackage { + [CmdletBinding(SupportsShouldProcess=$true)] param( - [Parameter(Mandatory,HelpMessage='The FileInfo of the file created by FPM')] - [System.IO.FileInfo]$FpmPackage, + [Parameter(Mandatory,HelpMessage='The FileInfo of the component package')] + [System.IO.FileInfo]$ComponentPackage, + + [Parameter(Mandatory,HelpMessage='Package name for the output file')] + [string]$PackageName, + + [Parameter(Mandatory,HelpMessage='Package version')] + [string]$Version, + + [Parameter(Mandatory,HelpMessage='Output directory for the final package')] + [string]$OutputDirectory, [Parameter(HelpMessage='x86_64 for Intel or arm64 for Apple Silicon')] [ValidateSet("x86_64", "arm64")] [string] $HostArchitecture = "x86_64", + [Parameter(HelpMessage='Package identifier')] + [string]$PackageIdentifier, + [Switch] $IsPreview ) @@ -1467,64 +1491,81 @@ function New-MacOsDistributionPackage throw 'New-MacOsDistributionPackage is only supported on macOS!' } - $packageName = Split-Path -Leaf -Path $FpmPackage - # Create a temp directory to store the needed files $tempDir = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName()) New-Item -ItemType Directory -Path $tempDir -Force > $null $resourcesDir = Join-Path -Path $tempDir -ChildPath 'resources' New-Item -ItemType Directory -Path $resourcesDir -Force > $null - #Copy background file to temp directory + + # Copy background file to temp directory $backgroundFile = "$RepoRoot/assets/macDialog.png" - Copy-Item -Path $backgroundFile -Destination $resourcesDir - # Move the current package to the temp directory - $tempPackagePath = Join-Path -Path $tempDir -ChildPath $packageName - Move-Item -Path $FpmPackage -Destination $tempPackagePath -Force - - # Add the OS information to the macOS package file name. - $packageExt = [System.IO.Path]::GetExtension($FpmPackage.Name) - - # get the package name from fpm without the extension, but replace powershell-preview at the beginning of the name with powershell. - $packageNameWithoutExt = [System.IO.Path]::GetFileNameWithoutExtension($FpmPackage.Name) -replace '^powershell\-preview' , 'powershell' - - $newPackageName = "{0}-{1}{2}" -f $packageNameWithoutExt, $script:Options.Runtime, $packageExt - $newPackagePath = Join-Path $FpmPackage.DirectoryName $newPackageName - - # -Force is not deleting the NewName if it exists, so delete it if it does - if ($Force -and (Test-Path -Path $newPackagePath)) - { - Remove-Item -Force $newPackagePath + if (Test-Path $backgroundFile) { + Copy-Item -Path $backgroundFile -Destination $resourcesDir -Force } + + # Copy the component package to temp directory + $componentFileName = Split-Path -Leaf -Path $ComponentPackage + $tempComponentPath = Join-Path -Path $tempDir -ChildPath $componentFileName + Copy-Item -Path $ComponentPackage -Destination $tempComponentPath -Force # Create the distribution xml $distributionXmlPath = Join-Path -Path $tempDir -ChildPath 'powershellDistribution.xml' - $packageId = Get-MacOSPackageId -IsPreview:$IsPreview.IsPresent + # Get package ID if not provided + if (-not $PackageIdentifier) { + $PackageIdentifier = Get-MacOSPackageId -IsPreview:$IsPreview.IsPresent + } + # Minimum OS version + $minOSVersion = "11.0" # macOS Big Sur minimum + # format distribution template with: # 0 - title # 1 - version - # 2 - package path + # 2 - package path (component package filename) # 3 - minimum os version # 4 - Package Identifier # 5 - host architecture (x86_64 for Intel or arm64 for Apple Silicon) - $PackagingStrings.OsxDistributionTemplate -f "PowerShell - $packageVersion", $packageVersion, $packageName, '10.14', $packageId, $HostArchitecture | Out-File -Encoding ascii -FilePath $distributionXmlPath -Force + $PackagingStrings.OsxDistributionTemplate -f $PackageName, $Version, $componentFileName, $minOSVersion, $PackageIdentifier, $HostArchitecture | Out-File -Encoding utf8 -FilePath $distributionXmlPath -Force - Write-Log "Applying distribution.xml to package..." - Push-Location $tempDir - try - { - # productbuild is an xcode command line tool, and those tools are installed when you install brew - Start-NativeExecution -sb {productbuild --distribution $distributionXmlPath --resources $resourcesDir $newPackagePath} -VerboseOutputOnError + # Build final package path + $finalPackagePath = Join-Path $OutputDirectory "$PackageName-$Version-osx-$HostArchitecture.pkg" + + # Remove existing package if it exists + if (Test-Path $finalPackagePath) { + Write-Warning "Removing existing package: $finalPackagePath" + Remove-Item $finalPackagePath -Force } - finally - { - Pop-Location - Remove-Item -Path $tempDir -Recurse -Force + + if ($PSCmdlet.ShouldProcess("Build product package with productbuild")) { + Write-Log "Applying distribution.xml to package..." + Push-Location $tempDir + try + { + # productbuild is an xcode command line tool + Start-NativeExecution -VerboseOutputOnError { + productbuild --distribution $distributionXmlPath ` + --package-path $tempDir ` + --resources $resourcesDir ` + $finalPackagePath + } + + if (Test-Path $finalPackagePath) { + Write-Log "Successfully created macOS package: $finalPackagePath" + } + else { + throw "Package was not created at expected location: $finalPackagePath" + } + } + finally + { + Pop-Location + Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue + } } - return (Get-Item $newPackagePath) + return (Get-Item $finalPackagePath) } Class LinkInfo @@ -1692,6 +1733,157 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination return $specContent } +function New-MacOSPackage +{ + [CmdletBinding(SupportsShouldProcess=$true)] + param( + [Parameter(Mandatory)] + [string]$Name, + + [Parameter(Mandatory)] + [string]$Version, + + [Parameter(Mandatory)] + [string]$Iteration, + + [Parameter(Mandatory)] + [string]$Staging, + + [Parameter(Mandatory)] + [string]$Destination, + + [Parameter(Mandatory)] + [string]$ManGzipFile, + + [Parameter(Mandatory)] + [string]$ManDestination, + + [Parameter(Mandatory)] + [LinkInfo[]]$LinkInfo, + + [Parameter(Mandatory)] + [string]$AfterInstallScript, + + [Parameter(Mandatory)] + [string]$AppsFolder, + + [Parameter(Mandatory)] + [string]$HostArchitecture, + + [string]$CurrentLocation = (Get-Location) + ) + + Write-Log "Creating macOS package using pkgbuild and productbuild..." + + # Create a temporary directory for package building + $tempRoot = New-TempFolder + $componentPkgPath = Join-Path $tempRoot "component.pkg" + $scriptsDir = Join-Path $tempRoot "scripts" + $resourcesDir = Join-Path $tempRoot "resources" + $distributionFile = Join-Path $tempRoot "distribution.xml" + + try { + # Create scripts directory + New-Item -ItemType Directory -Path $scriptsDir -Force | Out-Null + + # Copy and prepare the postinstall script + $postInstallPath = Join-Path $scriptsDir "postinstall" + Copy-Item -Path $AfterInstallScript -Destination $postInstallPath -Force + Start-NativeExecution { + chmod 755 $postInstallPath + } + + # Create a temporary directory for the package root + $pkgRoot = Join-Path $tempRoot "pkgroot" + New-Item -ItemType Directory -Path $pkgRoot -Force | Out-Null + + # Copy staging files to destination path in package root + $destInPkg = Join-Path $pkgRoot $Destination + New-Item -ItemType Directory -Path $destInPkg -Force | Out-Null + Write-Verbose "Copying staging files from $Staging to $destInPkg" -Verbose + Copy-Item -Path "$Staging/*" -Destination $destInPkg -Recurse -Force + + # Create man page directory structure + $manDir = Join-Path $pkgRoot (Split-Path $ManDestination -Parent) + New-Item -ItemType Directory -Path $manDir -Force | Out-Null + Copy-Item -Path $ManGzipFile -Destination (Join-Path $pkgRoot $ManDestination) -Force + + # Create symlinks in package root + # The LinkInfo contains Source (a temp file that IS a symlink) and Destination (where to install it) + foreach ($link in $LinkInfo) { + $linkDestDir = Join-Path $pkgRoot (Split-Path $link.Destination -Parent) + New-Item -ItemType Directory -Path $linkDestDir -Force | Out-Null + $finalLinkPath = Join-Path $pkgRoot $link.Destination + + Write-Verbose "Creating symlink at $finalLinkPath" -Verbose + + # Remove if exists + if (Test-Path $finalLinkPath) { + Remove-Item $finalLinkPath -Force + } + + # Get the target of the original symlink and recreate it in the package root + if (Test-Path $link.Source) { + $linkTarget = (Get-Item $link.Source).Target + if ($linkTarget) { + Write-Verbose "Creating symlink to target: $linkTarget" -Verbose + New-Item -ItemType SymbolicLink -Path $finalLinkPath -Target $linkTarget -Force | Out-Null + } else { + Write-Warning "Could not determine target for symlink at $($link.Source), copying file instead" + Copy-Item -Path $link.Source -Destination $finalLinkPath -Force + } + } else { + Write-Warning "Source symlink $($link.Source) does not exist" + } + } + + # Copy launcher app folder if provided + if ($AppsFolder) { + $appsInPkg = Join-Path $pkgRoot "Applications" + New-Item -ItemType Directory -Path $appsInPkg -Force | Out-Null + Write-Verbose "Copying launcher app from $AppsFolder to $appsInPkg" -Verbose + Copy-Item -Path "$AppsFolder/*" -Destination $appsInPkg -Recurse -Force + } + + # Build the component package using pkgbuild + $pkgIdentifier = Get-MacOSPackageId -IsPreview:($Name -like '*-preview') + + if ($PSCmdlet.ShouldProcess("Build component package with pkgbuild")) { + Write-Log "Running pkgbuild to create component package..." + + Start-NativeExecution -VerboseOutputOnError { + pkgbuild --root $pkgRoot ` + --identifier $pkgIdentifier ` + --version $Version ` + --scripts $scriptsDir ` + --install-location "/" ` + $componentPkgPath + } + + Write-Verbose "Component package created: $componentPkgPath" -Verbose + } + + # Create the final distribution package using the refactored function + $distributionPackage = New-MacOsDistributionPackage ` + -ComponentPackage (Get-Item $componentPkgPath) ` + -PackageName $Name ` + -Version $Version ` + -OutputDirectory $CurrentLocation ` + -HostArchitecture $HostArchitecture ` + -PackageIdentifier $pkgIdentifier ` + -IsPreview:($Name -like '*-preview') + + return $distributionPackage + } + finally { + # Clean up temporary directory + if (Test-Path $tempRoot) { + Write-Verbose "Cleaning up temporary directory: $tempRoot" -Verbose + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } +} + function Get-FpmArguments { param( @@ -1905,6 +2097,7 @@ function Get-PackageDependencies function Test-Dependencies { # Note: RPM packages no longer require fpm; they use rpmbuild directly + # macOS packages use pkgbuild and productbuild from Xcode Command Line Tools # DEB packages still use fpm $Dependencies = @() @@ -1913,22 +2106,31 @@ function Test-Dependencies $Dependencies += "fpm" } + # Check for macOS packaging tools + if ($Environment.IsMacOS) { + $Dependencies += "pkgbuild" + $Dependencies += "productbuild" + } + foreach ($Dependency in $Dependencies) { if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - # These tools are not added to the path automatically on OpenSUSE 13.2 - # try adding them to the path and re-tesing first - [string] $gemsPath = $null - [string] $depenencyPath = $null - $gemsPath = Get-ChildItem -Path /usr/lib64/ruby/gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName - if ($gemsPath) { - $depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName - $originalPath = $env:PATH - $env:PATH = $ENV:PATH +":" + $depenencyPath - if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - continue - } - else { - $env:PATH = $originalPath + # For Debian systems, try adding ruby gems to the path + if ($Environment.IsDebianFamily) { + # These tools are not added to the path automatically on OpenSUSE 13.2 + # try adding them to the path and re-tesing first + [string] $gemsPath = $null + [string] $depenencyPath = $null + $gemsPath = Get-ChildItem -Path /usr/lib64/ruby/gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName + if ($gemsPath) { + $depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName + $originalPath = $env:PATH + $env:PATH = $ENV:PATH +":" + $depenencyPath + if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { + continue + } + else { + $env:PATH = $originalPath + } } } @@ -2086,10 +2288,12 @@ function New-MacOSLauncher # Set permissions for plist and shell script. Start-NativeExecution { chmod 644 $plist + } + Start-NativeExecution { chmod 755 $shellscript } - # Add app folder to fpm paths. + # Return the app folder path for packaging $appsfolder = (Resolve-Path -Path "$macosapp/..").Path return $appsfolder diff --git a/tools/packaging/releaseTests/macOSPackage.tests.ps1 b/tools/packaging/releaseTests/macOSPackage.tests.ps1 new file mode 100644 index 00000000000..c1de1091562 --- /dev/null +++ b/tools/packaging/releaseTests/macOSPackage.tests.ps1 @@ -0,0 +1,162 @@ +Describe "Verify macOS Package" { + BeforeAll { + Write-Verbose "In Describe BeforeAll" -Verbose + Import-Module $PSScriptRoot/../../../build.psm1 + + # Find the macOS package + $packagePath = $env:PACKAGE_FOLDER + if (-not $packagePath) { + $packagePath = Get-Location + } + + Write-Verbose "Looking for package in: $packagePath" -Verbose + $package = Get-ChildItem -Path $packagePath -Filter "*.pkg" -ErrorAction SilentlyContinue | Select-Object -First 1 + + if (-not $package) { + Write-Warning "No .pkg file found in $packagePath" + } else { + Write-Verbose "Found package: $($package.FullName)" -Verbose + } + + # Set up test directories + $script:package = $package + $script:expandDir = $null + $script:payloadDir = $null + $script:extractedFiles = @() + + if ($package) { + # Use TestDrive for temporary directories - pkgutil will create the expand directory + $script:expandDir = Join-Path "TestDrive:" -ChildPath "package-contents-test" + $expandDirResolved = (Resolve-Path "TestDrive:").ProviderPath + $script:expandDir = Join-Path $expandDirResolved -ChildPath "package-contents-test" + + Write-Verbose "Expanding package to: $($script:expandDir)" -Verbose + # pkgutil will create the directory itself, so don't pre-create it + Start-NativeExecution { + pkgutil --expand $package.FullName $script:expandDir + } + + # Extract the payload to verify files + $script:payloadDir = Join-Path "TestDrive:" -ChildPath "package-payload-test" + $payloadDirResolved = (Resolve-Path "TestDrive:").ProviderPath + $script:payloadDir = Join-Path $payloadDirResolved -ChildPath "package-payload-test" + + # Create payload directory since cpio needs it + if (-not (Test-Path $script:payloadDir)) { + $null = New-Item -ItemType Directory -Path $script:payloadDir -Force + } + + $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse | Select-Object -First 1 + if ($componentPkg) { + Write-Verbose "Extracting payload from: $($componentPkg.FullName)" -Verbose + Push-Location $script:payloadDir + try { + $payloadFile = Join-Path $componentPkg.FullName "Payload" + Get-Content -Path $payloadFile -Raw -AsByteStream | & cpio -i 2>&1 | Out-Null + } finally { + Pop-Location + } + } + + # Get all extracted files for verification + $script:extractedFiles = Get-ChildItem -Path $script:payloadDir -Recurse -ErrorAction SilentlyContinue + Write-Verbose "Extracted $($script:extractedFiles.Count) files" -Verbose + } + } + + AfterAll { + # TestDrive automatically cleans up, but we can ensure cleanup happens + # No manual cleanup needed as TestDrive handles it + } + + Context "Package existence and structure" { + It "Package file should exist" { + $script:package | Should -Not -BeNullOrEmpty -Because "A .pkg file should be created" + $script:package.Extension | Should -Be ".pkg" + } + + It "Package should expand successfully" { + $script:expandDir | Should -Exist + Get-ChildItem -Path $script:expandDir | Should -Not -BeNullOrEmpty + } + + It "Package should have a component package" { + $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse -ErrorAction SilentlyContinue + $componentPkg | Should -Not -BeNullOrEmpty -Because "Package should contain a component.pkg" + } + + It "Payload should extract successfully" { + $script:payloadDir | Should -Exist + $script:extractedFiles | Should -Not -BeNullOrEmpty -Because "Package payload should contain files" + } + } + + Context "Required files in package" { + BeforeAll { + $expectedFilePatterns = @{ + "PowerShell executable" = "usr/local/microsoft/powershell/*/pwsh" + "PowerShell symlink in /usr/local/bin" = "usr/local/bin/pwsh*" + "Man page" = "usr/local/share/man/man1/pwsh*.gz" + "Launcher application plist" = "Applications/PowerShell*.app/Contents/Info.plist" + } + + $testCases = @() + foreach ($key in $expectedFilePatterns.Keys) { + $testCases += @{ + Description = $key + Pattern = $expectedFilePatterns[$key] + } + } + + $script:testCases = $testCases + } + + It "Should contain " -TestCases $script:testCases { + param($Description, $Pattern) + + $found = $script:extractedFiles | Where-Object { $_.FullName -like "*$Pattern*" } + $found | Should -Not -BeNullOrEmpty -Because "$Description should exist in the package at path matching '$Pattern'" + } + } + + Context "PowerShell binary verification" { + It "PowerShell executable should be executable" { + $pwshBinary = $script:extractedFiles | Where-Object { $_.FullName -like "*/pwsh" -and $_.FullName -like "*/microsoft/powershell/*" } + $pwshBinary | Should -Not -BeNullOrEmpty + + # Check if file has executable permissions (on Unix-like systems) + if ($IsLinux -or $IsMacOS) { + $permissions = (Get-Item $pwshBinary[0].FullName).UnixFileMode + # Executable bit should be set + $permissions.ToString() | Should -Match 'x' -Because "pwsh binary should have execute permissions" + } + } + } + + Context "Launcher application" { + It "Launcher app should have proper bundle structure" { + $plistFile = $script:extractedFiles | Where-Object { $_.FullName -like "*PowerShell*.app/Contents/Info.plist" } + $plistFile | Should -Not -BeNullOrEmpty + + # Verify the bundle has required components + $appPath = Split-Path (Split-Path $plistFile[0].FullName -Parent) -Parent + $macOSDir = Join-Path $appPath "Contents/MacOS" + $resourcesDir = Join-Path $appPath "Contents/Resources" + + Test-Path $macOSDir | Should -Be $true -Because "App bundle should have Contents/MacOS directory" + Test-Path $resourcesDir | Should -Be $true -Because "App bundle should have Contents/Resources directory" + } + + It "Launcher script should exist and be executable" { + $launcherScript = $script:extractedFiles | Where-Object { + $_.FullName -like "*PowerShell*.app/Contents/MacOS/PowerShell.sh" + } + $launcherScript | Should -Not -BeNullOrEmpty -Because "Launcher script should exist" + + if ($IsLinux -or $IsMacOS) { + $permissions = (Get-Item $launcherScript[0].FullName).UnixFileMode + $permissions.ToString() | Should -Match 'x' -Because "Launcher script should have execute permissions" + } + } + } +} From 9532f85fe436bb4c1143ea7597acbd4df37291be Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 20 Nov 2025 14:57:21 -0800 Subject: [PATCH 016/127] [release/v7.6] Make some experimental features stable (#26490) --- .../commands/utility/Var.cs | 1 - .../ExperimentalFeature.cs | 11 ---- .../engine/InitialSessionState.cs | 6 +-- .../engine/NativeCommandParameterBinder.cs | 7 +-- .../Commands/GetPSSubsystemCommand.cs | 1 - .../engine/runtime/Operations/MiscOps.cs | 17 +++---- .../Parser/RedirectionOperator.Tests.ps1 | 8 +-- .../NativeWindowsTildeExpansion.Tests.ps1 | 16 +++--- .../Set-Variable.Tests.ps1 | 50 +++++++------------ .../engine/Basic/DefaultCommands.Tests.ps1 | 1 + test/tools/TestMetadata.json | 3 -- 11 files changed, 37 insertions(+), 84 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs index 12cfb784c72..a41b284f568 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Var.cs @@ -697,7 +697,6 @@ public SwitchParameter PassThru /// Gets whether we will append to the variable if it exists. /// [Parameter] - [Experimental(ExperimentalFeature.PSRedirectToVariable, ExperimentAction.Show)] public SwitchParameter Append { get; set; } private bool _nameIsFormalParameter; diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs index 60d6b238065..877750bb199 100644 --- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs +++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs @@ -22,8 +22,6 @@ public class ExperimentalFeature internal const string EngineSource = "PSEngine"; internal const string PSFeedbackProvider = "PSFeedbackProvider"; - internal const string PSNativeWindowsTildeExpansion = nameof(PSNativeWindowsTildeExpansion); - internal const string PSRedirectToVariable = "PSRedirectToVariable"; internal const string PSSerializeJSONLongEnumAsNumber = nameof(PSSerializeJSONLongEnumAsNumber); internal const string PSProfileDSCResource = "PSProfileDSCResource"; @@ -108,21 +106,12 @@ static ExperimentalFeature() name: "PSFileSystemProviderV2", description: "Replace the old FileSystemProvider with cleaner design and faster code"), */ - new ExperimentalFeature( - name: "PSSubsystemPluginModel", - description: "A plugin model for registering and un-registering PowerShell subsystems"), new ExperimentalFeature( name: "PSLoadAssemblyFromNativeCode", description: "Expose an API to allow assembly loading from native code"), new ExperimentalFeature( name: PSFeedbackProvider, description: "Replace the hard-coded suggestion framework with the extensible feedback provider"), - new ExperimentalFeature( - name: PSNativeWindowsTildeExpansion, - description: "On windows, expand unquoted tilde (`~`) with the user's current home folder."), - new ExperimentalFeature( - name: PSRedirectToVariable, - description: "Add support for redirecting to the variable drive"), new ExperimentalFeature( name: PSSerializeJSONLongEnumAsNumber, description: "Serialize enums based on long or ulong as an numeric value rather than the string representation when using ConvertTo-Json." diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index 84f513d8450..86e6240fdad 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -5470,6 +5470,7 @@ private static void InitializeCoreCmdletsAndProviders( { "Get-Module", new SessionStateCmdletEntry("Get-Module", typeof(GetModuleCommand), helpFile) }, { "Get-PSHostProcessInfo", new SessionStateCmdletEntry("Get-PSHostProcessInfo", typeof(GetPSHostProcessInfoCommand), helpFile) }, { "Get-PSSession", new SessionStateCmdletEntry("Get-PSSession", typeof(GetPSSessionCommand), helpFile) }, + { "Get-PSSubsystem", new SessionStateCmdletEntry("Get-PSSubsystem", typeof(Subsystem.GetPSSubsystemCommand), helpFile) }, { "Import-Module", new SessionStateCmdletEntry("Import-Module", typeof(ImportModuleCommand), helpFile) }, { "Invoke-Command", new SessionStateCmdletEntry("Invoke-Command", typeof(InvokeCommandCommand), helpFile) }, { "Invoke-History", new SessionStateCmdletEntry("Invoke-History", typeof(InvokeHistoryCommand), helpFile) }, @@ -5510,11 +5511,6 @@ private static void InitializeCoreCmdletsAndProviders( { "Format-Default", new SessionStateCmdletEntry("Format-Default", typeof(FormatDefaultCommand), helpFile) }, }; - if (ExperimentalFeature.IsEnabled("PSSubsystemPluginModel")) - { - cmdlets.Add("Get-PSSubsystem", new SessionStateCmdletEntry("Get-PSSubsystem", typeof(Subsystem.GetPSSubsystemCommand), helpFile)); - } - #if UNIX cmdlets.Add("Switch-Process", new SessionStateCmdletEntry("Switch-Process", typeof(SwitchProcessCommand), helpFile)); #endif diff --git a/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs b/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs index 0124b01332c..19e17b71cca 100644 --- a/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs +++ b/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs @@ -406,12 +406,9 @@ private void PossiblyGlobArg(string arg, CommandParameterInternal parameter, boo } } #else - if (!usedQuotes && ExperimentalFeature.IsEnabled(ExperimentalFeature.PSNativeWindowsTildeExpansion)) + if (!usedQuotes && ExpandTilde(arg, parameter)) { - if (ExpandTilde(arg, parameter)) - { - argExpanded = true; - } + argExpanded = true; } #endif diff --git a/src/System.Management.Automation/engine/Subsystem/Commands/GetPSSubsystemCommand.cs b/src/System.Management.Automation/engine/Subsystem/Commands/GetPSSubsystemCommand.cs index 1ad79404f51..df828c724a2 100644 --- a/src/System.Management.Automation/engine/Subsystem/Commands/GetPSSubsystemCommand.cs +++ b/src/System.Management.Automation/engine/Subsystem/Commands/GetPSSubsystemCommand.cs @@ -8,7 +8,6 @@ namespace System.Management.Automation.Subsystem /// /// Implementation of 'Get-PSSubsystem' cmdlet. /// - [Experimental("PSSubsystemPluginModel", ExperimentAction.Show)] [Cmdlet(VerbsCommon.Get, "PSSubsystem", DefaultParameterSetName = AllSet)] [OutputType(typeof(SubsystemInfo))] public sealed class GetPSSubsystemCommand : PSCmdlet diff --git a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs index ddc70fabd50..50054f6501d 100644 --- a/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs +++ b/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs @@ -1092,14 +1092,11 @@ internal override void Bind(PipelineProcessor pipelineProcessor, CommandProcesso { // Check first to see if File is a variable path. If so, we'll not create the FileBytePipe bool redirectToVariable = false; - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSRedirectToVariable)) + + context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(File, out ProviderInfo p, out _); + if (p != null && p.NameEquals(context.ProviderNames.Variable)) { - ProviderInfo p; - context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(File, out p, out _); - if (p != null && p.NameEquals(context.ProviderNames.Variable)) - { - redirectToVariable = true; - } + redirectToVariable = true; } if (commandProcessor is NativeCommandProcessor nativeCommand @@ -1223,12 +1220,10 @@ internal Pipe GetRedirectionPipe(ExecutionContext context, PipelineProcessor par // determine whether we're trying to set a variable by inspecting the file path // if we can determine that it's a variable, we'll use Set-Variable rather than Out-File - ProviderInfo p; - PSDriveInfo d; CommandProcessorBase commandProcessor; - var name = context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(File, out p, out d); + var name = context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(File, out ProviderInfo p, out _); - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSRedirectToVariable) && p != null && p.NameEquals(context.ProviderNames.Variable)) + if (p != null && p.NameEquals(context.ProviderNames.Variable)) { commandProcessor = context.CreateCommand("Set-Variable", false); Diagnostics.Assert(commandProcessor != null, "CreateCommand returned null"); diff --git a/test/powershell/Language/Parser/RedirectionOperator.Tests.ps1 b/test/powershell/Language/Parser/RedirectionOperator.Tests.ps1 index d948881f1de..140d92fae88 100644 --- a/test/powershell/Language/Parser/RedirectionOperator.Tests.ps1 +++ b/test/powershell/Language/Parser/RedirectionOperator.Tests.ps1 @@ -127,12 +127,6 @@ Describe "File redirection should have 'DoComplete' called on the underlying pip Describe "Redirection and Set-Variable -append tests" -tags CI { Context "variable redirection should work" { BeforeAll { - if ( $EnabledExperimentalFeatures -contains "PSRedirectToVariable" ) { - $skipTest = $false - } - else { - $skipTest = $true - } $testCases = @{ Name = "Variable should be created"; scriptBlock = { 1..3>variable:a }; Validation = { ($a -join "") | Should -Be ((1..3) -join "") } }, @{ Name = "variable should be appended"; scriptBlock = {1..3>variable:a; 4..6>>variable:a}; Validation = { ($a -join "") | Should -Be ((1..6) -join "")}}, @{ Name = "variable should maintain type"; scriptBlock = {@{one=1}>variable:a};Validation = {$a | Should -BeOfType [hashtable]}}, @@ -220,7 +214,7 @@ Describe "Redirection and Set-Variable -append tests" -tags CI { } - It "" -TestCases $testCases -skip:$skipTest { + It "" -TestCases $testCases { param ( $scriptBlock, $validation ) . $scriptBlock . $validation diff --git a/test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1 b/test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1 index 04156099fa4..3a478607c08 100644 --- a/test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1 +++ b/test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1 @@ -5,7 +5,6 @@ Describe 'Native Windows tilde expansion tests' -tags "CI" { BeforeAll { $originalDefaultParams = $PSDefaultParameterValues.Clone() $PSDefaultParameterValues["it:skip"] = -Not $IsWindows - $EnabledExperimentalFeatures.Contains('PSNativeWindowsTildeExpansion') | Should -BeTrue } AfterAll { @@ -21,12 +20,13 @@ Describe 'Native Windows tilde expansion tests' -tags "CI" { cmd /c echo ~/foo | Should -BeExactly "$($ExecutionContext.SessionState.Provider.Get("FileSystem").Home)/foo" cmd /c echo ~\foo | Should -BeExactly "$($ExecutionContext.SessionState.Provider.Get("FileSystem").Home)\foo" } - It '~ should not be replaced when quoted' { - cmd /c echo '~' | Should -BeExactly '~' - cmd /c echo "~" | Should -BeExactly '~' - cmd /c echo '~/foo' | Should -BeExactly '~/foo' - cmd /c echo "~/foo" | Should -BeExactly '~/foo' + + It '~ should not be replaced when quoted' { + cmd /c echo '~' | Should -BeExactly '~' + cmd /c echo "~" | Should -BeExactly '~' + cmd /c echo '~/foo' | Should -BeExactly '~/foo' + cmd /c echo "~/foo" | Should -BeExactly '~/foo' cmd /c echo '~\foo' | Should -BeExactly '~\foo' - cmd /c echo "~\foo" | Should -BeExactly '~\foo' - } + cmd /c echo "~\foo" | Should -BeExactly '~\foo' + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Variable.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Variable.Tests.ps1 index d11fd5cfbb3..6e6fc1a2e1d 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Variable.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Set-Variable.Tests.ps1 @@ -244,44 +244,30 @@ Describe "Set-Variable" -Tags "CI" { Context "Set-Variable -Append tests" { BeforeAll { - if (! (Get-ExperimentalFeature PSRedirectToVariable).Enabled) { - $skipTest = $true - } - - $testCases = @{ value = 2; Count = 2 }, - @{ value = @(2,3,4); Count = 2}, - @{ value = "abc",(Get-Process -Id $PID) ; count = 2} + $testCases = @{ value = 2; Count = 2 }, + @{ value = @(2,3,4); Count = 2}, + @{ value = "abc",(Get-Process -Id $PID) ; count = 2} } - It "Can append values to a variable" -testCases $testCases { - param ($value, $count) - - if ($skipTest) { - Set-ItResult -skip -because "Experimental Feature PSRedirectToVariable not enabled" - return - } - - $variableName = "testVar" - Set-Variable -Name $variableName -Value 1 - Set-Variable -Name $variableName -Value $value -Append + It "Can append values to a variable" -testCases $testCases { + param ($value, $count) - $observedValues = Get-Variable $variableName -Value + $variableName = "testVar" + Set-Variable -Name $variableName -Value 1 + Set-Variable -Name $variableName -Value $value -Append - $observedValues.Count | Should -Be $count - $observedValues[0] | Should -Be 1 + $observedValues = Get-Variable $variableName -Value - $observedValues[1] | Should -Be $value - } + $observedValues.Count | Should -Be $count + $observedValues[0] | Should -Be 1 - It "Can use set-variable via streaming and append values" { - if ($skipTest) { - Set-ItResult -skip -because "Experimental Feature PSRedirectToVariable not enabled" - return - } + $observedValues[1] | Should -Be $value + } - $testVar = 1 - 4..6 | Set-Variable -Name testVar -Append - $testVar | Should -Be @(1,4,5,6) - } + It "Can use set-variable via streaming and append values" { + $testVar = 1 + 4..6 | Set-Variable -Name testVar -Append + $testVar | Should -Be @(1,4,5,6) + } } } diff --git a/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 b/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 index 312c34b6706..7a757e6eac4 100644 --- a/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 +++ b/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 @@ -337,6 +337,7 @@ Describe "Verify aliases and cmdlets" -Tags "CI" { "Cmdlet", "Get-PSSessionCapability", "", $($FullCLR -or $CoreWindows ), "", "", "None" "Cmdlet", "Get-PSSessionConfiguration", "", $($FullCLR -or $CoreWindows ), "", "", "None" "Cmdlet", "Get-PSSnapin", "", $($FullCLR ), "", "", "" +"Cmdlet", "Get-PSSubsystem", "", $( $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Get-Random", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Get-Runspace", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Get-RunspaceDebug", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" diff --git a/test/tools/TestMetadata.json b/test/tools/TestMetadata.json index bd716ccec7b..19ffb93ce92 100644 --- a/test/tools/TestMetadata.json +++ b/test/tools/TestMetadata.json @@ -1,9 +1,6 @@ { "ExperimentalFeatures": { "ExpTest.FeatureOne": [ "test/powershell/engine/ExperimentalFeature/ExperimentalFeature.Basic.Tests.ps1" ], - "PSCultureInvariantReplaceOperator": [ "test/powershell/Language/Operators/ReplaceOperator.Tests.ps1" ], - "Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/RunspaceBreakpointManagement.Tests.ps1" ], - "PSNativeWindowsTildeExpansion": [ "test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1" ], "PSSerializeJSONLongEnumAsNumber": [ "test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Json.PSSerializeJSONLongEnumAsNumber.Tests.ps1" ] } } From 61682d457a863bbdb9e3b831f96f39c0a6d56977 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Mon, 24 Nov 2025 12:37:27 -0800 Subject: [PATCH 017/127] [release/v7.6] Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26524) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/actions/build/ci/action.yml | 4 +- .../actions/test/linux-packaging/action.yml | 4 +- .github/actions/test/nix/action.yml | 6 +- .github/actions/test/windows/action.yml | 6 +- .../log-grouping-guidelines.instructions.md | 181 ++++++++++++++++++ .github/workflows/analyze-reusable.yml | 3 +- .github/workflows/linux-ci.yml | 13 +- .github/workflows/macos-ci.yml | 15 +- .github/workflows/windows-ci.yml | 15 +- .../workflows/windows-packaging-reusable.yml | 3 +- build.psm1 | 41 +++- tools/ci.psm1 | 8 + 12 files changed, 266 insertions(+), 33 deletions(-) create mode 100644 .github/instructions/log-grouping-guidelines.instructions.md diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index 997be8b264c..be9c0ecd20b 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -5,7 +5,9 @@ runs: steps: - name: Capture Environment if: success() || failure() - run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + run: |- + Import-Module .\tools\ci.psm1 + Show-Environment shell: pwsh - name: Set Build Name for Non-PR if: github.event_name != 'PullRequest' diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index b7bbdf37185..a04e09b6a5c 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -6,7 +6,9 @@ runs: steps: - name: Capture Environment if: success() || failure() - run: 'Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose' + run: |- + Import-Module ./tools/ci.psm1 + Show-Environment shell: pwsh - uses: actions/setup-dotnet@v5 diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index c7e97742694..7f68e71c1f5 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -24,10 +24,8 @@ runs: - name: Capture Environment if: success() || failure() run: |- - Import-Module ./build.psm1 - Write-LogGroupStart -Title 'Environment' - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - Write-LogGroupEnd -Title 'Environment' + Import-Module ./tools/ci.psm1 + Show-Environment shell: pwsh - name: Download Build Artifacts diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index c2ff1bc8fb6..2c41f6aac5c 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -24,10 +24,8 @@ runs: - name: Capture Environment if: success() || failure() run: |- - Import-Module ./build.psm1 - Write-LogGroupStart -Title 'Environment' - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - Write-LogGroupEnd -Title 'Environment' + Import-Module ./tools/ci.psm1 + Show-Environment shell: pwsh - name: Download Build Artifacts diff --git a/.github/instructions/log-grouping-guidelines.instructions.md b/.github/instructions/log-grouping-guidelines.instructions.md new file mode 100644 index 00000000000..ff845db4e4b --- /dev/null +++ b/.github/instructions/log-grouping-guidelines.instructions.md @@ -0,0 +1,181 @@ +--- +applyTo: + - "build.psm1" + - "tools/ci.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" +--- + +# Log Grouping Guidelines for GitHub Actions + +## Purpose + +Guidelines for using `Write-LogGroupStart` and `Write-LogGroupEnd` to create collapsible log sections in GitHub Actions CI/CD runs. + +## Key Principles + +### 1. Groups Cannot Be Nested + +GitHub Actions does not support nested groups. Only use one level of grouping. + +**❌ Don't:** +```powershell +Write-LogGroupStart -Title "Outer Group" +Write-LogGroupStart -Title "Inner Group" +# ... operations ... +Write-LogGroupEnd -Title "Inner Group" +Write-LogGroupEnd -Title "Outer Group" +``` + +**✅ Do:** +```powershell +Write-LogGroupStart -Title "Operation A" +# ... operations ... +Write-LogGroupEnd -Title "Operation A" + +Write-LogGroupStart -Title "Operation B" +# ... operations ... +Write-LogGroupEnd -Title "Operation B" +``` + +### 2. Groups Should Be Substantial + +Only create groups for operations that generate substantial output (5+ lines). Small groups add clutter without benefit. + +**❌ Don't:** +```powershell +Write-LogGroupStart -Title "Generate Resource Files" +Write-Log -message "Run ResGen" +Start-ResGen +Write-LogGroupEnd -Title "Generate Resource Files" +``` + +**✅ Do:** +```powershell +Write-Log -message "Run ResGen (generating C# bindings for resx files)" +Start-ResGen +``` + +### 3. Groups Should Represent Independent Operations + +Each group should be a logically independent operation that users might want to expand/collapse separately. + +**✅ Good examples:** +- Install Native Dependencies +- Install .NET SDK +- Build PowerShell +- Restore NuGet Packages + +**❌ Bad examples:** +- Individual project restores (too granular) +- Small code generation steps (too small) +- Sub-steps of a larger operation (would require nesting) + +### 4. One Group Per Iteration Is Excessive + +Avoid putting log groups inside loops where each iteration creates a separate group. This would probably cause nesting. + +**❌ Don't:** +```powershell +$projects | ForEach-Object { + Write-LogGroupStart -Title "Restore Project: $_" + dotnet restore $_ + Write-LogGroupEnd -Title "Restore Project: $_" +} +``` + +**✅ Do:** +```powershell +Write-LogGroupStart -Title "Restore All Projects" +$projects | ForEach-Object { + Write-Log -message "Restoring $_" + dotnet restore $_ +} +Write-LogGroupEnd -Title "Restore All Projects" +``` + +## Usage Pattern + +```powershell +Write-LogGroupStart -Title "Descriptive Operation Name" +try { + # ... operation code ... + Write-Log -message "Status updates" +} +finally { + # Ensure group is always closed +} +Write-LogGroupEnd -Title "Descriptive Operation Name" +``` + +## When to Use Log Groups + +Use log groups for: +- Major build phases (bootstrap, restore, build, test, package) +- Installation operations (dependencies, SDKs, tools) +- Operations that produce 5+ lines of output +- Operations where users might want to collapse verbose output + +Don't use log groups for: +- Single-line operations +- Code that's already inside another group +- Loop iterations with minimal output per iteration +- Diagnostic or debug output that should always be visible + +## Examples from build.psm1 + +### Good Usage + +```powershell +function Start-PSBootstrap { + # Multiple independent operations, each with substantial output + Write-LogGroupStart -Title "Install Native Dependencies" + # ... apt-get/yum/brew install commands ... + Write-LogGroupEnd -Title "Install Native Dependencies" + + Write-LogGroupStart -Title "Install .NET SDK" + # ... dotnet installation ... + Write-LogGroupEnd -Title "Install .NET SDK" +} +``` + +### Avoid + +```powershell +# Too small - just 2-3 lines +Write-LogGroupStart -Title "Generate Resource Files (ResGen)" +Write-Log -message "Run ResGen" +Start-ResGen +Write-LogGroupEnd -Title "Generate Resource Files (ResGen)" +``` + +## GitHub Actions Syntax + +These functions emit GitHub Actions workflow commands: +- `Write-LogGroupStart` → `::group::Title` +- `Write-LogGroupEnd` → `::endgroup::` + +In the GitHub Actions UI, this renders as collapsible sections with the specified title. + +## Testing + +Test log grouping locally: +```powershell +$env:GITHUB_ACTIONS = 'true' +Import-Module ./build.psm1 +Write-LogGroupStart -Title "Test" +Write-Log -Message "Content" +Write-LogGroupEnd -Title "Test" +``` + +Output should show: +``` +::group::Test +Content +::endgroup:: +``` + +## References + +- [GitHub Actions: Grouping log lines](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines) +- `build.psm1`: `Write-LogGroupStart` and `Write-LogGroupEnd` function definitions diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 1797e2234a6..10b2f0893a3 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -56,7 +56,8 @@ jobs: # queries: ./path/to/local/query, your-org/your-repo/queries@main - run: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + Import-Module .\tools\ci.psm1 + Show-Environment name: Capture Environment shell: pwsh diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 94829ac2a64..1e018065d39 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -53,6 +53,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout @@ -70,7 +71,7 @@ jobs: name: Build PowerShell runs-on: ubuntu-latest needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout uses: actions/checkout@v5 @@ -84,7 +85,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -102,7 +103,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -120,7 +121,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -138,7 +139,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: ubuntu-latest steps: - name: checkout @@ -155,7 +156,7 @@ jobs: name: xUnit Tests needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/xunit-tests.yml with: runner_os: ubuntu-latest diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 847d1e01cd0..dc8b77ee047 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -53,6 +53,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} steps: - name: checkout uses: actions/checkout@v5 @@ -67,7 +68,7 @@ jobs: name: Build PowerShell runs-on: macos-15-large needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout uses: actions/checkout@v5 @@ -80,7 +81,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: macos-15-large steps: - name: checkout @@ -98,7 +99,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: macos-15-large steps: - name: checkout @@ -116,7 +117,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: macos-15-large steps: - name: checkout @@ -134,7 +135,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: macos-15-large steps: - name: checkout @@ -151,7 +152,7 @@ jobs: name: xUnit Tests needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/xunit-tests.yml with: runner_os: macos-15-large @@ -160,7 +161,7 @@ jobs: name: macOS packaging and testing needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: - macos-15-large steps: diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index c21c319ec95..df23d5b3c48 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -56,6 +56,7 @@ jobs: # Set job outputs to values from filter step outputs: source: ${{ steps.filter.outputs.source }} + buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout @@ -70,7 +71,7 @@ jobs: ci_build: name: Build PowerShell needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -84,7 +85,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -102,7 +103,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -120,7 +121,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -138,7 +139,7 @@ jobs: needs: - ci_build - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} runs-on: windows-latest steps: - name: checkout @@ -155,7 +156,7 @@ jobs: name: xUnit Tests needs: - changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/xunit-tests.yml with: runner_os: windows-latest @@ -163,7 +164,7 @@ jobs: analyze: name: CodeQL Analysis needs: changes - if: ${{ needs.changes.outputs.source == 'true' }} + if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} uses: ./.github/workflows/analyze-reusable.yml permissions: actions: read diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 5a763544c62..6b42a8899ec 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -43,7 +43,8 @@ jobs: - name: Capture Environment if: success() || failure() run: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + Import-Module .\tools\ci.psm1 + Show-Environment shell: pwsh - name: Capture PowerShell Version Table diff --git a/build.psm1 b/build.psm1 index 88878bdd635..f5dfb60a2d0 100644 --- a/build.psm1 +++ b/build.psm1 @@ -385,7 +385,7 @@ function Start-PSBuild { } if ($Clean) { - Write-Log -message "Cleaning your working directory. You can also do it with 'git clean -fdX --exclude .vs/PowerShell/v16/Server/sqlite3'" + Write-LogGroupStart -Title "Cleaning your working directory" Push-Location $PSScriptRoot try { # Excluded sqlite3 folder is due to this Roslyn issue: https://github.com/dotnet/roslyn/issues/23060 @@ -393,6 +393,7 @@ function Start-PSBuild { # Excluded nuget.config as this is required for release build. git clean -fdX --exclude .vs/PowerShell/v16/Server/sqlite3 --exclude src/Modules/nuget.config --exclude nuget.config } finally { + Write-LogGroupEnd -Title "Cleaning your working directory" Pop-Location } } @@ -536,7 +537,9 @@ Fix steps: } # handle Restore + Write-LogGroupStart -Title "Restore NuGet Packages" Restore-PSPackage -Options $Options -Force:$Restore -InteractiveAuth:$InteractiveAuth + Write-LogGroupEnd -Title "Restore NuGet Packages" # handle ResGen # Heuristic to run ResGen on the fresh machine @@ -566,6 +569,7 @@ Fix steps: $publishPath = $Options.Output } + Write-LogGroupStart -Title "Build PowerShell" try { # Relative paths do not work well if cwd is not changed to project Push-Location $Options.Top @@ -620,6 +624,7 @@ Fix steps: } finally { Pop-Location } + Write-LogGroupEnd -Title "Build PowerShell" # No extra post-building task will run if '-SMAOnly' is specified, because its purpose is for a quick update of S.M.A.dll after full build. if ($SMAOnly) { @@ -627,6 +632,7 @@ Fix steps: } # publish reference assemblies + Write-LogGroupStart -Title "Publish Reference Assemblies" try { Push-Location "$PSScriptRoot/src/TypeCatalogGen" $refAssemblies = Get-Content -Path $incFileName | Where-Object { $_ -like "*microsoft.netcore.app*" } | ForEach-Object { $_.TrimEnd(';') } @@ -640,6 +646,7 @@ Fix steps: } finally { Pop-Location } + Write-LogGroupEnd -Title "Publish Reference Assemblies" if ($ReleaseTag) { $psVersion = $ReleaseTag @@ -682,10 +689,13 @@ Fix steps: # download modules from powershell gallery. # - PowerShellGet, PackageManagement, Microsoft.PowerShell.Archive if ($PSModuleRestore) { + Write-LogGroupStart -Title "Restore PowerShell Modules" Restore-PSModuleToBuild -PublishPath $publishPath + Write-LogGroupEnd -Title "Restore PowerShell Modules" } # publish powershell.config.json + Write-LogGroupStart -Title "Generate PowerShell Configuration" $config = [ordered]@{} if ($Options.Runtime -like "*win*") { @@ -731,10 +741,13 @@ Fix steps: } else { Write-Warning "No powershell.config.json generated for $publishPath" } + Write-LogGroupEnd -Title "Generate PowerShell Configuration" # Restore the Pester module if ($CI) { + Write-LogGroupStart -Title "Restore Pester Module" Restore-PSPester -Destination (Join-Path $publishPath "Modules") + Write-LogGroupEnd -Title "Restore Pester Module" } Clear-NativeDependencies -PublishFolder $publishPath @@ -2086,6 +2099,7 @@ function Install-Dotnet { [string]$FeedCredential ) + Write-LogGroupStart -Title "Install .NET SDK $Version" Write-Verbose -Verbose "In install-dotnet" # This allows sudo install to be optional; needed when running in containers / as root @@ -2220,6 +2234,7 @@ function Install-Dotnet { } } } + Write-LogGroupEnd -Title "Install .NET SDK $Version" } function Get-RedHatPackageManager { @@ -2296,12 +2311,14 @@ function Start-PSBootstrap { try { if ($environment.IsLinux -or $environment.IsMacOS) { + Write-LogGroupStart -Title "Install Native Dependencies" # This allows sudo install to be optional; needed when running in containers / as root # Note that when it is null, Invoke-Expression (but not &) must be used to interpolate properly $sudo = if (!$NoSudo) { "sudo" } if ($BuildLinuxArm -and $environment.IsLinux -and -not $environment.IsUbuntu -and -not $environment.IsMariner) { Write-Error "Cross compiling for linux-arm is only supported on AzureLinux/Ubuntu environment" + Write-LogGroupEnd -Title "Install Native Dependencies" return } @@ -2420,9 +2437,11 @@ function Start-PSBootstrap { } } } + Write-LogGroupEnd -Title "Install Native Dependencies" } if ($Scenario -eq 'DotNet' -or $Scenario -eq 'Both') { + Write-LogGroupStart -Title "Install .NET SDK" Write-Verbose -Verbose "Calling Find-Dotnet from Start-PSBootstrap" @@ -2461,10 +2480,12 @@ function Start-PSBootstrap { else { Write-Log -message "dotnet is already installed. Skipping installation." } + Write-LogGroupEnd -Title "Install .NET SDK" } # Install Windows dependencies if `-Package` or `-BuildWindowsNative` is specified if ($environment.IsWindows) { + Write-LogGroupStart -Title "Install Windows Dependencies" ## The VSCode build task requires 'pwsh.exe' to be found in Path if (-not (Get-Command -Name pwsh.exe -CommandType Application -ErrorAction Ignore)) { @@ -2477,12 +2498,30 @@ function Start-PSBootstrap { $isArm64 = "$env:RUNTIME" -eq 'arm64' Install-Wix -arm64:$isArm64 } + Write-LogGroupEnd -Title "Install Windows Dependencies" + } + + if ($Scenario -eq 'DotNet' -or $Scenario -eq 'Both') { + Write-LogGroupStart -Title "Install .NET SDK" + Write-Log -message "Installing .NET global tools" + + # Ensure dotnet is available + Find-Dotnet + + # Install dotnet-format + Write-Verbose -Verbose "Installing dotnet-format global tool" + Start-NativeExecution { + dotnet tool install --global dotnet-format + } + Write-LogGroupEnd -Title "Install .NET Global Tools" } if ($env:TF_BUILD) { + Write-LogGroupStart -Title "Capture NuGet Sources" Write-Verbose -Verbose "--- Start - Capturing nuget sources" dotnet nuget list source --format detailed Write-Verbose -Verbose "--- End - Capturing nuget sources" + Write-LogGroupEnd -Title "Capture NuGet Sources" } } finally { Pop-Location diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 44651c26109..478435e8543 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -688,6 +688,14 @@ function Set-Path } } +# Display environment variables in a log group for GitHub Actions +function Show-Environment +{ + Write-LogGroupStart -Title 'Environment' + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | Write-Verbose -Verbose + Write-LogGroupEnd -Title 'Environment' +} + # Bootstrap script for Linux and macOS function Invoke-BootstrapStage { From 391284f31c12a7f7841cf13fd8f366749043ea9b Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 25 Nov 2025 11:32:27 -0800 Subject: [PATCH 018/127] [release/v7.6] Remove usage of fpm for DEB package generation (#26504) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> --- build.psm1 | 83 ++-- .../linux/package-validation.tests.ps1 | 48 +- tools/packaging/packaging.psm1 | 462 ++++++++++-------- 3 files changed, 321 insertions(+), 272 deletions(-) diff --git a/build.psm1 b/build.psm1 index f5dfb60a2d0..5208fe55441 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2249,43 +2249,6 @@ function Get-RedHatPackageManager { } } -function Install-GlobalGem { - param( - [Parameter()] - [string] - $Sudo = "", - - [Parameter(Mandatory)] - [string] - $GemName, - - [Parameter(Mandatory)] - [string] - $GemVersion - ) - try { - # We cannot guess if the user wants to run gem install as root on linux and windows, - # but macOs usually requires sudo - $gemsudo = '' - if($environment.IsMacOS -or $env:TF_BUILD -or $env:GITHUB_ACTIONS) { - $gemsudo = $sudo - } - - Start-NativeExecution ([ScriptBlock]::Create("$gemsudo gem install $GemName -v $GemVersion --no-document")) - - } catch { - Write-Warning "Installation of gem $GemName $GemVersion failed! Must resolve manually." - $logs = Get-ChildItem "/var/lib/gems/*/extensions/x86_64-linux/*/$GemName-*/gem_make.out" | Select-Object -ExpandProperty FullName - foreach ($log in $logs) { - Write-Verbose "Contents of: $log" -Verbose - Get-Content -Raw -Path $log -ErrorAction Ignore | ForEach-Object { Write-Verbose $_ -Verbose } - Write-Verbose "END Contents of: $log" -Verbose - } - - throw - } -} - function Start-PSBootstrap { [CmdletBinding()] param( @@ -2297,7 +2260,12 @@ function Start-PSBootstrap { [switch]$BuildLinuxArm, [switch]$Force, [Parameter(Mandatory = $true)] - [ValidateSet("Package", "DotNet", "Both")] + # Package: Install dependencies for packaging tools (rpmbuild, dpkg-deb, pkgbuild, WiX) + # DotNet: Install the .NET SDK + # Both: Package and DotNet scenarios + # Tools: Install .NET global tools (e.g., dotnet-format) + # All: Install all dependencies (packaging, .NET SDK, and tools) + [ValidateSet("Package", "DotNet", "Both", "Tools", "All")] [string]$Scenario = "Package" ) @@ -2333,7 +2301,9 @@ function Start-PSBootstrap { elseif ($environment.IsUbuntu18) { $Deps += "libicu60"} # Packaging tools - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-dev", "groff", "libffi-dev", "rpm", "g++", "make" } + # Note: ruby-dev, libffi-dev, g++, and make are no longer needed for DEB packaging + # DEB packages now use native dpkg-deb (pre-installed) + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "groff", "rpm" } # Install dependencies # change the fontend from apt-get to noninteractive @@ -2357,7 +2327,9 @@ function Start-PSBootstrap { $Deps += "libicu", "openssl-libs" # Packaging tools - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-devel", "rpm-build", "groff", 'libffi-devel', "gcc-c++" } + # Note: ruby-devel and libffi-devel are no longer needed + # RPM packages use rpmbuild, DEB packages use dpkg-deb + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "rpm-build", "groff" } $PackageManager = Get-RedHatPackageManager @@ -2378,7 +2350,8 @@ function Start-PSBootstrap { $Deps += "wget" # Packaging tools - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-devel", "rpmbuild", "groff", 'libffi-devel', "gcc" } + # Note: ruby-devel and libffi-devel are no longer needed for packaging + if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "rpmbuild", "groff" } $PackageManager = "zypper --non-interactive install" $baseCommand = "$sudo $PackageManager" @@ -2417,17 +2390,7 @@ function Start-PSBootstrap { } } - # Install [fpm](https://github.com/jordansissel/fpm) - # Note: fpm is now only needed for DEB and macOS packages; RPM packages use rpmbuild directly - if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { - # Install fpm on Debian-based systems, macOS, and Mariner (where DEB packages are built) - if (($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) -or $environment.IsMacOS) { - Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1" - Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3" - Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1" - Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5" - } - + if ($Scenario -in 'All', 'Both', 'Package') { # For RPM-based systems, ensure rpmbuild is available if ($environment.IsLinux -and ($environment.IsRedHatFamily -or $environment.IsSUSEFamily -or $environment.IsMariner)) { Write-Verbose -Verbose "Checking for rpmbuild..." @@ -2436,6 +2399,22 @@ function Start-PSBootstrap { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y rpm-build")) -IgnoreExitcode } } + + # For Debian-based systems and Mariner, ensure dpkg-deb is available + if ($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) { + Write-Verbose -Verbose "Checking for dpkg-deb..." + if (!(Get-Command dpkg-deb -ErrorAction SilentlyContinue)) { + Write-Warning "dpkg-deb not found. Installing dpkg package..." + if ($environment.IsMariner) { + # For Mariner (Azure Linux), install the extended repo first to access dpkg. + Write-Verbose -Verbose "Installing azurelinux-repos-extended for Mariner..." + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager azurelinux-repos-extended")) -IgnoreExitcode + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager dpkg")) -IgnoreExitcode + } else { + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo apt-get install -y dpkg")) -IgnoreExitcode + } + } + } } Write-LogGroupEnd -Title "Install Native Dependencies" } diff --git a/test/packaging/linux/package-validation.tests.ps1 b/test/packaging/linux/package-validation.tests.ps1 index 241863de45d..594a729fa77 100644 --- a/test/packaging/linux/package-validation.tests.ps1 +++ b/test/packaging/linux/package-validation.tests.ps1 @@ -21,10 +21,7 @@ Describe "Linux Package Name Validation" { It "Should have valid RPM package names" { $rpmPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.rpm -ErrorAction SilentlyContinue - if ($rpmPackages.Count -eq 0) { - Set-ItResult -Skipped -Because "No RPM packages found in artifacts directory" - return - } + $rpmPackages.Count | Should -BeGreaterThan 0 -Because "At least one RPM package should exist in the artifacts directory" $invalidPackages = @() # Regex pattern for valid RPM package names. @@ -49,8 +46,42 @@ Describe "Linux Package Name Validation" { if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } + } + } + + Context "DEB Package Names" { + It "Should have valid DEB package names" { + $debPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.deb -ErrorAction SilentlyContinue + + $debPackages.Count | Should -BeGreaterThan 0 -Because "At least one DEB package should exist in the artifacts directory" + + $invalidPackages = @() + # Regex pattern for valid DEB package names. + # Valid examples: + # - powershell-preview_7.6.0-preview.6-1.deb_amd64.deb + # - powershell-lts_7.4.13-1.deb_amd64.deb + # - powershell_7.4.13-1.deb_amd64.deb + # Breakdown: + # ^powershell : Starts with 'powershell' + # (-preview|-lts)? : Optionally '-preview' or '-lts' + # _\d+\.\d+\.\d+ : Underscore followed by version number (e.g., _7.6.0) + # (-[a-z]+\.\d+)? : Optional dash, letters, dot, and digits (e.g., -preview.6) + # -1 : Literal '-1' + # \.deb_ : Literal '.deb_' + # (amd64|arm64) : Architecture + # \.deb$ : File extension + $debPackageNamePattern = '^powershell(-preview|-lts)?_\d+\.\d+\.\d+(-[a-z]+\.\d+)?-1\.deb_(amd64|arm64)\.deb$' + + foreach ($package in $debPackages) { + if ($package.Name -notmatch $debPackageNamePattern) { + $invalidPackages += "$($package.Name) is not a valid DEB package name" + Write-Warning "$($package.Name) is not a valid DEB package name" + } + } - $rpmPackages.Count | Should -BeGreaterThan 0 + if ($invalidPackages.Count -gt 0) { + throw ($invalidPackages | Out-String) + } } } @@ -58,10 +89,7 @@ Describe "Linux Package Name Validation" { It "Should have valid tar.gz package names" { $tarPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.tar.gz -ErrorAction SilentlyContinue - if ($tarPackages.Count -eq 0) { - Set-ItResult -Skipped -Because "No tar.gz packages found in artifacts directory" - return - } + $tarPackages.Count | Should -BeGreaterThan 0 -Because "At least one tar.gz package should exist in the artifacts directory" $invalidPackages = @() foreach ($package in $tarPackages) { @@ -76,8 +104,6 @@ Describe "Linux Package Name Validation" { if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } - - $tarPackages.Count | Should -BeGreaterThan 0 } } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 35ba148face..a55af6a83c2 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1199,8 +1199,6 @@ function New-UnixPackage { # Generate After Install and After Remove scripts $AfterScriptInfo = New-AfterScripts -Link $Link -Distribution $DebDistro -Destination $Destination - # Note: The fpm symlink workaround is no longer needed with native macOS packaging tools - # Generate gzip of man file $ManGzipInfo = New-ManGzip -IsPreview:$IsPreview -IsLTS:$LTS @@ -1319,6 +1317,33 @@ function New-UnixPackage { throw } } + } elseif ($Type -eq 'deb') { + # Use native DEB package builder + if ($PSCmdlet.ShouldProcess("Create DEB package natively")) { + Write-Log "Creating DEB package natively..." + try { + $result = New-NativeDeb ` + -Name $Name ` + -Version $packageVersion ` + -Iteration $Iteration ` + -Description $Description ` + -Staging $Staging ` + -Destination $Destination ` + -ManGzipFile $ManGzipInfo.GzipFile ` + -ManDestination $ManGzipInfo.ManFile ` + -LinkInfo $Links ` + -Dependencies $Dependencies ` + -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` + -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` + -HostArchitecture $HostArchitecture ` + -CurrentLocation $CurrentLocation + + $Output = @("Created package {:path=>""$($result.PackageName)""}") + } + catch { + Write-Verbose -Message "!!!Handling error in native DEB creation!!!" -Verbose -ErrorAction SilentlyContinue + } + } } elseif ($Type -eq 'osxpkg') { # Use native macOS packaging tools if ($PSCmdlet.ShouldProcess("Create macOS package with pkgbuild/productbuild")) { @@ -1350,40 +1375,8 @@ function New-UnixPackage { } } } else { - # Use fpm for DEB packages - $Arguments = @() - - $Arguments += Get-FpmArguments ` - -Name $Name ` - -Version $packageVersion ` - -Iteration $Iteration ` - -Description $Description ` - -Type $Type ` - -Dependencies $Dependencies ` - -AfterInstallScript $AfterScriptInfo.AfterInstallScript ` - -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` - -Staging $Staging ` - -Destination $Destination ` - -ManGzipFile $ManGzipInfo.GzipFile ` - -ManDestination $ManGzipInfo.ManFile ` - -LinkInfo $Links ` - -AppsFolder $AppsFolder ` - -Distribution $DebDistro ` - -HostArchitecture $HostArchitecture ` - -ErrorAction Stop - - if ($PSCmdlet.ShouldProcess("Create $type package")) { - Write-Log "Creating package with fpm $Arguments..." - try { - $Output = Start-NativeExecution { fpm $Arguments } - } - catch { - Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue - Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue - Get-Error -InputObject $_ - throw - } - } + # Nothing should reach here + throw "Unknown package type: $Type" } } finally { if ($Environment.IsMacOS) { @@ -1416,8 +1409,7 @@ function New-UnixPackage { $createdPackage = Get-Item (Join-Path $CurrentLocation (($Output[-1] -split ":path=>")[-1] -replace '["{}]')) # For macOS with native tools, the package is already in the correct format - # For macOS with fpm (no longer used), we would need New-MacOsDistributionPackage - # For other platforms, the package name from fpm/rpmbuild is sufficient + # For other platforms, the package name from dpkg-deb/rpmbuild is sufficient if (Test-Path $createdPackage) { @@ -1695,8 +1687,8 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination foreach ($link in $LinkInfo) { $linkDir = Split-Path -Parent $link.Destination $specContent += "mkdir -p `$RPM_BUILD_ROOT$linkDir`n" - # For RPM, we copy the symlink itself (which fpm does by including it in the source) - # The symlink at $link.Source points to the actual target, so we'll copy it + # For RPM, we copy the symlink itself. + # The symlink at $link.Source points to the actual target, so we'll copy it. # The -P flag preserves symlinks rather than copying their targets, which is critical for this operation. $specContent += "cp -P $($link.Source) `$RPM_BUILD_ROOT$($link.Destination)`n" } @@ -1733,6 +1725,217 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination return $specContent } +function New-NativeDeb +{ + param( + [Parameter(Mandatory, HelpMessage='Package Name')] + [String]$Name, + + [Parameter(Mandatory, HelpMessage='Package Version')] + [String]$Version, + + [Parameter(Mandatory)] + [String]$Iteration, + + [Parameter(Mandatory, HelpMessage='Package description')] + [String]$Description, + + [Parameter(Mandatory, HelpMessage='Staging folder for installation files')] + [String]$Staging, + + [Parameter(Mandatory, HelpMessage='Install path on target machine')] + [String]$Destination, + + [Parameter(Mandatory, HelpMessage='The built and gzipped man file.')] + [String]$ManGzipFile, + + [Parameter(Mandatory, HelpMessage='The destination of the man file')] + [String]$ManDestination, + + [Parameter(Mandatory, HelpMessage='Symlink to powershell executable')] + [LinkInfo[]]$LinkInfo, + + [Parameter(HelpMessage='Packages required to install this package.')] + [String[]]$Dependencies, + + [Parameter(HelpMessage='Script to run after the package installation.')] + [String]$AfterInstallScript, + + [Parameter(HelpMessage='Script to run after the package removal.')] + [String]$AfterRemoveScript, + + [string]$HostArchitecture, + + [string]$CurrentLocation + ) + + Write-Log "Creating native DEB package..." + + # Create temporary build directory + $debBuildRoot = Join-Path $env:HOME "debbuild-$(Get-Random)" + $debianDir = Join-Path $debBuildRoot "DEBIAN" + $dataDir = Join-Path $debBuildRoot "data" + + try { + New-Item -ItemType Directory -Path $debianDir -Force | Out-Null + New-Item -ItemType Directory -Path $dataDir -Force | Out-Null + + # Calculate installed size (in KB) + $installedSize = 0 + Get-ChildItem -Path $Staging -Recurse -File | ForEach-Object { $installedSize += $_.Length } + $installedSize += (Get-Item $ManGzipFile).Length + $installedSizeKB = [Math]::Ceiling($installedSize / 1024) + + # Create control file with all fields in proper order + # Description must be single line (first line) followed by extended description with leading space + $descriptionLines = $Description -split "`n" + $shortDescription = $descriptionLines[0] + $extendedDescription = if ($descriptionLines.Count -gt 1) { + ($descriptionLines[1..($descriptionLines.Count-1)] | ForEach-Object { " $_" }) -join "`n" + } + + $controlContent = @" +Package: $Name +Version: $Version-$Iteration +Architecture: $HostArchitecture +Maintainer: PowerShell Team +Installed-Size: $installedSizeKB +Priority: optional +Section: shells +Homepage: https://microsoft.com/powershell +Depends: $(if ($Dependencies) { $Dependencies -join ', ' }) +Description: $shortDescription +$(if ($extendedDescription) { $extendedDescription + "`n" }) +"@ + + $controlFile = Join-Path $debianDir "control" + $controlContent | Out-File -FilePath $controlFile -Encoding ascii -NoNewline + + Write-Verbose "Control file created: $controlFile" -Verbose + Write-LogGroup -Title "DEB Control File Content" -Message $controlContent + + # Copy postinst script if provided + if ($AfterInstallScript -and (Test-Path $AfterInstallScript)) { + $postinstFile = Join-Path $debianDir "postinst" + Copy-Item -Path $AfterInstallScript -Destination $postinstFile -Force + Start-NativeExecution { chmod 755 $postinstFile } + Write-Verbose "Postinst script copied to: $postinstFile" -Verbose + } + + # Copy postrm script if provided + if ($AfterRemoveScript -and (Test-Path $AfterRemoveScript)) { + $postrmFile = Join-Path $debianDir "postrm" + Copy-Item -Path $AfterRemoveScript -Destination $postrmFile -Force + Start-NativeExecution { chmod 755 $postrmFile } + Write-Verbose "Postrm script copied to: $postrmFile" -Verbose + } + + # Copy staging files to data directory + $targetPath = Join-Path $dataDir $Destination.TrimStart('/') + New-Item -ItemType Directory -Path $targetPath -Force | Out-Null + Copy-Item -Path "$Staging/*" -Destination $targetPath -Recurse -Force + Write-Verbose "Copied staging files to: $targetPath" -Verbose + + # Copy man page + $manDestPath = Join-Path $dataDir $ManDestination.TrimStart('/') + $manDestDir = Split-Path $manDestPath -Parent + New-Item -ItemType Directory -Path $manDestDir -Force | Out-Null + Copy-Item -Path $ManGzipFile -Destination $manDestPath -Force + Write-Verbose "Copied man page to: $manDestPath" -Verbose + + # Copy symlinks from temporary locations + foreach ($link in $LinkInfo) { + $linkPath = Join-Path $dataDir $link.Destination.TrimStart('/') + $linkDir = Split-Path $linkPath -Parent + New-Item -ItemType Directory -Path $linkDir -Force | Out-Null + + # Copy the temporary symlink file that was created by New-LinkInfo + # The Source contains a temporary symlink that points to the correct target + if (Test-Path $link.Source) { + # Use cp to preserve the symlink + Start-NativeExecution { cp -P $link.Source $linkPath } + Write-Verbose "Copied symlink: $linkPath (from $($link.Source))" -Verbose + } else { + Write-Warning "Symlink source not found: $($link.Source)" + } + } + + # Set proper permissions + Write-Verbose "Setting file permissions..." -Verbose + # 755 = rwxr-xr-x (owner can read/write/execute, group and others can read/execute) + Get-ChildItem $dataDir -Directory -Recurse | ForEach-Object { + Start-NativeExecution { chmod 755 $_.FullName } + } + # 644 = rw-r--r-- (owner can read/write, group and others can read only) + # Exclude symlinks to avoid "cannot operate on dangling symlink" error + Get-ChildItem $dataDir -File -Recurse | + Where-Object { -not $_.Target } | + ForEach-Object { + Start-NativeExecution { chmod 644 $_.FullName } + } + + # Set executable permission for pwsh if it exists + # 755 = rwxr-xr-x (executable permission) + $pwshPath = "$targetPath/pwsh" + if (Test-Path $pwshPath) { + Start-NativeExecution { chmod 755 $pwshPath } + } + + # Calculate md5sums for all files in data directory (excluding symlinks) + $md5sumsFile = Join-Path $debianDir "md5sums" + $md5Content = "" + Get-ChildItem -Path $dataDir -Recurse -File | + Where-Object { -not $_.Target } | + ForEach-Object { + $relativePath = $_.FullName.Substring($dataDir.Length + 1) + $md5Hash = (Get-FileHash -Path $_.FullName -Algorithm MD5).Hash.ToLower() + $md5Content += "$md5Hash $relativePath`n" + } + $md5Content | Out-File -FilePath $md5sumsFile -Encoding ascii -NoNewline + Write-Verbose "MD5 sums file created: $md5sumsFile" -Verbose + + # Build the package using dpkg-deb + $debFileName = "${Name}_${Version}-${Iteration}_${HostArchitecture}.deb" + $debFilePath = Join-Path $CurrentLocation $debFileName + + Write-Verbose "Building DEB package: $debFileName" -Verbose + + # Copy DEBIAN directory and data files to build root + $buildDir = Join-Path $debBuildRoot "build" + New-Item -ItemType Directory -Path $buildDir -Force | Out-Null + + Write-Verbose "debianDir: $debianDir" -Verbose + Write-Verbose "dataDir: $dataDir" -Verbose + Write-Verbose "buildDir: $buildDir" -Verbose + + # Use cp to preserve symlinks + Start-NativeExecution { cp -a $debianDir "$buildDir/DEBIAN" } + Start-NativeExecution { cp -a $dataDir/* $buildDir } + + # Build package with dpkg-deb + Start-NativeExecution -VerboseOutputOnError { + dpkg-deb --build $buildDir $debFilePath + } + + if (Test-Path $debFilePath) { + Write-Log "Successfully created DEB package: $debFileName" + return @{ + PackagePath = $debFilePath + PackageName = $debFileName + } + } else { + throw "DEB package file not found after build: $debFilePath" + } + } + finally { + # Cleanup temporary directory + if (Test-Path $debBuildRoot) { + Write-Verbose "Cleaning up temporary build directory: $debBuildRoot" -Verbose + Remove-Item -Path $debBuildRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } +} + function New-MacOSPackage { [CmdletBinding(SupportsShouldProcess=$true)] @@ -1884,146 +2087,6 @@ function New-MacOSPackage } } -function Get-FpmArguments -{ - param( - [Parameter(Mandatory,HelpMessage='Package Name')] - [String]$Name, - - [Parameter(Mandatory,HelpMessage='Package Version')] - [String]$Version, - - [Parameter(Mandatory)] - [String]$Iteration, - - [Parameter(Mandatory,HelpMessage='Package description')] - [String]$Description, - - # From start-PSPackage without modification, already validated - # Values: deb, rpm, osxpkg - [Parameter(Mandatory,HelpMessage='Installer Type')] - [String]$Type, - - [Parameter(Mandatory,HelpMessage='Staging folder for installation files')] - [String]$Staging, - - [Parameter(Mandatory,HelpMessage='Install path on target machine')] - [String]$Destination, - - [Parameter(Mandatory,HelpMessage='The built and gzipped man file.')] - [String]$ManGzipFile, - - [Parameter(Mandatory,HelpMessage='The destination of the man file')] - [String]$ManDestination, - - [Parameter(Mandatory,HelpMessage='Symlink to powershell executable')] - [LinkInfo[]]$LinkInfo, - - [Parameter(HelpMessage='Packages required to install this package. Not applicable for MacOS.')] - [ValidateScript({ - if (!$Environment.IsMacOS -and $_.Count -eq 0) - { - throw "Must not be null or empty on this environment." - } - return $true - })] - [String[]]$Dependencies, - - [Parameter(HelpMessage='Script to run after the package installation.')] - [AllowNull()] - [ValidateScript({ - if (!$Environment.IsMacOS -and !$_) - { - throw "Must not be null on this environment." - } - return $true - })] - [String]$AfterInstallScript, - - [Parameter(HelpMessage='Script to run after the package removal.')] - [AllowNull()] - [ValidateScript({ - if (!$Environment.IsMacOS -and !$_) - { - throw "Must not be null on this environment." - } - return $true - })] - [String]$AfterRemoveScript, - - [Parameter(HelpMessage='AppsFolder used to add macOS launcher')] - [AllowNull()] - [ValidateScript({ - if ($Environment.IsMacOS -and !$_) - { - throw "Must not be null on this environment." - } - return $true - })] - [String]$AppsFolder, - [String]$Distribution = 'rhel.7', - [string]$HostArchitecture - ) - - $Arguments = @( - "--force", "--verbose", - "--name", $Name, - "--version", $Version, - "--iteration", $Iteration, - "--maintainer", "PowerShell Team ", - "--vendor", "Microsoft Corporation", - "--url", "https://microsoft.com/powershell", - "--description", $Description, - "--architecture", $HostArchitecture, - "--category", "shells", - "-t", $Type, - "-s", "dir" - ) - if ($Distribution -in $script:RedHatDistributions) { - $Arguments += @("--rpm-digest", "sha256") - $Arguments += @("--rpm-dist", $Distribution) - $Arguments += @("--rpm-os", "linux") - $Arguments += @("--license", "MIT") - $Arguments += @("--rpm-rpmbuild-define", "_build_id_links none") - } else { - $Arguments += @("--license", "MIT License") - } - - if ($Environment.IsMacOS) { - $Arguments += @("--osxpkg-identifier-prefix", "com.microsoft") - } - - foreach ($Dependency in $Dependencies) { - $Arguments += @("--depends", $Dependency) - } - - if ($AfterInstallScript) { - $Arguments += @("--after-install", $AfterInstallScript) - } - - if ($AfterRemoveScript) { - $Arguments += @("--after-remove", $AfterRemoveScript) - } - - $Arguments += @( - "$Staging/=$Destination/", - "$ManGzipFile=$ManDestination" - ) - - foreach($link in $LinkInfo) - { - $linkArgument = "$($link.Source)=$($link.Destination)" - $Arguments += $linkArgument - } - - if ($AppsFolder) - { - $Arguments += "$AppsFolder=/" - } - - return $Arguments -} - function Get-PackageDependencies { [CmdletBinding()] @@ -2096,44 +2159,25 @@ function Get-PackageDependencies function Test-Dependencies { - # Note: RPM packages no longer require fpm; they use rpmbuild directly - # macOS packages use pkgbuild and productbuild from Xcode Command Line Tools - # DEB packages still use fpm + # RPM packages use rpmbuild directly. + # DEB packages use dpkg-deb directly. + # macOS packages use pkgbuild and productbuild from Xcode Command Line Tools. $Dependencies = @() - - # Only check for fpm on Debian-based systems - if ($Environment.IsDebianFamily) { - $Dependencies += "fpm" + + # Check for 'rpmbuild' and 'dpkg-deb' on Azure Linux. + if ($Environment.IsMariner) { + $Dependencies += "dpkg-deb" + $Dependencies += "rpmbuild" } - + # Check for macOS packaging tools if ($Environment.IsMacOS) { $Dependencies += "pkgbuild" $Dependencies += "productbuild" } - + foreach ($Dependency in $Dependencies) { if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - # For Debian systems, try adding ruby gems to the path - if ($Environment.IsDebianFamily) { - # These tools are not added to the path automatically on OpenSUSE 13.2 - # try adding them to the path and re-tesing first - [string] $gemsPath = $null - [string] $depenencyPath = $null - $gemsPath = Get-ChildItem -Path /usr/lib64/ruby/gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName - if ($gemsPath) { - $depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName - $originalPath = $env:PATH - $env:PATH = $ENV:PATH +":" + $depenencyPath - if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) { - continue - } - else { - $env:PATH = $originalPath - } - } - } - throw "Dependency precheck failed!" } } From 0b313f71111c159cd244d74b0e3668eeb776df3e Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 25 Nov 2025 14:23:36 -0800 Subject: [PATCH 019/127] [release/v7.6] Add reusable get-changed-files action and refactor existing actions (#26529) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../get-changed-files/README.md | 122 ++++++++++++++++++ .../get-changed-files/action.yml | 117 +++++++++++++++++ .../infrastructure/markdownlinks/action.yml | 47 ++----- .../infrastructure/path-filters/action.yml | 104 ++++++++------- 4 files changed, 305 insertions(+), 85 deletions(-) create mode 100644 .github/actions/infrastructure/get-changed-files/README.md create mode 100644 .github/actions/infrastructure/get-changed-files/action.yml diff --git a/.github/actions/infrastructure/get-changed-files/README.md b/.github/actions/infrastructure/get-changed-files/README.md new file mode 100644 index 00000000000..277b28c0674 --- /dev/null +++ b/.github/actions/infrastructure/get-changed-files/README.md @@ -0,0 +1,122 @@ +# Get Changed Files Action + +A reusable composite action that retrieves the list of files changed in a pull request or push event. + +## Features + +- Supports both `pull_request` and `push` events +- Optional filtering by file pattern +- Returns files as JSON array for easy consumption +- Filters out deleted files (only returns added, modified, or renamed files) +- Handles up to 100 changed files per request + +## Usage + +### Basic Usage (Pull Requests Only) + +```yaml +- name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + +- name: Process files + run: | + echo "Changed files: ${{ steps.changed-files.outputs.files }}" + echo "Count: ${{ steps.changed-files.outputs.count }}" +``` + +### With Filtering + +```yaml +# Get only markdown files +- name: Get changed markdown files + id: changed-md + uses: "./.github/actions/infrastructure/get-changed-files" + with: + filter: '*.md' + +# Get only GitHub workflow/action files +- name: Get changed GitHub files + id: changed-github + uses: "./.github/actions/infrastructure/get-changed-files" + with: + filter: '.github/' +``` + +### Support Both PR and Push Events + +```yaml +- name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + with: + event-types: 'pull_request,push' +``` + +## Inputs + +| Name | Description | Required | Default | +|------|-------------|----------|---------| +| `filter` | Optional filter pattern (e.g., `*.md` for markdown files, `.github/` for GitHub files) | No | `''` | +| `event-types` | Comma-separated list of event types to support (`pull_request`, `push`) | No | `pull_request` | + +## Outputs + +| Name | Description | +|------|-------------| +| `files` | JSON array of changed file paths | +| `count` | Number of changed files | + +## Filter Patterns + +The action supports simple filter patterns: + +- **Extension matching**: Use `*.ext` to match files with a specific extension + - Example: `*.md` matches all markdown files + - Example: `*.yml` matches all YAML files + +- **Path prefix matching**: Use a path prefix to match files in a directory + - Example: `.github/` matches all files in the `.github` directory + - Example: `tools/` matches all files in the `tools` directory + +## Example: Processing Changed Files + +```yaml +- name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + +- name: Process each file + shell: pwsh + env: + CHANGED_FILES: ${{ steps.changed-files.outputs.files }} + run: | + $changedFilesJson = $env:CHANGED_FILES + $changedFiles = $changedFilesJson | ConvertFrom-Json + + foreach ($file in $changedFiles) { + Write-Host "Processing: $file" + # Your processing logic here + } +``` + +## Limitations + +- Simple filter patterns only (no complex glob or regex patterns) + +## Pagination + +The action automatically handles pagination to fetch **all** changed files in a PR, regardless of how many files were changed: + +- Fetches files in batches of 100 per page +- Continues fetching until all files are retrieved +- Logs a note when pagination occurs, showing the total file count +- **No file limit** - all changed files will be processed, even in very large PRs + +This ensures that critical workflows (such as merge conflict checking, link validation, etc.) don't miss files due to pagination limits. + +## Related Actions + +- **markdownlinks**: Uses this pattern to get changed markdown files +- **merge-conflict-checker**: Uses this pattern to get changed files for conflict detection +- **path-filters**: Similar functionality but with more complex filtering logic diff --git a/.github/actions/infrastructure/get-changed-files/action.yml b/.github/actions/infrastructure/get-changed-files/action.yml new file mode 100644 index 00000000000..c897d4f388d --- /dev/null +++ b/.github/actions/infrastructure/get-changed-files/action.yml @@ -0,0 +1,117 @@ +name: 'Get Changed Files' +description: 'Gets the list of files changed in a pull request or push event' +inputs: + filter: + description: 'Optional filter pattern (e.g., "*.md" for markdown files, ".github/" for GitHub files)' + required: false + default: '' + event-types: + description: 'Comma-separated list of event types to support (pull_request, push)' + required: false + default: 'pull_request' +outputs: + files: + description: 'JSON array of changed file paths' + value: ${{ steps.get-files.outputs.files }} + count: + description: 'Number of changed files' + value: ${{ steps.get-files.outputs.count }} +runs: + using: 'composite' + steps: + - name: Get changed files + id: get-files + uses: actions/github-script@v7 + with: + script: | + const eventTypes = '${{ inputs.event-types }}'.split(',').map(t => t.trim()); + const filter = '${{ inputs.filter }}'; + let changedFiles = []; + + if (eventTypes.includes('pull_request') && context.eventName === 'pull_request') { + console.log(`Getting files changed in PR #${context.payload.pull_request.number}`); + + // Fetch all files changed in the PR with pagination + let allFiles = []; + let page = 1; + let fetchedCount; + + do { + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + per_page: 100, + page: page + }); + + allFiles = allFiles.concat(files); + fetchedCount = files.length; + page++; + } while (fetchedCount === 100); + + if (allFiles.length >= 100) { + console.log(`Note: This PR has ${allFiles.length} changed files. All files fetched using pagination.`); + } + + changedFiles = allFiles + .filter(file => file.status === 'added' || file.status === 'modified' || file.status === 'renamed') + .map(file => file.filename); + + } else if (eventTypes.includes('push') && context.eventName === 'push') { + console.log(`Getting files changed in push to ${context.ref}`); + + const { data: comparison } = await github.rest.repos.compareCommits({ + owner: context.repo.owner, + repo: context.repo.repo, + base: context.payload.before, + head: context.payload.after, + }); + + changedFiles = comparison.files + .filter(file => file.status === 'added' || file.status === 'modified' || file.status === 'renamed') + .map(file => file.filename); + + } else { + core.setFailed(`Unsupported event type: ${context.eventName}. Supported types: ${eventTypes.join(', ')}`); + return; + } + + // Apply filter if provided + if (filter) { + const filterLower = filter.toLowerCase(); + const beforeFilter = changedFiles.length; + changedFiles = changedFiles.filter(file => { + const fileLower = file.toLowerCase(); + // Support simple patterns like "*.md" or ".github/" + if (filterLower.startsWith('*.')) { + const ext = filterLower.substring(1); + return fileLower.endsWith(ext); + } else { + return fileLower.startsWith(filterLower); + } + }); + console.log(`Filter '${filter}' applied: ${beforeFilter} → ${changedFiles.length} files`); + } + + // Calculate simple hash for verification + const crypto = require('crypto'); + const filesJson = JSON.stringify(changedFiles.sort()); + const hash = crypto.createHash('sha256').update(filesJson).digest('hex').substring(0, 8); + + // Log changed files in a collapsible group + core.startGroup(`Changed Files (${changedFiles.length} total, hash: ${hash})`); + if (changedFiles.length > 0) { + changedFiles.forEach(file => console.log(` - ${file}`)); + } else { + console.log(' (no files changed)'); + } + core.endGroup(); + + console.log(`Found ${changedFiles.length} changed files`); + core.setOutput('files', JSON.stringify(changedFiles)); + core.setOutput('count', changedFiles.length); + +branding: + icon: 'file-text' + color: 'blue' diff --git a/.github/actions/infrastructure/markdownlinks/action.yml b/.github/actions/infrastructure/markdownlinks/action.yml index 1d6d0864784..de2952252d4 100644 --- a/.github/actions/infrastructure/markdownlinks/action.yml +++ b/.github/actions/infrastructure/markdownlinks/action.yml @@ -31,52 +31,23 @@ runs: steps: - name: Get changed markdown files id: changed-files - uses: actions/github-script@v7 + uses: "./.github/actions/infrastructure/get-changed-files" with: - script: | - let changedMarkdownFiles = []; - - if (context.eventName === 'pull_request') { - const { data: files } = await github.rest.pulls.listFiles({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.payload.pull_request.number, - }); - - changedMarkdownFiles = files - .filter(file => file.filename.endsWith('.md')) - .map(file => file.filename); - } else if (context.eventName === 'push') { - const { data: comparison } = await github.rest.repos.compareCommits({ - owner: context.repo.owner, - repo: context.repo.repo, - base: context.payload.before, - head: context.payload.after, - }); - - changedMarkdownFiles = comparison.files - .filter(file => file.filename.endsWith('.md')) - .map(file => file.filename); - } else { - core.setFailed(`Unsupported event type: ${context.eventName}. This action only supports 'pull_request' and 'push' events.`); - return; - } - - console.log('Changed markdown files:', changedMarkdownFiles); - core.setOutput('files', JSON.stringify(changedMarkdownFiles)); - core.setOutput('count', changedMarkdownFiles.length); - return changedMarkdownFiles; + filter: '*.md' + event-types: 'pull_request,push' - name: Verify markdown links id: verify shell: pwsh + env: + CHANGED_FILES_JSON: ${{ steps.changed-files.outputs.files }} run: | Write-Host "Starting markdown link verification..." -ForegroundColor Cyan - # Get changed markdown files from previous step - $changedFilesJson = '${{ steps.changed-files.outputs.files }}' + # Get changed markdown files from environment variable (secure against injection) + $changedFilesJson = $env:CHANGED_FILES_JSON $changedFiles = $changedFilesJson | ConvertFrom-Json - + if ($changedFiles.Count -eq 0) { Write-Host "No markdown files changed, skipping verification" -ForegroundColor Yellow "total=0" >> $env:GITHUB_OUTPUT @@ -85,7 +56,7 @@ runs: "skipped=0" >> $env:GITHUB_OUTPUT exit 0 } - + Write-Host "Changed markdown files: $($changedFiles.Count)" -ForegroundColor Cyan $changedFiles | ForEach-Object { Write-Host " - $_" -ForegroundColor Gray } diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index 09ed7c22d17..656719262b2 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -32,9 +32,16 @@ outputs: runs: using: composite steps: + - name: Get changed files + id: get-files + if: github.event_name == 'pull_request' + uses: "./.github/actions/infrastructure/get-changed-files" + - name: Check if GitHubWorkflowChanges is present id: filter uses: actions/github-script@v7.0.1 + env: + FILES_JSON: ${{ steps.get-files.outputs.files }} with: github-token: ${{ inputs.GITHUB_TOKEN }} script: | @@ -53,55 +60,71 @@ runs: return; } - console.log(`Getting files changed in PR #${context.issue.number}`); - - // Fetch the list of files changed in the PR - let files = []; - let page = 1; - let fetchedFiles; - do { - fetchedFiles = await github.rest.pulls.listFiles({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number, - per_page: 100, - page: page++ - }); - files = files.concat(fetchedFiles.data); - } while (fetchedFiles.data.length > 0); - - const actionsChanged = files.some(file => file.filename.startsWith('.github/actions')); - const workflowsChanged = files.some(file => file.filename.startsWith('.github/workflows')); + // Get files from environment variable (secure against injection) + const files = JSON.parse(process.env.FILES_JSON || '[]'); + + // Calculate hash for verification (matches get-changed-files action) + const crypto = require('crypto'); + const filesJson = JSON.stringify(files.sort()); + const hash = crypto.createHash('sha256').update(filesJson).digest('hex').substring(0, 8); + console.log(`Received ${files.length} files (hash: ${hash})`); + + // Analyze changes with detailed logging + core.startGroup('Path Filter Analysis'); + + const actionsChanged = files.some(file => file.startsWith('.github/actions')); + console.log(`✓ Actions changed: ${actionsChanged}`); + + const workflowsChanged = files.some(file => file.startsWith('.github/workflows')); + console.log(`✓ Workflows changed: ${workflowsChanged}`); + const githubChanged = actionsChanged || workflowsChanged; + console.log(`→ GitHub changed (actions OR workflows): ${githubChanged}`); + + const toolsCiPsm1Changed = files.some(file => file === 'tools/ci.psm1'); + console.log(`✓ tools/ci.psm1 changed: ${toolsCiPsm1Changed}`); + + const toolsBuildCommonChanged = files.some(file => file.startsWith('tools/buildCommon/')); + console.log(`✓ tools/buildCommon/ changed: ${toolsBuildCommonChanged}`); - const toolsCiPsm1Changed = files.some(file => file.filename.startsWith('tools/ci.psm1')); - const toolsBuildCommonChanged = files.some(file => file.filename.startsWith('tools/buildCommon/')); const toolsChanged = toolsCiPsm1Changed || toolsBuildCommonChanged; + console.log(`→ Tools changed: ${toolsChanged}`); - const propsChanged = files.some(file => file.filename.endsWith('.props')); + const propsChanged = files.some(file => file.endsWith('.props')); + console.log(`✓ Props files changed: ${propsChanged}`); - const testsChanged = files.some(file => file.filename.startsWith('test/powershell/') || file.filename.startsWith('test/tools/') || file.filename.startsWith('test/xUnit/')); + const testsChanged = files.some(file => file.startsWith('test/powershell/') || file.startsWith('test/tools/') || file.startsWith('test/xUnit/')); + console.log(`✓ Tests changed: ${testsChanged}`); - const mainSourceChanged = files.some(file => file.filename.startsWith('src/')); + const mainSourceChanged = files.some(file => file.startsWith('src/')); + console.log(`✓ Main source (src/) changed: ${mainSourceChanged}`); - const buildModuleChanged = files.some(file => file.filename.startsWith('build.psm1')); + const buildModuleChanged = files.some(file => file === 'build.psm1'); + console.log(`✓ build.psm1 changed: ${buildModuleChanged}`); - const globalConfigChanged = files.some(file => file.filename.startsWith('.globalconfig')) || files.some(file => file.filename.startsWith('nuget.config')) || files.some(file => file.filename.startsWith('global.json')); + const globalConfigChanged = files.some(file => file === '.globalconfig' || file === 'nuget.config' || file === 'global.json'); + console.log(`✓ Global config changed: ${globalConfigChanged}`); - const packagingChanged = files.some(file => - file.filename === '.github/workflows/windows-ci.yml' || - file.filename.startsWith('assets/wix/') || - file.filename === 'PowerShell.Common.props' || - file.filename.match(/^src\/.*\.csproj$/) || - file.filename.startsWith('test/packaging/windows/') || - file.filename.startsWith('tools/packaging/') || - file.filename.startsWith('tools/wix/') + const packagingChanged = files.some(file => + file === '.github/workflows/windows-ci.yml' || + file === '.github/workflows/linux-ci.yml' || + file.startsWith('assets/wix/') || + file === 'PowerShell.Common.props' || + file.match(/^src\/.*\.csproj$/) || + file.startsWith('test/packaging/windows/') || + file.startsWith('test/packaging/linux/') || + file.startsWith('tools/packaging/') || + file.startsWith('tools/wix/') ) || buildModuleChanged || globalConfigChanged || toolsCiPsm1Changed; + console.log(`→ Packaging changed: ${packagingChanged}`); const source = mainSourceChanged || toolsChanged || githubChanged || propsChanged || testsChanged || globalConfigChanged; + console.log(`→ Source (composite): ${source}`); + + core.endGroup(); core.setOutput('toolsChanged', toolsChanged); core.setOutput('githubChanged', githubChanged); @@ -112,16 +135,3 @@ runs: core.setOutput('globalConfigChanged', globalConfigChanged); core.setOutput('packagingChanged', packagingChanged); core.setOutput('source', source); - - - - name: Capture outputs - run: | - Write-Verbose -Verbose "source: ${{ steps.filter.outputs.source }}" - Write-Verbose -Verbose "github: ${{ steps.filter.outputs.githubChanged }}" - Write-Verbose -Verbose "tools: ${{ steps.filter.outputs.toolsChanged }}" - Write-Verbose -Verbose "props: ${{ steps.filter.outputs.propsChanged }}" - Write-Verbose -Verbose "tests: ${{ steps.filter.outputs.testsChanged }}" - Write-Verbose -Verbose "mainSource: ${{ steps.filter.outputs.mainSourceChanged }}" - Write-Verbose -Verbose "buildModule: ${{ steps.filter.outputs.buildModuleChanged }}" - Write-Verbose -Verbose "packaging: ${{ steps.filter.outputs.packagingChanged }}" - shell: pwsh From c63af4e2c910165f7a2055b062e282e94c7f573e Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 2 Dec 2025 15:56:04 -0800 Subject: [PATCH 020/127] [release/v7.6] Fix merge conflict checker for empty file lists and filter *.cs files (#26556) --- .../merge-conflict-checker/README.md | 86 ++++++ .../merge-conflict-checker/action.yml | 37 +++ test/infrastructure/ciModule.Tests.ps1 | 246 ++++++++++++++++++ tools/ci.psm1 | 224 +++++++++++++++- 4 files changed, 592 insertions(+), 1 deletion(-) create mode 100644 .github/actions/infrastructure/merge-conflict-checker/README.md create mode 100644 .github/actions/infrastructure/merge-conflict-checker/action.yml create mode 100644 test/infrastructure/ciModule.Tests.ps1 diff --git a/.github/actions/infrastructure/merge-conflict-checker/README.md b/.github/actions/infrastructure/merge-conflict-checker/README.md new file mode 100644 index 00000000000..b53d6f99964 --- /dev/null +++ b/.github/actions/infrastructure/merge-conflict-checker/README.md @@ -0,0 +1,86 @@ +# Merge Conflict Checker + +This composite GitHub Action checks for Git merge conflict markers in files changed in pull requests. + +## Purpose + +Automatically detects leftover merge conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) in pull request files to prevent them from being merged into the codebase. + +## Usage + +### In a Workflow + +```yaml +- name: Check for merge conflict markers + uses: "./.github/actions/infrastructure/merge-conflict-checker" +``` + +### Complete Example + +```yaml +jobs: + merge_conflict_check: + name: Check for Merge Conflict Markers + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + permissions: + pull-requests: read + contents: read + steps: + - name: checkout + uses: actions/checkout@v5 + + - name: Check for merge conflict markers + uses: "./.github/actions/infrastructure/merge-conflict-checker" +``` + +## How It Works + +1. **File Detection**: Uses GitHub's API to get the list of files changed in the pull request +2. **Marker Scanning**: Reads each changed file and searches for the following markers: + - `<<<<<<<` (conflict start marker) + - `=======` (conflict separator) + - `>>>>>>>` (conflict end marker) +3. **Result Reporting**: + - If markers are found, the action fails and lists all affected files + - If no markers are found, the action succeeds + +## Outputs + +- `files-checked`: Number of files that were checked +- `conflicts-found`: Number of files containing merge conflict markers + +## Behavior + +- **Event Support**: Only works with `pull_request` events +- **File Handling**: + - Checks only files that were added, modified, or renamed + - Skips deleted files + - **Filters out `*.cs` files** (C# files are excluded from merge conflict checking) + - Skips binary/unreadable files + - Skips directories +- **Empty File List**: Gracefully handles cases where no files need checking (e.g., PRs that only delete files) + +## Example Output + +When conflict markers are detected: + +``` +❌ Merge conflict markers detected in the following files: + - src/example.cs + Markers found: <<<<<<<, =======, >>>>>>> + - README.md + Markers found: <<<<<<<, =======, >>>>>>> + +Please resolve these conflicts before merging. +``` + +When no markers are found: + +``` +✅ No merge conflict markers found +``` + +## Integration + +This action is integrated into the `linux-ci.yml` workflow and runs automatically on all pull requests to ensure code quality before merging. diff --git a/.github/actions/infrastructure/merge-conflict-checker/action.yml b/.github/actions/infrastructure/merge-conflict-checker/action.yml new file mode 100644 index 00000000000..41c7d2ad941 --- /dev/null +++ b/.github/actions/infrastructure/merge-conflict-checker/action.yml @@ -0,0 +1,37 @@ +name: 'Check for Merge Conflict Markers' +description: 'Checks for Git merge conflict markers in changed files for pull requests' +author: 'PowerShell Team' + +outputs: + files-checked: + description: 'Number of files checked for merge conflict markers' + value: ${{ steps.check.outputs.files-checked }} + conflicts-found: + description: 'Number of files with merge conflict markers' + value: ${{ steps.check.outputs.conflicts-found }} + +runs: + using: 'composite' + steps: + - name: Get changed files + id: changed-files + uses: "./.github/actions/infrastructure/get-changed-files" + + - name: Check for merge conflict markers + id: check + shell: pwsh + env: + CHANGED_FILES_JSON: ${{ steps.changed-files.outputs.files }} + run: | + # Get changed files from environment variable (secure against injection) + $changedFilesJson = $env:CHANGED_FILES_JSON + # Ensure we always have an array (ConvertFrom-Json returns null for empty JSON arrays) + $changedFiles = @($changedFilesJson | ConvertFrom-Json) + + # Import ci.psm1 and run the check + Import-Module "$env:GITHUB_WORKSPACE/tools/ci.psm1" -Force + Test-MergeConflictMarker -File $changedFiles -WorkspacePath $env:GITHUB_WORKSPACE + +branding: + icon: 'alert-triangle' + color: 'red' diff --git a/test/infrastructure/ciModule.Tests.ps1 b/test/infrastructure/ciModule.Tests.ps1 new file mode 100644 index 00000000000..b7320ff49b7 --- /dev/null +++ b/test/infrastructure/ciModule.Tests.ps1 @@ -0,0 +1,246 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +# NOTE: This test file tests the Test-MergeConflictMarker function which detects Git merge conflict markers. +# IMPORTANT: Do NOT use here-strings or literal conflict markers (e.g., "<<<<<<<", "=======", ">>>>>>>") +# in this file, as they will trigger conflict marker detection in CI pipelines. +# Instead, use string multiplication (e.g., '<' * 7) to dynamically generate these markers at runtime. + +Describe "Test-MergeConflictMarker" { + BeforeAll { + # Import the module + Import-Module "$PSScriptRoot/../../tools/ci.psm1" -Force + + # Create a temporary test workspace + $script:testWorkspace = Join-Path $TestDrive "workspace" + New-Item -ItemType Directory -Path $script:testWorkspace -Force | Out-Null + + # Create temporary output files + $script:testOutputPath = Join-Path $TestDrive "outputs.txt" + $script:testSummaryPath = Join-Path $TestDrive "summary.md" + } + + AfterEach { + # Clean up test files after each test + if (Test-Path $script:testWorkspace) { + Get-ChildItem $script:testWorkspace -File -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue + } + Remove-Item $script:testOutputPath -Force -ErrorAction SilentlyContinue + Remove-Item $script:testSummaryPath -Force -ErrorAction SilentlyContinue + } + + Context "When no files are provided" { + It "Should handle empty file array gracefully" { + # The function now accepts empty arrays to handle cases like delete-only PRs + $emptyArray = @() + Test-MergeConflictMarker -File $emptyArray -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=0" + $outputs | Should -Contain "conflicts-found=0" + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "No Files to Check" + } + } + + Context "When files have no conflicts" { + It "Should pass for clean files" { + $testFile = Join-Path $script:testWorkspace "clean.txt" + "This is a clean file" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("clean.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=1" + $outputs | Should -Contain "conflicts-found=0" + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "No Conflicts Found" + } + } + + Context "When files have conflict markers" { + It "Should detect <<<<<<< marker" { + $testFile = Join-Path $script:testWorkspace "conflict1.txt" + "Some content`n" + ('<' * 7) + " HEAD`nConflicting content" | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict1.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=1" + $outputs | Should -Contain "conflicts-found=1" + } + + It "Should detect ======= marker" { + $testFile = Join-Path $script:testWorkspace "conflict2.txt" + "Some content`n" + ('=' * 7) + "`nMore content" | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict2.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + } + + It "Should detect >>>>>>> marker" { + $testFile = Join-Path $script:testWorkspace "conflict3.txt" + "Some content`n" + ('>' * 7) + " branch-name`nMore content" | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict3.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + } + + It "Should detect multiple markers in one file" { + $testFile = Join-Path $script:testWorkspace "conflict4.txt" + $content = "Some content`n" + ('<' * 7) + " HEAD`nContent A`n" + ('=' * 7) + "`nContent B`n" + ('>' * 7) + " branch`nMore content" + $content | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict4.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "Conflicts Detected" + $summary | Should -Match "conflict4.txt" + } + + It "Should detect conflicts in multiple files" { + $testFile1 = Join-Path $script:testWorkspace "conflict5.txt" + ('<' * 7) + " HEAD" | Out-File $testFile1 -Encoding utf8 + + $testFile2 = Join-Path $script:testWorkspace "conflict6.txt" + ('=' * 7) | Out-File $testFile2 -Encoding utf8 + + { Test-MergeConflictMarker -File @("conflict5.txt", "conflict6.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=2" + $outputs | Should -Contain "conflicts-found=2" + } + } + + Context "When markers are not at line start" { + It "Should not detect markers in middle of line" { + $testFile = Join-Path $script:testWorkspace "notconflict.txt" + "This line has <<<<<<< in the middle" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("notconflict.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "conflicts-found=0" + } + + It "Should not detect markers with wrong number of characters" { + $testFile = Join-Path $script:testWorkspace "wrongcount.txt" + ('<' * 6) + " Only 6`n" + ('<' * 8) + " 8 characters" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("wrongcount.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "conflicts-found=0" + } + } + + Context "When handling special file scenarios" { + It "Should skip non-existent files" { + Test-MergeConflictMarker -File @("nonexistent.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=0" + } + + It "Should handle absolute paths" { + $testFile = Join-Path $script:testWorkspace "absolute.txt" + "Clean content" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @($testFile) -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "conflicts-found=0" + } + + It "Should handle mixed relative and absolute paths" { + $testFile1 = Join-Path $script:testWorkspace "relative.txt" + "Clean" | Out-File $testFile1 -Encoding utf8 + + $testFile2 = Join-Path $script:testWorkspace "absolute.txt" + "Clean" | Out-File $testFile2 -Encoding utf8 + + Test-MergeConflictMarker -File @("relative.txt", $testFile2) -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Should -Contain "files-checked=2" + $outputs | Should -Contain "conflicts-found=0" + } + } + + Context "When summary and output generation" { + It "Should generate proper GitHub Actions outputs format" { + $testFile = Join-Path $script:testWorkspace "test.txt" + "Clean file" | Out-File $testFile -Encoding utf8 + + Test-MergeConflictMarker -File @("test.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath + + $outputs = Get-Content $script:testOutputPath + $outputs | Where-Object {$_ -match "^files-checked=\d+$"} | Should -Not -BeNullOrEmpty + $outputs | Where-Object {$_ -match "^conflicts-found=\d+$"} | Should -Not -BeNullOrEmpty + } + + It "Should generate markdown summary with conflict details" { + $testFile = Join-Path $script:testWorkspace "marked.txt" + $content = "Line 1`n" + ('<' * 7) + " HEAD`nLine 3`n" + ('=' * 7) + "`nLine 5" + $content | Out-File $testFile -Encoding utf8 + + { Test-MergeConflictMarker -File @("marked.txt") -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw + + $summary = Get-Content $script:testSummaryPath -Raw + $summary | Should -Match "# Merge Conflict Marker Check Results" + $summary | Should -Match "marked.txt" + $summary | Should -Match "\| Line \| Marker \|" + } + } +} + +Describe "Install-CIPester" { + BeforeAll { + # Import the module + Import-Module "$PSScriptRoot/../../tools/ci.psm1" -Force + } + + Context "When checking function exists" { + It "Should export Install-CIPester function" { + $function = Get-Command Install-CIPester -ErrorAction SilentlyContinue + $function | Should -Not -BeNullOrEmpty + $function.ModuleName | Should -Be 'ci' + } + + It "Should have expected parameters" { + $function = Get-Command Install-CIPester + $function.Parameters.Keys | Should -Contain 'MinimumVersion' + $function.Parameters.Keys | Should -Contain 'MaximumVersion' + $function.Parameters.Keys | Should -Contain 'Force' + } + + It "Should accept version parameters" { + $function = Get-Command Install-CIPester + $function.Parameters['MinimumVersion'].ParameterType.Name | Should -Be 'String' + $function.Parameters['MaximumVersion'].ParameterType.Name | Should -Be 'String' + $function.Parameters['Force'].ParameterType.Name | Should -Be 'SwitchParameter' + } + } + + Context "When validating real execution" { + # These tests only run in CI where we can safely install/test Pester + + It "Should successfully run without errors when Pester exists" { + if (!$env:CI) { + Set-ItResult -Skipped -Because "Test requires CI environment to safely install Pester" + } + + { Install-CIPester -ErrorAction Stop } | Should -Not -Throw + } + + It "Should accept custom version parameters" { + if (!$env:CI) { + Set-ItResult -Skipped -Because "Test requires CI environment to safely install Pester" + } + + { Install-CIPester -MinimumVersion '4.0.0' -MaximumVersion '5.99.99' -ErrorAction Stop } | Should -Not -Throw + } + } +} + diff --git a/tools/ci.psm1 b/tools/ci.psm1 index 478435e8543..dd59df65292 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -972,8 +972,230 @@ function Invoke-InitializeContainerStage { Write-Host "##vso[build.updatebuildnumber]PR-${env:SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}-$($selectedImage.JobName)-$((get-date).ToString("yyyyMMddhhmmss"))" } else { Write-Host "##vso[build.updatebuildnumber]${env:BUILD_SOURCEBRANCHNAME}-$($selectedImage.JobName)-${env:BUILD_SOURCEVERSION}-$((get-date).ToString("yyyyMMddhhmmss"))" - # Cannot do this for a PR Write-Host "##vso[build.addbuildtag]$($selectedImage.JobName)" } } + +Function Test-MergeConflictMarker +{ + <# + .SYNOPSIS + Checks files for Git merge conflict markers and outputs results for GitHub Actions. + .DESCRIPTION + Scans the specified files for Git merge conflict markers (<<<<<<<, =======, >>>>>>>) + and generates console output, GitHub Actions outputs, and job summary. + Designed for use in GitHub Actions workflows. + .PARAMETER File + Array of file paths (relative or absolute) to check for merge conflict markers. + .PARAMETER WorkspacePath + Base workspace path for resolving relative paths. Defaults to current directory. + .PARAMETER OutputPath + Path to write GitHub Actions outputs. Defaults to $env:GITHUB_OUTPUT. + .PARAMETER SummaryPath + Path to write GitHub Actions job summary. Defaults to $env:GITHUB_STEP_SUMMARY. + .EXAMPLE + Test-MergeConflictMarker -File @('file1.txt', 'file2.cs') -WorkspacePath $env:GITHUB_WORKSPACE + #> + [CmdletBinding()] + param( + [Parameter()] + [AllowEmptyCollection()] + [string[]] $File = @(), + + [Parameter()] + [string] $WorkspacePath = $PWD, + + [Parameter()] + [string] $OutputPath = $env:GITHUB_OUTPUT, + + [Parameter()] + [string] $SummaryPath = $env:GITHUB_STEP_SUMMARY + ) + + Write-Host "Starting merge conflict marker check..." -ForegroundColor Cyan + + # Helper function to write outputs when no files to check + function Write-NoFilesOutput { + param( + [string]$Message, + [string]$OutputPath, + [string]$SummaryPath + ) + + # Output results to GitHub Actions + if ($OutputPath) { + "files-checked=0" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + "conflicts-found=0" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + } + + # Create GitHub Actions job summary + if ($SummaryPath) { + $summaryContent = @" +# Merge Conflict Marker Check Results + +## Summary +- **Files Checked:** 0 +- **Files with Conflicts:** 0 + +## ℹ️ No Files to Check + +$Message + +"@ + $summaryContent | Out-File -FilePath $SummaryPath -Encoding utf8 + } + } + + # Handle empty file list (e.g., when PR only deletes files) + if ($File.Count -eq 0) { + Write-Host "No files to check (empty file list)" -ForegroundColor Yellow + Write-NoFilesOutput -Message "No files were provided for checking (this can happen when a PR only deletes files)." -OutputPath $OutputPath -SummaryPath $SummaryPath + return + } + + # Filter out *.cs files from merge conflict checking + $filesToCheck = @($File | Where-Object { $_ -notlike "*.cs" }) + $filteredCount = $File.Count - $filesToCheck.Count + + if ($filteredCount -gt 0) { + Write-Host "Filtered out $filteredCount *.cs file(s) from merge conflict checking" -ForegroundColor Yellow + } + + if ($filesToCheck.Count -eq 0) { + Write-Host "No files to check after filtering (all files were *.cs)" -ForegroundColor Yellow + Write-NoFilesOutput -Message "All $filteredCount file(s) were filtered out (*.cs files are excluded from merge conflict checking)." -OutputPath $OutputPath -SummaryPath $SummaryPath + return + } + + Write-Host "Checking $($filesToCheck.Count) changed files for merge conflict markers" -ForegroundColor Cyan + + # Convert relative paths to absolute paths for processing + $absolutePaths = $filesToCheck | ForEach-Object { + if ([System.IO.Path]::IsPathRooted($_)) { + $_ + } else { + Join-Path $WorkspacePath $_ + } + } + + $filesWithConflicts = @() + $filesChecked = 0 + + foreach ($filePath in $absolutePaths) { + # Check if file exists (might be deleted) + if (-not (Test-Path $filePath)) { + Write-Verbose " Skipping deleted file: $filePath" + continue + } + + # Skip binary files and directories + if ((Get-Item $filePath) -is [System.IO.DirectoryInfo]) { + continue + } + + $filesChecked++ + + # Get relative path for display + $relativePath = if ($WorkspacePath -and $filePath.StartsWith($WorkspacePath)) { + $filePath.Substring($WorkspacePath.Length).TrimStart([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) + } else { + $filePath + } + + Write-Host " Checking: $relativePath" -ForegroundColor Gray + + # Search for conflict markers using Select-String + try { + # Git conflict markers are 7 characters followed by a space or end of line + # Regex pattern breakdown: + # ^ - Matches the start of a line + # (<{7}|={7}|>{7}) - Matches exactly 7 consecutive '<', '=', or '>' characters (Git conflict markers) + # (\s|$) - Ensures the marker is followed by whitespace or end of line + $pattern = '^(<{7}|={7}|>{7})(\s|$)' + $matchedLines = Select-String -Path $filePath -Pattern $pattern -AllMatches -ErrorAction Stop + + if ($matchedLines) { + # Collect marker details with line numbers (Select-String provides LineNumber automatically) + $markerDetails = @() + + foreach ($match in $matchedLines) { + $markerDetails += [PSCustomObject]@{ + Marker = $match.Matches[0].Groups[1].Value + Line = $match.LineNumber + } + } + + $filesWithConflicts += [PSCustomObject]@{ + File = $relativePath + MarkerDetails = $markerDetails + } + + Write-Host " ❌ CONFLICT MARKERS FOUND in $relativePath" -ForegroundColor Red + foreach ($detail in $markerDetails) { + Write-Host " Line $($detail.Line): $($detail.Marker)" -ForegroundColor Red + } + } + } + catch { + # Skip files that can't be read (likely binary) + Write-Verbose " Skipping unreadable file: $relativePath" + } + } + + # Output results to GitHub Actions + if ($OutputPath) { + "files-checked=$filesChecked" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + "conflicts-found=$($filesWithConflicts.Count)" | Out-File -FilePath $OutputPath -Append -Encoding utf8 + } + + Write-Host "`nSummary:" -ForegroundColor Cyan + Write-Host " Files checked: $filesChecked" -ForegroundColor Cyan + Write-Host " Files with conflicts: $($filesWithConflicts.Count)" -ForegroundColor Cyan + + # Create GitHub Actions job summary + if ($SummaryPath) { + $summaryContent = @" +# Merge Conflict Marker Check Results + +## Summary +- **Files Checked:** $filesChecked +- **Files with Conflicts:** $($filesWithConflicts.Count) + +"@ + + if ($filesWithConflicts.Count -gt 0) { + Write-Host "`n❌ Merge conflict markers detected in the following files:" -ForegroundColor Red + + $summaryContent += "`n## ❌ Conflicts Detected`n`n" + $summaryContent += "The following files contain merge conflict markers:`n`n" + + foreach ($fileInfo in $filesWithConflicts) { + Write-Host " - $($fileInfo.File)" -ForegroundColor Red + + $summaryContent += "### 📄 ``$($fileInfo.File)```n`n" + $summaryContent += "| Line | Marker |`n" + $summaryContent += "|------|--------|`n" + + foreach ($detail in $fileInfo.MarkerDetails) { + Write-Host " Line $($detail.Line): $($detail.Marker)" -ForegroundColor Red + $summaryContent += "| $($detail.Line) | ``$($detail.Marker)`` |`n" + } + $summaryContent += "`n" + } + + $summaryContent += "`n**Action Required:** Please resolve these conflicts before merging.`n" + Write-Host "`nPlease resolve these conflicts before merging." -ForegroundColor Red + } else { + Write-Host "`n✅ No merge conflict markers found" -ForegroundColor Green + $summaryContent += "`n## ✅ No Conflicts Found`n`nAll checked files are free of merge conflict markers.`n" + } + + $summaryContent | Out-File -FilePath $SummaryPath -Encoding utf8 + } + + # Exit with error if conflicts found + if ($filesWithConflicts.Count -gt 0) { + throw "Merge conflict markers detected in $($filesWithConflicts.Count) file(s)" + } +} \ No newline at end of file From b0a5ec4a852277a0068da91f0e5cbfe34f0dbd2e Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 2 Dec 2025 15:56:21 -0800 Subject: [PATCH 021/127] [release/v7.6] Optimize/split windows package signing (#26557) --- .../chatmodes/cherry-pick-commits.chatmode.md | 78 ++++++ .../instructions/build-configuration-guide.md | 13 +- ...ode-review-branch-strategy.instructions.md | 230 ++++++++++++++++++ ...anch-restore-phase-pattern.instructions.md | 83 +++++++ ...anch-signing-configuration.instructions.md | 195 +++++++++++++++ .pipelines/MSIXBundle-vPack-Official.yml | 1 - ...werShell-Coordinated_Packages-Official.yml | 1 - .pipelines/PowerShell-Packages-Official.yml | 62 +++-- .pipelines/PowerShell-vPack-Official.yml | 1 - .pipelines/templates/SetVersionVariables.yml | 59 ++--- .pipelines/templates/checkAzureContainer.yml | 3 +- .pipelines/templates/cloneToOfficialPath.yml | 18 +- .pipelines/templates/compliance/apiscan.yml | 3 +- .pipelines/templates/install-dotnet.yml | 7 +- .pipelines/templates/linux-package-build.yml | 3 +- .pipelines/templates/mac-package-build.yml | 3 +- .pipelines/templates/nupkg.yml | 3 +- .pipelines/templates/package-create-msix.yml | 6 +- .../windows/package.yml} | 149 +++--------- .../templates/packaging/windows/sign.yml | 216 ++++++++++++++++ .../templates/release-MakeBlobPublic.yml | 6 +- .../templates/release-checkout-pwsh-repo.yml | 13 - .../templates/release-download-packages.yml | 122 ---------- .pipelines/templates/release-install-pwsh.yml | 34 --- .pipelines/templates/set-reporoot.yml | 35 +++ .pipelines/templates/shouldSign.yml | 7 +- .pipelines/templates/uploadToAzure.yml | 3 +- 27 files changed, 978 insertions(+), 376 deletions(-) create mode 100644 .github/chatmodes/cherry-pick-commits.chatmode.md create mode 100644 .github/instructions/code-review-branch-strategy.instructions.md create mode 100644 .github/instructions/onebranch-restore-phase-pattern.instructions.md create mode 100644 .github/instructions/onebranch-signing-configuration.instructions.md rename .pipelines/templates/{windows-package-build.yml => packaging/windows/package.yml} (56%) create mode 100644 .pipelines/templates/packaging/windows/sign.yml delete mode 100644 .pipelines/templates/release-checkout-pwsh-repo.yml delete mode 100644 .pipelines/templates/release-download-packages.yml delete mode 100644 .pipelines/templates/release-install-pwsh.yml create mode 100644 .pipelines/templates/set-reporoot.yml diff --git a/.github/chatmodes/cherry-pick-commits.chatmode.md b/.github/chatmodes/cherry-pick-commits.chatmode.md new file mode 100644 index 00000000000..826ab11d56c --- /dev/null +++ b/.github/chatmodes/cherry-pick-commits.chatmode.md @@ -0,0 +1,78 @@ +# Cherry-Pick Commits Between Branches + +Cherry-pick recent commits from a source branch to a target branch without switching branches. + +## Instructions for Copilot + +1. **Confirm branches with the user** + - Ask the user to confirm the source and target branches + - If different branches are needed, update the configuration + +2. **Identify unique commits** + - Run: `git log .. --oneline --reverse` + - **IMPORTANT**: The commit count may be misleading if branches diverged from different base commits + - Compare the LAST few commits from each branch to identify actual missing commits: + - `git log --oneline -10` + - `git log --oneline -10` + - Look for commits with the same message but different SHAs (rebased commits) + - Show the user ONLY the truly missing commits (usually just the most recent ones) + +3. **Confirm with user before proceeding** + - If the commit count seems unusually high (e.g., 400+), STOP and verify semantically + - Ask: "I found X commits to cherry-pick. Shall I proceed?" + - If there are many commits, warn that this may take time + +4. **Execute the cherry-pick** + - Ensure the target branch is checked out first + - Run: `git cherry-pick ` for single commits + - Or: `git cherry-pick ` for multiple commits + - Apply commits in chronological order (oldest first) + +5. **Handle any issues** + - If conflicts occur, pause and ask user for guidance + - If empty commits occur, automatically skip with `git cherry-pick --skip` + +6. **Verify and report results** + - Run: `git log - --oneline` + - Show the user the newly applied commits + - Confirm the branch is now ahead by X commits + +## Key Git Commands + +```bash +# Find unique commits (may show full divergence if branches were rebased) +git log .. --oneline --reverse + +# Compare recent commits on each branch (more reliable for rebased branches) +git log --oneline -10 +git log --oneline -10 + +# Cherry-pick specific commits (when target is checked out) +git cherry-pick +git cherry-pick + +# Skip empty commits +git cherry-pick --skip + +# Verify result +git log - --oneline +``` + +## Common Scenarios + +- **Empty commits**: Automatically skip with `git cherry-pick --skip` +- **Conflicts**: Stop, show files with conflicts, ask user to resolve +- **Many commits**: Warn user and confirm before proceeding +- **Already applied**: These will result in empty commits that should be skipped +- **Diverged branches**: If branches diverged (rebased), `git log` may show the entire history difference + - The actual missing commits are usually only the most recent ones + - Compare commit messages from recent history on both branches + - Cherry-pick only commits that are semantically missing + +## Workflow Style + +Use an interactive, step-by-step approach: +- Show output from each command +- Ask for confirmation before major actions +- Provide clear status updates +- Handle errors gracefully with user guidance diff --git a/.github/instructions/build-configuration-guide.md b/.github/instructions/build-configuration-guide.md index c31f8139c62..408a004e0c7 100644 --- a/.github/instructions/build-configuration-guide.md +++ b/.github/instructions/build-configuration-guide.md @@ -1,3 +1,12 @@ +--- +applyTo: + - "build.psm1" + - "tools/ci.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" + - ".pipelines/**/*.yml" +--- + # Build Configuration Guide ## Choosing the Right Configuration @@ -113,7 +122,7 @@ The `Switch-PSNugetConfig` function in `build.psm1` manages NuGet package source - **Public**: Uses public feeds (nuget.org and public Azure DevOps feeds) - Required for: CI/CD environments, public builds, packaging - Does not require authentication - + - **Private**: Uses internal PowerShell team feeds - Required for: Internal development with preview packages - Requires authentication credentials @@ -138,4 +147,4 @@ Switch-PSNugetConfig -Source NuGetOnly - **Always use `-Source Public`** before building in CI/CD workflows - Use before any build that will create packages for distribution -- Use in forks or environments without access to Microsoft internal feeds +- Use in forks or environments without access to Microsoft internal feeds \ No newline at end of file diff --git a/.github/instructions/code-review-branch-strategy.instructions.md b/.github/instructions/code-review-branch-strategy.instructions.md new file mode 100644 index 00000000000..191a677b912 --- /dev/null +++ b/.github/instructions/code-review-branch-strategy.instructions.md @@ -0,0 +1,230 @@ +--- +applyTo: "**/*" +--- + +# Code Review Branch Strategy Guide + +This guide helps GitHub Copilot provide appropriate feedback when reviewing code changes, particularly distinguishing between issues that should be fixed in the current branch versus the default branch. + +## Purpose + +When reviewing pull requests, especially those targeting release branches, it's important to identify whether an issue should be fixed in: +- **The current PR/branch** - Release-specific fixes or backports +- **The default branch first** - General bugs that exist in the main codebase + +## Branch Types and Fix Strategy + +### Release Branches (e.g., `release/v7.5`, `release/v7.4`) + +**Purpose:** Contain release-specific changes and critical backports + +**Should contain:** +- Release-specific configuration changes +- Critical bug fixes that are backported from the default branch +- Release packaging/versioning adjustments + +**Should NOT contain:** +- New general bug fixes that haven't been fixed in the default branch +- Refactoring or improvements that apply to the main codebase +- Workarounds for issues that exist in the default branch + +### Default/Main Branch (e.g., `master`, `main`) + +**Purpose:** Primary development branch for all ongoing work + +**Should contain:** +- All general bug fixes +- New features and improvements +- Refactoring and code quality improvements +- Fixes that will later be backported to release branches + +## Identifying Issues That Belong in the Default Branch + +When reviewing a PR targeting a release branch, look for these indicators that suggest the fix should be in the default branch first: + +### 1. The Root Cause Exists in Default Branch + +If the underlying issue exists in the default branch's code, it should be fixed there first. + +**Example:** +```yaml +# PR changes this in release/v7.5: +- $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json ++ $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json +``` + +**Analysis:** If `$repoRoot` is undefined because the template doesn't include its dependencies in BOTH the release branch AND the default branch, the fix should address the root cause in the default branch first. + +### 2. The Fix is a Workaround Rather Than a Proper Solution + +If the change introduces a workaround (hardcoded paths, special cases) rather than fixing the underlying design issue, it likely belongs in the default branch as a proper fix. + +**Example:** +- Using hardcoded paths instead of fixing variable initialization +- Adding special cases instead of fixing the logic +- Duplicating code instead of fixing shared dependencies + +### 3. The Issue Affects General Functionality + +If the issue affects general functionality not specific to a release, it should be fixed in the default branch. + +**Example:** +- Template dependencies that affect all pipelines +- Shared utility functions +- Common configuration issues + +## Providing Code Review Feedback + +### For Issues in the Current Branch + +When an issue is specific to the current branch or is a legitimate fix for the branch being targeted, **use the default code review feedback format** without any special branch-strategy commentary. + +### For Issues That Belong in the Default Branch + +1. **Provide the code review feedback** +2. **Explain why it should be fixed in the default branch** +3. **Provide an issue template** in markdown format + +**Example:** + +```markdown +The `channelSelection.yml` template relies on `$repoRoot` being set by `SetVersionVariables.yml`, but doesn't declare this dependency. This issue exists in both the release branch and the default branch. + +**This should be fixed in the default branch first**, then backported if needed. The proper fix is to ensure template dependencies are correctly declared, rather than using hardcoded paths as a workaround. + +--- + +**Suggested Issue for Default Branch:** + +### Issue Title +`channelSelection.yml` template missing dependency on `SetVersionVariables.yml` + +### Description +The `channelSelection.yml` template uses the `$repoRoot` variable but doesn't ensure it's set beforehand by including `SetVersionVariables.yml`. + +**Current State:** +- `channelSelection.yml` expects `$repoRoot` to be available +- Not all pipelines that use `channelSelection.yml` include `SetVersionVariables.yml` first +- This creates an implicit dependency that's not enforced + +**Expected State:** +Either: +1. `channelSelection.yml` should include `SetVersionVariables.yml` as a dependency, OR +2. `channelSelection.yml` should be refactored to not depend on `$repoRoot`, OR +3. Pipelines using `channelSelection.yml` should explicitly include `SetVersionVariables.yml` first + +**Files Affected:** +- `.pipelines/templates/channelSelection.yml` +- `.pipelines/templates/package-create-msix.yml` +- `.pipelines/templates/release-SetTagAndChangelog.yml` + +**Priority:** Medium +**Labels:** `Issue-Bug`, `Area-Build`, `Area-Pipeline` +``` + +## Issue Template Format + +When creating an issue template for the default branch, use this structure: + +```markdown +### Issue Title +[Clear, concise description of the problem] + +### Description +[Detailed explanation of the issue] + +**Current State:** +- [What's happening now] +- [Why it's problematic] + +**Expected State:** +- [What should happen] +- [Proposed solution(s)] + +**Files Affected:** +- [List of files] + +**Priority:** [Low/Medium/High/Critical] +**Labels:** [Suggested labels like `Issue-Bug`, `Area-*`] + +**Additional Context:** +[Any additional information, links to related issues, etc.] +``` + +## Common Scenarios + +### Scenario 1: Template Dependency Issues + +**Indicators:** +- Missing template includes +- Undefined variables from other templates +- Assumptions about pipeline execution order + +**Action:** Suggest fixing template dependencies in the default branch. + +### Scenario 2: Hardcoded Values + +**Indicators:** +- Hardcoded paths replacing variables +- Environment-specific values in shared code +- Magic strings or numbers + +**Action:** Suggest proper variable/parameter usage in the default branch. + +### Scenario 3: Logic Errors + +**Indicators:** +- Incorrect conditional logic +- Missing error handling +- Race conditions + +**Action:** Suggest fixing the logic in the default branch unless it's release-specific. + +### Scenario 4: Legitimate Release Branch Fixes + +**Indicators:** +- Version-specific configuration +- Release packaging changes +- Backport of already-fixed default branch issue + +**Action:** Provide normal code review feedback for the current PR. + +## Best Practices + +1. **Always check if the issue exists in the default branch** before suggesting a release-branch-only fix +2. **Prefer fixing root causes over workarounds** +3. **Provide clear rationale** for why a fix belongs in the default branch +4. **Include actionable issue templates** so users can easily create issues +5. **Be helpful, not blocking** - provide the feedback even if you can't enforce where it's fixed + +## Examples of Good vs. Bad Approaches + +### ❌ Bad: Workaround in Release Branch Only + +```yaml +# In release/v7.5 only +- pwsh: | + $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw +``` + +**Why bad:** Hardcodes path to work around missing `$repoRoot`, doesn't fix the default branch. + +### ✅ Good: Fix in Default Branch, Then Backport + +```yaml +# In default branch first +- template: SetVersionVariables.yml@self # Ensures $repoRoot is set +- template: channelSelection.yml@self # Now can use $repoRoot +``` + +**Why good:** Fixes the root cause by ensuring dependencies are declared, then backport to release if needed. + +## When in Doubt + +If you're unsure whether an issue should be fixed in the current branch or the default branch, ask yourself: + +1. Does this issue exist in the default branch? +2. Is this a workaround or a proper fix? +3. Will other branches/releases benefit from this fix? + +If the answer to any of these is "yes," suggest fixing it in the default branch first. diff --git a/.github/instructions/onebranch-restore-phase-pattern.instructions.md b/.github/instructions/onebranch-restore-phase-pattern.instructions.md new file mode 100644 index 00000000000..0945bb47c0b --- /dev/null +++ b/.github/instructions/onebranch-restore-phase-pattern.instructions.md @@ -0,0 +1,83 @@ +--- +applyTo: ".pipelines/**/*.{yml,yaml}" +--- + +# OneBranch Restore Phase Pattern + +## Overview +When steps need to run in the OneBranch restore phase (before the main build phase), the `ob_restore_phase` environment variable must be set in the `env:` block of **each individual step**. + +## Pattern + +### ✅ Correct (Working Pattern) +```yaml +parameters: +- name: "ob_restore_phase" + type: boolean + default: true # or false if you don't want restore phase + +steps: +- powershell: | + # script content + displayName: 'Step Name' + env: + ob_restore_phase: ${{ parameters.ob_restore_phase }} +``` + +The key is to: +1. Define `ob_restore_phase` as a **boolean** parameter +2. Set `ob_restore_phase: ${{ parameters.ob_restore_phase }}` directly in each step's `env:` block +3. Pass `true` to run in restore phase, `false` to run in normal build phase + +### ❌ Incorrect (Does Not Work) +```yaml +steps: +- powershell: | + # script content + displayName: 'Step Name' + ${{ if eq(parameters.useRestorePhase, 'yes') }}: + env: + ob_restore_phase: true +``` + +Using conditionals at the same indentation level as `env:` causes only the first step to execute in restore phase. + +## Parameters + +Templates using this pattern should accept an `ob_restore_phase` boolean parameter: + +```yaml +parameters: +- name: "ob_restore_phase" + type: boolean + default: true # Set to true to run in restore phase by default +``` + +## Reference Examples + +Working examples of this pattern can be found in: +- `.pipelines/templates/insert-nuget-config-azfeed.yml` - Demonstrates the correct pattern +- `.pipelines/templates/SetVersionVariables.yml` - Updated to use this pattern + +## Why This Matters + +The restore phase in OneBranch pipelines runs before signing and other build operations. Steps that need to: +- Set environment variables for the entire build +- Configure authentication +- Prepare the repository structure + +Must run in the restore phase to be available when subsequent stages execute. + +## Common Use Cases + +- Setting `REPOROOT` variable +- Configuring NuGet feeds with authentication +- Setting version variables +- Repository preparation and validation + +## Troubleshooting + +If only the first step in your template is running in restore phase: +1. Check that `env:` block exists for **each step** +2. Verify the conditional `${{ if ... }}:` is **inside** the `env:` block +3. Confirm indentation is correct (conditional is indented under `env:`) diff --git a/.github/instructions/onebranch-signing-configuration.instructions.md b/.github/instructions/onebranch-signing-configuration.instructions.md new file mode 100644 index 00000000000..747fcaffdd6 --- /dev/null +++ b/.github/instructions/onebranch-signing-configuration.instructions.md @@ -0,0 +1,195 @@ +--- +applyTo: + - ".pipelines/**/*.yml" + - ".pipelines/**/*.yaml" +--- + +# OneBranch Signing Configuration + +This guide explains how to configure OneBranch signing variables in Azure Pipeline jobs, particularly when signing is not required. + +## Purpose + +OneBranch pipelines include signing infrastructure by default. For build-only jobs where signing happens in a separate stage, you should disable signing setup to improve performance and avoid unnecessary overhead. + +## Disable Signing for Build-Only Jobs + +When a job does not perform signing (e.g., it only builds artifacts that will be signed in a later stage), disable both signing setup and code sign validation: + +```yaml +variables: + - name: ob_signing_setup_enabled + value: false # Disable signing setup - this is a build-only stage + - name: ob_sdl_codeSignValidation_enabled + value: false # Skip signing validation in build-only stage +``` + +### Why Disable These Variables? + +**`ob_signing_setup_enabled: false`** +- Prevents OneBranch from setting up the signing infrastructure +- Reduces job startup time +- Avoids unnecessary credential validation +- Only disable when the job will NOT sign any artifacts + +**`ob_sdl_codeSignValidation_enabled: false`** +- Skips validation that checks if files are properly signed +- Appropriate for build stages where artifacts are unsigned +- Must be enabled in signing/release stages to validate signatures + +## Common Patterns + +### Build-Only Job (No Signing) + +```yaml +jobs: +- job: build_artifacts + variables: + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_codeSignValidation_enabled + value: false + steps: + - checkout: self + - pwsh: | + # Build unsigned artifacts + Start-PSBuild +``` + +### Signing Job + +```yaml +jobs: +- job: sign_artifacts + variables: + - name: ob_signing_setup_enabled + value: true + - name: ob_sdl_codeSignValidation_enabled + value: true + steps: + - checkout: self + env: + ob_restore_phase: true # Steps before first signing operation + - pwsh: | + # Prepare artifacts for signing + env: + ob_restore_phase: true # Steps before first signing operation + - task: onebranch.pipeline.signing@1 + displayName: 'Sign artifacts' + # Signing step runs in build phase (no ob_restore_phase) + - pwsh: | + # Post-signing validation + # Post-signing steps run in build phase (no ob_restore_phase) +``` + +## Restore Phase Usage with Signing + +**The restore phase (`ob_restore_phase: true`) should only be used in jobs that perform signing operations.** It separates preparation steps from the actual signing and build steps. + +### When to Use Restore Phase + +Use `ob_restore_phase: true` **only** in jobs where `ob_signing_setup_enabled: true`: + +```yaml +jobs: +- job: sign_artifacts + variables: + - name: ob_signing_setup_enabled + value: true # Signing enabled + steps: + # Steps BEFORE first signing operation: use restore phase + - checkout: self + env: + ob_restore_phase: true + - template: prepare-for-signing.yml + parameters: + ob_restore_phase: true + + # SIGNING STEP: runs in build phase (no ob_restore_phase) + - task: onebranch.pipeline.signing@1 + displayName: 'Sign artifacts' + + # Steps AFTER signing: run in build phase (no ob_restore_phase) + - pwsh: | + # Validation or packaging +``` + +### When NOT to Use Restore Phase + +**Do not use restore phase in build-only jobs** where `ob_signing_setup_enabled: false`: + +```yaml +jobs: +- job: build_artifacts + variables: + - name: ob_signing_setup_enabled + value: false # No signing + - name: ob_sdl_codeSignValidation_enabled + value: false + steps: + - checkout: self + # NO ob_restore_phase - not needed without signing + - pwsh: | + Start-PSBuild +``` + +**Why?** The restore phase is part of OneBranch's signing infrastructure. Using it without signing enabled adds unnecessary overhead without benefit. + +## Related Variables + +Other OneBranch signing-related variables: + +- `ob_sdl_binskim_enabled`: Controls BinSkim security analysis (can be false in build-only, true in signing stages) + +## Best Practices + +1. **Separate build and signing stages**: Build artifacts in one job, sign in another +2. **Disable signing in build stages**: Improves performance and clarifies intent +3. **Only use restore phase with signing**: The restore phase should only be used in jobs where signing is enabled (`ob_signing_setup_enabled: true`) +4. **Restore phase before first signing step**: All steps before the first signing operation should use `ob_restore_phase: true` +5. **Always validate after signing**: Enable validation in signing stages to catch issues +6. **Document the reason**: Add comments explaining why signing is disabled or why restore phase is used + +## Example: Split Build and Sign Pipeline + +```yaml +stages: + - stage: Build + jobs: + - job: build_windows + variables: + - name: ob_signing_setup_enabled + value: false # Build-only, no signing + - name: ob_sdl_codeSignValidation_enabled + value: false # Artifacts are unsigned + steps: + - template: templates/build-unsigned.yml + + - stage: Sign + dependsOn: Build + jobs: + - job: sign_windows + variables: + - name: ob_signing_setup_enabled + value: true # Enable signing infrastructure + - name: ob_sdl_codeSignValidation_enabled + value: true # Validate signatures + steps: + - template: templates/sign-artifacts.yml +``` + +## Troubleshooting + +**Job fails with signing-related errors but signing is disabled:** +- Verify `ob_signing_setup_enabled: false` is set in variables +- Check that no template is overriding the setting +- Ensure `ob_sdl_codeSignValidation_enabled: false` is also set + +**Signed artifacts fail validation:** +- Confirm `ob_sdl_codeSignValidation_enabled: true` in signing job +- Verify signing actually occurred +- Check certificate configuration + +## Reference + +- PowerShell signing templates: `.pipelines/templates/packaging/windows/sign.yml` diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 8e175c5a6bb..997b7c458be 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -99,7 +99,6 @@ extends: - template: .pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - UseJson: no - pwsh: | Write-Verbose -Verbose 'PowerShell Version: $(version)' diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index e70b65a9a64..f36eeadf298 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -178,7 +178,6 @@ extends: parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes - UseJson: no - stage: macos displayName: macOS - build and sign diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 9c2dee1c571..8e06be1cc64 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -127,11 +127,13 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - stage: prep + displayName: 'Prep BuildInfo+Az' jobs: - template: /.pipelines/templates/checkAzureContainer.yml@self - stage: mac_package - dependsOn: [prep] + displayName: 'macOS Pkg+Sign' + dependsOn: [] jobs: - template: /.pipelines/templates/mac-package-build.yml@self parameters: @@ -141,35 +143,65 @@ extends: parameters: buildArchitecture: arm64 - - stage: windows_package - dependsOn: [prep] + - stage: windows_package_build + displayName: 'Win Pkg (unsigned)' + dependsOn: [] jobs: - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: x64 - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: arm64 - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: x86 - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: fxdependent - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self parameters: runtime: fxdependentWinDesktop - - template: /.pipelines/templates/windows-package-build.yml@self + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: minsize + + - stage: windows_package_sign + displayName: 'Win Pkg Sign' + dependsOn: [windows_package_build] + jobs: + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: arm64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x86 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependent + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependentWinDesktop + + - template: /.pipelines/templates/packaging/windows/sign.yml@self parameters: runtime: minsize - stage: linux_package - dependsOn: [prep] + displayName: 'Linux Pkg+Sign' + dependsOn: [] jobs: - template: /.pipelines/templates/linux-package-build.yml@self parameters: @@ -251,17 +283,19 @@ extends: jobName: minSize - stage: nupkg - dependsOn: [prep] + displayName: 'NuGet Pkg+Sign' + dependsOn: [] jobs: - template: /.pipelines/templates/nupkg.yml@self - stage: msixbundle - displayName: 'Create MSIX Bundle' - dependsOn: [windows_package] + displayName: 'MSIX Bundle+Sign' + dependsOn: [windows_package_build] # Only depends on unsigned packages jobs: - template: /.pipelines/templates/package-create-msix.yml@self - stage: upload - dependsOn: [mac_package, windows_package, linux_package, nupkg, msixbundle] + displayName: 'Upload' + dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON jobs: - template: /.pipelines/templates/uploadToAzure.yml@self diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 2c6ec989ee5..ba70ddb59df 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -158,7 +158,6 @@ extends: parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes - UseJson: no - pwsh: | $version = '$(Version)' diff --git a/.pipelines/templates/SetVersionVariables.yml b/.pipelines/templates/SetVersionVariables.yml index 9f692373f6c..30ed1704022 100644 --- a/.pipelines/templates/SetVersionVariables.yml +++ b/.pipelines/templates/SetVersionVariables.yml @@ -1,49 +1,18 @@ parameters: - ReleaseTagVar: v6.2.0 - ReleaseTagVarName: ReleaseTagVar - CreateJson: 'no' - UseJson: 'yes' +- name: ReleaseTagVar + default: v6.2.0 +- name: ReleaseTagVarName + default: ReleaseTagVar +- name: CreateJson + default: 'no' +- name: ob_restore_phase + type: boolean + default: true steps: -- ${{ if eq(parameters['UseJson'],'yes') }}: - - task: DownloadBuildArtifacts@0 - inputs: - artifactName: 'drop_prep_SetVars' - itemPattern: '*.json' - downloadPath: '$(System.ArtifactsDirectory)' - displayName: Download Build Info Json - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - -- powershell: | - $path = "./build.psm1" - if($env:REPOROOT){ - Write-Verbose "reporoot already set to ${env:REPOROOT}" -Verbose - exit 0 - } - if(Test-Path -Path $path) - { - Write-Verbose "reporoot detected at: ." -Verbose - $repoRoot = '.' - } - else{ - $path = "./PowerShell/build.psm1" - if(Test-Path -Path $path) - { - Write-Verbose "reporoot detect at: ./PowerShell" -Verbose - $repoRoot = './PowerShell' - } - } - if($repoRoot) { - $vstsCommandString = "vso[task.setvariable variable=repoRoot]$repoRoot" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - } else { - Write-Verbose -Verbose "repo not found" - } - displayName: 'Set repo Root' - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue +- template: set-reporoot.yml@self + parameters: + ob_restore_phase: ${{ parameters.ob_restore_phase }} - powershell: | $createJson = ("${{ parameters.CreateJson }}" -ne "no") @@ -69,11 +38,11 @@ steps: Write-Host "##$vstsCommandString" displayName: 'Set ${{ parameters.ReleaseTagVarName }} and other version Variables' env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + ob_restore_phase: ${{ parameters.ob_restore_phase }} - powershell: | Get-ChildItem -Path Env: | Out-String -Width 150 displayName: Capture environment condition: succeededOrFailed() env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/checkAzureContainer.yml b/.pipelines/templates/checkAzureContainer.yml index a6a86214d07..3e383d2c572 100644 --- a/.pipelines/templates/checkAzureContainer.yml +++ b/.pipelines/templates/checkAzureContainer.yml @@ -3,6 +3,8 @@ jobs: variables: - group: Azure Blob variable group - group: AzureBlobServiceConnection + - name: ob_artifactBaseName + value: BuildInfoJson - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/BuildJson' - name: ob_sdl_sbom_enabled @@ -29,7 +31,6 @@ jobs: parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes - UseJson: no - template: /.pipelines/templates/cloneToOfficialPath.yml@self diff --git a/.pipelines/templates/cloneToOfficialPath.yml b/.pipelines/templates/cloneToOfficialPath.yml index 844d8b8028d..b060c713683 100644 --- a/.pipelines/templates/cloneToOfficialPath.yml +++ b/.pipelines/templates/cloneToOfficialPath.yml @@ -1,5 +1,9 @@ parameters: - nativePathRoot: '' +- name: nativePathRoot + default: '' +- name: ob_restore_phase + type: boolean + default: true steps: - powershell: | @@ -12,8 +16,16 @@ steps: else { Write-Verbose -Verbose -Message "No cleanup required." } - git clone --quiet $env:REPOROOT $nativePath + # REPOROOT must be set by the pipeline - this is where the repository was checked out + $sourceDir = $env:REPOROOT + if (-not $sourceDir) { throw "REPOROOT environment variable is not set. This step depends on REPOROOT being configured in the pipeline." } + + $buildModulePath = Join-Path $sourceDir "build.psm1" + if (-not (Test-Path $buildModulePath)) { throw "build.psm1 not found at: $buildModulePath. REPOROOT must point to the PowerShell repository root." } + + Write-Verbose -Verbose -Message "Cloning from: $sourceDir to $nativePath" + git clone --quiet $sourceDir $nativePath displayName: Clone PowerShell Repo to /PowerShell errorActionPreference: silentlycontinue env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index 817d5ab777f..5809af8e28c 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -50,8 +50,7 @@ jobs: - template: ../SetVersionVariables.yml parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: ../insert-nuget-config-azfeed.yml parameters: diff --git a/.pipelines/templates/install-dotnet.yml b/.pipelines/templates/install-dotnet.yml index c2a2cfebeca..464e13d1047 100644 --- a/.pipelines/templates/install-dotnet.yml +++ b/.pipelines/templates/install-dotnet.yml @@ -1,3 +1,8 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + steps: - pwsh: | if (-not (Test-Path '$(RepoRoot)')) { @@ -15,5 +20,5 @@ steps: displayName: 'Install dotnet SDK' workingDirectory: $(RepoRoot) env: - ob_restore_phase: true + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 68fa46690c2..b1c170eaed5 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -54,8 +54,7 @@ jobs: - template: SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: shouldSign.yml diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 669ab3c8437..7d0930955b3 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -52,8 +52,7 @@ jobs: - template: SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: shouldSign.yml diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index 4756c99a9d3..3a2aa4f3172 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -41,8 +41,7 @@ jobs: - template: SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: shouldSign.yml diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index e464b612234..db801cf8748 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -26,7 +26,7 @@ jobs: - task: DownloadPipelineArtifact@2 inputs: buildType: 'current' - artifact: drop_windows_package_package_win_arm64 + artifact: drop_windows_package_arm64 itemPattern: | **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' @@ -35,7 +35,7 @@ jobs: - task: DownloadPipelineArtifact@2 inputs: buildType: 'current' - artifact: drop_windows_package_package_win_x64 + artifact: drop_windows_package_x64 itemPattern: | **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' @@ -44,7 +44,7 @@ jobs: - task: DownloadPipelineArtifact@2 inputs: buildType: 'current' - artifact: drop_windows_package_package_win_x86 + artifact: drop_windows_package_x86 itemPattern: | **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' diff --git a/.pipelines/templates/windows-package-build.yml b/.pipelines/templates/packaging/windows/package.yml similarity index 56% rename from .pipelines/templates/windows-package-build.yml rename to .pipelines/templates/packaging/windows/package.yml index bc23bfc659e..9a8be4b18fe 100644 --- a/.pipelines/templates/windows-package-build.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -2,8 +2,8 @@ parameters: runtime: x64 jobs: -- job: package_win_${{ parameters.runtime }} - displayName: Package Windows ${{ parameters.runtime }} +- job: build_win_${{ parameters.runtime }} + displayName: Build Windows Packages ${{ parameters.runtime }} condition: succeeded() pool: type: windows @@ -11,6 +11,12 @@ jobs: variables: - name: runCodesignValidationInjection value: false + - name: ob_sdl_codeSignValidation_enabled + value: false # Skip signing validation in build-only stage + - name: ob_signing_setup_enabled + value: false # Disable signing setup - this is a build-only stage, signing happens in separate stage + - name: ob_artifactBaseName + value: drop_windows_package_${{ parameters.runtime }} - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel @@ -22,7 +28,7 @@ jobs: - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)\ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled - value: true + value: false # Disable for build-only, enable in signing stage - name: ob_sdl_tsa_configFile value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - name: ob_sdl_credscan_suppressionsFile @@ -34,40 +40,35 @@ jobs: steps: - checkout: self clean: true - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - pwsh: | Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose displayName: Capture environment - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - - template: SetVersionVariables.yml@self + - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no + ob_restore_phase: false - - template: shouldSign.yml + - template: /.pipelines/templates/shouldSign.yml@self + parameters: + ob_restore_phase: false - - template: cloneToOfficialPath.yml + - template: /.pipelines/templates/cloneToOfficialPath.yml@self parameters: nativePathRoot: '$(Agent.TempDirectory)' + ob_restore_phase: false - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_${{ parameters.runtime }}_release displayName: Download signed artifacts condition: ${{ ne(parameters.runtime, 'minSize') }} - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_x64_${{ parameters.runtime }} displayName: Download minsize signed artifacts condition: ${{ eq(parameters.runtime, 'minSize') }} - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - pwsh: | Write-Verbose -Verbose "signed artifacts" @@ -75,18 +76,10 @@ jobs: displayName: 'Capture Downloaded Artifacts' # Diagnostics is not critical it passes every time it runs continueOnError: true - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - template: /.pipelines/templates/install-dotnet.yml@self - - - pwsh: | - $msixUrl = '$(makeappUrl)' - Invoke-RestMethod -Uri $msixUrl -OutFile '$(Pipeline.Workspace)\makeappx.zip' - Expand-Archive '$(Pipeline.Workspace)\makeappx.zip' -destination '\' -Force - displayName: Install packaging tools - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + parameters: + ob_restore_phase: false - pwsh: | $runtime = '$(Runtime)' @@ -168,94 +161,19 @@ jobs: Start-PSPackage -Type $packageTypes -SkipReleaseChecks -WindowsRuntime $WindowsRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS - displayName: 'Package ${{ parameters.buildArchitecture}}' + displayName: 'Build Packages (Unsigned)' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue - - - task: onebranch.pipeline.signing@1 - displayName: Sign MSI packages - inputs: - command: 'sign' - signing_profile: external_distribution - files_to_sign: '**\*.msi' - search_root: '$(Pipeline.Workspace)' - - - pwsh: | - $runtime = '$(Runtime)' - Write-Verbose -Verbose "runtime = '$(Runtime)'" - - $repoRoot = "$env:REPOROOT" - Import-Module "$repoRoot\build.psm1" - Import-Module "$repoRoot\tools\packaging" - - $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') - - if ($runtime -in $noExeRuntimes) { - Write-Verbose -Verbose "No EXE generated for $runtime" - return - } - - $version = '$(Version)' - - $msiLocation = Get-ChildItem -Path $(Pipeline.Workspace) -Recurse -Filter "powershell-*$runtime.msi" | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msiLocation: $msiLocation" - - Set-Location $repoRoot - - $exePath = New-ExePackage -ProductVersion $version -ProductTargetArchitecture $runtime -MsiLocationPath $msiLocation - Write-Verbose -Verbose "setting vso[task.setvariable variable=exePath]$exePath" - Write-Host "##vso[task.setvariable variable=exePath]$exePath" - Write-Verbose -Verbose "exePath: $exePath" - - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe - Expand-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime - displayName: 'Make exe and expand package' - - - task: onebranch.pipeline.signing@1 - displayName: Sign exe engine - inputs: - command: 'sign' - signing_profile: $(msft_3rd_party_cert_id) - files_to_sign: '$(System.ArtifactsDirectory)\unsignedEngine\*.exe' - search_root: '$(Pipeline.Workspace)' - - - pwsh: | - $runtime = '$(Runtime)' - Write-Verbose -Verbose "runtime = '$(Runtime)'" - $repoRoot = "$env:REPOROOT" - Import-Module "$repoRoot\build.psm1" - Import-Module "$repoRoot\tools\packaging" - - $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') - - if ($runtime -in $noExeRuntimes) { - Write-Verbose -Verbose "No EXE generated for $runtime" - return - } - - $exePath = '$(exePath)' - $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe - $enginePath | Get-AuthenticodeSignature | out-string | Write-Verbose -verbose - Compress-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime - displayName: Compress signed exe package - - - task: onebranch.pipeline.signing@1 - displayName: Sign exe packages - inputs: - command: 'sign' - signing_profile: external_distribution - files_to_sign: '**\*.exe' - search_root: '$(Pipeline.Workspace)' + # Copy unsigned packages to output directory - pwsh: | $runtime = '$(Runtime)' Write-Verbose -Verbose "runtime = '$(Runtime)'" $packageTypes = switch ($runtime) { - 'x64' { @('msi', 'zip', 'msix', 'exe') } - 'x86' { @('msi', 'zip', 'msix', 'exe') } - 'arm64' { @('msi', 'zip', 'msix', 'exe') } + 'x64' { @('msi', 'zip', 'msix') } + 'x86' { @('msi', 'zip', 'msix') } + 'arm64' { @('msi', 'zip', 'msix') } 'fxdependent' { 'fxdependent' } 'fxdependentWinDesktop' { 'fxdependent-win-desktop' } 'minsize' { 'min-size' } @@ -268,34 +186,25 @@ jobs: if ($packageTypes -contains 'msi') { $msiPkgNameFilter = "powershell-*.msi" $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msiPkgPath: $msiPkgPath" - Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose - } - - if ($packageTypes -contains 'exe') { - $msiPkgNameFilter = "powershell-*.exe" - $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msiPkgPath: $msiPkgPath" + Write-Verbose -Verbose "unsigned msiPkgPath: $msiPkgPath" Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose } if ($packageTypes -contains 'zip' -or $packageTypes -contains 'fxdependent' -or $packageTypes -contains 'min-size' -or $packageTypes -contains 'fxdependent-win-desktop') { $zipPkgNameFilter = "powershell-*.zip" $zipPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $zipPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "zipPkgPath: $zipPkgPath" + Write-Verbose -Verbose "unsigned zipPkgPath: $zipPkgPath" Copy-Item -Path $zipPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose } if ($packageTypes -contains 'msix') { $msixPkgNameFilter = "powershell-*.msix" $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "msixPkgPath: $msixPkgPath" + Write-Verbose -Verbose "unsigned msixPkgPath: $msixPkgPath" Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose } - displayName: Copy to output directory + displayName: Copy unsigned packages to output directory - pwsh: | Get-ChildItem -Path $(ob_outputDirectory) -Recurse - displayName: 'List artifacts' - env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + displayName: 'List unsigned artifacts' diff --git a/.pipelines/templates/packaging/windows/sign.yml b/.pipelines/templates/packaging/windows/sign.yml new file mode 100644 index 00000000000..4a095ba7694 --- /dev/null +++ b/.pipelines/templates/packaging/windows/sign.yml @@ -0,0 +1,216 @@ +parameters: + runtime: x64 + +jobs: +- job: sign_win_${{ parameters.runtime }} + displayName: Sign Windows Packages ${{ parameters.runtime }} + condition: succeeded() + pool: + type: windows + + variables: + - name: runCodesignValidationInjection + value: false + - name: ob_artifactBaseName + value: drop_windows_package_package_win_${{ parameters.runtime }} + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)\ONEBRANCH_ARTIFACT' + - name: ob_sdl_binskim_enabled + value: true + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: Runtime + value: ${{ parameters.runtime }} + - group: msixTools + + steps: + - checkout: self + clean: true + env: + ob_restore_phase: true + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - template: /.pipelines/templates/shouldSign.yml@self + + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + parameters: + nativePathRoot: '$(Agent.TempDirectory)' + + # Download unsigned packages from the build stage + - download: current + artifact: drop_windows_package_${{ parameters.runtime }} + displayName: Download unsigned packages + env: + ob_restore_phase: true + + - pwsh: | + Write-Verbose -Verbose "Downloaded unsigned artifacts:" + Get-ChildItem "$(Pipeline.Workspace)\drop_windows_package_${{ parameters.runtime }}" -Recurse + displayName: 'Capture Downloaded Unsigned Artifacts' + continueOnError: true + env: + ob_restore_phase: true + + - template: /.pipelines/templates/install-dotnet.yml@self + + # Import build.psm1 and bootstrap packaging dependencies (WiX Toolset) + - pwsh: | + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + Write-Verbose -Verbose "Modules imported successfully" + + # Install WiX Toolset for EXE package creation + $isArm64 = '$(Runtime)' -eq 'arm64' + $env:RUNTIME = '$(Runtime)' + Start-PSBootstrap -Scenario Package + displayName: 'Import modules and install WiX Toolset' + env: + ob_restore_phase: true + + # Sign MSI packages + - task: onebranch.pipeline.signing@1 + displayName: Sign MSI packages + inputs: + command: 'sign' + signing_profile: external_distribution + files_to_sign: '**\*.msi' + search_root: '$(Pipeline.Workspace)' + + # Create EXE package from signed MSI (for x64, x86, arm64 only) + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + + $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') + + if ($runtime -in $noExeRuntimes) { + Write-Verbose -Verbose "No EXE generated for $runtime" + return + } + + $version = '$(Version)' + + $msiLocation = Get-ChildItem -Path $(Pipeline.Workspace) -Recurse -Filter "powershell-*$runtime.msi" | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "msiLocation: $msiLocation" + + Set-Location $repoRoot + + $exePath = New-ExePackage -ProductVersion $version -ProductTargetArchitecture $runtime -MsiLocationPath $msiLocation + Write-Verbose -Verbose "setting vso[task.setvariable variable=exePath]$exePath" + Write-Host "##vso[task.setvariable variable=exePath]$exePath" + Write-Verbose -Verbose "exePath: $exePath" + + $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe + Expand-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime + displayName: 'Make exe and expand package' + + # Sign EXE engine + - task: onebranch.pipeline.signing@1 + displayName: Sign exe engine + inputs: + command: 'sign' + signing_profile: $(msft_3rd_party_cert_id) + files_to_sign: '$(System.ArtifactsDirectory)\unsignedEngine\*.exe' + search_root: '$(Pipeline.Workspace)' + + # Compress signed EXE engine back into package + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + $repoRoot = "$env:REPOROOT" + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + + $noExeRuntimes = @('fxdependent', 'fxdependentWinDesktop', 'minsize') + + if ($runtime -in $noExeRuntimes) { + Write-Verbose -Verbose "No EXE generated for $runtime" + return + } + + $exePath = '$(exePath)' + $enginePath = Join-Path -Path '$(System.ArtifactsDirectory)\unsignedEngine' -ChildPath engine.exe + $enginePath | Get-AuthenticodeSignature | out-string | Write-Verbose -verbose + Compress-ExePackageEngine -ExePath $exePath -EnginePath $enginePath -ProductTargetArchitecture $runtime + displayName: Compress signed exe package + + # Sign final EXE packages + - task: onebranch.pipeline.signing@1 + displayName: Sign exe packages + inputs: + command: 'sign' + signing_profile: external_distribution + files_to_sign: '**\*.exe' + search_root: '$(Pipeline.Workspace)' + + # Copy all signed packages to output directory + - pwsh: | + $runtime = '$(Runtime)' + Write-Verbose -Verbose "runtime = '$(Runtime)'" + + $packageTypes = switch ($runtime) { + 'x64' { @('msi', 'zip', 'msix', 'exe') } + 'x86' { @('msi', 'zip', 'msix', 'exe') } + 'arm64' { @('msi', 'zip', 'msix', 'exe') } + 'fxdependent' { 'fxdependent' } + 'fxdependentWinDesktop' { 'fxdependent-win-desktop' } + 'minsize' { 'min-size' } + } + + if (-not (Test-Path $(ob_outputDirectory))) { + New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force + } + + if ($packageTypes -contains 'msi') { + $msiPkgNameFilter = "powershell-*.msi" + $msiPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msiPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed msiPkgPath: $msiPkgPath" + Copy-Item -Path $msiPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + + if ($packageTypes -contains 'exe') { + $exePkgNameFilter = "powershell-*.exe" + $exePkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $exePkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed exePkgPath: $exePkgPath" + Copy-Item -Path $exePkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + + if ($packageTypes -contains 'zip' -or $packageTypes -contains 'fxdependent' -or $packageTypes -contains 'min-size' -or $packageTypes -contains 'fxdependent-win-desktop') { + $zipPkgNameFilter = "powershell-*.zip" + $zipPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $zipPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed zipPkgPath: $zipPkgPath" + Copy-Item -Path $zipPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + + if ($packageTypes -contains 'msix') { + $msixPkgNameFilter = "powershell-*.msix" + $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName + Write-Verbose -Verbose "signed msixPkgPath: $msixPkgPath" + Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + } + displayName: Copy signed packages to output directory + + - pwsh: | + Get-ChildItem -Path $(ob_outputDirectory) -Recurse + displayName: 'List signed artifacts' + env: + ob_restore_phase: true diff --git a/.pipelines/templates/release-MakeBlobPublic.yml b/.pipelines/templates/release-MakeBlobPublic.yml index c8f12938d25..758298202a1 100644 --- a/.pipelines/templates/release-MakeBlobPublic.yml +++ b/.pipelines/templates/release-MakeBlobPublic.yml @@ -45,8 +45,7 @@ jobs: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - pwsh: | Get-ChildItem Env: @@ -132,8 +131,7 @@ jobs: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - pwsh: | Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose diff --git a/.pipelines/templates/release-checkout-pwsh-repo.yml b/.pipelines/templates/release-checkout-pwsh-repo.yml deleted file mode 100644 index 9a7486887a6..00000000000 --- a/.pipelines/templates/release-checkout-pwsh-repo.yml +++ /dev/null @@ -1,13 +0,0 @@ -steps: - - pwsh: | - Write-Verbose -Verbose "Deploy Box Product Pathway Does Not Support the `"checkout`" task" - if ($ENV:BUILD_REASON -eq 'PullRequest') { - throw 'We dont support PRs' - } - - Write-Verbose -Verbose $ENV:BUILD_SOURCEBRANCH - $branchName = $ENV:BUILD_SOURCEBRANCH -replace '^refs/heads/' - Write-Verbose -Verbose "Branch Name: $branchName" - git clone --depth 1 --branch $branchName https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/PowerShell '$(Pipeline.Workspace)/PowerShell' - cd $(Pipeline.Workspace)/PowerShell - displayName: Checkout Powershell Repository diff --git a/.pipelines/templates/release-download-packages.yml b/.pipelines/templates/release-download-packages.yml deleted file mode 100644 index 27a3098d1e1..00000000000 --- a/.pipelines/templates/release-download-packages.yml +++ /dev/null @@ -1,122 +0,0 @@ -jobs: -- job: upload_packages - displayName: Upload packages - condition: succeeded() - pool: - type: windows - variables: - - template: ./variable/release-shared.yml@self - parameters: - REPOROOT: $(Build.SourcesDirectory) - SBOM: true - - steps: - - pwsh: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: Capture environment variables - - - download: PSPackagesOfficial - artifact: drop_linux_package_deb - displayName: Download linux deb packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_fxdependent - displayName: Download linux fx packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_mariner_arm64 - displayName: Download linux mariner packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_mariner_x64 - displayName: Download linux mariner x64 packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_minSize - displayName: Download linux min packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_rpm - displayName: Download linux rpm packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar - displayName: Download linux tar packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_alpine - displayName: Download linux tar alpine packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_alpine_fxd - displayName: Download linux tar alpine fxd packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_arm - displayName: Download linux tar arm packages - - - download: PSPackagesOfficial - artifact: drop_linux_package_tar_arm64 - displayName: Download linux tar arm 64 packages - - - download: PSPackagesOfficial - artifact: drop_nupkg_build_nupkg - displayName: Download nupkg packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_arm64 - displayName: Download windows arm64 packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_fxdependent - displayName: Download windows fxdependent packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_fxdependentWinDesktop - displayName: Download windows fxdependentWinDesktop packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_minsize - displayName: Download windows minsize packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_x64 - displayName: Download windows x64 packages - - - download: PSPackagesOfficial - artifact: drop_windows_package_package_win_x86 - displayName: Download windows x86 packages - - - download: PSPackagesOfficial - artifact: macos-pkgs - displayName: Download macos tar packages - - - download: PSPackagesOfficial - artifact: drop_mac_package_sign_package_macos_arm64 - displayName: Download macos arm packages - - - download: PSPackagesOfficial - artifact: drop_mac_package_sign_package_macos_x64 - displayName: Download macos x64 packages - - - pwsh: | - Get-ChildItem '$(Pipeline.Workspace)/PSPackagesOfficial' -Recurse | Select-Object -ExpandProperty FullName - displayName: 'Capture downloads' - - - pwsh: | - $PackagesPath = '$(Pipeline.Workspace)/PSPackagesOfficial' - Write-Verbose -Verbose "Copying Github Release files in $PackagesPath to use in Release Pipeline" - - Write-Verbose -Verbose "Creating output directory for GitHub Release files: $(ob_outputDirectory)/GitHubPackages" - New-Item -Path $(ob_outputDirectory)/GitHubPackages -ItemType Directory -Force - Get-ChildItem -Path "$PackagesPath/*" -Recurse | - Where-Object { $_.Extension -notin '.msix', '.nupkg' } | - Where-Object { $_.Extension -in '.gz', '.pkg', '.msi', '.zip', '.deb', '.rpm', '.zip' } | - Copy-Item -Destination $(ob_outputDirectory)/GitHubPackages -Recurse -Verbose - - Write-Verbose -Verbose "Creating output directory for NuGet packages: $(ob_outputDirectory)/NuGetPackages" - New-Item -Path $(ob_outputDirectory)/NuGetPackages -ItemType Directory -Force - Get-ChildItem -Path "$PackagesPath/*" -Recurse | - Where-Object { $_.Extension -eq '.nupkg' } | - Copy-Item -Destination $(ob_outputDirectory)/NuGetPackages -Recurse -Verbose - displayName: Copy downloads to Artifacts diff --git a/.pipelines/templates/release-install-pwsh.yml b/.pipelines/templates/release-install-pwsh.yml deleted file mode 100644 index 9d7080a7e78..00000000000 --- a/.pipelines/templates/release-install-pwsh.yml +++ /dev/null @@ -1,34 +0,0 @@ -steps: - - task: PowerShell@2 - inputs: - targetType: inline - script: | - $localInstallerPath = Get-ChildItem -Path "$(Pipeline.Workspace)/GitHubPackages" -Filter '*win-x64.msi' | Select-Object -First 1 -ExpandProperty FullName - if (Test-Path -Path $localInstallerPath) { - Write-Verbose -Verbose "Installer found at $localInstallerPath" - } else { - throw "Installer not found" - } - Write-Verbose -Verbose "Installing PowerShell via msiexec" - Start-Process -FilePath msiexec -ArgumentList "/package $localInstallerPath /quiet REGISTER_MANIFEST=1" -Wait -NoNewWindow - $pwshPath = Get-ChildItem -Directory -Path 'C:\Program Files\PowerShell\7*' | Select-Object -First 1 -ExpandProperty FullName - if (Test-Path -Path $pwshPath) { - Write-Verbose -Verbose "PowerShell installed at $pwshPath" - Write-Verbose -Verbose "Adding pwsh to env:PATH" - Write-Host "##vso[task.prependpath]$pwshPath" - } else { - throw "PowerShell not installed" - } - displayName: Install pwsh 7 - - - task: PowerShell@2 - inputs: - targetType: inline - pwsh: true - script: | - Write-Verbose -Verbose "Pwsh 7 Installed" - Write-Verbose -Verbose "env:Path: " - $env:PATH -split ';' | ForEach-Object { - Write-Verbose -Verbose $_ - } - displayName: Check pwsh 7 installation diff --git a/.pipelines/templates/set-reporoot.yml b/.pipelines/templates/set-reporoot.yml new file mode 100644 index 00000000000..af7983afaa1 --- /dev/null +++ b/.pipelines/templates/set-reporoot.yml @@ -0,0 +1,35 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + +steps: +- pwsh: | + $path = "./build.psm1" + if($env:REPOROOT){ + Write-Verbose "reporoot already set to ${env:REPOROOT}" -Verbose + exit 0 + } + if(Test-Path -Path $path) + { + Write-Verbose "reporoot detected at: ." -Verbose + $repoRoot = '.' + } + else{ + $path = "./PowerShell/build.psm1" + if(Test-Path -Path $path) + { + Write-Verbose "reporoot detected at: ./PowerShell" -Verbose + $repoRoot = './PowerShell' + } + } + if($repoRoot) { + $vstsCommandString = "vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + } else { + Write-Verbose -Verbose "repo not found" + } + displayName: 'Set repo Root' + env: + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/shouldSign.yml b/.pipelines/templates/shouldSign.yml index 4bac9e1a3ae..551297f3aaa 100644 --- a/.pipelines/templates/shouldSign.yml +++ b/.pipelines/templates/shouldSign.yml @@ -1,3 +1,8 @@ +parameters: +- name: ob_restore_phase + type: boolean + default: true + steps: - powershell: | $shouldSign = $true @@ -22,4 +27,4 @@ steps: Write-Host "##$vstsCommandString" displayName: 'Set SHOULD_SIGN Variable' env: - ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue + ob_restore_phase: ${{ parameters.ob_restore_phase }} diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index b330a2eef10..20842de81cc 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -36,8 +36,7 @@ jobs: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - UseJson: no + CreateJson: no - template: /.pipelines/templates/release-SetReleaseTagandContainerName.yml@self From d54c2d1df3116222d301fe361044699ba23af63d Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 2 Dec 2025 15:56:35 -0800 Subject: [PATCH 022/127] [release/v7.6] Move package validation to package pipeline (#26558) --- .pipelines/PowerShell-Packages-Official.yml | 6 ++++++ .pipelines/PowerShell-Release-Official.yml | 9 +-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 8e06be1cc64..afd82af4462 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -299,3 +299,9 @@ extends: dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON jobs: - template: /.pipelines/templates/uploadToAzure.yml@self + + - stage: validatePackages + displayName: 'Validate Packages' + dependsOn: [upload] + jobs: + - template: /.pipelines/templates/release-validate-packagenames.yml@self diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index ca6b79335dd..868d61ebfd0 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -216,12 +216,6 @@ extends: arm64: 'yes' enableCredScan: false - - stage: validatePackages - displayName: 'Validate Packages' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-packagenames.yml@self - - stage: ManualValidation dependsOn: [] displayName: Manual Validation @@ -272,7 +266,6 @@ extends: dependsOn: - ManualValidation - ReleaseAutomation - - validatePackages - fxdpackages - gbltool - validateSdk @@ -365,7 +358,7 @@ extends: This is typically done by the community 1-2 days after the release. - stage: PublishMsix - dependsOn: + dependsOn: - setReleaseTagAndChangelog - PushGitTagAndMakeDraftPublic displayName: Publish MSIX to store From a454f94daea0804b527b3e7ba841129d987db095 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 2 Dec 2025 15:57:16 -0800 Subject: [PATCH 023/127] [release/v7.6] Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26561) --- ...onebranch-condition-syntax.instructions.md | 223 ++++++++++++++++++ .pipelines/templates/package-create-msix.yml | 4 +- 2 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 .github/instructions/onebranch-condition-syntax.instructions.md diff --git a/.github/instructions/onebranch-condition-syntax.instructions.md b/.github/instructions/onebranch-condition-syntax.instructions.md new file mode 100644 index 00000000000..19bf331d9c3 --- /dev/null +++ b/.github/instructions/onebranch-condition-syntax.instructions.md @@ -0,0 +1,223 @@ +--- +applyTo: ".pipelines/**/*.{yml,yaml}" +--- + +# OneBranch Pipeline Condition Syntax + +## Overview +Azure Pipelines (OneBranch) uses specific syntax for referencing variables and parameters in condition expressions. Using the wrong syntax will cause conditions to fail silently or behave unexpectedly. + +## Variable Reference Patterns + +### In Condition Expressions + +**✅ Correct Pattern:** +```yaml +condition: eq(variables['VariableName'], 'value') +condition: or(eq(variables['VAR1'], 'true'), eq(variables['VAR2'], 'true')) +condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) +``` + +**❌ Incorrect Patterns:** +```yaml +# Don't use $(VAR) string expansion in conditions +condition: eq('$(VariableName)', 'value') + +# Don't use direct variable references +condition: eq($VariableName, 'value') +``` + +### In Script Content (pwsh, bash, etc.) + +**✅ Correct Pattern:** +```yaml +- pwsh: | + $value = '$(VariableName)' + Write-Host "Value: $(VariableName)" +``` + +### In Input Fields + +**✅ Correct Pattern:** +```yaml +inputs: + serviceEndpoint: '$(ServiceEndpoint)' + sbConfigPath: '$(SBConfigPath)' +``` + +## Parameter References + +### Template Parameters (Compile-Time) + +**✅ Correct Pattern:** +```yaml +parameters: + - name: OfficialBuild + type: boolean + default: false + +steps: + - task: SomeTask@1 + condition: eq('${{ parameters.OfficialBuild }}', 'true') +``` + +Note: Parameters use `${{ parameters.Name }}` because they're evaluated at template compile-time. + +### Runtime Variables (Execution-Time) + +**✅ Correct Pattern:** +```yaml +steps: + - pwsh: | + Write-Host "##vso[task.setvariable variable=MyVar]somevalue" + displayName: Set Variable + + - task: SomeTask@1 + condition: eq(variables['MyVar'], 'somevalue') +``` + +## Common Scenarios + +### Scenario 1: Check if Variable Equals Value + +```yaml +- task: DoSomething@1 + condition: eq(variables['PREVIEW'], 'true') +``` + +### Scenario 2: Multiple Variable Conditions (OR) + +```yaml +- task: DoSomething@1 + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) +``` + +### Scenario 3: Multiple Variable Conditions (AND) + +```yaml +- task: DoSomething@1 + condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) +``` + +### Scenario 4: Complex Conditions + +```yaml +- task: DoSomething@1 + condition: and( + succeededOrFailed(), + ne(variables['UseAzDevOpsFeed'], ''), + eq(variables['Build.SourceBranch'], 'refs/heads/master') + ) +``` + +### Scenario 5: Built-in Variables + +```yaml +- task: CodeQL3000Init@0 + condition: eq(variables['Build.SourceBranch'], 'refs/heads/master') + +- step: finalize + condition: eq(variables['Agent.JobStatus'], 'SucceededWithIssues') +``` + +### Scenario 6: Parameter vs Variable + +```yaml +parameters: + - name: OfficialBuild + type: boolean + +steps: + # Parameter condition (compile-time) + - task: SignFiles@1 + condition: eq('${{ parameters.OfficialBuild }}', 'true') + + # Variable condition (runtime) + - task: PublishArtifact@1 + condition: eq(variables['PUBLISH_ENABLED'], 'true') +``` + +## Why This Matters + +**String Expansion `$(VAR)` in Conditions:** +- When you use `'$(VAR)'` in a condition, Azure Pipelines attempts to expand it as a string +- If the variable is undefined or empty, it becomes an empty string `''` +- The condition `eq('', 'true')` will always be false +- This makes debugging difficult because there's no error message + +**Variables Array Syntax `variables['VAR']`:** +- This is the proper way to reference runtime variables in conditions +- Azure Pipelines correctly evaluates the variable's value +- Undefined variables are handled properly by the condition evaluator +- This is the standard pattern used throughout Azure Pipelines + +## Reference Examples + +Working examples can be found in: +- `.pipelines/templates/linux.yml` - Build.SourceBranch conditions +- `.pipelines/templates/windows-hosted-build.yml` - Architecture conditions +- `.pipelines/templates/compliance/apiscan.yml` - CODEQL_ENABLED conditions +- `.pipelines/templates/insert-nuget-config-azfeed.yml` - Complex AND/OR conditions + +## Quick Reference Table + +| Context | Syntax | Example | +|---------|--------|---------| +| Condition expression | `variables['Name']` | `condition: eq(variables['PREVIEW'], 'true')` | +| Script content | `$(Name)` | `pwsh: Write-Host "$(PREVIEW)"` | +| Task input | `$(Name)` | `inputs: path: '$(Build.SourcesDirectory)'` | +| Template parameter | `${{ parameters.Name }}` | `condition: eq('${{ parameters.Official }}', 'true')` | + +## Troubleshooting + +### Condition Always False +If your condition is always evaluating to false: +1. Check if you're using `'$(VAR)'` instead of `variables['VAR']` +2. Verify the variable is actually set (add a debug step to print the variable) +3. Check the variable value is exactly what you expect (case-sensitive) + +### Variable Not Found +If you get errors about variables not being found: +1. Ensure the variable is set before the condition is evaluated +2. Check that the variable name is spelled correctly +3. Verify the variable is in scope (job vs. stage vs. pipeline level) + +## Best Practices + +1. **Always use `variables['Name']` in conditions** - This is the correct Azure Pipelines pattern +2. **Use `$(Name)` for string expansion** in scripts and inputs +3. **Use `${{ parameters.Name }}` for template parameters** (compile-time) +4. **Add debug steps** to verify variable values when troubleshooting conditions +5. **Follow existing patterns** in the repository - grep for `condition:` to see examples + +## Common Mistakes + +❌ **Mistake 1: String expansion in condition** +```yaml +condition: eq('$(PREVIEW)', 'true') # WRONG +``` + +✅ **Fix:** +```yaml +condition: eq(variables['PREVIEW'], 'true') # CORRECT +``` + +❌ **Mistake 2: Missing quotes around parameter** +```yaml +condition: eq(${{ parameters.Official }}, true) # WRONG +``` + +✅ **Fix:** +```yaml +condition: eq('${{ parameters.Official }}', 'true') # CORRECT +``` + +❌ **Mistake 3: Mixing syntax** +```yaml +condition: or(eq('$(STABLE)', 'true'), eq(variables['LTS'], 'true')) # INCONSISTENT +``` + +✅ **Fix:** +```yaml +condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) # CORRECT +``` diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index db801cf8748..f0668c7d3dc 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -224,7 +224,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package' inputs: - serviceEndpoint: 'StoreAppPublish-Private' + serviceEndpoint: '$(ServiceConnection)' sbConfigPath: '$(SBConfigPath)' sourceFolder: '$(BundleDir)' contents: '*.msixBundle' @@ -254,4 +254,4 @@ jobs: else { Write-Error "Required files not found in $submissionPackageDir" } - displayName: 'Upload StoreBroker Package' + displayName: 'Upload StoreBroker Package' \ No newline at end of file From 47927a24e03bb27bd218e4dade81b073796d18c6 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 2 Dec 2025 15:57:34 -0800 Subject: [PATCH 024/127] [release/v7.6] Update the macos package name for preview releases to match the previous pattern (#26562) --- .../release-validate-packagenames.yml | 2 +- tools/packaging/packaging.psm1 | 9 +++---- .../releaseTests/macOSPackage.tests.ps1 | 25 +++++++++++++++++-- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml index c717b50f289..6344418cd8f 100644 --- a/.pipelines/templates/release-validate-packagenames.yml +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -82,7 +82,7 @@ jobs: - pwsh: | $message = @() Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.pkg | ForEach-Object { - if($_.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx(\.10\.12)?\-(x64|arm64)\.pkg') + if($_.Name -notmatch 'powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx\-(x64|arm64)\.pkg') { $messageInstance = "$($_.Name) is not a valid package name" $message += $messageInstance diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index a55af6a83c2..f27ce3acf02 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1147,15 +1147,12 @@ function New-UnixPackage { } # Determine if the version is a preview version - $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS - - # Preview versions have preview in the name + # Only LTS packages get a prefix in the name + # Preview versions are identified by the version string itself (e.g., 7.6.0-preview.6) + # Rebuild versions are also identified by the version string (e.g., 7.4.13-rebuild.5) $Name = if($LTS) { "powershell-lts" } - elseif ($IsPreview) { - "powershell-preview" - } else { "powershell" } diff --git a/tools/packaging/releaseTests/macOSPackage.tests.ps1 b/tools/packaging/releaseTests/macOSPackage.tests.ps1 index c1de1091562..6e027f8faa2 100644 --- a/tools/packaging/releaseTests/macOSPackage.tests.ps1 +++ b/tools/packaging/releaseTests/macOSPackage.tests.ps1 @@ -74,7 +74,28 @@ Describe "Verify macOS Package" { $script:package | Should -Not -BeNullOrEmpty -Because "A .pkg file should be created" $script:package.Extension | Should -Be ".pkg" } - + + It "Package name should follow correct naming convention" { + $script:package | Should -Not -BeNullOrEmpty + + # Regex pattern for valid macOS PKG package names. + # This pattern matches the validation used in release-validate-packagenames.yml + # Valid examples: + # - powershell-7.4.13-osx-x64.pkg (Stable release) + # - powershell-7.6.0-preview.6-osx-x64.pkg (Preview version string) + # - powershell-7.4.13-rebuild.5-osx-arm64.pkg (Rebuild version) + # - powershell-lts-7.4.13-osx-arm64.pkg (LTS package) + $pkgPackageNamePattern = '^powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx\-(x64|arm64)\.pkg$' + + $script:package.Name | Should -Match $pkgPackageNamePattern -Because "Package name should follow the standard naming convention" + } + + It "Package name should NOT use x86_64 with underscores" { + $script:package | Should -Not -BeNullOrEmpty + + $script:package.Name | Should -Not -Match 'x86_64' -Because "Package should use 'x64' not 'x86_64' (with underscores) for compatibility" + } + It "Package should expand successfully" { $script:expandDir | Should -Exist Get-ChildItem -Path $script:expandDir | Should -Not -BeNullOrEmpty @@ -159,4 +180,4 @@ Describe "Verify macOS Package" { } } } -} +} \ No newline at end of file From 2bdc89fc7d3841439a5ed81eb22da434add8a719 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 2 Dec 2025 15:57:46 -0800 Subject: [PATCH 025/127] [release/v7.6] Mirror .NET/runtime ICU version range in PowerShell (#26563) --- tools/packaging/packaging.psm1 | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index f27ce3acf02..6e04ac171b8 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -2111,6 +2111,22 @@ function Get-PackageDependencies # These should match those in the Dockerfiles, but exclude tools like Git, which, and curl $Dependencies = @() + + # ICU version range follows .NET runtime policy. + # See: https://github.com/dotnet/runtime/blob/3fe8518d51bbcaa179bbe275b2597fbe1b88bc5a/src/native/libs/System.Globalization.Native/pal_icushim.c#L235-L243 + # + # Version range rationale: + # - The runtime supports ICU versions >= the version it was built against + # and <= that version + 30, to allow sufficient headroom for future releases. + # - ICU typically releases about twice per year, so +30 provides roughly + # 15 years of forward compatibility. + # - On some platforms, the minimum supported version may be lower + # than the build version and we know that older versions just works. + # + $MinICUVersion = 60 # runtime minimum supported + $BuildICUVersion = 76 # current build version + $MaxICUVersion = $BuildICUVersion + 30 # headroom + if ($Distribution -eq 'deb') { $Dependencies = @( "libc6", @@ -2118,10 +2134,9 @@ function Get-PackageDependencies "libgssapi-krb5-2", "libstdc++6", "zlib1g", - "libicu76|libicu74|libicu72|libicu71|libicu70|libicu69|libicu68|libicu67|libicu66|libicu65|libicu63|libicu60|libicu57|libicu55|libicu52", + (($MaxICUVersion..$MinICUVersion).ForEach{ "libicu$_" } -join '|'), "libssl3|libssl1.1|libssl1.0.2|libssl1.0.0" ) - } elseif ($Distribution -eq 'rh') { $Dependencies = @( "openssl-libs", From 2e047922ca807f816f8a52aa2b8c63f3ad61bd1a Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 2 Dec 2025 15:58:22 -0800 Subject: [PATCH 026/127] [release/v7.6] Close pipe client handles after creating the child ssh process (#26564) --- .../remoting/common/RunspaceConnectionInfo.cs | 34 +++++++++---------- .../fanin/OutOfProcTransportManager.cs | 8 ++--- .../Remoting/SSHRemotingCmdlets.Tests.ps1 | 21 ++++++++++++ 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index d9a6d0b317b..0c99f90fa7e 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -2211,11 +2211,11 @@ internal int StartSSHProcess( CommandTypes.Application, SearchResolutionOptions.None, CommandOrigin.Internal, - context) as ApplicationInfo; + context); - if (cmdInfo != null) + if (cmdInfo is ApplicationInfo appInfo) { - filePath = cmdInfo.Path; + filePath = appInfo.Path; } } else @@ -2273,13 +2273,13 @@ internal int StartSSHProcess( // Subsystem powershell /usr/local/bin/pwsh -SSHServerMode -NoLogo -NoProfile // codeql[cs/microsoft/command-line-injection-shell-execution] - This is expected Poweshell behavior where user inputted paths are supported for the context of this method. The user assumes trust for the file path specified, so any file executed in the runspace would be in the user's local system/process or a system they have access to in which case restricted remoting security guidelines should be used. - System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(filePath); + ProcessStartInfo startInfo = new(filePath); // pass "-i identity_file" command line argument to ssh if KeyFilePath is set // if KeyFilePath is not set, then ssh will use IdentityFile / IdentityAgent from ssh_config if defined else none by default if (!string.IsNullOrEmpty(this.KeyFilePath)) { - if (!System.IO.File.Exists(this.KeyFilePath)) + if (!File.Exists(this.KeyFilePath)) { throw new FileNotFoundException( StringUtil.Format(RemotingErrorIdStrings.KeyFileNotFound, this.KeyFilePath)); @@ -2326,7 +2326,7 @@ internal int StartSSHProcess( // note that ssh expects IPv6 addresses to not be enclosed in square brackets so trim them if present startInfo.ArgumentList.Add(string.Create(CultureInfo.InvariantCulture, $@"-s {this.ComputerName.TrimStart('[').TrimEnd(']')} {this.Subsystem}")); - startInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(filePath); + startInfo.WorkingDirectory = Path.GetDirectoryName(filePath); startInfo.CreateNoWindow = true; startInfo.UseShellExecute = false; @@ -2580,7 +2580,7 @@ private static unsafe void AllocNullTerminatedArray(string[] arr, ref byte** arr // Allocate the unmanaged array to hold each string pointer. // It needs to have an extra element to null terminate the array. arrPtr = (byte**)Marshal.AllocHGlobal(sizeof(IntPtr) * arrLength); - System.Diagnostics.Debug.Assert(arrPtr != null, "Invalid array ptr"); + Debug.Assert(arrPtr != null, "Invalid array ptr"); // Zero the memory so that if any of the individual string allocations fails, // we can loop through the array to free any that succeeded. @@ -2597,7 +2597,7 @@ private static unsafe void AllocNullTerminatedArray(string[] arr, ref byte** arr byte[] byteArr = System.Text.Encoding.UTF8.GetBytes(arr[i]); arrPtr[i] = (byte*)Marshal.AllocHGlobal(byteArr.Length + 1); // +1 for null termination - System.Diagnostics.Debug.Assert(arrPtr[i] != null, "Invalid array ptr"); + Debug.Assert(arrPtr[i] != null, "Invalid array ptr"); Marshal.Copy(byteArr, 0, (IntPtr)arrPtr[i], byteArr.Length); // copy over the data from the managed byte array arrPtr[i][byteArr.Length] = (byte)'\0'; // null terminate @@ -2641,13 +2641,13 @@ internal static extern unsafe int ForkAndExecProcess( /// P-Invoking native APIs. /// private static int StartSSHProcessImpl( - System.Diagnostics.ProcessStartInfo startInfo, + ProcessStartInfo startInfo, out StreamWriter stdInWriterVar, out StreamReader stdOutReaderVar, out StreamReader stdErrReaderVar) { Exception ex = null; - System.Diagnostics.Process sshProcess = null; + Process sshProcess = null; // // These std pipe handles are bound to managed Reader/Writer objects and returned to the transport // manager object, which uses them for PSRP communication. The lifetime of these handles are then @@ -2668,7 +2668,7 @@ private static int StartSSHProcessImpl( catch (InvalidOperationException e) { ex = e; } catch (ArgumentException e) { ex = e; } catch (FileNotFoundException e) { ex = e; } - catch (System.ComponentModel.Win32Exception e) { ex = e; } + catch (Win32Exception e) { ex = e; } if ((ex != null) || (sshProcess == null) || @@ -2693,9 +2693,9 @@ private static int StartSSHProcessImpl( { if (stdInWriterVar != null) { stdInWriterVar.Dispose(); } else { stdInPipeServer.Dispose(); } - if (stdOutReaderVar != null) { stdInWriterVar.Dispose(); } else { stdOutPipeServer.Dispose(); } + if (stdOutReaderVar != null) { stdOutReaderVar.Dispose(); } else { stdOutPipeServer.Dispose(); } - if (stdErrReaderVar != null) { stdInWriterVar.Dispose(); } else { stdErrPipeServer.Dispose(); } + if (stdErrReaderVar != null) { stdErrReaderVar.Dispose(); } else { stdErrPipeServer.Dispose(); } throw; } @@ -2705,7 +2705,7 @@ private static int StartSSHProcessImpl( private static void KillSSHProcessImpl(int pid) { - using (var sshProcess = System.Diagnostics.Process.GetProcessById(pid)) + using (var sshProcess = Process.GetProcessById(pid)) { if ((sshProcess != null) && (sshProcess.Handle != IntPtr.Zero) && !sshProcess.HasExited) { @@ -2736,7 +2736,7 @@ private static Process CreateProcessWithRedirectedStd( SafeFileHandle stdInPipeClient = null; SafeFileHandle stdOutPipeClient = null; SafeFileHandle stdErrPipeClient = null; - string randomName = System.IO.Path.GetFileNameWithoutExtension(System.IO.Path.GetRandomFileName()); + string randomName = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); try { @@ -2829,16 +2829,14 @@ private static Process CreateProcessWithRedirectedStd( catch (Exception) { stdInPipeServer?.Dispose(); - stdInPipeClient?.Dispose(); stdOutPipeServer?.Dispose(); - stdOutPipeClient?.Dispose(); stdErrPipeServer?.Dispose(); - stdErrPipeClient?.Dispose(); throw; } finally { + lpStartupInfo.Dispose(); lpProcessInformation.Dispose(); } } diff --git a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs index d9532c8691a..47ff6270dba 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs @@ -1733,7 +1733,7 @@ public override void CreateAsync() bool sshTerminated = false; try { - using (var sshProcess = System.Diagnostics.Process.GetProcessById(_sshProcessId)) + using (var sshProcess = Process.GetProcessById(_sshProcessId)) { sshTerminated = sshProcess == null || sshProcess.Handle == IntPtr.Zero || sshProcess.HasExited; } @@ -1847,7 +1847,7 @@ private void ProcessErrorThread(object state) // Messages in error stream from ssh are unreliable, and may just be warnings or // banner text. // So just report the messages but don't act on them. - System.Console.WriteLine(error); + Console.WriteLine(error); } catch (IOException) { } @@ -1907,10 +1907,10 @@ private void ProcessReaderThread(object state) break; } - if (data.StartsWith(System.Management.Automation.Remoting.Server.FormattedErrorTextWriter.ErrorPrefix, StringComparison.OrdinalIgnoreCase)) + if (data.StartsWith(OutOfProcessTextWriter.ErrorPrefix, StringComparison.OrdinalIgnoreCase)) { // Error message from the server. - string errorData = data.Substring(System.Management.Automation.Remoting.Server.FormattedErrorTextWriter.ErrorPrefix.Length); + string errorData = data.Substring(OutOfProcessTextWriter.ErrorPrefix.Length); HandleErrorDataReceived(errorData); } else diff --git a/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 index 1568d284d0f..c1090bdc186 100644 --- a/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 +++ b/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 @@ -70,3 +70,24 @@ Describe "SSHConnection parameter hashtable type conversions" -Tags 'Feature', ' $err.FullyQualifiedErrorId | Should -Match 'PSSessionOpenFailed' } } + +Describe "No hangs when host doesn't exist" -Tags "CI" { + $testCases = @( + @{ + Name = 'Verifies no hang for New-PSSession with non-existing host name' + ScriptBlock = { New-PSSession -HostName "test-notexist" -UserName "test" -ErrorAction Stop } + FullyQualifiedErrorId = 'PSSessionOpenFailed' + }, + @{ + Name = 'Verifies no hang for Invoke-Command with non-existing host name' + ScriptBlock = { Invoke-Command -HostName "test-notexist" -UserName "test" -ScriptBlock { 1 } -ErrorAction Stop } + FullyQualifiedErrorId = 'PSSessionStateBroken' + } + ) + + It "" -TestCases $testCases { + param ($ScriptBlock, $FullyQualifiedErrorId) + + $ScriptBlock | Should -Throw -ErrorId $FullyQualifiedErrorId -ExceptionType 'System.Management.Automation.Remoting.PSRemotingTransportException' + } +} From 6827de520bcf32edb212f713685ebb008503c866 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 4 Dec 2025 10:37:54 -0800 Subject: [PATCH 027/127] [release/v7.6] Properly Expand Aliases to their actual ResolvedCommand (#26571) Co-authored-by: Ryan Yates --- .../engine/TypeTable_Types_Ps1Xml.cs | 10 ++-------- .../Microsoft.PowerShell.Utility/Get-Alias.Tests.ps1 | 10 ++++++++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/System.Management.Automation/engine/TypeTable_Types_Ps1Xml.cs b/src/System.Management.Automation/engine/TypeTable_Types_Ps1Xml.cs index c1a134cdfbf..26e3621c240 100644 --- a/src/System.Management.Automation/engine/TypeTable_Types_Ps1Xml.cs +++ b/src/System.Management.Automation/engine/TypeTable_Types_Ps1Xml.cs @@ -565,9 +565,7 @@ private void Process_Types_Ps1Xml(string filePath, ConcurrentBag errors) typeName, new PSScriptProperty( @"DisplayName", - GetScriptBlock(@"if ($this.Name.IndexOf('-') -lt 0) - { - if ($null -ne $this.ResolvedCommand) + GetScriptBlock(@"if ($null -ne $this.ResolvedCommand) { $this.Name + "" -> "" + $this.ResolvedCommand.Name } @@ -575,11 +573,7 @@ private void Process_Types_Ps1Xml(string filePath, ConcurrentBag errors) { $this.Name + "" -> "" + $this.Definition } - } - else - { - $this.Name - }"), + "), setterScript: null, shouldCloneOnAccess: true), typeMembers, diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Alias.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Alias.Tests.ps1 index edccb912ca7..a5b0b039d00 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Alias.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Alias.Tests.ps1 @@ -155,6 +155,16 @@ Describe "Get-Alias DRT Unit Tests" -Tags "CI" { $returnObject[$i].Definition | Should -Be 'Get-Command' } } + + It "Get-Alias DisplayName should always show AliasName -> ResolvedCommand for all aliases" { + Set-Alias -Name Test-MyAlias -Value Get-Command -Force + Set-Alias -Name tma -Value Test-MyAlias -force + $aliases = Get-Alias Test-MyAlias, tma + $aliases | ForEach-Object { + $_.DisplayName | Should -Be "$($_.Name) -> Get-Command" + } + $aliases.Name.foreach{Remove-Item Alias:$_ -ErrorAction SilentlyContinue} + } } Describe "Get-Alias" -Tags "CI" { From 2d213e283b27c22ec8e2357ab9a5f86838c3f766 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 4 Dec 2025 10:40:57 -0800 Subject: [PATCH 028/127] [release/v7.6] Add Delimiter parameter to Get-Clipboard (#26572) Co-authored-by: MartinGC94 <42123497+MartinGC94@users.noreply.github.com> --- .../management/GetClipboardCommand.cs | 42 ++++++++++++++++++- .../Clipboard.Tests.ps1 | 7 ++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs index dd878bd72ce..a2b7f03ce70 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetClipboardCommand.cs @@ -2,8 +2,10 @@ // Licensed under the MIT License. using System; +using System.Collections; using System.Collections.Generic; using System.Management.Automation; +using System.Management.Automation.Language; using Microsoft.PowerShell.Commands.Internal; namespace Microsoft.PowerShell.Commands @@ -34,6 +36,13 @@ public SwitchParameter Raw } } + /// + /// Gets or sets the delimiters to use when splitting the clipboard content. + /// + [Parameter] + [ArgumentCompleter(typeof(DelimiterCompleter))] + public string[] Delimiter { get; set; } = [Environment.NewLine]; + private bool _raw; /// @@ -68,11 +77,40 @@ private List GetClipboardContentAsText() } else { - string[] splitSymbol = { Environment.NewLine }; - result.AddRange(textContent.Split(splitSymbol, StringSplitOptions.None)); + result.AddRange(textContent.Split(Delimiter, StringSplitOptions.None)); } return result; } } + + /// + /// Provides argument completion for the Delimiter parameter. + /// + public sealed class DelimiterCompleter : IArgumentCompleter + { + /// + /// Provides argument completion for the Delimiter parameter. + /// + /// The name of the command that is being completed. + /// The name of the parameter that is being completed. + /// The input text to filter the results by. + /// The ast of the command that triggered the completion. + /// The parameters bound to the command. + /// Completion results. + public IEnumerable CompleteArgument(string commandName, string parameterName, string wordToComplete, CommandAst commandAst, IDictionary fakeBoundParameters) + { + wordToComplete ??= string.Empty; + var pattern = new WildcardPattern(wordToComplete + '*', WildcardOptions.IgnoreCase); + if (pattern.IsMatch("CRLF") || pattern.IsMatch("Windows")) + { + yield return new CompletionResult("\"`r`n\"", "CRLF", CompletionResultType.ParameterValue, "Windows (CRLF)"); + } + + if (pattern.IsMatch("LF") || pattern.IsMatch("Unix") || pattern.IsMatch("Linux")) + { + yield return new CompletionResult("\"`n\"", "LF", CompletionResultType.ParameterValue, "UNIX (LF)"); + } + } + } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Clipboard.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Clipboard.Tests.ps1 index 7cd4f492bfa..62f8d77a44c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Clipboard.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Clipboard.Tests.ps1 @@ -36,6 +36,13 @@ Describe 'Clipboard cmdlet tests' -Tag CI { Get-Clipboard -Raw | Should -BeExactly "1$([Environment]::NewLine)2" } + It 'Get-Clipboard -Delimiter should return items based on the delimiter' { + Set-Clipboard -Value "Line1`r`nLine2`nLine3" + $result = Get-Clipboard -Delimiter "`r`n", "`n" + $result.Count | Should -Be 3 + $result | ForEach-Object -Process {$_.Length | Should -Be "LineX".Length} + } + It 'Set-Clipboard -Append will add text' { 'hello' | Set-Clipboard 'world' | Set-Clipboard -Append From 4109551362e0ec31feac39c19907472a591a21a4 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Thu, 4 Dec 2025 16:11:20 -0800 Subject: [PATCH 029/127] [release/v7.6] Improve ADO package build and validation across platforms (#26532) --- .github/workflows/macos-ci.yml | 2 +- .pipelines/templates/mac-package-build.yml | 26 +++++-- build.psm1 | 11 ++- .../macos/package-validation.tests.ps1 | 72 ++++++++++--------- tools/packaging/packaging.psm1 | 70 +++++++++--------- 5 files changed, 101 insertions(+), 80 deletions(-) rename tools/packaging/releaseTests/macOSPackage.tests.ps1 => test/packaging/macos/package-validation.tests.ps1 (90%) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index dc8b77ee047..92fac143187 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -201,7 +201,7 @@ jobs: } Import-Module Pester $pesterConfig = New-PesterConfiguration - $pesterConfig.Run.Path = './tools/packaging/releaseTests/macOSPackage.tests.ps1' + $pesterConfig.Run.Path = './test/packaging/macos/package-validation.tests.ps1' $pesterConfig.Run.PassThru = $true $pesterConfig.Output.Verbosity = 'Detailed' $pesterConfig.TestResult.Enabled = $true diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 7d0930955b3..1abb1722398 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -115,13 +115,25 @@ jobs: Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS $pkgNameFilter = "powershell-*$macosRuntime.pkg" - $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$pkgPath" + Write-Verbose -Verbose "Looking for pkg packages with filter: $pkgNameFilter in '$(Pipeline.Workspace)' to upload..." + $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgNameFilter -Recurse -File + + foreach($p in $pkgPath) { + $file = $p.FullName + Write-Verbose -verbose "Uploading $file to macos-pkgs" + Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" + } Start-PSPackage -Type tar -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS $tarPkgNameFilter = "powershell-*$macosRuntime.tar.gz" - $tarPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $tarPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName - Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$tarPkgPath" + Write-Verbose -Verbose "Looking for tar packages with filter: $tarPkgNameFilter in '$(Pipeline.Workspace)' to upload..." + $tarPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $tarPkgNameFilter -Recurse -File + + foreach($t in $tarPkgPath) { + $file = $t.FullName + Write-Verbose -verbose "Uploading $file to macos-pkgs" + Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" + } displayName: 'Package ${{ parameters.buildArchitecture}}' env: @@ -194,14 +206,14 @@ jobs: - pwsh: | $signedPkg = Get-ChildItem -Path $(Pipeline.Workspace) -Filter "*osx*.zip" -File - + $signedPkg | ForEach-Object { Write-Verbose -Verbose "Signed package zip: $_" - + if (-not (Test-Path $_)) { throw "Package not found: $_" } - + if (-not (Test-Path $(ob_outputDirectory))) { $null = New-Item -Path $(ob_outputDirectory) -ItemType Directory } diff --git a/build.psm1 b/build.psm1 index 5208fe55441..83bab7f846c 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2399,7 +2399,7 @@ function Start-PSBootstrap { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y rpm-build")) -IgnoreExitcode } } - + # For Debian-based systems and Mariner, ensure dpkg-deb is available if ($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) { Write-Verbose -Verbose "Checking for dpkg-deb..." @@ -2407,9 +2407,14 @@ function Start-PSBootstrap { Write-Warning "dpkg-deb not found. Installing dpkg package..." if ($environment.IsMariner) { # For Mariner (Azure Linux), install the extended repo first to access dpkg. + Write-Verbose -verbose "BEGIN: /etc/os-release content:" + Get-Content /etc/os-release | Write-Verbose -verbose + Write-Verbose -verbose "END: /etc/os-release content" + Write-Verbose -Verbose "Installing azurelinux-repos-extended for Mariner..." - Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager azurelinux-repos-extended")) -IgnoreExitcode - Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager dpkg")) -IgnoreExitcode + + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager azurelinux-repos-extended")) -IgnoreExitcode -Verbose + Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager dpkg")) -IgnoreExitcode -Verbose } else { Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo apt-get install -y dpkg")) -IgnoreExitcode } diff --git a/tools/packaging/releaseTests/macOSPackage.tests.ps1 b/test/packaging/macos/package-validation.tests.ps1 similarity index 90% rename from tools/packaging/releaseTests/macOSPackage.tests.ps1 rename to test/packaging/macos/package-validation.tests.ps1 index 6e027f8faa2..02b09fbb078 100644 --- a/tools/packaging/releaseTests/macOSPackage.tests.ps1 +++ b/test/packaging/macos/package-validation.tests.ps1 @@ -1,51 +1,54 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + Describe "Verify macOS Package" { BeforeAll { Write-Verbose "In Describe BeforeAll" -Verbose Import-Module $PSScriptRoot/../../../build.psm1 - + # Find the macOS package $packagePath = $env:PACKAGE_FOLDER if (-not $packagePath) { $packagePath = Get-Location } - + Write-Verbose "Looking for package in: $packagePath" -Verbose $package = Get-ChildItem -Path $packagePath -Filter "*.pkg" -ErrorAction SilentlyContinue | Select-Object -First 1 - + if (-not $package) { Write-Warning "No .pkg file found in $packagePath" } else { Write-Verbose "Found package: $($package.FullName)" -Verbose } - + # Set up test directories $script:package = $package $script:expandDir = $null $script:payloadDir = $null $script:extractedFiles = @() - + if ($package) { # Use TestDrive for temporary directories - pkgutil will create the expand directory $script:expandDir = Join-Path "TestDrive:" -ChildPath "package-contents-test" $expandDirResolved = (Resolve-Path "TestDrive:").ProviderPath $script:expandDir = Join-Path $expandDirResolved -ChildPath "package-contents-test" - + Write-Verbose "Expanding package to: $($script:expandDir)" -Verbose # pkgutil will create the directory itself, so don't pre-create it Start-NativeExecution { pkgutil --expand $package.FullName $script:expandDir } - + # Extract the payload to verify files $script:payloadDir = Join-Path "TestDrive:" -ChildPath "package-payload-test" $payloadDirResolved = (Resolve-Path "TestDrive:").ProviderPath $script:payloadDir = Join-Path $payloadDirResolved -ChildPath "package-payload-test" - + # Create payload directory since cpio needs it if (-not (Test-Path $script:payloadDir)) { $null = New-Item -ItemType Directory -Path $script:payloadDir -Force } - + $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse | Select-Object -First 1 if ($componentPkg) { Write-Verbose "Extracting payload from: $($componentPkg.FullName)" -Verbose @@ -57,18 +60,18 @@ Describe "Verify macOS Package" { Pop-Location } } - + # Get all extracted files for verification $script:extractedFiles = Get-ChildItem -Path $script:payloadDir -Recurse -ErrorAction SilentlyContinue Write-Verbose "Extracted $($script:extractedFiles.Count) files" -Verbose } } - + AfterAll { # TestDrive automatically cleans up, but we can ensure cleanup happens # No manual cleanup needed as TestDrive handles it } - + Context "Package existence and structure" { It "Package file should exist" { $script:package | Should -Not -BeNullOrEmpty -Because "A .pkg file should be created" @@ -79,13 +82,12 @@ Describe "Verify macOS Package" { $script:package | Should -Not -BeNullOrEmpty # Regex pattern for valid macOS PKG package names. - # This pattern matches the validation used in release-validate-packagenames.yml # Valid examples: - # - powershell-7.4.13-osx-x64.pkg (Stable release) - # - powershell-7.6.0-preview.6-osx-x64.pkg (Preview version string) - # - powershell-7.4.13-rebuild.5-osx-arm64.pkg (Rebuild version) - # - powershell-lts-7.4.13-osx-arm64.pkg (LTS package) - $pkgPackageNamePattern = '^powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx\-(x64|arm64)\.pkg$' + # - powershell-7.4.13-osx-x64.pkg (Intel x64 - note: x64 with hyphens for compatibility) + # - powershell-7.4.13-osx-arm64.pkg (Apple Silicon) + # - powershell-preview-7.6.0-preview.6-osx-x64.pkg + # - powershell-lts-7.4.13-osx-arm64.pkg + $pkgPackageNamePattern = '^powershell(-preview|-lts)?-\d+\.\d+\.\d+(-[a-z]+\.\d+)?-osx-(x64|arm64)\.pkg$' $script:package.Name | Should -Match $pkgPackageNamePattern -Because "Package name should follow the standard naming convention" } @@ -100,18 +102,18 @@ Describe "Verify macOS Package" { $script:expandDir | Should -Exist Get-ChildItem -Path $script:expandDir | Should -Not -BeNullOrEmpty } - + It "Package should have a component package" { $componentPkg = Get-ChildItem -Path $script:expandDir -Filter "*.pkg" -Recurse -ErrorAction SilentlyContinue $componentPkg | Should -Not -BeNullOrEmpty -Because "Package should contain a component.pkg" } - + It "Payload should extract successfully" { $script:payloadDir | Should -Exist $script:extractedFiles | Should -Not -BeNullOrEmpty -Because "Package payload should contain files" } } - + Context "Required files in package" { BeforeAll { $expectedFilePatterns = @{ @@ -120,7 +122,7 @@ Describe "Verify macOS Package" { "Man page" = "usr/local/share/man/man1/pwsh*.gz" "Launcher application plist" = "Applications/PowerShell*.app/Contents/Info.plist" } - + $testCases = @() foreach ($key in $expectedFilePatterns.Keys) { $testCases += @{ @@ -128,23 +130,23 @@ Describe "Verify macOS Package" { Pattern = $expectedFilePatterns[$key] } } - + $script:testCases = $testCases } - + It "Should contain " -TestCases $script:testCases { param($Description, $Pattern) - + $found = $script:extractedFiles | Where-Object { $_.FullName -like "*$Pattern*" } $found | Should -Not -BeNullOrEmpty -Because "$Description should exist in the package at path matching '$Pattern'" } } - + Context "PowerShell binary verification" { It "PowerShell executable should be executable" { $pwshBinary = $script:extractedFiles | Where-Object { $_.FullName -like "*/pwsh" -and $_.FullName -like "*/microsoft/powershell/*" } $pwshBinary | Should -Not -BeNullOrEmpty - + # Check if file has executable permissions (on Unix-like systems) if ($IsLinux -or $IsMacOS) { $permissions = (Get-Item $pwshBinary[0].FullName).UnixFileMode @@ -153,31 +155,31 @@ Describe "Verify macOS Package" { } } } - + Context "Launcher application" { It "Launcher app should have proper bundle structure" { $plistFile = $script:extractedFiles | Where-Object { $_.FullName -like "*PowerShell*.app/Contents/Info.plist" } $plistFile | Should -Not -BeNullOrEmpty - + # Verify the bundle has required components $appPath = Split-Path (Split-Path $plistFile[0].FullName -Parent) -Parent $macOSDir = Join-Path $appPath "Contents/MacOS" $resourcesDir = Join-Path $appPath "Contents/Resources" - + Test-Path $macOSDir | Should -Be $true -Because "App bundle should have Contents/MacOS directory" Test-Path $resourcesDir | Should -Be $true -Because "App bundle should have Contents/Resources directory" } - + It "Launcher script should exist and be executable" { - $launcherScript = $script:extractedFiles | Where-Object { - $_.FullName -like "*PowerShell*.app/Contents/MacOS/PowerShell.sh" + $launcherScript = $script:extractedFiles | Where-Object { + $_.FullName -like "*PowerShell*.app/Contents/MacOS/PowerShell.sh" } $launcherScript | Should -Not -BeNullOrEmpty -Because "Launcher script should exist" - + if ($IsLinux -or $IsMacOS) { $permissions = (Get-Item $launcherScript[0].FullName).UnixFileMode $permissions.ToString() | Should -Match 'x' -Because "Launcher script should have execute permissions" } } } -} \ No newline at end of file +} diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 6e04ac171b8..8b73a939af9 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1236,15 +1236,15 @@ function New-UnixPackage { # Use rpmbuild directly for RPM packages if ($PSCmdlet.ShouldProcess("Create RPM package with rpmbuild")) { Write-Log "Creating RPM package with rpmbuild..." - + # Create rpmbuild directory structure $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" $specsDir = Join-Path $rpmBuildRoot "SPECS" $rpmsDir = Join-Path $rpmBuildRoot "RPMS" - + New-Item -ItemType Directory -Path $specsDir -Force | Out-Null New-Item -ItemType Directory -Path $rpmsDir -Force | Out-Null - + # Generate RPM spec file $specContent = New-RpmSpec ` -Name $Name ` @@ -1261,11 +1261,11 @@ function New-UnixPackage { -LinkInfo $Links ` -Distribution $DebDistro ` -HostArchitecture $HostArchitecture - + $specFile = Join-Path $specsDir "$Name.spec" $specContent | Out-File -FilePath $specFile -Encoding ascii Write-Verbose "Generated spec file: $specFile" -Verbose - + # Log the spec file content if ($env:GITHUB_ACTIONS -eq 'true') { Write-Host "::group::RPM Spec File Content" @@ -1274,7 +1274,7 @@ function New-UnixPackage { } else { Write-Verbose "RPM Spec File Content:`n$specContent" -Verbose } - + # Build RPM package try { # Use bash to properly handle rpmbuild arguments @@ -1287,16 +1287,16 @@ function New-UnixPackage { Write-Verbose "Running: $buildCmd" -Verbose $Output = bash -c $buildCmd 2>&1 $exitCode = $LASTEXITCODE - + if ($exitCode -ne 0) { throw "rpmbuild failed with exit code $exitCode" } - + # Find the generated RPM - $rpmFile = Get-ChildItem -Path (Join-Path $rpmsDir $HostArchitecture) -Filter "*.rpm" -ErrorAction Stop | - Sort-Object -Property LastWriteTime -Descending | + $rpmFile = Get-ChildItem -Path (Join-Path $rpmsDir $HostArchitecture) -Filter "*.rpm" -ErrorAction Stop | + Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 - + if ($rpmFile) { # Copy RPM to current location Copy-Item -Path $rpmFile.FullName -Destination $CurrentLocation -Force @@ -1334,7 +1334,7 @@ function New-UnixPackage { -AfterRemoveScript $AfterScriptInfo.AfterRemoveScript ` -HostArchitecture $HostArchitecture ` -CurrentLocation $CurrentLocation - + $Output = @("Created package {:path=>""$($result.PackageName)""}") } catch { @@ -1345,7 +1345,7 @@ function New-UnixPackage { # Use native macOS packaging tools if ($PSCmdlet.ShouldProcess("Create macOS package with pkgbuild/productbuild")) { Write-Log "Creating macOS package with native tools..." - + $macPkgArgs = @{ Name = $Name Version = $packageVersion @@ -1360,7 +1360,7 @@ function New-UnixPackage { HostArchitecture = $HostArchitecture CurrentLocation = $CurrentLocation } - + try { $packageFile = New-MacOSPackage @macPkgArgs $Output = @("Created package {:path=>""$($packageFile.Name)""}") @@ -1383,7 +1383,7 @@ function New-UnixPackage { Clear-MacOSLauncher } } - + # Clean up rpmbuild directory if it was created if ($Type -eq 'rpm') { $rpmBuildRoot = Join-Path $env:HOME "rpmbuild" @@ -1392,7 +1392,7 @@ function New-UnixPackage { Remove-Item -Path $rpmBuildRoot -Recurse -Force -ErrorAction SilentlyContinue } } - + if ($AfterScriptInfo.AfterInstallScript) { Remove-Item -ErrorAction 'silentlycontinue' $AfterScriptInfo.AfterInstallScript -Force } @@ -1486,13 +1486,13 @@ function New-MacOsDistributionPackage $resourcesDir = Join-Path -Path $tempDir -ChildPath 'resources' New-Item -ItemType Directory -Path $resourcesDir -Force > $null - + # Copy background file to temp directory $backgroundFile = "$RepoRoot/assets/macDialog.png" if (Test-Path $backgroundFile) { Copy-Item -Path $backgroundFile -Destination $resourcesDir -Force } - + # Copy the component package to temp directory $componentFileName = Split-Path -Leaf -Path $ComponentPackage $tempComponentPath = Join-Path -Path $tempDir -ChildPath $componentFileName @@ -1508,7 +1508,7 @@ function New-MacOsDistributionPackage # Minimum OS version $minOSVersion = "11.0" # macOS Big Sur minimum - + # format distribution template with: # 0 - title # 1 - version @@ -1519,8 +1519,10 @@ function New-MacOsDistributionPackage $PackagingStrings.OsxDistributionTemplate -f $PackageName, $Version, $componentFileName, $minOSVersion, $PackageIdentifier, $HostArchitecture | Out-File -Encoding utf8 -FilePath $distributionXmlPath -Force # Build final package path - $finalPackagePath = Join-Path $OutputDirectory "$PackageName-$Version-osx-$HostArchitecture.pkg" - + # Rename x86_64 to x64 for compatibility + $packageArchName = if ($HostArchitecture -eq "x86_64") { "x64" } else { $HostArchitecture } + $finalPackagePath = Join-Path $OutputDirectory "$PackageName-$Version-osx-$packageArchName.pkg" + # Remove existing package if it exists if (Test-Path $finalPackagePath) { Write-Warning "Removing existing package: $finalPackagePath" @@ -1539,7 +1541,7 @@ function New-MacOsDistributionPackage --resources $resourcesDir ` $finalPackagePath } - + if (Test-Path $finalPackagePath) { Write-Log "Successfully created macOS package: $finalPackagePath" } @@ -1609,7 +1611,7 @@ function New-RpmSpec # RPM doesn't allow hyphens in version, so convert them to underscores # e.g., "7.6.0-preview.6" becomes Version: 7.6.0_preview.6 $rpmVersion = $Version -replace '-', '_' - + # Build Release field with distribution suffix (e.g., "1.cm" or "1.rh") # Don't use RPM macros - build the full release string in PowerShell $rpmRelease = "$Iteration.$Distribution" @@ -1635,7 +1637,7 @@ AutoReq: no } else { # For cross-architecture builds, don't specify BuildArch in spec # The --target option will handle the architecture - + # Disable automatic binary stripping for cross-arch builds # The native /bin/strip on x86_64 cannot process ARM64 binaries and would fail with: # "Unable to recognise the format of the input file" @@ -1643,7 +1645,7 @@ AutoReq: no # __strip: This macro controls the command used for stripping binaries during the build process. # /bin/true: A command that does nothing and always exits successfully, effectively bypassing the stripping process. $specContent += "%define __strip /bin/true`n" - + # Disable debug package generation to prevent strip-related errors # Debug packages require binary stripping which fails for cross-arch builds # See: https://rpm-packaging-guide.github.io/#debugging @@ -1900,11 +1902,11 @@ $(if ($extendedDescription) { $extendedDescription + "`n" }) # Copy DEBIAN directory and data files to build root $buildDir = Join-Path $debBuildRoot "build" New-Item -ItemType Directory -Path $buildDir -Force | Out-Null - + Write-Verbose "debianDir: $debianDir" -Verbose Write-Verbose "dataDir: $dataDir" -Verbose Write-Verbose "buildDir: $buildDir" -Verbose - + # Use cp to preserve symlinks Start-NativeExecution { cp -a $debianDir "$buildDir/DEBIAN" } Start-NativeExecution { cp -a $dataDir/* $buildDir } @@ -2014,14 +2016,14 @@ function New-MacOSPackage $linkDestDir = Join-Path $pkgRoot (Split-Path $link.Destination -Parent) New-Item -ItemType Directory -Path $linkDestDir -Force | Out-Null $finalLinkPath = Join-Path $pkgRoot $link.Destination - + Write-Verbose "Creating symlink at $finalLinkPath" -Verbose - + # Remove if exists if (Test-Path $finalLinkPath) { Remove-Item $finalLinkPath -Force } - + # Get the target of the original symlink and recreate it in the package root if (Test-Path $link.Source) { $linkTarget = (Get-Item $link.Source).Target @@ -2047,10 +2049,10 @@ function New-MacOSPackage # Build the component package using pkgbuild $pkgIdentifier = Get-MacOSPackageId -IsPreview:($Name -like '*-preview') - + if ($PSCmdlet.ShouldProcess("Build component package with pkgbuild")) { Write-Log "Running pkgbuild to create component package..." - + Start-NativeExecution -VerboseOutputOnError { pkgbuild --root $pkgRoot ` --identifier $pkgIdentifier ` @@ -2059,7 +2061,7 @@ function New-MacOSPackage --install-location "/" ` $componentPkgPath } - + Write-Verbose "Component package created: $componentPkgPath" -Verbose } @@ -2072,7 +2074,7 @@ function New-MacOSPackage -HostArchitecture $HostArchitecture ` -PackageIdentifier $pkgIdentifier ` -IsPreview:($Name -like '*-preview') - + return $distributionPackage } finally { From 932aea6967ab68bc0503487a023b4d813138753c Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 5 Dec 2025 10:52:30 -0800 Subject: [PATCH 030/127] [release/v7.6] Update the WCF packages to the latest version that is compatible with v4.10.3 (#26503) --- .../Microsoft.PowerShell.SDK.csproj | 17 +- .../System.Management.Automation.csproj | 7 - tools/packaging/boms/windows.json | 350 +++++++++++++----- tools/packaging/packaging.psm1 | 32 +- 4 files changed, 299 insertions(+), 107 deletions(-) diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 31c48def673..57994fb98f7 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -23,19 +23,10 @@ - - - - - - - - - + + + + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 0e435448b5f..11846f54897 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -34,17 +34,10 @@ - - - - - - - diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index af4d1736ed8..f811109f818 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -89,11 +89,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "cs/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "cs/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -159,6 +154,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "cs\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "cs\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "cs\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "cs\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "D3DCompiler_47_cor3.dll", "FileType": "NonProduct", @@ -201,11 +216,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "de/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "de/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -271,6 +281,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "de\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "de\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "de\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "de\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "DirectWriteForwarder.dll", "FileType": "NonProduct", @@ -316,11 +346,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "es/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "es/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -386,6 +411,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "es\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "es\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "es\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "es\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "fr/Microsoft.CodeAnalysis.CSharp.resources.dll", "FileType": "NonProduct", @@ -421,11 +466,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "fr/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "fr/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -491,6 +531,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "fr\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "fr\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "fr\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "fr\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "getfilesiginforedist.dll", "FileType": "NonProduct", @@ -551,11 +611,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "it/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "it/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -621,6 +676,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "it\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "it\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "it\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "it\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "ja/Microsoft.CodeAnalysis.CSharp.resources.dll", "FileType": "NonProduct", @@ -656,11 +731,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "ja/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "ja/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -726,6 +796,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "ja\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ja\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ja\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ja\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "Json.More.dll", "FileType": "NonProduct", @@ -776,11 +866,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "ko/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "ko/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -846,6 +931,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "ko\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ko\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ko\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ko\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "Markdig.Signed.dll", "FileType": "NonProduct", @@ -1111,11 +1216,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "Modules/ThreadJob/*.psd1", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\Microsoft.PowerShell.PSResourceGet.pdb", "FileType": "NonProduct", @@ -1156,16 +1256,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "Modules\\ThreadJob\\.signature.p7s", - "FileType": "NonProduct", - "Architecture": null - }, - { - "Pattern": "Modules\\ThreadJob\\ThreadJob.psm1", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "mscordaccore_*.dll", "FileType": "NonProduct", @@ -1246,11 +1336,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "pl/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "pl/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -1316,6 +1401,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "pl\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pl\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pl\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pl\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "powershell.config.json", "FileType": "NonProduct", @@ -1466,11 +1571,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "pt-BR/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "pt-BR/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -1536,6 +1636,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "pt-BR\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pt-BR\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pt-BR\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "pt-BR\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "pwrshplugin.dll", "FileType": "NonProduct", @@ -2431,11 +2551,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "ru/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "ru/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -2501,6 +2616,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "ru\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ru\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ru\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "ru\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "Schemas/PSMaml/base.xsd", "FileType": "NonProduct", @@ -3316,11 +3451,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "System.Private.ServiceModel.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "System.Private.Uri.dll", "FileType": "NonProduct", @@ -3606,6 +3736,11 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "System.ServiceModel.NetFramingBase.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "System.ServiceModel.NetTcp.dll", "FileType": "NonProduct", @@ -3901,11 +4036,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "tr/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "tr/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -3971,6 +4101,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "tr\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "tr\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "tr\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "tr\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "UIAutomationClient.dll", "FileType": "NonProduct", @@ -4046,11 +4196,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "zh-Hans/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "zh-Hans/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -4116,6 +4261,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "zh-Hans\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hans\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hans\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hans\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll", "FileType": "NonProduct", @@ -4151,11 +4316,6 @@ "FileType": "NonProduct", "Architecture": null }, - { - "Pattern": "zh-Hant/System.Private.ServiceModel.resources.dll", - "FileType": "NonProduct", - "Architecture": null - }, { "Pattern": "zh-Hant/System.Web.Services.Description.resources.dll", "FileType": "NonProduct", @@ -4221,6 +4381,26 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "zh-Hant\\System.ServiceModel.Http.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hant\\System.ServiceModel.NetFramingBase.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hant\\System.ServiceModel.NetTcp.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, + { + "Pattern": "zh-Hant\\System.ServiceModel.Primitives.resources.dll", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "_manifest/spdx_2.2/manifest.spdx.json", "FileType": "Product", diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 8b73a939af9..8e4dc9aa1dc 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -284,6 +284,18 @@ function Start-PSPackage { $createdSpdxPathSha = New-Item -Path $manifestSpdxPathSha -Force Write-Verbose -Verbose "Created manifest.spdx.json.sha256 file: $createdSpdxPathSha" } + + $bsiJsonPath = (Join-Path -Path $Source "_manifest\spdx_2.2\bsi.json") + if (-not (Test-Path -Path $bsiJsonPath)) { + $createdBsiJsonPath = New-Item -Path $bsiJsonPath -Force + Write-Verbose -Verbose "Created bsi.json file: $createdBsiJsonPath" + } + + $manifestCatPath = (Join-Path -Path $Source "_manifest\spdx_2.2\manifest.cat") + if (-not (Test-Path -Path $manifestCatPath)) { + $createdCatPath = New-Item -Path $manifestCatPath -Force + Write-Verbose -Verbose "Created manifest.cat file: $createdCatPath" + } } # If building a symbols package, we add a zip of the parent to publish @@ -5533,8 +5545,24 @@ function Send-AzdoFile { Copy-Item -Path $Path -Destination $logFile } - Write-Host "##vso[artifact.upload containerfolder=$newName;artifactname=$newName]$logFile" - Write-Verbose "Log file captured as $newName" -Verbose + Write-Verbose "Capture the log file as '$newName'" -Verbose + if($env:TF_BUILD) { + ## In Azure DevOps + Write-Host "##vso[artifact.upload containerfolder=$newName;artifactname=$newName]$logFile" + } elseif ($env:GITHUB_WORKFLOW -and $env:SYSTEM_ARTIFACTSDIRECTORY) { + ## In GitHub Actions + $destinationPath = $env:SYSTEM_ARTIFACTSDIRECTORY + Write-Verbose "Upload '$logFile' to '$destinationPath' in GitHub Action" -Verbose + + # Create the folder if it does not exist + if (!(Test-Path -Path $destinationPath)) { + $null = New-Item -ItemType Directory -Path $destinationPath -Force + } + + Copy-Item -Path $logFile -Destination $destinationPath -Force -Verbose + } else { + Write-Warning "This environment is neither Azure Devops nor GitHub Actions. Cannot capture the log file in this environment." + } } # Class used for serializing and deserialing a BOM into Json From dfa094e8517469559ff466f119dcda36fd38f293 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 5 Dec 2025 10:53:01 -0800 Subject: [PATCH 031/127] [release/v7.6] Fix a regression in the API `CompletionCompleters.CompleteFilename()` that causes null reference exception (#26487) --- .../CommandCompletion/CompletionCompleters.cs | 4 ++-- .../Host/TabCompletion/BugFix.Tests.ps1 | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 8ca133cf1c2..e0104805d0c 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -4580,8 +4580,8 @@ internal static IEnumerable CompleteFilename(CompletionContext return CommandCompletion.EmptyCompletionResult; } - var lastAst = context.RelatedAsts[^1]; - if (lastAst.Parent is UsingStatementAst usingStatement + var lastAst = context.RelatedAsts?[^1]; + if (lastAst?.Parent is UsingStatementAst usingStatement && usingStatement.UsingStatementKind is UsingStatementKind.Module or UsingStatementKind.Assembly && lastAst.Extent.File is not null) { diff --git a/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 b/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 index 32fd73f8c09..a7191d06e9b 100644 --- a/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/BugFix.Tests.ps1 @@ -126,4 +126,27 @@ Describe "Tab completion bug fix" -Tags "CI" { $Runspace.Dispose() } } + + It "Issue#26277 - [CompletionCompleters]::CompleteFilename('') should work" { + $testDir = Join-Path $TestDrive "TempTestDir" + $file1 = Join-Path $testDir "abc.ps1" + $file2 = Join-Path $testDir "def.py" + + New-Item -ItemType Directory -Path $testDir > $null + New-Item -ItemType File -Path $file1 > $null + New-Item -ItemType File -Path $file2 > $null + + try { + Push-Location -Path $testDir + $result = [System.Management.Automation.CompletionCompleters]::CompleteFilename("") + $result | Should -Not -Be $null + $result | Measure-Object | ForEach-Object -MemberName Count | Should -Be 2 + + $item1, $item2 = @($result) + $item1.ListItemText | Should -BeExactly 'abc.ps1' + $item2.ListItemText | Should -BeExactly 'def.py' + } finally { + Pop-Location + } + } } From f19ac4ccb4d6e1a1fb09c07fa9e9897609fcdec8 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 5 Dec 2025 11:04:24 -0800 Subject: [PATCH 032/127] [release/v7.6] Add rebuild branch support with conditional MSIX signing (#26573) --- .../ServiceGroupRoot/Shell/Run/Run.ps1 | 6 ++- ...werShell-Coordinated_Packages-Official.yml | 13 ++++- .pipelines/PowerShell-Packages-Official.yml | 2 + .pipelines/templates/channelSelection.yml | 26 ++++++++-- .pipelines/templates/linux-package-build.yml | 18 ++++++- .pipelines/templates/mac-package-build.yml | 18 ++++++- .pipelines/templates/package-create-msix.yml | 47 +++++++++++++++---- .../templates/packaging/windows/package.yml | 18 ++++++- .pipelines/templates/rebuild-branch-check.yml | 17 +++++++ 9 files changed, 147 insertions(+), 18 deletions(-) create mode 100644 .pipelines/templates/rebuild-branch-check.yml diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 index 25a5686b33e..23f91c1bff2 100644 --- a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 +++ b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 @@ -354,6 +354,9 @@ try { $skipPublish = $metadataContent.SkipPublish $lts = $metadataContent.LTS + # Check if this is a rebuild version (e.g., 7.4.13-rebuild.5) + $isRebuild = $releaseVersion -match '-rebuild\.' + if ($releaseVersion.Contains('-')) { $channel = 'preview' $packageNames = @('powershell-preview') @@ -363,7 +366,8 @@ try { $packageNames = @('powershell') } - if ($lts) { + # Only add LTS package if not a rebuild branch + if ($lts -and -not $isRebuild) { $packageNames += @('powershell-lts') } diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index f36eeadf298..e4de1fe5c21 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -296,9 +296,20 @@ extends: - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) + - template: /.pipelines/templates/rebuild-branch-check.yml@self - powershell: | $metadata = Get-Content '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't mark as LTS release for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, not marking as LTS release" -Verbose + } + @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" Get-Content "$(Build.StagingDirectory)\release.json" diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index afd82af4462..18ef7b2d14c 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -293,6 +293,8 @@ extends: dependsOn: [windows_package_build] # Only depends on unsigned packages jobs: - template: /.pipelines/templates/package-create-msix.yml@self + parameters: + OfficialBuild: ${{ parameters.OfficialBuild }} - stage: upload displayName: 'Upload' diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml index 3d1f445c559..9dd0f3fb216 100644 --- a/.pipelines/templates/channelSelection.yml +++ b/.pipelines/templates/channelSelection.yml @@ -2,13 +2,31 @@ steps: - pwsh: | # Determine LTS, Preview, or Stable $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json + $releaseTag = '$(OutputReleaseTag.releaseTag)' + + # Rebuild branches should be treated as preview builds + # NOTE: The following regex is duplicated from rebuild-branch-check.yml. + # This duplication is necessary because channelSelection.yml does not call rebuild-branch-check.yml, + # and is used in contexts where that check may not have run. + # If you update this regex, also update it in rebuild-branch-check.yml to keep them in sync. + $isRebuildBranch = '$(Build.SourceBranch)' -match 'refs/heads/rebuild/.*-rebuild\.' + $LTS = $metadata.LTSRelease.Latest $Stable = $metadata.StableRelease.Latest - $isPreview = '$(OutputReleaseTag.releaseTag)' -match '-' + $isPreview = $releaseTag -match '-' - $IsLTS = [bool]$LTS - $IsStable = [bool]$Stable - $IsPreview = [bool]$isPreview + # If this is a rebuild branch, force preview mode and ignore LTS metadata + if ($isRebuildBranch) { + $IsLTS = $false + $IsStable = $false + $IsPreview = $true + Write-Verbose -Message "Rebuild branch detected, forcing Preview channel" -Verbose + } + else { + $IsLTS = [bool]$LTS + $IsStable = [bool]$Stable + $IsPreview = [bool]$isPreview + } $channelVars = @{ IsLTS = $IsLTS diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index b1c170eaed5..bcf332b3778 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -62,6 +62,8 @@ jobs: parameters: nativePathRoot: '$(Agent.TempDirectory)' + - template: rebuild-branch-check.yml@self + - download: CoOrdinatedBuildPipeline artifact: ${{ parameters.unsignedDrop }} displayName: 'Download unsigned artifacts' @@ -139,7 +141,21 @@ jobs: } $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't build LTS packages for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose + } + + Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 1abb1722398..4e7040d4acc 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -60,6 +60,8 @@ jobs: parameters: nativePathRoot: '$(Agent.TempDirectory)' + - template: rebuild-branch-check.yml@self + - download: CoOrdinatedBuildPipeline artifact: macosBinResults-${{ parameters.buildArchitecture }} @@ -103,7 +105,21 @@ jobs: Get-PSOptions | Write-Verbose -Verbose $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't build LTS packages for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose + } + + Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index f0668c7d3dc..f3c7ef6fbe8 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -1,3 +1,8 @@ +parameters: + - name: OfficialBuild + type: boolean + default: false + jobs: - job: CreateMSIXBundle displayName: Create .msixbundle file @@ -49,7 +54,7 @@ jobs: **/*.msix targetPath: '$(Build.ArtifactStagingDirectory)/downloads' displayName: Download windows x86 packages - + # Finds the makeappx tool on the machine with image: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - pwsh: | $cmd = Get-Command makeappx.exe -ErrorAction Ignore @@ -99,12 +104,13 @@ jobs: - task: onebranch.pipeline.signing@1 displayName: Sign MsixBundle + condition: eq('${{ parameters.OfficialBuild }}', 'true') inputs: command: 'sign' signing_profile: $(MSIXProfile) files_to_sign: '**/*.msixbundle' search_root: '$(BundleDir)' - + - pwsh: | $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File Write-Verbose -Verbose "Signed bundle: $signedBundle" @@ -126,12 +132,12 @@ jobs: Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Recurse | Select-Object -ExpandProperty FullName Test-Path -Path '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP-Private.xml' | Write-Verbose -Verbose displayName: Output Pipeline.Workspace and System.DefaultWorkingDirectory - + - template: channelSelection.yml@self - pwsh: | $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' - $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' + $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" @@ -161,11 +167,11 @@ jobs: $currentChannel = if ($IsLTS) { 'LTS' } elseif ($IsStable) { 'Stable' } elseif ($IsPreview) { 'Preview' } - else { + else { Write-Error "No valid channel detected" exit 1 } - + $config = $channelConfigs[$currentChannel] Write-Verbose -Verbose "Selected channel: $currentChannel" Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" @@ -181,7 +187,7 @@ jobs: # Create namespace manager for XML with default namespace $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") - + $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) if ($appStoreNameElement) { $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) @@ -218,9 +224,32 @@ jobs: Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" + + # These variables are used in the next tasks to determine which ServiceEndpoint to use + $ltsValue = $IsLTS.ToString().ToLower() + $stableValue = $IsStable.ToString().ToLower() + $previewValue = $IsPreview.ToString().ToLower() + + Write-Verbose -Verbose "About to set variables:" + Write-Verbose -Verbose " LTS=$ltsValue" + Write-Verbose -Verbose " STABLE=$stableValue" + Write-Verbose -Verbose " PREVIEW=$previewValue" + + Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" + Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" + Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" + + Write-Verbose -Verbose "Variables set successfully" name: UpdateConfigs displayName: Update PDPs and SBConfig.json + - pwsh: | + Write-Verbose -Verbose "Checking variables after UpdateConfigs:" + Write-Verbose -Verbose "LTS=$(LTS)" + Write-Verbose -Verbose "STABLE=$(STABLE)" + Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" + displayName: Debug - Check Variables + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package' inputs: @@ -242,14 +271,14 @@ jobs: $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" - + if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { Write-Verbose -Verbose "Uploading StoreBroker Package files:" Write-Verbose -Verbose "JSON File: $jsonFile" Write-Verbose -Verbose "ZIP File: $zipFile" Copy-Item -Path $submissionPackageDir -Destination "$(ob_outputDirectory)" -Verbose -Recurse - } + } else { Write-Error "Required files not found in $submissionPackageDir" diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 9a8be4b18fe..83cdf730b53 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -60,6 +60,8 @@ jobs: nativePathRoot: '$(Agent.TempDirectory)' ob_restore_phase: false + - template: rebuild-branch-check.yml@self + - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_${{ parameters.runtime }}_release displayName: Download signed artifacts @@ -127,7 +129,21 @@ jobs: Get-PSOptions | Write-Verbose -Verbose $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json - $LTS = $metadata.LTSRelease.Package + + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't build LTS packages for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose + } + + Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" diff --git a/.pipelines/templates/rebuild-branch-check.yml b/.pipelines/templates/rebuild-branch-check.yml new file mode 100644 index 00000000000..a4b546a0dc6 --- /dev/null +++ b/.pipelines/templates/rebuild-branch-check.yml @@ -0,0 +1,17 @@ +# This template checks if the current branch is a rebuild branch +# and sets an output variable IsRebuildBranch that can be used by other templates +steps: +- pwsh: | + # Check if this is a rebuild branch (e.g., rebuild/v7.4.13-rebuild.5) + $isRebuildBranch = '$(Build.SourceBranch)' -match 'refs/heads/rebuild/.*-rebuild\.' + + $value = if ($isRebuildBranch) { 'true' } else { 'false' } + Write-Verbose -Message "IsRebuildBranch: $value" -Verbose + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected: $(Build.SourceBranch)" -Verbose + } + + Write-Host "##vso[task.setvariable variable=IsRebuildBranch;isOutput=true]$value" + name: RebuildBranchCheck + displayName: Check if Rebuild Branch From 55b48f79b92c0218d2c7bf2b6977c13b3b625069 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 5 Dec 2025 11:04:37 -0800 Subject: [PATCH 033/127] [release/v7.6] Update the macos package name for preview releases to match the previous pattern (#26576) --- test/packaging/macos/package-validation.tests.ps1 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/packaging/macos/package-validation.tests.ps1 b/test/packaging/macos/package-validation.tests.ps1 index 02b09fbb078..92179c31624 100644 --- a/test/packaging/macos/package-validation.tests.ps1 +++ b/test/packaging/macos/package-validation.tests.ps1 @@ -82,12 +82,13 @@ Describe "Verify macOS Package" { $script:package | Should -Not -BeNullOrEmpty # Regex pattern for valid macOS PKG package names. + # This pattern matches the validation used in release-validate-packagenames.yml # Valid examples: - # - powershell-7.4.13-osx-x64.pkg (Intel x64 - note: x64 with hyphens for compatibility) - # - powershell-7.4.13-osx-arm64.pkg (Apple Silicon) - # - powershell-preview-7.6.0-preview.6-osx-x64.pkg - # - powershell-lts-7.4.13-osx-arm64.pkg - $pkgPackageNamePattern = '^powershell(-preview|-lts)?-\d+\.\d+\.\d+(-[a-z]+\.\d+)?-osx-(x64|arm64)\.pkg$' + # - powershell-7.4.13-osx-x64.pkg (Stable release) + # - powershell-7.6.0-preview.6-osx-x64.pkg (Preview version string) + # - powershell-7.4.13-rebuild.5-osx-arm64.pkg (Rebuild version) + # - powershell-lts-7.4.13-osx-arm64.pkg (LTS package) + $pkgPackageNamePattern = '^powershell-(lts-)?\d+\.\d+\.\d+\-([a-z]*.\d+\-)?osx\-(x64|arm64)\.pkg$' $script:package.Name | Should -Match $pkgPackageNamePattern -Because "Package name should follow the standard naming convention" } @@ -182,4 +183,4 @@ Describe "Verify macOS Package" { } } } -} +} \ No newline at end of file From f5c8ae67852cf6932abd746e59cce9ac7101075a Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 5 Dec 2025 11:10:53 -0800 Subject: [PATCH 034/127] [release/v7.6] Fix template path for rebuild branch check in package.yml (#26560) Co-authored-by: Travis Plunk --- .pipelines/templates/packaging/windows/package.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 83cdf730b53..2d2869867c0 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -58,9 +58,8 @@ jobs: - template: /.pipelines/templates/cloneToOfficialPath.yml@self parameters: nativePathRoot: '$(Agent.TempDirectory)' - ob_restore_phase: false - - template: rebuild-branch-check.yml@self + - template: /.pipelines/templates/rebuild-branch-check.yml@self - download: CoOrdinatedBuildPipeline artifact: drop_windows_build_windows_${{ parameters.runtime }}_release @@ -223,4 +222,6 @@ jobs: - pwsh: | Get-ChildItem -Path $(ob_outputDirectory) -Recurse - displayName: 'List unsigned artifacts' + displayName: 'List artifacts' + env: + ob_restore_phase: true # This ensures this done in restore phase to workaround signing issue From 8f3b14c74be678d013fcab6fc0449862fb2d07b3 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 5 Dec 2025 11:47:24 -0800 Subject: [PATCH 035/127] [release/v7.6] Make the experimental feature `PSFeedbackProvider` stable (#26502) --- .../host/msh/ConsoleHost.cs | 47 +-- .../ExperimentalFeature.cs | 5 - .../engine/hostifaces/HostUtilities.cs | 357 ------------------ .../resources/SuggestionStrings.resx | 9 - 4 files changed, 1 insertion(+), 417 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index b866815a25c..bcc1d45da49 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -2565,14 +2565,7 @@ internal void Run(bool inputLoopIsNested) // Evaluate any suggestions if (previousResponseWasEmpty == false) { - if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSFeedbackProvider)) - { - EvaluateFeedbacks(ui); - } - else - { - EvaluateSuggestions(ui); - } + EvaluateFeedbacks(ui); } // Then output the prompt @@ -2896,44 +2889,6 @@ private void EvaluateFeedbacks(ConsoleHostUserInterface ui) } } - private void EvaluateSuggestions(ConsoleHostUserInterface ui) - { - // Output any training suggestions - try - { - List suggestions = HostUtilities.GetSuggestion(_parent.Runspace); - - if (suggestions.Count > 0) - { - ui.WriteLine(); - } - - bool first = true; - foreach (string suggestion in suggestions) - { - if (!first) - ui.WriteLine(); - - ui.WriteLine(suggestion); - - first = false; - } - } - catch (TerminateException) - { - // A variable breakpoint may be hit by HostUtilities.GetSuggestion. The debugger throws TerminateExceptions to stop the execution - // of the current statement; we do not want to treat these exceptions as errors. - } - catch (Exception e) - { - // Catch-all OK. This is a third-party call-out. - ui.WriteErrorLine(e.Message); - - LocalRunspace localRunspace = (LocalRunspace)_parent.Runspace; - localRunspace.GetExecutionContext.AppendDollarError(e); - } - } - private string EvaluatePrompt() { string promptString = _promptExec.ExecuteCommandAndGetResultAsString("prompt", out _); diff --git a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs index 877750bb199..7e17ec43137 100644 --- a/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs +++ b/src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -21,7 +20,6 @@ public class ExperimentalFeature #region Const Members internal const string EngineSource = "PSEngine"; - internal const string PSFeedbackProvider = "PSFeedbackProvider"; internal const string PSSerializeJSONLongEnumAsNumber = nameof(PSSerializeJSONLongEnumAsNumber); internal const string PSProfileDSCResource = "PSProfileDSCResource"; @@ -109,9 +107,6 @@ static ExperimentalFeature() new ExperimentalFeature( name: "PSLoadAssemblyFromNativeCode", description: "Expose an API to allow assembly loading from native code"), - new ExperimentalFeature( - name: PSFeedbackProvider, - description: "Replace the hard-coded suggestion framework with the extensible feedback provider"), new ExperimentalFeature( name: PSSerializeJSONLongEnumAsNumber, description: "Serialize enums based on long or ulong as an numeric value rather than the string representation when using ConvertTo-Json." diff --git a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs index 003625791b1..f06399e09d2 100644 --- a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs +++ b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Management.Automation.Host; using System.Management.Automation.Internal; @@ -12,26 +10,10 @@ using System.Management.Automation.Subsystem.Feedback; using System.Runtime.InteropServices; using System.Text; -using System.Text.RegularExpressions; - -using Microsoft.PowerShell.Commands; using Microsoft.PowerShell.Commands.Internal.Format; namespace System.Management.Automation { - internal enum SuggestionMatchType - { - /// Match on a command. - Command = 0, - /// Match based on exception message. - Error = 1, - /// Match by running a script block. - Dynamic = 2, - - /// Match by fully qualified ErrorId. - ErrorId = 3 - } - #region Public HostUtilities Class /// @@ -43,31 +25,6 @@ public static class HostUtilities private static readonly char s_actionIndicator = HostSupportUnicode() ? '\u27a4' : '>'; - private static readonly string s_checkForCommandInCurrentDirectoryScript = @" - [System.Diagnostics.DebuggerHidden()] - param() - - $foundSuggestion = $false - - if($lastError -and - ($lastError.Exception -is ""System.Management.Automation.CommandNotFoundException"")) - { - $escapedCommand = [System.Management.Automation.WildcardPattern]::Escape($lastError.TargetObject) - $foundSuggestion = @(Get-Command ($ExecutionContext.SessionState.Path.Combine(""."", $escapedCommand)) -ErrorAction Ignore).Count -gt 0 - } - - $foundSuggestion - "; - - private static readonly string s_createCommandExistsInCurrentDirectoryScript = @" - [System.Diagnostics.DebuggerHidden()] - param([string] $formatString) - - $formatString -f $lastError.TargetObject,"".\$($lastError.TargetObject)"" - "; - - private static readonly List s_suggestions = InitializeSuggestions(); - private static bool HostSupportUnicode() { // Reference: https://github.com/zkat/supports-unicode/blob/main/src/lib.rs @@ -87,23 +44,6 @@ private static bool HostSupportUnicode() return ctype.EndsWith("UTF8") || ctype.EndsWith("UTF-8"); } - private static List InitializeSuggestions() - { - var suggestions = new List() - { - NewSuggestion( - id: 3, - category: "General", - matchType: SuggestionMatchType.Dynamic, - rule: ScriptBlock.CreateDelayParsedScriptBlock(s_checkForCommandInCurrentDirectoryScript, isProductCode: true), - suggestion: ScriptBlock.CreateDelayParsedScriptBlock(s_createCommandExistsInCurrentDirectoryScript, isProductCode: true), - suggestionArgs: new object[] { SuggestionStrings.Suggestion_CommandExistsInCurrentDirectory_Legacy }, - enabled: true) - }; - - return suggestions; - } - #region GetProfileCommands /// /// Gets a PSObject whose base object is currentUserCurrentHost and with notes for the other 4 parameters. @@ -282,303 +222,6 @@ internal static string GetMaxLines(string source, int maxLines) return returnValue.ToString(); } - internal static List GetSuggestion(Runspace runspace) - { - if (!(runspace is LocalRunspace localRunspace)) - { - return new List(); - } - - // Get the last value of $? - bool questionMarkVariableValue = localRunspace.ExecutionContext.QuestionMarkVariableValue; - - // Get the last history item - History history = localRunspace.History; - HistoryInfo[] entries = history.GetEntries(-1, 1, true); - - if (entries.Length == 0) - return new List(); - - HistoryInfo lastHistory = entries[0]; - - // Get the last error - ArrayList errorList = (ArrayList)localRunspace.GetExecutionContext.DollarErrorVariable; - object lastError = null; - - if (errorList.Count > 0) - { - lastError = errorList[0] as Exception; - ErrorRecord lastErrorRecord = null; - - // The error was an actual ErrorRecord - if (lastError == null) - { - lastErrorRecord = errorList[0] as ErrorRecord; - } - else if (lastError is RuntimeException) - { - lastErrorRecord = ((RuntimeException)lastError).ErrorRecord; - } - - // If we got information about the error invocation, - // we can be more careful with the errors we pass along - if ((lastErrorRecord != null) && (lastErrorRecord.InvocationInfo != null)) - { - if (lastErrorRecord.InvocationInfo.HistoryId == lastHistory.Id) - lastError = lastErrorRecord; - else - lastError = null; - } - } - - Runspace oldDefault = null; - bool changedDefault = false; - if (Runspace.DefaultRunspace != runspace) - { - oldDefault = Runspace.DefaultRunspace; - changedDefault = true; - Runspace.DefaultRunspace = runspace; - } - - List suggestions = null; - - try - { - suggestions = GetSuggestion(lastHistory, lastError, errorList); - } - finally - { - if (changedDefault) - { - Runspace.DefaultRunspace = oldDefault; - } - } - - // Restore $? - localRunspace.ExecutionContext.QuestionMarkVariableValue = questionMarkVariableValue; - return suggestions; - } - - [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")] - internal static List GetSuggestion(HistoryInfo lastHistory, object lastError, ArrayList errorList) - { - var returnSuggestions = new List(); - - PSModuleInfo invocationModule = new PSModuleInfo(true); - invocationModule.SessionState.PSVariable.Set("lastHistory", lastHistory); - invocationModule.SessionState.PSVariable.Set("lastError", lastError); - - int initialErrorCount = 0; - - // Go through all of the suggestions - foreach (Hashtable suggestion in s_suggestions) - { - initialErrorCount = errorList.Count; - - // Make sure the rule is enabled - if (!LanguagePrimitives.IsTrue(suggestion["Enabled"])) - continue; - - SuggestionMatchType matchType = (SuggestionMatchType)LanguagePrimitives.ConvertTo( - suggestion["MatchType"], - typeof(SuggestionMatchType), - CultureInfo.InvariantCulture); - - // If this is a dynamic match, evaluate the ScriptBlock - if (matchType == SuggestionMatchType.Dynamic) - { - object result = null; - - ScriptBlock evaluator = suggestion["Rule"] as ScriptBlock; - if (evaluator == null) - { - suggestion["Enabled"] = false; - - throw new ArgumentException( - SuggestionStrings.RuleMustBeScriptBlock, "Rule"); - } - - try - { - result = invocationModule.Invoke(evaluator, null); - } - catch (Exception) - { - // Catch-all OK. This is a third-party call-out. - suggestion["Enabled"] = false; - continue; - } - - // If it returned results, evaluate its suggestion - if (LanguagePrimitives.IsTrue(result)) - { - string suggestionText = GetSuggestionText(suggestion["Suggestion"], (object[])suggestion["SuggestionArgs"], invocationModule); - - if (!string.IsNullOrEmpty(suggestionText)) - { - string returnString = string.Format( - CultureInfo.CurrentCulture, - "Suggestion [{0},{1}]: {2}", - (int)suggestion["Id"], - (string)suggestion["Category"], - suggestionText); - - returnSuggestions.Add(returnString); - } - } - } - else - { - string matchText = string.Empty; - - // Otherwise, this is a Regex match against the - // command or error - if (matchType == SuggestionMatchType.Command) - { - matchText = lastHistory.CommandLine; - } - else if (matchType == SuggestionMatchType.Error) - { - if (lastError != null) - { - Exception lastException = lastError as Exception; - if (lastException != null) - { - matchText = lastException.Message; - } - else - { - matchText = lastError.ToString(); - } - } - } - else if (matchType == SuggestionMatchType.ErrorId) - { - if (lastError != null && lastError is ErrorRecord errorRecord) - { - matchText = errorRecord.FullyQualifiedErrorId; - } - } - else - { - suggestion["Enabled"] = false; - - throw new ArgumentException( - SuggestionStrings.InvalidMatchType, - "MatchType"); - } - - // If the text matches, evaluate the suggestion - if (Regex.IsMatch(matchText, (string)suggestion["Rule"], RegexOptions.IgnoreCase)) - { - string suggestionText = GetSuggestionText(suggestion["Suggestion"], (object[])suggestion["SuggestionArgs"], invocationModule); - - if (!string.IsNullOrEmpty(suggestionText)) - { - string returnString = string.Format( - CultureInfo.CurrentCulture, - "Suggestion [{0},{1}]: {2}", - (int)suggestion["Id"], - (string)suggestion["Category"], - suggestionText); - - returnSuggestions.Add(returnString); - } - } - } - - // If the rule generated an error, disable it - if (errorList.Count != initialErrorCount) - { - suggestion["Enabled"] = false; - } - } - - return returnSuggestions; - } - - /// - /// Create suggestion with string rule and scriptblock suggestion. - /// - /// Identifier for the suggestion. - /// Category for the suggestion. - /// Suggestion match type. - /// Rule to match. - /// Scriptblock to run that returns the suggestion. - /// Arguments to pass to suggestion scriptblock. - /// True if the suggestion is enabled. - /// Hashtable representing the suggestion. - private static Hashtable NewSuggestion(int id, string category, SuggestionMatchType matchType, string rule, ScriptBlock suggestion, object[] suggestionArgs, bool enabled) - { - Hashtable result = new Hashtable(StringComparer.CurrentCultureIgnoreCase); - - result["Id"] = id; - result["Category"] = category; - result["MatchType"] = matchType; - result["Rule"] = rule; - result["Suggestion"] = suggestion; - result["SuggestionArgs"] = suggestionArgs; - result["Enabled"] = enabled; - - return result; - } - - /// - /// Create suggestion with scriptblock rule and suggestion. - /// - private static Hashtable NewSuggestion(int id, string category, SuggestionMatchType matchType, ScriptBlock rule, ScriptBlock suggestion, bool enabled) - { - Hashtable result = new Hashtable(StringComparer.CurrentCultureIgnoreCase); - - result["Id"] = id; - result["Category"] = category; - result["MatchType"] = matchType; - result["Rule"] = rule; - result["Suggestion"] = suggestion; - result["Enabled"] = enabled; - - return result; - } - - /// - /// Create suggestion with scriptblock rule and scriptblock suggestion with arguments. - /// - private static Hashtable NewSuggestion(int id, string category, SuggestionMatchType matchType, ScriptBlock rule, ScriptBlock suggestion, object[] suggestionArgs, bool enabled) - { - Hashtable result = NewSuggestion(id, category, matchType, rule, suggestion, enabled); - result.Add("SuggestionArgs", suggestionArgs); - - return result; - } - - /// - /// Get suggestion text from suggestion scriptblock with arguments. - /// - private static string GetSuggestionText(object suggestion, object[] suggestionArgs, PSModuleInfo invocationModule) - { - if (suggestion is ScriptBlock) - { - ScriptBlock suggestionScript = (ScriptBlock)suggestion; - - object result = null; - try - { - result = invocationModule.Invoke(suggestionScript, suggestionArgs); - } - catch (Exception) - { - // Catch-all OK. This is a third-party call-out. - return string.Empty; - } - - return (string)LanguagePrimitives.ConvertTo(result, typeof(string), CultureInfo.CurrentCulture); - } - else - { - return (string)LanguagePrimitives.ConvertTo(suggestion, typeof(string), CultureInfo.CurrentCulture); - } - } - /// /// Returns the prompt used in remote sessions: "[machine]: basePrompt" /// diff --git a/src/System.Management.Automation/resources/SuggestionStrings.resx b/src/System.Management.Automation/resources/SuggestionStrings.resx index 9e325b2616c..39fbc3469f2 100644 --- a/src/System.Management.Automation/resources/SuggestionStrings.resx +++ b/src/System.Management.Automation/resources/SuggestionStrings.resx @@ -123,16 +123,7 @@ PowerShell does not load commands from the current location by default (see 'Get If you trust this command, run the following command instead: - - The command "{0}" was not found, but does exist in the current location. PowerShell does not load commands from the current location by default. If you trust this command, instead type: "{1}". See "get-help about_Command_Precedence" for more details. - The most similar commands are: - - Rule must be a ScriptBlock for dynamic match types. - - - MatchType must be 'Command', 'Error', or 'Dynamic'. - From e7132af80388df3410ece0219c3199a0888126b3 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Fri, 5 Dec 2025 16:24:15 -0800 Subject: [PATCH 036/127] [release/v7.6] Add merge conflict marker detection to linux-ci workflow and refactor existing actions to use reusable get-changed-files action (#26530) --- .../actions/test/linux-packaging/action.yml | 6 + ...rshell-automatic-variables.instructions.md | 159 ++++++++++++++ ...rshell-module-organization.instructions.md | 201 ++++++++++++++++++ .github/workflows/linux-ci.yml | 89 ++++++-- .github/workflows/macos-ci.yml | 8 + .vsts-ci/templates/nanoserver.yml | 61 ------ tools/ci.psm1 | 43 +++- 7 files changed, 488 insertions(+), 79 deletions(-) create mode 100644 .github/instructions/powershell-automatic-variables.instructions.md create mode 100644 .github/instructions/powershell-module-organization.instructions.md delete mode 100644 .vsts-ci/templates/nanoserver.yml diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index a04e09b6a5c..ef9ba23e799 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -80,6 +80,12 @@ runs: Invoke-CIFinish shell: pwsh + - name: Install Pester + run: |- + Import-Module ./tools/ci.psm1 + Install-CIPester + shell: pwsh + - name: Validate Package Names run: |- # Run Pester tests to validate package names diff --git a/.github/instructions/powershell-automatic-variables.instructions.md b/.github/instructions/powershell-automatic-variables.instructions.md new file mode 100644 index 00000000000..5015847f41f --- /dev/null +++ b/.github/instructions/powershell-automatic-variables.instructions.md @@ -0,0 +1,159 @@ +--- +applyTo: + - "**/*.ps1" + - "**/*.psm1" +--- + +# PowerShell Automatic Variables - Naming Guidelines + +## Purpose + +This instruction provides guidelines for avoiding conflicts with PowerShell's automatic variables when writing PowerShell scripts and modules. + +## What Are Automatic Variables? + +PowerShell has built-in automatic variables that are created and maintained by PowerShell itself. Assigning values to these variables can cause unexpected behavior and side effects. + +## Common Automatic Variables to Avoid + +### Critical Variables (Never Use) + +- **`$matches`** - Contains the results of regular expression matches. Overwriting this can break regex operations. +- **`$_`** - Represents the current object in the pipeline. Only use within pipeline blocks. +- **`$PSItem`** - Alias for `$_`. Same rules apply. +- **`$args`** - Contains an array of undeclared parameters. Don't use as a regular variable. +- **`$input`** - Contains an enumerator of all input passed to a function. Don't reassign. +- **`$LastExitCode`** - Exit code of the last native command. Don't overwrite unless intentional. +- **`$?`** - Success status of the last command. Don't use as a variable name. +- **`$$`** - Last token in the last line received by the session. Don't use. +- **`$^`** - First token in the last line received by the session. Don't use. + +### Context Variables (Use with Caution) + +- **`$Error`** - Array of error objects. Don't replace, but can modify (e.g., `$Error.Clear()`). +- **`$PSBoundParameters`** - Parameters passed to the current function. Read-only. +- **`$MyInvocation`** - Information about the current command. Read-only. +- **`$PSCmdlet`** - Cmdlet object for advanced functions. Read-only. + +### Other Common Automatic Variables + +- `$true`, `$false`, `$null` - Boolean and null constants +- `$HOME`, `$PSHome`, `$PWD` - Path-related variables +- `$PID` - Process ID of the current PowerShell session +- `$Host` - Host application object +- `$PSVersionTable` - PowerShell version information + +For a complete list, see: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_automatic_variables + +## Best Practices + +### ❌ Bad - Using Automatic Variable Names + +```powershell +# Bad: $matches is an automatic variable used for regex capture groups +$matches = Select-String -Path $file -Pattern $pattern + +# Bad: $args is an automatic variable for undeclared parameters +$args = Get-ChildItem + +# Bad: $input is an automatic variable for pipeline input +$input = Read-Host "Enter value" +``` + +### ✅ Good - Using Descriptive Alternative Names + +```powershell +# Good: Use descriptive names that avoid conflicts +$matchedLines = Select-String -Path $file -Pattern $pattern + +# Good: Use specific names for arguments +$arguments = Get-ChildItem + +# Good: Use specific names for user input +$userInput = Read-Host "Enter value" +``` + +## Naming Alternatives + +When you encounter a situation where you might use an automatic variable name, use these alternatives: + +| Avoid | Use Instead | +|-------|-------------| +| `$matches` | `$matchedLines`, `$matchResults`, `$regexMatches` | +| `$args` | `$arguments`, `$parameters`, `$commandArgs` | +| `$input` | `$userInput`, `$inputValue`, `$inputData` | +| `$_` (outside pipeline) | Use a named parameter or explicit variable | +| `$Error` (reassignment) | Don't reassign; use `$Error.Clear()` if needed | + +## How to Check + +### PSScriptAnalyzer Rule + +PSScriptAnalyzer has a built-in rule that detects assignments to automatic variables: + +```powershell +# This will trigger PSAvoidAssignmentToAutomaticVariable +$matches = Get-Something +``` + +**Rule ID**: PSAvoidAssignmentToAutomaticVariable + +### Manual Review + +When writing PowerShell code, always: +1. Avoid variable names that match PowerShell keywords or automatic variables +2. Use descriptive, specific names that clearly indicate the variable's purpose +3. Run PSScriptAnalyzer on your code before committing +4. Review code for variable naming during PR reviews + +## Examples from the Codebase + +### Example 1: Regex Matching + +```powershell +# ❌ Bad - Overwrites automatic $matches variable +$matches = [regex]::Matches($content, $pattern) + +# ✅ Good - Uses descriptive name +$regexMatches = [regex]::Matches($content, $pattern) +``` + +### Example 2: Select-String Results + +```powershell +# ❌ Bad - Conflicts with automatic $matches +$matches = Select-String -Path $file -Pattern $pattern + +# ✅ Good - Clear and specific +$matchedLines = Select-String -Path $file -Pattern $pattern +``` + +### Example 3: Collecting Arguments + +```powershell +# ❌ Bad - Conflicts with automatic $args +function Process-Items { + $args = $MyItems + # ... process items +} + +# ✅ Good - Descriptive parameter name +function Process-Items { + [CmdletBinding()] + param( + [Parameter(ValueFromRemainingArguments)] + [string[]]$Items + ) + # ... process items +} +``` + +## References + +- [PowerShell Automatic Variables Documentation](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_automatic_variables) +- [PSScriptAnalyzer Rules](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/docs/Rules/README.md) +- [PowerShell Best Practices](https://learn.microsoft.com/powershell/scripting/developer/cmdlet/strongly-encouraged-development-guidelines) + +## Summary + +**Key Takeaway**: Always use descriptive, specific variable names that clearly indicate their purpose and avoid conflicts with PowerShell's automatic variables. When in doubt, choose a longer, more descriptive name over a short one that might conflict. diff --git a/.github/instructions/powershell-module-organization.instructions.md b/.github/instructions/powershell-module-organization.instructions.md new file mode 100644 index 00000000000..461d19fb5df --- /dev/null +++ b/.github/instructions/powershell-module-organization.instructions.md @@ -0,0 +1,201 @@ +--- +applyTo: + - "tools/ci.psm1" + - "build.psm1" + - "tools/packaging/**/*.psm1" + - ".github/**/*.yml" + - ".github/**/*.yaml" +--- + +# Guidelines for PowerShell Code Organization + +## When to Move Code from YAML to PowerShell Modules + +PowerShell code in GitHub Actions YAML files should be kept minimal. Move code to a module when: + +### Size Threshold +- **More than ~30 lines** of PowerShell in a YAML file step +- **Any use of .NET types** like `[regex]`, `[System.IO.Path]`, etc. +- **Complex logic** requiring multiple nested loops or conditionals +- **Reusable functionality** that might be needed elsewhere + +### Indicators to Move Code +1. Using .NET type accelerators (`[regex]`, `[PSCustomObject]`, etc.) +2. Complex string manipulation or parsing +3. File system operations beyond basic reads/writes +4. Logic that would benefit from unit testing +5. Code that's difficult to read/maintain in YAML format + +## Which Module to Use + +### ci.psm1 (`tools/ci.psm1`) +**Purpose**: CI/CD-specific operations and workflows + +**Use for**: +- Build orchestration (invoking builds, tests, packaging) +- CI environment setup and configuration +- Test execution and result processing +- Artifact handling and publishing +- CI-specific validations and checks +- Environment variable management for CI + +**Examples**: +- `Invoke-CIBuild` - Orchestrates build process +- `Invoke-CITest` - Runs Pester tests +- `Test-MergeConflictMarker` - Validates files for conflicts +- `Set-BuildVariable` - Manages CI variables + +**When NOT to use**: +- Core build operations (use build.psm1) +- Package creation logic (use packaging.psm1) +- Platform-specific build steps + +### build.psm1 (`build.psm1`) +**Purpose**: Core build operations and utilities + +**Use for**: +- Compiling source code +- Resource generation +- Build configuration management +- Core build utilities (New-PSOptions, Get-PSOutput, etc.) +- Bootstrap operations +- Cross-platform build helpers + +**Examples**: +- `Start-PSBuild` - Main build function +- `Start-PSBootstrap` - Bootstrap dependencies +- `New-PSOptions` - Create build configuration +- `Start-ResGen` - Generate resources + +**When NOT to use**: +- CI workflow orchestration (use ci.psm1) +- Package creation (use packaging.psm1) +- Test execution + +### packaging.psm1 (`tools/packaging/packaging.psm1`) +**Purpose**: Package creation and distribution + +**Use for**: +- Creating distribution packages (MSI, RPM, DEB, etc.) +- Package-specific metadata generation +- Package signing operations +- Platform-specific packaging logic + +**Examples**: +- `Start-PSPackage` - Create packages +- `New-MSIPackage` - Create Windows MSI +- `New-DotnetSdkContainerFxdPackage` - Create container packages + +**When NOT to use**: +- Building binaries (use build.psm1) +- Running tests (use ci.psm1) +- General utilities + +## Best Practices + +### Keep YAML Minimal +```yaml +# ❌ Bad - too much logic in YAML +- name: Check files + shell: pwsh + run: | + $files = Get-ChildItem -Recurse + foreach ($file in $files) { + $content = Get-Content $file -Raw + if ($content -match $pattern) { + # ... complex processing ... + } + } + +# ✅ Good - call function from module +- name: Check files + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Test-SomeCondition -Path ${{ github.workspace }} +``` + +### Document Functions +Always include comment-based help for functions: +```powershell +function Test-MyFunction +{ + <# + .SYNOPSIS + Brief description + .DESCRIPTION + Detailed description + .PARAMETER ParameterName + Parameter description + .EXAMPLE + Test-MyFunction -ParameterName Value + #> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string] $ParameterName + ) + # Implementation +} +``` + +### Error Handling +Use proper error handling in modules: +```powershell +try { + # Operation +} +catch { + Write-Error "Detailed error message: $_" + throw +} +``` + +### Verbose Output +Use `Write-Verbose` for debugging information: +```powershell +Write-Verbose "Processing file: $filePath" +``` + +## Module Dependencies + +- **ci.psm1** imports both `build.psm1` and `packaging.psm1` +- **build.psm1** is standalone (minimal dependencies) +- **packaging.psm1** imports `build.psm1` + +When adding new functions, consider these import relationships to avoid circular dependencies. + +## Testing Modules + +Functions in modules should be testable: +```powershell +# Test locally +Import-Module ./tools/ci.psm1 -Force +Test-MyFunction -Parameter Value + +# Can be unit tested with Pester +Describe "Test-MyFunction" { + It "Should return expected result" { + # Test implementation + } +} +``` + +## Migration Checklist + +When moving code from YAML to a module: + +1. ✅ Determine which module is appropriate (ci, build, or packaging) +2. ✅ Create function with proper parameter validation +3. ✅ Add comment-based help documentation +4. ✅ Use `[CmdletBinding()]` for advanced function features +5. ✅ Include error handling +6. ✅ Add verbose output for debugging +7. ✅ Test the function independently +8. ✅ Update YAML to call the new function +9. ✅ Verify the workflow still works end-to-end + +## References + +- PowerShell Advanced Functions: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_functions_advanced +- Comment-Based Help: https://learn.microsoft.com/powershell/scripting/developer/help/writing-help-for-windows-powershell-scripts-and-functions diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 1e018065d39..4146725fbb1 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -67,6 +67,20 @@ jobs: with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + merge_conflict_check: + name: Check for Merge Conflict Markers + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && (startsWith(github.repository_owner, 'azure') || github.repository_owner == 'PowerShell') + permissions: + pull-requests: read + contents: read + steps: + - name: checkout + uses: actions/checkout@v5 + + - name: Check for merge conflict markers + uses: "./.github/actions/infrastructure/merge-conflict-checker" + ci_build: name: Build PowerShell runs-on: ubuntu-latest @@ -162,6 +176,48 @@ jobs: runner_os: ubuntu-latest test_results_artifact_name: testResults-xunit + infrastructure_tests: + name: Infrastructure Tests + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v5 + with: + fetch-depth: 1 + + - name: Install Pester + shell: pwsh + run: | + Import-Module ./tools/ci.psm1 + Install-CIPester + + - name: Run Infrastructure Tests + shell: pwsh + run: | + $testResultsFolder = Join-Path $PWD "testResults" + New-Item -ItemType Directory -Path $testResultsFolder -Force | Out-Null + + $config = New-PesterConfiguration + $config.Run.Path = './test/infrastructure/' + $config.Run.PassThru = $true + $config.TestResult.Enabled = $true + $config.TestResult.OutputFormat = 'NUnitXml' + $config.TestResult.OutputPath = "$testResultsFolder/InfrastructureTests.xml" + $config.Output.Verbosity = 'Detailed' + + $result = Invoke-Pester -Configuration $config + + if ($result.FailedCount -gt 0 -or $result.Result -eq 'Failed') { + throw "Infrastructure tests failed" + } + + - name: Publish Test Results + uses: "./.github/actions/test/process-pester-results" + if: always() + with: + name: "InfrastructureTests" + testResultsFolder: "${{ github.workspace }}/testResults" + ## Temporarily disable the CodeQL analysis on Linux as it doesn't work for .NET SDK 10-rc.2. # analyze: # name: CodeQL Analysis @@ -173,22 +229,6 @@ jobs: # contents: read # security-events: write # with: - # runner_os: ubuntu-latest - - ready_to_merge: - name: Linux ready to merge - needs: - - xunit_tests - - linux_test_elevated_ci - - linux_test_elevated_others - - linux_test_unelevated_ci - - linux_test_unelevated_others - # - analyze - - linux_packaging - if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 - with: - needs_context: ${{ toJson(needs) }} linux_packaging: name: Linux Packaging needs: @@ -203,3 +243,20 @@ jobs: fetch-depth: 0 - name: Linux Packaging uses: "./.github/actions/test/linux-packaging" + + ready_to_merge: + name: Linux ready to merge + needs: + - xunit_tests + - linux_test_elevated_ci + - linux_test_elevated_others + - linux_test_unelevated_ci + - linux_test_unelevated_others + - linux_packaging + - merge_conflict_check + - infrastructure_tests + # - analyze + if: always() + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + with: + needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 92fac143187..85549d04229 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -191,6 +191,14 @@ jobs: $macOSRuntime = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'osx-arm64' } else { 'osx-x64' } Start-PSPackage -Type osxpkg -ReleaseTag $releaseTag -MacOSRuntime $macOSRuntime -SkipReleaseChecks shell: pwsh + + - name: Install Pester + if: success() + run: |- + Import-Module ./tools/ci.psm1 + Install-CIPester + shell: pwsh + - name: Test package contents if: success() run: |- diff --git a/.vsts-ci/templates/nanoserver.yml b/.vsts-ci/templates/nanoserver.yml deleted file mode 100644 index ae9f639b3b2..00000000000 --- a/.vsts-ci/templates/nanoserver.yml +++ /dev/null @@ -1,61 +0,0 @@ -parameters: - vmImage: 'windows-latest' - jobName: 'Nanoserver_Tests' - continueOnError: false - -jobs: - -- job: ${{ parameters.jobName }} - variables: - scriptName: ${{ parameters.scriptName }} - - pool: - vmImage: ${{ parameters.vmImage }} - - displayName: ${{ parameters.jobName }} - - steps: - - script: | - set - displayName: Capture Environment - condition: succeededOrFailed() - - - task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - downloadType: specific - itemPattern: | - build/**/* - downloadPath: '$(System.ArtifactsDirectory)' - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Artifacts Directory' - continueOnError: true - - - pwsh: | - Install-module Pester -Scope CurrentUser -Force -MaximumVersion 4.99 - displayName: 'Install Pester' - continueOnError: true - - - pwsh: | - Import-Module .\tools\ci.psm1 - Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' - $options = (Get-PSOptions) - $path = split-path -path $options.Output - Write-Verbose "Path: '$path'" -Verbose - $rootPath = split-Path -path $path - Expand-Archive -Path '$(System.ArtifactsDirectory)\build\build.zip' -DestinationPath $rootPath -Force - Invoke-Pester -Path ./test/nanoserver -OutputFormat NUnitXml -OutputFile ./test-nanoserver.xml - displayName: Test - condition: succeeded() - - - task: PublishTestResults@2 - condition: succeededOrFailed() - displayName: Publish Nanoserver Test Results **\test*.xml - inputs: - testRunner: NUnit - testResultsFiles: '**\test*.xml' - testRunTitle: nanoserver - mergeTestResults: true - failTaskOnFailedTests: true diff --git a/tools/ci.psm1 b/tools/ci.psm1 index dd59df65292..9090e11a19a 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -228,6 +228,45 @@ function Invoke-CIxUnit } } +# Install Pester module if not already installed with a compatible version +function Install-CIPester +{ + [CmdletBinding()] + param( + [string]$MinimumVersion = '5.0.0', + [string]$MaximumVersion = '5.99.99', + [switch]$Force + ) + + Write-Verbose "Checking for Pester module (required: $MinimumVersion - $MaximumVersion)" -Verbose + + # Check if a compatible version of Pester is already installed + $installedPester = Get-Module -Name Pester -ListAvailable | + Where-Object { $_.Version -ge $MinimumVersion -and $_.Version -le $MaximumVersion } | + Sort-Object -Property Version -Descending | + Select-Object -First 1 + + if ($installedPester -and -not $Force) { + Write-Host "Pester version $($installedPester.Version) is already installed and meets requirements" -ForegroundColor Green + return + } + + if ($Force) { + Write-Host "Installing Pester module (forced)" -ForegroundColor Yellow + } else { + Write-Host "Installing Pester module" -ForegroundColor Yellow + } + + try { + Install-Module -Name Pester -Force -SkipPublisherCheck -MaximumVersion $MaximumVersion -ErrorAction Stop + Write-Host "Successfully installed Pester module" -ForegroundColor Green + } + catch { + Write-Error "Failed to install Pester module: $_" + throw + } +} + # Implement CI 'Test_script' function Invoke-CITest { @@ -621,7 +660,7 @@ function Invoke-CIFinish # Install the latest Pester and import it $maximumPesterVersion = '4.99' - Install-Module Pester -Force -SkipPublisherCheck -MaximumVersion $maximumPesterVersion + Install-CIPester -MinimumVersion '4.0.0' -MaximumVersion $maximumPesterVersion -Force Import-Module Pester -Force -MaximumVersion $maximumPesterVersion $testResultPath = Join-Path -Path $env:TEMP -ChildPath "win-package-$channel-$runtime.xml" @@ -1198,4 +1237,4 @@ $Message if ($filesWithConflicts.Count -gt 0) { throw "Merge conflict markers detected in $($filesWithConflicts.Count) file(s)" } -} \ No newline at end of file +} From b9f8920f04e9811b7620ed7e498021351bb4ecd4 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 8 Dec 2025 15:56:48 -0800 Subject: [PATCH 037/127] [release/v7.6] Update Microsoft.PowerShell.PSResourceGet to v1.2.0-preview5 (#26590) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index d2a49e26d2a..b6e5506e0b0 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + From 6e97a080362073983d9435de2259eb2dc68c12fb Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 10 Dec 2025 11:44:44 -0800 Subject: [PATCH 038/127] [release/v7.6] Separate Store Automation Service Endpoints, Resolve AppID (#26599) --- .pipelines/templates/package-create-msix.yml | 38 ++++++-------- .pipelines/templates/release-MSIX-Publish.yml | 52 ++++++++----------- 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index f3c7ef6fbe8..be2446461cb 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -221,25 +221,13 @@ jobs: Write-Error "SBConfig file not found: $sbConfigPath" exit 1 } - Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" # These variables are used in the next tasks to determine which ServiceEndpoint to use - $ltsValue = $IsLTS.ToString().ToLower() - $stableValue = $IsStable.ToString().ToLower() - $previewValue = $IsPreview.ToString().ToLower() - - Write-Verbose -Verbose "About to set variables:" - Write-Verbose -Verbose " LTS=$ltsValue" - Write-Verbose -Verbose " STABLE=$stableValue" - Write-Verbose -Verbose " PREVIEW=$previewValue" - - Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" - Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" - Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" - - Write-Verbose -Verbose "Variables set successfully" + Write-Host "##vso[task.setvariable variable=LTS]$($IsLTS.ToString().ToLower())" + Write-Host "##vso[task.setvariable variable=STABLE]$($IsStable.ToString().ToLower())" + Write-Host "##vso[task.setvariable variable=PREVIEW]$($IsPreview.ToString().ToLower())" name: UpdateConfigs displayName: Update PDPs and SBConfig.json @@ -251,9 +239,10 @@ jobs: displayName: Debug - Check Variables - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package' + displayName: 'Create StoreBroker Package (Preview)' + condition: eq('$(PREVIEW)', 'true') inputs: - serviceEndpoint: '$(ServiceConnection)' + serviceEndpoint: 'StoreAppPublish-Preview' sbConfigPath: '$(SBConfigPath)' sourceFolder: '$(BundleDir)' contents: '*.msixBundle' @@ -261,10 +250,17 @@ jobs: pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - - pwsh: | - Get-Item -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue | - Copy-Item -Destination "$(ob_outputDirectory)" -Verbose - displayName: Upload Store Failure Log + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Stable/LTS)' + condition: or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true')) + inputs: + serviceEndpoint: 'StoreAppPublish-Stable' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(BundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' condition: failed() - pwsh: | diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 4d3e0cb41c8..1735cd9f710 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -50,7 +50,7 @@ jobs: $middleURL = $matches[1] } - $endURL = $tagString -replace '^v|\.', '' + $endURL = $tagString -replace '^v','' -replace '\.','' $message = "Changelog: https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/$middleURL.md#$endURL" Write-Verbose -Verbose "Release Notes for the Store:" Write-Verbose -Verbose "$message" @@ -73,7 +73,6 @@ jobs: Write-Verbose -Verbose "Channel Selection - LTS: $(LTS), Stable: $(STABLE), Preview: $(PREVIEW)" - # Determine the current channel for logging purposes $currentChannel = if ($IsLTS) { 'LTS' } elseif ($IsStable) { 'Stable' } elseif ($IsPreview) { 'Preview' } @@ -81,17 +80,30 @@ jobs: Write-Error "No valid channel detected" exit 1 } - + + # Assign AppID for Store-Publish Task + $appID = $null + if ($IsLTS) { + $appID = '$(AppID-LTS)' + } + elseif ($IsStable) { + $appID = '$(AppID-Stable)' + } + else { + $appID = '$(AppID-Preview)' + } + + Write-Host "##vso[task.setvariable variable=AppID]$appID" Write-Verbose -Verbose "Selected channel: $currentChannel" Write-Verbose -Verbose "Conditional tasks will handle the publishing based on channel variables" displayName: 'Validate Channel Selection' - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish LTS StoreBroker Package' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['LTS'], 'true')) + displayName: 'Publish StoreBroker Package (Stable/LTS)' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true'))) inputs: - serviceEndpoint: 'StoreAppPublish-Private' - appId: '$(AppID-LTS)' + serviceEndpoint: 'StoreAppPublish-Stable' + appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' @@ -100,32 +112,14 @@ jobs: targetPublishMode: 'Immediate' - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish Stable StoreBroker Package' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['STABLE'], 'true')) + displayName: 'Publish StoreBroker Package (Preview)' + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq('$(PREVIEW)', 'true')) inputs: - serviceEndpoint: 'StoreAppPublish-Private' - appId: '$(AppID-Stable)' + serviceEndpoint: 'StoreAppPublish-Preview' + appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' - - - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 - displayName: 'Publish Preview StoreBroker Package' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) - inputs: - serviceEndpoint: 'StoreAppPublish-Private' - appId: '$(AppID-Preview)' - inputMethod: JsonAndZip - jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' - zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' - numberOfPackagesToKeep: 2 - jsonZipUpdateMetadata: true - targetPublishMode: 'Immediate' - - - pwsh: | - Get-Content -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue - displayName: Upload Store Failure Log - condition: failed() From dcccde9e0ec3bb79c9010ac5c707ac6fb2657641 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 10 Dec 2025 13:15:05 -0800 Subject: [PATCH 039/127] [release/v7.6] [master] Update branch for release (#26600) Co-authored-by: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 2 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../System.Management.Automation.csproj | 12 +- .../BenchmarkDotNet.Extensions.csproj | 6 +- .../ResultsComparer/ResultsComparer.csproj | 6 +- .../nested/Test.Isolated.Nested.csproj | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- test/xUnit/xUnit.tests.csproj | 2 +- tools/cgmanifest.json | 148 +++++++----------- 16 files changed, 82 insertions(+), 122 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 8541f8ba795..267f0bda7d6 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.100-rc.1.25451.107", + "sdkImageVersion": "10.0.100", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 83e6a8b43e0..376af49c07f 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.100-rc.2.25502.107" + "version": "10.0.100" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index cc3760db39f..a338c175f14 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index f5f6fede1af..ef949508346 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index da15fe82350..1f9f342b259 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 228d6360022..45b4d8c0a0a 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 57994fb98f7..87f71daada9 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,19 +16,19 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index bef80519d56..48b4d8ff29c 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 11846f54897..55513901c22 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,12 +32,12 @@ - - - - - - + + + + + + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 74a4cf9e089..2416d128bf5 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -6,12 +6,12 @@ - - + + - + \ No newline at end of file diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 9883c8b2d63..3bcb86355be 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -9,7 +9,7 @@ - - + + - + \ No newline at end of file diff --git a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj index de06b206f37..886b5f11826 100644 --- a/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj +++ b/test/tools/TestAlc/nested/Test.Isolated.Nested.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index d2004ea2fdd..15a6e49864c 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 056f6810c71..1dddf99ba5e 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ - + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 5cb4a1e48d8..0863a23d441 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -30,7 +30,7 @@ all - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 26936804614..d8165298b22 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -86,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -126,7 +126,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -166,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -176,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -186,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -206,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -216,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -226,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -236,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -246,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -256,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -266,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -276,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -286,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -296,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -306,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -316,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -326,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -336,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -356,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -366,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -376,7 +376,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -436,7 +436,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -446,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -456,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -466,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -476,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -486,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -506,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -516,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -526,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -536,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -546,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -556,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -566,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -576,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -586,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -596,17 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "9.0.10" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Private.ServiceModel", - "Version": "4.10.3" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -616,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -626,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -636,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -646,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -656,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -666,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -675,8 +665,8 @@ "Component": { "Type": "nuget", "Nuget": { - "Name": "System.ServiceModel.Duplex", - "Version": "4.10.3" + "Name": "System.ServiceModel.Http", + "Version": "8.1.2" } }, "DevelopmentDependency": false @@ -685,8 +675,8 @@ "Component": { "Type": "nuget", "Nuget": { - "Name": "System.ServiceModel.Http", - "Version": "4.10.3" + "Name": "System.ServiceModel.NetFramingBase", + "Version": "8.1.2" } }, "DevelopmentDependency": false @@ -696,7 +686,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.NetTcp", - "Version": "4.10.3" + "Version": "8.1.2" } }, "DevelopmentDependency": false @@ -706,17 +696,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Primitives", - "Version": "4.10.3" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.ServiceModel.Security", - "Version": "4.10.3" + "Version": "8.1.2" } }, "DevelopmentDependency": false @@ -726,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -736,7 +716,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -746,27 +726,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "9.0.10" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Text.Encoding.CodePages", - "Version": "9.0.10" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "nuget", - "Nuget": { - "Name": "System.Threading.AccessControl", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false @@ -786,7 +746,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "9.0.10" + "Version": "10.0.0" } }, "DevelopmentDependency": false From 826a2d0801455673e4f05d90089883eb3ee0b94f Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 11 Dec 2025 13:39:34 -0800 Subject: [PATCH 040/127] [release/v7.6] Update Microsoft.PowerShell.Native package version (#26607) --- .../System.Management.Automation.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 55513901c22..e929166b20d 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -40,7 +40,7 @@ - + From 9a326b200d7b58cb2bb419f5dd018cbac6b1e90a Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 16 Dec 2025 12:40:31 -0800 Subject: [PATCH 041/127] [release/v7.6] Fix the DSC test by skipping `AfterAll` cleanup if the initial setup in `BeforeAll` failed (#26622) --- .../dsc/dsc.profileresource.Tests.ps1 | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/test/powershell/dsc/dsc.profileresource.Tests.ps1 b/test/powershell/dsc/dsc.profileresource.Tests.ps1 index f361e67ea8e..cb357c7350b 100644 --- a/test/powershell/dsc/dsc.profileresource.Tests.ps1 +++ b/test/powershell/dsc/dsc.profileresource.Tests.ps1 @@ -4,8 +4,10 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { BeforeAll { $DSC_ROOT = $env:DSC_ROOT + $skipCleanup = $false if (-not (Test-Path -Path $DSC_ROOT)) { + $skipCleanup = $true throw "DSC_ROOT environment variable is not set or path does not exist." } @@ -40,6 +42,10 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { New-Item -Path $testProfilePathCurrentUserAllHosts -Value $testProfileContent -Force -ItemType File } AfterAll { + if ($skipCleanup) { + return + } + # Restore original profile $testProfilePathCurrentUserCurrentHost = $PROFILE.CurrentUserCurrentHost if (Test-Path "$TestDrive/currentuser-currenthost-profile.bak") { @@ -118,16 +124,19 @@ Describe "DSC PowerShell Profile Resource Tests" -Tag "CI" { Describe "DSC PowerShell Profile resource elevated tests" -Tag "CI", 'RequireAdminOnWindows', 'RequireSudoOnUnix' { BeforeAll { $DSC_ROOT = $env:DSC_ROOT + $skipCleanup = $false if (-not (Test-Path -Path $DSC_ROOT)) { + $skipCleanup = $true throw "DSC_ROOT environment variable is not set or path does not exist." } Write-Verbose "DSC_ROOT is set to $DSC_ROOT" -Verbose - $pathSeparator = [System.IO.Path]::PathSeparator - $env:PATH += "$pathSeparator$DSC_ROOT" + $originalPath = $env:PATH + $pathSeparator = [System.IO.Path]::PathSeparator + $env:PATH += "$pathSeparator$DSC_ROOT" $env:PATH += "$pathSeparator$PSHome" Write-Verbose "Updated PATH to include DSC_ROOT: $env:PATH" -Verbose @@ -151,11 +160,12 @@ Describe "DSC PowerShell Profile resource elevated tests" -Tag "CI", 'RequireAdm $testProfilePathAllUsersAllHosts = $PROFILE.AllUsersAllHosts Copy-Item -Path $testProfilePathAllUsersAllHosts -Destination "$TestDrive/allusers-allhosts-profile.bak" -Force -ErrorAction SilentlyContinue New-Item -Path $testProfilePathAllUsersAllHosts -Value $testProfileContent -Force -ItemType File - - $originalPath = $env:PATH - $env:PATH += "$pathSeparator$PSHome" } AfterAll { + if ($skipCleanup) { + return + } + $env:PATH = $originalPath $testProfilePathAllUsersCurrentHost = $PROFILE.AllUsersCurrentHost From 911a3ca5d6369e1f42c60bc5bfe1d570ff4d0948 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 17 Dec 2025 17:06:58 -0600 Subject: [PATCH 042/127] Bring release changes from the v7.6.0-preview.6 release (#26626) --- .pipelines/templates/package-create-msix.yml | 7 +- .../templates/packaging/windows/package.yml | 1 + .pipelines/templates/release-MSIX-Publish.yml | 4 +- CHANGELOG/preview.md | 71 + ThirdPartyNotices.txt | 1536 ++++------------- build.psm1 | 22 +- 6 files changed, 416 insertions(+), 1225 deletions(-) diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index be2446461cb..22815c98e11 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -240,7 +240,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Preview)' - condition: eq('$(PREVIEW)', 'true') + condition: eq(variables['PREVIEW'], 'true') inputs: serviceEndpoint: 'StoreAppPublish-Preview' sbConfigPath: '$(SBConfigPath)' @@ -252,7 +252,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Stable/LTS)' - condition: or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true')) + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) inputs: serviceEndpoint: 'StoreAppPublish-Stable' sbConfigPath: '$(SBConfigPath)' @@ -261,7 +261,6 @@ jobs: outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - condition: failed() - pwsh: | $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" @@ -279,4 +278,4 @@ jobs: else { Write-Error "Required files not found in $submissionPackageDir" } - displayName: 'Upload StoreBroker Package' \ No newline at end of file + displayName: 'Upload StoreBroker Package' diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 2d2869867c0..3a4ecacbfce 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -58,6 +58,7 @@ jobs: - template: /.pipelines/templates/cloneToOfficialPath.yml@self parameters: nativePathRoot: '$(Agent.TempDirectory)' + ob_restore_phase: false - template: /.pipelines/templates/rebuild-branch-check.yml@self diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 1735cd9f710..2bf1e130103 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -100,7 +100,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Stable/LTS)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq('$(STABLE)', 'true'), eq('$(LTS)', 'true'))) + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) inputs: serviceEndpoint: 'StoreAppPublish-Stable' appId: '$(AppID)' @@ -113,7 +113,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Preview)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq('$(PREVIEW)', 'true')) + condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) inputs: serviceEndpoint: 'StoreAppPublish-Preview' appId: '$(AppID)' diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index 3648f4cc121..f1c5f566289 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,76 @@ # Preview Changelog +## [7.6.0-preview.6] - 2025-12-11 + +### Engine Updates and Fixes + +- Properly Expand Aliases to their actual ResolvedCommand (#26571) (Thanks @kilasuit!) + +### General Cmdlet Updates and Fixes + +- Update `Microsoft.PowerShell.PSResourceGet` to `v1.2.0-preview5` (#26590) +- Make the experimental feature `PSFeedbackProvider` stable (#26502) +- Fix a regression in the API `CompletionCompleters.CompleteFilename()` that causes null reference exception (#26487) +- Add Delimiter parameter to `Get-Clipboard` (#26572) (Thanks @MartinGC94!) +- Close pipe client handles after creating the child ssh process (#26564) +- Make some experimental features stable (#26490) +- DSC v3 resource for PowerShell Profile (#26447) + +### Tools + +- Add merge conflict marker detection to linux-ci workflow and refactor existing actions to use reusable get-changed-files action (#26530) +- Add reusable get-changed-files action and refactor existing actions (#26529) +- Refactor analyze job to reusable workflow and enable on Windows CI (#26494) + +### Tests + +- Fix merge conflict checker for empty file lists and filter *.cs files (#26556) +- Add markdown link verification for PRs (#26445) + +### Build and Packaging Improvements + +
+ + + +

Expand to see details.

+ +
+ +
    +
  • Fix template path for rebuild branch check in package.yml (#26560)
  • +
  • Update the macos package name for preview releases to match the previous pattern (#26576)
  • +
  • Add rebuild branch support with conditional MSIX signing (#26573)
  • +
  • Update the WCF packages to the latest version that is compatible with v4.10.3 (#26503)
  • +
  • Improve ADO package build and validation across platforms (#26532)
  • +
  • Mirror .NET/runtime ICU version range in PowerShell (#26563) (Thanks @kasperk81!)
  • +
  • Update the macos package name for preview releases to match the previous pattern (#26562)
  • +
  • Fix condition syntax for StoreBroker package tasks in MSIX pipeline (#26561)
  • +
  • Move package validation to package pipeline (#26558)
  • +
  • Optimize/split windows package signing (#26557)
  • +
  • Remove usage of fpm for DEB package generation (#26504)
  • +
  • Add log grouping to build.psm1 for collapsible GitHub Actions logs (#26524)
  • +
  • Replace fpm with native macOS packaging tools (pkgbuild/productbuild) (#26501)
  • +
  • Replace fpm with native rpmbuild for RPM package generation (#26441)
  • +
  • Fix GitHub API rate limit errors in test actions (#26492)
  • +
  • Convert Azure DevOps Linux Packaging pipeline to GitHub Actions workflow (#26493)
  • +
  • Refactor: Centralize xUnit tests into reusable workflow and remove legacy verification (#26488)
  • +
  • Fix build to only enable ready-to-run for the Release configuration (#26481)
  • +
  • Integrate Windows packaging into windows-ci workflow using reusable workflow (#26468)
  • +
  • Update outdated package references (#26471)
  • +
  • GitHub Workflow cleanup (#26439)
  • +
  • Update PSResourceGet package version to preview4 (#26438)
  • +
  • Update PSReadLine to v2.4.5 (#26446)
  • +
  • Add network isolation policy parameter to vPack pipeline (#26444)
  • +
  • Fix a couple more lint errors
  • +
  • Fix lint errors in preview.md
  • +
  • Make MSIX publish stage dependent on SetReleaseTagandContainerName stage
  • +
+ +
+ +[7.6.0-preview.6]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.5...v7.6.0-preview.6 + ## [7.6.0-preview.5] - 2025-09-30 ### Engine Updates and Fixes diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 8abff24592f..0397684ed7a 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -17,7 +17,7 @@ required to debug changes to any libraries licensed under the GNU Lesser General --------------------------------------------------------- -Markdig.Signed 0.42.0 - BSD-2-Clause +Markdig.Signed 0.43.0 - BSD-2-Clause @@ -170,7 +170,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Bcl.AsyncInterfaces 9.0.9 - MIT +Microsoft.Bcl.AsyncInterfaces 10.0.0 - MIT Copyright (c) 2021 @@ -193,7 +193,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -214,7 +214,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -231,30 +230,15 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- @@ -305,7 +289,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 9.0.9 - MIT +Microsoft.Extensions.ObjectPool 10.0.0 - MIT Copyright Jorn Zaefferer @@ -395,7 +379,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Win32.Registry.AccessControl 9.0.9 - MIT +Microsoft.Win32.Registry.AccessControl 10.0.0 - MIT Copyright (c) 2021 @@ -418,7 +402,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -439,7 +423,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -456,36 +439,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -Microsoft.Win32.SystemEvents 9.0.9 - MIT +Microsoft.Win32.SystemEvents 10.0.0 - MIT Copyright (c) 2021 @@ -508,7 +476,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -529,7 +497,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -546,36 +513,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -Microsoft.Windows.Compatibility 9.0.9 - MIT +Microsoft.Windows.Compatibility 10.0.0 - MIT (c) Microsoft Corporation @@ -628,7 +580,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -651,7 +603,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -672,7 +624,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -689,36 +640,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -741,7 +677,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -762,7 +698,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -779,36 +714,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -831,7 +751,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -852,7 +772,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -869,36 +788,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -921,7 +825,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -942,7 +846,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -959,36 +862,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1011,7 +899,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1032,7 +920,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1049,36 +936,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1101,7 +973,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1122,7 +994,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1139,36 +1010,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1191,7 +1047,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1212,7 +1068,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1229,36 +1084,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) +MIT License -Copyright (c) .NET Foundation and Contributors +Copyright (c) -All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1281,7 +1121,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1302,7 +1142,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1319,36 +1158,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1371,7 +1195,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1392,7 +1216,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1409,36 +1232,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1461,7 +1269,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1482,7 +1290,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1499,36 +1306,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1551,7 +1343,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1572,7 +1364,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1589,36 +1380,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1641,7 +1417,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1662,7 +1438,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1679,36 +1454,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1731,7 +1491,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1752,7 +1512,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1769,36 +1528,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1821,7 +1565,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1842,7 +1586,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1859,30 +1602,15 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- @@ -1933,7 +1661,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -1956,7 +1684,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -1977,7 +1705,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -1994,36 +1721,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -2046,7 +1758,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2067,7 +1779,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2084,36 +1795,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 9.0.9 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -2136,7 +1832,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2157,7 +1853,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2174,36 +1869,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) +MIT License -Copyright (c) .NET Foundation and Contributors +Copyright (c) -All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.CodeDom 9.0.9 - MIT +System.CodeDom 10.0.0 - MIT Copyright (c) 2021 @@ -2226,7 +1906,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2247,7 +1927,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2264,36 +1943,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.ComponentModel.Composition 9.0.9 - MIT +System.ComponentModel.Composition 10.0.0 - MIT Copyright (c) 2021 @@ -2316,7 +1980,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2337,7 +2001,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2354,36 +2017,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.ComponentModel.Composition.Registration 9.0.9 - MIT +System.ComponentModel.Composition.Registration 10.0.0 - MIT Copyright (c) 2021 @@ -2406,7 +2054,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2427,7 +2075,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2444,36 +2091,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Configuration.ConfigurationManager 9.0.9 - MIT +System.Configuration.ConfigurationManager 10.0.0 - MIT Copyright (c) 2021 @@ -2496,7 +2128,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2517,7 +2149,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2534,36 +2165,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Data.Odbc 9.0.9 - MIT +System.Data.Odbc 10.0.0 - MIT Copyright (c) 2021 @@ -2586,7 +2202,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2607,7 +2223,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2624,36 +2239,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Data.OleDb 9.0.9 - MIT +System.Data.OleDb 10.0.0 - MIT Copyright (c) 2021 @@ -2676,7 +2276,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2697,7 +2297,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2714,30 +2313,15 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- @@ -2762,7 +2346,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Diagnostics.EventLog 9.0.9 - MIT +System.Diagnostics.EventLog 10.0.0 - MIT Copyright (c) 2021 @@ -2785,7 +2369,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2806,7 +2390,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2823,36 +2406,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 9.0.9 - MIT +System.Diagnostics.PerformanceCounter 10.0.0 - MIT Copyright (c) 2021 @@ -2875,7 +2443,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2896,7 +2464,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -2913,36 +2480,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.DirectoryServices 9.0.9 - MIT +System.DirectoryServices 10.0.0 - MIT Copyright (c) 2021 @@ -2965,7 +2517,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -2986,7 +2538,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3003,36 +2554,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.DirectoryServices.AccountManagement 9.0.9 - MIT +System.DirectoryServices.AccountManagement 10.0.0 - MIT Copyright (c) 2021 @@ -3055,7 +2591,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3076,7 +2612,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3093,36 +2628,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) +MIT License -Copyright (c) .NET Foundation and Contributors +Copyright (c) -All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.DirectoryServices.Protocols 9.0.9 - MIT +System.DirectoryServices.Protocols 10.0.0 - MIT Copyright (c) 2021 @@ -3145,7 +2665,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3166,7 +2686,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3183,36 +2702,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Drawing.Common 9.0.9 - MIT +System.Drawing.Common 10.0.0 - MIT (c) Microsoft Corporation @@ -3247,7 +2751,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 9.0.9 - MIT +System.IO.Packaging 10.0.0 - MIT Copyright (c) 2021 @@ -3270,7 +2774,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3291,7 +2795,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3308,36 +2811,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.IO.Ports 9.0.9 - MIT +System.IO.Ports 10.0.0 - MIT Copyright (c) 2021 @@ -3360,7 +2848,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3381,7 +2869,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3398,36 +2885,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Management 9.0.9 - MIT +System.Management 10.0.0 - MIT Copyright (c) 2021 @@ -3450,7 +2922,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3471,7 +2943,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3488,36 +2959,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Net.Http.WinHttpHandler 9.0.9 - MIT +System.Net.Http.WinHttpHandler 10.0.0 - MIT Copyright (c) 2021 @@ -3540,7 +2996,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3561,7 +3017,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3578,72 +3033,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ---------------------------------------------------------- - ---------------------------------------------------------- - -System.Private.ServiceModel 4.10.3 - MIT - - -(c) Microsoft Corporation -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Reflection.Context 9.0.9 - MIT +System.Reflection.Context 10.0.0 - MIT Copyright (c) 2021 @@ -3666,7 +3070,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3687,7 +3091,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3704,36 +3107,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Runtime.Caching 9.0.9 - MIT +System.Runtime.Caching 10.0.0 - MIT Copyright (c) 2021 @@ -3756,7 +3144,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3777,7 +3165,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3794,36 +3181,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Security.Cryptography.Pkcs 9.0.9 - MIT +System.Security.Cryptography.Pkcs 10.0.0 - MIT Copyright (c) 2021 @@ -3846,7 +3218,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3867,7 +3239,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3884,36 +3255,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 9.0.9 - MIT +System.Security.Cryptography.ProtectedData 10.0.0 - MIT Copyright (c) 2021 @@ -3936,7 +3292,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -3957,7 +3313,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -3974,36 +3329,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Security.Cryptography.Xml 9.0.9 - MIT +System.Security.Cryptography.Xml 10.0.0 - MIT Copyright (c) 2021 @@ -4026,7 +3366,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4047,7 +3387,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4064,36 +3403,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Security.Permissions 9.0.9 - MIT +System.Security.Permissions 10.0.0 - MIT Copyright (c) 2021 @@ -4116,7 +3440,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4137,7 +3461,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4154,113 +3477,26 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ---------------------------------------------------------- - ---------------------------------------------------------- - -System.ServiceModel.Duplex 4.10.3 - MIT - - -(c) Microsoft Corporation -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - ---------------------------------------------------------- - ---------------------------------------------------------- - -System.ServiceModel.Http 4.10.3 - MIT - - -(c) Microsoft Corporation -Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) - -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.ServiceModel.NetTcp 4.10.3 - MIT +System.ServiceModel.Http 8.1.2 - MIT (c) Microsoft Corporation Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) +Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) Provided The MIT License (MIT) @@ -4291,12 +3527,12 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Primitives 4.10.3 - MIT +System.ServiceModel.NetFramingBase 8.1.2 - MIT (c) Microsoft Corporation Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) +Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) Provided The MIT License (MIT) @@ -4327,12 +3563,12 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Security 4.10.3 - MIT +System.ServiceModel.NetTcp 8.1.2 - MIT (c) Microsoft Corporation Copyright (c) .NET Foundation and Contributors -Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) +Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) Provided The MIT License (MIT) @@ -4363,66 +3599,12 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 9.0.9 - MIT +System.ServiceModel.Primitives 8.1.2 - MIT -Copyright (c) 2021 -Copyright (c) Six Labors (c) Microsoft Corporation -Copyright (c) 2022 FormatJS -Copyright (c) Andrew Arnott -Copyright 2019 LLVM Project -Copyright (c) 1998 Microsoft -Copyright 2018 Daniel Lemire -Copyright (c) .NET Foundation -Copyright (c) 2011, Google Inc. -Copyright (c) 2020 Dan Shechter -(c) 1997-2005 Sean Eron Anderson -Copyright (c) 2015 Andrew Gallant -Copyright (c) 2022, Wojciech Mula -Copyright (c) 2017 Yoshifumi Kawai -Copyright (c) 2022, Geoff Langdale -Copyright (c) 2005-2020 Rich Felker -Copyright (c) 2012-2021 Yann Collet -Copyright (c) Microsoft Corporation -Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. -Copyright (c) 2013-2017, Alfred Klomp -Copyright (c) 2018 Nemanja Mijailovic -Copyright 2012 the V8 project authors -Copyright (c) 1999 Lucent Technologies -Copyright (c) 2008-2016, Wojciech Mula -Copyright (c) 2011-2020 Microsoft Corp -Copyright (c) 2015-2017, Wojciech Mula -Copyright (c) 2015-2018, Wojciech Mula -Copyright (c) 2005-2007, Nick Galbreath -Copyright (c) 2015 The Chromium Authors -Copyright (c) 2018 Alexander Chermyanin -Copyright (c) The Internet Society 1997 -Copyright (c) 2004-2006 Intel Corporation -Copyright (c) 2011-2015 Intel Corporation -Copyright (c) 2013-2017, Milosz Krajewski -Copyright (c) 2016-2017, Matthieu Darbois -Copyright (c) The Internet Society (2003) -Copyright (c) .NET Foundation Contributors -(c) 1995-2024 Jean-loup Gailly and Mark Adler -Copyright (c) 2020 Mara Bos Copyright (c) .NET Foundation and Contributors -Copyright (c) 2012 - present, Victor Zverovich -Copyright (c) 2006 Jb Evain (jbevain@gmail.com) -Copyright (c) 2008-2020 Advanced Micro Devices, Inc. -Copyright (c) 2019 Microsoft Corporation, Daan Leijen -Copyright (c) 2011 Novell, Inc (http://www.novell.com) -Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) -Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors -Copyright (c) 2014 Ryan Juckett http://www.ryanjuckett.com -Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. -Portions (c) International Organization for Standardization 1986 -Copyright (c) YEAR W3C(r) (MIT, ERCIM, Keio, Beihang) Disclaimers -Copyright (c) 2015 THL A29 Limited, a Tencent company, and Milo Yip -Copyright (c) 1980, 1986, 1993 The Regents of the University of California -Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California -Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass +Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) Provided The MIT License (MIT) @@ -4453,7 +3635,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceProcess.ServiceController 9.0.9 - MIT +System.ServiceModel.Syndication 10.0.0 - MIT Copyright (c) 2021 @@ -4476,7 +3658,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4497,7 +3679,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4514,36 +3695,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Speech 9.0.9 - MIT +System.ServiceProcess.ServiceController 10.0.0 - MIT Copyright (c) 2021 @@ -4566,7 +3732,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4587,7 +3753,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4604,36 +3769,21 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- --------------------------------------------------------- -System.Threading.AccessControl 9.0.9 - MIT +System.Speech 10.0.0 - MIT Copyright (c) 2021 @@ -4656,7 +3806,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4677,7 +3827,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4694,30 +3843,15 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- @@ -4759,7 +3893,7 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 9.0.9 - MIT +System.Windows.Extensions 10.0.0 - MIT Copyright (c) 2021 @@ -4782,7 +3916,7 @@ Copyright (c) 2005-2020 Rich Felker Copyright (c) 2012-2021 Yann Collet Copyright (c) Microsoft Corporation Copyright (c) 2007 James Newton-King -Copyright (c) 1991-2022 Unicode, Inc. +Copyright (c) 1991-2024 Unicode, Inc. Copyright (c) 2013-2017, Alfred Klomp Copyright (c) 2018 Nemanja Mijailovic Copyright 2012 the V8 project authors @@ -4803,7 +3937,6 @@ Copyright (c) The Internet Society (2003) Copyright (c) .NET Foundation Contributors (c) 1995-2024 Jean-loup Gailly and Mark Adler Copyright (c) 2020 Mara Bos -Copyright (c) .NET Foundation and Contributors Copyright (c) 2012 - present, Victor Zverovich Copyright (c) 2006 Jb Evain (jbevain@gmail.com) Copyright (c) 2008-2020 Advanced Micro Devices, Inc. @@ -4820,30 +3953,15 @@ Copyright (c) 1980, 1986, 1993 The Regents of the University of California Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the University of California Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & Digital Equipment Corporation, Maynard, Mass -The MIT License (MIT) - -Copyright (c) .NET Foundation and Contributors - -All rights reserved. +MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Copyright (c) -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- diff --git a/build.psm1 b/build.psm1 index 83bab7f846c..7640bf5ccf5 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2485,19 +2485,21 @@ function Start-PSBootstrap { Write-LogGroupEnd -Title "Install Windows Dependencies" } - if ($Scenario -eq 'DotNet' -or $Scenario -eq 'Both') { - Write-LogGroupStart -Title "Install .NET SDK" - Write-Log -message "Installing .NET global tools" + # Ensure dotnet is available + Find-Dotnet - # Ensure dotnet is available - Find-Dotnet + if (-not $env:TF_BUILD) { + if ($Scenario -eq 'DotNet' -or $Scenario -eq 'Both') { + Write-LogGroupStart -Title "Install .NET SDK" + Write-Log -message "Installing .NET global tools" - # Install dotnet-format - Write-Verbose -Verbose "Installing dotnet-format global tool" - Start-NativeExecution { - dotnet tool install --global dotnet-format + # Install dotnet-format + Write-Verbose -Verbose "Installing dotnet-format global tool" + Start-NativeExecution { + dotnet tool install --global dotnet-format + } + Write-LogGroupEnd -Title "Install .NET Global Tools" } - Write-LogGroupEnd -Title "Install .NET Global Tools" } if ($env:TF_BUILD) { From 86475e9bb9e53306e7e1fd5667aa529beb8bfb3c Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 21 Jan 2026 11:52:09 -0800 Subject: [PATCH 043/127] [release/v7.6] Fix `$PSDefaultParameterValues` leak causing tests to skip unexpectedly (#26705) --- .../Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 | 3 ++- .../Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 | 3 ++- test/powershell/engine/ETS/CimAdapter.Tests.ps1 | 4 +++- test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 | 2 -- test/powershell/engine/Remoting/SessionOption.Tests.ps1 | 3 ++- test/powershell/engine/Security/FileSignature.Tests.ps1 | 1 + 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 index 82f944612f9..f1937f824a6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Rename-Computer.Tests.ps1 @@ -7,6 +7,7 @@ $DefaultResultValue = 0 try { # set up for testing + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() $PSDefaultParameterValues["it:skip"] = ! $IsWindows Enable-Testhook -testhookName $RenameTesthook # we also set TestStopComputer @@ -73,7 +74,7 @@ try } finally { - $PSDefaultParameterValues.Remove("it:skip") + $global:PSDefaultParameterValues = $originalDefaultParameterValues Disable-Testhook -testhookName $RenameTestHook Disable-Testhook -testhookName TestStopComputer Set-TesthookResult -testhookName $RenameResultName -value 0 diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 index 0e50d7c3603..52938a0b881 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/AclCmdlets.Tests.ps1 @@ -3,6 +3,7 @@ Describe "Acl cmdlets are available and operate properly" -Tag CI { Context "Windows ACL test" { BeforeAll { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() $PSDefaultParameterValues["It:Skip"] = -not $IsWindows } @@ -103,7 +104,7 @@ Describe "Acl cmdlets are available and operate properly" -Tag CI { } AfterAll { - $PSDefaultParameterValues.Remove("It:Skip") + $global:PSDefaultParameterValues = $originalDefaultParameterValues } } } diff --git a/test/powershell/engine/ETS/CimAdapter.Tests.ps1 b/test/powershell/engine/ETS/CimAdapter.Tests.ps1 index 1e71bc28b95..3cfff4bd9e4 100644 --- a/test/powershell/engine/ETS/CimAdapter.Tests.ps1 +++ b/test/powershell/engine/ETS/CimAdapter.Tests.ps1 @@ -3,6 +3,8 @@ Describe "CIM Objects are adapted properly" -Tag @("CI") { BeforeAll { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() + function getIndex { param([string[]]$strings,[string]$pattern) @@ -32,7 +34,7 @@ Describe "CIM Objects are adapted properly" -Tag @("CI") { } } AfterAll { - $PSDefaultParameterValues.Remove("it:pending") + $global:PSDefaultParameterValues = $originalDefaultParameterValues } It "Namespace-qualified Win32_Process is present" -Skip:(!$IsWindows) { diff --git a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 index a5d49b75005..2093eaa7ce5 100644 --- a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 +++ b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 @@ -83,9 +83,7 @@ Describe "JEA session Transcript script test" -Tag @("Feature", 'RequireAdminOnW AfterAll { if ($skipTest) { Pop-DefaultParameterValueStack - return } - Pop-DefaultParameterValueStack } It "Configuration name should be in the transcript header" { diff --git a/test/powershell/engine/Remoting/SessionOption.Tests.ps1 b/test/powershell/engine/Remoting/SessionOption.Tests.ps1 index 1ff51e2a707..e85777e90ba 100644 --- a/test/powershell/engine/Remoting/SessionOption.Tests.ps1 +++ b/test/powershell/engine/Remoting/SessionOption.Tests.ps1 @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. try { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() if ( ! $IsWindows ) { $PSDefaultParameterValues['it:skip'] = $true } @@ -52,5 +53,5 @@ try { } } finally { - $PSDefaultParameterValues.remove("it:skip") + $global:PSDefaultParameterValues = $originalDefaultParameterValues } diff --git a/test/powershell/engine/Security/FileSignature.Tests.ps1 b/test/powershell/engine/Security/FileSignature.Tests.ps1 index 51194903a94..9dd26f98aed 100644 --- a/test/powershell/engine/Security/FileSignature.Tests.ps1 +++ b/test/powershell/engine/Security/FileSignature.Tests.ps1 @@ -89,6 +89,7 @@ Describe "Windows file content signatures" -Tags @('Feature', 'RequireAdminOnWin AfterAll { if ($shouldSkip) { + Pop-DefaultParameterValueStack return } From d02a4ccabf2fb32f13925bf63a2d4b65ee83873e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 21 Jan 2026 11:52:37 -0800 Subject: [PATCH 044/127] [release/v7.6] Update `Get-ChangeLog` to handle backport PRs correctly (#26706) --- tools/releaseTools.psm1 | 113 +++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 26 deletions(-) diff --git a/tools/releaseTools.psm1 b/tools/releaseTools.psm1 index b034e2863dd..99edf93c08a 100644 --- a/tools/releaseTools.psm1 +++ b/tools/releaseTools.psm1 @@ -37,6 +37,7 @@ $Script:powershell_team = @( "dependabot-preview[bot]" "dependabot[bot]" "github-actions[bot]" + "Copilot" "Anam Navied" "Andrew Schwartzmeyer" "Jason Helmick" @@ -46,6 +47,27 @@ $Script:powershell_team = @( "Justin Chung" ) +# The powershell team members GitHub logins. We use them to decide if the original author of a backport PR is from the team. +$script:psteam_logins = @( + 'andyleejordan' + 'TravisEz13' + 'daxian-dbw' + 'adityapatwardhan' + 'SteveL-MSFT' + 'dependabot[bot]' + 'pwshBot' + 'jshigetomi' + 'SeeminglyScience' + 'anamnavi' + 'sdwheeler' + 'Copilot' + 'copilot-swe-agent' + 'app/copilot-swe-agent' + 'StevenBucher98' + 'alerickson' + 'tgauth' +) + # They are very active contributors, so we keep their email-login mappings here to save a few queries to Github. $Script:community_login_map = @{ "darpa@yandex.ru" = "iSazonov" @@ -54,11 +76,6 @@ $Script:community_login_map = @{ "info@powercode-consulting.se" = "powercode" } -# Ignore dependency bumping bot (Dependabot): -$Script:attribution_ignore_list = @( - 'dependabot[bot]@users.noreply.github.com' -) - ############################## #.SYNOPSIS #In the release workflow, the release branch will be merged back to master after the release is done, @@ -262,25 +279,76 @@ function Get-ChangeLog $clExperimental = @() foreach ($commit in $new_commits) { + $commitSubject = $commit.Subject + $prNumber = $commit.PullRequest + Write-Verbose "subject: $commitSubject" Write-Verbose "authorname: $($commit.AuthorName)" - if ($commit.AuthorEmail.EndsWith("@microsoft.com") -or $powershell_team -contains $commit.AuthorName -or $Script:attribution_ignore_list -contains $commit.AuthorEmail) { - $commit.ChangeLogMessage = "- {0}" -f (Get-ChangeLogMessage $commit.Subject) + + try { + $pr = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/PowerShell/PowerShell/pulls/$prNumber" ` + -Headers $header ` + -ErrorAction Stop ` + -Verbose:$false ## Always disable verbose to avoid noise when we debug this function. + } catch { + ## A commit may not have corresponding GitHub PRs. In that case, we will get status code 404 (Not Found). + ## Otherwise, let the error bubble up. + if ($_.Exception.Response.StatusCode -ne 404) { + throw + } + } + + if ($commitSubject -match '^\[release/v\d\.\d\] ') { + ## The commit was from a backport PR. We need to get the real author in this case. + if (-not $pr) { + throw "The commit is from a backport PR (#$prNumber), but the PR cannot be found.`nPR Title: $commitSubject" + } + + $userPattern = 'Triggered by @.+ on behalf of @(.+)' + if ($pr.body -match $userPattern) { + $commit.AuthorGitHubLogin = ($Matches.1).Trim() + Write-Verbose "backport PR. real author login: $($commit.AuthorGitHubLogin)" + } else { + throw "The commit is from a backport PR (#$prNumber), but the PR description failed to match the pattern '$userPattern'. Was the template for backport PRs changed?`nPR Title: $commitSubject" + } + } + + if ($commit.AuthorGitHubLogin) { + if ($script:psteam_logins -contains $commit.AuthorGitHubLogin) { + $commit.ChangeLogMessage = "- {0}" -f (Get-ChangeLogMessage $commitSubject) + } else { + $commit.ChangeLogMessage = ("- {0} (Thanks @{1}!)" -f (Get-ChangeLogMessage $commitSubject), $commit.AuthorGitHubLogin) + $commit.ThankYouMessage = ("@{0}" -f ($commit.AuthorGitHubLogin)) + } + } elseif ($commit.AuthorEmail.EndsWith("@microsoft.com") -or $powershell_team -contains $commit.AuthorName) { + $commit.ChangeLogMessage = "- {0}" -f (Get-ChangeLogMessage $commitSubject) } else { if ($community_login_map.ContainsKey($commit.AuthorEmail)) { $commit.AuthorGitHubLogin = $community_login_map[$commit.AuthorEmail] } else { - $uri = "https://api.github.com/repos/PowerShell/PowerShell/commits/$($commit.Hash)" try{ - $response = Invoke-WebRequest -Uri $uri -Method Get -Headers $header -ErrorAction Ignore - } catch{} + ## Always disable verbose to avoid noise when we debug this function. + $response = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/PowerShell/PowerShell/commits/$($commit.Hash)" ` + -Headers $header ` + -ErrorAction Stop ` + -Verbose:$false + } catch { + ## A commit could be available in ADO only. In that case, we will get status code 422 (UnprocessableEntity). + ## Otherwise, let the error bubble up. + if ($_.Exception.Response.StatusCode -ne 422) { + throw + } + } + if($response) { - $content = ConvertFrom-Json -InputObject $response.Content - $commit.AuthorGitHubLogin = $content.author.login + $commit.AuthorGitHubLogin = $response.author.login $community_login_map[$commit.AuthorEmail] = $commit.AuthorGitHubLogin } } - $commit.ChangeLogMessage = ("- {0} (Thanks @{1}!)" -f (Get-ChangeLogMessage $commit.Subject), $commit.AuthorGitHubLogin) + + $commit.ChangeLogMessage = ("- {0} (Thanks @{1}!)" -f (Get-ChangeLogMessage $commitSubject), $commit.AuthorGitHubLogin) $commit.ThankYouMessage = ("@{0}" -f ($commit.AuthorGitHubLogin)) } @@ -289,16 +357,6 @@ function Get-ChangeLog } ## Get the labels for the PR - try { - $pr = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/PowerShell/pulls/$($commit.PullRequest)" -Headers $header -ErrorAction SilentlyContinue - } - catch { - if ($_.Exception.Response.StatusCode -eq '404') { - $pr = $null - #continue - } - } - if($pr) { $clLabel = $pr.labels | Where-Object { $_.Name -match "^CL-"} @@ -328,7 +386,7 @@ function Get-ChangeLog "CL-Tools" { $clTools += $commit } "CL-Untagged" { $clUntagged += $commit } "CL-NotInBuild" { continue } - Default { throw "unknown tag '$cLabel' for PR: '$($commit.PullRequest)'" } + Default { throw "unknown tag '$cLabel' for PR: '$prNumber'" } } } } @@ -426,6 +484,9 @@ function Get-ChangeLogMessage '^Build\(deps\): ' { return $OriginalMessage.replace($Matches.0,'') } + '^\[release/v\d\.\d\] ' { + return $OriginalMessage.replace($Matches.0,'') + } default { return $OriginalMessage } @@ -867,8 +928,8 @@ function Invoke-PRBackport { ) $continue = $false while(!$continue) { - $input= Read-Host -Prompt ($Message + "`nType 'Yes' to continue 'No' to exit") - switch($input) { + $value = Read-Host -Prompt ($Message + "`nType 'Yes' to continue 'No' to exit") + switch($value) { 'yes' { $continue= $true } From 2a08a3c13722fedf0b81696a63b2e41fb4c8b481 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 21 Jan 2026 11:54:00 -0800 Subject: [PATCH 045/127] [release/v7.6] Remove unused `runCodesignValidationInjection` variable from pipeline templates (#26707) --- .pipelines/templates/compliance/apiscan.yml | 2 -- .pipelines/templates/compliance/generateNotice.yml | 2 -- .pipelines/templates/linux-package-build.yml | 2 -- .pipelines/templates/linux.yml | 4 ---- .pipelines/templates/mac-package-build.yml | 2 -- .pipelines/templates/mac.yml | 2 -- .pipelines/templates/nupkg.yml | 2 -- .pipelines/templates/packaging/windows/package.yml | 2 -- .pipelines/templates/release-symbols.yml | 2 -- .pipelines/templates/release-upload-buildinfo.yml | 2 -- .pipelines/templates/testartifacts.yml | 4 ---- .pipelines/templates/uploadToAzure.yml | 2 -- .pipelines/templates/variable/release-shared.yml | 2 -- .pipelines/templates/windows-hosted-build.yml | 2 -- 14 files changed, 32 deletions(-) diff --git a/.pipelines/templates/compliance/apiscan.yml b/.pipelines/templates/compliance/apiscan.yml index 5809af8e28c..b5a15699026 100644 --- a/.pipelines/templates/compliance/apiscan.yml +++ b/.pipelines/templates/compliance/apiscan.yml @@ -4,8 +4,6 @@ jobs: - job: APIScan variables: - - name: runCodesignValidationInjection - value : false - name: NugetSecurityAnalysisWarningLevel value: none - name: ReleaseTagVar diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 7de316e8b49..0a38ed8f8e6 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -10,8 +10,6 @@ parameters: jobs: - job: generateNotice variables: - - name: runCodesignValidationInjection - value : false - name: NugetSecurityAnalysisWarningLevel value: none - name: ob_outputDirectory diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index bcf332b3778..ea49b9fea5d 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -13,8 +13,6 @@ jobs: type: linux variables: - - name: runCodesignValidationInjection - value: false - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel diff --git a/.pipelines/templates/linux.yml b/.pipelines/templates/linux.yml index aef0b53381f..97b594830b3 100644 --- a/.pipelines/templates/linux.yml +++ b/.pipelines/templates/linux.yml @@ -10,8 +10,6 @@ jobs: pool: type: linux variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO @@ -139,8 +137,6 @@ jobs: pool: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 4e7040d4acc..def866173ac 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -15,8 +15,6 @@ jobs: variables: - name: HOMEBREW_NO_ANALYTICS value: 1 - - name: runCodesignValidationInjection - value: false - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index ff4787b9bcf..1699207c657 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -13,8 +13,6 @@ jobs: variables: - name: HOMEBREW_NO_ANALYTICS value: 1 - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - group: DotNetPrivateBuildAccess diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index 3a2aa4f3172..3558c949402 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -6,8 +6,6 @@ jobs: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: nugetMultiFeedWarnLevel value: none - name: NugetSecurityAnalysisWarningLevel diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 3a4ecacbfce..d163b69eb23 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -9,8 +9,6 @@ jobs: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: ob_sdl_codeSignValidation_enabled value: false # Skip signing validation in build-only stage - name: ob_signing_setup_enabled diff --git a/.pipelines/templates/release-symbols.yml b/.pipelines/templates/release-symbols.yml index 1023dcf5259..a628f4d7127 100644 --- a/.pipelines/templates/release-symbols.yml +++ b/.pipelines/templates/release-symbols.yml @@ -10,8 +10,6 @@ jobs: pool: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index c18c96fc646..e32272c6306 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -14,8 +14,6 @@ jobs: demands: - ImageOverride -equals PSMMS2019-Secure variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO diff --git a/.pipelines/templates/testartifacts.yml b/.pipelines/templates/testartifacts.yml index 751c9d5a53b..3a6bec4a859 100644 --- a/.pipelines/templates/testartifacts.yml +++ b/.pipelines/templates/testartifacts.yml @@ -1,8 +1,6 @@ jobs: - job: build_testartifacts_win variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - group: DotNetPrivateBuildAccess @@ -73,8 +71,6 @@ jobs: - job: build_testartifacts_nonwin variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - group: DotNetPrivateBuildAccess diff --git a/.pipelines/templates/uploadToAzure.yml b/.pipelines/templates/uploadToAzure.yml index 20842de81cc..ce7f26131cc 100644 --- a/.pipelines/templates/uploadToAzure.yml +++ b/.pipelines/templates/uploadToAzure.yml @@ -7,8 +7,6 @@ jobs: variables: - name: ob_sdl_sbom_enabled value: true - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO diff --git a/.pipelines/templates/variable/release-shared.yml b/.pipelines/templates/variable/release-shared.yml index 325f72224f5..70d3dd2df97 100644 --- a/.pipelines/templates/variable/release-shared.yml +++ b/.pipelines/templates/variable/release-shared.yml @@ -17,8 +17,6 @@ variables: value: false - name: ob_sdl_sbom_enabled value: ${{ parameters.SBOM }} - - name: runCodesignValidationInjection - value: false - name: DOTNET_NOLOGO value: 1 - group: 'mscodehub-code-read-akv' diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 44b83ad20aa..83c6b32cdfd 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -10,8 +10,6 @@ jobs: pool: type: windows variables: - - name: runCodesignValidationInjection - value: false - name: NugetSecurityAnalysisWarningLevel value: none - name: DOTNET_NOLOGO From c56b9f6ec408d51020e23d86ec2c04d5db1c6339 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 21 Jan 2026 11:54:31 -0800 Subject: [PATCH 046/127] [release/v7.6] Update `metadata.json` to update the Latest attribute with a better name (#26708) --- .pipelines/templates/channelSelection.yml | 8 ++++---- .pipelines/templates/release-prep-for-ev2.yml | 8 ++++---- .pipelines/templates/release-upload-buildinfo.yml | 4 ++-- tools/metadata.json | 14 +++++++------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.pipelines/templates/channelSelection.yml b/.pipelines/templates/channelSelection.yml index 9dd0f3fb216..d6ddb53256e 100644 --- a/.pipelines/templates/channelSelection.yml +++ b/.pipelines/templates/channelSelection.yml @@ -2,6 +2,10 @@ steps: - pwsh: | # Determine LTS, Preview, or Stable $metadata = Get-Content "$(Build.SourcesDirectory)/PowerShell/tools/metadata.json" -Raw | ConvertFrom-Json + + $LTS = $metadata.LTSRelease.PublishToChannels + $Stable = $metadata.StableRelease.PublishToChannels + $isPreview = '$(OutputReleaseTag.releaseTag)' -match '-' $releaseTag = '$(OutputReleaseTag.releaseTag)' # Rebuild branches should be treated as preview builds @@ -11,10 +15,6 @@ steps: # If you update this regex, also update it in rebuild-branch-check.yml to keep them in sync. $isRebuildBranch = '$(Build.SourceBranch)' -match 'refs/heads/rebuild/.*-rebuild\.' - $LTS = $metadata.LTSRelease.Latest - $Stable = $metadata.StableRelease.Latest - $isPreview = $releaseTag -match '-' - # If this is a rebuild branch, force preview mode and ignore LTS metadata if ($isRebuildBranch) { $IsLTS = $false diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index cf7982cd5e1..e644bece68f 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -33,7 +33,7 @@ stages: - template: release-SetReleaseTagandContainerName.yml parameters: restorePhase: true - + - pwsh: | $packageVersion = '$(OutputReleaseTag.ReleaseTag)'.ToLowerInvariant() -replace '^v','' $vstsCommandString = "vso[task.setvariable variable=packageVersion]$packageVersion" @@ -42,7 +42,7 @@ stages: displayName: Set Package version env: ob_restore_phase: true - + - pwsh: | $branch = 'mirror-target' $gitArgs = "clone", @@ -151,7 +151,7 @@ stages: $metadataHash = @{} $skipPublishValue = '${{ parameters.skipPublish }}' $metadataHash["ReleaseTag"] = '$(OutputReleaseTag.ReleaseTag)' - $metadataHash["LTS"] = $metadata.LTSRelease.Latest + $metadataHash["LTS"] = $metadata.LTSRelease.PublishToChannels $metadataHash["ForProduction"] = $true $metadataHash["SkipPublish"] = [System.Convert]::ToBoolean($skipPublishValue) @@ -222,7 +222,7 @@ stages: files_to_sign: '*.ps1' search_root: '$(repoRoot)/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run' displayName: Sign Run.ps1 - + - pwsh: | # folder to tar must have: Run.ps1, settings.toml, python_dl $srcPath = Join-Path '$(ev2ServiceGroupRootFolder)' -ChildPath 'Shell' diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index e32272c6306..bcb2a43396f 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -56,8 +56,8 @@ jobs: $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) $metadata = Get-Content -LiteralPath "$toolsDirectory/metadata.json" -ErrorAction Stop | ConvertFrom-Json - $stableRelease = $metadata.StableRelease.Latest - $ltsRelease = $metadata.LTSRelease.Latest + $stableRelease = $metadata.StableRelease.PublishToChannels + $ltsRelease = $metadata.LTSRelease.PublishToChannels Write-Verbose -Verbose "Writing $jsonFile contents:" $buildInfoJsonContent = Get-Content $jsonFile -Encoding UTF8NoBom -Raw diff --git a/tools/metadata.json b/tools/metadata.json index 377b6ead763..e0f4952c588 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -1,10 +1,10 @@ { - "StableReleaseTag": "v7.5.3", - "PreviewReleaseTag": "v7.6.0-preview.4", + "StableReleaseTag": "v7.5.4", + "PreviewReleaseTag": "v7.6.0-preview.5", "ServicingReleaseTag": "v7.0.13", - "ReleaseTag": "v7.5.3", - "LTSReleaseTag" : ["v7.4.12"], - "NextReleaseTag": "v7.6.0-preview.5", - "LTSRelease": { "Latest": false, "Package": false }, - "StableRelease": { "Latest": false, "Package": false } + "ReleaseTag": "v7.5.4", + "LTSReleaseTag" : ["v7.4.13"], + "NextReleaseTag": "v7.6.0-preview.6", + "LTSRelease": { "PublishToChannels": false, "Package": false }, + "StableRelease": { "PublishToChannels": false, "Package": false } } From 9f65a8e2384119473519a5a0a1f51eb599aeb34b Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 21 Jan 2026 11:55:08 -0800 Subject: [PATCH 047/127] [release/v7.6] Fix macOS preview package identifier detection to use version string (#26709) --- test/packaging/packaging.tests.ps1 | 67 +++++++++++++++++++++++++++++ tools/packaging/packaging.psm1 | 69 ++++++++++++++++++++++-------- 2 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 test/packaging/packaging.tests.ps1 diff --git a/test/packaging/packaging.tests.ps1 b/test/packaging/packaging.tests.ps1 new file mode 100644 index 00000000000..cc4bbe0d728 --- /dev/null +++ b/test/packaging/packaging.tests.ps1 @@ -0,0 +1,67 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe "Packaging Module Functions" { + BeforeAll { + Import-Module $PSScriptRoot/../../build.psm1 -Force + Import-Module $PSScriptRoot/../../tools/packaging/packaging.psm1 -Force + } + + Context "Test-IsPreview function" { + It "Should return True for preview versions" { + Test-IsPreview -Version "7.6.0-preview.6" | Should -Be $true + Test-IsPreview -Version "7.5.0-rc.1" | Should -Be $true + } + + It "Should return False for stable versions" { + Test-IsPreview -Version "7.6.0" | Should -Be $false + Test-IsPreview -Version "7.5.0" | Should -Be $false + } + + It "Should return False for LTS builds regardless of version string" { + Test-IsPreview -Version "7.6.0-preview.6" -IsLTS | Should -Be $false + Test-IsPreview -Version "7.5.0" -IsLTS | Should -Be $false + } + } + + Context "Get-MacOSPackageIdentifierInfo function (New-MacOSPackage logic)" { + It "Should detect preview builds and return preview identifier" { + $result = Get-MacOSPackageIdentifierInfo -Version "7.6.0-preview.6" -LTS:$false + + $result.IsPreview | Should -Be $true + $result.PackageIdentifier | Should -Be "com.microsoft.powershell-preview" + } + + It "Should detect stable builds and return stable identifier" { + $result = Get-MacOSPackageIdentifierInfo -Version "7.6.0" -LTS:$false + + $result.IsPreview | Should -Be $false + $result.PackageIdentifier | Should -Be "com.microsoft.powershell" + } + + It "Should treat LTS builds as stable even with preview version string" { + $result = Get-MacOSPackageIdentifierInfo -Version "7.4.0-preview.1" -LTS:$true + + $result.IsPreview | Should -Be $false + $result.PackageIdentifier | Should -Be "com.microsoft.powershell" + } + + It "Should NOT use package name for preview detection (bug fix verification)" { + # This test verifies the fix for issue #26673 + # The bug was using ($Name -like '*-preview') which always returned false + # because preview builds use Name="powershell" not "powershell-preview" + + $Version = "7.6.0-preview.6" + $Name = "powershell" # Preview builds use "powershell" not "powershell-preview" + + # The INCORRECT logic (the bug): $Name -like '*-preview' + $incorrectCheck = $Name -like '*-preview' + $incorrectCheck | Should -Be $false -Because "Package name is 'powershell' not 'powershell-preview'" + + # The CORRECT logic (the fix): uses version string + $result = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$false + $result.IsPreview | Should -Be $true -Because "Version string correctly identifies preview" + $result.PackageIdentifier | Should -Be "com.microsoft.powershell-preview" + } + } +} diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 8e4dc9aa1dc..9a9e34ab6de 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1371,6 +1371,7 @@ function New-UnixPackage { AppsFolder = $AppsFolder HostArchitecture = $HostArchitecture CurrentLocation = $CurrentLocation + LTS = $LTS } try { @@ -1515,7 +1516,12 @@ function New-MacOsDistributionPackage # Get package ID if not provided if (-not $PackageIdentifier) { - $PackageIdentifier = Get-MacOSPackageId -IsPreview:$IsPreview.IsPresent + if ($IsPreview.IsPresent) { + $PackageIdentifier = 'com.microsoft.powershell-preview' + } + else { + $PackageIdentifier = 'com.microsoft.powershell' + } } # Minimum OS version @@ -1984,7 +1990,9 @@ function New-MacOSPackage [Parameter(Mandatory)] [string]$HostArchitecture, - [string]$CurrentLocation = (Get-Location) + [string]$CurrentLocation = (Get-Location), + + [switch]$LTS ) Write-Log "Creating macOS package using pkgbuild and productbuild..." @@ -2059,8 +2067,10 @@ function New-MacOSPackage Copy-Item -Path "$AppsFolder/*" -Destination $appsInPkg -Recurse -Force } - # Build the component package using pkgbuild - $pkgIdentifier = Get-MacOSPackageId -IsPreview:($Name -like '*-preview') + # Get package identifier info based on version and LTS flag + $packageInfo = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$LTS + $IsPreview = $packageInfo.IsPreview + $pkgIdentifier = $packageInfo.PackageIdentifier if ($PSCmdlet.ShouldProcess("Build component package with pkgbuild")) { Write-Log "Running pkgbuild to create component package..." @@ -2085,7 +2095,7 @@ function New-MacOSPackage -OutputDirectory $CurrentLocation ` -HostArchitecture $HostArchitecture ` -PackageIdentifier $pkgIdentifier ` - -IsPreview:($Name -like '*-preview') + -IsPreview:$IsPreview return $distributionPackage } @@ -2292,20 +2302,44 @@ function New-ManGzip } } -# Returns the macOS Package Identifier -function Get-MacOSPackageId +<# + .SYNOPSIS + Determines the package identifier and preview status for macOS packages. + .DESCRIPTION + This function determines if a package is a preview build based on the version string + and LTS flag, then returns the appropriate package identifier. + .PARAMETER Version + The version string (e.g., "7.6.0-preview.6" or "7.6.0") + .PARAMETER LTS + Whether this is an LTS build + .OUTPUTS + Hashtable with IsPreview (boolean) and PackageIdentifier (string) properties + .EXAMPLE + Get-MacOSPackageIdentifierInfo -Version "7.6.0-preview.6" -LTS:$false + Returns @{ IsPreview = $true; PackageIdentifier = "com.microsoft.powershell-preview" } +#> +function Get-MacOSPackageIdentifierInfo { param( - [switch] - $IsPreview + [Parameter(Mandatory)] + [string]$Version, + + [switch]$LTS ) - if ($IsPreview.IsPresent) - { - return 'com.microsoft.powershell-preview' + + $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS + + # Determine package identifier based on preview status + if ($IsPreview) { + $PackageIdentifier = 'com.microsoft.powershell-preview' } - else - { - return 'com.microsoft.powershell' + else { + $PackageIdentifier = 'com.microsoft.powershell' + } + + return @{ + IsPreview = $IsPreview + PackageIdentifier = $PackageIdentifier } } @@ -2319,8 +2353,9 @@ function New-MacOSLauncher [switch]$LTS ) - $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS - $packageId = Get-MacOSPackageId -IsPreview:$IsPreview + $packageInfo = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$LTS + $IsPreview = $packageInfo.IsPreview + $packageId = $packageInfo.PackageIdentifier # Define folder for launcher application. $suffix = if ($IsPreview) { "-preview" } elseif ($LTS) { "-lts" } From a86a5df678e4810d557ccdc53a0fcb224410f1ed Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 21 Jan 2026 11:55:37 -0800 Subject: [PATCH 048/127] [release/v7.6] Update `Microsoft.PowerShell.PSResourceGet` version to 1.2.0-rc1 (#26710) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index b6e5506e0b0..cbc47ef200c 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + From e29b66e1fa243b57534efb1bb0470037d29a19e2 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 21 Jan 2026 12:48:44 -0800 Subject: [PATCH 049/127] [release/v7.6] Fix `buildinfo.json` uploading for preview, LTS, and stable releases (#26715) --- .../templates/release-upload-buildinfo.yml | 58 +++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index bcb2a43396f..c470af1fd6e 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -56,6 +56,9 @@ jobs: $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) $metadata = Get-Content -LiteralPath "$toolsDirectory/metadata.json" -ErrorAction Stop | ConvertFrom-Json + $stableReleaseTag = $metadata.StableReleaseTag -Replace 'v','' + + $currentReleaseTag = $buildInfo.ReleaseTag -Replace 'v','' $stableRelease = $metadata.StableRelease.PublishToChannels $ltsRelease = $metadata.LTSRelease.PublishToChannels @@ -65,40 +68,44 @@ jobs: $buildInfo = $buildInfoJsonContent | ConvertFrom-Json $buildInfo.ReleaseDate = $dateTime + $currentReleaseTag = $buildInfo.ReleaseTag -Replace 'v','' $targetFile = "$ENV:PIPELINE_WORKSPACE/$fileName" ConvertTo-Json -InputObject $buildInfo | Out-File $targetFile -Encoding ascii - if ($stableRelease -or $fileName -eq "preview.json") { - Set-BuildVariable -Name CopyMainBuildInfo -Value YES + if ($fileName -eq "preview.json") { + Set-BuildVariable -Name UploadPreview -Value YES } else { - Set-BuildVariable -Name CopyMainBuildInfo -Value NO + Set-BuildVariable -Name UploadPreview -Value NO } - Set-BuildVariable -Name BuildInfoJsonFile -Value $targetFile - - ## Create 'lts.json' if it's the latest stable and also a LTS release. + Set-BuildVariable -Name PreviewBuildInfoFile -Value $targetFile + ## Create 'lts.json' if marked as a LTS release. if ($fileName -eq "stable.json") { + [System.Management.Automation.SemanticVersion] $stableVersion = $stableReleaseTag + [System.Management.Automation.SemanticVersion] $currentVersion = $currentReleaseTag if ($ltsRelease) { $ltsFile = "$ENV:PIPELINE_WORKSPACE/lts.json" Copy-Item -Path $targetFile -Destination $ltsFile -Force - Set-BuildVariable -Name LtsBuildInfoJsonFile -Value $ltsFile - Set-BuildVariable -Name CopyLTSBuildInfo -Value YES + Set-BuildVariable -Name LTSBuildInfoFile -Value $ltsFile + Set-BuildVariable -Name UploadLTS -Value YES } else { - Set-BuildVariable -Name CopyLTSBuildInfo -Value NO + Set-BuildVariable -Name UploadLTS -Value NO } - $releaseTag = $buildInfo.ReleaseTag - $version = $releaseTag -replace '^v' - $semVersion = [System.Management.Automation.SemanticVersion] $version + ## Only update the stable.json if the current version is greater than the stable version. + if ($currentVersion -gt $stableVersion) { + $versionFile = "$ENV:PIPELINE_WORKSPACE/$($currentVersion.Major)-$($currentVersion.Minor).json" + Copy-Item -Path $targetFile -Destination $versionFile -Force + Set-BuildVariable -Name StableBuildInfoFile -Value $versionFile + Set-BuildVariable -Name UploadStable -Value YES + } else { + Set-BuildVariable -Name UploadStable -Value NO + } - $versionFile = "$ENV:PIPELINE_WORKSPACE/$($semVersion.Major)-$($semVersion.Minor).json" - Copy-Item -Path $targetFile -Destination $versionFile -Force - Set-BuildVariable -Name VersionBuildInfoJsonFile -Value $versionFile - Set-BuildVariable -Name CopyVersionBuildInfo -Value YES } else { - Set-BuildVariable -Name CopyVersionBuildInfo -Value NO + Set-BuildVariable -Name UploadStable -Value NO } displayName: Create json files @@ -116,24 +123,27 @@ jobs: $storageContext = New-AzStorageContext -StorageAccountName $storageAccount -UseConnectedAccount - if ($env:CopyMainBuildInfo -eq 'YES') { - $jsonFile = "$env:BuildInfoJsonFile" + #preview + if ($env:UploadPreview -eq 'YES') { + $jsonFile = "$env:PreviewBuildInfoFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - if ($env:CopyLTSBuildInfo -eq 'YES') { - $jsonFile = "$env:LtsBuildInfoJsonFile" + #LTS + if ($env:UploadLTS -eq 'YES') { + $jsonFile = "$env:LTSBuildInfoFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - if ($env:CopyVersionBuildInfo -eq 'YES') { - $jsonFile = "$env:VersionBuildInfoJsonFile" + #stable + if ($env:UploadStable -eq 'YES') { + $jsonFile = "$env:StableBuildInfoFile" $blobName = Get-Item $jsonFile | Split-Path -Leaf Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - condition: and(succeeded(), eq(variables['CopyMainBuildInfo'], 'YES')) + condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'))) From 9c844308b0c043fa782d528c7496c1883916f632 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 21 Jan 2026 12:49:24 -0800 Subject: [PATCH 050/127] [release/v7.6] Move PowerShell build to depend on .NET SDK 10.0.101 (#26716) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 6 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../PSVersionInfoGenerator.csproj | 2 +- .../System.Management.Automation.csproj | 12 +- .../BenchmarkDotNet.Extensions.csproj | 4 +- .../ResultsComparer/ResultsComparer.csproj | 2 +- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- tools/cgmanifest.json | 108 +++++++++--------- 15 files changed, 80 insertions(+), 80 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 267f0bda7d6..1ae71bf0737 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.100", + "sdkImageVersion": "10.0.101", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 376af49c07f..936a420a573 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.100" + "version": "10.0.101" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index a338c175f14..f63196d3645 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index ef949508346..b2622f0517f 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 1f9f342b259..b99139eb68e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -8,7 +8,7 @@ - + @@ -32,8 +32,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 45b4d8c0a0a..feea5665288 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 87f71daada9..d3446d28c98 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,19 +16,19 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 48b4d8ff29c..178f0473f26 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 1e53a35f966..1099b2a3c11 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index e929166b20d..542fa8526ff 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,12 +32,12 @@ - - - - - - + + + + + + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 2416d128bf5..2e9d13b32bb 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 3bcb86355be..cd2015c85b5 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -9,7 +9,7 @@ - + \ No newline at end of file diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 15a6e49864c..03aa5697267 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 1dddf99ba5e..db2fde85955 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index d8165298b22..efbc103f25e 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -26,7 +26,7 @@ "Type": "nuget", "Nuget": { "Name": "Humanizer.Core", - "Version": "2.14.1" + "Version": "3.0.1" } }, "DevelopmentDependency": false @@ -36,7 +36,7 @@ "Type": "nuget", "Nuget": { "Name": "Json.More.Net", - "Version": "2.1.1" + "Version": "2.2.0" } }, "DevelopmentDependency": false @@ -46,7 +46,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonPointer.Net", - "Version": "5.3.1" + "Version": "6.0.0" } }, "DevelopmentDependency": false @@ -66,7 +66,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "0.43.0" + "Version": "0.44.0" } }, "DevelopmentDependency": false @@ -86,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -106,7 +106,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.CodeAnalysis.Common", - "Version": "4.14.0" + "Version": "5.0.0" } }, "DevelopmentDependency": false @@ -116,7 +116,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.CodeAnalysis.CSharp", - "Version": "4.14.0" + "Version": "5.0.0" } }, "DevelopmentDependency": false @@ -126,7 +126,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -166,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -176,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -186,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -206,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -216,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -226,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -236,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -246,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -256,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -266,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -276,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -286,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -296,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -306,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -316,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -326,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -336,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -356,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -366,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -376,7 +376,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -436,7 +436,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -446,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -456,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -466,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -476,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -486,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -506,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -516,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -526,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -536,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -546,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -556,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -566,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -576,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -586,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -596,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -606,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -616,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -626,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -636,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -646,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -656,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -706,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -716,7 +716,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -726,7 +726,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false @@ -746,7 +746,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.0" + "Version": "10.0.1" } }, "DevelopmentDependency": false From 0a912658a4a4b4059e7de0c84dcc59948f2ea7b1 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 21 Jan 2026 13:31:55 -0800 Subject: [PATCH 051/127] [release/v7.6] Move PowerShell build to depend on .NET SDK 10.0.102 (#26717) --- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 2 +- ...soft.PowerShell.Commands.Management.csproj | 2 +- ...crosoft.PowerShell.Commands.Utility.csproj | 2 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 10 +- .../Microsoft.WSMan.Management.csproj | 2 +- .../System.Management.Automation.csproj | 12 +-- test/tools/TestService/TestService.csproj | 2 +- test/tools/WebListener/WebListener.csproj | 2 +- test/xUnit/xUnit.tests.csproj | 2 +- tools/cgmanifest.json | 102 +++++++++--------- 12 files changed, 71 insertions(+), 71 deletions(-) diff --git a/global.json b/global.json index 936a420a573..c2af57a3fe4 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.101" + "version": "10.0.102" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index f63196d3645..32e0d329886 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index b2622f0517f..7d9d61ede96 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,7 @@ - + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index b99139eb68e..5ee999c2d9c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index feea5665288..78232a2f1af 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index d3446d28c98..161170355e6 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,19 +16,19 @@ - - + + - - + + - + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 178f0473f26..da5ea7ddd04 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 542fa8526ff..9b5e21811cf 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,12 +32,12 @@ - - - - - - + + + + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 03aa5697267..af62ecaacab 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index db2fde85955..cbb01a67da5 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,6 @@ - + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 0863a23d441..6cf26ad718a 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -29,7 +29,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index efbc103f25e..1001370ade7 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -1,5 +1,4 @@ { - "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -46,7 +45,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonPointer.Net", - "Version": "6.0.0" + "Version": "6.0.1" } }, "DevelopmentDependency": false @@ -86,7 +85,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -126,7 +125,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -166,7 +165,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -176,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -186,7 +185,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -206,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -216,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -226,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -236,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -246,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -256,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -266,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -276,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -286,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -296,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -306,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -316,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -326,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -336,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -356,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -366,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -376,7 +375,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -436,7 +435,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -446,7 +445,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -456,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -466,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -476,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -486,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -506,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -516,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -526,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -536,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -546,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -556,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -566,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -576,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -586,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -596,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -606,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -616,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -626,7 +625,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -636,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -646,7 +645,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -656,7 +655,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -706,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -716,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -726,7 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false @@ -746,10 +745,11 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.1" + "Version": "10.0.2" } }, "DevelopmentDependency": false } - ] + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" } From 60ab5bcbdde18336d2435cde75d5a0fe9070b5fb Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 5 Feb 2026 14:02:36 -0800 Subject: [PATCH 052/127] [release/v7.6] Update `Microsoft.PowerShell.Native` package version (#26748) --- .../System.Management.Automation.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 9b5e21811cf..8c77c770a8f 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -40,7 +40,7 @@ - + From 5238377499e23fd7d36d276d3452435204ad6625 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 9 Feb 2026 10:53:59 -0800 Subject: [PATCH 053/127] [release/v7.6] Update Microsoft.PowerShell.PSResourceGet version to 1.2.0-rc3 (#26767) --- src/Modules/PSGalleryModules.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index cbc47ef200c..7008fe6a08d 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + From c04c9b65cf6ae52293607ca17ebdf4eba72fbc89 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:15:28 -0800 Subject: [PATCH 054/127] [release/v7.6] Update branch for release (#26779) --- DotnetRuntimeMetadata.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 3 +- ...soft.PowerShell.Commands.Management.csproj | 3 +- ...crosoft.PowerShell.Commands.Utility.csproj | 3 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 42 +++++-- .../Microsoft.WSMan.Management.csproj | 3 +- .../PSVersionInfoGenerator.csproj | 8 ++ .../System.Management.Automation.csproj | 16 ++- .../BenchmarkDotNet.Extensions.csproj | 3 + .../dotnet-tools/Reporting/Reporting.csproj | 1 + .../ResultsComparer/ResultsComparer.csproj | 2 + test/tools/TestService/TestService.csproj | 28 ++++- test/tools/WebListener/WebListener.csproj | 5 +- test/xUnit/xUnit.tests.csproj | 2 +- tools/cgmanifest.json | 110 +++++++++--------- 16 files changed, 155 insertions(+), 78 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 1ae71bf0737..0d602086a6a 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.101", + "sdkImageVersion": "10.0.102", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 32e0d329886..c94dfdde337 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,8 +7,9 @@ + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 7d9d61ede96..bea446f6293 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,7 +47,8 @@ - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index 5ee999c2d9c..c7cd0b86cf3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -7,6 +7,7 @@ + @@ -33,7 +34,7 @@ - + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 78232a2f1af..6e740281999 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 161170355e6..64fd931f233 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,19 +16,45 @@ - - + + + + + + + + + + + + + + + + - - + + + + + + + + + + - - - + + + + - + + + + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index da5ea7ddd04..168633bbf31 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,10 +7,11 @@ + - + diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 1099b2a3c11..4001869d26c 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -16,5 +16,13 @@ + + + + + + + + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 8c77c770a8f..13ec26b68ed 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,17 +32,21 @@ - - - - - - + + + + + + + + + + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 2e9d13b32bb..1192b7ff00f 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -8,6 +8,9 @@ + + + diff --git a/test/perf/dotnet-tools/Reporting/Reporting.csproj b/test/perf/dotnet-tools/Reporting/Reporting.csproj index b11b5e36ec4..6df1cfb5d87 100644 --- a/test/perf/dotnet-tools/Reporting/Reporting.csproj +++ b/test/perf/dotnet-tools/Reporting/Reporting.csproj @@ -6,6 +6,7 @@ + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index cd2015c85b5..07eb84c5680 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -8,8 +8,10 @@ + + \ No newline at end of file diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index af62ecaacab..663cbe83f5f 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,8 +15,34 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index cbb01a67da5..debbdf1a389 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,6 +7,9 @@ - + + + + diff --git a/test/xUnit/xUnit.tests.csproj b/test/xUnit/xUnit.tests.csproj index 6cf26ad718a..6ce2ee32ceb 100644 --- a/test/xUnit/xUnit.tests.csproj +++ b/test/xUnit/xUnit.tests.csproj @@ -24,7 +24,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tools/cgmanifest.json b/tools/cgmanifest.json index 1001370ade7..0474a86df42 100644 --- a/tools/cgmanifest.json +++ b/tools/cgmanifest.json @@ -25,7 +25,7 @@ "Type": "nuget", "Nuget": { "Name": "Humanizer.Core", - "Version": "3.0.1" + "Version": "2.14.1" } }, "DevelopmentDependency": false @@ -35,7 +35,7 @@ "Type": "nuget", "Nuget": { "Name": "Json.More.Net", - "Version": "2.2.0" + "Version": "2.1.1" } }, "DevelopmentDependency": false @@ -45,7 +45,7 @@ "Type": "nuget", "Nuget": { "Name": "JsonPointer.Net", - "Version": "6.0.1" + "Version": "5.3.1" } }, "DevelopmentDependency": false @@ -85,7 +85,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -125,7 +125,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -165,7 +165,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -175,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -185,7 +185,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -205,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -215,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -225,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -235,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -245,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -255,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -265,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -275,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -285,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -295,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -305,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -315,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -325,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -335,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -355,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -365,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -375,7 +375,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -435,7 +435,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -445,7 +445,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -455,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -465,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -475,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -485,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -505,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -515,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -525,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -535,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -545,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -555,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -565,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -575,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -585,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -595,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -605,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -615,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -625,7 +625,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -635,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -645,7 +645,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -655,7 +655,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -665,7 +665,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Http", - "Version": "8.1.2" + "Version": "10.0.652802" } }, "DevelopmentDependency": false @@ -675,7 +675,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.NetFramingBase", - "Version": "8.1.2" + "Version": "10.0.652802" } }, "DevelopmentDependency": false @@ -685,7 +685,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.NetTcp", - "Version": "8.1.2" + "Version": "10.0.652802" } }, "DevelopmentDependency": false @@ -695,7 +695,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Primitives", - "Version": "8.1.2" + "Version": "10.0.652802" } }, "DevelopmentDependency": false @@ -705,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -715,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -725,7 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false @@ -745,7 +745,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.2" + "Version": "10.0.3" } }, "DevelopmentDependency": false From 8bb4182b02048bd912ea15c1c9945061de6d5b57 Mon Sep 17 00:00:00 2001 From: Travis Plunk Date: Tue, 17 Feb 2026 16:45:03 -0500 Subject: [PATCH 055/127] [release/v7.6] Update the `Update-Help` tests to use `-Force` to remove read-only files (#26787) --- test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index 593a2ee89d7..e871a8d1603 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -215,7 +215,7 @@ function RunUpdateHelpTests It ('Validate Update-Help for module ''{0}'' in {1}' -F $moduleName, [PSCustomObject] $updateScope) -Skip:(!(Test-CanWriteToPsHome) -and $userscope -eq $false) { # Delete the whole help directory - Remove-Item ($moduleHelpPath) -Recurse + Remove-Item ($moduleHelpPath) -Recurse -Force -ErrorAction SilentlyContinue [hashtable] $UICultureParam = $(if ((Get-UICulture).Name -ne $myUICulture) { @{ UICulture = $myUICulture } } else { @{} }) [hashtable] $sourcePathParam = $(if ($useSourcePath) { @{ SourcePath = Join-Path $PSScriptRoot assets } } else { @{} }) From 32f7691b3aef2a103a7ddd1207ec20d2d71c1aef Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 17 Feb 2026 14:26:10 -0800 Subject: [PATCH 056/127] [release/v7.6] Mark flaky Update-Help web tests as pending to unblock CI (#26846) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> --- ...ester-set-itresult-pattern.instructions.md | 198 ++++++++++++++++++ .../engine/Help/UpdatableHelpSystem.Tests.ps1 | 35 +++- 2 files changed, 226 insertions(+), 7 deletions(-) create mode 100644 .github/instructions/pester-set-itresult-pattern.instructions.md diff --git a/.github/instructions/pester-set-itresult-pattern.instructions.md b/.github/instructions/pester-set-itresult-pattern.instructions.md new file mode 100644 index 00000000000..33a73ca081d --- /dev/null +++ b/.github/instructions/pester-set-itresult-pattern.instructions.md @@ -0,0 +1,198 @@ +--- +applyTo: + - "**/*.Tests.ps1" +--- + +# Pester Set-ItResult Pattern for Pending and Skipped Tests + +## Purpose + +This instruction explains when and how to use `Set-ItResult` in Pester tests to mark tests as Pending or Skipped dynamically within test execution. + +## When to Use Set-ItResult + +Use `Set-ItResult` when you need to conditionally mark a test as Pending or Skipped based on runtime conditions that can't be determined at test definition time. + +### Pending vs Skipped + +**Pending**: Use for tests that should be enabled but temporarily can't run due to: +- Intermittent external service failures (network, APIs) +- Known bugs being fixed +- Missing features being implemented +- Environmental issues that are being resolved + +**Skipped**: Use for tests that aren't applicable to the current environment: +- Platform-specific tests running on wrong platform +- Tests requiring specific hardware/configuration not present +- Tests requiring elevated permissions when not available +- Feature-specific tests when feature is disabled + +## Pattern + +### Basic Usage + +```powershell +It "Test description" { + if ($shouldBePending) { + Set-ItResult -Pending -Because "Explanation of why test is pending" + return + } + + if ($shouldBeSkipped) { + Set-ItResult -Skipped -Because "Explanation of why test is skipped" + return + } + + # Test code here +} +``` + +### Important: Always Return After Set-ItResult + +After calling `Set-ItResult`, you **must** return from the test to prevent further execution: + +```powershell +It "Test that checks environment" { + if ($env:SKIP_TESTS -eq 'true') { + Set-ItResult -Skipped -Because "SKIP_TESTS environment variable is set" + return # This is required! + } + + # Test assertions + $result | Should -Be $expected +} +``` + +**Why?** Without `return`, the test continues executing and may fail with errors unrelated to the pending/skipped condition. + +## Examples from the Codebase + +### Example 1: Pending for Intermittent Network Issues + +```powershell +It "Validate Update-Help for module" { + if ($markAsPending) { + Set-ItResult -Pending -Because "Update-Help from the web has intermittent connectivity issues. See issues #2807 and #6541." + return + } + + Update-Help -Module $moduleName -Force + # validation code... +} +``` + +### Example 2: Skipped for Missing Environment + +```powershell +It "Test requires CI environment" { + if (-not $env:CI) { + Set-ItResult -Skipped -Because "Test requires CI environment to safely install Pester" + return + } + + Install-CIPester -ErrorAction Stop +} +``` + +### Example 3: Pending for Platform-Specific Issue + +```powershell +It "Clear-Host works correctly" { + if ($IsARM64) { + Set-ItResult -Pending -Because "ARM64 runs in non-interactively mode and Clear-Host does not work." + return + } + + & { Clear-Host; 'hi' } | Should -BeExactly 'hi' +} +``` + +### Example 4: Skipped for Missing Feature + +```powershell +It "Test ACR authentication" { + if ($env:ACRTESTS -ne 'true') { + Set-ItResult -Skipped -Because "The tests require the ACRTESTS environment variable to be set to 'true' for ACR authentication." + return + } + + $psgetModuleInfo = Find-PSResource -Name $ACRTestModule -Repository $ACRRepositoryName + # test assertions... +} +``` + +## Alternative: Static -Skip and -Pending Parameters + +For conditions that can be determined at test definition time, use the static parameters instead: + +```powershell +# Static skip - condition known at definition time +It "Windows-only test" -Skip:(-not $IsWindows) { + # test code +} + +# Static pending - always pending +It "Test for feature being implemented" -Pending { + # test code that will fail until feature is done +} +``` + +**Use Set-ItResult when**: +- Condition depends on runtime state +- Condition is determined inside a helper function +- Need to check multiple conditions sequentially + +**Use static parameters when**: +- Condition is known at test definition +- Condition doesn't change during test run +- Want Pester to show the condition in test discovery + +## Best Practices + +1. **Always include -Because parameter** with a clear explanation +2. **Always return after Set-ItResult** to prevent further execution +3. **Reference issues or documentation** when relevant (e.g., "See issue #1234") +4. **Be specific in the reason** - explain what's wrong and what's needed +5. **Use Pending sparingly** - it indicates a problem that should be fixed +6. **Prefer Skipped over Pending** when test truly isn't applicable + +## Common Mistakes + +### ❌ Mistake 1: Forgetting to Return + +```powershell +It "Test" { + if ($condition) { + Set-ItResult -Pending -Because "Reason" + # Missing return - test code will still execute! + } + $value | Should -Be $expected # This runs and fails +} +``` + +### ❌ Mistake 2: Vague Reason + +```powershell +Set-ItResult -Pending -Because "Doesn't work" # Too vague +``` + +### ✅ Correct: + +```powershell +It "Test" { + if ($condition) { + Set-ItResult -Pending -Because "Update-Help has intermittent network timeouts. See issue #2807." + return + } + $value | Should -Be $expected +} +``` + +## See Also + +- [Pester Documentation: Set-ItResult](https://pester.dev/docs/commands/Set-ItResult) +- [Pester Documentation: It](https://pester.dev/docs/commands/It) +- Examples in the codebase: + - `test/powershell/Host/ConsoleHost.Tests.ps1` + - `test/infrastructure/ciModule.Tests.ps1` + - `tools/packaging/releaseTests/sbom.tests.ps1` diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index e871a8d1603..6bf82d21af1 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -191,7 +191,8 @@ function RunUpdateHelpTests param ( [string]$tag = "CI", [switch]$useSourcePath, - [switch]$userscope + [switch]$userscope, + [switch]$markAsPending ) foreach ($moduleName in $modulesInBox) @@ -214,8 +215,15 @@ function RunUpdateHelpTests It ('Validate Update-Help for module ''{0}'' in {1}' -F $moduleName, [PSCustomObject] $updateScope) -Skip:(!(Test-CanWriteToPsHome) -and $userscope -eq $false) { + if ($markAsPending) { + Set-ItResult -Pending -Because "Update-Help from the web has intermittent connectivity issues. See issues #2807 and #6541." + return + } + # Delete the whole help directory - Remove-Item ($moduleHelpPath) -Recurse -Force -ErrorAction SilentlyContinue + if ($moduleHelpPath) { + Remove-Item ($moduleHelpPath) -Recurse -Force -ErrorAction SilentlyContinue + } [hashtable] $UICultureParam = $(if ((Get-UICulture).Name -ne $myUICulture) { @{ UICulture = $myUICulture } } else { @{} }) [hashtable] $sourcePathParam = $(if ($useSourcePath) { @{ SourcePath = Join-Path $PSScriptRoot assets } } else { @{} }) @@ -246,8 +254,15 @@ function RunSaveHelpTests { try { - $saveHelpFolder = Join-Path $TestDrive (Get-Random).ToString() - New-Item $saveHelpFolder -Force -ItemType Directory > $null + $saveHelpFolder = if ($TestDrive) { + Join-Path $TestDrive (Get-Random).ToString() + } else { + $null + } + + if ($saveHelpFolder) { + New-Item $saveHelpFolder -Force -ItemType Directory > $null + } ## Save help has intermittent connectivity issues for downloading PackageManagement help content. ## Hence the test has been marked as Pending. @@ -283,7 +298,9 @@ function RunSaveHelpTests } finally { - Remove-Item $saveHelpFolder -Force -ErrorAction SilentlyContinue -Recurse + if ($saveHelpFolder) { + Remove-Item $saveHelpFolder -Force -ErrorAction SilentlyContinue -Recurse + } } } } @@ -316,7 +333,9 @@ Describe "Validate Update-Help from the Web for one PowerShell module." -Tags @( $ProgressPreference = $SavedProgressPreference } - RunUpdateHelpTests -Tag "CI" + ## Update-Help from the web has intermittent connectivity issues that cause CI failures. + ## Tests are marked as Pending to unblock work. See issues #2807 and #6541. + RunUpdateHelpTests -Tag "CI" -MarkAsPending } Describe "Validate Update-Help from the Web for one PowerShell module for user scope." -Tags @('CI', 'RequireAdminOnWindows', 'RequireSudoOnUnix') { @@ -328,7 +347,9 @@ Describe "Validate Update-Help from the Web for one PowerShell module for user s $ProgressPreference = $SavedProgressPreference } - RunUpdateHelpTests -Tag "CI" -UserScope + ## Update-Help from the web has intermittent connectivity issues that cause CI failures. + ## Tests are marked as Pending to unblock work. See issues #2807 and #6541. + RunUpdateHelpTests -Tag "CI" -UserScope -MarkAsPending } Describe "Validate Update-Help from the Web for all PowerShell modules." -Tags @('Feature', 'RequireAdminOnWindows', 'RequireSudoOnUnix') { From d32bbec5935408388fcc6e928d3f1ff06d77edfb Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Tue, 17 Feb 2026 18:03:32 -0500 Subject: [PATCH 057/127] [release/v7.6] Skip the flaky `Update-Help` test for the `PackageManagement` module (#26847) Co-authored-by: Dongbo Wang --- .../engine/Help/UpdatableHelpSystem.Tests.ps1 | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index 6bf82d21af1..155654b3b80 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -215,7 +215,7 @@ function RunUpdateHelpTests It ('Validate Update-Help for module ''{0}'' in {1}' -F $moduleName, [PSCustomObject] $updateScope) -Skip:(!(Test-CanWriteToPsHome) -and $userscope -eq $false) { - if ($markAsPending) { + if ($markAsPending -or ($IsLinux -and $moduleName -eq "PackageManagement")) { Set-ItResult -Pending -Because "Update-Help from the web has intermittent connectivity issues. See issues #2807 and #6541." return } @@ -333,9 +333,7 @@ Describe "Validate Update-Help from the Web for one PowerShell module." -Tags @( $ProgressPreference = $SavedProgressPreference } - ## Update-Help from the web has intermittent connectivity issues that cause CI failures. - ## Tests are marked as Pending to unblock work. See issues #2807 and #6541. - RunUpdateHelpTests -Tag "CI" -MarkAsPending + RunUpdateHelpTests -Tag "CI" } Describe "Validate Update-Help from the Web for one PowerShell module for user scope." -Tags @('CI', 'RequireAdminOnWindows', 'RequireSudoOnUnix') { @@ -347,9 +345,7 @@ Describe "Validate Update-Help from the Web for one PowerShell module for user s $ProgressPreference = $SavedProgressPreference } - ## Update-Help from the web has intermittent connectivity issues that cause CI failures. - ## Tests are marked as Pending to unblock work. See issues #2807 and #6541. - RunUpdateHelpTests -Tag "CI" -UserScope -MarkAsPending + RunUpdateHelpTests -Tag "CI" -UserScope } Describe "Validate Update-Help from the Web for all PowerShell modules." -Tags @('Feature', 'RequireAdminOnWindows', 'RequireSudoOnUnix') { From 9a42b9152f22da557f65e414e0a630403a60ba45 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Thu, 19 Feb 2026 17:41:17 -0500 Subject: [PATCH 058/127] Update CHANGELOG for v7.6.0-rc.1 (#26781) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> --- CHANGELOG/preview.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/CHANGELOG/preview.md b/CHANGELOG/preview.md index f1c5f566289..851640f8cc5 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/preview.md @@ -1,5 +1,39 @@ # Preview Changelog +## [7.6.0-rc.1] - 2026-02-19 + +### Tests + +- Fix `$PSDefaultParameterValues` leak causing tests to skip unexpectedly (#26705) + +### Build and Packaging Improvements + +
+ + + +

Expand to see details.

+ +
+ +
    +
  • Update branch for release (#26779)
  • +
  • Update Microsoft.PowerShell.PSResourceGet version to 1.2.0-rc3 (#26767)
  • +
  • Update Microsoft.PowerShell.Native package version (#26748)
  • +
  • Move PowerShell build to depend on .NET SDK 10.0.102 (#26717)
  • +
  • Fix buildinfo.json uploading for preview, LTS, and stable releases (#26715)
  • +
  • Fix macOS preview package identifier detection to use version string (#26709)
  • +
  • Update metadata.json to update the Latest attribute with a better name (#26708)
  • +
  • Remove unused runCodesignValidationInjection variable from pipeline templates (#26707)
  • +
  • Update Get-ChangeLog to handle backport PRs correctly (#26706)
  • +
  • Bring release changes from the v7.6.0-preview.6 release (#26626)
  • +
  • Fix the DSC test by skipping AfterAll cleanup if the initial setup in BeforeAll failed (#26622)
  • +
+ +
+ +[7.6.0-rc.1]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-preview.6...v7.6.0-rc.1 + ## [7.6.0-preview.6] - 2025-12-11 ### Engine Updates and Fixes From 0a88d498fde1c01322af9e1e551ee8e449106e89 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 23 Feb 2026 15:13:53 -0800 Subject: [PATCH 059/127] [release/v7.6] Correct the package name for .deb and .rpm packages (#26884) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Travis Plunk --- .github/workflows/macos-ci.yml | 3 ++- tools/packaging/packaging.psm1 | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 85549d04229..24fd7c7e407 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -54,6 +54,7 @@ jobs: outputs: source: ${{ steps.filter.outputs.source }} buildModuleChanged: ${{ steps.filter.outputs.buildModuleChanged }} + packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout uses: actions/checkout@v5 @@ -161,7 +162,7 @@ jobs: name: macOS packaging and testing needs: - changes - if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} + if: ${{ needs.changes.outputs.packagingChanged == 'true' }} runs-on: - macos-15-large steps: diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 9a9e34ab6de..4b162a2f500 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -1159,12 +1159,16 @@ function New-UnixPackage { } # Determine if the version is a preview version - # Only LTS packages get a prefix in the name - # Preview versions are identified by the version string itself (e.g., 7.6.0-preview.6) - # Rebuild versions are also identified by the version string (e.g., 7.4.13-rebuild.5) + $IsPreview = Test-IsPreview -Version $Version -IsLTS:$LTS + + # For deb/rpm packages, use the '-lts' and '-preview' channel suffix variants to match existing names on packages.microsoft.com. + # For osxpkg package, only LTS packages get a channel suffix in the name. $Name = if($LTS) { "powershell-lts" } + elseif ($IsPreview -and $Type -ne "osxpkg") { + "powershell-preview" + } else { "powershell" } From b71310621ce714455adf63713d9ab218883debb5 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 24 Feb 2026 11:39:25 -0800 Subject: [PATCH 060/127] [release/v7.6] Exclude .exe packages from publishing to GitHub (#26887) --- .pipelines/templates/release-githubNuget.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index 5f67ce6a9e4..206079c555f 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -35,6 +35,14 @@ jobs: targetType: inline script: | $Path = "$(Pipeline.Workspace)/GitHubPackages" + + # The .exe packages are for Windows Update only and should not be uploaded to GitHub release. + $exefiles = Get-ChildItem -Path $Path -Filter *.exe + if ($exefiles) { + Write-Verbose -Verbose "Remove .exe packages:" + $exefiles | Remove-Item -Force -Verbose + } + $OutputPath = Join-Path $Path 'hashes.sha256' $packages = Get-ChildItem -Path $Path -Include * -Recurse -File $checksums = $packages | From 45e05e9dc87bbf16190690e0aca444284cfc3a19 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 24 Feb 2026 12:59:56 -0800 Subject: [PATCH 061/127] [release/v7.6] Fix `Import-Module.Tests.ps1` to handle Arm32 platform (#26888) --- .../Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 index 6885abe847d..19dc80caf28 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Core/Import-Module.Tests.ps1 @@ -62,6 +62,7 @@ Describe "Import-Module" -Tags "CI" { 'X86' { 'x86' } 'X64' { 'amd64' } 'Arm64' { 'arm' } + 'Arm' { 'arm' } default { throw "Unknown processor architecture" } } New-ModuleManifest -Path "$TestDrive\TestModule.psd1" -ProcessorArchitecture $currentProcessorArchitecture From 1ccd4130b6f64124e08ba5d1bc04d7afdc558adc Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 24 Feb 2026 13:27:36 -0800 Subject: [PATCH 062/127] [release/v7.6] Add version in description and pass store task on failure (#26889) --- .pipelines/templates/release-MSIX-Publish.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index 2bf1e130103..a92c71f826b 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -59,8 +59,15 @@ jobs: $json.listings.'en-us'.baseListing.releaseNotes = $message + # Add PowerShell version to the top of the description + $description = $json.listings.'en-us'.baseListing.description + $version = "$(ReleaseTag)" + $updatedDescription = "Version: $version`n`n$description" + $json.listings.'en-us'.baseListing.description = $updatedDescription + Write-Verbose -Verbose "Updated description: $updatedDescription" + $json | ConvertTo-Json -Depth 100 | Set-Content $jsonPath -Encoding UTF8 - displayName: 'Update Release Notes in JSON' + displayName: 'Add Changelog Link and Version Number to SBJSON' - task: PowerShell@2 inputs: @@ -101,6 +108,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Stable/LTS)' condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) + continueOnError: true inputs: serviceEndpoint: 'StoreAppPublish-Stable' appId: '$(AppID)' @@ -114,6 +122,7 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Preview)' condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) + continueOnError: true inputs: serviceEndpoint: 'StoreAppPublish-Preview' appId: '$(AppID)' From ffe3aa4ee177ed91ccc364fd3dea74270a5b7a74 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 27 Feb 2026 10:32:27 -0800 Subject: [PATCH 063/127] [release/v7.6] Add PMC packages for debian13 and rhel10 (#26917) --- tools/packages.microsoft.com/mapping.json | 42 +++++++++++++++-------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/tools/packages.microsoft.com/mapping.json b/tools/packages.microsoft.com/mapping.json index 682c96d9110..334f6dfdd55 100644 --- a/tools/packages.microsoft.com/mapping.json +++ b/tools/packages.microsoft.com/mapping.json @@ -21,6 +21,13 @@ ], "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.rh.x86_64.rpm" }, + { + "url": "microsoft-rhel10.0-prod", + "distribution": [ + "stable" + ], + "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.rh.x86_64.rpm" + }, { "url": "cbl-mariner-2.0-prod-Microsoft-aarch64", "distribution": [ @@ -99,6 +106,27 @@ ], "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" }, + { + "url": "microsoft-debian-bullseye-prod", + "distribution": [ + "bullseye" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + }, + { + "url": "microsoft-debian-bookworm-prod", + "distribution": [ + "bookworm" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + }, + { + "url": "microsoft-debian-trixie-prod", + "distribution": [ + "trixie" + ], + "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" + }, { "url": "microsoft-ubuntu-bionic-prod", "distribution": [ @@ -133,20 +161,6 @@ "xenial" ], "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" - }, - { - "url": "microsoft-debian-bullseye-prod", - "distribution": [ - "bullseye" - ], - "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" - }, - { - "url": "microsoft-debian-bookworm-prod", - "distribution": [ - "bookworm" - ], - "PackageFormat": "PACKAGE_NAME_POWERSHELL_RELEASE-1.deb_amd64.deb" } ] } From b30abaec354cc467c37ebb86a6b5ca70c639fa9d Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 9 Mar 2026 15:45:23 -0700 Subject: [PATCH 064/127] [release/v7.6] Update PowerShell Profile DSC resource manifests to allow null for content (#26973) --- dsc/pwsh.profile.dsc.resource.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsc/pwsh.profile.dsc.resource.json b/dsc/pwsh.profile.dsc.resource.json index cd18e94eec6..aa5f5c29eee 100644 --- a/dsc/pwsh.profile.dsc.resource.json +++ b/dsc/pwsh.profile.dsc.resource.json @@ -90,7 +90,7 @@ "content": { "title": "Content", "description": "Defines the content of the profile. If you don't specify this property, the resource doesn't manage the file contents. If you specify this property as an empty string, the resource removes all content from the file. If you specify this property as a non-empty string, the resource sets the file contents to the specified string. The resources retains newlines from this property without any modification.", - "type": "string" + "type": [ "string", "null" ] }, "_exist": { "$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json" From f912f2b912da915cc73cc1ff9c9c23ad955184b2 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 9 Mar 2026 16:28:37 -0700 Subject: [PATCH 065/127] [release/v7.6] Fetch latest ICU release version dynamically (#26970) --- tools/packaging/packaging.psm1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 4b162a2f500..14812bac413 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -2152,7 +2152,7 @@ function Get-PackageDependencies # than the build version and we know that older versions just works. # $MinICUVersion = 60 # runtime minimum supported - $BuildICUVersion = 76 # current build version + $BuildICUVersion = Get-IcuLatestRelease $MaxICUVersion = $BuildICUVersion + 30 # headroom if ($Distribution -eq 'deb') { @@ -5812,3 +5812,15 @@ function Test-IsProductFile { return $false } + +# Get major version from latest ICU release (latest: stable version) +function Get-IcuLatestRelease { + $response = Invoke-WebRequest -Uri "https://github.com/unicode-org/icu/releases/latest" + $tagUrl = ($response.Links | Where-Object href -like "*releases/tag/release-*")[0].href + + if ($tagUrl -match 'release-(\d+)\.') { + return [int]$Matches[1] + } + + throw "Unable to determine the latest ICU release version." +} From ccf7ae9d905cce316c15c40d0f2724b0e2f0ad0c Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 9 Mar 2026 16:29:04 -0700 Subject: [PATCH 066/127] [release/v7.6] Fix a preview detection test for the packaging script (#26971) --- test/packaging/packaging.tests.ps1 | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/test/packaging/packaging.tests.ps1 b/test/packaging/packaging.tests.ps1 index cc4bbe0d728..a7d322205bc 100644 --- a/test/packaging/packaging.tests.ps1 +++ b/test/packaging/packaging.tests.ps1 @@ -46,18 +46,15 @@ Describe "Packaging Module Functions" { $result.PackageIdentifier | Should -Be "com.microsoft.powershell" } - It "Should NOT use package name for preview detection (bug fix verification)" { + It "Should NOT use package name for preview detection (bug fix verification) - " -TestCases @( + @{ Version = "7.6.0-preview.6"; Name = "Preview" } + @{ Version = "7.6.0-rc.1"; Name = "RC" } + ) { # This test verifies the fix for issue #26673 # The bug was using ($Name -like '*-preview') which always returned false # because preview builds use Name="powershell" not "powershell-preview" - - $Version = "7.6.0-preview.6" - $Name = "powershell" # Preview builds use "powershell" not "powershell-preview" - - # The INCORRECT logic (the bug): $Name -like '*-preview' - $incorrectCheck = $Name -like '*-preview' - $incorrectCheck | Should -Be $false -Because "Package name is 'powershell' not 'powershell-preview'" - + param($Version) + # The CORRECT logic (the fix): uses version string $result = Get-MacOSPackageIdentifierInfo -Version $Version -LTS:$false $result.IsPreview | Should -Be $true -Because "Version string correctly identifies preview" From ed90130d0f4d8b3a8e40965eb7750cf767809ab0 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 9 Mar 2026 16:29:28 -0700 Subject: [PATCH 067/127] [release/v7.6] Hardcode Official templates (#26972) --- .../PowerShell-Coordinated_Packages-Official.yml | 11 +++-------- .pipelines/PowerShell-Packages-Official.yml | 11 +++-------- .pipelines/PowerShell-Release-Official-Azure.yml | 9 ++------- .pipelines/PowerShell-Release-Official.yml | 11 +++-------- .pipelines/PowerShell-vPack-Official.yml | 9 ++------- 5 files changed, 13 insertions(+), 38 deletions(-) diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index e4de1fe5c21..380c9c5516e 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -29,11 +29,8 @@ parameters: displayName: Debugging - Enable CodeQL and set cadence to 1 hour type: boolean default: false - - name: OfficialBuild - type: boolean - default: false -name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) resources: repositories: @@ -91,8 +88,6 @@ variables: value: true ${{ else }}: value: false - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} # Fix for BinSkim ICU package error in Linux containers - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT value: true @@ -100,10 +95,10 @@ variables: - name: ob_sdl_binskim_enabled value: false - name: ps_official_build - value: ${{ parameters.OfficialBuild }} + value: true extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: customTags: 'ES365AIMigrationTooling' featureFlags: diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index 18ef7b2d14c..a13ef12378a 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -24,14 +24,11 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' - - name: OfficialBuild - type: boolean - default: false - name: disableNetworkIsolation type: boolean default: false -name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -67,8 +64,6 @@ variables: - name: branchCounter value: $[counter(variables['branchCounterKey'], 1)] - group: MSIXSigningProfile - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} - name: disableNetworkIsolation value: ${{ parameters.disableNetworkIsolation }} @@ -89,7 +84,7 @@ resources: ref: refs/heads/main extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: cloudvault: enabled: false @@ -294,7 +289,7 @@ extends: jobs: - template: /.pipelines/templates/package-create-msix.yml@self parameters: - OfficialBuild: ${{ parameters.OfficialBuild }} + OfficialBuild: true - stage: upload displayName: 'Upload' diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index f4c41143b5f..81543420460 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -13,11 +13,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip Signing type: string default: 'NO' - - name: OfficialBuild - type: boolean - default: false -name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -49,8 +46,6 @@ variables: - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - group: PoolNames - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} resources: repositories: @@ -72,7 +67,7 @@ resources: - releases/* extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: featureFlags: WindowsHostVersion: diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index 868d61ebfd0..fa14b9b0acb 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -29,11 +29,8 @@ parameters: # parameters are shown up in ADO UI in a build queue time displayName: Skip MSIX Publish type: boolean default: false - - name: OfficialBuild - type: boolean - default: false -name: release-$(BUILD.SOURCEBRANCHNAME)-prod.${{ parameters.OfficialBuild }}-$(Build.BuildId) +name: release-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -65,10 +62,8 @@ variables: - name: ReleaseTagVar value: ${{ parameters.ReleaseTagVar }} - group: PoolNames - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} - name: releaseEnvironment - value: ${{ iif ( parameters.OfficialBuild, 'Production', 'Test' ) }} + value: 'Production' # Fix for BinSkim ICU package error in Linux containers - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT value: true @@ -97,7 +92,7 @@ resources: - releases/* extends: - template: ${{ variables.templateFile }} + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates parameters: release: category: NonAzure diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index ba70ddb59df..653f9628e72 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -1,9 +1,6 @@ trigger: none parameters: # parameters are shown up in ADO UI in a build queue time -- name: OfficialBuild - type: boolean - default: true - name: 'createVPack' displayName: 'Create and Submit VPack' type: boolean @@ -32,7 +29,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time - Netlock default: "R1" -name: vPack_$(Build.SourceBranchName)_Prod.${{ parameters.OfficialBuild }}_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) +name: vPack_$(Build.SourceBranchName)_Prod.true_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - name: CDP_DEFINITION_BUILD_COUNT @@ -57,8 +54,6 @@ variables: value: ${{ parameters.ReleaseTagVar }} - group: Azure Blob variable group - group: certificate_logical_to_actual # used within signing task - - name: templateFile - value: ${{ iif ( parameters.OfficialBuild, 'v2/Microsoft.Official.yml@onebranchTemplates', 'v2/Microsoft.NonOfficial.yml@onebranchTemplates' ) }} - group: DotNetPrivateBuildAccess - group: certificate_logical_to_actual - name: netiso @@ -74,7 +69,7 @@ resources: ref: refs/heads/main extends: - template: ${{ variables.templateFile }} + template: v2/Microsoft.Official.yml@onebranchTemplates parameters: platform: name: 'windows_undocked' # windows undocked From 762a1a75515f01e7ca5c454509a3fdb2b9d8f24a Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 9 Mar 2026 16:29:56 -0700 Subject: [PATCH 068/127] [release/v7.6] Bump actions/dependency-review-action from 4.8.3 to 4.9.0 (#26974) --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index c0f2e6e0092..5f159650425 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -19,4 +19,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@595b5aeba73380359d98a5e087f648dbb0edce1b # v4.7.3 + uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 From f76a9f1209f9edfdc1d52d94e17e57d202355b86 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 9 Mar 2026 16:30:31 -0700 Subject: [PATCH 069/127] [release/v7.6] Bump github/codeql-action from 4.32.4 to 4.32.6 (#26975) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 10b2f0893a3..a7f9aeb9879 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e94bd11f71e507f7f87df81788dff88d1dacbfb # v3.29.5 + uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 237a05d3479..38bbc07c38c 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5 + uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 with: sarif_file: results.sarif From a573afaaca32470bdfad9e44127353614ba759a8 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 9 Mar 2026 16:46:51 -0700 Subject: [PATCH 070/127] [release/v7.6] Add GitHub Actions annotations for Pester test failures (#26969) --- .../process-pester-results.ps1 | 56 +++++++++++++++++ build.psm1 | 63 +++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/.github/actions/test/process-pester-results/process-pester-results.ps1 b/.github/actions/test/process-pester-results/process-pester-results.ps1 index 523de3bebaa..5804bec9a94 100644 --- a/.github/actions/test/process-pester-results/process-pester-results.ps1 +++ b/.github/actions/test/process-pester-results/process-pester-results.ps1 @@ -24,6 +24,7 @@ $testIgnoredCount = 0 $testSkippedCount = 0 $testInvalidCount = 0 +# Process test results and generate annotations for failures Get-ChildItem -Path "${TestResultsFolder}/*.xml" -Recurse | ForEach-Object { $results = [xml] (get-content $_.FullName) @@ -35,6 +36,61 @@ Get-ChildItem -Path "${TestResultsFolder}/*.xml" -Recurse | ForEach-Object { $testIgnoredCount += [int]$results.'test-results'.ignored $testSkippedCount += [int]$results.'test-results'.skipped $testInvalidCount += [int]$results.'test-results'.invalid + + # Generate GitHub Actions annotations for test failures + # Select failed test cases + if ("System.Xml.XmlDocumentXPathExtensions" -as [Type]) { + $failures = [System.Xml.XmlDocumentXPathExtensions]::SelectNodes($results.'test-results', './/test-case[@result = "Failure"]') + } + else { + $failures = $results.SelectNodes('.//test-case[@result = "Failure"]') + } + + foreach ($testfail in $failures) { + $description = $testfail.description + $testName = $testfail.name + $message = $testfail.failure.message + $stack_trace = $testfail.failure.'stack-trace' + + # Parse stack trace to get file and line info + $fileInfo = Get-PesterFailureFileInfo -StackTraceString $stack_trace + + if ($fileInfo.File) { + # Convert absolute path to relative path for GitHub Actions + $filePath = $fileInfo.File + + # GitHub Actions expects paths relative to the workspace root + if ($env:GITHUB_WORKSPACE) { + $workspacePath = $env:GITHUB_WORKSPACE + if ($filePath.StartsWith($workspacePath)) { + $filePath = $filePath.Substring($workspacePath.Length).TrimStart('/', '\') + # Normalize to forward slashes for consistency + $filePath = $filePath -replace '\\', '/' + } + } + + # Create annotation title + $annotationTitle = "Test Failure: $description / $testName" + + # Build the annotation message + $annotationMessage = $message -replace "`n", "%0A" -replace "`r" + + # Build and output the workflow command + $workflowCommand = "::error file=$filePath" + if ($fileInfo.Line) { + $workflowCommand += ",line=$($fileInfo.Line)" + } + $workflowCommand += ",title=$annotationTitle::$annotationMessage" + + Write-Host $workflowCommand + + # Output a link to the test run + if ($env:GITHUB_SERVER_URL -and $env:GITHUB_REPOSITORY -and $env:GITHUB_RUN_ID) { + $logUrl = "$($env:GITHUB_SERVER_URL)/$($env:GITHUB_REPOSITORY)/actions/runs/$($env:GITHUB_RUN_ID)" + Write-Host "Test logs: $logUrl" + } + } + } } @" diff --git a/build.psm1 b/build.psm1 index 7640bf5ccf5..871526cff0d 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1864,6 +1864,69 @@ $stack_trace } +function Get-PesterFailureFileInfo +{ + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [string]$StackTraceString + ) + + # Parse stack trace to extract file path and line number + # Common patterns: + # "at line: 123 in C:\path\to\file.ps1" (Pester 4) + # "at C:\path\to\file.ps1:123" + # "at , C:\path\to\file.ps1: line 123" + # "at 1 | Should -Be 2, /path/to/file.ps1:123" (Pester 5) + # "at 1 | Should -Be 2, C:\path\to\file.ps1:123" (Pester 5 Windows) + + $result = @{ + File = $null + Line = $null + } + + if ([string]::IsNullOrWhiteSpace($StackTraceString)) { + return $result + } + + # Try pattern: "at line: 123 in " (Pester 4) + if ($StackTraceString -match 'at line:\s*(\d+)\s+in\s+(.+?)(?:\r|\n|$)') { + $result.Line = $matches[1] + $result.File = $matches[2].Trim() + return $result + } + + # Try pattern: ", :123" (Pester 5 format) + # This handles both Unix paths (/path/file.ps1:123) and Windows paths (C:\path\file.ps1:123) + if ($StackTraceString -match ',\s*((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1):(\d+)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result + } + + # Try pattern: "at :123" (without comma) + # Handle both absolute Unix and Windows paths + if ($StackTraceString -match 'at\s+((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):(\d+)(?:\r|\n|$)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result + } + + # Try pattern: ": line 123" + if ($StackTraceString -match '((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):\s*line\s+(\d+)(?:\r|\n|$)') { + $result.File = $matches[1].Trim() + $result.Line = $matches[2] + return $result + } + + # Try to extract just the file path if no line number found + if ($StackTraceString -match '(?:at\s+|in\s+)?((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1)') { + $result.File = $matches[1].Trim() + } + + return $result +} + function Test-XUnitTestResults { param( From dcdb0a5c9083a3cdf5f612e0e5026a3c7d0d2cb7 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 10 Mar 2026 12:06:52 -0700 Subject: [PATCH 071/127] [release/v7.6] Split TPN manifest and Component Governance manifest (#26978) --- .../templates/compliance/generateNotice.yml | 2 +- .vsts-ci/linux-internal.yml | 2 +- .vsts-ci/mac.yml | 2 +- .vsts-ci/psresourceget-acr.yml | 2 +- .vsts-ci/windows-arm64.yml | 2 +- tools/{ => cgmanifest/main}/cgmanifest.json | 0 tools/cgmanifest/tpn/cgmanifest.json | 755 ++++++++++++++++++ tools/clearlyDefined/ClearlyDefined.ps1 | 2 +- .../Find-LastHarvestedVersion.ps1 | 156 ++++ .../src/ClearlyDefined/ClearlyDefined.psm1 | 275 ++++++- tools/findMissingNotices.ps1 | 234 +++++- tools/packaging/packaging.psm1 | 2 +- 12 files changed, 1411 insertions(+), 23 deletions(-) rename tools/{ => cgmanifest/main}/cgmanifest.json (100%) create mode 100644 tools/cgmanifest/tpn/cgmanifest.json create mode 100644 tools/clearlyDefined/Find-LastHarvestedVersion.ps1 diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 0a38ed8f8e6..90fd08dd8d9 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -55,7 +55,7 @@ jobs: - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: 'Component Detection' inputs: - sourceScanPath: '$(repoRoot)\tools' + sourceScanPath: '$(repoRoot)\tools\cgmanifest\tpn' - pwsh: | $(repoRoot)/tools/clearlyDefined/ClearlyDefined.ps1 -TestAndHarvest diff --git a/.vsts-ci/linux-internal.yml b/.vsts-ci/linux-internal.yml index c1c8bcef62d..b90ab0d9eb4 100644 --- a/.vsts-ci/linux-internal.yml +++ b/.vsts-ci/linux-internal.yml @@ -34,7 +34,7 @@ pr: - .vsts-ci/misc-analysis.yml - .vsts-ci/windows.yml - .vsts-ci/windows/* - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/.vsts-ci/mac.yml b/.vsts-ci/mac.yml index 4d3681edca1..678ded65259 100644 --- a/.vsts-ci/mac.yml +++ b/.vsts-ci/mac.yml @@ -34,7 +34,7 @@ pr: - .vsts-ci/misc-analysis.yml - .vsts-ci/windows.yml - .vsts-ci/windows/* - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/.vsts-ci/psresourceget-acr.yml b/.vsts-ci/psresourceget-acr.yml index 194c7ba9f57..225e2699533 100644 --- a/.vsts-ci/psresourceget-acr.yml +++ b/.vsts-ci/psresourceget-acr.yml @@ -34,7 +34,7 @@ pr: - .github/ISSUE_TEMPLATE/* - .github/workflows/* - .vsts-ci/misc-analysis.yml - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/.vsts-ci/windows-arm64.yml b/.vsts-ci/windows-arm64.yml index 4c75c1d31e0..1c4bc2ee8af 100644 --- a/.vsts-ci/windows-arm64.yml +++ b/.vsts-ci/windows-arm64.yml @@ -28,7 +28,7 @@ pr: - .dependabot/config.yml - .github/ISSUE_TEMPLATE/* - .vsts-ci/misc-analysis.yml - - tools/cgmanifest.json + - tools/cgmanifest/* - LICENSE.txt - test/common/markdown/* - test/perf/* diff --git a/tools/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json similarity index 100% rename from tools/cgmanifest.json rename to tools/cgmanifest/main/cgmanifest.json diff --git a/tools/cgmanifest/tpn/cgmanifest.json b/tools/cgmanifest/tpn/cgmanifest.json new file mode 100644 index 00000000000..a0746028a56 --- /dev/null +++ b/tools/cgmanifest/tpn/cgmanifest.json @@ -0,0 +1,755 @@ +{ + "Registrations": [ + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "DotNetAnalyzers.DocumentationAnalyzers.Unstable", + "Version": "1.0.0.59" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "DotNetAnalyzers.DocumentationAnalyzers", + "Version": "1.0.0-beta.59" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Humanizer.Core", + "Version": "2.14.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Json.More.Net", + "Version": "2.1.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "JsonPointer.Net", + "Version": "5.3.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "JsonSchema.Net", + "Version": "7.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Markdig.Signed", + "Version": "0.45.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.ApplicationInsights", + "Version": "2.23.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Bcl.AsyncInterfaces", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.CodeAnalysis.Analyzers", + "Version": "3.11.0" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.CodeAnalysis.Common", + "Version": "5.0.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.CodeAnalysis.CSharp", + "Version": "5.0.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Extensions.ObjectPool", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Management.Infrastructure.Runtime.Win", + "Version": "3.0.0" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.PowerShell.MarkdownRender", + "Version": "7.2.1" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Security.Extensions", + "Version": "1.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Win32.Registry.AccessControl", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Win32.SystemEvents", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Microsoft.Windows.Compatibility", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "Newtonsoft.Json", + "Version": "13.0.4" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-arm.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.android-x86.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.win-arm64.runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.win-x64.runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "runtime.win-x86.runtime.native.System.Data.SqlClient.sni", + "Version": "4.4.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "StyleCop.Analyzers.Unstable", + "Version": "1.2.0.556" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "StyleCop.Analyzers", + "Version": "1.1.118" + } + }, + "DevelopmentDependency": true + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.CodeDom", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ComponentModel.Composition.Registration", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ComponentModel.Composition", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Configuration.ConfigurationManager", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Data.Odbc", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Data.OleDb", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Data.SqlClient", + "Version": "4.9.0" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Diagnostics.EventLog", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Diagnostics.PerformanceCounter", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.DirectoryServices.AccountManagement", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.DirectoryServices.Protocols", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.DirectoryServices", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Drawing.Common", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.IO.Packaging", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.IO.Ports", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Management", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Net.Http.WinHttpHandler", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Reflection.Context", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Runtime.Caching", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Cryptography.Pkcs", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Cryptography.ProtectedData", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Cryptography.Xml", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Security.Permissions", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Http", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.NetFramingBase", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.NetTcp", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Primitives", + "Version": "10.0.652802" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceModel.Syndication", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.ServiceProcess.ServiceController", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Speech", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Web.Services.Description", + "Version": "8.1.2" + } + }, + "DevelopmentDependency": false + }, + { + "Component": { + "Type": "nuget", + "Nuget": { + "Name": "System.Windows.Extensions", + "Version": "10.0.3" + } + }, + "DevelopmentDependency": false + } + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" +} diff --git a/tools/clearlyDefined/ClearlyDefined.ps1 b/tools/clearlyDefined/ClearlyDefined.ps1 index 1830c2969e5..c5303b8622b 100644 --- a/tools/clearlyDefined/ClearlyDefined.ps1 +++ b/tools/clearlyDefined/ClearlyDefined.ps1 @@ -21,7 +21,7 @@ if ($ForceModuleReload) { Import-Module -Name "$PSScriptRoot/src/ClearlyDefined" @extraParams -$cgManfest = Get-Content "$PSScriptRoot/../cgmanifest.json" | ConvertFrom-Json +$cgManfest = Get-Content "$PSScriptRoot/../cgmanifest/main/cgmanifest.json" | ConvertFrom-Json $fullCgList = $cgManfest.Registrations.Component | ForEach-Object { [Pscustomobject]@{ diff --git a/tools/clearlyDefined/Find-LastHarvestedVersion.ps1 b/tools/clearlyDefined/Find-LastHarvestedVersion.ps1 new file mode 100644 index 00000000000..a989a3e1fc4 --- /dev/null +++ b/tools/clearlyDefined/Find-LastHarvestedVersion.ps1 @@ -0,0 +1,156 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<# +.SYNOPSIS + Find the last harvested version of a NuGet package from ClearlyDefined. + +.DESCRIPTION + Searches for the last harvested version of a package by checking versions + backwards from the specified current version. This is useful for reverting + to a known-good harvested version when a newer version hasn't been harvested yet. + +.PARAMETER Name + The NuGet package name to search for. + +.PARAMETER CurrentVersion + The version to start searching backwards from. Version comparison uses semantic versioning. + +.PARAMETER PackageSourceName + The NuGet package source name to use when searching for available versions. + Default is 'findMissingNoticesNugetOrg' if not specified. + +.EXAMPLE + Find-LastHarvestedVersion -Name "Microsoft.Windows.Compatibility" -CurrentVersion "8.0.24" + + # This will return "8.0.22" if that's the last harvested version + +.NOTES + Requires the ClearlyDefined module to be imported: + Import-Module ".\clearlyDefined\src\ClearlyDefined" -Force +#> + +function Find-LastHarvestedVersion { + [CmdletBinding()] + param( + [parameter(Mandatory)] + [string]$Name, + + [parameter(Mandatory)] + [string]$CurrentVersion, + + [string]$PackageSourceName = 'findMissingNoticesNugetOrg' + ) + + try { + Write-Verbose "Finding last harvested version for $Name starting from v$CurrentVersion..." + + # Parse the current version + try { + [System.Management.Automation.SemanticVersion]$currentSemVer = $CurrentVersion + } catch { + [Version]$currentSemVer = $CurrentVersion + } + + # First try the ClearlyDefined search API (more efficient) + try { + Write-Verbose "Searching ClearlyDefined API for versions of $Name (sorted by release date)..." + # Get versions sorted by release date descending (newest first) for efficiency + $versions = Get-ClearlyDefinedPackageVersions -PackageName $Name + + if ($versions -and $versions.Count -gt 0) { + # Results are already sorted by release date newest first + # Filter to versions <= current version + foreach ($versionInfo in $versions) { + try { + $versionObj = [System.Management.Automation.SemanticVersion]$versionInfo.Version + if ($versionObj -le $currentSemVer) { + # Check harvest status + if ($versionInfo.Harvested) { + Write-Verbose "Found harvested version: v$($versionInfo.Version)" + return $versionInfo.Version + } else { + Write-Verbose "v$($versionInfo.Version) - Not harvested, continuing..." + } + } + } catch { + # Skip versions that can't be parsed + } + } + + Write-Verbose "No harvested version found in ClearlyDefined results" + return $null + } + } catch { + Write-Verbose "ClearlyDefined search API failed ($_), falling back to NuGet search..." + } + + # Fallback: Get all available versions from NuGet and check individually + Write-Verbose "Falling back to NuGet source search..." + + # Ensure package source exists + if (!(Get-PackageSource -Name $PackageSourceName -ErrorAction SilentlyContinue)) { + Write-Verbose "Registering package source: $PackageSourceName" + $null = Register-PackageSource -Name $PackageSourceName -Location https://www.nuget.org/api/v2 -ProviderName NuGet + } + + # Get all available versions from NuGet + try { + $allVersions = Find-Package -Name $Name -AllowPrereleaseVersions -source $PackageSourceName -AllVersions -ErrorAction SilentlyContinue | ForEach-Object { + try { + $packageVersion = [System.Management.Automation.SemanticVersion]$_.Version + } catch { + $packageVersion = [Version]$_.Version + } + $_ | Add-Member -Name SemVer -MemberType NoteProperty -Value $packageVersion -PassThru + } | Where-Object { $_.SemVer -le $currentSemVer } | Sort-Object -Property SemVer -Descending | ForEach-Object { $_.Version } + } catch { + Write-Warning "Failed to get versions for $Name : $_" + return $null + } + + if (!$allVersions) { + Write-Verbose "No versions found for $Name" + return $null + } + + # Check each version backwards until we find one that's harvested + foreach ($version in $allVersions) { + $pkg = [PSCustomObject]@{ + type = "nuget" + Name = $Name + PackageVersion = $version + } + + try { + $result = $pkg | Get-ClearlyDefinedData + if ($result -and $result.harvested) { + Write-Verbose "Found harvested version: v$version" + return $version + } else { + Write-Verbose "v$version - Not harvested, continuing..." + } + } catch { + Write-Verbose "Error checking v$version : $_" -Verbose + } + } + + Write-Verbose "No harvested version found for $Name" + return $null + } finally { + Save-ClearlyDefinedCache + } +} + +# If this script is called directly (not sourced), run a test +if ($MyInvocation.InvocationName -eq '.' -or $MyInvocation.Line -like '. "*Find-LastHarvestedVersion*') { + # Script was sourced, just load the function +} else { + # Script was called directly + Write-Host "Testing Find-LastHarvestedVersion function..." + Write-Host "Ensure ClearlyDefined module is loaded first:" + Write-Host ' Import-Module ".\clearlydefined\src\ClearlyDefined" -Force' + Write-Host "" + Write-Host "Example usage:" + Write-Host ' Find-LastHarvestedVersion -Name "Microsoft.Windows.Compatibility" -CurrentVersion "8.0.24"' +} diff --git a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 index 4d874402977..4e3d375dc5a 100644 --- a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 +++ b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 @@ -2,6 +2,9 @@ # Licensed under the MIT License. # Start the collection (known as harvest) of ClearlyDefined data for a package + +$retryIntervalSec = 90 +$maxRetryCount = 5 function Start-ClearlyDefinedHarvest { [CmdletBinding()] param( @@ -27,7 +30,9 @@ function Start-ClearlyDefinedHarvest { $coordinates = Get-ClearlyDefinedCoordinates @PSBoundParameters $body = @{tool='package';coordinates=$coordinates} | convertto-json Write-Verbose $body -Verbose - (Invoke-WebRequest -Method Post -Uri 'https://api.clearlydefined.io/harvest' -Body $body -ContentType 'application/json' -MaximumRetryCount 5 -RetryIntervalSec 60 -Verbose).Content + Start-job -ScriptBlock { + Invoke-WebRequest -Method Post -Uri 'https://api.clearlydefined.io/harvest' -Body $using:body -ContentType 'application/json' -MaximumRetryCount $using:maxRetryCount -RetryIntervalSec $using:retryIntervalSec + } } } @@ -74,6 +79,207 @@ Function Get-ClearlyDefinedCoordinates { # Cache of ClearlyDefined data $cdCache = @{} +function Test-ClearlyDefinedCachePersistenceAllowed { + [CmdletBinding()] + param() + + if ($env:TF_BUILD -or $env:ADO_BUILD_ID -or $env:BUILD_BUILDID) { + return $false + } + + if ($env:GITHUB_ACTIONS -or $env:GITHUB_RUN_ID) { + return $false + } + + return $true +} + +function Get-ClearlyDefinedCachePath { + [CmdletBinding()] + param() + + $tempPath = [System.IO.Path]::GetTempPath() + return (Join-Path -Path $tempPath -ChildPath 'clearlydefined-cache.json') +} + +function Save-ClearlyDefinedCache { + [CmdletBinding()] + param() + + if (-not (Test-ClearlyDefinedCachePersistenceAllowed)) { + Write-Verbose 'Skipping cache persistence for CI environment.' + return + } + + if ($cdCache.Count -eq 0) { + Write-Verbose 'No cache entries to persist.' + return + } + + $cachePath = Get-ClearlyDefinedCachePath + $entries = foreach ($key in $cdCache.Keys) { + [PSCustomObject]@{ + coordinates = $key + data = $cdCache[$key] + } + } + + $cachePayload = @{ + savedAtUtc = (Get-Date).ToUniversalTime() + entries = $entries + } | ConvertTo-Json -Depth 20 + + $cachePayload | Set-Content -Path $cachePath -Encoding UTF8 + Write-Verbose "Persisted cache to $cachePath" +} + +function Import-ClearlyDefinedCache { + [CmdletBinding()] + param() + + if (-not (Test-ClearlyDefinedCachePersistenceAllowed)) { + Write-Verbose 'Skipping cache import for CI environment.' + return + } + + $cachePath = Get-ClearlyDefinedCachePath + if (-not (Test-Path -Path $cachePath)) { + Write-Verbose 'No persisted cache found.' + return + } + + try { + $payload = Get-Content -Path $cachePath -Raw | ConvertFrom-Json + } catch { + Write-Verbose "Failed to read cache file: $cachePath" + return + } + + if (-not $payload.entries) { + Write-Verbose 'Cache file did not contain entries.' + return + } + + foreach ($entry in $payload.entries) { + if (-not $entry.coordinates -or -not $entry.data) { + continue + } + + try { + $entry.data.cachedTime = [datetime]$entry.data.cachedTime + } catch { + continue + } + + $cdCache[$entry.coordinates] = $entry.data + } + + Write-Verbose "Imported $($cdCache.Count) cache entries from $cachePath" +} + +# Search for packages in ClearlyDefined +Function Search-ClearlyDefined { + [CmdletBinding()] + param( + [string]$Type = 'nuget', + [string]$Provider = 'nuget', + [string]$Namespace, + [string]$Name, + [string]$Pattern, + [datetime]$ReleasedAfter, + [datetime]$ReleasedBefore, + [ValidateSet('releaseDate', 'name')] + [string]$Sort, + [switch]$SortDesc + ) + + $queryParams = @() + if ($Type) { $queryParams += "type=$([System.Uri]::EscapeDataString($Type))" } + if ($Provider) { $queryParams += "provider=$([System.Uri]::EscapeDataString($Provider))" } + if ($Namespace) { $queryParams += "namespace=$([System.Uri]::EscapeDataString($Namespace))" } + if ($Name) { $queryParams += "name=$([System.Uri]::EscapeDataString($Name))" } + if ($Pattern) { $queryParams += "pattern=$([System.Uri]::EscapeDataString($Pattern))" } + if ($ReleasedAfter) { $queryParams += "releasedAfter=$($ReleasedAfter.ToString('o'))" } + if ($ReleasedBefore) { $queryParams += "releasedBefore=$($ReleasedBefore.ToString('o'))" } + if ($Sort) { $queryParams += "sort=$([System.Uri]::EscapeDataString($Sort))" } + if ($SortDesc) { $queryParams += "sortDesc=true" } + + $searchUri = "https://api.clearlydefined.io/definitions?" + ($queryParams -join '&') + Write-Verbose "Searching ClearlyDefined: $searchUri" + + try { + $results = Invoke-RestMethod -Uri $searchUri -MaximumRetryCount $maxRetryCount -RetryIntervalSec $retryIntervalSec + return $results + } catch { + if ($retryIntervalSec -lt 300) { + $retryIntervalSec++ + } + + Write-Warning "Failed to search ClearlyDefined: $_" + return $null + } +} + +# Get available versions for a NuGet package with harvest status +Function Get-ClearlyDefinedPackageVersions { + [CmdletBinding()] + param( + [parameter(mandatory = $true)] + [string] + $PackageName, + + [validateset('nuget')] + [string] + $PackageType = 'nuget' + ) + + # Search for all definitions of this package, sorted by release date (newest first) + Write-Verbose "Fetching versions of $PackageName from ClearlyDefined..." + + $results = Search-ClearlyDefined -Type $PackageType -Provider nuget -Name $PackageName -Sort releaseDate -SortDesc + + if (!$results) { + Write-Verbose "No results found for $PackageName" + return @() + } + + # Convert results to version info objects + $versions = @() + + # API returns results in different formats depending on the query + $dataArray = $null + if ($results.data) { + $dataArray = $results.data + } elseif ($results -is [array]) { + $dataArray = $results + } elseif ($results.PSObject.Properties.Count -gt 0) { + # If it's an object with properties, try to extract the actual results + foreach ($prop in $results.PSObject.Properties) { + if ($prop.Value -is [object] -and $prop.Value.revision) { + $dataArray += $prop.Value + } + } + } + + if ($dataArray) { + foreach ($item in $dataArray) { + if ($item.revision) { + $harvested = if ($item.licensed -and $item.licensed.declared) { $true } else { $false } + + $versions += [PSCustomObject]@{ + Name = $item.name + Version = $item.revision + Harvested = $harvested + Licensed = $item.licensed.declared + } + } + } + } + + # Results are already sorted by API, no need to re-sort + return $versions +} + # Get the ClearlyDefined data for a package Function Get-ClearlyDefinedData { [CmdletBinding()] @@ -96,8 +302,9 @@ Function Get-ClearlyDefinedData { ) Begin { - $cacheMinutes = 60 - $cacheCutoff = (get-date).AddMinutes(-$cacheMinutes) + # Different TTLs for different cache types + $harvestedCacheMinutes = 60 # Cache positive results for 60 minutes + $nonHarvestedCacheMinutes = 30 # Cache negative results for 30 minutes (less aggressive) $coordinateList = @() } @@ -111,19 +318,55 @@ Function Get-ClearlyDefinedData { foreach($coordinates in $coordinateList) { Write-Progress -Activity "Getting ClearlyDefined data" -Status "Getting data for $coordinates" -PercentComplete (($completed / $total) * 100) $containsKey = $cdCache.ContainsKey($coordinates) - if ($containsKey -and $cdCache[$coordinates].cachedTime -gt $cacheCutoff) { - Write-Verbose "Returning cached data for $coordinates" - Write-Output $cdCache[$coordinates] - continue + + if ($containsKey) { + $cached = $cdCache[$coordinates] + # Check if cache entry is still valid based on its type + $cacheCutoff = if ($cached.harvestedResult) { + (get-date).AddMinutes(-$harvestedCacheMinutes) + } else { + (get-date).AddMinutes(-$nonHarvestedCacheMinutes) + } + + if ($cached.cachedTime -gt $cacheCutoff) { + Write-Progress -Activity "Getting ClearlyDefined data" -Status "Getting data for $coordinates - cache hit" -PercentComplete (($completed / $total) * 100) + Write-Verbose "Returning cached data for $coordinates (harvested: $($cached.harvestedResult))" + Write-Output $cached + $completed++ + continue + } } - Invoke-RestMethod -Uri "https://api.clearlydefined.io/definitions/$coordinates" -MaximumRetryCount 5 -RetryIntervalSec 60 | ForEach-Object { - [bool] $harvested = if ($_.licensed.declared) { $true } else { $false } - Add-Member -NotePropertyName cachedTime -NotePropertyValue (get-date) -InputObject $_ -PassThru | Add-Member -NotePropertyName harvested -NotePropertyValue $harvested -PassThru - if ($_.harvested) { - Write-Verbose "Caching data for $coordinates" - $cdCache[$coordinates] = $_ + Write-Progress -Activity "Getting ClearlyDefined data" -Status "Getting data for $coordinates - cache miss" -PercentComplete (($completed / $total) * 100) + + try { + Invoke-RestMethod -Uri "https://api.clearlydefined.io/definitions/$coordinates" -MaximumRetryCount $maxRetryCount -RetryIntervalSec $retryIntervalSec | ForEach-Object { + [bool] $harvested = if ($_.licensed.declared) { $true } else { $false } + # Always cache, with harvestedResult property to distinguish for TTL purposes + Add-Member -NotePropertyName cachedTime -NotePropertyValue (get-date) -InputObject $_ -PassThru | + Add-Member -NotePropertyName harvested -NotePropertyValue $harvested -PassThru | + Add-Member -NotePropertyName harvestedResult -NotePropertyValue $harvested -PassThru | + ForEach-Object { + Write-Verbose "Caching data for $coordinates (harvested: $($_.harvested))" + $cdCache[$coordinates] = $_ + Write-Output $_ + } + } + } catch { + if ($retryIntervalSec -lt 300) { + $retryIntervalSec++ + } + + Write-Warning "Failed to get ClearlyDefined data for $coordinates : $_" + # Return a minimal object indicating failure/not harvested so the pipeline continues + $failedResult = [PSCustomObject]@{ + coordinates = $coordinates + harvested = $false + harvestedResult = $false + cachedTime = (get-date) + licensed = @{ declared = $null } } + Write-Output $failedResult } $completed++ } @@ -134,4 +377,10 @@ Export-ModuleMember -Function @( 'Start-ClearlyDefinedHarvest' 'Get-ClearlyDefinedData' 'ConvertFrom-ClearlyDefinedCoordinates' + 'Search-ClearlyDefined' + 'Get-ClearlyDefinedPackageVersions' + 'Save-ClearlyDefinedCache' + 'Import-ClearlyDefinedCache' + 'Test-ClearlyDefinedCachePersistenceAllowed' + 'Get-ClearlyDefinedCachePath' ) diff --git a/tools/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index 42722701d97..456b77df0ba 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -7,12 +7,14 @@ param( [switch] $Fix, - [switch] $IsStable + [switch] $IsStable, + [switch] $ForceHarvestedOnly ) Import-Module dotnet.project.assets Import-Module "$PSScriptRoot\..\.github\workflows\GHWorkflowHelper" -Force . "$PSScriptRoot\..\tools\buildCommon\startNativeExecution.ps1" +. "$PSScriptRoot\clearlyDefined\Find-LastHarvestedVersion.ps1" $packageSourceName = 'findMissingNoticesNugetOrg' if (!(Get-PackageSource -Name $packageSourceName -ErrorAction SilentlyContinue)) { @@ -20,7 +22,7 @@ if (!(Get-PackageSource -Name $packageSourceName -ErrorAction SilentlyContinue)) } $existingRegistrationTable = @{} -$cgManifestPath = (Resolve-Path -Path $PSScriptRoot\..\tools\cgmanifest.json).ProviderPath +$cgManifestPath = (Resolve-Path -Path $PSScriptRoot\cgmanifest\main\cgmanifest.json).ProviderPath $existingRegistrationsJson = Get-Content $cgManifestPath | ConvertFrom-Json -AsHashtable $existingRegistrationsJson.Registrations | ForEach-Object { $registration = [Registration]$_ @@ -335,8 +337,91 @@ if ($IsStable) { } $count = $newRegistrations.Count +$registrationsToSave = $newRegistrations +$tpnRegistrationsToSave = $null + +# If -ForceHarvestedOnly is specified with -Fix, only include harvested packages +# and revert non-harvested packages to their previous versions +if ($Fix -and $ForceHarvestedOnly) { + Write-Verbose "Checking harvest status and filtering to harvested packages with reversion..." -Verbose + + # Import ClearlyDefined module to check harvest status + Import-Module -Name "$PSScriptRoot/clearlyDefined/src/ClearlyDefined" -Force + + # Import cache from previous runs to speed up lookups + Import-ClearlyDefinedCache + + # Get harvest data for all registrations + $fullCgList = $newRegistrations | + ForEach-Object { + [PSCustomObject]@{ + type = $_.Component.Type + Name = $_.Component.Nuget.Name + PackageVersion = $_.Component.Nuget.Version + } + } + + $fullList = $fullCgList | Get-ClearlyDefinedData + + # Build a lookup table of harvest status by package name + version + $harvestStatus = @{} + foreach ($item in $fullList) { + $key = "$($item.Name)|$($item.PackageVersion)" + $harvestStatus[$key] = $item.harvested + } + + # Build a lookup table of old versions from existing manifest + $oldVersions = @{} + foreach ($registration in $existingRegistrationsJson.Registrations) { + $name = $registration.Component.Nuget.Name + if (!$oldVersions.ContainsKey($name)) { + $oldVersions[$name] = $registration + } + } + + # Process each new registration: keep harvested, revert non-harvested + $tpnRegistrationsToSave = @() + $harvestedCount = 0 + $revertedCount = 0 + + foreach ($reg in $newRegistrations) { + $name = $reg.Component.Nuget.Name + $version = $reg.Component.Nuget.Version + $key = "$name|$version" + + if ($harvestStatus.ContainsKey($key) -and $harvestStatus[$key]) { + # Package is harvested, include it + $tpnRegistrationsToSave += $reg + $harvestedCount++ + } else { + # Package not harvested, find last harvested version + $lastHarvestedVersion = Find-LastHarvestedVersion -Name $name -CurrentVersion $version + + # Use last harvested version if found, otherwise use old version as fallback + if ($lastHarvestedVersion) { + if ($lastHarvestedVersion -ne $version) { + $revertedReg = New-NugetComponent -Name $name -Version $lastHarvestedVersion -DevelopmentDependency:$reg.DevelopmentDependency + $tpnRegistrationsToSave += $revertedReg + $revertedCount++ + Write-Verbose "Reverted $name from v$version to last harvested v$lastHarvestedVersion" -Verbose + } else { + $tpnRegistrationsToSave += $reg + } + } elseif ($oldVersions.ContainsKey($name)) { + $tpnRegistrationsToSave += $oldVersions[$name] + $revertedCount++ + Write-Verbose "Reverted $name to previous version (no harvested version found)" -Verbose + } else { + Write-Warning "$name v$version not harvested and no previous version found. Excluding from manifest." + } + } + } + + Write-Verbose "Completed filtering for TPN: $harvestedCount harvested + $revertedCount reverted = $($tpnRegistrationsToSave.Count) total" -Verbose +} + $newJson = @{ - Registrations = $newRegistrations + Registrations = $registrationsToSave '$schema' = "https://json.schemastore.org/component-detection-manifest.json" } | ConvertTo-Json -depth 99 @@ -345,6 +430,149 @@ if ($Fix -and $registrationChanged) { Set-GWVariable -Name CGMANIFEST_PATH -Value $cgManifestPath } +# If -ForceHarvestedOnly was used, write the TPN manifest with filtered registrations +if ($Fix -and $ForceHarvestedOnly -and $tpnRegistrationsToSave.Count -gt 0) { + $tpnManifestDir = Join-Path -Path $PSScriptRoot -ChildPath "cgmanifest\tpn" + New-Item -ItemType Directory -Path $tpnManifestDir -Force | Out-Null + $tpnManifestPath = Join-Path -Path $tpnManifestDir -ChildPath "cgmanifest.json" + + $tpnManifest = @{ + Registrations = @($tpnRegistrationsToSave) + '$schema' = "https://json.schemastore.org/component-detection-manifest.json" + } + + $tpnJson = $tpnManifest | ConvertTo-Json -depth 99 + $tpnJson | Set-Content $tpnManifestPath -Encoding utf8NoBOM + Write-Verbose "TPN manifest created/updated with $($tpnRegistrationsToSave.Count) registrations (filtered for harvested packages)" -Verbose +} + +# Skip legacy TPN update when -ForceHarvestedOnly already produced a filtered manifest +if ($Fix -and $registrationChanged -and -not $ForceHarvestedOnly) { + # Import ClearlyDefined module to check harvest status + Write-Verbose "Checking harvest status for newly added packages..." -Verbose + Import-Module -Name "$PSScriptRoot/clearlyDefined/src/ClearlyDefined" -Force + + # Get harvest data for all registrations + $fullCgList = $newRegistrations | + ForEach-Object { + [PSCustomObject]@{ + type = $_.Component.Type + Name = $_.Component.Nuget.Name + PackageVersion = $_.Component.Nuget.Version + } + } + + $fullList = $fullCgList | Get-ClearlyDefinedData + $needHarvest = $fullList | Where-Object { !$_.harvested } + + if ($needHarvest.Count -gt 0) { + Write-Verbose "Found $($needHarvest.Count) packages that need harvesting. Starting harvest..." -Verbose + $needHarvest | Select-Object -ExpandProperty coordinates | ConvertFrom-ClearlyDefinedCoordinates | Start-ClearlyDefinedHarvest + } else { + Write-Verbose "All packages are already harvested." -Verbose + } + + # After manifest update and harvest, update TPN manifest with individual package status + Write-Verbose "Updating TPN manifest with individual package harvest status..." -Verbose + $tpnManifestDir = Join-Path -Path $PSScriptRoot -ChildPath "cgmanifest\tpn" + $tpnManifestPath = Join-Path -Path $tpnManifestDir -ChildPath "cgmanifest.json" + + # Load current TPN manifest to get previous versions + $currentTpnManifest = @() + if (Test-Path $tpnManifestPath) { + $currentTpnJson = Get-Content $tpnManifestPath | ConvertFrom-Json -AsHashtable + $currentTpnManifest = $currentTpnJson.Registrations + } + + # Build a lookup table of old versions + $oldVersions = @{} + foreach ($registration in $currentTpnManifest) { + $name = $registration.Component.Nuget.Name + if (!$oldVersions.ContainsKey($name)) { + $oldVersions[$name] = $registration + } + } + + # Note: Do not recheck harvest status here. Harvesting is an async process that takes a significant amount of time. + # Use the harvest data from the initial check. Newly triggered harvests will be captured + # on the next run of this script after harvesting completes. + $finalHarvestData = $fullList + + # Update packages individually based on harvest status + $tpnRegistrations = @() + $harvestedCount = 0 + $restoredCount = 0 + + foreach ($item in $finalHarvestData) { + $matchingNewRegistration = $newRegistrations | Where-Object { + $_.Component.Nuget.Name -eq $item.Name -and + $_.Component.Nuget.Version -eq $item.PackageVersion + } + + if ($matchingNewRegistration) { + if ($item.harvested) { + # Use new harvested version + $tpnRegistrations += $matchingNewRegistration + $harvestedCount++ + } else { + # Package not harvested - find the last harvested version from ClearlyDefined API + Write-Verbose "Finding last harvested version for $($item.Name)..." -Verbose + + $lastHarvestedVersion = $null + try { + # Search through all versions of this package to find the last harvested one + # Create a list of versions we know about from all runtimes + $packageVersionsToCheck = $newRegistrations | Where-Object { + $_.Component.Nuget.Name -eq $item.Name + } | ForEach-Object { $_.Component.Nuget.Version } | Sort-Object -Unique -Descending + + foreach ($versionToCheck in $packageVersionsToCheck) { + $versionCheckList = [PSCustomObject]@{ + type = "nuget" + Name = $item.Name + PackageVersion = $versionToCheck + } + + $versionStatus = $versionCheckList | Get-ClearlyDefinedData + if ($versionStatus -and $versionStatus.harvested) { + $lastHarvestedVersion = $versionToCheck + break # Found the most recent harvested version + } + } + } catch { + Write-Verbose "Error checking harvested versions for $($item.Name): $_" -Verbose + } + + # Use last harvested version if found, otherwise use old version as fallback + if ($lastHarvestedVersion) { + $revertedReg = New-NugetComponent -Name $item.Name -Version $lastHarvestedVersion -DevelopmentDependency:$matchingNewRegistration.DevelopmentDependency + $tpnRegistrations += $revertedReg + $restoredCount++ + Write-Verbose "Reverted $($item.Name) from v$($item.PackageVersion) to last harvested v$lastHarvestedVersion" -Verbose + } elseif ($oldVersions.ContainsKey($item.Name)) { + $tpnRegistrations += $oldVersions[$item.Name] + $restoredCount++ + Write-Verbose "Reverted $($item.Name) to previous version in TPN (no harvested version found)" -Verbose + } else { + Write-Warning "$($item.Name) v$($item.PackageVersion) not harvested and no harvested version found. Excluding from TPN manifest." + } + } + } + } + + # Save updated TPN manifest + if ($tpnRegistrations.Count -gt 0) { + $tpnManifest = @{ + Registrations = @($tpnRegistrations) + '$schema' = "https://json.schemastore.org/component-detection-manifest.json" + } + + $tpnJson = $tpnManifest | ConvertTo-Json -depth 99 + $tpnJson | Set-Content $tpnManifestPath -Encoding utf8NoBOM + Write-Verbose "TPN manifest updated: $harvestedCount new harvested + $restoredCount reverted to last harvested versions" -Verbose + } +} + if (!$Fix -and $registrationChanged) { $temp = Get-GWTempPath diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 14812bac413..e9b22715d74 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4920,7 +4920,7 @@ function New-GlobalToolNupkgSource } # Set VSTS environment variable for CGManifest file path. - $globalToolCGManifestPFilePath = Join-Path -Path "$env:REPOROOT" -ChildPath "tools\cgmanifest.json" + $globalToolCGManifestPFilePath = Join-Path -Path "$env:REPOROOT" -ChildPath "tools/cgmanifest/main/cgmanifest.json" $globalToolCGManifestFilePath = Resolve-Path -Path $globalToolCGManifestPFilePath -ErrorAction SilentlyContinue if (($null -eq $globalToolCGManifestFilePath) -or (! (Test-Path -Path $globalToolCGManifestFilePath))) { From 8a00d5b5cda61f2ed885e00fbabe3ad437591948 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 10 Mar 2026 12:31:14 -0700 Subject: [PATCH 072/127] [release/v7.6] Bump actions/upload-artifact from 6 to 7 (#26979) --- .github/workflows/macos-ci.yml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/windows-packaging-reusable.yml | 2 +- .github/workflows/xunit-tests.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index 24fd7c7e407..de5f7318660 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -229,7 +229,7 @@ jobs: testResultsFolder: "${{ runner.workspace }}/testResults" - name: Upload package artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: macos-package path: "*.pkg" diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 38bbc07c38c..1f95d1cae7c 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 6b42a8899ec..22f5e33314d 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -81,7 +81,7 @@ jobs: - name: Upload Build Artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} path: | diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index 8bf5fd699d0..1ab649d5492 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -46,7 +46,7 @@ jobs: Write-Host "Completed xUnit test run." - name: Upload xUnit results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: always() with: name: ${{ inputs.test_results_artifact_name }} From 9d8816d34b4dcdfca7bc62acde323a9e469763ec Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 10 Mar 2026 12:34:00 -0700 Subject: [PATCH 073/127] [release/v7.6] Update NuGet package versions in `cgmanifest.json` to actually match the branch (#26982) --- tools/cgmanifest/tpn/cgmanifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/cgmanifest/tpn/cgmanifest.json b/tools/cgmanifest/tpn/cgmanifest.json index a0746028a56..c1087b359a5 100644 --- a/tools/cgmanifest/tpn/cgmanifest.json +++ b/tools/cgmanifest/tpn/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -65,7 +66,7 @@ "Type": "nuget", "Nuget": { "Name": "Markdig.Signed", - "Version": "0.45.0" + "Version": "0.44.0" } }, "DevelopmentDependency": false @@ -750,6 +751,5 @@ }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } From f9a6fa473ad506025667990b66218aa5a332a320 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 10 Mar 2026 15:42:40 -0700 Subject: [PATCH 074/127] [release/v7.6] Fix ConvertFrom-ClearlyDefinedCoordinates to handle API object coordinates (#26986) Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: TravisEz13 <10873629+TravisEz13@users.noreply.github.com> Co-authored-by: Travis Plunk Co-authored-by: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> --- .../src/ClearlyDefined/ClearlyDefined.psm1 | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 index 4e3d375dc5a..88fc1f7cabd 100644 --- a/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 +++ b/tools/clearlyDefined/src/ClearlyDefined/ClearlyDefined.psm1 @@ -40,19 +40,30 @@ function ConvertFrom-ClearlyDefinedCoordinates { [CmdletBinding()] param( [parameter(mandatory = $true, ValueFromPipeline = $true)] - [string] + [object] $Coordinates ) Begin {} Process { - $parts = $Coordinates.Split('/') - [PSCustomObject]@{ - type = $parts[0] - provider = $parts[1] - namespace = $parts[2] - name = $parts[3] - revision = $parts[4] + if ($Coordinates -is [string]) { + $parts = $Coordinates.Split('/') + [PSCustomObject]@{ + type = $parts[0] + provider = $parts[1] + namespace = $parts[2] + name = $parts[3] + revision = $parts[4] + } + } else { + # Coordinates is already an object (e.g., from ClearlyDefined API response) + [PSCustomObject]@{ + type = $Coordinates.type + provider = $Coordinates.provider + namespace = $Coordinates.namespace + name = $Coordinates.name + revision = $Coordinates.revision + } } } End {} From 5ea8cb48cfbf08b35c372550b2a9bf0ba44d250c Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Tue, 10 Mar 2026 19:27:36 -0400 Subject: [PATCH 075/127] [release/v7.6] Update branch for release (#26989) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 6 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 4 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 64 +++++------ .../Microsoft.WSMan.Management.csproj | 4 +- .../PSVersionInfoGenerator.csproj | 6 +- .../System.Management.Automation.csproj | 20 ++-- .../BenchmarkDotNet.Extensions.csproj | 9 +- .../ResultsComparer/ResultsComparer.csproj | 9 +- ...soft.PowerShell.NamedPipeConnection.csproj | 8 ++ test/tools/TestService/TestService.csproj | 58 +++++----- test/tools/WebListener/WebListener.csproj | 4 +- tools/cgmanifest/main/cgmanifest.json | 102 +++++++++--------- 16 files changed, 164 insertions(+), 140 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 0d602086a6a..b0ab47f8077 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.102", + "sdkImageVersion": "10.0.200", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index c2af57a3fe4..8adf16d044b 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.102" + "version": "10.0.200" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index c94dfdde337..579f6b133ec 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,9 +7,11 @@ - + + + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index bea446f6293..2bad86795e2 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index c7cd0b86cf3..f1e014196d5 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -7,7 +7,7 @@ - + @@ -34,7 +34,7 @@ - + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index 6e740281999..a4a85d4065d 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 64fd931f233..f70aa478938 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,45 +16,47 @@ - - - - - - - - - - + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - + + + + + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 168633bbf31..1a4fc02622c 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ - + - + diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index 4001869d26c..587a45bb7b6 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -15,13 +15,13 @@ - + - + - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 13ec26b68ed..487e18cd8fc 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,21 +32,21 @@ - - - - - - - - - + + + + + + + + + - + diff --git a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj index 1192b7ff00f..d3dd673a0b7 100644 --- a/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj +++ b/test/perf/dotnet-tools/BenchmarkDotNet.Extensions/BenchmarkDotNet.Extensions.csproj @@ -8,9 +8,14 @@ - + + - + + + + + diff --git a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj index 07eb84c5680..7fd5d444266 100644 --- a/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj +++ b/test/perf/dotnet-tools/ResultsComparer/ResultsComparer.csproj @@ -8,10 +8,15 @@ - + + - + + + + + \ No newline at end of file diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index 89147481bc3..1dbb104dfa6 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -15,6 +15,14 @@ + + + + + + + + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 663cbe83f5f..5fcb84e733f 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,34 +15,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index debbdf1a389..7c51aa7016d 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index 0474a86df42..6ca29fc3aa6 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -85,7 +86,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -125,7 +126,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -165,7 +166,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -175,7 +176,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -185,7 +186,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -205,7 +206,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -215,7 +216,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -225,7 +226,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -235,7 +236,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -245,7 +246,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -255,7 +256,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -265,7 +266,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -275,7 +276,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -285,7 +286,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -295,7 +296,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -305,7 +306,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -315,7 +316,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -325,7 +326,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -335,7 +336,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -355,7 +356,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -365,7 +366,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -375,7 +376,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -435,7 +436,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -445,7 +446,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -455,7 +456,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -465,7 +466,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -475,7 +476,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -485,7 +486,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -495,7 +496,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.SqlClient", - "Version": "4.9.0" + "Version": "4.9.1" } }, "DevelopmentDependency": false @@ -505,7 +506,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -515,7 +516,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -525,7 +526,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -535,7 +536,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -545,7 +546,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -555,7 +556,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -565,7 +566,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -575,7 +576,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -585,7 +586,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -595,7 +596,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -605,7 +606,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -615,7 +616,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -625,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -635,7 +636,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -645,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -655,7 +656,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -705,7 +706,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -715,7 +716,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -725,7 +726,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false @@ -745,11 +746,10 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.3" + "Version": "10.0.4" } }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } From 348e3470c06e4e423428e4f3edcf7187540e44a2 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 11 Mar 2026 18:24:34 +0000 Subject: [PATCH 076/127] Merged PR 38918: Update `MaxVisitCount` and `MaxHashtableKeyCount` if `VisitorSafeValueContext` indicates `SkipLimitCheck` is true Update MaxVisitCount and MaxHashtableKeyCount if visitor safe value context indicates SkipLimitCheck is true Related work items: #163537 ---- #### AI description (iteration 1) #### PR Classification Enhancement: Conditionally update AST limit checks based on safe value context flags. #### PR Summary This pull request refactors the safe value visitor to initialize runtime limit values, setting them to maximum if the `SkipLimitCheck` flag is present, and adjusts the corresponding condition checks to support larger AST structures safely. - `src/System.Management.Automation/engine/parser/SafeValues.cs`: Replaced hard-coded limit constants with runtime-initialized readonly fields based on the safe value context, and updated conditional checks in `IsAstSafe` and `VisitHashtable`. - `test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1`: Added tests to validate behavior when using `-SkipLimitCheck`, ensuring insecure PSD1 files are properly rejected. Related work items: #163537 --- .../engine/parser/SafeValues.cs | 14 +++++++++----- .../PowerShellData.tests.ps1 | 6 ++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/SafeValues.cs b/src/System.Management.Automation/engine/parser/SafeValues.cs index 05c87daab5b..38181168a66 100644 --- a/src/System.Management.Automation/engine/parser/SafeValues.cs +++ b/src/System.Management.Automation/engine/parser/SafeValues.cs @@ -47,11 +47,15 @@ public static bool IsAstSafe(Ast ast, GetSafeValueVisitor.SafeValueContext safeV internal IsSafeValueVisitor(GetSafeValueVisitor.SafeValueContext safeValueContext) { _safeValueContext = safeValueContext; + + bool skipSizeCheck = safeValueContext is GetSafeValueVisitor.SafeValueContext.SkipHashtableSizeCheck; + _maxVisitCount = skipSizeCheck ? uint.MaxValue : 5000; + _maxHashtableKeyCount = skipSizeCheck ? int.MaxValue : 500; } internal bool IsAstSafe(Ast ast) { - if ((bool)ast.Accept(this) && _visitCount < MaxVisitCount) + if ((bool)ast.Accept(this) && _visitCount < _maxVisitCount) { return true; } @@ -65,8 +69,8 @@ internal bool IsAstSafe(Ast ast) // This is a check of the number of visits private uint _visitCount = 0; - private const uint MaxVisitCount = 5000; - private const int MaxHashtableKeyCount = 500; + private readonly uint _maxVisitCount; + private readonly int _maxHashtableKeyCount; // Used to determine if we are being called within a GetPowerShell() context, // which does some additional security verification outside of the scope of @@ -330,7 +334,7 @@ public object VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst) public object VisitHashtable(HashtableAst hashtableAst) { - if (hashtableAst.KeyValuePairs.Count > MaxHashtableKeyCount) + if (hashtableAst.KeyValuePairs.Count > _maxHashtableKeyCount) { return false; } @@ -373,7 +377,7 @@ public static object GetSafeValue(Ast ast, ExecutionContext context, SafeValueCo { t_context = context; - if (safeValueContext == SafeValueContext.SkipHashtableSizeCheck || IsSafeValueVisitor.IsAstSafe(ast, safeValueContext)) + if (IsSafeValueVisitor.IsAstSafe(ast, safeValueContext)) { return ast.Accept(new GetSafeValueVisitor()); } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 index cfba4a4cbed..148993b69b1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 @@ -49,4 +49,10 @@ Describe "Tests for the Import-PowerShellDataFile cmdlet" -Tags "CI" { $result = Import-PowerShellDataFile $largePsd1Path -SkipLimitCheck $result.Keys.Count | Should -Be 501 } + + It 'Fails if psd1 file is insecure while -SkipLimitCheck is used' { + $path = Setup -f insecure2.psd1 -Content '@{ Foo = [object] (calc.exe) }' -pass + { Import-PowerShellDataFile $path -SkipLimitCheck -ErrorAction Stop } | + Should -Throw -ErrorId "System.InvalidOperationException,Microsoft.PowerShell.Commands.ImportPowerShellDataFileCommand" + } } From 9e2d1e968110b839cb08716f25aa90e3c7f88522 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:08:27 -0500 Subject: [PATCH 077/127] Update LTS and StableRelease settings in metadata (#27006) --- tools/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/metadata.json b/tools/metadata.json index e0f4952c588..379bf32cd04 100644 --- a/tools/metadata.json +++ b/tools/metadata.json @@ -5,6 +5,6 @@ "ReleaseTag": "v7.5.4", "LTSReleaseTag" : ["v7.4.13"], "NextReleaseTag": "v7.6.0-preview.6", - "LTSRelease": { "PublishToChannels": false, "Package": false }, - "StableRelease": { "PublishToChannels": false, "Package": false } + "LTSRelease": { "PublishToChannels": false, "Package": true }, + "StableRelease": { "PublishToChannels": true, "Package": true } } From 4eee8d13dad9bb68dbd1f4a1f8f276f2572c7075 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 11 Mar 2026 14:36:33 -0700 Subject: [PATCH 078/127] Update ChangeLog for v7.6.0 release (#27001) --- CHANGELOG/{preview.md => 7.6.md} | 46 +++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) rename CHANGELOG/{preview.md => 7.6.md} (96%) diff --git a/CHANGELOG/preview.md b/CHANGELOG/7.6.md similarity index 96% rename from CHANGELOG/preview.md rename to CHANGELOG/7.6.md index 851640f8cc5..8dad96a4fd7 100644 --- a/CHANGELOG/preview.md +++ b/CHANGELOG/7.6.md @@ -1,4 +1,48 @@ -# Preview Changelog +# 7.6 Changelog + +## [7.6.0] - 2026-03-12 + +### General Cmdlet Updates and Fixes + +- Update PowerShell Profile DSC resource manifests to allow `null` for content (#26973) + +### Tests + +- Add GitHub Actions annotations for Pester test failures (#26969) +- Fix `Import-Module.Tests.ps1` to handle Arm32 platform (#26888) + +### Build and Packaging Improvements + +
+ + + +

We thank the following contributors!

+

@kasperk81

+ +
+ +
    +
  • Update branch for release (#26989)
  • +
  • Fix ConvertFrom-ClearlyDefinedCoordinates to handle API object coordinates (#26986)
  • +
  • Update NuGet package versions in cgmanifest.json to actually match the branch (#26982)
  • +
  • Bump actions/upload-artifact from 6 to 7 (#26979)
  • +
  • Split TPN manifest and Component Governance manifest (#26978)
  • +
  • Bump github/codeql-action from 4.32.4 to 4.32.6 (#26975)
  • +
  • Bump actions/dependency-review-action from 4.8.3 to 4.9.0 (#26974)
  • +
  • Hardcode Official templates (#26972)
  • +
  • Fix a preview detection test for the packaging script (#26971)
  • +
  • Fetch latest ICU release version dynamically (#26970) (Thanks @kasperk81!)
  • +
  • Add PMC packages for debian13 and rhel10 (#26917)
  • +
  • Add version in description and pass store task on failure (#26889)
  • +
  • Exclude .exe packages from publishing to GitHub (#26887)
  • +
  • Correct the package name for .deb and .rpm packages (#26884)
  • +
  • Update Microsoft.PowerShell.PSResourceGet version to 1.2.0 (#27007)
  • +
+ +
+ +[7.6.0]: https://github.com/PowerShell/PowerShell/compare/v7.6.0-rc.1...v7.6.0 ## [7.6.0-rc.1] - 2026-02-19 From 49b31c1c763a38ab53d9fa412854a513e0de78e9 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 11 Mar 2026 16:27:01 -0700 Subject: [PATCH 079/127] [release/v7.6] Update `Microsoft.PowerShell.PSResourceGet` version to 1.2.0 (#27007) --- src/Modules/PSGalleryModules.csproj | 2 +- tools/packaging/boms/windows.json | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Modules/PSGalleryModules.csproj b/src/Modules/PSGalleryModules.csproj index 7008fe6a08d..6b738974b9d 100644 --- a/src/Modules/PSGalleryModules.csproj +++ b/src/Modules/PSGalleryModules.csproj @@ -13,7 +13,7 @@ - + diff --git a/tools/packaging/boms/windows.json b/tools/packaging/boms/windows.json index f811109f818..32561b7e319 100644 --- a/tools/packaging/boms/windows.json +++ b/tools/packaging/boms/windows.json @@ -1216,6 +1216,11 @@ "FileType": "NonProduct", "Architecture": null }, + { + "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\.signature.p7s", + "FileType": "NonProduct", + "Architecture": null + }, { "Pattern": "Modules\\Microsoft.PowerShell.PSResourceGet\\Microsoft.PowerShell.PSResourceGet.pdb", "FileType": "NonProduct", From d8f221c2255564888ac02166af907efa71508c62 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Mar 2026 15:22:39 -0700 Subject: [PATCH 080/127] Revert "[release/v7.6] Fetch latest ICU release version dynamically" (#27019) --- tools/packaging/packaging.psm1 | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index e9b22715d74..51498d7b04b 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -2152,7 +2152,7 @@ function Get-PackageDependencies # than the build version and we know that older versions just works. # $MinICUVersion = 60 # runtime minimum supported - $BuildICUVersion = Get-IcuLatestRelease + $BuildICUVersion = 76 # current build version $MaxICUVersion = $BuildICUVersion + 30 # headroom if ($Distribution -eq 'deb') { @@ -5812,15 +5812,3 @@ function Test-IsProductFile { return $false } - -# Get major version from latest ICU release (latest: stable version) -function Get-IcuLatestRelease { - $response = Invoke-WebRequest -Uri "https://github.com/unicode-org/icu/releases/latest" - $tagUrl = ($response.Links | Where-Object href -like "*releases/tag/release-*")[0].href - - if ($tagUrl -match 'release-(\d+)\.') { - return [int]$Matches[1] - } - - throw "Unable to determine the latest ICU release version." -} From d4febbd45d7f321528ac9d85500c6ef73da11c4d Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 12 Mar 2026 15:23:25 -0700 Subject: [PATCH 081/127] [release/v7.6] Fix the container image for vPack, MSIX vPack and Package pipelines (#27020) --- .pipelines/MSIXBundle-vPack-Official.yml | 5 ++++- .pipelines/PowerShell-Coordinated_Packages-Official.yml | 3 ++- .pipelines/PowerShell-vPack-Official.yml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 997b7c458be..876da9c2aff 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -22,7 +22,7 @@ variables: BuildSolution: $(Build.SourcesDirectory)\dirs.proj ReleaseTagVar: ${{ parameters.ReleaseTagVar }} BuildConfiguration: Release - WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' Codeql.Enabled: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack DOTNET_CLI_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1 @@ -46,6 +46,9 @@ resources: extends: template: v2/Microsoft.Official.yml@onebranchTemplates parameters: + featureFlags: + WindowsHostVersion: + Version: 2022 platform: name: 'windows_undocked' # windows undocked diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 380c9c5516e..12460e2861c 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -68,7 +68,7 @@ variables: - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: WindowsContainerImage - value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest + value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest - name: CDP_DEFINITION_BUILD_COUNT value: $[counter('', 0)] - name: ReleaseTagVar @@ -105,6 +105,7 @@ extends: LinuxHostVersion: Network: KS3 WindowsHostVersion: + Version: 2022 Network: KS3 incrementalSDLBinaryAnalysis: true globalSdl: diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index 653f9628e72..f7faeb30656 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -41,7 +41,7 @@ variables: - name: BuildConfiguration value: Release - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - name: Codeql.Enabled value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - name: DOTNET_CLI_TELEMETRY_OPTOUT From f64a190324a97e747507f9a02c831c77107a3758 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 16 Mar 2026 12:52:39 -0700 Subject: [PATCH 082/127] [release/v7.6] Create LTS pkg and non-LTS pkg for macOS for LTS releases (#27040) --- .pipelines/templates/mac-package-build.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index def866173ac..6585773c743 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -102,6 +102,10 @@ jobs: Restore-PSOptions -PSOptionsPath "$psoptionsPath" Get-PSOptions | Write-Verbose -Verbose + if (-not (Test-Path "$repoRoot/tools/metadata.json")) { + throw "metadata.json not found in $repoRoot/tools" + } + $metadata = Get-Content "$repoRoot/tools/metadata.json" -Raw | ConvertFrom-Json Write-Verbose -Verbose "metadata:" @@ -120,14 +124,19 @@ jobs: Write-Verbose -Verbose "LTS: $LTS" if ($LTS) { - Write-Verbose -Message "LTS Release: $LTS" + Write-Verbose -Message "LTS Release: $LTS" -Verbose } Start-PSBootstrap -Scenario Package $macosRuntime = "osx-$buildArch" - Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS + Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath + + if ($LTS) { + Start-PSPackage -Type osxpkg -SkipReleaseChecks -MacOSRuntime $macosRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS + } + $pkgNameFilter = "powershell-*$macosRuntime.pkg" Write-Verbose -Verbose "Looking for pkg packages with filter: $pkgNameFilter in '$(Pipeline.Workspace)' to upload..." $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgNameFilter -Recurse -File From d384bb89b3b52c239b4b71204698e33fdabf0603 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Mon, 16 Mar 2026 16:30:52 -0400 Subject: [PATCH 083/127] [release/v7.6] Update v7.6 release branch to use .NET SDK 10.0.201 (#27041) --- DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- ...oft.PowerShell.Commands.Diagnostics.csproj | 8 +- ...soft.PowerShell.Commands.Management.csproj | 4 +- ...crosoft.PowerShell.Commands.Utility.csproj | 4 +- ...crosoft.PowerShell.CoreCLR.Eventing.csproj | 2 +- .../Microsoft.PowerShell.SDK.csproj | 80 ++++++++------ .../Microsoft.WSMan.Management.csproj | 4 +- .../System.Management.Automation.csproj | 20 ++-- ...soft.PowerShell.NamedPipeConnection.csproj | 1 + test/tools/TestService/TestService.csproj | 74 ++++++++----- test/tools/WebListener/WebListener.csproj | 4 +- tools/cgmanifest/main/cgmanifest.json | 100 +++++++++--------- 13 files changed, 169 insertions(+), 136 deletions(-) diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index b0ab47f8077..89ea4c44790 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.200", + "sdkImageVersion": "10.0.201", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 8adf16d044b..ce67766bbb5 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.200" + "version": "10.0.201" } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj index 579f6b133ec..f156ea867ff 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/Microsoft.PowerShell.Commands.Diagnostics.csproj @@ -7,11 +7,11 @@ - - - + + + - + diff --git a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj index 2bad86795e2..d4bbc23db28 100644 --- a/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj +++ b/src/Microsoft.PowerShell.Commands.Management/Microsoft.PowerShell.Commands.Management.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj index f1e014196d5..9ed5a433413 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj +++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj @@ -7,7 +7,7 @@ - + @@ -34,7 +34,7 @@ - + diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj index a4a85d4065d..750626be2dc 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/Microsoft.PowerShell.CoreCLR.Eventing.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index f70aa478938..df66cf90663 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -16,47 +16,63 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + diff --git a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj index 1a4fc02622c..e334db82957 100644 --- a/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj +++ b/src/Microsoft.WSMan.Management/Microsoft.WSMan.Management.csproj @@ -7,11 +7,11 @@ - + - + diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 487e18cd8fc..63dc69e5119 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -32,21 +32,21 @@ - - - - - - - - - + + + + + + + + + - + diff --git a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj index 1dbb104dfa6..d3d4e43733d 100644 --- a/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj +++ b/test/tools/NamedPipeConnection/src/code/Microsoft.PowerShell.NamedPipeConnection.csproj @@ -19,6 +19,7 @@ + diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 5fcb84e733f..1b2c5aa03a4 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -15,36 +15,52 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 7c51aa7016d..3e0f8b2cd36 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index 6ca29fc3aa6..4004daffd93 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -1,5 +1,4 @@ { - "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -86,7 +85,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Bcl.AsyncInterfaces", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -126,7 +125,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Extensions.ObjectPool", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -166,7 +165,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.Registry.AccessControl", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -176,7 +175,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Win32.SystemEvents", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -186,7 +185,7 @@ "Type": "nuget", "Nuget": { "Name": "Microsoft.Windows.Compatibility", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -206,7 +205,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -216,7 +215,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -226,7 +225,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -236,7 +235,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.android-x86.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -246,7 +245,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -256,7 +255,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -266,7 +265,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -276,7 +275,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-bionic-x64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -286,7 +285,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -296,7 +295,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -306,7 +305,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-musl-x64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -316,7 +315,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.linux-x64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -326,7 +325,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -336,7 +335,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.maccatalyst-x64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -356,7 +355,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -366,7 +365,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-arm64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -376,7 +375,7 @@ "Type": "nuget", "Nuget": { "Name": "runtime.osx-x64.runtime.native.System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -436,7 +435,7 @@ "Type": "nuget", "Nuget": { "Name": "System.CodeDom", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -446,7 +445,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition.Registration", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -456,7 +455,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ComponentModel.Composition", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -466,7 +465,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Configuration.ConfigurationManager", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -476,7 +475,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.Odbc", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -486,7 +485,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Data.OleDb", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -506,7 +505,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.EventLog", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -516,7 +515,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Diagnostics.PerformanceCounter", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -526,7 +525,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.AccountManagement", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -536,7 +535,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices.Protocols", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -546,7 +545,7 @@ "Type": "nuget", "Nuget": { "Name": "System.DirectoryServices", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -556,7 +555,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Drawing.Common", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -566,7 +565,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Packaging", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -576,7 +575,7 @@ "Type": "nuget", "Nuget": { "Name": "System.IO.Ports", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -586,7 +585,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Management", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -596,7 +595,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Net.Http.WinHttpHandler", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -606,7 +605,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Reflection.Context", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -616,7 +615,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Runtime.Caching", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -626,7 +625,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -636,7 +635,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.ProtectedData", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -646,7 +645,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -656,7 +655,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Permissions", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -706,7 +705,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceModel.Syndication", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -716,7 +715,7 @@ "Type": "nuget", "Nuget": { "Name": "System.ServiceProcess.ServiceController", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -726,7 +725,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Speech", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false @@ -746,10 +745,11 @@ "Type": "nuget", "Nuget": { "Name": "System.Windows.Extensions", - "Version": "10.0.4" + "Version": "10.0.5" } }, "DevelopmentDependency": false } - ] + ], + "$schema": "https://json.schemastore.org/component-detection-manifest.json" } From 47d65d0b1e7c6a153b5dc8940c10abec80bd7fec Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 16 Mar 2026 13:44:32 -0700 Subject: [PATCH 084/127] Update the ChangeLog for v7.6.0 with new changes ported to the release branch (#27042) --- CHANGELOG/7.6.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG/7.6.md b/CHANGELOG/7.6.md index 8dad96a4fd7..fb1037f7e24 100644 --- a/CHANGELOG/7.6.md +++ b/CHANGELOG/7.6.md @@ -17,12 +17,16 @@ -

We thank the following contributors!

-

@kasperk81

+

Update to .NET SDK 10.0.201

    +
  • Update v7.6 release branch to use .NET SDK 10.0.201 (#27041)
  • +
  • Create LTS package and non-LTS package for macOS for LTS releases (#27040)
  • +
  • Fix the container image for package pipelines (#27020)
  • +
  • Update Microsoft.PowerShell.PSResourceGet version to 1.2.0 (#27007)
  • +
  • Update LTS and Stable release settings in metadata (#27006)
  • Update branch for release (#26989)
  • Fix ConvertFrom-ClearlyDefinedCoordinates to handle API object coordinates (#26986)
  • Update NuGet package versions in cgmanifest.json to actually match the branch (#26982)
  • @@ -32,12 +36,10 @@
  • Bump actions/dependency-review-action from 4.8.3 to 4.9.0 (#26974)
  • Hardcode Official templates (#26972)
  • Fix a preview detection test for the packaging script (#26971)
  • -
  • Fetch latest ICU release version dynamically (#26970) (Thanks @kasperk81!)
  • Add PMC packages for debian13 and rhel10 (#26917)
  • Add version in description and pass store task on failure (#26889)
  • Exclude .exe packages from publishing to GitHub (#26887)
  • Correct the package name for .deb and .rpm packages (#26884)
  • -
  • Update Microsoft.PowerShell.PSResourceGet version to 1.2.0 (#27007)
From 9a85ea63900f0740dfe3184bfddaf282d4464f91 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 17 Mar 2026 10:51:41 -0700 Subject: [PATCH 085/127] Update 'ThirdPartyNotices.txt' for the v7.6.0 release (#27048) --- ThirdPartyNotices.txt | 110 +++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 0397684ed7a..18d02c5ce43 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -17,7 +17,7 @@ required to debug changes to any libraries licensed under the GNU Lesser General --------------------------------------------------------- -Markdig.Signed 0.43.0 - BSD-2-Clause +Markdig.Signed 0.44.0 - BSD-2-Clause @@ -170,7 +170,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Bcl.AsyncInterfaces 10.0.0 - MIT +Microsoft.Bcl.AsyncInterfaces 10.0.3 - MIT Copyright (c) 2021 @@ -244,7 +244,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.CodeAnalysis.Common 4.14.0 - MIT +Microsoft.CodeAnalysis.Common 5.0.0 - MIT (c) Microsoft Corporation @@ -264,7 +264,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.CodeAnalysis.CSharp 4.14.0 - MIT +Microsoft.CodeAnalysis.CSharp 5.0.0 - MIT (c) Microsoft Corporation @@ -289,7 +289,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Extensions.ObjectPool 10.0.0 - MIT +Microsoft.Extensions.ObjectPool 10.0.3 - MIT Copyright Jorn Zaefferer @@ -379,7 +379,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Win32.Registry.AccessControl 10.0.0 - MIT +Microsoft.Win32.Registry.AccessControl 10.0.3 - MIT Copyright (c) 2021 @@ -453,7 +453,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Win32.SystemEvents 10.0.0 - MIT +Microsoft.Win32.SystemEvents 10.0.3 - MIT Copyright (c) 2021 @@ -527,7 +527,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -Microsoft.Windows.Compatibility 10.0.0 - MIT +Microsoft.Windows.Compatibility 10.0.3 - MIT (c) Microsoft Corporation @@ -580,7 +580,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -runtime.android-arm.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.android-arm.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -654,7 +654,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.android-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.android-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -728,7 +728,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.android-x64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.android-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -802,7 +802,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.android-x86.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.android-x86.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -876,7 +876,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.linux-arm.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.linux-arm.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -950,7 +950,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.linux-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.linux-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1024,7 +1024,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.linux-bionic-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1098,7 +1098,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.linux-bionic-x64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.linux-bionic-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1172,7 +1172,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.linux-musl-arm.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.linux-musl-arm.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1246,7 +1246,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.linux-musl-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.linux-musl-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1320,7 +1320,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.linux-musl-x64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.linux-musl-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1394,7 +1394,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.linux-x64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.linux-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1468,7 +1468,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.maccatalyst-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1542,7 +1542,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.maccatalyst-x64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.maccatalyst-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1661,7 +1661,7 @@ SOFTWARE. --------------------------------------------------------- -runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1735,7 +1735,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.osx-arm64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.osx-arm64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1809,7 +1809,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -runtime.osx-x64.runtime.native.System.IO.Ports 10.0.0 - MIT +runtime.osx-x64.runtime.native.System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -1883,7 +1883,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.CodeDom 10.0.0 - MIT +System.CodeDom 10.0.3 - MIT Copyright (c) 2021 @@ -1957,7 +1957,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.ComponentModel.Composition 10.0.0 - MIT +System.ComponentModel.Composition 10.0.3 - MIT Copyright (c) 2021 @@ -2031,7 +2031,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.ComponentModel.Composition.Registration 10.0.0 - MIT +System.ComponentModel.Composition.Registration 10.0.3 - MIT Copyright (c) 2021 @@ -2105,7 +2105,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Configuration.ConfigurationManager 10.0.0 - MIT +System.Configuration.ConfigurationManager 10.0.3 - MIT Copyright (c) 2021 @@ -2179,7 +2179,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Data.Odbc 10.0.0 - MIT +System.Data.Odbc 10.0.3 - MIT Copyright (c) 2021 @@ -2253,7 +2253,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Data.OleDb 10.0.0 - MIT +System.Data.OleDb 10.0.3 - MIT Copyright (c) 2021 @@ -2346,7 +2346,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Diagnostics.EventLog 10.0.0 - MIT +System.Diagnostics.EventLog 10.0.3 - MIT Copyright (c) 2021 @@ -2420,7 +2420,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Diagnostics.PerformanceCounter 10.0.0 - MIT +System.Diagnostics.PerformanceCounter 10.0.3 - MIT Copyright (c) 2021 @@ -2494,7 +2494,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.DirectoryServices 10.0.0 - MIT +System.DirectoryServices 10.0.3 - MIT Copyright (c) 2021 @@ -2568,7 +2568,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.DirectoryServices.AccountManagement 10.0.0 - MIT +System.DirectoryServices.AccountManagement 10.0.3 - MIT Copyright (c) 2021 @@ -2642,7 +2642,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.DirectoryServices.Protocols 10.0.0 - MIT +System.DirectoryServices.Protocols 10.0.3 - MIT Copyright (c) 2021 @@ -2716,7 +2716,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Drawing.Common 10.0.0 - MIT +System.Drawing.Common 10.0.3 - MIT (c) Microsoft Corporation @@ -2751,7 +2751,7 @@ SOFTWARE. --------------------------------------------------------- -System.IO.Packaging 10.0.0 - MIT +System.IO.Packaging 10.0.3 - MIT Copyright (c) 2021 @@ -2825,7 +2825,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.IO.Ports 10.0.0 - MIT +System.IO.Ports 10.0.3 - MIT Copyright (c) 2021 @@ -2899,7 +2899,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Management 10.0.0 - MIT +System.Management 10.0.3 - MIT Copyright (c) 2021 @@ -2973,7 +2973,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Net.Http.WinHttpHandler 10.0.0 - MIT +System.Net.Http.WinHttpHandler 10.0.3 - MIT Copyright (c) 2021 @@ -3047,7 +3047,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Reflection.Context 10.0.0 - MIT +System.Reflection.Context 10.0.3 - MIT Copyright (c) 2021 @@ -3121,7 +3121,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Runtime.Caching 10.0.0 - MIT +System.Runtime.Caching 10.0.3 - MIT Copyright (c) 2021 @@ -3195,7 +3195,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Security.Cryptography.Pkcs 10.0.0 - MIT +System.Security.Cryptography.Pkcs 10.0.3 - MIT Copyright (c) 2021 @@ -3269,7 +3269,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Security.Cryptography.ProtectedData 10.0.0 - MIT +System.Security.Cryptography.ProtectedData 10.0.3 - MIT Copyright (c) 2021 @@ -3343,7 +3343,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Security.Cryptography.Xml 10.0.0 - MIT +System.Security.Cryptography.Xml 10.0.3 - MIT Copyright (c) 2021 @@ -3417,7 +3417,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Security.Permissions 10.0.0 - MIT +System.Security.Permissions 10.0.3 - MIT Copyright (c) 2021 @@ -3491,7 +3491,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.ServiceModel.Http 8.1.2 - MIT +System.ServiceModel.Http 10.0.652802 - MIT (c) Microsoft Corporation @@ -3527,7 +3527,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.NetFramingBase 8.1.2 - MIT +System.ServiceModel.NetFramingBase 10.0.652802 - MIT (c) Microsoft Corporation @@ -3563,7 +3563,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.NetTcp 8.1.2 - MIT +System.ServiceModel.NetTcp 10.0.652802 - MIT (c) Microsoft Corporation @@ -3599,7 +3599,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Primitives 8.1.2 - MIT +System.ServiceModel.Primitives 10.0.652802 - MIT (c) Microsoft Corporation @@ -3635,7 +3635,7 @@ SOFTWARE. --------------------------------------------------------- -System.ServiceModel.Syndication 10.0.0 - MIT +System.ServiceModel.Syndication 10.0.3 - MIT Copyright (c) 2021 @@ -3709,7 +3709,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.ServiceProcess.ServiceController 10.0.0 - MIT +System.ServiceProcess.ServiceController 10.0.3 - MIT Copyright (c) 2021 @@ -3783,7 +3783,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -System.Speech 10.0.0 - MIT +System.Speech 10.0.3 - MIT Copyright (c) 2021 @@ -3893,7 +3893,7 @@ SOFTWARE. --------------------------------------------------------- -System.Windows.Extensions 10.0.0 - MIT +System.Windows.Extensions 10.0.3 - MIT Copyright (c) 2021 From f282cf7641d421d044ec9f9aeea3ddc16d67676b Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 17 Mar 2026 15:10:57 -0700 Subject: [PATCH 086/127] Create Linux LTS deb/rpm packages for LTS releases (#27051) --- .pipelines/templates/linux-package-build.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index ea49b9fea5d..bb7ed723f42 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -155,10 +155,6 @@ jobs: Write-Verbose -Verbose "LTS: $LTS" - if ($LTS) { - Write-Verbose -Message "LTS Release: $LTS" - } - if (-not (Test-Path $(ob_outputDirectory))) { New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force } @@ -168,6 +164,11 @@ jobs: Start-PSPackage -Type $packageType -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath + if ($LTS) { + Write-Verbose -Message "LTS Release: $LTS" -Verbose + Start-PSPackage -Type $packageType -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS + } + $vstsCommandString = "vso[task.setvariable variable=PackageFilter]$pkgFilter" Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" From 44e158c121150a3f0ff15df7ec2f77150c432a5a Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 18 Mar 2026 13:57:01 -0700 Subject: [PATCH 087/127] [release/v7.6] Fix PMC Repo URL for RHEL10 (#27061) (#27062) --- .pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 | 2 +- tools/packages.microsoft.com/mapping.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 index 23f91c1bff2..6797ff94575 100644 --- a/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 +++ b/.pipelines/EV2Specs/ServiceGroupRoot/Shell/Run/Run.ps1 @@ -64,7 +64,7 @@ function Get-MappedRepositoryIds { $repoIds.AddRange(([string[]]$repos.id)) } else { - Write-Failure "Could not find repo for $urlGlob" + throw "Could not find repo for $urlGlob" } if ($repoIds.Count -gt 0) { diff --git a/tools/packages.microsoft.com/mapping.json b/tools/packages.microsoft.com/mapping.json index 334f6dfdd55..154a9582872 100644 --- a/tools/packages.microsoft.com/mapping.json +++ b/tools/packages.microsoft.com/mapping.json @@ -22,7 +22,7 @@ "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.rh.x86_64.rpm" }, { - "url": "microsoft-rhel10.0-prod", + "url": "microsoft-rhel10-prod", "distribution": [ "stable" ], From 031e7c9e8d39d2492cf1570516f0892421ba2376 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 19 Mar 2026 15:33:13 -0700 Subject: [PATCH 088/127] [release/v7.6] Create infrastructure to create two msixs and msixbundles for LTS and Stable (#27071) --- .pipelines/templates/package-create-msix.yml | 78 +++++++++++++++---- .../templates/packaging/windows/package.yml | 8 ++ tools/packaging/packaging.psm1 | 19 ++--- 3 files changed, 81 insertions(+), 24 deletions(-) diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 22815c98e11..3acddf1c000 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -85,17 +85,44 @@ jobs: $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose } - $file = Get-ChildItem $sourceDir | Select-Object -First 1 - $prefix = ($file.BaseName -split "-win")[0] - $pkgName = "$prefix.msixbundle" - Write-Verbose -Verbose "Creating $pkgName" - $makeappx = '$(MakeAppxPath)' $outputDir = "$sourceDir\output" New-Item $outputDir -Type Directory -Force > $null - & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" - Get-ChildItem -Path $sourceDir -Recurse + # Separate LTS and Stable/Preview MSIX files by filename convention + $ltsMsix = @(Get-ChildItem $sourceDir -Filter '*.msix' | Where-Object { $_.BaseName -match '-LTS-' }) + $stableMsix = @(Get-ChildItem $sourceDir -Filter '*.msix' | Where-Object { $_.BaseName -notmatch '-LTS-' }) + + Write-Verbose -Verbose "Stable/Preview MSIX files: $($stableMsix.Name -join ', ')" + Write-Verbose -Verbose "LTS MSIX files: $($ltsMsix.Name -join ', ')" + + # Create Stable/Preview bundle + if ($stableMsix.Count -gt 0) { + $stableDir = "$sourceDir\stable" + New-Item $stableDir -Type Directory -Force > $null + $stableMsix | Copy-Item -Destination $stableDir -Force + $file = $stableMsix | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $stableBundleName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating Stable/Preview bundle: $stableBundleName" + & $makeappx bundle /d $stableDir /p "$outputDir\$stableBundleName" + } + + # Create LTS bundle + if ($ltsMsix.Count -gt 0) { + $ltsDir = "$sourceDir\lts" + New-Item $ltsDir -Type Directory -Force > $null + $ltsMsix | Copy-Item -Destination $ltsDir -Force + $file = $ltsMsix | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $ltsBundleName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating LTS bundle: $ltsBundleName" + & $makeappx bundle /d $ltsDir /p "$outputDir\$ltsBundleName" + } + + Write-Verbose -Verbose "Created bundles:" + Get-ChildItem -Path $outputDir -Recurse + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" Write-Host "sending " + $vstsCommandString Write-Host "##$vstsCommandString" @@ -112,16 +139,18 @@ jobs: search_root: '$(BundleDir)' - pwsh: | - $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File - Write-Verbose -Verbose "Signed bundle: $signedBundle" + $signedBundles = @(Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File) + Write-Verbose -Verbose "Signed bundles: $($signedBundles.Name -join ', ')" if (-not (Test-Path $(ob_outputDirectory))) { New-Item -ItemType Directory -Path $(ob_outputDirectory) -Force } - Copy-Item -Path $signedBundle.FullName -Destination "$(ob_outputDirectory)" -Verbose + foreach ($bundle in $signedBundles) { + Copy-Item -Path $bundle.FullName -Destination "$(ob_outputDirectory)" -Verbose + } - Write-Verbose -Verbose "Uploaded Bundle:" + Write-Verbose -Verbose "Uploaded Bundles:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose displayName: Upload msixbundle to Artifacts @@ -224,6 +253,29 @@ jobs: Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" + # Select the correct bundle based on channel + $bundleFiles = @(Get-ChildItem -Path '$(BundleDir)' -Filter '*.msixbundle') + Write-Verbose -Verbose "Available bundles: $($bundleFiles.Name -join ', ')" + + if ($IsLTS) { + $bundleFile = $bundleFiles | Where-Object { $_.Name -match '-LTS-' } + } else { + # Catches Stable or Preview + $bundleFile = $bundleFiles | Where-Object { $_.Name -notmatch '-LTS-' } + } + + if (-not $bundleFile) { + Write-Error "No matching bundle found for channel '$currentChannel'. Available bundles: $($bundleFiles.Name -join ', ')" + exit 1 + } + + # Copy the selected bundle to a dedicated directory for store packaging + $storeBundleDir = '$(Pipeline.Workspace)\releasePipeline\msix\store-bundle' + New-Item $storeBundleDir -Type Directory -Force > $null + Copy-Item -Path $bundleFile.FullName -Destination $storeBundleDir -Force -Verbose + Write-Host "##vso[task.setvariable variable=StoreBundleDir]$storeBundleDir" + Write-Verbose -Verbose "Selected bundle for store packaging: $($bundleFile.Name)" + # These variables are used in the next tasks to determine which ServiceEndpoint to use Write-Host "##vso[task.setvariable variable=LTS]$($IsLTS.ToString().ToLower())" Write-Host "##vso[task.setvariable variable=STABLE]$($IsStable.ToString().ToLower())" @@ -244,7 +296,7 @@ jobs: inputs: serviceEndpoint: 'StoreAppPublish-Preview' sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(BundleDir)' + sourceFolder: '$(StoreBundleDir)' contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' @@ -256,7 +308,7 @@ jobs: inputs: serviceEndpoint: 'StoreAppPublish-Stable' sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(BundleDir)' + sourceFolder: '$(StoreBundleDir)' contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index d163b69eb23..13ed80ee123 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -136,12 +136,14 @@ jobs: # Don't build LTS packages for rebuild branches $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + $Stable = [bool]$metadata.StableRelease.Package if ($isRebuildBranch) { Write-Verbose -Message "Rebuild branch detected, skipping LTS package build" -Verbose } Write-Verbose -Verbose "LTS: $LTS" + Write-Verbose -Verbose "Stable: $Stable" if ($LTS) { Write-Verbose -Message "LTS Release: $LTS" @@ -175,6 +177,12 @@ jobs: Start-PSPackage -Type $packageTypes -SkipReleaseChecks -WindowsRuntime $WindowsRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$LTS + # When both LTS and Stable are requested, also build the Stable MSIX + if ($packageTypes -contains 'msix' -and $LTS -and $Stable) { + Write-Verbose -Verbose "Both LTS and Stable packages requested. Building additional Stable MSIX." + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $WindowsRuntime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath + } + displayName: 'Build Packages (Unsigned)' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 51498d7b04b..1e03d983c48 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4274,18 +4274,8 @@ function New-MSIXPackage $makepri = Get-Item (Join-Path $makeappx.Directory "makepri.exe") -ErrorAction Stop + $displayName = $ProductName $ProductSemanticVersion = Get-PackageSemanticVersion -Version $ProductVersion - $productSemanticVersionWithName = $ProductName + '-' + $ProductSemanticVersion - $packageName = $productSemanticVersionWithName - if ($Private) { - $ProductNameSuffix = 'Private' - } - - if ($ProductNameSuffix) { - $packageName += "-$ProductNameSuffix" - } - - $displayName = $productName if ($Private) { $ProductName = 'PowerShell-Private' @@ -4301,6 +4291,13 @@ function New-MSIXPackage Write-Verbose -Verbose "ProductName: $productName" Write-Verbose -Verbose "DisplayName: $displayName" + $packageName = $ProductName + '-' + $ProductSemanticVersion + + # Appends Architecture to the package name + if ($ProductNameSuffix) { + $packageName += "-$ProductNameSuffix" + } + $ProductVersion = Get-WindowsVersion -PackageName $packageName # Any app that is submitted to the Store must have a PhoneIdentity in its appxmanifest. From 30d30ab6249259100b5f3e68a0be4a05cfa5568f Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:17:01 -0700 Subject: [PATCH 089/127] [release/v7.6.1] Separate Official and NonOfficial templates for ADO pipelines (#27176) --- .github/agents/SplitADOPipelines.agent.md | 164 ++++++++ ...Shell-Coordinated_Packages-NonOfficial.yml | 97 +++++ .../PowerShell-Packages-NonOfficial.yml | 97 +++++ .../PowerShell-Release-Azure-NonOfficial.yml | 76 ++++ .../PowerShell-Release-NonOfficial.yml | 106 ++++++ .../PowerShell-vPack-NonOfficial.yml | 88 +++++ ...werShell-Coordinated_Packages-Official.yml | 247 +----------- .pipelines/PowerShell-Packages-Official.yml | 227 +---------- .../PowerShell-Release-Official-Azure.yml | 34 +- .pipelines/PowerShell-Release-Official.yml | 358 +----------------- .pipelines/PowerShell-vPack-Official.yml | 268 +------------ .pipelines/templates/release-MSIX-Publish.yml | 2 +- .pipelines/templates/release-githubNuget.yml | 4 +- ...PowerShell-Coordinated_Packages-Stages.yml | 202 ++++++++++ .../stages/PowerShell-Packages-Stages.yml | 186 +++++++++ .../stages/PowerShell-Release-Stages.yml | 323 ++++++++++++++++ .../stages/PowerShell-vPack-Stages.yml | 236 ++++++++++++ ...erShell-Coordinated_Packages-Variables.yml | 67 ++++ .../PowerShell-Packages-Variables.yml | 50 +++ .../PowerShell-Release-Azure-Variables.yml | 35 ++ .../PowerShell-Release-Variables.yml | 41 ++ .../variables/PowerShell-vPack-Variables.yml | 39 ++ .../release-shared.yml | 0 23 files changed, 1858 insertions(+), 1089 deletions(-) create mode 100644 .github/agents/SplitADOPipelines.agent.md create mode 100644 .pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml create mode 100644 .pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml create mode 100644 .pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml create mode 100644 .pipelines/templates/stages/PowerShell-Packages-Stages.yml create mode 100644 .pipelines/templates/stages/PowerShell-Release-Stages.yml create mode 100644 .pipelines/templates/stages/PowerShell-vPack-Stages.yml create mode 100644 .pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-Packages-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-Release-Variables.yml create mode 100644 .pipelines/templates/variables/PowerShell-vPack-Variables.yml rename .pipelines/templates/{variable => variables}/release-shared.yml (100%) diff --git a/.github/agents/SplitADOPipelines.agent.md b/.github/agents/SplitADOPipelines.agent.md new file mode 100644 index 00000000000..8322f473e7b --- /dev/null +++ b/.github/agents/SplitADOPipelines.agent.md @@ -0,0 +1,164 @@ +--- +name: SplitADOPipelines +description: This agent will implement and restructure the repository's existing ADO pipelines into Official and NonOfficial pipelines. +tools: ['vscode', 'execute', 'read', 'agent', 'edit', 'search', 'todo'] +--- + +This agent will implement and restructure the repository's existing ADO pipelines into Official and NonOfficial pipelines. + +A repository will have under the ./pipelines directory a series of yaml files that define the ADO pipelines for the repository. + +First confirm if the pipelines are using a toggle switch for Official and NonOfficial. This will look something like this + +```yaml +parameters: + - name: templateFile + value: ${{ iif ( parameters.OfficialBuild, 'v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates', 'v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates' ) }} +``` + +Followed by: + +```yaml +extends: + template: ${{ variables.templateFile }} +``` + +This is an indicator that this work needs to be done. This toggle switch is no longer allowed and the templates need to be hard coded. + +## Refactoring Steps + +### Step 1: Extract Shared Templates + +For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Packages.yml`): + +1. Create a `./pipelines/templates` directory if it doesn't exist +2. Extract the **variables section** into `./pipelines/templates/PowerShell-Packages-Variables.yml` +3. Extract the **stages section** into `./pipelines/templates/PowerShell-Packages-Stages.yml` + +**IMPORTANT**: Only extract the `variables:` and `stages:` sections. All other sections (parameters, resources, extends, etc.) remain in the pipeline files. + +### Step 2: Create Official Pipeline (In-Place Refactoring) + +The original toggle-based file becomes the Official pipeline: + +1. **Keep the file in its original location** (e.g., `./pipelines/PowerShell-Packages.yml` stays where it is) +2. Remove the toggle switch parameter (`templateFile` parameter) +3. Hard-code the Official template reference: + ```yaml + extends: + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates + ``` +4. Replace the `variables:` section with a template reference: + ```yaml + variables: + - template: templates/PowerShell-Packages-Variables.yml + ``` +5. Replace the `stages:` section with a template reference: + ```yaml + stages: + - template: templates/PowerShell-Packages-Stages.yml + ``` + +### Step 3: Create NonOfficial Pipeline + +1. Create `./pipelines/NonOfficial` directory if it doesn't exist +2. Create the NonOfficial pipeline file (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`) +3. Copy the structure from the refactored Official pipeline +4. Hard-code the NonOfficial template reference: + ```yaml + extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + ``` +5. Reference the same shared templates: + ```yaml + variables: + - template: ../templates/PowerShell-Packages-Variables.yml + + stages: + - template: ../templates/PowerShell-Packages-Stages.yml + ``` + +**Note**: The NonOfficial pipeline uses `../templates/` because it's one directory deeper than the Official pipeline. + +### Step 4: Link NonOfficial Pipelines to NonOfficial Dependencies + +After creating NonOfficial pipelines, ensure they consume artifacts from other **NonOfficial** pipelines, not Official ones. + +1. **Check the `resources:` section** in each NonOfficial pipeline for `pipelines:` dependencies +2. **Identify Official pipeline references** that need to be changed to NonOfficial +3. **Update the `source:` field** to point to the NonOfficial version + +**Example Problem:** NonOfficial pipeline pointing to Official dependency +```yaml +resources: + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated Binaries-Official' # ❌ Wrong - Official! +``` + +**Solution:** Update to NonOfficial dependency +```yaml +resources: + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated Binaries-NonOfficial' # ✅ Correct - NonOfficial! +``` + +**IMPORTANT**: The `source:` field must match the **exact ADO pipeline definition name** as it appears in Azure DevOps, not necessarily the file name. + +### Step 5: Configure Release Environment Parameters (NonAzure Only) + +**This step only applies if the pipeline uses `category: NonAzure` in the release configuration.** + +If you detect this pattern in the original pipeline: + +```yaml +extends: + template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates # or NonOfficial + parameters: + release: + category: NonAzure +``` + +Then you must configure the `ob_release_environment` parameter when referencing the stages template. + +#### Official Pipeline Configuration + +In the Official pipeline (e.g., `./pipelines/PowerShell-Packages.yml`): + +```yaml +stages: + - template: templates/PowerShell-Packages-Stages.yml + parameters: + ob_release_environment: Production +``` + +#### NonOfficial Pipeline Configuration + +In the NonOfficial pipeline (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`): + +```yaml +stages: + - template: ../templates/PowerShell-Packages-Stages.yml + parameters: + ob_release_environment: Test +``` + +#### Update Stages Template to Accept Parameter + +The extracted stages template (e.g., `./pipelines/templates/PowerShell-Packages-Stages.yml`) must declare the parameter at the top: + +```yaml +parameters: + - name: ob_release_environment + type: string + +stages: + # ... rest of stages configuration using ${{ parameters.ob_release_environment }} +``` + +**IMPORTANT**: +- Only configure this for pipelines with `category: NonAzure` +- Official pipelines always use `ob_release_environment: Production` +- NonOfficial pipelines always use `ob_release_environment: Test` +- The stages template must accept this parameter and use it in the appropriate stage configurations diff --git a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml new file mode 100644 index 00000000000..55d4c4557d8 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml @@ -0,0 +1,97 @@ +trigger: none + +parameters: + - name: InternalSDKBlobURL + displayName: URL to the blob having internal .NET SDK + type: string + default: ' ' + - name: ReleaseTagVar + displayName: Release Tag + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + displayName: Debugging - Skip Signing + type: string + default: 'NO' + - name: RUN_TEST_AND_RELEASE + displayName: Debugging - Run Test and Release Artifacts Stage + type: boolean + default: true + - name: RUN_WINDOWS + displayName: Debugging - Enable Windows Stage + type: boolean + default: true + - name: ENABLE_MSBUILD_BINLOGS + displayName: Debugging - Enable MSBuild Binary Logs + type: boolean + default: false + - name: FORCE_CODEQL + displayName: Debugging - Enable CodeQL and set cadence to 1 hour + type: boolean + default: false + +name: bins-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +resources: + repositories: + - repository: ComplianceRepo + type: github + endpoint: ComplianceGHRepo + name: PowerShell/compliance + ref: master + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +variables: + - template: ../templates/variables/PowerShell-Coordinated_Packages-Variables.yml + parameters: + InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + SKIP_SIGNING: ${{ parameters.SKIP_SIGNING }} + ENABLE_MSBUILD_BINLOGS: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} + FORCE_CODEQL: ${{ parameters.FORCE_CODEQL }} + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + customTags: 'ES365AIMigrationTooling' + featureFlags: + LinuxHostVersion: + Network: KS3 + WindowsHostVersion: + Network: KS3 + incrementalSDLBinaryAnalysis: true + globalSdl: + disableLegacyManifest: true + # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + sbom: + enabled: true + codeql: + compiled: + enabled: $(CODEQL_ENABLED) + tsaEnabled: true # This enables TSA bug filing only for CodeQL 3000 + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + cg: + enabled: true + ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config\tsaoptions.json + + stages: + - template: ../templates/stages/PowerShell-Coordinated_Packages-Stages.yml + parameters: + RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} + RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} + OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml new file mode 100644 index 00000000000..81f343a04a0 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml @@ -0,0 +1,97 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time + - name: ForceAzureBlobDelete + displayName: Delete Azure Blob + type: string + values: + - true + - false + default: false + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + - name: InternalSDKBlobURL + displayName: URL to the blob having internal .NET SDK + type: string + default: ' ' + - name: ReleaseTagVar + displayName: Release Tag + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + displayName: Skip Signing + type: string + default: 'NO' + - name: disableNetworkIsolation + type: boolean + default: false + +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +variables: + - template: ../templates/variables/PowerShell-Packages-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + disableNetworkIsolation: ${{ parameters.disableNetworkIsolation }} + +resources: + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated_Packages-NonOfficial' + trigger: + branches: + include: + - master + - releases/* + + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + cloudvault: + enabled: false + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: KS3 + LinuxHostVersion: + Network: KS3 + linuxEsrpSigning: true + incrementalSDLBinaryAnalysis: true + disableNetworkIsolation: ${{ variables.disableNetworkIsolation }} + globalSdl: + disableLegacyManifest: true + # disabled Armorty as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + sbom: + enabled: true + compiled: + enabled: false + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + cg: + enabled: true + ignoreDirectories: '.devcontainer,demos,docker,docs,src,test,tools/packaging' + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config\tsaoptions.json + stages: + - template: ../templates/stages/PowerShell-Packages-Stages.yml + parameters: + OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml new file mode 100644 index 00000000000..681babb2220 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -0,0 +1,76 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + - name: skipPublish + displayName: Skip PMC Publish + type: boolean + default: false + - name: SKIP_SIGNING + displayName: Skip Signing + type: string + default: 'NO' + +name: ev2-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +variables: + - template: ../templates/variables/PowerShell-Release-Azure-Variables.yml + parameters: + debug: ${{ parameters.debug }} + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated_Packages-NonOfficial' + + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-NonOfficial' + trigger: + branches: + include: + - master + - releases/* + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: Netlock + linuxEsrpSigning: true + incrementalSDLBinaryAnalysis: true + cloudvault: + enabled: false + globalSdl: + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + tsa: + enabled: true + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + break: false # always break the build on binskim issues in addition to TSA upload + exactToolVersion: 4.4.2 + policheck: + break: true # always break the build on policheck issues. You can disable it by setting to 'false' + tsaOptionsFile: .config\tsaoptions.json + stages: + - template: /.pipelines/templates/release-prep-for-ev2.yml@self + parameters: + skipPublish: ${{ parameters.skipPublish }} + + - template: /.pipelines/templates/release-publish-pmc.yml@self diff --git a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml new file mode 100644 index 00000000000..ca5a6383f33 --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml @@ -0,0 +1,106 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + - name: InternalSDKBlobURL + displayName: URL to the blob having internal .NET SDK + type: string + default: ' ' + - name: ReleaseTagVar + displayName: Release Tag + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + displayName: Skip Signing + type: string + default: 'NO' + - name: SkipPublish + displayName: Skip Publishing to Nuget + type: boolean + default: false + - name: SkipPSInfraInstallers + displayName: Skip Copying Archives and Installers to PSInfrastructure Public Location + type: boolean + default: false + - name: skipMSIXPublish + displayName: Skip MSIX Publish + type: boolean + default: false + +name: release-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) + +variables: + - template: ../templates/variables/PowerShell-Release-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + - repository: PSInternalTools + type: git + name: PowerShellCore/Internal-PowerShellTeam-Tools + ref: refs/heads/master + + pipelines: + - pipeline: CoOrdinatedBuildPipeline + source: 'PowerShell-Coordinated_Packages-NonOfficial' + + # NOTE: The alias name "PSPackagesOfficial" is intentionally reused here even + # for the NonOfficial pipeline source. Downstream shared templates (for example, + # release-validate-sdk.yml and release-upload-buildinfo.yml) reference artifacts + # using `download: PSPackagesOfficial`, so changing this alias would break them. + - pipeline: PSPackagesOfficial + source: 'PowerShell-Packages-NonOfficial' + trigger: + branches: + include: + - master + - releases/* + +extends: + template: v2/OneBranch.NonOfficial.CrossPlat.yml@onebranchTemplates + parameters: + release: + category: NonAzure + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: KS3 + incrementalSDLBinaryAnalysis: true + cloudvault: + enabled: false + globalSdl: + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + tsa: + enabled: true + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + break: false # always break the build on binskim issues in addition to TSA upload + exactToolVersion: 4.4.2 + policheck: + break: true # always break the build on policheck issues. You can disable it by setting to 'false' + # suppression: + # suppressionFile: $(Build.SourcesDirectory)\.gdn\global.gdnsuppress + tsaOptionsFile: .config\tsaoptions.json + + stages: + - template: ../templates/stages/PowerShell-Release-Stages.yml + parameters: + releaseEnvironment: Test + SkipPublish: ${{ parameters.SkipPublish }} + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} diff --git a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml new file mode 100644 index 00000000000..642b169adaf --- /dev/null +++ b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml @@ -0,0 +1,88 @@ +trigger: none + +parameters: # parameters are shown up in ADO UI in a build queue time +- name: 'createVPack' + displayName: 'Create and Submit VPack' + type: boolean + default: true +- name: vPackName + type: string + displayName: 'VPack Name:' + default: 'PowerShell.BuildTool' + values: + - PowerShell.BuildTool + - PowerShell + - PowerShellDoNotUse +- name: 'ReleaseTagVar' + type: string + displayName: 'Release Tag Var:' + default: 'fromBranch' +- name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false +- name: netiso + displayName: "Network Isolation Policy" + type: string + values: + - KS4 + - R1 + - Netlock + default: "R1" + +name: vPack_$(Build.SourceBranchName)_NonOfficial_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) + +variables: + - template: ../templates/variables/PowerShell-vPack-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + netiso: ${{ parameters.netiso }} + +resources: + repositories: + - repository: onebranchTemplates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/Microsoft.NonOfficial.yml@onebranchTemplates + parameters: + platform: + name: 'windows_undocked' # windows undocked + + featureFlags: + WindowsHostVersion: + Version: 2022 + Network: ${{ variables.netiso }} + + cloudvault: + enabled: false + + globalSdl: + useCustomPolicy: true # for signing code + disableLegacyManifest: true + # disabled Armory as we dont have any ARM templates to scan. It fails on some sample ARM templates. + armory: + enabled: false + sbom: + enabled: true + compiled: + enabled: false + credscan: + enabled: true + scanFolder: $(Build.SourcesDirectory) + suppressionsFile: $(Build.SourcesDirectory)\.config\suppress.json + binskim: + enabled: false + exactToolVersion: 4.4.2 + # APIScan requires a non-Ready-To-Run build + apiscan: + enabled: false + tsaOptionsFile: .config/tsaoptions.json + stages: + - template: ../templates/stages/PowerShell-vPack-Stages.yml + parameters: + createVPack: ${{ parameters.createVPack }} + vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/PowerShell-Coordinated_Packages-Official.yml b/.pipelines/PowerShell-Coordinated_Packages-Official.yml index 12460e2861c..82f129a0a5e 100644 --- a/.pipelines/PowerShell-Coordinated_Packages-Official.yml +++ b/.pipelines/PowerShell-Coordinated_Packages-Official.yml @@ -30,7 +30,7 @@ parameters: type: boolean default: false -name: bins-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: bins-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) resources: repositories: @@ -45,57 +45,13 @@ resources: ref: refs/heads/main variables: - - name: PS_RELEASE_BUILD - value: 1 - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: branchCounterKey - value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - - name: branchCounter - value: $[counter(variables['branchCounterKey'], 1)] - - name: BUILDSECMON_OPT_IN - value: true - - name: __DOTNET_RUNTIME_FEED - value: ${{ parameters.InternalSDKBlobURL }} - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - name: WindowsContainerImage - value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - name: SKIP_SIGNING - value: ${{ parameters.SKIP_SIGNING }} - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - name: ENABLE_MSBUILD_BINLOGS - value: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} - - ${{ if eq(parameters['FORCE_CODEQL'],'true') }}: - # Cadence is hours before CodeQL will allow a re-upload of the database - - name: CodeQL.Cadence - value: 1 - - name: CODEQL_ENABLED - ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters['FORCE_CODEQL'],'true')) }}: - value: true - ${{ else }}: - value: false - # Fix for BinSkim ICU package error in Linux containers - - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT - value: true - # Disable BinSkim at job level to override NonOfficial template defaults - - name: ob_sdl_binskim_enabled - value: false - - name: ps_official_build - value: true + - template: templates/variables/PowerShell-Coordinated_Packages-Variables.yml + parameters: + InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + SKIP_SIGNING: ${{ parameters.SKIP_SIGNING }} + ENABLE_MSBUILD_BINLOGS: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} + FORCE_CODEQL: ${{ parameters.FORCE_CODEQL }} extends: template: v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates @@ -135,185 +91,8 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - stage: prep - jobs: - - job: SetVars - displayName: Set Variables - pool: - type: linux - - variables: - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/BuildJson' - - name: ob_sdl_codeSignValidation_enabled - value: false - - name: ob_sdl_codeql_compiled_enabled - value: false - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_signing_setup_enabled - value: false - - name: ob_sdl_sbom_enabled - value: false - - steps: - - checkout: self - clean: true - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - - - pwsh: | - Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: Capture environment variables - env: - ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase - - - template: /.pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - - - stage: macos - displayName: macOS - build and sign - dependsOn: ['prep'] - jobs: - - template: /.pipelines/templates/mac.yml@self - parameters: - buildArchitecture: x64 - - template: /.pipelines/templates/mac.yml@self - parameters: - buildArchitecture: arm64 - - - stage: linux - displayName: linux - build and sign - dependsOn: ['prep'] - jobs: - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-x64' - JobName: 'linux_x64' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-x64' - JobName: 'linux_x64_minSize' - BuildConfiguration: 'minSize' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-arm' - JobName: 'linux_arm' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-arm64' - JobName: 'linux_arm64' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent-linux-x64' - JobName: 'linux_fxd_x64_mariner' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent-linux-arm64' - JobName: 'linux_fxd_arm64_mariner' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent-noopt-linux-musl-x64' - JobName: 'linux_fxd_x64_alpine' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'fxdependent' - JobName: 'linux_fxd' - - - template: /.pipelines/templates/linux.yml@self - parameters: - Runtime: 'linux-musl-x64' - JobName: 'linux_x64_alpine' - - - stage: windows - displayName: windows - build and sign - dependsOn: ['prep'] - condition: and(succeeded(),eq('${{ parameters.RUN_WINDOWS }}','true')) - jobs: - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: x64 - BuildConfiguration: release - JobName: build_windows_x64_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: x64 - BuildConfiguration: minSize - JobName: build_windows_x64_minSize_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: x86 - JobName: build_windows_x86_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: arm64 - JobName: build_windows_arm64_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: fxdependent - JobName: build_windows_fxdependent_release - - template: /.pipelines/templates/windows-hosted-build.yml@self - parameters: - Architecture: fxdependentWinDesktop - JobName: build_windows_fxdependentWinDesktop_release - - - stage: test_and_release_artifacts - displayName: Test and Release Artifacts - dependsOn: ['prep'] - condition: and(succeeded(),eq('${{ parameters.RUN_TEST_AND_RELEASE }}','true')) - jobs: - - template: /.pipelines/templates/testartifacts.yml@self - - - job: release_json - displayName: Create and Upload release.json - pool: - type: windows - variables: - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json - - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - steps: - - checkout: self - clean: true - - template: /.pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - template: /.pipelines/templates/rebuild-branch-check.yml@self - - powershell: | - $metadata = Get-Content '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -Raw | ConvertFrom-Json - - # Use the rebuild branch check from the template - $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' - - # Don't mark as LTS release for rebuild branches - $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch - - if ($isRebuildBranch) { - Write-Verbose -Message "Rebuild branch detected, not marking as LTS release" -Verbose - } - - @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" - Get-Content "$(Build.StagingDirectory)\release.json" - - if (-not (Test-Path "$(ob_outputDirectory)\metadata")) { - New-Item -ItemType Directory -Path "$(ob_outputDirectory)\metadata" - } - - Copy-Item -Path "$(Build.StagingDirectory)\release.json" -Destination "$(ob_outputDirectory)\metadata" -Force - displayName: Create and upload release.json file to build artifact - retryCountOnTaskFailure: 2 - - template: /.pipelines/templates/step/finalize.yml@self + - template: templates/stages/PowerShell-Coordinated_Packages-Stages.yml + parameters: + RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} + RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} + OfficialBuild: true diff --git a/.pipelines/PowerShell-Packages-Official.yml b/.pipelines/PowerShell-Packages-Official.yml index a13ef12378a..8afce29ede7 100644 --- a/.pipelines/PowerShell-Packages-Official.yml +++ b/.pipelines/PowerShell-Packages-Official.yml @@ -28,44 +28,15 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: pkgs-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] # needed for onebranch.pipeline.version task - - name: system.debug - value: ${{ parameters.debug }} - - name: ENABLE_PRS_DELAYSIGN - value: 1 - - name: ROOT - value: $(Build.SourcesDirectory) - - name: ForceAzureBlobDelete - value: ${{ parameters.ForceAzureBlobDelete }} - - name: NUGET_XMLDOC_MODE - value: none - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - group: mscodehub-feed-read-general - - group: mscodehub-feed-read-akv - - name: branchCounterKey - value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] - - name: branchCounter - value: $[counter(variables['branchCounterKey'], 1)] - - group: MSIXSigningProfile - - name: disableNetworkIsolation - value: ${{ parameters.disableNetworkIsolation }} + - template: templates/variables/PowerShell-Packages-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + disableNetworkIsolation: ${{ parameters.disableNetworkIsolation }} resources: pipelines: @@ -121,184 +92,6 @@ extends: enabled: false tsaOptionsFile: .config\tsaoptions.json stages: - - stage: prep - displayName: 'Prep BuildInfo+Az' - jobs: - - template: /.pipelines/templates/checkAzureContainer.yml@self - - - stage: mac_package - displayName: 'macOS Pkg+Sign' - dependsOn: [] - jobs: - - template: /.pipelines/templates/mac-package-build.yml@self - parameters: - buildArchitecture: x64 - - - template: /.pipelines/templates/mac-package-build.yml@self - parameters: - buildArchitecture: arm64 - - - stage: windows_package_build - displayName: 'Win Pkg (unsigned)' - dependsOn: [] - jobs: - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: x64 - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: arm64 - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: x86 - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: fxdependent - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: fxdependentWinDesktop - - - template: /.pipelines/templates/packaging/windows/package.yml@self - parameters: - runtime: minsize - - - stage: windows_package_sign - displayName: 'Win Pkg Sign' - dependsOn: [windows_package_build] - jobs: - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: x64 - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: arm64 - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: x86 - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: fxdependent - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: fxdependentWinDesktop - - - template: /.pipelines/templates/packaging/windows/sign.yml@self - parameters: - runtime: minsize - - - stage: linux_package - displayName: 'Linux Pkg+Sign' - dependsOn: [] - jobs: - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64' - signedDrop: 'drop_linux_sign_linux_x64' - packageType: deb - jobName: deb - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd_x64_mariner' - signedDrop: 'drop_linux_sign_linux_fxd_x64_mariner' - packageType: rpm-fxdependent #mariner-x64 - jobName: mariner_x64 - signingProfile: 'CP-459159-pgpdetached' - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd_arm64_mariner' - signedDrop: 'drop_linux_sign_linux_fxd_arm64_mariner' - packageType: rpm-fxdependent-arm64 #mariner-arm64 - jobName: mariner_arm64 - signingProfile: 'CP-459159-pgpdetached' - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64' - signedDrop: 'drop_linux_sign_linux_x64' - packageType: rpm - jobName: rpm - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_arm' - signedDrop: 'drop_linux_sign_linux_arm' - packageType: tar-arm - jobName: tar_arm - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_arm64' - signedDrop: 'drop_linux_sign_linux_arm64' - packageType: tar-arm64 - jobName: tar_arm64 - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64_alpine' - signedDrop: 'drop_linux_sign_linux_x64_alpine' - packageType: tar-alpine - jobName: tar_alpine - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd' - signedDrop: 'drop_linux_sign_linux_fxd' - packageType: fxdependent - jobName: fxdependent - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64' - signedDrop: 'drop_linux_sign_linux_x64' - packageType: tar - jobName: tar - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_fxd_x64_alpine' - signedDrop: 'drop_linux_sign_linux_fxd_x64_alpine' - packageType: tar-alpine-fxdependent - jobName: tar_alpine_fxd - - - template: /.pipelines/templates/linux-package-build.yml@self - parameters: - unsignedDrop: 'drop_linux_build_linux_x64_minSize' - signedDrop: 'drop_linux_sign_linux_x64_minSize' - packageType: min-size - jobName: minSize - - - stage: nupkg - displayName: 'NuGet Pkg+Sign' - dependsOn: [] - jobs: - - template: /.pipelines/templates/nupkg.yml@self - - - stage: msixbundle - displayName: 'MSIX Bundle+Sign' - dependsOn: [windows_package_build] # Only depends on unsigned packages - jobs: - - template: /.pipelines/templates/package-create-msix.yml@self - parameters: - OfficialBuild: true - - - stage: upload - displayName: 'Upload' - dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON - jobs: - - template: /.pipelines/templates/uploadToAzure.yml@self - - - stage: validatePackages - displayName: 'Validate Packages' - dependsOn: [upload] - jobs: - - template: /.pipelines/templates/release-validate-packagenames.yml@self + - template: templates/stages/PowerShell-Packages-Stages.yml + parameters: + OfficialBuild: true diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 81543420460..24040a2463d 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -14,38 +14,12 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: string default: 'NO' -name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: ev2-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: system.debug - value: ${{ parameters.debug }} - - name: ENABLE_PRS_DELAYSIGN - value: 1 - - name: ROOT - value: $(Build.SourcesDirectory) - - name: REPOROOT - value: $(Build.SourcesDirectory) - - name: OUTPUTROOT - value: $(REPOROOT)\out - - name: NUGET_XMLDOC_MODE - value: none - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: ob_sdl_tsa_configFile - value: $(Build.SourcesDirectory)\.config\tsaoptions.json - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - group: PoolNames + - template: templates/variables/PowerShell-Release-Azure-Variables.yml + parameters: + debug: ${{ parameters.debug }} resources: repositories: diff --git a/.pipelines/PowerShell-Release-Official.yml b/.pipelines/PowerShell-Release-Official.yml index fa14b9b0acb..3528e6b1471 100644 --- a/.pipelines/PowerShell-Release-Official.yml +++ b/.pipelines/PowerShell-Release-Official.yml @@ -30,43 +30,13 @@ parameters: # parameters are shown up in ADO UI in a build queue time type: boolean default: false -name: release-$(BUILD.SOURCEBRANCHNAME)-prod.true-$(Build.BuildId) +name: release-$(BUILD.SOURCEBRANCHNAME)-prod-$(Build.BuildId) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: system.debug - value: ${{ parameters.debug }} - - name: ENABLE_PRS_DELAYSIGN - value: 1 - - name: ROOT - value: $(Build.SourcesDirectory) - - name: REPOROOT - value: $(Build.SourcesDirectory) - - name: OUTPUTROOT - value: $(REPOROOT)\out - - name: NUGET_XMLDOC_MODE - value: none - - name: nugetMultiFeedWarnLevel - value: none - - name: NugetSecurityAnalysisWarningLevel - value: none - - name: skipNugetSecurityAnalysis - value: true - - name: ob_outputDirectory - value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - - name: LinuxContainerImage - value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - group: PoolNames - - name: releaseEnvironment - value: 'Production' - # Fix for BinSkim ICU package error in Linux containers - - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT - value: true + - template: templates/variables/PowerShell-Release-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} resources: repositories: @@ -124,315 +94,9 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - stage: setReleaseTagAndChangelog - displayName: 'Set Release Tag and Upload Changelog' - jobs: - - template: /.pipelines/templates/release-SetTagAndChangelog.yml@self - - - stage: validateSdk - displayName: 'Validate SDK' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-sdk.yml@self - parameters: - jobName: "windowsSDK" - displayName: "Windows SDK Validation" - imageName: PSMMS2019-Secure - poolName: $(windowsPool) - - - template: /.pipelines/templates/release-validate-sdk.yml@self - parameters: - jobName: "MacOSSDK" - displayName: "MacOS SDK Validation" - imageName: macOS-latest - poolName: Azure Pipelines - - - template: /.pipelines/templates/release-validate-sdk.yml@self - parameters: - jobName: "LinuxSDK" - displayName: "Linux SDK Validation" - imageName: PSMMSUbuntu22.04-Secure - poolName: $(ubuntuPool) - - - stage: gbltool - displayName: 'Validate Global tools' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-globaltools.yml@self - parameters: - jobName: "WindowsGlobalTools" - displayName: "Windows Global Tools Validation" - jobtype: windows - - - template: /.pipelines/templates/release-validate-globaltools.yml@self - parameters: - jobName: "LinuxGlobalTools" - displayName: "Linux Global Tools Validation" - jobtype: linux - globalToolExeName: 'pwsh' - globalToolPackageName: 'PowerShell.Linux.x64' - - - stage: fxdpackages - displayName: 'Validate FXD Packages' - dependsOn: [] - jobs: - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'winfxd' - displayName: 'Validate Win Fxd Packages' - jobtype: 'windows' - artifactName: 'drop_windows_package_package_win_fxdependent' - packageNamePattern: '**/*win-fxdependent.zip' - - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'winfxdDesktop' - displayName: 'Validate WinDesktop Fxd Packages' - jobtype: 'windows' - artifactName: 'drop_windows_package_package_win_fxdependentWinDesktop' - packageNamePattern: '**/*win-fxdependentwinDesktop.zip' - - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'linuxfxd' - displayName: 'Validate Linux Fxd Packages' - jobtype: 'linux' - artifactName: 'drop_linux_package_fxdependent' - packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' - - - template: /.pipelines/templates/release-validate-fxdpackages.yml@self - parameters: - jobName: 'linuxArm64fxd' - displayName: 'Validate Linux ARM64 Fxd Packages' - jobtype: 'linux' - artifactName: 'drop_linux_package_fxdependent' - # this is really an architecture independent package - packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' - arm64: 'yes' - enableCredScan: false - - - stage: ManualValidation - dependsOn: [] - displayName: Manual Validation - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Validate Windows Packages - jobName: ValidateWinPkg - instructions: | - Validate zip package on windows - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Validate OSX Packages - jobName: ValidateOsxPkg - instructions: | - Validate tar.gz package on osx-arm64 - - - stage: ReleaseAutomation - dependsOn: [] - displayName: 'Release Automation' - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Start Release Automation - jobName: StartRA - instructions: | - Kick off Release automation build at: https://dev.azure.com/powershell-rel/Release-Automation/_build?definitionId=10&_a=summary - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Triage results - jobName: TriageRA - dependsOnJob: StartRA - instructions: | - Triage ReleaseAutomation results - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Signoff Tests - dependsOnJob: TriageRA - jobName: SignoffTests - instructions: | - Signoff ReleaseAutomation results - - - stage: UpdateChangeLog - displayName: Update the changelog - dependsOn: - - ManualValidation - - ReleaseAutomation - - fxdpackages - - gbltool - - validateSdk - - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Make sure the changelog is updated - jobName: MergeChangeLog - instructions: | - Update and merge the changelog for the release. - This step is required for creating GitHub draft release. - - - stage: PublishGitHubReleaseAndNuget - displayName: Publish GitHub and Nuget Release - dependsOn: - - setReleaseTagAndChangelog - - UpdateChangeLog - variables: - ob_release_environment: ${{ variables.releaseEnvironment }} - jobs: - - template: /.pipelines/templates/release-githubNuget.yml@self - parameters: - skipPublish: ${{ parameters.SkipPublish }} - - - stage: PushGitTagAndMakeDraftPublic - displayName: Push Git Tag and Make Draft Public - dependsOn: PublishGitHubReleaseAndNuget - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Push Git Tag - jobName: PushGitTag - instructions: | - Push the git tag to upstream - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Make Draft Public - dependsOnJob: PushGitTag - jobName: DraftPublic - instructions: | - Make the GitHub Release Draft Public - - - stage: BlobPublic - displayName: Make Blob Public - dependsOn: - - UpdateChangeLog - - PushGitTagAndMakeDraftPublic - jobs: - - template: /.pipelines/templates/release-MakeBlobPublic.yml@self - parameters: - SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} - - - stage: PublishPMC - displayName: Publish PMC - dependsOn: PushGitTagAndMakeDraftPublic - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Publish to PMC - jobName: ReleaseToPMC - instructions: | - Run PowerShell-Release-Official-Azure.yml pipeline to publish to PMC - - - stage: UpdateDotnetDocker - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Update DotNet SDK Docker images - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Update .NET SDK docker images - jobName: DotnetDocker - instructions: | - Create PR for updating dotnet-docker images to use latest PowerShell version. - 1. Fork and clone https://github.com/dotnet/dotnet-docker.git - 2. git checkout upstream/nightly -b updatePS - 3. dotnet run --project .\eng\update-dependencies\ specific --product-version powershell= --compute-shas - 4. create PR targeting nightly branch - - - stage: UpdateWinGet - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Add manifest entry to winget - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Add manifest entry to winget - jobName: UpdateWinGet - instructions: | - This is typically done by the community 1-2 days after the release. - - - stage: PublishMsix - dependsOn: - - setReleaseTagAndChangelog - - PushGitTagAndMakeDraftPublic - displayName: Publish MSIX to store - variables: - ob_release_environment: ${{ variables.releaseEnvironment }} - jobs: - - template: /.pipelines/templates/release-MSIX-Publish.yml@self - parameters: - skipMSIXPublish: ${{ parameters.skipMSIXPublish }} - - - stage: PublishVPack - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Release vPack - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Start 2 vPack Release pipelines - jobName: PublishVPack - instructions: | - 1. Kick off PowerShell-vPack-Official pipeline - 2. Kick off PowerShell-MSIXBundle-VPack pipeline - - # Need to verify if the Az PS / CLI team still uses this. Skippinng for this release. - # - stage: ReleaseDeps - # dependsOn: GitHubTasks - # displayName: Update pwsh.deps.json links - # jobs: - # - template: templates/release-UpdateDepsJson.yml - - - stage: UploadBuildInfoJson - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Upload BuildInfo.json - jobs: - - template: /.pipelines/templates/release-upload-buildinfo.yml@self - - - stage: ReleaseSymbols - dependsOn: PushGitTagAndMakeDraftPublic - displayName: Release Symbols - jobs: - - template: /.pipelines/templates/release-symbols.yml@self - - - stage: ChangesToMaster - displayName: Ensure changes are in GH master - dependsOn: - - PublishPMC - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Make sure changes are in master - jobName: MergeToMaster - instructions: | - Make sure that changes README.md and metadata.json are merged into master on GitHub. - - - stage: ReleaseToMU - displayName: Release to MU - dependsOn: PushGitTagAndMakeDraftPublic # This only needs the blob to be available - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Release to MU - instructions: | - Notify the PM team to start the process of releasing to MU. - - - stage: ReleaseClose - displayName: Finish Release - dependsOn: - - ReleaseToMU - - ReleaseSymbols - jobs: - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Retain Build - jobName: RetainBuild - instructions: | - Retain the build - - - template: /.pipelines/templates/approvalJob.yml@self - parameters: - displayName: Delete release branch - jobName: DeleteBranch - instructions: | - Delete release + - template: templates/stages/PowerShell-Release-Stages.yml + parameters: + releaseEnvironment: Production + SkipPublish: ${{ parameters.SkipPublish }} + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} diff --git a/.pipelines/PowerShell-vPack-Official.yml b/.pipelines/PowerShell-vPack-Official.yml index f7faeb30656..9a7ff3b86e6 100644 --- a/.pipelines/PowerShell-vPack-Official.yml +++ b/.pipelines/PowerShell-vPack-Official.yml @@ -29,37 +29,14 @@ parameters: # parameters are shown up in ADO UI in a build queue time - Netlock default: "R1" -name: vPack_$(Build.SourceBranchName)_Prod.true_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) +name: vPack_$(Build.SourceBranchName)_Prod_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - - name: CDP_DEFINITION_BUILD_COUNT - value: $[counter('', 0)] - - name: system.debug - value: ${{ parameters.debug }} - - name: BuildSolution - value: $(Build.SourcesDirectory)\dirs.proj - - name: BuildConfiguration - value: Release - - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - - name: Codeql.Enabled - value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - - name: DOTNET_CLI_TELEMETRY_OPTOUT - value: 1 - - name: POWERSHELL_TELEMETRY_OPTOUT - value: 1 - - name: nugetMultiFeedWarnLevel - value: none - - name: ReleaseTagVar - value: ${{ parameters.ReleaseTagVar }} - - group: Azure Blob variable group - - group: certificate_logical_to_actual # used within signing task - - group: DotNetPrivateBuildAccess - - group: certificate_logical_to_actual - - name: netiso - value: ${{ parameters.netiso }} -# We shouldn't be using PATs anymore -# - group: mscodehub-feed-read-general + - template: templates/variables/PowerShell-vPack-Variables.yml + parameters: + debug: ${{ parameters.debug }} + ReleaseTagVar: ${{ parameters.ReleaseTagVar }} + netiso: ${{ parameters.netiso }} resources: repositories: @@ -104,232 +81,7 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - stage: BuildStage - jobs: - - job: BuildJob - pool: - type: windows - - strategy: - matrix: - x86: - architecture: x86 - - x64: - architecture: x64 - - arm64: - architecture: arm64 - - variables: - ArtifactPlatform: 'windows' - ob_artifactBaseName: drop_build_$(architecture) - ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' - ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_owneralias: tplunk - ob_createvpack_versionAs: parts - ob_createvpack_propsFile: true - ob_createvpack_verbose: true - ob_createvpack_packagename: '${{ parameters.vPackName }}.$(architecture)' - ob_createvpack_description: PowerShell $(architecture) $(version) - # I think the variables reload after we transition back to the host so this works. 🤷‍♂️ - ob_createvpack_majorVer: $(pwshMajorVersion) - ob_createvpack_minorVer: $(pwshMinorVersion) - ob_createvpack_patchVer: $(pwshPatchVersion) - ${{ if ne(variables['pwshPrereleaseVersion'], '') }}: - ob_createvpack_prereleaseVer: $(pwshPrereleaseVersion) - ${{ else }}: - ob_createvpack_prereleaseVer: $(Build.SourceVersion) - - steps: - - checkout: self - displayName: Checkout source code - during restore - clean: true - path: s - env: - ob_restore_phase: true - - - template: .pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: yes - - - pwsh: | - $version = '$(Version)' - Write-Verbose -Verbose "Version: $version" - if(!$version) { - throw "Version is not set." - } - - $mainVersionParts = $version -split '-' - - Write-Verbose -Verbose "mainVersionParts: $($mainVersionParts[0]) ; $($mainVersionParts[1])" - $versionParts = $mainVersionParts[0] -split '[.]'; - $major = $versionParts[0] - $minor = $versionParts[1] - $patch = $versionParts[2] - - $previewPart = $mainVersionParts[1] - Write-Verbose -Verbose "previewPart: $previewPart" - - Write-Host "major: $major; minor: $minor; patch: $patch;" - - $vstsCommandString = "vso[task.setvariable variable=pwshMajorVersion]$major" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $vstsCommandString = "vso[task.setvariable variable=pwshMinorVersion]$minor" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $vstsCommandString = "vso[task.setvariable variable=pwshPatchVersion]$patch" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - if($previewPart) { - $vstsCommandString = "vso[task.setvariable variable=pwshPrereleaseVersion]$previewPart" - } else { - Write-Verbose -Verbose "No prerelease part found in version string." - } - displayName: Set ob_createvpack_*Ver - env: - ob_restore_phase: true - - # Validate pwsh*Version variables - - pwsh: | - $variables = @("pwshMajorVersion", "pwshMinorVersion", "pwshPatchVersion") - foreach ($var in $variables) { - if (-not (get-item "Env:\$var" -ErrorAction SilentlyContinue).value) { - throw "Required variable '`$env:$var' is not set." - } - } - displayName: Validate pwsh*Version variables - env: - ob_restore_phase: true - - - pwsh: | - if($env:RELEASETAGVAR -match '-') { - throw "Don't release a preview build without coordinating with Windows Engineering Build Tools Team" - } - displayName: Stop any preview release - env: - ob_restore_phase: true - - - task: UseDotNet@2 - displayName: 'Use .NET Core sdk' - inputs: - packageType: sdk - version: 3.1.x - installationPath: $(Agent.ToolsDirectory)/dotnet - - ### BUILD ### - - - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self - parameters: - repoRoot: $(repoRoot) - - - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - inputs: - Enabled: true - AnalyzeInPipeline: false # Do not upload results - Language: csharp - - - task: UseDotNet@2 - displayName: 'Install .NET based on global.json' - inputs: - useGlobalJson: true - workingDirectory: $(repoRoot) - env: - ob_restore_phase: true - - - pwsh: | - # Need to set PowerShellRoot variable for obp-file-signing template - $vstsCommandString = "vso[task.setvariable variable=PowerShellRoot]$(repoRoot)" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - $Architecture = '$(Architecture)' - $runtime = switch ($Architecture) - { - "x64" { "win7-x64" } - "x86" { "win7-x86" } - "arm64" { "win-arm64" } - } - - $params = @{} - if ($env:BuildConfiguration -eq 'minSize') { - $params['ForMinimalSize'] = $true - } - - $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - - Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" - Import-Module -Name $(repoRoot)/build.psm1 -Force - $buildWithSymbolsPath = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/Symbols_$Architecture" -Force - - Start-PSBootstrap -Scenario Package - $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose - - $ReleaseTagParam = @{} - - if ($env:RELEASETAGVAR) { - $ReleaseTagParam['ReleaseTag'] = $env:RELEASETAGVAR - } - - Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore @params @ReleaseTagParam - - $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' - Write-Verbose -Verbose "refFolderPath: $refFolderPath" - $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' - $null = New-Item -ItemType Directory -Path $outputPath -Force - $psOptPath = "$outputPath/psoptions.json" - Save-PSOptions -PSOptionsPath $psOptPath - - Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" - displayName: Build Windows Universal - $(Architecture) -$(BuildConfiguration) Symbols folder - env: - __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - - - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. - env: - ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. - - - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - inputs: - sourceScanPath: '$(repoRoot)\src' - ob_restore_phase: true - - - template: /.pipelines/templates/obp-file-signing.yml@self - parameters: - binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' - SigningProfile: $(windows_build_tools_cert_id) - OfficialBuild: false - vPackScenario: true - - ### END OF BUILD ### - - - pwsh: | - Get-ChildItem env:/ob_createvpack_*Ver - Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse - Get-Content "$(Pipeline.Workspace)\PowerShell\preview.json" -ErrorAction SilentlyContinue | Write-Host - displayName: Debug Output Directory and Version - condition: succeededOrFailed() - - - pwsh: | - Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose - displayName: Capture Environment - condition: succeededOrFailed() - - - pwsh: | - $vpackFiles = Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse - if($vpackFiles.Count -eq 0) { - throw "No files found in $(Pipeline.Workspace)\Symbols_$(Architecture)" - } - $vpackFiles - displayName: Debug Output Directory and Version - condition: succeededOrFailed() + - template: templates/stages/PowerShell-vPack-Stages.yml + parameters: + createVPack: ${{ parameters.createVPack }} + vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index a92c71f826b..aaef3c6f269 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -21,7 +21,7 @@ jobs: value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsStable'] ] - name: PREVIEW value: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['ChannelSelection.IsPreview'] ] - - template: ./variable/release-shared.yml@self + - template: ./variables/release-shared.yml@self parameters: RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] steps: diff --git a/.pipelines/templates/release-githubNuget.yml b/.pipelines/templates/release-githubNuget.yml index 206079c555f..95698554c40 100644 --- a/.pipelines/templates/release-githubNuget.yml +++ b/.pipelines/templates/release-githubNuget.yml @@ -17,7 +17,7 @@ jobs: pipeline: PSPackagesOfficial artifactName: drop_upload_upload_packages variables: - - template: ./variable/release-shared.yml@self + - template: ./variables/release-shared.yml@self parameters: RELEASETAG: $[ stageDependencies.setReleaseTagAndChangelog.setTagAndChangelog.outputs['OutputReleaseTag.releaseTag'] ] @@ -167,7 +167,7 @@ jobs: pipeline: PSPackagesOfficial artifactName: drop_upload_upload_packages variables: - - template: ./variable/release-shared.yml@self + - template: ./variables/release-shared.yml@self parameters: VERSION: $[ stageDependencies.setReleaseTagAndChangelog.SetTagAndChangelog.outputs['OutputVersion.Version'] ] diff --git a/.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml new file mode 100644 index 00000000000..cd0a4ebc065 --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml @@ -0,0 +1,202 @@ +parameters: + - name: RUN_WINDOWS + type: boolean + default: true + - name: RUN_TEST_AND_RELEASE + type: boolean + default: true + - name: OfficialBuild + type: boolean + +stages: +- stage: prep + jobs: + - job: SetVars + displayName: Set Variables + pool: + type: linux + + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT/BuildJson' + - name: ob_sdl_codeSignValidation_enabled + value: false + - name: ob_sdl_codeql_compiled_enabled + value: false + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_sbom_enabled + value: false + + steps: + - checkout: self + clean: true + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + + - pwsh: | + Get-ChildItem Env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture environment variables + env: + ob_restore_phase: true # This ensures checkout is done at the beginning of the restore phase + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + +- stage: macos + displayName: macOS - build and sign + dependsOn: ['prep'] + variables: + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} + jobs: + - template: /.pipelines/templates/mac.yml@self + parameters: + buildArchitecture: x64 + - template: /.pipelines/templates/mac.yml@self + parameters: + buildArchitecture: arm64 + +- stage: linux + displayName: linux - build and sign + dependsOn: ['prep'] + variables: + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} + jobs: + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-x64' + JobName: 'linux_x64' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-x64' + JobName: 'linux_x64_minSize' + BuildConfiguration: 'minSize' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-arm' + JobName: 'linux_arm' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-arm64' + JobName: 'linux_arm64' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent-linux-x64' + JobName: 'linux_fxd_x64_mariner' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent-linux-arm64' + JobName: 'linux_fxd_arm64_mariner' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent-noopt-linux-musl-x64' + JobName: 'linux_fxd_x64_alpine' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'fxdependent' + JobName: 'linux_fxd' + + - template: /.pipelines/templates/linux.yml@self + parameters: + Runtime: 'linux-musl-x64' + JobName: 'linux_x64_alpine' + +- stage: windows + displayName: windows - build and sign + dependsOn: ['prep'] + condition: and(succeeded(),eq('${{ parameters.RUN_WINDOWS }}','true')) + variables: + - name: ps_official_build + value: ${{ parameters.OfficialBuild }} + jobs: + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: x64 + BuildConfiguration: release + JobName: build_windows_x64_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: x64 + BuildConfiguration: minSize + JobName: build_windows_x64_minSize_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: x86 + JobName: build_windows_x86_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: arm64 + JobName: build_windows_arm64_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: fxdependent + JobName: build_windows_fxdependent_release + - template: /.pipelines/templates/windows-hosted-build.yml@self + parameters: + Architecture: fxdependentWinDesktop + JobName: build_windows_fxdependentWinDesktop_release + +- stage: test_and_release_artifacts + displayName: Test and Release Artifacts + dependsOn: ['prep'] + condition: and(succeeded(),eq('${{ parameters.RUN_TEST_AND_RELEASE }}','true')) + jobs: + - template: /.pipelines/templates/testartifacts.yml@self + + - job: release_json + displayName: Create and Upload release.json + pool: + type: windows + variables: + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + steps: + - checkout: self + clean: true + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + - template: /.pipelines/templates/rebuild-branch-check.yml@self + - powershell: | + $metadata = Get-Content '$(Build.SourcesDirectory)/PowerShell/tools/metadata.json' -Raw | ConvertFrom-Json + + # Use the rebuild branch check from the template + $isRebuildBranch = '$(RebuildBranchCheck.IsRebuildBranch)' -eq 'true' + + # Don't mark as LTS release for rebuild branches + $LTS = $metadata.LTSRelease.Package -and -not $isRebuildBranch + + if ($isRebuildBranch) { + Write-Verbose -Message "Rebuild branch detected, not marking as LTS release" -Verbose + } + + @{ ReleaseVersion = "$(Version)"; LTSRelease = $LTS } | ConvertTo-Json | Out-File "$(Build.StagingDirectory)\release.json" + Get-Content "$(Build.StagingDirectory)\release.json" + + if (-not (Test-Path "$(ob_outputDirectory)\metadata")) { + New-Item -ItemType Directory -Path "$(ob_outputDirectory)\metadata" + } + + Copy-Item -Path "$(Build.StagingDirectory)\release.json" -Destination "$(ob_outputDirectory)\metadata" -Force + displayName: Create and upload release.json file to build artifact + retryCountOnTaskFailure: 2 + - template: /.pipelines/templates/step/finalize.yml@self diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml new file mode 100644 index 00000000000..ff40941e31b --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -0,0 +1,186 @@ +parameters: + - name: OfficialBuild + type: boolean + +stages: +- stage: prep + displayName: 'Prep BuildInfo+Az' + jobs: + - template: /.pipelines/templates/checkAzureContainer.yml@self + +- stage: mac_package + displayName: 'macOS Pkg+Sign' + dependsOn: [] + jobs: + - template: /.pipelines/templates/mac-package-build.yml@self + parameters: + buildArchitecture: x64 + + - template: /.pipelines/templates/mac-package-build.yml@self + parameters: + buildArchitecture: arm64 + +- stage: windows_package_build + displayName: 'Win Pkg (unsigned)' + dependsOn: [] + jobs: + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: x64 + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: arm64 + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: x86 + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: fxdependent + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: fxdependentWinDesktop + + - template: /.pipelines/templates/packaging/windows/package.yml@self + parameters: + runtime: minsize + +- stage: windows_package_sign + displayName: 'Win Pkg Sign' + dependsOn: [windows_package_build] + jobs: + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: arm64 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: x86 + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependent + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: fxdependentWinDesktop + + - template: /.pipelines/templates/packaging/windows/sign.yml@self + parameters: + runtime: minsize + +- stage: linux_package + displayName: 'Linux Pkg+Sign' + dependsOn: [] + jobs: + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' + packageType: deb + jobName: deb + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd_x64_mariner' + signedDrop: 'drop_linux_sign_linux_fxd_x64_mariner' + packageType: rpm-fxdependent #mariner-x64 + jobName: mariner_x64 + signingProfile: 'CP-459159-pgpdetached' + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd_arm64_mariner' + signedDrop: 'drop_linux_sign_linux_fxd_arm64_mariner' + packageType: rpm-fxdependent-arm64 #mariner-arm64 + jobName: mariner_arm64 + signingProfile: 'CP-459159-pgpdetached' + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' + packageType: rpm + jobName: rpm + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_arm' + signedDrop: 'drop_linux_sign_linux_arm' + packageType: tar-arm + jobName: tar_arm + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_arm64' + signedDrop: 'drop_linux_sign_linux_arm64' + packageType: tar-arm64 + jobName: tar_arm64 + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64_alpine' + signedDrop: 'drop_linux_sign_linux_x64_alpine' + packageType: tar-alpine + jobName: tar_alpine + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd' + signedDrop: 'drop_linux_sign_linux_fxd' + packageType: fxdependent + jobName: fxdependent + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' + packageType: tar + jobName: tar + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_fxd_x64_alpine' + signedDrop: 'drop_linux_sign_linux_fxd_x64_alpine' + packageType: tar-alpine-fxdependent + jobName: tar_alpine_fxd + + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_x64_minSize' + signedDrop: 'drop_linux_sign_linux_x64_minSize' + packageType: min-size + jobName: minSize + +- stage: nupkg + displayName: 'NuGet Pkg+Sign' + dependsOn: [] + jobs: + - template: /.pipelines/templates/nupkg.yml@self + +- stage: msixbundle + displayName: 'MSIX Bundle+Sign' + dependsOn: [windows_package_build] # Only depends on unsigned packages + jobs: + - template: /.pipelines/templates/package-create-msix.yml@self + parameters: + OfficialBuild: ${{ parameters.OfficialBuild }} + +- stage: upload + displayName: 'Upload' + dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON + jobs: + - template: /.pipelines/templates/uploadToAzure.yml@self + +- stage: validatePackages + displayName: 'Validate Packages' + dependsOn: [upload] + jobs: + - template: /.pipelines/templates/release-validate-packagenames.yml@self diff --git a/.pipelines/templates/stages/PowerShell-Release-Stages.yml b/.pipelines/templates/stages/PowerShell-Release-Stages.yml new file mode 100644 index 00000000000..52ce428a663 --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-Release-Stages.yml @@ -0,0 +1,323 @@ +parameters: + - name: releaseEnvironment + type: string + - name: SkipPublish + type: boolean + - name: SkipPSInfraInstallers + type: boolean + - name: skipMSIXPublish + type: boolean + +stages: +- stage: setReleaseTagAndChangelog + displayName: 'Set Release Tag and Upload Changelog' + jobs: + - template: /.pipelines/templates/release-SetTagAndChangelog.yml@self + +- stage: validateSdk + displayName: 'Validate SDK' + dependsOn: [] + jobs: + - template: /.pipelines/templates/release-validate-sdk.yml@self + parameters: + jobName: "windowsSDK" + displayName: "Windows SDK Validation" + imageName: PSMMS2019-Secure + poolName: $(windowsPool) + + - template: /.pipelines/templates/release-validate-sdk.yml@self + parameters: + jobName: "MacOSSDK" + displayName: "MacOS SDK Validation" + imageName: macOS-latest + poolName: Azure Pipelines + + - template: /.pipelines/templates/release-validate-sdk.yml@self + parameters: + jobName: "LinuxSDK" + displayName: "Linux SDK Validation" + imageName: PSMMSUbuntu22.04-Secure + poolName: $(ubuntuPool) + +- stage: gbltool + displayName: 'Validate Global tools' + dependsOn: [] + jobs: + - template: /.pipelines/templates/release-validate-globaltools.yml@self + parameters: + jobName: "WindowsGlobalTools" + displayName: "Windows Global Tools Validation" + jobtype: windows + + - template: /.pipelines/templates/release-validate-globaltools.yml@self + parameters: + jobName: "LinuxGlobalTools" + displayName: "Linux Global Tools Validation" + jobtype: linux + globalToolExeName: 'pwsh' + globalToolPackageName: 'PowerShell.Linux.x64' + +- stage: fxdpackages + displayName: 'Validate FXD Packages' + dependsOn: [] + jobs: + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'winfxd' + displayName: 'Validate Win Fxd Packages' + jobtype: 'windows' + artifactName: 'drop_windows_package_package_win_fxdependent' + packageNamePattern: '**/*win-fxdependent.zip' + + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'winfxdDesktop' + displayName: 'Validate WinDesktop Fxd Packages' + jobtype: 'windows' + artifactName: 'drop_windows_package_package_win_fxdependentWinDesktop' + packageNamePattern: '**/*win-fxdependentwinDesktop.zip' + + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'linuxfxd' + displayName: 'Validate Linux Fxd Packages' + jobtype: 'linux' + artifactName: 'drop_linux_package_fxdependent' + packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' + + - template: /.pipelines/templates/release-validate-fxdpackages.yml@self + parameters: + jobName: 'linuxArm64fxd' + displayName: 'Validate Linux ARM64 Fxd Packages' + jobtype: 'linux' + artifactName: 'drop_linux_package_fxdependent' + # this is really an architecture independent package + packageNamePattern: '**/*linux-x64-fxdependent.tar.gz' + arm64: 'yes' + enableCredScan: false + +- stage: ManualValidation + dependsOn: [] + displayName: Manual Validation + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Validate Windows Packages + jobName: ValidateWinPkg + instructions: | + Validate zip package on windows + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Validate OSX Packages + jobName: ValidateOsxPkg + instructions: | + Validate tar.gz package on osx-arm64 + +- stage: ReleaseAutomation + dependsOn: [] + displayName: 'Release Automation' + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Start Release Automation + jobName: StartRA + instructions: | + Kick off Release automation build at: https://dev.azure.com/powershell-rel/Release-Automation/_build?definitionId=10&_a=summary + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Triage results + jobName: TriageRA + dependsOnJob: StartRA + instructions: | + Triage ReleaseAutomation results + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Signoff Tests + dependsOnJob: TriageRA + jobName: SignoffTests + instructions: | + Signoff ReleaseAutomation results + +- stage: UpdateChangeLog + displayName: Update the changelog + dependsOn: + - ManualValidation + - ReleaseAutomation + - fxdpackages + - gbltool + - validateSdk + + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Make sure the changelog is updated + jobName: MergeChangeLog + instructions: | + Update and merge the changelog for the release. + This step is required for creating GitHub draft release. + +- stage: PublishGitHubReleaseAndNuget + displayName: Publish GitHub and Nuget Release + dependsOn: + - setReleaseTagAndChangelog + - UpdateChangeLog + variables: + ob_release_environment: ${{ parameters.releaseEnvironment }} + jobs: + - template: /.pipelines/templates/release-githubNuget.yml@self + parameters: + skipPublish: ${{ parameters.SkipPublish }} + +- stage: PushGitTagAndMakeDraftPublic + displayName: Push Git Tag and Make Draft Public + dependsOn: PublishGitHubReleaseAndNuget + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Push Git Tag + jobName: PushGitTag + instructions: | + Push the git tag to upstream + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Make Draft Public + dependsOnJob: PushGitTag + jobName: DraftPublic + instructions: | + Make the GitHub Release Draft Public + +- stage: BlobPublic + displayName: Make Blob Public + dependsOn: + - UpdateChangeLog + - PushGitTagAndMakeDraftPublic + jobs: + - template: /.pipelines/templates/release-MakeBlobPublic.yml@self + parameters: + SkipPSInfraInstallers: ${{ parameters.SkipPSInfraInstallers }} + +- stage: PublishPMC + displayName: Publish PMC + dependsOn: PushGitTagAndMakeDraftPublic + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Publish to PMC + jobName: ReleaseToPMC + instructions: | + Run PowerShell-Release-Official-Azure.yml pipeline to publish to PMC + +- stage: UpdateDotnetDocker + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Update DotNet SDK Docker images + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Update .NET SDK docker images + jobName: DotnetDocker + instructions: | + Create PR for updating dotnet-docker images to use latest PowerShell version. + 1. Fork and clone https://github.com/dotnet/dotnet-docker.git + 2. git checkout upstream/nightly -b updatePS + 3. dotnet run --project .\eng\update-dependencies\ specific --product-version powershell= --compute-shas + 4. create PR targeting nightly branch + +- stage: UpdateWinGet + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Add manifest entry to winget + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Add manifest entry to winget + jobName: UpdateWinGet + instructions: | + This is typically done by the community 1-2 days after the release. + +- stage: PublishMsix + dependsOn: + - setReleaseTagAndChangelog + - PushGitTagAndMakeDraftPublic + displayName: Publish MSIX to store + variables: + ob_release_environment: ${{ parameters.releaseEnvironment }} + jobs: + - template: /.pipelines/templates/release-MSIX-Publish.yml@self + parameters: + skipMSIXPublish: ${{ parameters.skipMSIXPublish }} + +- stage: PublishVPack + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Release vPack + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Start 2 vPack Release pipelines + jobName: PublishVPack + instructions: | + 1. Kick off PowerShell-vPack-Official pipeline + 2. Kick off PowerShell-MSIXBundle-VPack pipeline + +# Need to verify if the Az PS / CLI team still uses this. Skipping for this release. +# - stage: ReleaseDeps +# dependsOn: GitHubTasks +# displayName: Update pwsh.deps.json links +# jobs: +# - template: templates/release-UpdateDepsJson.yml + +- stage: UploadBuildInfoJson + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Upload BuildInfo.json + jobs: + - template: /.pipelines/templates/release-upload-buildinfo.yml@self + +- stage: ReleaseSymbols + dependsOn: PushGitTagAndMakeDraftPublic + displayName: Release Symbols + jobs: + - template: /.pipelines/templates/release-symbols.yml@self + +- stage: ChangesToMaster + displayName: Ensure changes are in GH master + dependsOn: + - PublishPMC + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Make sure changes are in master + jobName: MergeToMaster + instructions: | + Make sure that changes README.md and metadata.json are merged into master on GitHub. + +- stage: ReleaseToMU + displayName: Release to MU + dependsOn: PushGitTagAndMakeDraftPublic # This only needs the blob to be available + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Release to MU + instructions: | + Notify the PM team to start the process of releasing to MU. + +- stage: ReleaseClose + displayName: Finish Release + dependsOn: + - ReleaseToMU + - ReleaseSymbols + jobs: + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Retain Build + jobName: RetainBuild + instructions: | + Retain the build + + - template: /.pipelines/templates/approvalJob.yml@self + parameters: + displayName: Delete release branch + jobName: DeleteBranch + instructions: | + Delete release branch diff --git a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml new file mode 100644 index 00000000000..f0d49e8b489 --- /dev/null +++ b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml @@ -0,0 +1,236 @@ +parameters: + - name: createVPack + type: boolean + - name: vPackName + type: string + +stages: +- stage: BuildStage + jobs: + - job: BuildJob + pool: + type: windows + + strategy: + matrix: + x86: + architecture: x86 + + x64: + architecture: x64 + + arm64: + architecture: arm64 + + variables: + ArtifactPlatform: 'windows' + ob_artifactBaseName: drop_build_$(architecture) + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_createvpack_enabled: ${{ parameters.createVPack }} + ob_createvpack_owneralias: tplunk + ob_createvpack_versionAs: parts + ob_createvpack_propsFile: true + ob_createvpack_verbose: true + ob_createvpack_packagename: '${{ parameters.vPackName }}.$(architecture)' + ob_createvpack_description: PowerShell $(architecture) $(version) + # I think the variables reload after we transition back to the host so this works. 🤷‍♂️ + ob_createvpack_majorVer: $(pwshMajorVersion) + ob_createvpack_minorVer: $(pwshMinorVersion) + ob_createvpack_patchVer: $(pwshPatchVersion) + ${{ if ne(variables['pwshPrereleaseVersion'], '') }}: + ob_createvpack_prereleaseVer: $(pwshPrereleaseVersion) + ${{ else }}: + ob_createvpack_prereleaseVer: $(Build.SourceVersion) + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s + env: + ob_restore_phase: true + + - template: .pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + + - pwsh: | + $version = '$(Version)' + Write-Verbose -Verbose "Version: $version" + if(!$version) { + throw "Version is not set." + } + + $mainVersionParts = $version -split '-' + + Write-Verbose -Verbose "mainVersionParts: $($mainVersionParts[0]) ; $($mainVersionParts[1])" + $versionParts = $mainVersionParts[0] -split '[.]'; + $major = $versionParts[0] + $minor = $versionParts[1] + $patch = $versionParts[2] + + $previewPart = $mainVersionParts[1] + Write-Verbose -Verbose "previewPart: $previewPart" + + Write-Host "major: $major; minor: $minor; patch: $patch;" + + $vstsCommandString = "vso[task.setvariable variable=pwshMajorVersion]$major" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $vstsCommandString = "vso[task.setvariable variable=pwshMinorVersion]$minor" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $vstsCommandString = "vso[task.setvariable variable=pwshPatchVersion]$patch" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + if($previewPart) { + $vstsCommandString = "vso[task.setvariable variable=pwshPrereleaseVersion]$previewPart" + } else { + Write-Verbose -Verbose "No prerelease part found in version string." + } + displayName: Set ob_createvpack_*Ver + env: + ob_restore_phase: true + + # Validate pwsh*Version variables + - pwsh: | + $variables = @("pwshMajorVersion", "pwshMinorVersion", "pwshPatchVersion") + foreach ($var in $variables) { + if (-not (get-item "Env:\$var" -ErrorAction SilentlyContinue).value) { + throw "Required variable '`$env:$var' is not set." + } + } + displayName: Validate pwsh*Version variables + env: + ob_restore_phase: true + + - pwsh: | + if($env:RELEASETAGVAR -match '-') { + throw "Don't release a preview build without coordinating with Windows Engineering Build Tools Team" + } + displayName: Stop any preview release + env: + ob_restore_phase: true + + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + packageType: sdk + version: 3.1.x + installationPath: $(Agent.ToolsDirectory)/dotnet + + ### BUILD ### + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(repoRoot) + + - task: CodeQL3000Init@0 # Add CodeQL Init task right before your 'Build' step. + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + inputs: + Enabled: true + AnalyzeInPipeline: false # Do not upload results + Language: csharp + + - task: UseDotNet@2 + displayName: 'Install .NET based on global.json' + inputs: + useGlobalJson: true + workingDirectory: $(repoRoot) + env: + ob_restore_phase: true + + - pwsh: | + # Need to set PowerShellRoot variable for obp-file-signing template + $vstsCommandString = "vso[task.setvariable variable=PowerShellRoot]$(repoRoot)" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + $Architecture = '$(Architecture)' + $runtime = switch ($Architecture) + { + "x64" { "win7-x64" } + "x86" { "win7-x86" } + "arm64" { "win-arm64" } + } + + $params = @{} + if ($env:BuildConfiguration -eq 'minSize') { + $params['ForMinimalSize'] = $true + } + + $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" + Import-Module -Name $(repoRoot)/build.psm1 -Force + $buildWithSymbolsPath = New-Item -ItemType Directory -Path "$(Pipeline.Workspace)/Symbols_$Architecture" -Force + + Start-PSBootstrap -Scenario Package + $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose + + $ReleaseTagParam = @{} + + if ($env:RELEASETAGVAR) { + $ReleaseTagParam['ReleaseTag'] = $env:RELEASETAGVAR + } + + Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore @params @ReleaseTagParam + + $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' + Write-Verbose -Verbose "refFolderPath: $refFolderPath" + $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' + $null = New-Item -ItemType Directory -Path $outputPath -Force + $psOptPath = "$outputPath/psoptions.json" + Save-PSOptions -PSOptionsPath $psOptPath + + Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" + displayName: Build Windows Universal - $(Architecture) -$(BuildConfiguration) Symbols folder + env: + __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: CodeQL3000Finalize@0 # Add CodeQL Finalize task right after your 'Build' step. + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + sourceScanPath: '$(repoRoot)\src' + ob_restore_phase: true + + - template: /.pipelines/templates/obp-file-signing.yml@self + parameters: + binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' + SigningProfile: $(windows_build_tools_cert_id) + OfficialBuild: false + vPackScenario: true + + ### END OF BUILD ### + + - pwsh: | + Get-ChildItem env:/ob_createvpack_*Ver + Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse + Get-Content "$(Pipeline.Workspace)\PowerShell\preview.json" -ErrorAction SilentlyContinue | Write-Host + displayName: Debug Output Directory and Version + condition: succeededOrFailed() + + - pwsh: | + Get-ChildItem -Path env: | Out-String -width 9999 -Stream | write-Verbose -Verbose + displayName: Capture Environment + condition: succeededOrFailed() + + - pwsh: | + $vpackFiles = Get-ChildItem -Path "$(Pipeline.Workspace)\Symbols_$(Architecture)\*" -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(Pipeline.Workspace)\Symbols_$(Architecture)" + } + $vpackFiles + displayName: Debug Output Directory and Version + condition: succeededOrFailed() diff --git a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml new file mode 100644 index 00000000000..de3ac0ba1b6 --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml @@ -0,0 +1,67 @@ +parameters: + - name: InternalSDKBlobURL + type: string + default: ' ' + - name: ReleaseTagVar + type: string + default: 'fromBranch' + - name: SKIP_SIGNING + type: string + default: 'NO' + - name: ENABLE_MSBUILD_BINLOGS + type: boolean + default: false + - name: FORCE_CODEQL + type: boolean + default: false + +variables: + - name: PS_RELEASE_BUILD + value: 1 + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 + - name: POWERSHELL_TELEMETRY_OPTOUT + value: 1 + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: branchCounterKey + value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] + - name: branchCounter + value: $[counter(variables['branchCounterKey'], 1)] + - name: BUILDSECMON_OPT_IN + value: true + - name: __DOTNET_RUNTIME_FEED + value: ${{ parameters.InternalSDKBlobURL }} + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - name: WindowsContainerImage + value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - name: SKIP_SIGNING + value: ${{ parameters.SKIP_SIGNING }} + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv + - name: ENABLE_MSBUILD_BINLOGS + value: ${{ parameters.ENABLE_MSBUILD_BINLOGS }} + - ${{ if eq(parameters['FORCE_CODEQL'],'true') }}: + # Cadence is hours before CodeQL will allow a re-upload of the database + - name: CodeQL.Cadence + value: 1 + - name: CODEQL_ENABLED + ${{ if or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(parameters['FORCE_CODEQL'],'true')) }}: + value: true + ${{ else }}: + value: false + # Fix for BinSkim ICU package error in Linux containers + - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: true + # Disable BinSkim at job level to override NonOfficial template defaults + - name: ob_sdl_binskim_enabled + value: false diff --git a/.pipelines/templates/variables/PowerShell-Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Packages-Variables.yml new file mode 100644 index 00000000000..7d1818909b5 --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Packages-Variables.yml @@ -0,0 +1,50 @@ +parameters: + - name: debug + type: boolean + default: false + - name: ForceAzureBlobDelete + type: string + default: 'false' + - name: ReleaseTagVar + type: string + default: 'fromBranch' + - name: disableNetworkIsolation + type: boolean + default: false + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] # needed for onebranch.pipeline.version task + - name: system.debug + value: ${{ parameters.debug }} + - name: ENABLE_PRS_DELAYSIGN + value: 1 + - name: ROOT + value: $(Build.SourcesDirectory) + - name: ForceAzureBlobDelete + value: ${{ parameters.ForceAzureBlobDelete }} + - name: NUGET_XMLDOC_MODE + value: none + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - group: mscodehub-feed-read-general + - group: mscodehub-feed-read-akv + - name: branchCounterKey + value: $[format('{0:yyyyMMdd}-{1}', pipeline.startTime,variables['Build.SourceBranch'])] + - name: branchCounter + value: $[counter(variables['branchCounterKey'], 1)] + - group: MSIXSigningProfile + - name: disableNetworkIsolation + value: ${{ parameters.disableNetworkIsolation }} diff --git a/.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml b/.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml new file mode 100644 index 00000000000..3b47e5eff2b --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml @@ -0,0 +1,35 @@ +parameters: + - name: debug + type: boolean + default: false + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: ENABLE_PRS_DELAYSIGN + value: 1 + - name: ROOT + value: $(Build.SourcesDirectory) + - name: REPOROOT + value: $(Build.SourcesDirectory) + - name: OUTPUTROOT + value: $(REPOROOT)\out + - name: NUGET_XMLDOC_MODE + value: none + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\.config\tsaoptions.json + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - group: PoolNames diff --git a/.pipelines/templates/variables/PowerShell-Release-Variables.yml b/.pipelines/templates/variables/PowerShell-Release-Variables.yml new file mode 100644 index 00000000000..930c559eafe --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-Release-Variables.yml @@ -0,0 +1,41 @@ +parameters: + - name: debug + type: boolean + default: false + - name: ReleaseTagVar + type: string + default: 'fromBranch' + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: ENABLE_PRS_DELAYSIGN + value: 1 + - name: ROOT + value: $(Build.SourcesDirectory) + - name: REPOROOT + value: $(Build.SourcesDirectory) + - name: OUTPUTROOT + value: $(REPOROOT)\out + - name: NUGET_XMLDOC_MODE + value: none + - name: nugetMultiFeedWarnLevel + value: none + - name: NugetSecurityAnalysisWarningLevel + value: none + - name: skipNugetSecurityAnalysis + value: true + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + - name: LinuxContainerImage + value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - group: PoolNames + # Fix for BinSkim ICU package error in Linux containers + - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: true diff --git a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml new file mode 100644 index 00000000000..276911a35b3 --- /dev/null +++ b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml @@ -0,0 +1,39 @@ +parameters: + - name: debug + type: boolean + default: false + - name: ReleaseTagVar + type: string + default: 'fromBranch' + - name: netiso + type: string + default: 'R1' + +variables: + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: BuildSolution + value: $(Build.SourcesDirectory)\dirs.proj + - name: BuildConfiguration + value: Release + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + - name: Codeql.Enabled + value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 + - name: POWERSHELL_TELEMETRY_OPTOUT + value: 1 + - name: nugetMultiFeedWarnLevel + value: none + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - group: Azure Blob variable group + - group: certificate_logical_to_actual # used within signing task + - group: DotNetPrivateBuildAccess + - name: netiso + value: ${{ parameters.netiso }} +# We shouldn't be using PATs anymore +# - group: mscodehub-feed-read-general diff --git a/.pipelines/templates/variable/release-shared.yml b/.pipelines/templates/variables/release-shared.yml similarity index 100% rename from .pipelines/templates/variable/release-shared.yml rename to .pipelines/templates/variables/release-shared.yml From 309fb4e2d3d509fbbe9d6f36947f27e862b2db7c Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:17:13 -0700 Subject: [PATCH 090/127] [release/v7.6.1] Move `_GetDependencies` MSBuild target from dynamic generation in `build.psm1` into `Microsoft.PowerShell.SDK.csproj` (#27177) --- build.psm1 | 25 ++----------------- .../Microsoft.PowerShell.SDK.csproj | 24 +++++++++++++++++- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/build.psm1 b/build.psm1 index 871526cff0d..de108c5cd0f 100644 --- a/build.psm1 +++ b/build.psm1 @@ -2681,38 +2681,17 @@ function Start-TypeGen # Add .NET CLI tools to PATH Find-Dotnet - # This custom target depends on 'ResolveAssemblyReferencesDesignTime', whose definition can be found in the sdk folder. - # To find the available properties of '_ReferencesFromRAR' when switching to a new dotnet sdk, follow the steps below: - # 1. create a dummy project using the new dotnet sdk. - # 2. build the dummy project with this command: - # dotnet msbuild .\dummy.csproj /t:ResolveAssemblyReferencesDesignTime /fileLogger /noconsolelogger /v:diag - # 3. search '_ReferencesFromRAR' in the produced 'msbuild.log' file. You will find the properties there. - $GetDependenciesTargetPath = "$PSScriptRoot/src/Microsoft.PowerShell.SDK/obj/Microsoft.PowerShell.SDK.csproj.TypeCatalog.targets" - $GetDependenciesTargetValue = @' - - - - <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> - - - - -'@ - New-Item -ItemType Directory -Path (Split-Path -Path $GetDependenciesTargetPath -Parent) -Force > $null - Set-Content -Path $GetDependenciesTargetPath -Value $GetDependenciesTargetValue -Force -Encoding Ascii - Push-Location "$PSScriptRoot/src/Microsoft.PowerShell.SDK" try { $ps_inc_file = "$PSScriptRoot/src/TypeCatalogGen/$IncFileName" - dotnet msbuild .\Microsoft.PowerShell.SDK.csproj /t:_GetDependencies "/property:DesignTimeBuild=true;_DependencyFile=$ps_inc_file" /nologo + Start-NativeExecution { dotnet msbuild .\Microsoft.PowerShell.SDK.csproj /t:_GetDependencies "/property:DesignTimeBuild=true;_DependencyFile=$ps_inc_file" /nologo } } finally { Pop-Location } Push-Location "$PSScriptRoot/src/TypeCatalogGen" try { - dotnet run ../System.Management.Automation/CoreCLR/CorePsTypeCatalog.cs $IncFileName + Start-NativeExecution { dotnet run ../System.Management.Automation/CoreCLR/CorePsTypeCatalog.cs $IncFileName } } finally { Pop-Location } diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index df66cf90663..290786be1e1 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -75,4 +75,26 @@
- + + + + + <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> + + + + + \ No newline at end of file From 0ef9498fcc4a77634cf657d80e6d71d771b6ed03 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:17:27 -0700 Subject: [PATCH 091/127] [release/v7.6.1] Fix the `PSNativeCommandArgumentPassing` test (#27179) --- .../NativeExecution/NativeCommandArguments.Tests.ps1 | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 b/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 index 8e09df9b699..ead0fb39efb 100644 --- a/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 +++ b/test/powershell/Language/Scripting/NativeExecution/NativeCommandArguments.Tests.ps1 @@ -5,12 +5,7 @@ param() Describe "Behavior is specific for each platform" -tags "CI" { It "PSNativeCommandArgumentPassing is set to 'Windows' on Windows systems" -skip:(-not $IsWindows) { - if ([Version]::TryParse($PSVersiontable.PSVersion.ToString(), [ref]$null)) { - $PSNativeCommandArgumentPassing | Should -BeExactly "Legacy" - } - else { - $PSNativeCommandArgumentPassing | Should -BeExactly "Windows" - } + $PSNativeCommandArgumentPassing | Should -BeExactly "Windows" } It "PSNativeCommandArgumentPassing is set to 'Standard' on non-Windows systems" -skip:($IsWindows) { $PSNativeCommandArgumentPassing | Should -Be "Standard" From bd95caaa743436bc6b72035a329466e541136bfa Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:17:38 -0700 Subject: [PATCH 092/127] [release/v7.6.1] release-upload-buildinfo: replace version-comparison channel gating with metadata flags (#27180) --- .../templates/release-upload-buildinfo.yml | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/.pipelines/templates/release-upload-buildinfo.yml b/.pipelines/templates/release-upload-buildinfo.yml index c470af1fd6e..9e3d6a6accb 100644 --- a/.pipelines/templates/release-upload-buildinfo.yml +++ b/.pipelines/templates/release-upload-buildinfo.yml @@ -51,14 +51,17 @@ jobs: Import-Module "$toolsDirectory/ci.psm1" $jsonFile = Get-Item "$ENV:PIPELINE_WORKSPACE/PSPackagesOfficial/BuildInfoJson/*.json" $fileName = Split-Path $jsonFile -Leaf + # The build itself has already determined if it is preview or stable/LTS, + # we just need to check via the file name + $isPreview = $fileName -eq "preview.json" + $isStable = $fileName -eq "stable.json" $dateTime = [datetime]::UtcNow $dateTime = [datetime]::new($dateTime.Ticks - ($dateTime.Ticks % [timespan]::TicksPerSecond), $dateTime.Kind) $metadata = Get-Content -LiteralPath "$toolsDirectory/metadata.json" -ErrorAction Stop | ConvertFrom-Json - $stableReleaseTag = $metadata.StableReleaseTag -Replace 'v','' - - $currentReleaseTag = $buildInfo.ReleaseTag -Replace 'v','' + # Note: version tags in metadata.json (e.g. StableReleaseTag) may not reflect the current release being + # published, so they must not be used to gate channel decisions. Use the explicit publish flags instead. $stableRelease = $metadata.StableRelease.PublishToChannels $ltsRelease = $metadata.LTSRelease.PublishToChannels @@ -73,7 +76,7 @@ jobs: $targetFile = "$ENV:PIPELINE_WORKSPACE/$fileName" ConvertTo-Json -InputObject $buildInfo | Out-File $targetFile -Encoding ascii - if ($fileName -eq "preview.json") { + if ($isPreview) { Set-BuildVariable -Name UploadPreview -Value YES } else { Set-BuildVariable -Name UploadPreview -Value NO @@ -82,9 +85,7 @@ jobs: Set-BuildVariable -Name PreviewBuildInfoFile -Value $targetFile ## Create 'lts.json' if marked as a LTS release. - if ($fileName -eq "stable.json") { - [System.Management.Automation.SemanticVersion] $stableVersion = $stableReleaseTag - [System.Management.Automation.SemanticVersion] $currentVersion = $currentReleaseTag + if ($isStable) { if ($ltsRelease) { $ltsFile = "$ENV:PIPELINE_WORKSPACE/lts.json" Copy-Item -Path $targetFile -Destination $ltsFile -Force @@ -94,18 +95,24 @@ jobs: Set-BuildVariable -Name UploadLTS -Value NO } - ## Only update the stable.json if the current version is greater than the stable version. - if ($currentVersion -gt $stableVersion) { - $versionFile = "$ENV:PIPELINE_WORKSPACE/$($currentVersion.Major)-$($currentVersion.Minor).json" - Copy-Item -Path $targetFile -Destination $versionFile -Force - Set-BuildVariable -Name StableBuildInfoFile -Value $versionFile + ## Gate stable.json upload on the metadata publish flag. + if ($stableRelease) { + Set-BuildVariable -Name StableBuildInfoFile -Value $targetFile Set-BuildVariable -Name UploadStable -Value YES } else { Set-BuildVariable -Name UploadStable -Value NO } + ## Always publish the version-specific {Major}-{Minor}.json for non-preview builds. + [System.Management.Automation.SemanticVersion] $currentVersion = $currentReleaseTag + $versionFile = "$ENV:PIPELINE_WORKSPACE/$($currentVersion.Major)-$($currentVersion.Minor).json" + Copy-Item -Path $targetFile -Destination $versionFile -Force + Set-BuildVariable -Name VersionSpecificBuildInfoFile -Value $versionFile + Set-BuildVariable -Name UploadVersionSpecific -Value YES + } else { Set-BuildVariable -Name UploadStable -Value NO + Set-BuildVariable -Name UploadVersionSpecific -Value NO } displayName: Create json files @@ -146,4 +153,12 @@ jobs: Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force } - condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'))) + + #version-specific + if ($env:UploadVersionSpecific -eq 'YES') { + $jsonFile = "$env:VersionSpecificBuildInfoFile" + $blobName = Get-Item $jsonFile | Split-Path -Leaf + Write-Verbose -Verbose "Uploading $jsonFile to $containerName/$prefix/$blobName" + Set-AzStorageBlobContent -File $jsonFile -Container $containerName -Blob "$prefix/$blobName" -Context $storageContext -Force + } + condition: and(succeeded(), or(eq(variables['UploadPreview'], 'YES'), eq(variables['UploadLTS'], 'YES'), eq(variables['UploadStable'], 'YES'), eq(variables['UploadVersionSpecific'], 'YES'))) From a911eae43d838d8d70ee00f6723a602c5e81e316 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:17:52 -0700 Subject: [PATCH 093/127] [release/v7.6.1] Update the PhoneProductId to be the official LTS id used by Store (#27181) --- tools/packaging/packaging.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 1e03d983c48..c5d67756004 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4314,7 +4314,7 @@ function New-MSIXPackage Write-Verbose "Using Preview assets" -Verbose } elseif ($LTS) { # This is the PhoneProductId for the "Microsoft.PowerShell-LTS" package. - $PhoneProductId = "a9af273a-c636-47ac-bc2a-775edf80b2b9" + $PhoneProductId = "b7a4b003-3704-47a9-b018-cfcc9801f4fc" Write-Verbose "Using LTS assets" -Verbose } From 89178b9b708c8df05104a4e6c5ff0d1ba4049b71 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 2 Apr 2026 18:18:50 -0700 Subject: [PATCH 094/127] [release/v7.6.1] Select New MSIX Package Name (#27183) --- .pipelines/templates/packaging/windows/package.yml | 2 +- .pipelines/templates/packaging/windows/sign.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/packaging/windows/package.yml b/.pipelines/templates/packaging/windows/package.yml index 13ed80ee123..ccbfa740592 100644 --- a/.pipelines/templates/packaging/windows/package.yml +++ b/.pipelines/templates/packaging/windows/package.yml @@ -220,7 +220,7 @@ jobs: } if ($packageTypes -contains 'msix') { - $msixPkgNameFilter = "powershell-*.msix" + $msixPkgNameFilter = "PowerShell*.msix" $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "unsigned msixPkgPath: $msixPkgPath" Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose diff --git a/.pipelines/templates/packaging/windows/sign.yml b/.pipelines/templates/packaging/windows/sign.yml index 4a095ba7694..f7a2e5e03e8 100644 --- a/.pipelines/templates/packaging/windows/sign.yml +++ b/.pipelines/templates/packaging/windows/sign.yml @@ -202,7 +202,7 @@ jobs: } if ($packageTypes -contains 'msix') { - $msixPkgNameFilter = "powershell-*.msix" + $msixPkgNameFilter = "PowerShell*.msix" $msixPkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $msixPkgNameFilter -Recurse -File | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "signed msixPkgPath: $msixPkgPath" Copy-Item -Path $msixPkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose From d72d4022d204e0e35e5a924ea4b851e52f7df73f Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 3 Apr 2026 09:27:24 -0700 Subject: [PATCH 095/127] [release/v7.6.1] Bump github/codeql-action from 4.32.6 to 4.34.1 (#27182) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index a7f9aeb9879..0baa21fcb0b 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 + uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 + uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 1f95d1cae7c..c92c705b00f 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5 + uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 with: sarif_file: results.sarif From c818284337afae36424903efc4ade495cff2b61a Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 3 Apr 2026 09:56:58 -0700 Subject: [PATCH 096/127] [release/v7.6.1] Bump github/codeql-action from 4.34.1 to 4.35.1 (#27184) --- .github/workflows/analyze-reusable.yml | 4 ++-- .github/workflows/scorecards.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 0baa21fcb0b..75886342851 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 + uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -74,4 +74,4 @@ jobs: shell: pwsh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 + uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index c92c705b00f..44378b60b74 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v3.29.5 with: - sarif_file: results.sarif + sarif_file: results.sarif \ No newline at end of file From 94fafbd04aa5ab0cf9878827722c68b16a47bc25 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 9 Apr 2026 09:54:34 -0700 Subject: [PATCH 097/127] [release/v7.6.1] Separate Store Package Creation, Skip Polling for Store Publish, Clean up PDP-Media (#27214) --- ...Shell-Coordinated_Packages-NonOfficial.yml | 4 +- .../PowerShell-Packages-NonOfficial.yml | 4 +- .../PowerShell-Release-Azure-NonOfficial.yml | 2 +- .../PowerShell-Release-NonOfficial.yml | 4 +- .../PowerShell-vPack-NonOfficial.yml | 4 +- .../store/PDP/PDP-Media/en-US/Error.png | Bin 120539 -> 0 bytes .../PDP-Media/en-US/Experimental_Features.png | Bin 161370 -> 0 bytes .../PDP/PDP-Media/en-US/Feedback_Provider.png | Bin 167038 -> 0 bytes .../PDP/PDP-Media/en-US/Predictor_Inline.png | Bin 110258 -> 0 bytes .../PDP-Media/en-US/Predictor_ListView.png | Bin 146469 -> 0 bytes .../store/PDP/PDP-Media/en-US/Prompt.png | Bin 132747 -> 0 bytes .../PDP/PDP-Media/en-US/Stable_Release.png | Bin 179123 -> 0 bytes .../store/PDP/PDP-Media/en-US/pwshLogo.png | Bin 13152 -> 0 bytes .pipelines/store/PDP/PDP/en-US/PDP.xml | 25 -- .pipelines/templates/package-create-msix.yml | 179 ------------- .../templates/package-store-package.yml | 242 ++++++++++++++++++ .pipelines/templates/release-MSIX-Publish.yml | 14 +- .../stages/PowerShell-Packages-Stages.yml | 6 + 18 files changed, 266 insertions(+), 218 deletions(-) delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Error.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Predictor_ListView.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Prompt.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/Stable_Release.png delete mode 100644 .pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png create mode 100644 .pipelines/templates/package-store-package.yml diff --git a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml index 55d4c4557d8..0b417df5c05 100644 --- a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml @@ -45,7 +45,7 @@ resources: ref: refs/heads/main variables: - - template: ../templates/variables/PowerShell-Coordinated_Packages-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml@self parameters: InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -90,7 +90,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ../templates/stages/PowerShell-Coordinated_Packages-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml@self parameters: RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} diff --git a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml index 81f343a04a0..9419d3f29b5 100644 --- a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml @@ -31,7 +31,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: pkgs-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ../templates/variables/PowerShell-Packages-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Packages-Variables.yml@self parameters: debug: ${{ parameters.debug }} ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} @@ -92,6 +92,6 @@ extends: enabled: false tsaOptionsFile: .config\tsaoptions.json stages: - - template: ../templates/stages/PowerShell-Packages-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml index 681babb2220..b524cb0ff81 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -17,7 +17,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: ev2-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ../templates/variables/PowerShell-Release-Azure-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml index ca5a6383f33..7864513fc2c 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: release-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ../templates/variables/PowerShell-Release-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-Release-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -98,7 +98,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ../templates/stages/PowerShell-Release-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-Release-Stages.yml@self parameters: releaseEnvironment: Test SkipPublish: ${{ parameters.SkipPublish }} diff --git a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml index 642b169adaf..f1f4211ca8f 100644 --- a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: vPack_$(Build.SourceBranchName)_NonOfficial_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - - template: ../templates/variables/PowerShell-vPack-Variables.yml + - template: ./pipelines/templates/variables/PowerShell-vPack-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -82,7 +82,7 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - template: ../templates/stages/PowerShell-vPack-Stages.yml + - template: ./pipelines/templates/stages/PowerShell-vPack-Stages.yml@self parameters: createVPack: ${{ parameters.createVPack }} vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Error.png b/.pipelines/store/PDP/PDP-Media/en-US/Error.png deleted file mode 100644 index 48e96378055b5d7fbb4d744007c1ebc073da2453..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120539 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

qKdpe4ED4mcn4J%^2KM0@o*9MuqiJ3p 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 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png b/.pipelines/store/PDP/PDP-Media/en-US/Experimental_Features.png deleted file mode 100644 index 90420254a8e4a4720601e3050567db719819efc6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161370 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 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png b/.pipelines/store/PDP/PDP-Media/en-US/Feedback_Provider.png deleted file mode 100644 index f4084360d5c630119e469b721dde87920d5a8346..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167038 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 z 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 L$C>(5*M9y#()S`v diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png b/.pipelines/store/PDP/PDP-Media/en-US/Predictor_Inline.png deleted file mode 100644 index 3b8d62284859c6ce60c96d643b3b2bdb994471d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 110258 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 W56C)9ct$q>0000&bOJEruf;N2sW%7_MGX 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৉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 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png b/.pipelines/store/PDP/PDP-Media/en-US/Prompt.png deleted file mode 100644 index a40d6fddfdc44c9f7fb643ebc4e84eda527a395d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132747 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ǟ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િI>b zIL(nX*w6!9B2ADp2phZXN-UAXV-$wfk<>QM#Bsotr%Fx!sOPxNW{ zk<_A__ z7N-^CgL^9KFZ=^Zzw@T&weTEa0SxPX)Yro6hiqb+(Aqt$9OrJl2EEC$`{5zoy-TmYmrmMT> z!|ECwN$ z3?3qLPjPxQ70Vg)Ng^Y)4^MF5zj%FcEN+VjhZe7}6ED9Nw#;=@@>q+sU*vh!F9*4auDDs(j5+5V-5mec-suDW5$}c_!V_;U1dJ_qcOVpPU8_*8Ll#)Oy#w)} zvcWz-5J>_BmYg!|c65G|IgT4LKAbWBhA>U=UDbYETaE~GZJr`{=6k`03X4-HzCDzW z!Vw;*32!?LJeBlqcfsO(Q-4)0*QDjP@CwEiuVW*I!QHEuz29NWK3`zEwE9_{u%uiM zpZETJiqjkt`uJ7d#0D~GFwPz+j|T#fbSkOG2j@>31XtF$k7t?azt3rg+MRm1XQPrVuO8ojppfh~cvmyEAW>x7KQmW-qP z#}k!E?*6PcF8TFV`}W~dxEzf3-6Er29A)fbY&RO3d!6?N`l@;5t!^r2X=$ancPTKf zltyrck+>+>gNWE1ho`<1=0~qg-GH@^JE61GFp?}6;*t{WkmSmKMVh0XVJdQpLWG5_ zj4Q-|vZrgP7gUvO-wdpDT*qNt2Q1`db92L*LoFJLNLJ&{CJXHf;zxF5R4N^rRCoM*gGr`sMpOG7a~sj@!Nrv0G(ZntY)*5Qo@ zeHg%+ruuhMtVoH?I{w-zdP*+mpyGkfq85Q!dld1o^Rs%~vO7^dX8Q_8$IpXh1!U;9 zG>fa*(}y|}F~PMdh32OS{yzWQ=0v$@(xceZo$C3=DAS;}F=NvN}=Lr;eAmFw2J4!EX~!ucGS84Qi;Dnd{Bs$VZ`t3sCt z&AT)f$Z*ue`6UMCdl`CN!o{0gH&Y%i(Tf&%2hrTB9<HxUqm(Q`(@f%C=BEyP_8+)b zkZ};uGbAjFep1>X$}uXdZrrP^x~r<{!jV#Uk1H_QY1wI!s3pfIC~$G5e@0tCFgJ99#L^BIVo}Kw9@%#6g}}q#=HFk7hFu%!&l)+-d1k3sWy8pm zQi7_=dQmzO)9xgR7q%YJmZ(d7m5G`sJ`pl}7##b&WZ~4AC-9C@?5qj6%CFzVOQnG- z{#gQ?Kis=_aj9$(vX|mMCWll{-iJw~gF(1p5Pn{vJ=$co-2b&he>`yHB0rN?5{@?P zUhNv?1BF>k1V?*0;ijXV#$4%p-y5&K#b2{)tU?l4wdr=#E~;2Vh&$XV1dy0Art#|` ziNAtt_{7eTrT#9c@JN-dT|WJ=RTEQ#?1#qbN9Du(uh*6JPgfbzMp7d#hhEp#eIyRs z{$yA8%IK3Lm|B~CTw1bm<}&Ba-K%P!NNOPNjAWf@fY*4Am0%FG{^t4N)Tx(8`g&?B z2c3)c=b9;@p$``(7J#<4dQ}FXV12sPLbKv<pIj7MhN?oHKTM$%cq(A7^;wdg zq#8Q85_V1o9csNVKNF&?izCu1dB&)XBL1Bzi6`B46995_p-kjgh0gQ(HA#b8l~85g z;5{uXT_;@KFhK)Yl0#XST#3^FX10B!=g#_v{c)jSW=|0wNz{<`edm!aL_eIF(e&mS z?99kAf#Gb}XMu@P-!jjF42d6V5l)K4_;dysvL0DJKuI# z^l3?VPl~9=iZ5f4Dg|a?#W2tel~n)r<6dDJ8U?=)(UluJj{}W#rO<|jg(;KJYs)Wfrcnwc2b_!7xy3!UtX=q6)&qFPIW*5A5_r3 zGnAsFwR!^U6Ok?Gt->o_l>nBhU z=gP^9n=s+sXQIEubNlE0=O)(4P{ludC9jZjtx#?nPS64K9XZy6764Vi{iCh9(OB4SnYQru>@IW!AJ#1ZZ z7K-KZS(+|R*{B7wa_Jqq6Vq-~n$3`&f|DXW+K6EWBG+;1#M%wO z@MuwgF+*FC~$eCTfm^2s1;(Adh^GkXx=Zhgoo1u5 zKyH!kOQ3_6Ri1V9WS-?)m^F`my@*Od9tI*b)je|@EADM_Ov4Nul zoh0fkCWjv~0n8X*!ot~0DYLYt$^7(+QaIl)hqhRF!?ldEllKgXmse@EprcP2Ra2ve zbkA^hW;RzT>g~%qjcZ5sRLCFHNdb?ThNMP-Up~CI6o9$#MX1TAU z27PPGfn;RTWPTX7=fc~2@Rx1=E4E-guupTf!#o=%_r8#^?!ITWx>s47lUj07M(0Tk zX{bQ$oISrlP1CxQUE-9=3#h3rXOfqekb%`hu<=@e{;b z?-R4NKl|r9i0LS`r;QoPjoBS6Z`P%!xh;O)IZ*mzb|iX=WZ_Ore{f+l$U}1e@|N-a z)bmtOQRiYMo|H^(VjBjBC0q<@U%0z0jC>%n7P_M%M~a*Q$NM0gIbb4SHjgA1fF5)b zDGY@fPP?}c?mOoylX|Gj>$`=ua|vmERU`Sb$^8{}9q}a*Mg~d# zKweeM-G0L&C^9c*-(ctv5D>vQIglh<(OpJnqNc4%`+zMEl)EIYwD&@cn~R#Vi)RD2 zuw4c`0&lQJ98YQfgCDn&b#rAVAY@W0loFBE%>OZQ#~FiD4qo-sF=q)-Lp9qXgJ+AA zXT{S$*g>2Bbjo7gM^m0POa9f4T_oF9Px#363boI&#IT*%6)Z|*=H13aaWVObRc+J6 zi`zQeYhfT0hBB|r>>M<+?|{lVM6Y)Uoe(+WJ2TE$GWI2eMH_BHG}k5Ltm!Mo#dosY zN2c)ltTt{)br->lh|bhPsgUO&C@O1dIN5h~?(^B@zOiR&cgKe?tyS4&L%<)-p{T+9 zG`cOj*F_E}OpBuCszKsHq$eU_wta4X#d}=SE!Q}RkWWlbNE$%+WJP5*BkZDqzXZKp z^O}ao#P3QB3G7CDpT@&J%8lPfjxZ0OCpM=qNNg3w{(}3X3=6oT=f~9ZU4QOS0Ns!q zie3%VXJOOnYA~Dhm-4LLBCd&(-EwyC(X&H{5J&ww%xt0JewRzk6ezx8JH0q6`6w-M zIJ>{f8f&Z(A{+5hC%qKnj%t3F2TPn}fFgJ`!!W>3OETrurblArWtiVg$Zxi-5bgFR zYWiDptgJm@|g&(Sarjjxe6n3 z#ITtfm>fy-uA_W~E7pEW8CUPa&ZD{@HrD|ggT8ia>WKFMh@NFYLHTv?@?1R1P`LwL zJR0Bu+tTp_dh#IkR-~QJb{Zrp7R7n&a5*5H-`Q_4e2xl@SzLR0qDfVuRE}N@j_}_r zz-*)2HL_WiTvvfxIOpSc+L2$@rG>9_Vu28XBu#^N{^TS4ar$MOQogT01^yGZ_GhQ*_os;U zcd1CIEl!L7{ZIe&O@#sQGv36G{~_xQSd6P2rL>eeJW5~j2|rG~PbzwSPXCv)R99rl|5g)vLd8!q{)}qB~|p|=YT(~l_8V3XHJ*C4|{K?UeAAz27sTz(tqsbYSVyT*z+&MoS2yNDv#E3(*?UZ zCjPa$`BnkTT83#ED?n=8rqpPg`Q6t&ENUJcqbf7g(2zOv@ZA;Me!Mru{mTIPg4_83 zsJ+LzCtq&RNBIkK>7SJgcp+`vREw><-KBdbdWdH*&>v8jMuEqcfBMhkF^zg zY)e;8p=tZoqvcY!p+u7Ix_#Sy@!AuE%*;yXH|4{l+mu8b0>Qbc)4kaUrULOb)rz#_ z*kuQ#9P@>djcU^To~^}(?-AZJ>%1A;ZIOA(-(%6znO}6>s*k1z8cAX8)}XC-?P?w- zC9@Xaj4K~iRgw^r(X~w)KO=69SWuASimuvLey*5X@vB7rk#C#YHbjM`S>9Q34>y&( zB(?OW-+7$y_J#kwuniS7bP8@-h2e7ASUO_JHe`3b1 zE%sqx5d5URha!O!OswJ zpM$@6c2W`LY^|b#^IW!3n<*~iq}fXq69y6X$W3p|o9vT`p;D*na&A42II?fLqIhqJ z`mELAc?SIhaES(L{uKteCb?IKJc>BrE=>_EquTmHxO`nIS($4-r){^72`MTxDv9fZ z$juAk?+QxZtT|RER?Ti*P^Fa`JN?RGY1Xvo6|+3uGn+j_Kb~;@q1m6{@wTUTgG5Q9 z{#-DXL;tWqd4hSm%NOCuc7lX|?zrb_so5lkr%A9peM!L1j}n-4WF-6v9sS!2eU+|s z%l>%KJ@CQl&FhR;85>s19h0HTj+DJ@%nqwJVR_BXh6CUd(}5-6#?emfzx8mhO2gU( z68%Wlmpf9x?%p!kF4*Q=%=74<+*GS_-y<{v=TY{pV8y30h$6gWX1Fdq8C_AU>*2YV zM+)YECj2t^4Alq1UKSYbioEawh|?J*)Tq3rQ*h=F;4W8_zQ)Y0vg|NS8_)tG@On}A za3*Vzfvp#?9hAPoewAm`N_a-S#`^S}vO+D7- zAr&UL>vH$l$QOG#k0I!5ej~IE_EuSzw35<5bJh&KT-tw%d&Yks*9}HjfqB~DNxI8R z+zh+0eN(2~iGrxHf#$^V$}$dMh;TleBMB zE+uGttA`9`=T;Iof&;;voRePofd@n85NvdQ?b%?5p;mrl72`ZFAZ`++QEVbKA%H|i zek0B;q~zW|;)KyPC*;94r(NkubIcrbBo|JMk}cdV z!Ky)YT$^8{ov!Ac)`eoD+0Ci8eCEx2&fDLF&>rg?&0Ab8_6_cMN}gmjKE9SuH2q0? zX=!$S$_{k~osriIKGLFY%YqO9+HKXg%}X%mJF1n*s7)vk=|X^d_~0J7XOk3;LKm1MnS z^f|eO2f0C+uLG_IO{D@u`_5r7DW6__mnS)Ac_HT@hsl<@(&ybR3!*|ROj($2i-Jf= zj~n%0{YBN1sm`3Gg)fq6z{CemNSV2fyzbGy_X@)!C1_|8%{nmQ<4^Q#3O!>S$vTpLy>?89$R;GQ7(WlFc?#h`Smt?$yS+^>VOdRi2o#+71j zmIv?b8x!^?N8*hxTl=8yF!~Do%=EkO_&=^vo_JieO;b4qe#~+-ei;5s4sW%`EAFwk zAlK~l=f$ntAYiS|BHbEoqez!ImohkdFb`Jh^y&)V-nuK%E~cfnSk(DC%i($UUOrT$ zLM+b%g_uE!7K2}%KIWKUK6iRm3hGmIiF`Az4YjchlL-<`)Jq@7JOnod0$+-okOU%5 zYe2$s-s_bI9e6diJNzVQ`m56qtrt$pv}Z@6PTy~2Koj95o;lEV63cDG$u8~%xPBT} zi>3t%BAGcRjz5Ij=s35$<^=&*?V#bMa(O7DN76s?k@?0PKE(PKI}~)cakzNFEmM2a zI<1QDml{<;W>zP?(5$RTJZb(u$N#EPtc@@k>RDE`;e5u4AEGY2aEamlxVqt|BOd1* z>ia`)kp^yWtUl}m!4)>X%8p1CIf1FJr-R603l3rPuQMr+&fjyYD(8Y{)oW}>R)d)G zC9934&?}`yfH)amOz48Z1_*eQkK}hRQL?|G5G$fjUGcdamUQGgO!murn;Se-;xMS-OHWTZeCO!l(?kk5B@fpWCT);~22liOmMnby7rUuHj@@S1PwFJs71~>nD?&d)qxv0;eU*4&c)tqT=YE ziV$r*m>1Hcr|9VoLtVEv;}Fc$wD;-ZtHDZUcE>+wc44P2) zGKZ;+nJwB2OvF%b@Z}M6FttFaK+tnG2iqM_f~6IEK$E8Rbl>-qADtR)%05ogOP@&4 zW{&Xopj4GX(aTq_E6wVEMsRq2*REQ{O4pTM$8d%^%^+PjOhn<^D||s}%fc9v#f6|* z4$r8yS=4@8t~N((Ha!i%!olT_@5HPsP)G|&`@tBsS2y2do7WG;HoQnnNe@h=c|LGj zm?wv8So(dMHqp(gEbHsLsBTR()-*JHzHii%dfoJmwg$Yw{U6lnz=CJ!E=mgz75XA# zm7M(2Jg%o4^e2|q-&>qfrVSxQRuHY>u`X{rPa)CGRe0tZd7TkxQj5BP!40_F+*{!=w3W z`zZuy+n+$}wH^1SvasvOPSl>K*~$~M`a_%@a*d&`IK^2}?&cd| zuVHl3mWSN0!G|>+Y*)ud_D^}xbE?WhbT%D@?s-XEU zXs}lK=6L?L@+iNm?!0MUNic_6{`fr28?wr4tMGi}-Zy1ykmg^K#(M3z+`3gLECHHN zUfi*sp*@y8YVA6?JKUxsu0b;P!W-E3FU`JIwtIcv7aR`7H>5ipuduPBECpTRembO+ zz8<|Y-_oR=fw*WLHtf7`)nVje7|u}c(ozJSGJk#SX+O!MYW_&xm(g)h14b+a%4e@e!w(@UUFz-CDM5QBt-QDuBX#<59jVgd%+rQ3cqJ z?LG&JNxBHelZSEDVUcNCX(yhqHiqh(h-;mU{U_6g>b6`sgzRh?(x`BpiAglY+k$t` zjZjKUk*_aG#1ar*!BNJ6)+AJ$tNE=m?j496&K;F6fLcjdEcbwo1)eT}tES+M%+;tr zRlV04+M&epE=cvLPJJ+v{cXyFkrh##%B;W#tSQ)Ry-+{$!Yth0j+}XTNZ`U6oZ&lQ zA>pbT?mgcy`Rr*g<5dx#1s(njz6DWgnT%9;UekiEMsI;h-F@Ihd9Bfo?Gs7YOy`R# zuu>m}6L@S}9}6@8+KIlpQ3>eNb#N*Q#OQK>NxCsl0mj;`B zO$*kw6IVZ#7L8+qbNUFuc#zG$@65RsGdX{P8UJFY-$X}4b!(EKsnbS$vO`CUq1>P0 z@I$b}7vKCEVrLN~BD6UFaAJ_h&au1e@aqXUzHgY-JvC_*_Z$(n4Fq!%U@ zyQZHo#ym12cx#30BT5xwqsZ5A>Ctn$xVCbM12SI%fgCa+)OSKXD(=w7ujF~;2kYcJ z+oL+@!?`C^b2MjG(?4*W@L{PjSO-fl>zY!3ZCJtdX4 z7Re-_tH?UfyL4iz8^?w|s2C~Nm(qO`imQQ&EH^AF~3u7n%n zS57R<-+5yC8fE$K|NL*hxq2>E?E>7v=Y6mDKhAlG^1b#%oz`)Uzj@@}s`TGCan%bz z_E;k3j(6Ifd;#Ey;+yBq{;NJwHCbz*xE{s_%tqP__Mud<9`c8b`ka0})=g=o##movEAikaZ0FRhBhump2 zue$51p^}}-vlze&pjb^z3ZQQBy((IY;teQnRO8A7Z5E=#^JJ?^hZnmr(DM`Df^1;>9|yGTj!O^cT)k9Yeu z*2gUQ79rs(@4mDRI?5H9H|ur!J)=9J2AUKAQhov8Wu*=Z;UHO`g=3M@@oR z)5Mj5*mZnvBTVA|M~AwgImJ6b~uU4aZ(Ar~W z?s!7wmeng>!u+3(39g>QX)`%dr;Uefrn#On;a}Kg@<0HgwLio~% z$5>~M*;C!L(NM+#6<4|94l1hMrCr=|OJB5Kc5?I~TZ~!%+nCT;6-sS zJBF=7w0;60&15O$LX2~8#Y^}tD4(VJ?7HRPb$p)!0>=r&cJi`G?vkvqR&RCBw=%`W z7i&Z|1DzCMivo2Be4d+c_n<5KgMD)`wu&C-Pi0iDXgaz!AA$4inos{%M8!FtMcY@W zAMK3P9!Ul31!vU+=+Oef0|tEV5V^9WrjLFfb98HT+!eNokA!fc`Jtou>PlprPZp}} zHR$p;vUk-wR*eMg<|%4w@g!_2$F{IxV0or^Qy2$H(c zY1}THE!3h6`&rTmr*PT$vOLlb)RG__=55!nyAxL#Sgm(~`6W)8m zZUACnK{&zfJ}G6QHCaQu9~yFOg5irofEGMz6`TFDk%exV|C6Q})8FSb1C+H>t-r!( z5xp0?G-9EYs4%nE7JWgKg0h(JMXQN${PlYLiz~^Jjx@x*MN_O%W>FN?#l}#-Jf?WE zIaDuezJp4>toK+;>pSC2+igF#H@;#tS1tK1Dk8U=6aGsfzm4=0l&Kn>Rz3AV1%$O! zWf10l3?J^8*nYNW!TdT{uaz#mT%y*K_RXUuT%ioh>WU(-$50z9`q)#ra%PZ6W+X!8 zbCevcI_EIxbw^rDY|JNa=I@Vupz~ngCg1XtJpOnmzdK_sH&6xMdN;dAOyxi(jbpmP zgD7Y>jb374X}HJSj%3Ww=02R{bNP7kbI)WA7}H-D^D{C?HZ5+cHV-gl$0Xf?rJV~H zinJ!dD~gc@3Z^&G%1;*5QsCU-L7GK#=915qCk9jz6im)ie=~dw@=$t<=?E%vEoJmv zd7&vsf9^wo;&LQNe%I$(UgpT-Uiw-}t~;QZt0`N3xOuWE?Q3X#zM-hSLNw&+eM-tO z9P%m>(E^Mzd$UC*%{>_1B3Nx#8tzD@`Kkby>zDKP1pn)BD-KlL`Wxl@nR8Ap@0V6&zL+sH!+M zFRsKFKPGm2lWILs{&TrfcZzuV?(DrJf4;2{oK>)_oteNo+W~7{WZb+@EI)!XO~xc3 zD<}$A6H{VbOsCNeyD}y6pdVm5YS z{;g3^90nu1(-~3XuV_H4)4RfT-|uw_`;@oMp~<_wFRF;iMk+QfB~xS%(eKuA-RtsC zsD_?&+%uq)X2@UHq#v$TYSc+_JnIREl|;7{t_&WS$Afzx;;*0JSZ!aQ-ZjnJ<@02CfC@`Uh>{a zZyd;{-zk^-`;LD>E3|NzDCW1S=%aw5xL%rm%M)sz>5&5_zC)}q`UuKqjlAEGs?3WV z9TejTlSvGgwa-APChdZH^Fs7ME^Lu&V18?uZ!+Uq-5l!3ov(t>4ohk><=)nW%9rBg zhZ@!@(X`Za@174cdR>V#QZW;zk0*Z*l9FF&kNFNm40{Z8Oe^BiWQNO_mt9(!THjfp zDPIb}tJE`lm8=RLOn?Zk53;gOOptwHE7D7p#^HUj4-^(UKat}f0|*Q9+65+P#QlP| zU*yHRw+U`be5Qr1uXF*H&#IAy1t8^B<#fYY3PG+vi6PE0OsiTIIsQSG63Sz`yAZ9}TVq%AvQXn}AIxrJP)Gv_SNB8iUP zU63>EPl;NNwseqZ1DxhSj=$w;zpXoln&WuiFiqO?%Cp6oyD~d;*e6w(sgGSvGDf4+ z0i`OV`@$2X3eY6iR-?U;{-aZ*{o=caKU_T&Ym=U0Gh8woPsq`(^bF(~_7pADcR|wv zZB>wn4<1m_0j&Y@dIXkx-`4@X)63KG_%#R3uBa><%r4fL-Px<0RZvL9;9~or)Gpb` zaR_|2Z2rM;_O~@#ki3VY>TNyT;!1(6AE3}(tE4u&BuYgr5H?=+^wvgLshb|F-d1kW zgsgnBdBdeLW+0~+Uw^f_>F5&235<7Zb- z;&CNCNqyxpksDv)YP2Qg`E`AW8|Xala=q^Qk&A4jOdLECzH?4)5a}3x+6ATO#z9Bk z9y4M_2KZ#f(5LAygjQ_7Rr8r`3-|xV{QeQaS)Ge@+Gv=Re`5%GrtPr3*DUc6YJcIFe-q{ZDK3=f zFLL`zFF+H+o5f`Ny}eAaUa9QY;*s($h$er@oPfd!5@4!d%Zdduc~$qxNiwRA*6$6M zMhTV8vQGfBPi@;$ARXwL=eNY@regjHMi^@K@GIeu1X zG~;!4k4mOw$Ru2_T3E!k;`^Y3WWLrHa;2o(?1YY`^K&73w%k{eh0D^=>X_95&>rTy z4-Np~vEpOs?q99OUpuXKD$1WmyFe~Q*iC#Dn7x*3l$Y`DC{ZXf^zcvnZc<(VZcXt%^YbMW0=B&=7K+SERbYzKYSTlnBfaX(v%12G%9 zQTs|Dd~0b`!R)KMR3QG3j`e`cObk6IZjIv}o(5q#R_Jf*82|F{2RC$hJk+t)J@pGDxj& z*1b!HmVbJVb_r28J>`L}@G%#YO)u)FhF%-_$}p;~kRGN76iEl0?cfrk4Sll2t@VCW z!Twkar^dm*fJ1*pL(Yw|EymsP2;1yGGHq8z)LfAt*Lbe9L(@J(bnB@F*+MQpTQH5& zFij0{;g}1V+WtjOab&FOYPsR{E}bxq-PW7-7pwt89v=f~C zAH+K906VGytu(tWe{1NcSmefj!`tHwD+_^cEmv^X_92?;E=_}Yt?s}lPWntL)bXfD zJ??`7VQsXomn>^J{bM{a03Qi@@X)OtEOB#dthbUVvVzOGtA62WMzX83 z?-4zBwGAhd9KqG?P=l9K_gyF{IZ|UowV|Z!j0>{d_#BTRo|F_#(OK%wdjxw~Fkj|d z5Blj?GjGQ@A)}vaYCh^7;+N6ozzAx2Bt7{faor+nCOwTERX${G6=a_IvJX48q+TyJ zb}{@w399U_I_9Eu(efv5bd5#~wM=f6Pe6-XhRO7gJvc(_4`b6Sl5bQ>JNsRa#NoAa z95ijQ-wDkRV_}b9u7||4(2+O0j~f1j)NEgAJC`>&oRVCHX8?-#uW$NKLSUs6o1?oM zA8W7lM8_as+^Qiz+0&T9n!WE4Up%5R?Y%k1BStW3)M^$MEzr3h;tk!UhLKH74VhMO zFno=+E{8=5dLxO@F9p>iy~~Srswb1;BtTj-NS`aJK4vm*4Zj3{5Nzea5S?W6@N#gW z2o>ZpD|U_&#OsFmpCXu5Ms`7l&tEjcJV1SR$S0B-n)IQ>b1(+fWMA} zV8$EdXGN&&sKjG?Xm%?yXDIG9+ve{O4x!R5yW?Fa3+%~1lUkbkGHaegpE)4y!q0el z=uX<>RO|r*0Ke!`I`JyCEyA0<)M7V>2$EMFn?339dH?v`vurC-m^3u5Sm#P1egK!L zdg<{-!uSiw&?$rOEG~RJXRgr>=yHJm@KjEAL_sY{3Z(0*xwbdf@^gsFGg~CoEEAV_ zt+_IUvJ+p0Ciw^m^*%Z3I<63Fs08**>&3z(NTo*)m$yU z#`j!RGX6!z5`r{b-g|bze%Ohh_d+V4+;W35Hp06aAX%QkJALEmC9lNy`j>dc$&-cDezL>4cTd7>5N@q;Q(frphm9Q{L#`_11pqx@ zG{R9UQ!rXf6d-G#oi}{MyxD?|G^pnAg3iEZlRbl~t)V6(wJ5(pegyPjel3=0`E)Xb zf335I)O@ne*i%?b~&O&@XA*Q+Nwx>Xp4^7fI>940%n!8{=9`YFpDFUKV^w#<%YDirw z!}#yy?RPx$sFGpQ<~I1=?Zf);jQW(i#932)ua2^Cl7l)@=X%hLkHMn8LqR{_%yMkU zyD@ZOp#@B$5M@hc3*tqqOw&!=jJhwdz1;5WZY|5XQdt-uJxFX>>Tj#qE`&7?kJa{# zKg9RF+*+v*-&Y_FAlB6W=DiX0ra-`UlGGl~abY9vL0Y27O$or5Y!T&!OL4Sj zvC1=v5+_wPrPs_SlD9sF;%&W^A>`m$H80hDB>lpC`ip!i&}CqLa(+7Uj{&Lw6&S9e zR{pX3Qg7C0+&z5U1K~&Zyw|=?j&55wYNx#?*+9{E=?Cht6<&=I5J*@dc<-wyG-j1ld+yCdD)_cs>!bv`|Y{zGaD%5})pXXO+u<)0eZ# zt2_WzzapxxWm##4=?STK`a{chP;U7u1}9XnQeiyVrnN4 zgGnt6H^XH*0a0GVy?8WifZ@uJx+@*avk6l#n>3I}^OJ9gr%|ny5Va4KWS^|@g`Ge2 z7-`omkC;@ORo9<;YJTe(zr1&v5>b-R^yZvW4JA2726sqMt0Y2_bvq7QARMnx&hO!v zRvz*2A)kVwvT|+8tZ!ZMdCo$&Ro?6K(L=V%qS1`Xjw5;W`|zEm*z(QcN#DURxRt?T zMNUI8^u8B6KlD$Q=08O$c^wtCvY_x5sa-`lABrK5-id!~nq?dgZa;~)==6F9S4k?E z=<4w3J%2Gkv9|NhWSn&fVH{9X6J+vew?bz9H zyA%FlxN`fjp|OnkJMf{$BN^S#Kw;-)9qo+fU2&QP79>w?2b4cfSIrl#`jf55&n+iS zyVnWQb-?7yU>X{wNxD3gndq4fZoaYwk#nKNluwYJUA>}i5@YugzOy4Lix*K1AHx?4 zS2=qH32qcSA0ezeff#4X{@TL^UM+vrSxU@;vhxnHGtbeF#PC8Gm<$ckz7cVR`cN;j ztuIbrjA6vofb{_1A1CAr8H?w|vGFsqG9xTw+Tu~WFei!vorlLsvD9(ERQ z;DRm6n~Q@>y1LiNEVja57L7feC4@qjW{>+HVrk;qNRtIE-4+m$nC}$1=(`YYry5KP z>TnM|VPiwLHDXN+qVuL~Cauo-L0hu9@*_t}5d4$V)?=Cjebhc<81dHmmMiK3sPdQ7 zAptb|0e#>O+w$#2T+QSg$SAX~0cwy{aBP(Nu+)1i#l0nWIELhvtz15b`ET7Pi=z=jnN*>uNXqv%zC1}Q6{@S$y3_nV@}c#L)AGKjYR|B z*=e-BJ5#j&<-S)l^b(pxIM;;HHRdadw6*dr;9!?;&W-`Oeh?>1oUs)80X(2>T|;Bl zR?3yDK<~1ua9SedFFNFBh>dyx{y*OIa%-cT#yLj%Wf5rN!kX7wHI`15|0rylW^alb&+rh_Qki8aO_6)dx|TMnx2rI-7a+YY0r znoYup8wz23+6nRzMFHGGlj|3hyagv@#EW-!b-yoqFHb} zbAab9i%6_tHCMS9_@vSfu!(4!>#!sTI0a@k(i`&XKm^pso&dxWlggn%8REjdPWsfP z4eKN6S#`aNY^ol`Y$75$PW-r7SY~PjYBFvPr8#$EcH!sA1W^OvZp&h<7F>zrS7lb2 z<1smE67_br;W2{vCni>pjt=1=ZQ0nf$^Sr!8I>w=R@!NbWctiAtfJ$z!e(`Tj+J~Y zK71cASooH$5q)@g+4)JHw|1o|BxVx=SLE_~W?s$hV|Gm5&UUpR9_Cu^>f&*n4W3IP z^UG#H>k=kWN$mXrKIUhQ@F+!cBhXiZCRK_`%S~VWr^=yzr%~F9Fh=GnG26(o8j=G^ zexI{K%KC4pWK62+>xRJRcZGiu6#io%f8z7>S%Y+-PWTe{-wrLmRZ3cg#dfP*3&7GT zAI6l^VebS={}me4bNGHH`bd zvYsBY^CVo)_TZGh%8>LzcIMdQ*PNyQ4rE?!SvRC2IgnHWdZWpPD97sB=cl<-z2rF{ z(=Cui-26OxRW7z&|MjP8UmVUEc%AqS#?STMns(g8V9Q0+Wh^N%Nz?-Nuy`mRhKqKDK8JbpeSYTm+NC(t{NLM>v)9$D1(`j5SCa`~ zW>au1Ej@)6xqNw!$oMlIIreLn`e@05vlR`<=@+oPhmwKg#a6oCX1E%tytC|dZ5aT{ zi=xiQvw!@>_ua4dZ@pol2xHE2H^=AI#XrZL4dzM!ts(juc18intUUQUer#o+>OYbg z)jdXYVkE59`Qjg!v8(g6LCAXi=f&BZYzb2c#Uh|{l0Quz;?UQeW;Q#hvdC#j^sFMvUYkUnr`@j9> z4}6fSdd0kjV^yYh`@uWhW-ald_%(prZhwU1~8e zq}%*Pj45q9c+LKUmVTe4_=o?eZRhS?>uO18y*$&g#yfd6Ki+a{Z9e>i#>Z=iNyH~=KZ4uo|x2s7VDZ~vrP*k8+0ms>q< z(nv(c%d7T2d~b{3SJA(5HGcdmZiB>5>D5~2ARu8vIw<+7)$agwvzC80qHJ5^#2t z8#c%@Zj$tSnF}5~bcL^m50?LoFWwPbkD1Dy&p`BhP&Z;#!>tx{o@yKXQzr9wfryo< z)ePjN-~@W+cfRiy1e%ALwFA1|(SID6C=^3SOBN;%KiS**MOLPu?Z}r1pyz>Qh(lAZ z$iC%^D?SWj0rx6~le)q<0wMtI|1bqdI`%$SE)s0TUaChFtw|0d&7*X0i$Wiw&!Hs; z7TXRODkW7y^{nSXtx+_UG>}oI-vX(G9RSi>>SAKB}r|$E>81C2b={vF=rS zoqt!0(i&51Awk7~9)6uZ@pYNy^L>-vn`=IfC8F@dhI79-U5w6FDtJKbMz%Z@OVUo; zOj`d6&@X_#h@p;yT7C4K{ONAYcJr|+3En6nnIBFNm!t-LPpTB=X&gi2x zL&gC=vrRanvO%BxOOx5@>W4r{fX{pnL-n9-tGXTEKpzjzmV03^OhRr$_d2EkV>@?i zIiGmU;rdQWc-babA-bwabFJ;vVVx92xBBBy#a(fKVX-EM7x}73it)_v2Y3&JgMu}o zNOLHCTUPm>O8&L}JoEoZjJ96_k_JU-}L)X3Iqo`kgByaGO_OCLompJ|kPBUX_ zey_maF99`l$ z6>Ky;?lcx{7o;^%B+wtvT7Z{~_fG-63?t57?t0KyISIrIxd;J?Qf8I z71zo}dgSgl_O-Yg53hoj%Q?P%I?domUP#XwKF3l(EeD!eL*?^(=mBJIp<= zv(B9*e|$&F+8fCMf2uFA!dC)4T9_{}h1b@6yRXHEn)}8gGCq-EunaZE^!-iorLAn(#p@$xL0~TGxyCM%b0^(EppbJp+Oq1*cmM~)KAex8?JVXLDmx)HIyhzld~e%bl-BVnQ$biZzPRQ3A%x7&Z}hw z8FpHCk$1lA3Gt=Zc<5oGJ2ZZl`4`88K|8!cFh%;h#r#}U^{gRRVCj)`fUrt(+%Yt! zfzPn<4PYYpMfSs&r`kMDjhtV)i{uzpoSaTUWGS| zdxmH)TFD#}u&)^Tc{6toZz9hHL#fvE@rU-b=uV(N{0QpEwmTY4RtHI!y&a-qmC1w8 zwp|J=YBu&cl6}_CZoU2e$Wmk{$fP8=y}s~B2_n8cc(1&RA>NB;uUOGDSOv4Myh%^& zTI84>=qlFE5zhYhbW-zPAy*Ju=Qrdp+W{f6i{*N=EW^NRIqV=&C%w$9D&G zCQJK*_sJKWZKRX4k%_cU`uL!QG)&618!3>Q81fTG!lkt`EMg;$Uo#e)#%)Cx1n!^?F8Q zO_j8>DPRxVWu2(v>H)Jmce@3i11v(u8CIKaYQg2gc*#8&Q+aBdq4^+X*Gm| z?3;294Ve`)m*xsr_Q&d1CKLMt2BofCCpX;6m7V?~PibWk5@>4bQa8hLf%YU9`j@wN z6Q5X*YtCL6_z1VO+7EOr<;{&>PP=0(gEe0S)Jn57cd`KPFR;F+gDvU|#3CS~{K0&P z?buP#vX{@%a1KzN+T_(fvLGS=f~igmo++Hg=|9&h?ddHZUm<)Mnx7{e%|&nxxu57W z>suzQ{dlOU!ODR5kMXEUX!s>PCH>hM9Qj1N_7UyY?*dL6pAekN(vE`^m0|A|DF6hO zcty1D2`pnhW|Hvo?8Q^OVtJ0;Lzoe;(Pm1<_wGIwe5eI=FT>1C5Qo<-a>`;z?3e?m zdY1BgnexyrcG7d7Nka)6$*@2hc$j$`(D81FAXtp#_4j&A)tF$)a;pe}!r52*N8%{W zX^{oRR6{*cWws}OIqy1sAp8^xn6mJOA0Uk`9v6G=%-nSJ+&${YEO9%8Pic%o^@Nlg zwl67+zlHby1M={PQu;O~_G{hUB+KHy2fqNC2YlA?xR=8*-huS>sg~7wX$?8RuBAs7 ztmYkciu#DGMg1_Qr5bCZBVzzj5*OtUOb@kchjnCKkYOX8{M}EdSQ7Ad%;Io75oo3d zi+N0;>pbfcy#Q2*^*E?dfVQ7%9?PgruBNkq>a;A8V_g_!q*Rku5xD~LfD@lQKZH@O&^HYiom{t z&_?)GdJT&)j0}#X776x7vRtcz6Nu%~5tHy}i-mclKWDp!*2Og1%T@56z!tpu4SjY; zVY`6x8BqZR>b^D|y>Ktz%ny3B2R*12GiYv~gc0Rxp1b?WvO1mv^ z`y7(ThQx=pAI+b?!P@RRiY`R{0m%XTgNeYOM+EW*Hc7ADneM!ZD(Ovd;WgCe+sREu=!%p zi%pq2annEs>amIsY|K9GYuvYPXYOtx3LRQK55V=DDuvHbN3swuYI z$E>)i>hqzR-agl<(bq9Gg+k2PaeI5atXEi=+~PHl|a9KsS2zeKN}tuIuo=9pcI<*ZQzp)_6GIFM2^O zU0a!Gc~U&*U;dIQCK5+9G2)}Y zs*T#$Q9eH@$T0oxP^%{d{3{_^)wrlFDAAX`U@CyHYZ=2e|hNDMGkKcw*(X;<$oCn zc-Iq5rvl|PVsysU=+nlYrE{6db|EyBY^n6sDLMYfE{$||4uzt*UEd9t%++N8y$#2_ zLd|(cB8qEl*=+!35x%p{u8HFD{f*l&r2so-a5DUkX-i(JI1OC7I-+TdD!)vc?oAUH z%U1NI_x~SzZy(R}-v5D@qZ^fU=t||TPDx4>C%IRgt2?)myD%J$#0W9WETwdETW&^f zmI}$u+-~kRsuMD-#D=jcw3uz~wz1jv`{-Qfy3RS*>A24Czu)ii?Jtk@**@?0>-~Da z?qAQBl?3i2E5?ne63QDbesIH$ebX(a8+ZG!sy=?v`>nGpWw~>9+PznHa?kcDs@iqE z);)hI|FG#)dmTMVw)bkaWl{-sufdz|i!Dp&pG}Gv`~&l@)}=e|Mm-$WaS|JAHjyFM z*!7Ir{ghJ=27B^=0=DfQBP`z8C}bN{q!P?QvS*QSZx%>ncV2A z1b+!@f%wL>j1(>R>5&?dK<au!ba0X(dw3$1!9;>|J%$P}7V%~gZ z;z_w@6we&fA=9DicVk05%)8({oTOxnC*ecQF(}J2PP5?ze?AQZf(;LWT#3I$yZm$4 z?V4+>c+Nvid38eS15pfzQEYpHgg{rKisOUJ#TQ=MA2CAOIuI%%^TzvDP!+Bko@+Vo zSJ&VFiTBeBhzrc^eTpOZQp&mOlW8{m@ZyiguMOT@vDdX{Ue38v;s0@p&_{owTQr4c zfTqG8TtB`3_`CW#q+zY~5q~f@MzNt^*FU?wf>$ry=1Hulgqse59sJOExMI9={PX>p(qAKDCLMZ=Oxy4foJ*+&FD9nVQ*tOJUkWpo@; zQrv&+lJ9d<^6+}sXl1EkJI`9guy%d}(D#uUp}L3Ycj@%6vG}iWsU+*n=xbq|LGt(K zz{S?Z`(Ic1`KLe4FjTX)I(OMZ`}D^_ZPg2mOncdvBp?vODbdAVZ@5nB_O!wcCg;Du z4ou3)55_XVOnd_v1_06SK9l^!Ur?z#dqfwRZ_UATW?`k~Z67zDy9F!}yIb966eL;H zlZRE_M^=Wxkct)|^qF!9CoE!h`K@?nR0V1#x}JMi_wYu?8v_Q66T7p>xQW#zU+ucu}Ds^Z%<1MrkI4dx#=)>L1{6JS3pB+{A^HC zQ@;?1M1RP8=?X6&&TQY|Z@9xck_Q={(#r_$pJI05sBwp z#A6T2pCzn`RoJ-Suf}GhO~{1@+|?sb|F(?Q#D+?W2nZoPKFIFH37S!}Uh#Jfpt02` zcKAaribVZ@@c1-$}MiR9+RZv;ewf!7UU@TaUjU5vhU=D z-`K8ywvYc12xy)>4G4EZ@k1m2>w4KS?)@& zyW1&-T>Z_~hfl{$68GgA58sW%;20+#dj-(XseyfuU7WI`^z==%m83soBJMry$SEP zbo`ekGa(6bt2lIgb?@(YB%D!{1Qs2Cf%LU8Fke}|JdlHqK4t0f_g)vV6(BO|)j`JU z>g2cYjorNI3uyJt{*r&ANd9kBjV(ShGYLQvptu_uN~@mW@7|dpRZCGpz^ZmTTn~=* zKnOV>nt<{EH@1MsRspUJG65SL^bhR@*4MAh;Cbsa$oJ^Je%l2xlXGhtFyUWyeKZnfx zw6!eof1~@%{*|KiWdN))9sufzIUN8MKpwC3)xQGxTO|f4a!63C#^@%CoULSo<_)5z zVXxcAwFX!E(!ZT8OvAZO5Z@RU0ZB@G2A|&kYo5}o*R(MCIMWEJP4rWU*7SaklH6D( zcZL3jqZhHj%P8IfjrnQ319gVg4;ukJ+P(_ehi|p^10kkq9x#n9{^7-U-e4C|2#=Ny z=dng=tWLAsjnr(}TXM#;Z~*J1g>Uhf4M}!z4e$?%z*~C#f^Fcxu1NMgxdKrd0$}tv zPenQ$@AAFB3AQLI{>Yb)c$jVr`F{Ti`GZV z3bHn-voAeREio_cgx=~TV}BLBH7 zFIfO3{@$%E-ggaxGFPujN?w;r5j_of8N0NBS6Vv^K&19wlWQ|sc;E?USEa;s_g_}= zHvK`tsoOA?6?Ja(N(Q)puCx#CKmgVG&pglf9XoKXf8CtY37tu`>BdgzxOtP3e@gyI?w?I;ym8|z6+g&U4_#mfV#zE{b--B}1;$>&iLA9N|nP|3uY2TCS zlywzD#}~)$yRKl9#JX?VvM!Y&)+}j}d#WXMS8ZdogUIzVQnVVVN9_A=BX*j_eEe`l zIakcqjL&dMr3{YD$q3C0NXz>W!W6MOtY7rbbZxWjOUgupeolf% z`dLndXcAm_$m15{p?>n3*s&c4PYpyTPmi4eQF;xEVz8(|ocO>`2nEL;M9%mbi_pcG z7)vUpv8~U171=Yt?d;UzySbl#4AR+aI^U&J*gsFFnsUkO=48YGjJ&qojIDEnNt*#c ze9}M8KKeX?^uS+>h%q{*dL>=Os?UNIwBw6uPPCPvNKP0L$s^*}7T za%*%c=%G4IdP*155EDS9C^j|zszZJ!+y5iZJYytaoA&}|H}>)~o7RHxYQo+}jGB&{ z&hhw{fk|q`hpz!mm78@c(F)%`3_%#W|8w7$!*P(Dd(z~cYby*8 z>I@g`OHgl5_lEJ3n{}};hsmHwO<_+s!@YBS=`HU?qt*n!1CJq=M$i}C-EWmp%x<*y z%Q{aqjpSZVuA(g|UO|FUgS+UB2=xMpe;U(!fqJ<)c@;A(c5K^#>qh-pvhG6N=EvaJ zPT3*LEYE)1pb?tEb-g~Hww!R;<}OrdKEbZXJb$dJc>NSoR|Ihf6=E##jbd2&?haHY3;xEDm>%r&#d*VNjDWhDer5B*K3ReS z+{w6rEn$PEQr|~>-9$xlsCq-%gW=NL zi_>53UBjkYlrWT89J895j~&@$w zgn)d`vv{*Rlc7o%176(%ukQo7O6g+?aJBAaq)9ELPZ%|pbYiMIgWNu4?Qy54y^-!U zv30BBQ4-tAGK&1_q=_WvXXI>MO4T?%BRAIt>KO3W>C@PlY0}hGpoj#U@Xz&)}wC2oe zrt#%xG^Tz4I?amhFae;78Od;(GKf>#KTh>jOI-I{idc$PUcJB7S^>XK(F(X*r)@;6xJ>vkuVIk00N)d)$kRUS! zQP~Ks8@b+5ygW=$*a(it8Za)|`n~iB?Yxkgb;r`qM3}|ET`i-5%R(apiSxEC-p0lL z*S3c9SN2nSAXU8e4MJ`_6t@h0lX^-xXnL{j>-YixGWf6kLz27OZ0nVqplnXWl{cn* zUoO$%W+i0XBl!cR6pPU^<}2rpN)rsorpfz5pKfZFizU52G07`gI08mRtsO78#%L7Q zAEGh^+BKV!k1%1?#xc_a&E%*LA3`ks@ntNGR$)H30cUeW!JAS6b2!{M!X&{4m;8t@ z*s?Pl1D8&&n>fCrodzmS3L-&QJ?JemomKg(OafQ{{BUe?u^4N?rLbJiC?iu$Tbiv;M!0+qa2YLU5%-cQGd_l}&wB+JB8Kbz@Cj8 z2I+XiAv8q$b@aU;SV~X0vc7L5Iz9BLk1dJHWq9h zX&C!KcllxKM}rq~)Esy9;GkQ$oc?;;lhC}xky}M^ZVam8d))KHCO9g6w$Ho7{LMtY z9cyPkJz84%7Rm%@Y8c(Qu9NN{)JL`qY1fwVvrR9i2>(sSulzAOu&$!pZ;ce3+8i1B zPH;wSu>EMU39(K~$`U`@rcfh&z2`OL;EiYjmzmMn0aLAbaxixg&M3@#qi6c?8Pa?4 zg4qbofh_m76W0(n*`H<`!WxvCpyRxLsnZSJwsW%#JycVyWT&i}l^cVlt^IU#2mFto z*MC_`q1*HpEjx_k=2AqE89gt|+$DBBoK2YS3U!NmF|-h>5pj$>=nG|1K;FkLsofYR zy@HW_19==7p&z$*E=l1;=hV`?fsU`oGtYPhN~6<+DCbPuLxH84i?>b*9dAcf2yKM2 zQ!n+ekmcGB0BrvJ()AzIES*-lGoIlRHCy(cQIEZ$JF2UCFm>A`U?O$CE#7{zK8!)S zJ!>OH@*$0vVlHQr!d;Hv$Q_Hs-a}%G?+h1bHVwbz^2YORC2C8Iy(k7(+<0Lcqo#c| z-YrhA)lv*n-ExPHwa>og4e+Dugr(Tx%+i#qFI?8XH?`$bWe*%L{P3Oe*GG|qP+6&U)(g0ABlp~=y(ISrR}A1zhVI#Q@znl#CI2# zOQ!l4FE9W*(mxDc5zpKAk_&IxG5zWm=J+jkBa;TGjF*-zU|p^ey0P{^@pbf}*zv4% z+YqJE9?_3T4qT(0*9cMO?{>q|lE3Imf&|moT=2~k!Wp9>djy%FjFL9DqXpdtU~F-%*=#Bc_^ zH>FEt2o6R+d|aEST^uDHc;?IzU~$eGb9o0-s4_=CP1pFfz)-Kf#~`NjWMNFTUrRgx z^A}0~S2w8ACU!i@;?ts0oSSa=;7^j zLzp4M@fA(d;TWNM4`k1iBiMkZJgIOOJ?=KTDg;Bmcym9l@?-VvRvg}+UEnX=mT$fu zECw=EgsCw)6{Za*io*2`4gH}^coR;ylVhL%zQEz-S#vs?Ud?-<>341Fc;-=8cJ$Vf z7UcI$?+C@$qyr^KJpm1{W#hO>9k8vV&PNHl#*)=b0~^Tpve@6TKc+R+!s8=AT5qfq)yOrg2D zAvZ;24oM%IAHK8B!cgjYo!2YL$)RlG`K2lYx!eH8a{`%R9vg4xa~=k?9%WZToAzIJ zGm{5rew58RLN5rQ4^(S0^aBU8+Lrx!+C>Y+^5=&$&b7S@EfHjD6EdmC2TGwxs%l3s z!{0Ff<499m=&~lxLRcsRL0EXe(Db_eu#zXoRd#!*)0#|zsLd`QWq1$n5j?05KrzpZ zKg8q|9&rum6!n6Fas~BHb?YacDDBgSgsnzPh;jfh%y4T?x&~^rI(BBJ253#Ybz1tBrgzV$&q1;i>lO+tO0iUB%Hj7c z1^}m(z3m($bsJdeX&D1@Yc%o*vk!7a!5-AIA{xEVD})(?Jrrg%1u!td-<*i^zLe&W ztaQk*7D1y*?XII^7s`F_lkXVa=|u9Qfd9TTWs@3l@bmjpHKtW$3y)t{3YYpoX6IpO zxT8X6k4~81XT?tgn4~IxQDzWB(ZCmniDHv6cxo`%qhhcCoDp?i3HX(^&`o5|U07cU zNo)H@P#cBalZU|ZQv)QC1HbzGAcPZCmR~@;!=J|+i{8>~9FMsb1{hj@@zTB`Tfb;h z&ws@Fmu?4P1F~bGd1FpX8^mz}*^S-DN;Ra=dA+jn+G&*P;Ma%tc3SmZ@Y{FlRSCCv zd-4F5*GP`kw-LlxzxAC8yC0%%TC7T?fJnyi?cwOoCATo2ZUDIu4_HZ1ugBIBk`)!L zZ=rbiXez`$k|Ly%eP3Y&I4k?GRXq@^b<`Zd11sVrDx+-8m5Ii@;ibefbtA5C@_dvJ z-97BiJ4G_4t}IVcXZzL;|Mtdo&tS6zW?7)r`U-~Orwh~bzQr(>>fNE7$jCCPcLan+ zecjkx97PR2{3#yaCbystXS%0MG7cfmn@sQ;_V>}ahD>={7{7W--%=soASIIc>DcwW zj9K{<_hFCo3Jen!!SQ-ly%NxQ73;VMW$MzIxZD6u>2{_mBc3tc7hr?FuXIg_;qTby zdEYSqqC@kG!5Di+LN#>x=a0W!`3(tY4Dq5Ck$k~njnvdDnX;MnFSo;X8L)9j{Z~b_ z|BnGW@Ss&qyku&Mp7fH8oTXZJxIT9|e&)!Y=w{mcc38{bg6+kq%^Zw#^Epig;jVra z>h-^@o-dp=nl5?%)8bFBKMtuU5uE@0ncwO9FW>stCj+<}+vZqFb$`XW|NZ6Br;>50 zHdEJk|B9dg-;ey+C$S@&Hv-7&&YOR`g1=HszpTpo{K<_=Ppykz{D<_be+lqy{%>o) zr}O{&Qv+fXrUUT9m;M*B|K^#|A0(AEy5ge0EABn|_xN(!Vw8{H-TNgGleoE=JLI2G zoF6sS{1ynJ@9ms-O_lz3lJT#>LJfta!8YfYmR4$thxzTtsPXwc_l zehuX;jWUa3)xKHOL#+@ zB^Hh$Dnb2sLh%ou3{hgnoUJ9AS2DjJYQ?QVE>hoVF9J)!za$z<> zeH`9EG-(hrPxB4Egx!eN7AsoiuTa{DVs-4AV=x9=u7xOLX^iS;Eo_c9Vz=Y zR`~wfki?R8MvG=;Cv@QM{=S?Ub^#K+cDxZ0IvF~m#`yi!_!DW>%9kLk7&(ha;Y#|d zGg&T46jhxAK-674%ZiJGtxb{qt~$UV#|_PDPeKiJDmL3BUPr%rBO}=vhPvY<{T4gH z;0=N{gqS5|WIrRo{PSFfZ0^3YU0Il_WG8?LeGAgkPC`)%qw%n!Z@1JNX|86kez`V!C3x0=jbXp%lmhegC}o6uoj^$?$4t$?>( z>l$-0zS6l?N0leBjiV=bryiKK6>0mU%OHQ{FJo$%dDmdJXQ<0m2$-gB%q9rZyFTe= zf;3-lS(08?Aziod5JRJC?$J z5ijfKdkVyb?^(-;@lR09ja6FxNh(5#%?b0d`kCYN0k#;j&_@N z+DM-W>^KP8_@poGWV->Pf}eDP8Zmr(=zA&?CA5AaX-D>>2k%p;=o2bEKV)rOiitKe zGAC3t!|l5|P8e#$?nXO?xKl9h6&sNbagB1_D)Lx?bFup!EKrDgaw(vH}O3Y9-py?VE> z;t!s5oxNH)|0tKXtM$Uodb_T>OzIhR_xqjy|&su3fENNbSx-^))p=>d3ec}&36e8 zFba{DPs2o44U8Muv6&9 z{3+d`keogm37oUSb()*{P+^f1+h~L#cI#4XXL{igGD)X!>q<-EU)x);OB<(+;)b_| zj{y?2 zeoA5~`Z>F0NfD&`&8%iuQ4H}4#bm+vGDT%ohv-JDj|5C+FLnfCz9kZ_absY!F{wrl z$(P%sxM^pmHp2w_qC08}ut|XLcI>i`)L^`CEWqnt(IZi-ZD%!`Ef7<5(&HFN0M59A zN-g9$&(yJkMo>}k9G%akwS|pIUK zQ9`JbSvCT5ixFNF{8@BU3sYsr5#T=FZLBC=U8R`EGMXIEdWIeR?1arr9Ze7690MEI$f+3( zDx;W2cD&~wM(udjbc3ULM?0Qd@Ik~1KovK}x7AHWoIl7}QEx*Q&kE}-n#_emx1m}; zykCDvF2X%*xXzaZoyZIA-(7?&@YkAP?77ex=s$Uz9X~w8^KCnN5kqdNs@~<@!0N0r zk1fe>e|vl&{}tCjeT-d~F^ggOHQ`Bw*+OC@tKXpo-x);_^9Q=_;#d!2Y-W2R;V%id$W z{})ET2&C5sEYL%{h(p`V4erl)xyUBwRPW!Cee!hBxk~L1c**aINaWJu>C#&}AX(`2 z!M4zs_jZwirgyERa`|*Ol8@HWEbpjrX5>`{OUb@7fYQ|0#GqR>!)kW68(QO3A^r5@ zUK5~gP0;CTII}?^%HwJN!V~v4>OPJjtc=<>_%Lx@QEy5_zlBzxdy7eJ{;W)0zXIFV z7%aARpWrkY@p@qFhxbkeAz=8-B>x;<8W<9}BE+4}?V-)ieUlRn?cRrqpO`;Elb;h7 zKvhr)7e?rFdDor=f!)l}l+`q&$GlJ{D1TMbW0w#zK zG|sFWiJCA_oY&;MzNS&;)@cRrsT<*f2c6rfI$=#rfzKd^%Jp{fJOqMxv`M@RqfK#Y z4Rt>?%TE=G-kIaX10+{Am|k2Ln4+Q})?}%91C5Sf_WWq85_YV|f5`|$pRX$Sm!~kH zw|m>%1g?B~_Nuzp*~XK;cO2sy_O@JlfBH2~<0tgzYhQF3<=FZvRF(=Z_<;Q>Xo7|- zyWjMC2D7@csF}L{lK&I+cCF3(txKLb`FK!q7-&P#KiHsApA3H>dp{C95!F-Yu0?qH zSe+tT6xQ08H-boT5v9g5U) z|EUQK7j&)SNLu6E*}=ZS^*RGp2N%P zQV{vIenD}ScX6DXg?nTVrwQ#J@xC>57gVWBdAEhqdCm5IFdZNB3^qUPzOYj35c=&w z)R9OQ9M#Rc5#63=(ScpSinern9NcxuQD}1Pe@I~6XcetfHVT*?H$|Di zgT1qd!Yf7$EL${Eb8RE2?*(|IrBccl_`YkqCBmLz6Far!yab{}_Fuwuyx4q2x?gX>u0n^uht9BI53(S`}oo#=WP zok(z)uRssNbJ1>wkQ|^Qzm2&rBMN@L!C*UTjPWSgU2MR9r5G9>PV$esPU{n;I9A`5 zf1hIXC{{aIh8R--m$jEyY&PN>$ zF}4Vypu@U`3>*goaZdUe&8G6GDTDHrG*>HY-5tCu`}qWS{xR=KE{MY6(VD5G_l9jI zE6MM_G#EYc5-_Q~ygMx#PqFOODHGox{o73nnLuEoq&=cmP?Q*XK3jcF6PI>p&_CkU5w`!l?C&SBqVu~Zxi!oLqGjGfBjDxVr9wK?tNL-%}rrv(OXS@97i>9YbIP6L0KL8IM&(=z$yhgBy6Dbz0slxV6VNFW@~EOg3aD9pj9@6I|%5 z_MVSohsI3Ta|Ln4ykkeutH#2CLNAMr4TV?CH-=sN@!*wV(uE*3pu9*SC^!CKQJkV& z{T1KToZV$*lo3*t!ukNl5h3K2GNb_xVH29R79*=5`#Ksovq2uANfX0X4F`(T)z^Cy z0mK5_!d&0A3qli1)d^#}{F5+a@HuL;3=Jr2QHO*-u&HXdL`TINUz zF{VErq~jLUnRUEm$p8z)`Gx{|?FH7pLQ5F6x&;C)3y3V|Xb9o~7CkpejnKw(g?1hY zz(kLs*Oi!-}VKz+4z0=sQf#oOGANja8$i^?f~DJ-E_GyuB(NrqnsS zvROM(0=BSQ{6H5M!jFa}p2^?GDq!@z?v$`X}rm$$3sf4A1SDw2pB)phQ zD!aWql|G)?X)df*7*)upcAXWLN*c@k@#8e#tiR zf*J9SglcG;5_#1kgFi$(wthGBbL6MRWyB8h*4}TDR!iXh!7RO2D`5tpu1{V6I!5Fl z-uFd?wt4}1E19v1RaMvTzkKHKp1A1RV(a!*ihce=?=L!0@idUPI?B4VN@4N;ZSAkE zn;XEXQ8({3)w5*$O;Vm5y(_6ak=z{@{X_Apm0Eu|yslHDUK15WW5x9&ujfXhUo$rCQ`T9?93|m-XE5u7!Rbkf^*ey|J@t&S1RqO!rHy#gSnfO z{vJZ+HAUd+wFl=fJor0AxzQQ`Ts_~=L)ZUCf_=p-4&LZy%Kmg~>~k6D@5+chu@CfP zeylnwHy7Iz>+|=HLa`K}X;r?ya8=#&JJES<4?xpzUifGJJ=#=la&t9`0J3NK$zh88 zRdE-8&mOH?*D2GJR4THhBIDma|C{T*2OMT`gk#cQU>N^_+g2_s@XEMU=-tw*t63Aj zzbC~90Xcflw?FIm8(582)3%Q`0Wm@^oxi!clcV+PVscMZ0PJeKAGd0e`R@+$q^BuB z89^{<)8DxHK!7Ff+ihllQ#Y?{pSy2QT(gRA`6`m|50ui|1#nxMe#UyUKRKg6Jo_6- z@PAwT1ONU1`_$_3&PICKFLrMHTb#UBqG@|Xy0Na@oMux0-;+qAl7MuunR&Wf_HVrr zXd(ovgY5q9Xl`rUQT{DC#q_ueL}_5gx5gqE>Ga=$i?!6LqE>On!*<9Maz~3g$k<^FqQ`x8}6I_^==H&$& z@xo)HKx%UXopk))XzqV?VxFO~j2x$eJEh;v^jc`S@4V_094+LKwWe!+%~NO9ob-9z zGY5?L*1`*!K`3+!&;XI3g;*lc8KPeYSzptTz>^gT*}XPj(UsR4S5z=85UO2GN3|?s zTW_aAUzXYZ^0X(AY@EI5gQ`GQ3(;au%MP;&ud;tt#h=-m%03D%X(2bybskPY$8bs$ z?JZO&!*s)G-cYcAJS1f2v!>7fZmZhAi_bctMfHbZACbl?67%=;j z6V(V2Jzj&JessIkX<`7HC7C|2)bVxwG*Afesb-i>B@3tlao^dmLo^EYq5z=xP8NIC zj*ID&s3@b)9{krfM+-z~S*i++aPR<=CYeC|F_ zQ{g@L;n(Udx(=op0D((OIlRszYO?Tkl0u3om{C%kf2fIwI#Dh#0~-!yg^K0u2wOV9 zZ=wv%Ln6E9KN=-2RmHFEHhAjdCSo82rStt1@ds0+`v!#Q1WLGY+hiGO${)JTYzW-H zu$!(?&JizhX_|P>%&a_OiS*IAO~;82YPrNtSEoOAqT-h}EtoxAfg6uDEc1oQ?QClQ zR1?7Bk@>`Q`C3CLO9Q_=p@r;rF>Ya#cO>|$!21g4a?5#euc~^{=7iTN`1zUH^4A~Z z{d|8kPPc(Q`Ko}A zO1-Z1L(g=_%??xiA=z;uPt5hzy6uH<`#5*W%q@QFKCI4APk{}xP?P1-ZxB096W=nG zKaKCGe@CK;nQV6hlOAA@0Ij~3mK?dcdA`RGX^?ddwTrD)70|pdw$otCTt7M{?A`ja zx`CHB|DzVQnecr1Wu9s7gs={Wp-;huAA*`?wJUD5dw-JJC!VpfHcZUj)1RP)*NZ&B z7_I@qIsI?E#>3YyHh>hEVb{upf$d&7t=h3x<_~dW$T}C0&7P%lTBC!manPwzIdpSm zNoMIZKvA;PUJo;P{S)~gM57x_2M%BTlK1#i+tKq#tc|FPn5%-^Ggnu4bztn2)b^FJ z5DAir?U_L1ul+Y2C8d3Nw#>cA1$h6OkP$Ihm!j-?Q-))=;Q>SF6bw}N&>|8PPT+DTkwcC~wZTMc%JJ`;OV)PXE> zthxm7+XaI%aK2N~b|;^ktu*1AAkZNWLOeCyYhw5Z>+QE{Ga1N36*T6!M8gQSclFke zX_)JL=evG9{G0-SY=dYPv?VEwq=rbnQ~ptxCYv8K{N`#Q69GB|FTa;Z6d8@%At|J& zp{u^RJ$l^1ct{dBhm+X7GdtU>g)?&@GcFm}96HWh#&{o)#%T!j#Y~3#<(YEd*2+IV zEGlz-(T^1qRN&0zMGBHh5*fL`RbTMVWjuIfr zXfe%<$zl|%=Rt0Eo7@liV_U{j41;d3iOpE2?aw+u7?_n(;$@;1`^sPQTEdskKylUF zq|MvgvwY62X_!_pox9p>5Du?6bPdRGI>=ne|Eix*iD`Xd*5T{xd#j*d@)9N0|8&-# z5UtM-=O7XKYpDRx6Vyw4K3M6K)u6d#Dj{pgI+>-BYcS_bqltIx4--#!02CZ10o)l%K8ATZ_8TAYU9UTtafDQSXiS zzUYtA9gz(EbUn{^$GEOrZtH9l3h_N5IFcEUsCHhSp+14DM&!%8gr% zsAJ0lMtU%0xdVYnb)mYheJ6$!oUeWRlvQ~^A%_L(xV87i8w z^DNa&yFs!M^`Z0GyEnfjwL2sB&uEEX+shx!TvF9T&fgCqbb_7@06Mg0$Jv>gJSa7C zxdQ{%iCxax$9q#fPR)ix*65?@p&B(PBD}=6$I63IIi<*tVS3BME=Y99^F$GcW5-mM zd!Ee9R#%&vOx2Tyb}0hYxVu~=+M%preVIdAhhc8AQ5K_DH!qJtTdJIH#Cg;B)~$iZ3A%B*yUZ#&@HI!iW78Voq8 z&UCwet!vQf;jUUkWMS8JH-4JuY_%#NI*P`Ptb<+Dj4}qx=iRU8(9YPrBLUG1XU!QX zVlGF1lQ7L!)PEbIAo)r2t>`#VJyOt+a_XyNJ!8kdtvBIS>R6kL)8Z2*4^PSD^dsO^bVsdg*SP z8Qi*xPzs}EApzBB3%==!vnAa&>u);*CU{AisNKymg?VWC3A99W<%LYKkR}4bouS5K zSKCR4oqa-CxbQ;)T~6{VvPghvypF$T)8lGPxPr!YSw7r#hQgSjMRVULgdbq3zj)Cb zPC*xBKc<9CEK=tWF?q>aV?=-E@qCf$b(0ALmC~ki=oGBjiH_k;h+HWA54a>oqu*PbbNMLX7YVQ0D>4 zloS0)5Vd6@f*21BwmcWl?&iW$v%}qC6lh*(636)JGgP)J?0f@P&*mxyh(2KtXO2q=(!wuw2a%f8%5BQ$=K)LH|Be=X(jslDW$L!c+@RBrFukP_ zEF0>3p&~DzGWKrPS8Jd+FWnI_;S0PVaK0d?oan+OjltO(!DoTsCv%}d1zU1f$B zX=9zr71PzM+V{ydflclzI#&p+Mp_{*m%>9VKCwt*08_7nh9iqE2EV0qwQi*oQMba+ zkA2P0X+5{OE9$^_$(+59N&Y1=zO&A2D%|mdJ7=HH7UY_cp$_f=3kpym1-UAe`hLri z$xvg%Iok#}+s3)tJ$%>j`EB2?{TO$PvJK3?FO+&(WcjkBxY06uDMG=UhJ+f|gbq#T z(Q?_jlxC0?UrD4V+wkGrO{FjpGW8+u$5>}=Tj;1njVX3DZ$%Ap6W zUQj(umP^#6go$Mz68yb+qQ>QPj-)_C@Q(o=eYEk3#b+Go{F-Vi^chE8M@8j%Q2bTi zc5y&7>sDks%;V+jQYu|0%mni;5NN%Iw<+EFc+3&nIetc?xOsU_OFZ}8-qGPSS+hXo zw7ARHBoy>%Ohp_am>UhBa(AR3;z;XWf2?IGHOC75tXiLYjcqEtEsjuE%)#&9mPfYp z$p9n6(7h=R1lD7kR7AU0W}&Fj`c0I z;F@KdGgT|2I!}#94NDaU!pZ~-nm}bDz8aK*1`!#M&ssH$BnzV=4T!P64{|TR%H*{n zdAfR*9QJfNy;W#J1dp^hkdf;oW!s)3!3ASrPJbBlDvlY7&P(_64e%!bxXI2z=RfPU zbCMyHN?iU)Sj*r9eKgA02>+zQba@jDE=1e6pBR-gw!Xq~rnW;C{R1K>qP=a-uJO@F z=z*U%s1x|dKXhB>LU?Caqtr_b0CMs$$D8*p z%e{ZX_QhcS`{(c=f|{NpeaQ5~sMWB&uX6BJMg_$tCvx0Ptv=VAi|f-FC}O&Ie`mP; zaoH;nZpOz9=&cwGVT|=`Hd;n;7eU!}+_yx;EHWsMc*m8u&%1j|D`n%mK#HMoS!lXA z|GGttH5Jqo%AufxUibkr*>2EdYfrdwPyQLRL1v^@JCe@jD;d%uVhg26R#IUMe30+F z*vNWsYZ$Dwo1xh=Q9Y|T#VL7#UG@_cWUEr%zC7UVhj?ly+I}6KBztrju=$1|+GzUy zZInDi=nnIVsatYx$>;onI*)N?N$u-GQq)n$!rlxY)+m)){_HA4IMI>^qsgy0Y_8?` z_J{IXFH+|@4|s@}=-HQ>wfdUW&`6jq{A7b^Ivl4xQCC7_8eHnB(79fKWpQ zFz`_L)`q;$6SZ47IHj?-v+a$Dg9n#|Y@l5wHEQjItfJ`CiI$~$H=MR(kUMm#=csC* z8yVq1qHJR~1<_0w-%@rZTcD!$4tEU*QfR`qAEy#~C=~*+sDJRInn_rxKZy~99gUlL z-sSKs7C;_lnrDj`TW0a_q12oeL6+isR@8dN zJM2ecrv?u;?eH9)`i^thv8{LS1W@Hm!}q-M=|E#Mj>5(g3)#Nj_FP#V>0=3!+5G8 z0C(h%E;U#j&V&d&TJi_)lHIkFxkg151)&2?ZSh0Y{szUXLGOi-&lOv@^y%CSf zQEHoXo#FQk7qgA#r{VzP%lBDh1`oN$MeFoy>}U4ajC%+o*w6AGo+!~-HZq}Br?`x83vB-LAcOm=hUjW0*j3ypZRBvAtUB^ zb=Qjf<}J`(B=y1DOD?hxEUr{+?a3fd(F?Y@x%-eAI6xy?cA%xj(zl<-bJc7wY|yY{ zJKr_96MFQVX-cFz8yCLCn@zz?n_w&kbjUUW(781s?;lNK+GlRjVs`!zlNCwuzS1Dt zoB}#`W$BOxPVmDnC{>`En5(i+kpMFkY5;|2u~Lj4W}^m`5^Zv4%^clSyi_i&j~bL( zCRrE?W^C8!x2IPIEA8lkmzV2+DN!|O`G6jgMkFN18-9_&74uZ6%kSGWe8Oq&no?Ol zr-yY@A7;bpl?xIblVqs)bI;@a!V>~VX*+f`Yr)rvpvxb*B)u+G=ZbDD~ zl32InU|Xp?QGBnXuxHeuD*+caj(m*8F4bqy&tg7~+QIt&$l?Ao8Gcwg z*6vP{sEEae)uKYxJ9ETH?^We0p{J^w3l-wCw_kD_uJJK`q(xmQgP3Mnm))nu2UXdt zM@?256O1IJ5aK(1zc2E=T;oeguN5^i-yLEHyzCL(#hW~il!30Y1~ig z?M`^l2j)xRn1BZv4>1DwUO%~IZf%H>zZ>|o+in#yX*igU*&J6F_Dr|g@hB!p^4jT1 zAgT@Dy~=JYFPHvU_4+;gHAt-TP$t?iaVO_}qUQ(+^F+x)Ez;vsDxTfabJ+VoCS(L|kx538QLSMSb-Ai=Z8HK>>X$l77(5cwV1m=wAD z81MG$eMe*hh?ZxyHyOgCj?eg)mp9fKGx0hr z&GA(R;L*PQ6eW7+RjYY=-2C#;q1|0(qh8{z{`eSWf zO?N}>+g{U)zPTi6_DZ?q)3Dhs7*D;U-q?svVZ)`9?L^j;4$Fb`SN-%?DTpPDYTIto zx!@8@PE)UvC~rtT9Awmf5=e*HiC)8Bv<)3Lln!3i#=V@#CiUEDQXyow38FA%S-`b` zg{Y-9^>fj3$42i|rb$+HQiak-WCzV>@lzFXKNUPY9MswXq$}KkjtM18ALVtMgTaE6fdP;=QmmU2ENIeq{Hw3117{k;Mt`I@KdbsaEeW~4DDr&mg zaOZIgX;Gj17{^wh;2=Vt8nsWg*(8g)*P*p=%Ao%Tn_$SKWsxuwB)!Yufhqfn-XsO`k*SMI9tfJud3STZ7`2S{!Q$f6xHFtg%AQ(B64pH`Osw z@78N+{-QL!bW~6p7EV7) zqoTf?^`Qcg7uE}iB>bGGfLzuOcA`n<2I#}VZl{QpO zd$or5F3-UxrTw~`bg?X@I%l*}Sf?sPk29;_5;o^1AVlI#T5@OKf69^llCfiTCtR@P zs6-ID`sK?eWiSao3QA@G6cg$X6w?+{Zfd&DxHFI{vJ(f2tyDwH~6dc#NlmOZ_; z*&w#Q1#D`oaUyGN&l1xhg?Wf@k=vM{)@gdczF%+F|yJe$u7%i1!aRW>< z@WRph(7Yz;V8q!Ce$QHjBS9-(a zXDvw{Al+W7KltmI*XS2 zG@J3@lIQ*^DaGjQUq7B(&}KYLVn1%h_--me+(t?Hw>}nng@X0u`HYqxpNl#%>8u@A zYp|!>plY|jizjtvBbhqdNV&ch_3ndj_+AG|^qzR?cAJbnm8nWqiYQ>tsf{6OQH|=a z+!ddZ?~~Dw+Pd$jeY+mh3@9;HQiPHakj6unnP+KJSQoQG-@TpeynU6uj8VTqV^s+{ z5;Cb#?i{=-YS3A2Eqej?#$^{b-8)CeG9(}xFvKVPSc~`2u4v%!l z-nEZq#vP`GJwi2o8L<4KKmeyzdU>2IDoDH@N)91dG-f=m-PYk21?HOQ(dN22K2WFH zgBXU7=mCVfUf_+lKrA7?RkBc6NDAoVhn~-|W;dB+2pSS50$WRkn&+>Ye5A7Y6WB{- zk(ao3_4|L+l_6X1t~IO373Puyc|Fc{pPZTGl)2~X!WRz~v1ewa~fs-q<6?nToI zV2h6JGLKQ3mmLY!vNxCPg_Phl>+t!FYa(+>F1^d2l3YIwh-?BT4ZeJL&ZPtGI%=?d z4$|mFQ@9IgL7?AzmK8ke?6~H#^U`nf^u;kHs`SBYQAj#>3_2^%Ds+YJkgHMvzm})u zXJ@g4%M78fs%r8s<|i zK&{v@q|jQL&p|c?2A$L&mR3ZJ-BXwOg8d12CGg{BS#0lIdjgl|G6-a_Rc}2Ky^9bT z%E@vl2W4!n-xh8u>2O25+s(jGPmkbW+oXjG1xtMFp<1_=`Wl=h_;%>Xn#(?yEgfdE z+{O)lrt{e(-mK9?!?yNXa@qG?B|?7A4GfEf5U`f#<5G?-QBO!{#mKhe%%f6em#MQE z)=>zNg>K3jiP`SJ!o8REYL=Ty7WYznFxCcTkn3KZCDwisCEDOxGLFXqRLr)+2=+o!8S6M>^nTp^tU+r9t9!1 z4)t&1tPo$PpUn}P0F=<8YmvJ|-`tBh$4DZdN8-)dGz^tQU83idUJuVp)_pdllonv) zRIp8n)g?`B7L2D>pxLt}y)&Ig08ktKxvFERYa zD)tx4Tp{<|aa02+=3(Md?<^Saoj|su-|i7L1f!bxZJ1>$Qa7o|$8kNc{&|XRdbU46 zM0PSnpp1i9tuxR;Kk{??j%d7H$9HlOz*f|Zcs5wboe!D| z885kgN-dQ&GC>kSM7MDl#j9CYW-CHRB7AcWd+L3^aIP_KNop3W%OPy=>vK)R#jr?D zPs?__YCd;aSfVt{XaLNi^F5VRYD4H$bk)PYmP;m*O~ohO(Mcmf{Oj!`w9h@XR{zeH z%9d1pGD3&@FSBpy-_VW7vi4ObrE@#`)WXZH<-rDR#EM%Iz_Er@ZaubCP zMwu1yjh5 z&+@HyaR}2xLHV^US~{C{l|=q9Q60qrtx^1zPi`YH=QW#O=g>4Vmf!wR5w`{PHX;8a zqser8L|2WLO~IwGvK$>`_v6d7-Pdk(F?t^QZt|Ra>k_T<@;B$YCsN(1>LC%-?u|>$ zox%C>18)Nn9%k_Gjw@Hp84`bhge zqOsJq?&IN0&JnJQeR}llxb#B7!n0W+VQJ%v=QT<71bJUe&njS0fU_p` z+Khk9;flV>-WZl)*b-u9Pijm#p5p9;))ld*JE>Xsxt2HA&qo1!8`MHnPE3Mqh9qp-$y6gIspRZ=!euN>NDq;_mF`ZB$s`yAk zh2%gzji8E(I)NML`-CgO+qsKw^1WFBTD5Mm-&Vhn{m4}S>|%<43O~=Rat$y4OuyAn*buNNQL?;lEESQB4Txv8 zE@z-rP57Q6##F;@huKKe`VmD=T>BuiX2=Ru%Xp{>PjE?TxD-Jjf{b4`c-dGfcl=zd z4^T_2Kg{tLx;g9`Ifxq}R{UH)?_bc*JIi$!G&<)Q^(|VI-fkZ;fFr z0pZ?rqW&mDkk%E^D}(79b=8WXRIwhaXxm|7ZZ)Vc`bU)RPOYdV988gS=^cpS zt<0*1WJ@m)`KfFw#LjZGh*D_~+D8!Dpct-?iso}jEelI=hAWSkY5Y|XpYlG7v^ISk z*LB(mlkYeRWS-F}>JfPfs5N-=$^v|wV&yuRN_id4G`r}*d)Etcie|y)^@;PPD@FxS zmSRi&huet+HkI8q*B~D~<_E8wu}(vQk>OLl=O@=9o(kumD<_fa2Ko25H$ICx(B#0j z)9(sJ+&4$7y_^_{hI9R>s*r;eMFO3_U@RTiS=G{vT4E=KITKg|9A)$&QWeX$)Zj}V z!o`h-t4Be>hAWCvJUU~!CfUf)=)q%Xs>RznAa@ZL{^7EZ&{furp&4pwpxm6ptS2U{ zgSJv6b*Wt)*X-AJ@bSpw?fwEO^2h2e9OO^wi=86o@dgTSor=TnF6M)I_X|h1b)^B} zvPBfywRo}ejn^#kHY*8ikcR3}KYzXKSX+H;YxLHl;Q$^@@EebUcbLV@j2_qTgxU}l9 z-%N#ez&1W01T5@~8zPicg-M+!om)NVo8y%s2tJw{D4EvVQ|l|EN#?JIv*)+h)D2c>jTm`wRB_ zPYWH8ygm@|@a<^Y+aK$EY%mpzlDfY-veTaXwQd1Y@k)(0ky1Zht$nz~j;8)%EYZ^o zOlX$w4!zNlVGy#*v^BM;F=t1pox{n;uX95g>&?emE_KA9FxU>}J{l>>v$q+c3KnddG#KK{jZVhs=Z`x*G&vKb z+6`;2iLspCeO!vY>f#m_{K%$@&&{5ehSSO|TE`J)GfVZ7d~p zpW^7+sa%F04emxCVfC83)%g(|M~LUbwIK(%est^%wScRSdCGHl;95M)FDs9pQi2;g zbVZnDT!hE#z+?x{lTdxGMRZ$)sCXY4DC>UQ_wId9%vjcU_1g{sUOXYU&71nn{e&uG z$n~^R;}bQ7Bz)g*ddDP!x~3N&V4H(HZ6?D=%}~SdgPd!7z>l)K1^Wo2&x2K~nivi+ zw<^DrGr%O5_{!**zI+h-PXO;f9r>YLIlzprA9b0v@6F~ z>y1m-vj-c~3Q?=Epe*~KhF%9kL}RxIEtx~m?J zo-qYCJoj~p5|FPul-gu4cyf5?PM@fe>UUEoSBl2qgUt1Kawf_$=7UuXkPqj1rhLKm z-mYyBYZz z)|;y1+m;tM?mjZ6l9biI4_e(;{aWGTmuG?3$pFnxv2E>Tf+E^ty2OWNk-sOyVqFD< z-c2snVnTpXyUAzwpHK!{rPOIC-x&Du8TZj==J`-8*9S;yqQc5Kgx3=I7<69 zU4zhn{)@fp&o=|zKu%AK|HTQH(*$nlROzee{(i`93U9K;>$Xa;bXn`z-MH+HI*=uF zL73a8u~wfYB=aE9mSpMc`$zA=CFcns8me3RVMBq?+C=TH`}&_IEdn~xZ)3r&M5>hB zuWKXzMc}t){)1tG5y?Q!5CGn7GyHz(5X9!oO?1yq*RMKT{7?Hf z;UOq;%x~9Avdyb6uf>{p@NY36!L{&0RKHM-{L@rwi`A3 zTowK-+kf`KK9PDqaK`=G&fhwrxe{n{a21XE^8fwp>30LYgix(+?OZ@+XKn8Tqq~rVDS>JZl?df8Ng(C3nQr{?+KL{wu z3ZL`&M!vXg|3YrkQ{tQXVpIAp{o@tiDqo)8r6d*lezSbZTozf{@LJ&;2~x1p%m{({ zW<3@AEAVJL|MzHrQakp4kM=ha|DUA&jUfM%w7+>uyZ@&i|I-ft|JkO+h7C6U#iT9l z7J%}RzzlwF94un>ov=S~jR9;l2M7HbT>clor49}lA69ah^S_jD)}|HFq~O-D7Irw^ z7;$%P5Y(5;r9zt`mfLEVTYvg;?Dwy4`LJs9Mwu50Ucde6rDG<@(O15Q$)t@rFREIgg9+< zisk7t%ZBdBZml1~8wgf|5YjBC$sNjpVV>f!4n{$r7K*`tay+`NX(c-`%I`aJF+~+x z|K<4Z_jsdwBhfkL!_xkv-vO7WtO!nudn-JdOxHKS0;^b!V|fQLW}goIBKN0f8ryoH z+n<{9I%p5z(#QkjytWRKv$PHtKHXb4dtL|gm7wKC)#kAkla7euKqtK5JroyHNUGTi zjq*+Tp2w!U#?=ZUF35;3I|*Cbf2;&h>9Id<@7VoZbP8395XuF+SM_HE)wvym5$m^Ui2!+QVw>6Ts2WZnwckcocdLB zQTw@&ck9%SlJsN#@=4S-jf#h5;p<6&%igg?731CMi_##;9~D&g7`uV9&NUr_=*$ne zz!9b&$wIp?NtXBIrTI7r92zPSkwBp7QMFYw*F*{yFoRL>Kql7$Lz~fw)Ol$%E|JA6Y}?r3QDNE;3wh z!$b<9xTSJLZf-)!=|j@(nNSG=D@09}b%Ec0u=e3s-qi14K$W7byU2@NmHLB7q}iR$ zyf?XHLjA=7y_c56D)Y^N-mCB;2pjcg<=n`FA*D{`+6OPY&@~n1Bo+vEp zSUJg_Vb%BsFWFEhOmB^sdk>O+asBk&^D;>wxuWiD-eak%c1|hAuvD!lLcO_*gDTB$ zVR+B*=cnEbs59^b;{&>3@s8cP7&W`%;cTpQ`$gnW5|<#e?@)ckFab~X&Ph*~ zpadgtFvYtIy-heDI(>v57M7V$dCxZ0o@Eu*+tQstIt8!ADOSz+m~!e*d4|lC$LAHS z8MLtsTp1~Md6@d#GD<;$;YnvDyzfH6sq<~3G91_9Z3;dK%dSrbemwapgx`B|!ZrCr z+z}Ut(<$;*^b1I!u#C!uw-AHoQUU|n)n*H&Wb6t&^%Vgf8 zG{$`lGzSYV6+M#OC@0OeeOWi_BDpt#mQXT1a_HTEH-QU#1+=0>g0znYUiC6MuCV)B z&>25AWtwS~W@dk;na4qbumq3RE~}*)xg6^h5d4+wTu>~}B(^>VWjj(#;>wXT`*<@q zLr6m$_7KK8WInr~=dRx^DL3)CI0)S!77%mzvG~yoQ)(4CyeBSQOO`X>t1N+y>*fN>s!&>_Z9ZA@}+cA=ni3JyI) z$1AM-P`GqSahESG!sV?rG6ay} zeZe#@$zx^38eLI;I%c2OKl*Vm8lzm7U4u?2Sn+Uim?M00+`WyWmI2+?52~OuEff zh6XEkM_*X_J=d(ft8VITVZvjJe06fk2){O9rj4#MZy&Yg!QwUk>O?-DpG5CJuP6)F zl~ONbuLzHw9zlJ@f!Pr2JmHs;TJdqsm z6GMN21=f?$g@Qx`K7tC#uw5YW*RI@n35|}KE;5lu#yN(WDrl|&o>Tf{g&rqQtQqP`isCezuYN)vrmp%EYUosOQh8M>p zxAZH-u-qjR_Ir=lxrqezxjGKt|HRgxfB8SMk%b%Qd2*9hOZdE-x{KPP!uaO?KyUx< zRWI?NMC%j@=EA9l8p(q9Q3vmvo#q{m(6`AD44UoqtnftCDr1UPKwV5gNlqBl|8Ix9uHO=}nb8Soqm5dK>)G`*9KzzLaYP5l+c}%b9+r*nTROnd!%YddAXCVeZBK6^Bg5C1BN}WTx>pc&hI$kR@zc2T z)Fpf9rrEFaoP}n;XGe6aA z<^98Sp3v=1m!*Eo)4Fhf&ieOF*b0DFYq5h-v_U@*Y_UOwwVSiT4L=X*OL*g4pCRZZ+A`xEU z-YJnhZz62gs~4-WsP{D%kaC!COG#3z&w$L|;b%YTJayZ&&p>fr+$~`RrH!*-9lY7X z$A;RJ8~@xPm>eVWCNrcW!)J&4{iqpl#JRU>5og~O=@R2=K1nEM`T8@LcDJ0|pPvifF-IhcN|B#wpp9)TyC*U+K+`M-O^a*#;JiQx1h?@S&Re zkmaQ+y-%Y=QDSGJ41p--UO{eP-^h%~S}+H$(Qa7SUY1)yNEWKon5zfwv;?_-S#YDqo3^oaXgri8z2GDn_@W)`o@J)I>Y^Hg|-w@?S45j$=rW zXfD(0ZA=TJTkv#9=%E6uw<=WD1zpu~Vp(ov0+XR1h-(;`y@n>Lna7dWt?@)qY`nF7 zS}h$FaUdB~ae_>j)Y!4YgVq;@Z-`iLV)%vAU4(WQH)k|j0Q zVb0+83h6nHJf+K$r?VrxtdC`BLVuLK=3FlFtz zr1G=qmnY!-uD16rFvYg0r5se%@6R?-)R-MRg+2AFx1yXJ0$$iMEV_kAaf}ckXhb+E zjhi^%_f8tJ)O>yLN_h=iZs4Al+Uco#gQ6#V0YI_|w=smDSWd6gjA4<1SkQz2c8*si|;- z!In8y?SaB6nRmQN5|^BmK757s^^q^k5x3TYtPL%lIE*+uEdS#U9Z~VqDdKp!8}NHS zODiy(8-{`r1|(<#c1S@?ah&0K-Gp2-^UNK%*1g)-!@S$!(6T%|(Q_hhGXqNouK4$+ zb;{lnkoaNxgX3MxLn*P;BR~wtSo3c3XEfEQSu-k!G1DqpO>SaSkw9i-f@BG?g@K%HACMh(hi$$Hvm( zt>j{FdCC92Nhy}H{bM7Tw*==CD%ph~Zc%9@+DJx=RyC=>vr5}vuzCOmOS1@>>OXrS z=96e41OVk$=_qVXwVpPKJ;veN($zw>{ru<#@j!x57Ki{_g|8m zl*TgUl#DZ@$9|i<>*?poigfrcWC}&>``yo%`sH%Mkyj)>rBIw!)Qj{p=xfw4OH6S% z_?7YCvBsj|9FIN8(tlBIQkD}yPI0=I01fZGq#(m*kiaB|FE%Xv%d7WOnlS08WrS+} zYG%3`<6`b4)Sdm?)_i6uE4{O~NKQ9K-q$NSW#b1?j`Qgu50RK*E0BNPANwP9M zhOt<~&ncAQFZi~+{$hveziJr)-avKIUu8b}FV;R<;cz5=(LL7Cr$ca(zl!UZBK+$r zU-~81;io3_RA=^oEPH|fl>TdUQT8W=`b9{`dYY9jfVkDvT(tWyw$b)Ll2E%p|4Q^Z zCU=1&3?e162%q3ze>vzs9hEU>pt4KI(%b(Ra(*9crs-$uz^Ask1{Fig;*_g{?e#%|4BCVVa31(OG?6YL@)=a==!5cf?p{m{rw6P7Xiz1X|wk?QnCktt3~{fEc1;YYx)TQ$9Y{@Uy}I^pN!oD zPy~Bi2%CFg;l1*|*tDnZqXmitIUa<3IWCs|Q{<1h7`g?QdQ2LY=38({|VdQ z1^@8LiShWuH}oI9z=5IM>Gh#ZrhUyoFN;X01p;rU42GPli5p>k!9Nc{Hv+D0f8lXV@iy8;(I9VG^-j_qURCsFU z-KIf-M(fI<6up;FZQA-|04)$_6zeSVhG+XIe|mjJeU^Xo>U6I(Zy^pfQ{)U~lz`Ez zG+75-?q zkg{k1O?g@5pMd^#VKEk~>y(=u`{*m`M7ivmJkBCP`O{b^Z+Xz7I*WYWGhMgn$YQk+ z4BkFd7qW3yBe-|4xP>#{Xepu<);jG>HK|#Z3m(tfkJ`^raDwMZU$R!^1H=6DeAldA z0lQg@ccgo@6te63C+pI1^$@$wEjYu{d@MCaaAfYjbsWbP20eZ(#ECi6*ARH|=S9Q| z+sm_=nX}aPim^~?DZV(D`P$f=Vd24{W!~0aIk8E5s-^9+%zQ7Ro}@}HuW`T@>V8vQV@vz zxyh6bu@sSxaQ_w3?xi1hi3!y1w5?Jr3v?BDFQq7pWoVRTD#?#kZQkp9V?4L!BG#Ed z$-gK=x;@ExwF0*8?q{QlqThZgK{v0mz$6N3hw;XCcBD8`uXP1uMnNhI!+&9@6Tg-_Pko;6_VW7*IL8&9TumQj|hc zbB9u_qSS{IC#RtbHME(T+4>W@XXyyO>+-U*6#!0pp|bI`FFBtAI*SbT5W1_%N9OxJk$Ad;ZWacD)Wf>j&=E*k>S)d83As zqu&qJ5(3`sN@XE}=QSgOEFIXun(D^MnwA+&%E$dfDMd^<+Aj)MYP0UDv_yHEp4K|E z{7MGru5_eaaFhPc<9KQ*0lk046MJqXswcPkW6g#55@*2B+a5ZHoIrx2d!Qj+-74&c z&@yzh)F&OmvKK~~U26XEDG7N^U};Et9|iU!o4!SaImCMCP{7?m4yEZ|E$R~eyT<-x z$_#gfb5;vD{+;llTnRy({xE}ApA5Lteg~66<+Oy2`2xp8n}UObgiX;WG8JVMY3u0- z0QZA$M6INNDodf6*QCpCv(8>N{|>SkVNNbyK5ex910mV$+A~ucbvA}Bw7t&xQH+1M zmq1Y8Nb}J%b-`E4EpvANhky5P>-xgwr@0`Jpxm;QAIGb`)t!-66Uio33{OWuVIYx- zswr+>4kEWAgM-u#BO0pV$w@$F(NFe`<>7fweKUVRmH0$1J9pPPN@Rj1Q0OpZEF`{2 zJ=g&uD_1997@IWJOII#VlW^H>(I6?Kar*ZYc0mJ^HhcExnN_DS36J zTogO5{gF*A2d%Q=GajX9ZOhH)vx>OZRzb^$`3?0@yj3FByxnXi`?qosCM}SnuYu&& zQ`rY^iic9K*DmM#1b;u19f(Bi3hw-GgNniCWY~Vam@nY zS+{{ee%uy2q+X|opHp^9nxR?Ftt55FU^}I8uEq$iN(2AWu*EyS7Ph{B1GCeEOBx6b zEHU)Wdy9WI=RM>5E_vQ8Qb$Wc{~Jbl9@GTwhi}eKKOoJ%z zI*R$E$NuK&0dI?ydrmd!sMopVuQ^^7fZx?$=(oK(D>UQLnBM`c$#PmCR)?Q|1$Bls zwDn_JyIVFZ*lz+wPGn|gDfWh?GTCw@>nnss){>Ve;XU3nLXTyyxIr#@7Jo3sdZu@= zRJ9<-KJt4l3{JfVrIDsGi2lV+wSF46umgbDadvzlOxKH6&F8R#eQgHdD0R?`Vp^h* z1COn^YFYK3Zw4S24qOjF_+~mc%(yq$kt$@<{OfV6CDz+AuUR1iAs#b$l z5lSiaP^aBB#O0QzQmz)%@ILJpf3 z_rGG{L=mc*%rtWd1*YRSn62UBA7pil(r?qh$yWO`@ATg5bQx!9RHhZr&I)7Q!0sC24h#(W$uKxURr@W4B*ydTZ8eM< za$gIjZxD34`v5vOAQ)AeF<-ROUO)b-OZ28a+tNHVJ%zbHZU&h>wDcg$+nP~2JS>Jn zOI0AMtJNUATkCYRo)!9?V%#a+#`N?^(JAP9B;5F#T{=L^Bt2PqWik=5(Tgy~@;6od z$#=9cCsXcv8T8CdB4U&6px&&5eakTHwg{MjU?@j`mUMAi@qHP-I`d;th6k63*%{4l z)S6+%_u=UNREL7b9G6m@m9w{@@s$x>KKgwTZvKL9-$U2L66ev8S$N>ZV}`2reU^~s zF?Q9Em}|uS(C4eZ4EvT^52OQOb*Z_WTxeKT<1*_#$H}ib2x;==Uoh~*R0l+qVqmQ+ z?NHpph04mYZ<(B--Yb{3p5zv-`97EzrySsyf-LduhC!6#xZP6B5EeSt*h?ST z2D^%^+&dL`ea(h&Iz)c8Bh1+QqhzV%-iRL0oAVG_HM`>V$Hv!y@mQBgzJaUb!H9wnxwp_qo{x!0K-N|}Gge7&cwh~F`r zQrC=ouDK1BlloDc0i9oQ>NJj%ym+~Bo@rQi*3iM;!70088lLVmz719Fw`vcv9`Z&z zE1Aw3n}$`j6d=ZmON(9cOG!A>mbf$7HP|fj+cA4_wn?+EL)7>opn#}Sxv%J#GtFS%^Yr)O&i@AM_KY=kP;p&c?mhMNQL zA0M6_+FBO6znpltNkKRYgkrBSp5>!kc4SdK{JX^&*Qol#iXAGYarGuPic*tq%h~d- zk*YrUmo|KkcI}xkX{Zx8SJ^wq*~@8g(qP^6eo%BzXop61T=aEGDJTj(%o(tt6q;*h zW-32;UYJ&$V(shl9;CG`lhB7+8R@*z8OH3jD;UtBycKu5e;r8$JBXLf+;`aP4Bj|f z6I_g_ZWzINlZ#i8Y7}R!gEK7=MJ2%evalP6MULk!$j zVgT47IqGizDifG(G2>zM{(`P?iU*ZaUF70l!v*kbcG+Gn4(aHo#Ik#7sG-Med4{fA z@c1?qe~4;Dc$w?0H>~G+badPM zm?2j`2sWWgr&|ZB6X+=FRvH;(EaFNx7c8rZ4KfE+97|! zp>PW{2$R(ImKpMF0Oyo_#GZ4-i*fbV(j*h1JDh&Rr|%-V>6H-qBr1xl|_}|m^CrZ+Hh3O zY-j!QTm+Om7UgHOo&!cz4FT^&Q8EtcGUdUk=y{&&2I=}f{WRDFUYks3{x(VQE^M*dj#)}OU zv$vzOW0a+67?*3F968uvZZzv(J#z01>r61TZ-44=sy7nWABips^X51dMwL`v?}d56 zeFYIGFCR0xW|0-JIj4UzRo*k}s9nS%X#mfW;{{VQ38P_?%kUVpd<}AHcCg>aqHw>Q z`J(G@W6;M-H~Th4s!rPrCzSNvOJHF=3oUA7Af!URn(CBJcO^p zsrIIJ?kLZ}qYAc6uXqc=T~jHrsCkDpm93wzoi2C?gk{~*-=z*l(P!MO&=J~N(!s61 z0EBWG48W_dmxr9B4CwEr)y1fv_A9H-8ep9EMwV-I6~X*x*k~+B5smh4)xzmuh(~)$ z2hpeP8m8%XF4hw9MMKROT)1Q) zEHuF6Cl1!Duq?J30*M-xuAPj=N}&>Wo!@0l+B01EbiPK4rr}iNUfMEG^#$|Up%Y?& z%Rg^Al7d{zYaYVBQ)!;`oVU%#LiJ)wa2m6nxlVfC_M}Q>oLOz%=R8oE=ZfpngUEDr z^cS4GKheK6-{8Bmn`2cr22~ZcoX9E6o@%#?3bJYJA19qFzGBbDo4;c6_JFCP{)qnL z2p}W(+&EVA$TgT}iKo5GzB38SPw9lW`?%iiw8Avam*h|B9w4Av)2^QxI>Mwmyr}ac zP3;dM0BFpz)iEXm2gVu(a>g_{8@>ax6Y-Szy#&hC>FKC^g^D?b6=!uQZY^(q$Ydmf zw1hVECOu9m+z-}kCvnQa=RaGTj;)Q_w|jhdm-%<=NcxfOPqlK#JM2$h+zUA1;i|EC zxK9RW?Lj{gZsygw+t5gi=#i$mgT5*%uraKn|DMJnSAUn(npu+s${AeW zQ*`OnG+_Ha=lG9VPN-TM89p4>m#>E=<8uvfPo~B~r2UCO>0%yQ7mZU4g7zQO8njP; zRY{R3AFOwTTKcOiGV7*16HMVBNx?c-8{lcZ29TUAAWe=H6GlS;B|uCvQ}NV z8P%!6ecLRl6&4TDG6-&~S&l+GUoKkRfl;*5{q)HJe88!c{D^E(o;{^HAs6%t5j^j{ zEhR<)a>k+91!Bbba5PwNgsL8^!d`VfXbZZ&l)88pWaCLH%GM?9AiM;g0EeoD*`yUN zxqN=7-n{JdMxfbD-IzZGJ-4(oIohsyq;d+5^Uk-@UlznqrbRr4?J9N_w$^H!?ad=k zUFYn?W%cX0pl877L7QizOrM9{K>kStX52EZb|i4icLIc;hBP(Z9in_1e%W?8T z9wk|x>rOpM$eWBAuzkN*hp0CWpJeQT9Vv^9KabQaE5=P(wRadF$hXo9zjd9Ym%xDG zqA=`NL+lJX(X)lJid$2i14hvyR*_Nj_HjXDxz#s~>qCpfx*oOkE%OHQ+eaJx)f4Qvrc!3?aIfNDj1Usi`!@I!IfoIZ#UGDb38nEK2 zb*>#i)Qif{Gv-Z~GF_xrJG0s^!bg6iB}zDfDP>uCZu51s10QR<7r8EFG}q>~bI;rvC$58L|vlS8wzK{vvc({?G#v*b!IT1ve#)>?pm*> zyPA2M4Q4oU5N-vI1AP4WCY(4F_TKQSo!>>{SEm0?KK(oU6Kg6MswJe8@f7@~`~CU- z_d7h~=Er^A*L~mDd7amJ{i4N|YIN>+9U7K?-q=o*e^!F+TfKD|lkm~8u5wSrlP$OO zM79rP0K0F_Ju|&uNmnVK6Cy?<+d}bXj4z&xj&EhvKQVh=LIXwg<}@uk@I&YLArH#R zy+W&11&$1lHcc8*xoHusBdfV$-=D+BbAqoxe@fFoKU#5iX7d~Y$lzMHs6&m4s{721 zM~myOU@>Jl_rul~c zJM|5GBkom29Jc6kmB?A%)PD*M9Y1XBrGn_2dH>}YW9G#N7vlq^8a7JmnC#Nmqe>jk z+Ut=Uh2R`WoZ;u=8HUk~R%qET7R%d>9m1ZF)CfJTZ#8%=3aj*b9e-<;PjFUbbZEgv z4@_?&U-$(Lt@l-U{j6Aea+)k?7zl5eL*-)}epYO^Hu8sYLTRyq^Kq_zsa9{)eeQT- zS@SoVy*(6-Dp-VYJ0H`Z892wmY3KaD)Tjwr+;QzC>Wof`pEjdBq>w?xWTgVe%2@~1 zd-#hBuGa9*6+yT|HNc)lXZ_Jr{S!dEqOIMJLkLGAVCki%(?G?mn0MvT24T%g)yfuK zSc8Qi1f!tVa-Z+sh?(AxT_I$MJ#(WSZ`buBUxVyFc|7RZ|CZ~2n%lG@7ZqBp4tgfM zxmXfPwCDxK9C2+dzr@m%M208U$Cge-w<2VGCcEUFO+1>NiX98IkwZ(kCOqB=Jz*u?CyD2KT~|R(OWDkw3P5OgfYiSFQPI>u~q=+&5)$qTWAs}*#7bO7WFJs&6yUIo3T^RNo={Zi%;h07$qLiNa}qQwaS7^5j<1C9 z5f=Tv4v76YA8Qafq*^F>(ZA#eEl6*oS<~lQuFX(b1tKU^;!J-fI9%66Knx!Dv|hPMH!cK#JN7p#2CG=9Z{-3wI*+ZBB0Og)x8npE^g0GO54 z=kHx(?rsCKWf!d$x$HV}F}PGz2cZvrj5=b9ZN7%SS=vWa?Z=d{$P*QZfNzs=KH>st ztDSeyB#+RuPl9n?ru^(FM19BAFYR9lvsk4*bg`a^_%kHojot%!Soh% zE3>xSjh(sDP~Hd(gmWN4Hcr~ysjdO39jhq+QPjnOg01g+{v2#qYP_A>Fi%iRg}hbK z9?@=wFRY%VttxH1xn);>-)c|mf++eh?RmW33gM_Aa}MsW z%(V_c9Gom+A@vQ>Gv};8Ewsp2g9M7p(h3qly24e0Gcv=cVsh&iF)QwxIBf~+A|K9Z zUTdA})A#CM>Z|WlaMT8neU2Ad!eBlTIw{qxLh;C3!m<+=)JH)*W~U?gba#2XKFf&J zer6hThsrdaFc9Ok0y-o-Dg%5A?r)sjHBA_?+G@I$lKn=K0j<^My>8YSMxq3|N5v9? z-jl68#p9y8RN>(dUHW@^%cLa%ji#=eCA!U9>(Z1!$j2T`o2HXKLhFjbdk4JWiv&y( zq0^8J!g<5T;o5}al13np0EyE+IxmB8KV42B_LvPCt4WF04NI{Q{MBG#bEZ#a5`-v-Do}*2&IpzKQLiQ5he+^eZd>EA98+&Z*h+GQ!Wu-aqc2-1jYYWj+xhBOmxN0{`NF z{a+rgU;8xD@bOVft3a+r)+2Ltb=J>1#s&5JDi_ZRiVyMozl`zM|3rf2YcIY!k?^rU zg>!q{`S&$hyS%3Py%SH9q5t;c8%)JtBdk9p@MSC^Zj!UZ#o#FlOB<- zwEZu2s(*WzR;cU^h}HPlg}av*$hwsKul}c|;YK&q|9ZhsqjE4_;dkr}m;ZnM6|#Cf zjl-&yO)vhpdbPiY)~zG!FB`M_!harlqjyaJ%jnFpRSW6v|L0l#MzM(4FQX>To%?mu z|J4@%Ma)o_vDIq200I9i$Nq0tW_o=Z8FBe_Q^f9dPhqXDvaRDyg?Lt+cxv5ey!t-B z5Gz~)3cRfT8K5u9xG{^>_y5Zqy?;nPyq>22+amq<@z<*+u1stl6&im?ACVy(G+n~! z-78yvjz6O?nDN8)-`A53GP?MZf1{4dqsG^*5iEqz{^!xZs5oD{lSar;uZ#$=JCPJa%>+Pum9GggPf5PbK1}UGYym^? zk<%!?bOO%M%KIyhX1$S=qezLd|ChZ!mDWNuR=0u%!+;Ou3TtV#wGtC z1CcFUU~NJ@EwVSb2@O)t;kl{e=LPU1j zz=jJ!ru%~TKz*Vw!}n+b2^Gdum=s}d+M28@u@yN^1MMa_`lRePA=xr0vr-eW^*Tn* zKi>`@jcf~1O~~w&QL{WGlZa(aO5Qx6%V#F?itdCjViPKYYP|2?>r?*aWvLo> zvo#N+q7QKfw!g7BbGKUaiAwbosuK*J?5_aq_4J6eo|p7nOZwX%IRkY{W0t??q^#CW zBN&DGPpYLB79HF5O$Pl0QwV+i&qhi5U#`sIM@4k2AGG>;Eo)MegeBDgJpN zm`r$7lzX?J)0{p;T`jXXQ9n71kRHKwYWklv?l6V zp^uO5sdtjCf6l7XhV6e7>~;@Ls!crb(7cj6M7`Z)Rotp>?7+z&F6a(uZ>H|O1Efi1 zeYmY33DQL(`^}>#<=@{=GCSNfy32d-^VZ5O1E=e~bjyyw_Dr6SPY#=@FXlGBNO@T# zsw>VC;igAi%wNXAJgBrbVwo(ZWTn)YYQvGWouJJ#T}~3H9HG5EYJR@xqP@GynP;gK zkH+ZZFv>y{TLw^WICGJP2@!Ub4_`ppsQmgx8J-)z!21Y?9|!%OhU5{&bEF=L%T@!z zCm9mFtX8zSdwaLTj69{RE^LG;jFLA1Y?{TB1JY8&W z4FI{SC?Yz(G`vkPF}g(o*k2(KVq_H6(W+I(@Nw`t|u0E~e)Y%;@DxIS;bR zZ>ao?k~CX!has)dg?O|w^Y}h|1A+j+xGb=s)IcVF)~t!U~q%F=PLY?#7?ye+ZYTO~CgI1$kL;ADkmjP|jimM4(-e z%5BiwlWy*w9&OEP%7Ax4Pv>HTRTHn{mc^k))? z=3U~cLWtU)kVPUC5_N~>+;zJX>#B*vEze!S(^q&abQ))-Ae2uPIZ7W_?p9rNx@|l*-Rm<P?;MHnry;KRC0yA!|_2(##{Wd2kX>hbB2yq|BFV% zPp2P81QirRs#7<4#GS|RnQVH-jMsSJG_kbBp#UL!Go1bxN_JhE6=2XT51f4x;D~Iq z)SM;g=jE4vr;cyOfWzU?q@h(aUG)V#o>cuWnw6YZh3K)1_#;I&ibNq$1kG)SJ6HIxY zI_)y(LD;Q3YjM*({qSifN6P$#>*!Qs@L4`C4M4UNg6V$dM{PfWGb1w8un)vXpBdy<~Ik=vekDrHm8EEfm{yqVs6#g2?E_Bwazqh-$LfqY)S;f40@qt-^ij)p-!zJ_hHb7W=c z61y{-^^G}XwvOG4)8pZUaAt0u5r3e-Ia*w&>jp9yahXnmH?APdy6cu$<3Enc=WD+c z02%)5PRExY9jj(xVc0*Q7`rM>Z7zhE8tZNeVITa%U+mPJn(A?4u6$9z_3LG!QTJ6x zzVu*?uSC#IMJBJS(_T087Q-s6a3=W3<}Ber&xdg7=%14Yj1Z=*wb$_JYC$yGvWg}; zhNuoIs5IDW-0-G3%YMdpf!4Rb&SCHS%N*`YVBSKnXM9j~wZ#=GM? z#Og3Al)d~EWGT%Zm07F24o`+OpT?W_*XGbFSZw;xi+}+f5S#5n_#zg=C1=KR3?Af| z(JXPON=*@&0`TET7ZwfBEhQM*qY;zv)x=P!gFyfQr$j=7#xQzRk+^}~kB#OEW9(EU zQaGntS>+GNR2Yj1FAW0z!5uI98D6p7n#M~W>&7V=8%cX3ZimHMu;E}XK-_et5kBp- z>`eDCO|jZJAks4k@Jar+8>j$djMBpt}#28XGrc|k~p zOM`~ERrVueh)i1{CUo(nvGaLj%z}DcP@pRhyHJ-Hd0r+%FkN9>b^fLk)ZE?DG%Fh- zNSSeK{+y-wNYe9`z-H*rl^agb-}5u_OR&lpR02jrlu?bQR~Zul&YanF0qnSHc3{gN zLZ;w&DWQf%@0{>U<*Tn)ML0B5A<7quYLn?Bnb1ZpR<8?(Ow}ldmEUXjDKva)$QNf& zJ->GWRKF$!)mD2O@Ry^tmok14y?UfcJHxG9u(I}V;e-vSu3g{^%Fbg^oz_8y@Z{Yj zk!1kuJU6UB9)}wSh$iZQF2NwP2Sf0c!MbVP%J=yc=}V2U+dcnfQNajyt(rEU4)N_7 zI7C91ujrxOaaf%?11h8iO5qr>P<49Ysw`JUMq=*kB7qeR>{Z&4Q!G=!V~oO#aA}L` z2v_BCU`h*qMi(NvzWCa;y4WrNJYGAF^{DQA|<(T430}%{1 z#Lk($50+q`2*ZxJ;IKZ1r|*a_`{oX$Tg=w<1Whx?u+;2;Jh;H8#!eMMS1=lHFu_27 z!kCLWA3bCOUN8qN&Hfx6XXb=HjVV{gq=?W8`eGe_bH?g`-s%6=0+<)ZRV#?dX=_%} zQHgBw{^a=uNO}kmDa3Nv41rH>!8yBd?H$fT&p^}M=?0~4oHA7wc3E{YtV^7}n$mTI zyEZUn=p&M`q*WPTle6r63hDx{0Occk8*d*ROf0v!n&C1!Uyo}ETzN9BnFI)C6y6>hZv{!?o@VFwyy$Ho7QhZhn3EJRkdj8^3SsM}Vnrj537&UwZ#6F} zptoSMfL&mM-un8g<-wA}VSc@oFGF@C;l1W7Xk!vJC(wDEIo|fhs4Lb#=8D(MJgrm< z5#WU!z3-G4ph_j>nhommJ0g4f38&fe8Ffj;kL1ez27jF{1YcT|S?guSuN45;0M&p{ zJcZ|yA-%aZz?87Af5y>HhX?dsCjW>r7DgOi}b6eM{8SV`=2a& z_Zts@DY*lb?ZO~1ez^%gP|K{16NdF}Ed3x*TaUdqz0dA+vEFwKREla0zLYjRBOxg2 z(h4HT^%#2^0W6aqEO>O(qfqQw#H(p(+2jIyh*xxyEhV$hpH=+lC@T&=gKV)k2j0Z# zsd4eIHa0CA!vxP&s}yyOGZBMFNQDqg1t7JY7L3#ON=G`poM9xkeWc%4pP$Te$xtZm zvS8Pj*!NvuG!~7Q5XK)k7Xh;zS-l#(GSAu;?ee3!v(B0(SV>gR?Ryqyz7DL2zuI~8 zIDtK|6Rgo_7_^faVjXf&S)B{P-GfXZ>VeclG zPo>Y}*3#=a{EYh21rsx&>rh+2urkWps23Alr{|MuiXEr}g>XUr#%fT2qbN8e6%|0M zQbFjRcBxtBn&tnCdmuSK8MDi&ex?3o(i6VJ8e>Z3g7Jo44zbF0j; z17+$!83E5gubu~R%5n@tLDJzRO^X>E1NIlna9=ttGfJQ_klGZCtGeXsaui%k*z>IxpJud`+Iy?VWmwv-K_WtpiIGFqtPR41Csm;u~BWVA4{1R$UL|@VB5t-RP& z_R@BMgJ7UT5Cx24v*{FbiYv02RW2Gye7zwYm(aX*Hd;P}_!}zb-d)(MK3mx_&iw7A zaW?g#@ab3%!)e0bi9f|VYU-JnO$e*PB$fpw59U)O!P%wr&Z+qj%PyWgsbtSx#tN=z zfZE&N;tfuZr9Rs6NJdw54F5tI!O%Jn`=2;Jo(5REQEGjS%IH}s09QaS9!f`-M3uAY z{bER03~*&gUt3h?KjKk$uiwwQg^lE!bMNW()H?(@1DCQ}q`Tu~cOudrFG3$J$+OZW zDR?%sn>2rgXYw7holrbg;r;hl{oR2^p zUraw;j~}52+BcN;>C#3u!otsC-9(fYhl;bzUrog3a!!6KE139B@Pm!dPJ3zyBuhX9i*?0U1fM!Vh+W#1~}Lygp>iI`W( zn--%WhAP#c8DjcQEH?(BjCCwt#qq4%t_(dptTwP2l#k|K^5+uLjT_IB8 z8zJqj@`%HMk^4Djqv7i)=5^4s(dC|l`n#iM%1UqSG?qg0R6Zj#oF~g9H!12Fu$V+? z+CdRF#*4CiV~KPzto9>wiDuurj&1rSQXw}DgH~prZW`i5ZBpCrp<+Pu3#!kfG9OyGTbmeT;P0+vG^sj9cL@gY z%&%Sn$gh%�E+=*#$Yf8)8vJb1}=9_dWABXCqD%pWa_q_sbD7Q@=YUrk0Qi3$a5 zS=Fn5S&oE`_j|oFZ_D+yPvE4}!D9m%`DxdI?vkAD0akeTcH_tF-D0v#6bqA-#hksR^_wjm7 zyHWIrZM^A4S~+x3trRbH2sw_R%>kr3D@}`AdQHe^23CtVu4>Z?VW2J{3z)kpX3whDnT;pQ~(JQt=qYXB@J*E z`j)AW*?o(cD5iTyBSl?%1T*pj(Mhn8j{Dn581t?JSt0V5nBup zr#y!T7rD<{n%b)KmcUc)W!X;ML^VqfRTr`;J7%D^sWcAewPS3Ce~Ry+HK#%)_m*%Bm%7Bv(isWuwV62RP1+#>ej!2Qj+T=BZoXm#6Wy3UVW{q2*z< z@rS&i9x~qb_2{|suO76K^2N~rF(LZ$2rNs7eOShLQTmIn zs}!8X)6LuL!GWy)qr&XsXculW*zV%^Ry5-MOb((ryxiJ%Cx`H(sK&F;m6Q~7!O!vC z`|u^VfW1L8oov2Rb`wihRWZ)9!bo!BorY5!dP~IeN!4lP8VE}?c-#Y_F|1E1rkJO> zBWVLXZL-bA1f}|`HzG2gWIPxB5rfkv1m8VAtDcb_5=R!u@k{#%ig#pGw$cHCR+Hr5 zd1G%;zQVt#Y=sQ=)Usc9PfI}KRWvm<#wnKnqi>}xq9`DTU~DRG$XyPwkeG`2E<^~9 z1&q0EFWm84d0}$Qm)aI=vo5>J3`D#EewALs?q%>$ z@M^VD&z-q@4bALulo1vxhQoh~v4TRv=2;hSa6}{Y1|+KPk77;>mo;O=uHxRMw>eAk z7vDV{S2n#u$!h_Sb{UOcO%x1)s1_JLQBdAdGv4_Qi*{X;DY~bykvu!-m0l2MO}oFY zoj?y88S9M%`oTX3PtuJkvjXnXVh z@t49=W46kmh%(uFe23)?AE)?l>z^8!+%2xlBN?%1#N)wfUGsT*XQ2$?CHs z7l_NKoC9Hdf!j0clfh+YVU3pj_<^e6zgUYthHO z@OLWR-Dj4~rz<31GS4IxH>WyWR-MYLi=30VJEB({YJI$KH44~;$Wc3OGGHbm^%0** ziQLKnvC7vZer-+o4bB=FdCD;%0&*Vb>$y@(usr;yEc18C&R7P2#j2hLbxm!ftxlYG zL57dNB2tJlBHmbj4EQLC8|5bYBjlI!K$YGXzdv13h@wQLr^?tUlMl|vf3IO&>>fp} z<)tCo_(&c+s?x`_Au7Wp^*XS3644_m�-ID=%B|=h~b5ZOc}~$w;f(<4)0Z?9))3 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 diff --git a/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png b/.pipelines/store/PDP/PDP-Media/en-US/pwshLogo.png deleted file mode 100644 index c531f719c85429fa6192eae82bb434e0318de801..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13152 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 - - - Prompt - - - - Inline Prediction - - - - Prediction List View - - - - Error Feedback Provider - - - - Feedback Provider - - - - Experimental Features - - diff --git a/.pipelines/templates/package-create-msix.yml b/.pipelines/templates/package-create-msix.yml index 3acddf1c000..97d2f4fc46a 100644 --- a/.pipelines/templates/package-create-msix.yml +++ b/.pipelines/templates/package-create-msix.yml @@ -12,7 +12,6 @@ jobs: variables: - group: msixTools - group: 'Azure Blob variable group' - - group: 'Store Publish Variables' - name: ob_sdl_credscan_suppressionsFile value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json - name: ob_sdl_tsa_configFile @@ -153,181 +152,3 @@ jobs: Write-Verbose -Verbose "Uploaded Bundles:" Get-ChildItem -Path $(ob_outputDirectory) | Write-Verbose -Verbose displayName: Upload msixbundle to Artifacts - - - pwsh: | - Write-Verbose -Verbose "Pipeline.Workspace: $(Pipeline.Workspace)" - Get-ChildItem -Path $(Pipeline.Workspace) -Recurse | Select-Object -ExpandProperty FullName - Write-Verbose -Verbose "System.DefaultWorkingDirectory: $(System.DefaultWorkingDirectory)" - Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Recurse | Select-Object -ExpandProperty FullName - Test-Path -Path '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP-Private.xml' | Write-Verbose -Verbose - displayName: Output Pipeline.Workspace and System.DefaultWorkingDirectory - - - template: channelSelection.yml@self - - - pwsh: | - $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' - $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' - $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' - - Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" - - # Define app configurations for each channel - $channelConfigs = @{ - 'LTS' = @{ - AppStoreName = 'PowerShell-LTS' - ProductId = '$(productId-LTS)' - AppId = '$(AppID-LTS)' - ServiceEndpoint = "StoreAppPublish-Stable" - } - 'Stable' = @{ - AppStoreName = 'PowerShell' - ProductId = '$(productId-Stable)' - AppId = '$(AppID-Stable)' - ServiceEndpoint = "StoreAppPublish-Stable" - } - 'Preview' = @{ - AppStoreName = 'PowerShell (Preview)' - ProductId = '$(productId-Preview)' - AppId = '$(AppID-Preview)' - ServiceEndpoint = "StoreAppPublish-Preview" - } - } - - $currentChannel = if ($IsLTS) { 'LTS' } - elseif ($IsStable) { 'Stable' } - elseif ($IsPreview) { 'Preview' } - else { - Write-Error "No valid channel detected" - exit 1 - } - - $config = $channelConfigs[$currentChannel] - Write-Verbose -Verbose "Selected channel: $currentChannel" - Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" - Write-Verbose -Verbose "Product ID: $($config.ProductId)" - - # Update PDP.xml file - $pdpPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP/en-US/PDP.xml' - if (Test-Path $pdpPath) { - Write-Verbose -Verbose "Updating PDP file: $pdpPath" - - [xml]$pdpXml = Get-Content $pdpPath -Raw - - # Create namespace manager for XML with default namespace - $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) - $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") - - $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) - if ($appStoreNameElement) { - $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) - Write-Verbose -Verbose "Updated AppStoreName _locID to: $($config.AppStoreName)" - } else { - Write-Warning "AppStoreName element not found in PDP file" - } - - $pdpXml.Save($pdpPath) - Write-Verbose -Verbose "PDP file updated successfully" - Get-Content -Path $pdpPath | Write-Verbose -Verbose - } else { - Write-Error "PDP file not found: $pdpPath" - exit 1 - } - - # Update SBConfig.json file - $sbConfigPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/SBConfig.json' - if (Test-Path $sbConfigPath) { - Write-Verbose -Verbose "Updating SBConfig file: $sbConfigPath" - - $sbConfigJson = Get-Content $sbConfigPath -Raw | ConvertFrom-Json - - $sbConfigJson.appSubmission.productId = $config.ProductId - Write-Verbose -Verbose "Updated productId to: $($config.ProductId)" - - $sbConfigJson | ConvertTo-Json -Depth 100 | Set-Content $sbConfigPath -Encoding UTF8 - Write-Verbose -Verbose "SBConfig file updated successfully" - Get-Content -Path $sbConfigPath | Write-Verbose -Verbose - } else { - Write-Error "SBConfig file not found: $sbConfigPath" - exit 1 - } - Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" - Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" - - # Select the correct bundle based on channel - $bundleFiles = @(Get-ChildItem -Path '$(BundleDir)' -Filter '*.msixbundle') - Write-Verbose -Verbose "Available bundles: $($bundleFiles.Name -join ', ')" - - if ($IsLTS) { - $bundleFile = $bundleFiles | Where-Object { $_.Name -match '-LTS-' } - } else { - # Catches Stable or Preview - $bundleFile = $bundleFiles | Where-Object { $_.Name -notmatch '-LTS-' } - } - - if (-not $bundleFile) { - Write-Error "No matching bundle found for channel '$currentChannel'. Available bundles: $($bundleFiles.Name -join ', ')" - exit 1 - } - - # Copy the selected bundle to a dedicated directory for store packaging - $storeBundleDir = '$(Pipeline.Workspace)\releasePipeline\msix\store-bundle' - New-Item $storeBundleDir -Type Directory -Force > $null - Copy-Item -Path $bundleFile.FullName -Destination $storeBundleDir -Force -Verbose - Write-Host "##vso[task.setvariable variable=StoreBundleDir]$storeBundleDir" - Write-Verbose -Verbose "Selected bundle for store packaging: $($bundleFile.Name)" - - # These variables are used in the next tasks to determine which ServiceEndpoint to use - Write-Host "##vso[task.setvariable variable=LTS]$($IsLTS.ToString().ToLower())" - Write-Host "##vso[task.setvariable variable=STABLE]$($IsStable.ToString().ToLower())" - Write-Host "##vso[task.setvariable variable=PREVIEW]$($IsPreview.ToString().ToLower())" - name: UpdateConfigs - displayName: Update PDPs and SBConfig.json - - - pwsh: | - Write-Verbose -Verbose "Checking variables after UpdateConfigs:" - Write-Verbose -Verbose "LTS=$(LTS)" - Write-Verbose -Verbose "STABLE=$(STABLE)" - Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" - displayName: Debug - Check Variables - - - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package (Preview)' - condition: eq(variables['PREVIEW'], 'true') - inputs: - serviceEndpoint: 'StoreAppPublish-Preview' - sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(StoreBundleDir)' - contents: '*.msixBundle' - outSBName: 'PowerShellStorePackage' - pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' - pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - - - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 - displayName: 'Create StoreBroker Package (Stable/LTS)' - condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) - inputs: - serviceEndpoint: 'StoreAppPublish-Stable' - sbConfigPath: '$(SBConfigPath)' - sourceFolder: '$(StoreBundleDir)' - contents: '*.msixBundle' - outSBName: 'PowerShellStorePackage' - pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' - pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - - - pwsh: | - $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" - $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" - $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" - - if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { - Write-Verbose -Verbose "Uploading StoreBroker Package files:" - Write-Verbose -Verbose "JSON File: $jsonFile" - Write-Verbose -Verbose "ZIP File: $zipFile" - - Copy-Item -Path $submissionPackageDir -Destination "$(ob_outputDirectory)" -Verbose -Recurse - } - - else { - Write-Error "Required files not found in $submissionPackageDir" - } - displayName: 'Upload StoreBroker Package' diff --git a/.pipelines/templates/package-store-package.yml b/.pipelines/templates/package-store-package.yml new file mode 100644 index 00000000000..7667b1361e7 --- /dev/null +++ b/.pipelines/templates/package-store-package.yml @@ -0,0 +1,242 @@ +jobs: +- job: CreateStorePackage + displayName: Create StoreBroker Package + pool: + type: windows + + variables: + - group: 'Azure Blob variable group' + - group: 'Store Publish Variables' + - name: ob_sdl_credscan_suppressionsFile + value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)\PowerShell\.config\tsaoptions.json + - name: ob_outputDirectory + value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' + - name: ob_signing_setup_enabled + value: false + - name: ob_sdl_codeSignValidation_enabled + value: false + + steps: + - checkout: self + clean: true + + - template: release-SetReleaseTagandContainerName.yml@self + + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'current' + artifact: drop_msixbundle_CreateMSIXBundle + itemPattern: | + **/*.msixbundle + targetPath: '$(Build.ArtifactStagingDirectory)/downloads' + displayName: Download signed msixbundle + + - pwsh: | + $bundleDir = '$(Build.ArtifactStagingDirectory)/downloads' + $bundle = Get-ChildItem -Path $bundleDir -Filter '*.msixbundle' -Recurse | Select-Object -First 1 + if (-not $bundle) { + Write-Error "No .msixbundle file found in $bundleDir" + exit 1 + } + Write-Verbose -Verbose "Found bundle: $($bundle.FullName)" + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$($bundle.DirectoryName)" + Write-Host "##$vstsCommandString" + displayName: Locate msixbundle + + - template: channelSelection.yml@self + + - pwsh: | + $IsLTS = '$(ChannelSelection.IsLTS)' -eq 'true' + $IsStable = '$(ChannelSelection.IsStable)' -eq 'true' + $IsPreview = '$(ChannelSelection.IsPreview)' -eq 'true' + + Write-Verbose -Verbose "Channel Selection - LTS: $IsLTS, Stable: $IsStable, Preview: $IsPreview" + + # Define app configurations for each channel + $channelConfigs = @{ + 'LTS' = @{ + AppStoreName = 'PowerShell-LTS' + ProductId = '$(productId-LTS)' + AppId = '$(AppID-LTS)' + ServiceEndpoint = "StoreAppPublish-Stable" + } + 'Stable' = @{ + AppStoreName = 'PowerShell' + ProductId = '$(productId-Stable)' + AppId = '$(AppID-Stable)' + ServiceEndpoint = "StoreAppPublish-Stable" + } + 'Preview' = @{ + AppStoreName = 'PowerShell (Preview)' + ProductId = '$(productId-Preview)' + AppId = '$(AppID-Preview)' + ServiceEndpoint = "StoreAppPublish-Preview" + } + } + + $currentChannel = if ($IsLTS) { 'LTS' } + elseif ($IsStable) { 'Stable' } + elseif ($IsPreview) { 'Preview' } + else { + Write-Error "No valid channel detected" + exit 1 + } + + $config = $channelConfigs[$currentChannel] + Write-Verbose -Verbose "Selected channel: $currentChannel" + Write-Verbose -Verbose "App Store Name: $($config.AppStoreName)" + Write-Verbose -Verbose "Product ID: $($config.ProductId)" + + # Update PDP.xml file + $pdpPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP/en-US/PDP.xml' + if (Test-Path $pdpPath) { + Write-Verbose -Verbose "Updating PDP file: $pdpPath" + + [xml]$pdpXml = Get-Content $pdpPath -Raw + + # Create namespace manager for XML with default namespace + $nsManager = New-Object System.Xml.XmlNamespaceManager($pdpXml.NameTable) + $nsManager.AddNamespace("pd", "http://schemas.microsoft.com/appx/2012/ProductDescription") + + $appStoreNameElement = $pdpXml.SelectSingleNode("//pd:AppStoreName", $nsManager) + if ($appStoreNameElement) { + $appStoreNameElement.SetAttribute("_locID", $config.AppStoreName) + Write-Verbose -Verbose "Updated AppStoreName _locID to: $($config.AppStoreName)" + } else { + Write-Warning "AppStoreName element not found in PDP file" + } + + $pdpXml.Save($pdpPath) + Write-Verbose -Verbose "PDP file updated successfully" + Get-Content -Path $pdpPath | Write-Verbose -Verbose + } else { + Write-Error "PDP file not found: $pdpPath" + exit 1 + } + + # Update SBConfig.json file + $sbConfigPath = '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/SBConfig.json' + if (Test-Path $sbConfigPath) { + Write-Verbose -Verbose "Updating SBConfig file: $sbConfigPath" + + $sbConfigJson = Get-Content $sbConfigPath -Raw | ConvertFrom-Json + + $sbConfigJson.appSubmission.productId = $config.ProductId + Write-Verbose -Verbose "Updated productId to: $($config.ProductId)" + + $sbConfigJson | ConvertTo-Json -Depth 100 | Set-Content $sbConfigPath -Encoding UTF8 + Write-Verbose -Verbose "SBConfig file updated successfully" + Get-Content -Path $sbConfigPath | Write-Verbose -Verbose + } else { + Write-Error "SBConfig file not found: $sbConfigPath" + exit 1 + } + + Write-Host "##vso[task.setvariable variable=ServiceConnection]$($config.ServiceEndpoint)" + Write-Host "##vso[task.setvariable variable=SBConfigPath]$($sbConfigPath)" + + # Select the correct bundle based on channel + $bundleFiles = @(Get-ChildItem -Path '$(BundleDir)' -Filter '*.msixbundle') + Write-Verbose -Verbose "Available bundles: $($bundleFiles.Name -join ', ')" + + if ($IsLTS) { + $bundleFile = $bundleFiles | Where-Object { $_.Name -match '-LTS-' } + } else { + # Catches Stable or Preview + $bundleFile = $bundleFiles | Where-Object { $_.Name -notmatch '-LTS-' } + } + + if (-not $bundleFile) { + Write-Error "No matching bundle found for channel '$currentChannel'. Available bundles: $($bundleFiles.Name -join ', ')" + exit 1 + } + + # Copy the selected bundle to a dedicated directory for store packaging + $storeBundleDir = '$(Pipeline.Workspace)\releasePipeline\msix\store-bundle' + New-Item $storeBundleDir -Type Directory -Force > $null + Copy-Item -Path $bundleFile.FullName -Destination $storeBundleDir -Force -Verbose + Write-Host "##vso[task.setvariable variable=StoreBundleDir]$storeBundleDir" + Write-Verbose -Verbose "Selected bundle for store packaging: $($bundleFile.Name)" + + # These variables are used in the next tasks to determine which ServiceEndpoint to use + $ltsValue = $IsLTS.ToString().ToLower() + $stableValue = $IsStable.ToString().ToLower() + $previewValue = $IsPreview.ToString().ToLower() + + Write-Verbose -Verbose "About to set variables:" + Write-Verbose -Verbose " LTS=$ltsValue" + Write-Verbose -Verbose " STABLE=$stableValue" + Write-Verbose -Verbose " PREVIEW=$previewValue" + + Write-Host "##vso[task.setvariable variable=LTS]$ltsValue" + Write-Host "##vso[task.setvariable variable=STABLE]$stableValue" + Write-Host "##vso[task.setvariable variable=PREVIEW]$previewValue" + + Write-Verbose -Verbose "Variables set successfully" + name: UpdateConfigs + displayName: Update PDPs and SBConfig.json + + - pwsh: | + Write-Verbose -Verbose "Checking variables after UpdateConfigs:" + Write-Verbose -Verbose "LTS=$(LTS)" + Write-Verbose -Verbose "STABLE=$(STABLE)" + Write-Verbose -Verbose "PREVIEW=$(PREVIEW)" + displayName: Debug - Check Variables + + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Preview)' + condition: eq(variables['PREVIEW'], 'true') + inputs: + serviceEndpoint: 'StoreAppPublish-Preview' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(StoreBundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + + - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 + displayName: 'Create StoreBroker Package (Stable/LTS)' + condition: or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true')) + inputs: + serviceEndpoint: 'StoreAppPublish-Stable' + sbConfigPath: '$(SBConfigPath)' + sourceFolder: '$(StoreBundleDir)' + contents: '*.msixBundle' + outSBName: 'PowerShellStorePackage' + pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + + - pwsh: | + $outputDirectory = "$(ob_outputDirectory)" + if (-not (Test-Path -LiteralPath $outputDirectory)) { + New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null + } + + Get-Item -Path "$(System.DefaultWorkingDirectory)/SBLog.txt" -ErrorAction SilentlyContinue | + Copy-Item -Destination $outputDirectory -Verbose + displayName: Upload Store Failure Log + condition: failed() + + - pwsh: | + $outputDirectory = "$(ob_outputDirectory)" + if (-not (Test-Path -LiteralPath $outputDirectory)) { + New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null + } + + $submissionPackageDir = "$(System.DefaultWorkingDirectory)/SBOutDir" + $jsonFile = "$submissionPackageDir/PowerShellStorePackage.json" + $zipFile = "$submissionPackageDir/PowerShellStorePackage.zip" + + if ((Test-Path $jsonFile) -and (Test-Path $zipFile)) { + Write-Verbose -Verbose "Uploading StoreBroker Package files:" + Write-Verbose -Verbose "JSON File: $jsonFile" + Write-Verbose -Verbose "ZIP File: $zipFile" + + Copy-Item -Path $submissionPackageDir -Destination $outputDirectory -Verbose -Recurse + } + else { + Write-Error "Required files not found in $submissionPackageDir" + exit 1 + } + displayName: 'Upload StoreBroker Package' diff --git a/.pipelines/templates/release-MSIX-Publish.yml b/.pipelines/templates/release-MSIX-Publish.yml index aaef3c6f269..cbbdb70cc4f 100644 --- a/.pipelines/templates/release-MSIX-Publish.yml +++ b/.pipelines/templates/release-MSIX-Publish.yml @@ -12,7 +12,7 @@ jobs: inputs: - input: pipelineArtifact pipeline: PSPackagesOfficial - artifactName: drop_msixbundle_CreateMSIXBundle + artifactName: drop_store_package_CreateStorePackage variables: - group: 'Store Publish Variables' - name: LTS @@ -107,28 +107,32 @@ jobs: - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Stable/LTS)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) - continueOnError: true + condition: and(not(${{ parameters.skipMSIXPublish }}), or(eq(variables['STABLE'], 'true'), eq(variables['LTS'], 'true'))) inputs: serviceEndpoint: 'StoreAppPublish-Stable' appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + force: true + deletePackages: true numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' + skipPolling: true - task: MS-RDX-MRO.windows-store-publish.publish-task.store-publish@3 displayName: 'Publish StoreBroker Package (Preview)' - condition: and(ne('${{ parameters.skipMSIXPublish }}', 'true'), eq(variables['PREVIEW'], 'true')) - continueOnError: true + condition: and(not(${{ parameters.skipMSIXPublish }}), eq(variables['PREVIEW'], 'true')) inputs: serviceEndpoint: 'StoreAppPublish-Preview' appId: '$(AppID)' inputMethod: JsonAndZip jsonPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.json' zipPath: '$(Pipeline.Workspace)\SBOutDir\PowerShellStorePackage.zip' + force: true + deletePackages: true numberOfPackagesToKeep: 2 jsonZipUpdateMetadata: true targetPublishMode: 'Immediate' + skipPolling: true diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml index ff40941e31b..b1efb2a8097 100644 --- a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -173,6 +173,12 @@ stages: parameters: OfficialBuild: ${{ parameters.OfficialBuild }} +- stage: store_package + displayName: 'Store Package' + dependsOn: [msixbundle] + jobs: + - template: /.pipelines/templates/package-store-package.yml@self + - stage: upload displayName: 'Upload' dependsOn: [prep, mac_package, windows_package_sign, linux_package, nupkg, msixbundle] # prep needed for BuildInfo JSON From b14d502e62887c08b288513426c9b70f3afc2b2e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 9 Apr 2026 09:56:45 -0700 Subject: [PATCH 098/127] [release/v7.6.1] Delay update notification for one week to ensure all packages become available (#27215) --- .../host/msh/UpdatesNotification.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs index 28cd31473dd..d0b1ed4572c 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs @@ -28,6 +28,9 @@ internal static class UpdatesNotification private const string StableBuildInfoURL = "https://aka.ms/pwsh-buildinfo-stable"; private const string PreviewBuildInfoURL = "https://aka.ms/pwsh-buildinfo-preview"; + private const int NotificationDelayDays = 7; + private const int UpdateCheckBackoffDays = 7; + ///

/// The version of new update is persisted using a file, not as the file content, but instead baked in the file name in the following template: /// `update{notification-type}_{version}_{publish-date}` -- held by 's_updateFileNameTemplate', @@ -89,9 +92,18 @@ internal static void ShowUpdateNotification(PSHostUserInterface hostUI) if (TryParseUpdateFile( updateFilePath: out _, out SemanticVersion lastUpdateVersion, - lastUpdateDate: out _) + out DateTime lastUpdateDate) && lastUpdateVersion != null) { + DateTime today = DateTime.UtcNow; + if ((today - lastUpdateDate).TotalDays < NotificationDelayDays) + { + // The update was out less than 1 week ago and it's possible the packages are still rolling out. + // We only show the notification when the update is at least 1 week old, to reduce the chance that + // users see the notification but cannot get the new update when they try to install it. + return; + } + string releaseTag = lastUpdateVersion.ToString(); string notificationMsgTemplate = s_notificationType == NotificationType.LTS ? ManagedEntranceStrings.LTSUpdateNotificationMessage @@ -169,7 +181,7 @@ internal static async Task CheckForUpdates() out DateTime lastUpdateDate); DateTime today = DateTime.UtcNow; - if (parseSuccess && updateFilePath != null && (today - lastUpdateDate).TotalDays < 7) + if (parseSuccess && updateFilePath != null && (today - lastUpdateDate).TotalDays < UpdateCheckBackoffDays) { // There is an existing update file, and the last update was less than 1 week ago. // It's unlikely a new version is released within 1 week, so we can skip this check. From d41f7685bd24b9658b4d15ce96a22094ed0f53b7 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 9 Apr 2026 09:57:26 -0700 Subject: [PATCH 099/127] [release/v7.6.1] Add comment-based help documentation to build.psm1 functions (#27216) --- build.psm1 | 847 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 822 insertions(+), 25 deletions(-) diff --git a/build.psm1 b/build.psm1 index de108c5cd0f..42a202d94fb 100644 --- a/build.psm1 +++ b/build.psm1 @@ -35,6 +35,16 @@ $tagsUpToDate = $false # This function is used during the setup phase in tools/ci.psm1 function Sync-PSTags { + <# + .SYNOPSIS + Syncs git tags from the PowerShell/PowerShell upstream remote. + .DESCRIPTION + Ensures that tags from the PowerShell/PowerShell upstream remote have been fetched. + Functions like Get-PSCommitId and Get-PSLatestTag require tags to be current. + This is called during the setup phase in tools/ci.psm1. + .PARAMETER AddRemoteIfMissing + If specified, adds the upstream remote automatically when it is not present. + #> param( [Switch] $AddRemoteIfMissing @@ -78,6 +88,15 @@ function Sync-PSTags # Gets the latest tag for the current branch function Get-PSLatestTag { + <# + .SYNOPSIS + Gets the latest git tag reachable from the current HEAD. + .DESCRIPTION + Returns the most recent annotated git tag. Run Sync-PSTags first to ensure tags + are up to date; otherwise a warning is emitted. + .OUTPUTS + System.String. The latest tag string, e.g. 'v7.5.0'. + #> [CmdletBinding()] param() # This function won't always return the correct value unless tags have been sync'ed @@ -92,6 +111,17 @@ function Get-PSLatestTag function Get-PSVersion { + <# + .SYNOPSIS + Returns the PowerShell version string for the current commit. + .DESCRIPTION + Derives the version from the latest git tag, optionally omitting the commit-ID suffix. + .PARAMETER OmitCommitId + When specified, returns only the bare version (e.g. '7.5.0') from the latest tag, + without the commit-count and hash suffix appended by git describe. + .OUTPUTS + System.String. A version string such as '7.5.0' or '7.5.0-15-gabcdef1234'. + #> [CmdletBinding()] param( [switch] @@ -109,6 +139,16 @@ function Get-PSVersion function Get-PSCommitId { + <# + .SYNOPSIS + Returns the PowerShell commit-ID string produced by git describe. + .DESCRIPTION + Returns the full git describe string including the tag, number of commits since + the tag, and the abbreviated commit hash (e.g. 'v7.5.0-15-gabcdef1234567890'). + Run Sync-PSTags first; otherwise a warning is emitted. + .OUTPUTS + System.String. A git describe string such as 'v7.5.0-15-gabcdef1234567890'. + #> [CmdletBinding()] param() # This function won't always return the correct value unless tags have been sync'ed @@ -123,6 +163,19 @@ function Get-PSCommitId function Get-EnvironmentInformation { + <# + .SYNOPSIS + Collects information about the current operating environment. + .DESCRIPTION + Returns a PSCustomObject containing OS-identity flags, architecture, admin status, + NuGet package root paths, and Linux distribution details. The object is used + throughout the build module to make platform-conditional decisions. + .OUTPUTS + System.Management.Automation.PSCustomObject. An object with properties such as + IsWindows, IsLinux, IsMacOS, IsAdmin, OSArchitecture, and distribution-specific flags + (IsUbuntu, IsDebian, IsRedHatFamily, etc.). + #> + param() $environment = @{'IsWindows' = [System.Environment]::OSVersion.Platform -eq [System.PlatformID]::Win32NT} # PowerShell will likely not be built on pre-1709 nanoserver if ('System.Management.Automation.Platform' -as [type]) { @@ -281,6 +334,54 @@ function Test-IsReleaseCandidate $optimizedFddRegex = 'fxdependent-(linux|win|win7|osx)-(x64|x86|arm64|arm)' function Start-PSBuild { + <# + .SYNOPSIS + Builds PowerShell from source using dotnet publish. + .DESCRIPTION + Compiles the PowerShell source tree for the specified runtime and configuration. + Optionally restores NuGet packages, regenerates resources, generates the type catalog, + and restores Gallery modules. Saves build options so subsequent commands can reuse them. + .PARAMETER StopDevPowerShell + Stops any running dev pwsh process before building to prevent file-in-use errors. + .PARAMETER Restore + Forces NuGet package restore even when packages already exist. + .PARAMETER Output + Path to the output directory. Defaults to the standard build location. + .PARAMETER ResGen + Regenerates C# bindings for resx resource files before building. + .PARAMETER TypeGen + Regenerates the CorePsTypeCatalog.cs type-catalog file before building. + .PARAMETER Clean + Runs 'git clean -fdX' to remove untracked and ignored files before building. + .PARAMETER PSModuleRestore + Restores PowerShell Gallery modules to the build output directory (legacy parameter set). + .PARAMETER NoPSModuleRestore + Skips restoring PowerShell Gallery modules to the build output directory. + .PARAMETER CI + Indicates a CI build; restores the Pester module to the output directory. + .PARAMETER ForMinimalSize + Produces a build optimized for minimal binary size (linux-x64, win7-x64, or osx-x64 only). + .PARAMETER SkipExperimentalFeatureGeneration + Skips the step that runs the built pwsh to produce the experimental-features list. + .PARAMETER SMAOnly + Rebuilds only System.Management.Automation.dll for rapid engine iteration. + .PARAMETER UseNuGetOrg + Uses nuget.org instead of the private PowerShell feed for package restore. + .PARAMETER Runtime + The .NET runtime identifier (RID) to target, e.g. 'win7-x64' or 'linux-x64'. + .PARAMETER Configuration + The build configuration: Debug, Release, CodeCoverage, or StaticAnalysis. + .PARAMETER ReleaseTag + A git tag in 'vX.Y.Z[-preview.N|-rc.N]' format to embed as the release version. + .PARAMETER Detailed + Passes '--verbosity d' to dotnet for detailed build output. + .PARAMETER InteractiveAuth + Passes '--interactive' to dotnet restore for interactive feed authentication. + .PARAMETER SkipRoslynAnalyzers + Skips Roslyn analyzer execution during the build. + .PARAMETER PSOptionsPath + When supplied, saves the resolved build options to this JSON file path. + #> [CmdletBinding(DefaultParameterSetName="Default")] param( # When specified this switch will stops running dev powershell @@ -763,6 +864,20 @@ Fix steps: } function Switch-PSNugetConfig { + <# + .SYNOPSIS + Switches the NuGet configuration between public, private, and NuGet.org-only sources. + .DESCRIPTION + Regenerates nuget.config files in the repository root, src/Modules, and test/tools/Modules + to point to the specified feed source. Optionally stores authenticated credentials. + .PARAMETER Source + The feed set to activate: 'Public' (nuget.org + dotnet feed), 'Private' (PowerShell ADO + feed), or 'NuGetOnly' (nuget.org only). + .PARAMETER UserName + Username for authenticated private feed access. + .PARAMETER ClearTextPAT + Personal access token in clear text for authenticated private feed access. + #> param( [Parameter(Mandatory = $true, ParameterSetName = 'user')] [Parameter(Mandatory = $true, ParameterSetName = 'nouser')] @@ -814,6 +929,18 @@ function Switch-PSNugetConfig { function Test-ShouldGenerateExperimentalFeatures { + <# + .SYNOPSIS + Determines whether experimental-feature JSON files should be generated on this host. + .DESCRIPTION + Returns $true only when the current runtime identifier matches the host OS and + architecture, the build is not a release build (PS_RELEASE_BUILD not set), and the + runtime is not fxdependent. + .PARAMETER Runtime + The .NET runtime identifier (RID) being targeted by the build. + .OUTPUTS + System.Boolean. $true if the experimental-feature list should be generated. + #> param( [Parameter(Mandatory)] $Runtime @@ -853,6 +980,23 @@ function Test-ShouldGenerateExperimentalFeatures function Restore-PSPackage { + <# + .SYNOPSIS + Restores NuGet packages for the PowerShell project directories. + .DESCRIPTION + Runs 'dotnet restore' on the main PowerShell project directories with up to five + retries on transient failures. Honors the target runtime identifier and build verbosity. + .PARAMETER ProjectDirs + Explicit list of project directories to restore. Defaults to the standard PS project set. + .PARAMETER Options + PSOptions object specifying runtime and configuration. Defaults to Get-PSOptions. + .PARAMETER Force + Forces restore even when project.assets.json already exists. + .PARAMETER InteractiveAuth + Passes '--interactive' to dotnet restore for interactive feed authentication. + .PARAMETER PSModule + Restores in PSModule mode, omitting the runtime argument. + #> [CmdletBinding()] param( [ValidateNotNullOrEmpty()] @@ -967,6 +1111,16 @@ function Restore-PSPackage function Restore-PSModuleToBuild { + <# + .SYNOPSIS + Copies PowerShell Gallery modules from the NuGet cache into the build output Modules folder. + .DESCRIPTION + Resolves Gallery module packages referenced in PSGalleryModules.csproj and copies + them to the Modules subdirectory of the specified publish path. Also removes + .nupkg.metadata files left behind by the restore. + .PARAMETER PublishPath + The PowerShell build output directory whose Modules sub-folder receives the modules. + #> param( [Parameter(Mandatory)] [string] @@ -983,6 +1137,14 @@ function Restore-PSModuleToBuild function Restore-PSPester { + <# + .SYNOPSIS + Downloads and saves the Pester module (v4.x) from the PowerShell Gallery. + .DESCRIPTION + Uses Save-Module to install Pester up to version 4.99 into the target directory. + .PARAMETER Destination + Directory to save Pester into. Defaults to the Modules folder of the current build output. + #> param( [ValidateNotNullOrEmpty()] [string] $Destination = ([IO.Path]::Combine((Split-Path (Get-PSOptions -DefaultToNew).Output), "Modules")) @@ -991,6 +1153,15 @@ function Restore-PSPester } function Compress-TestContent { + <# + .SYNOPSIS + Compresses the test directory into a zip archive for distribution. + .DESCRIPTION + Publishes PSTestTools and then zips the entire test/ directory to the given + destination path using System.IO.Compression.ZipFile. + .PARAMETER Destination + The path of the output zip file to create. + #> [CmdletBinding()] param( $Destination @@ -1005,6 +1176,30 @@ function Compress-TestContent { } function New-PSOptions { + <# + .SYNOPSIS + Creates a new PSOptions hashtable describing a PowerShell build configuration. + .DESCRIPTION + Computes the output path, project directory, and framework for a PowerShell build + based on the supplied runtime and configuration. The resulting hashtable is consumed + by Start-PSBuild, Restore-PSPackage, and related functions. + .PARAMETER Configuration + The build configuration: Debug (default), Release, CodeCoverage, or StaticAnalysis. + .PARAMETER Framework + The target .NET framework moniker. Defaults to 'net11.0'. + .PARAMETER Runtime + The .NET runtime identifier (RID). Detected automatically via 'dotnet --info' if omitted. + .PARAMETER Output + Optional path to the output directory. The executable name is appended automatically. + .PARAMETER SMAOnly + Targets only the System.Management.Automation project rather than the full host. + .PARAMETER PSModuleRestore + Indicates whether Start-PSBuild should restore PowerShell Gallery modules. + .PARAMETER ForMinimalSize + Produces a build targeting minimal binary size. + .OUTPUTS + System.Collections.Hashtable. A hashtable with build option properties. + #> [CmdletBinding()] param( [ValidateSet('Debug', 'Release', 'CodeCoverage', 'StaticAnalysis', '')] @@ -1152,6 +1347,17 @@ function New-PSOptions { # Get the Options of the last build function Get-PSOptions { + <# + .SYNOPSIS + Returns the PSOptions from the most recent Start-PSBuild call. + .DESCRIPTION + Retrieves the script-level $script:Options object. If no build has been run and + -DefaultToNew is specified, returns a fresh object from New-PSOptions. + .PARAMETER DefaultToNew + When specified, returns default options from New-PSOptions if no build has occurred. + .OUTPUTS + System.Collections.Hashtable. The current PSOptions hashtable, or $null. + #> param( [Parameter(HelpMessage='Defaults to New-PSOption if a build has not occurred.')] [switch] @@ -1167,6 +1373,15 @@ function Get-PSOptions { } function Set-PSOptions { + <# + .SYNOPSIS + Stores the supplied PSOptions as the active build options. + .DESCRIPTION + Writes the options hashtable to the script-scoped $script:Options variable, + making it available to subsequent Get-PSOptions calls. + .PARAMETER Options + The PSOptions hashtable to store. + #> param( [PSObject] $Options @@ -1176,6 +1391,17 @@ function Set-PSOptions { } function Get-PSOutput { + <# + .SYNOPSIS + Returns the path to the PowerShell executable produced by the build. + .DESCRIPTION + Looks up the Output path from the supplied options hashtable, the cached + script-level options, or a fresh New-PSOptions call, in that order of precedence. + .PARAMETER Options + An explicit options hashtable. If omitted, the most recent build options are used. + .OUTPUTS + System.String. The full path to the built pwsh or pwsh.exe executable. + #> [CmdletBinding()]param( [hashtable]$Options ) @@ -1189,6 +1415,21 @@ function Get-PSOutput { } function Get-PesterTag { + <# + .SYNOPSIS + Scans the Pester test tree and returns a summary of all tags in use. + .DESCRIPTION + Parses every *.tests.ps1 file under the specified base directory using the + PowerShell AST, validates that each Describe block has exactly one priority tag + (CI, Feature, or Scenario), and returns a summary object with tag counts and + any validation warnings. + .PARAMETER testbase + Root directory to search for test files. + Defaults to '$PSScriptRoot/test/powershell'. + .OUTPUTS + PSCustomObject (DescribeTagsInUse). Properties are tag names mapped to usage + counts, plus 'Result' (Pass/Fail) and 'Warnings' (string[]). + #> param ( [Parameter(Position=0)][string]$testbase = "$PSScriptRoot/test/powershell" ) $alltags = @{} $warnings = @() @@ -1255,6 +1496,13 @@ function Get-PesterTag { # testing PowerShell remote custom connections. function Publish-CustomConnectionTestModule { + <# + .SYNOPSIS + Builds and publishes the Microsoft.PowerShell.NamedPipeConnection test module. + .DESCRIPTION + Invokes the module's own build.ps1 script, copies the output to + test/tools/Modules, and then runs a clean build to remove intermediate artifacts. + #> Write-LogGroupStart -Title "Publish-CustomConnectionTestModule" $sourcePath = "${PSScriptRoot}/test/tools/NamedPipeConnection" $outPath = "${PSScriptRoot}/test/tools/NamedPipeConnection/out/Microsoft.PowerShell.NamedPipeConnection" @@ -1285,6 +1533,18 @@ function Publish-CustomConnectionTestModule } function Publish-PSTestTools { + <# + .SYNOPSIS + Builds and publishes all test tool projects to their bin directories. + .DESCRIPTION + Runs 'dotnet publish' for each test tool project (TestAlc, TestExe, UnixSocket, + WebListener, and on Windows TestService), copies Gallery test modules, and + publishes the NamedPipeConnection module. The tool bin directories are added to PATH + so that tests can locate the executables. + .PARAMETER runtime + The .NET runtime identifier (RID) used when publishing executables. + Defaults to the runtime from the current build options. + #> [CmdletBinding()] param( [string] @@ -1367,6 +1627,16 @@ function Publish-PSTestTools { } function Get-ExperimentalFeatureTests { + <# + .SYNOPSIS + Returns a mapping of experimental feature names to their associated test files. + .DESCRIPTION + Reads test/tools/TestMetadata.json and extracts the ExperimentalFeatures section, + returning a hashtable where keys are feature names and values are arrays of test paths. + .OUTPUTS + System.Collections.Hashtable. Keys are experimental feature names; values are + arrays of test file paths. + #> $testMetadataFile = Join-Path $PSScriptRoot "test/tools/TestMetadata.json" $metadata = Get-Content -Path $testMetadataFile -Raw | ConvertFrom-Json | ForEach-Object -MemberName ExperimentalFeatures $features = $metadata | Get-Member -MemberType NoteProperty | ForEach-Object -MemberName Name @@ -1379,6 +1649,57 @@ function Get-ExperimentalFeatureTests { } function Start-PSPester { + <# + .SYNOPSIS + Runs the Pester test suite against the built PowerShell. + .DESCRIPTION + Launches the built pwsh process with the Pester module and runs the specified + test paths. Automatically adjusts tag exclusions based on the current elevation + level, and emits NUnit XML results that are optionally published to Azure DevOps + or GitHub Actions. + .PARAMETER Path + One or more test file or directory paths to run. Defaults to test/powershell. + .PARAMETER OutputFormat + The Pester output format. Defaults to 'NUnitXml'. + .PARAMETER OutputFile + Path for the XML results file. Defaults to 'pester-tests.xml'. + .PARAMETER ExcludeTag + Tags to exclude from the run. Defaults to 'Slow'; adjusted for elevation level. + .PARAMETER Tag + Tags to include in the run. Defaults to 'CI' and 'Feature'. + .PARAMETER ThrowOnFailure + Throws an exception after the run if any tests failed. + .PARAMETER BinDir + Directory containing the built pwsh executable. Defaults to the current build output. + .PARAMETER powershell + Full path to the pwsh executable used for running tests. + .PARAMETER Pester + Path to the Pester module directory. + .PARAMETER Unelevate + Runs tests in an unelevated child process on Windows. + .PARAMETER Quiet + Suppresses most Pester output. + .PARAMETER Terse + Shows compact pass/fail indicators instead of full output lines. + .PARAMETER PassThru + Returns the Pester result object to the caller. + .PARAMETER Sudo + Runs tests under sudo on Unix (PassThru parameter set). + .PARAMETER IncludeFailingTest + Includes tests from tools/failingTests. + .PARAMETER IncludeCommonTests + Includes tests from test/common. + .PARAMETER ExperimentalFeatureName + Enables the named experimental feature for this test run via a temporary config file. + .PARAMETER Title + Title for the published test results. Defaults to 'PowerShell 7 Tests'. + .PARAMETER Wait + Waits for a debugger to attach before starting Pester (Debug builds only). + .PARAMETER SkipTestToolBuild + Skips rebuilding test tool executables before running tests. + .PARAMETER UseNuGetOrg + Switches NuGet config to public feeds before running tests. + #> [CmdletBinding(DefaultParameterSetName='default')] param( [Parameter(Position=0)] @@ -1428,7 +1749,7 @@ function Start-PSPester { if($IncludeCommonTests.IsPresent) { - $path = += "$PSScriptRoot/test/common" + $path += "$PSScriptRoot/test/common" } # we need to do few checks and if user didn't provide $ExcludeTag explicitly, we should alternate the default @@ -1744,6 +2065,20 @@ function Start-PSPester { function Publish-TestResults { + <# + .SYNOPSIS + Publishes test result files to Azure DevOps or GitHub Actions. + .DESCRIPTION + In an Azure DevOps build (TF_BUILD), uploads the result file via a ##vso command + and attaches it as a build artifact. In GitHub Actions, copies the file to the + testResults directory under $env:RUNNER_WORKSPACE. Does nothing outside of CI environments. + .PARAMETER Title + The run title shown in the CI testing tab. + .PARAMETER Path + Path to the NUnit or XUnit result file to publish. + .PARAMETER Type + The result file format: 'NUnit' (default) or 'XUnit'. + #> param( [Parameter(Mandatory)] [string] @@ -1804,6 +2139,17 @@ function Publish-TestResults function script:Start-UnelevatedProcess { + <# + .SYNOPSIS + Starts a process at an unelevated trust level on Windows. + .DESCRIPTION + Uses runas.exe /trustlevel:0x20000 to launch a process without elevation. + Only supported on Windows and non-arm64 architectures. + .PARAMETER process + The path to the executable to start. + .PARAMETER arguments + Arguments to pass to the executable. + #> param( [string]$process, [string[]]$arguments @@ -1814,7 +2160,7 @@ function script:Start-UnelevatedProcess throw "Start-UnelevatedProcess is currently not supported on non-Windows platforms" } - if (-not $environment.OSArchitecture -eq 'arm64') + if ($environment.OSArchitecture -eq 'arm64') { throw "Start-UnelevatedProcess is currently not supported on arm64 platforms" } @@ -1824,6 +2170,18 @@ function script:Start-UnelevatedProcess function Show-PSPesterError { + <# + .SYNOPSIS + Outputs a formatted error block for a single Pester test failure. + .DESCRIPTION + Accepts either an XmlElement from a NUnit result file or a PSCustomObject from + a Pester PassThru result, and writes a structured description/name/message/stack-trace + block to the log output. + .PARAMETER testFailure + An XML test-case element from a Pester NUnit result file (xml parameter set). + .PARAMETER testFailureObject + A Pester test-result PSCustomObject from a PassThru run (object parameter set). + #> [CmdletBinding(DefaultParameterSetName='xml')] param ( [Parameter(ParameterSetName='xml',Mandatory)] @@ -1866,6 +2224,18 @@ $stack_trace function Get-PesterFailureFileInfo { + <# + .SYNOPSIS + Parses a Pester stack-trace string and returns the source file path and line number. + .DESCRIPTION + Tries several common stack-trace formats produced by Pester 4 and Pester 5 (on + both Windows and Unix) and returns a hashtable with File and Line keys. + Returns $null values for both keys when no pattern matches. + .PARAMETER StackTraceString + The raw stack trace text from a Pester test failure. + .OUTPUTS + System.Collections.Hashtable. A hashtable with 'File' (string) and 'Line' (string). + #> [CmdletBinding()] param ( [Parameter(Mandatory)] @@ -1879,23 +2249,23 @@ function Get-PesterFailureFileInfo # "at , C:\path\to\file.ps1: line 123" # "at 1 | Should -Be 2, /path/to/file.ps1:123" (Pester 5) # "at 1 | Should -Be 2, C:\path\to\file.ps1:123" (Pester 5 Windows) - + $result = @{ File = $null Line = $null } - + if ([string]::IsNullOrWhiteSpace($StackTraceString)) { return $result } - + # Try pattern: "at line: 123 in " (Pester 4) if ($StackTraceString -match 'at line:\s*(\d+)\s+in\s+(.+?)(?:\r|\n|$)') { $result.Line = $matches[1] $result.File = $matches[2].Trim() return $result } - + # Try pattern: ", :123" (Pester 5 format) # This handles both Unix paths (/path/file.ps1:123) and Windows paths (C:\path\file.ps1:123) if ($StackTraceString -match ',\s*((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1):(\d+)') { @@ -1903,7 +2273,7 @@ function Get-PesterFailureFileInfo $result.Line = $matches[2] return $result } - + # Try pattern: "at :123" (without comma) # Handle both absolute Unix and Windows paths if ($StackTraceString -match 'at\s+((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):(\d+)(?:\r|\n|$)') { @@ -1911,24 +2281,33 @@ function Get-PesterFailureFileInfo $result.Line = $matches[2] return $result } - + # Try pattern: ": line 123" if ($StackTraceString -match '((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):\s*line\s+(\d+)(?:\r|\n|$)') { $result.File = $matches[1].Trim() $result.Line = $matches[2] return $result } - + # Try to extract just the file path if no line number found if ($StackTraceString -match '(?:at\s+|in\s+)?((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1)') { $result.File = $matches[1].Trim() } - + return $result } function Test-XUnitTestResults { + <# + .SYNOPSIS + Validates an xUnit XML result file and throws if any tests failed. + .DESCRIPTION + Parses the specified xUnit result file, logs description, name, message, and + stack trace for each failed test, then throws an exception summarizing the count. + .PARAMETER TestResultsFile + Path to the xUnit XML result file to validate. + #> param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] @@ -1984,6 +2363,23 @@ function Test-XUnitTestResults # Throw if a test failed function Test-PSPesterResults { + <# + .SYNOPSIS + Validates Pester test results and throws if any tests failed. + .DESCRIPTION + In file mode, reads a NUnit XML result file and logs each failure before throwing. + In object mode, inspects a Pester PassThru result object. Optionally permits + empty result sets. + .PARAMETER TestResultsFile + Path to the NUnit XML result file. Defaults to 'pester-tests.xml'. + .PARAMETER TestArea + Label for the test area, used in error messages. Defaults to 'test/powershell'. + .PARAMETER ResultObject + A Pester PassThru result object to inspect instead of parsing a file. + .PARAMETER CanHaveNoResult + When specified with ResultObject, suppresses the 'NO TESTS RUN' exception for + zero-count results. + #> [CmdletBinding(DefaultParameterSetName='file')] param( [Parameter(ParameterSetName='file')] @@ -2059,6 +2455,20 @@ function Test-PSPesterResults } function Start-PSxUnit { + <# + .SYNOPSIS + Runs the xUnit tests for the PowerShell engine. + .DESCRIPTION + Executes 'dotnet test' in the test/xUnit directory against the built PowerShell + binaries. On Unix, copies native libraries and required dependencies into the test + output directory. Publishes results to CI when not in debug-logging mode. + .PARAMETER xUnitTestResultsFile + Path for the xUnit XML result file. Defaults to 'xUnitResults.xml'. + .PARAMETER DebugLogging + Enables detailed console test output instead of writing an XML result file. + .PARAMETER Filter + An xUnit filter expression to restrict which tests are run. + #> [CmdletBinding()]param( [string] $xUnitTestResultsFile = "xUnitResults.xml", [switch] $DebugLogging, @@ -2150,6 +2560,29 @@ function Start-PSxUnit { } function Install-Dotnet { + <# + .SYNOPSIS + Installs the .NET SDK using the official install script. + .DESCRIPTION + Downloads and runs dotnet-install.sh (Linux/macOS) or dotnet-install.ps1 (Windows) + to install the specified SDK version into the user-local dotnet installation directory. + .PARAMETER Channel + The release channel to install from when no explicit version is given. + .PARAMETER Version + The exact SDK version to install. Defaults to the version required by this repository. + .PARAMETER Quality + The quality level (e.g. 'GA', 'preview') used when installing by channel. + .PARAMETER RemovePreviousVersion + Attempts to uninstall previously installed dotnet packages before installing. + .PARAMETER NoSudo + Omits sudo from install commands, useful inside containers running as root. + .PARAMETER InstallDir + Custom installation directory for the .NET SDK. + .PARAMETER AzureFeed + Override URL for the Azure CDN feed used to download the SDK. + .PARAMETER FeedCredential + Credential token for accessing a private Azure feed. + #> [CmdletBinding()] param( [string]$Channel = $dotnetCLIChannel, @@ -2301,6 +2734,15 @@ function Install-Dotnet { } function Get-RedHatPackageManager { + <# + .SYNOPSIS + Returns the install command prefix for the available Red Hat-family package manager. + .DESCRIPTION + Detects whether yum, dnf, or tdnf is installed and returns the corresponding + install command string for use in bootstrapping scripts. + .OUTPUTS + System.String. A package-manager install command such as 'dnf install -y -q'. + #> if ($environment.IsCentOS -or (Get-Command -Name yum -CommandType Application -ErrorAction SilentlyContinue)) { "yum install -y -q" } elseif ($environment.IsFedora -or (Get-Command -Name dnf -CommandType Application -ErrorAction SilentlyContinue)) { @@ -2313,6 +2755,27 @@ function Get-RedHatPackageManager { } function Start-PSBootstrap { + <# + .SYNOPSIS + Installs build dependencies for PowerShell. + .DESCRIPTION + Depending on the selected scenario, installs native OS packages, the required + .NET SDK, Windows packaging tools (WiX), and/or .NET global tools (dotnet-format). + Supports Linux, macOS, and Windows. + .PARAMETER Channel + The .NET SDK release channel to use when installing by channel. + .PARAMETER Version + The exact .NET SDK version to install. Defaults to the required version. + .PARAMETER NoSudo + Omits sudo from native-package install commands, useful inside containers. + .PARAMETER BuildLinuxArm + Installs Linux ARM cross-compilation dependencies (Ubuntu/AzureLinux only). + .PARAMETER Force + Forces .NET SDK reinstallation even if the correct version is already present. + .PARAMETER Scenario + What to install: 'Package' (packaging tools), 'DotNet' (.NET SDK), + 'Both' (Package + DotNet), 'Tools' (.NET global tools), or 'All' (everything). + #> [CmdletBinding()] param( [string]$Channel = $dotnetCLIChannel, @@ -2580,6 +3043,17 @@ function Start-PSBootstrap { ## If the required SDK version is found, return it. ## Otherwise, return the latest installed SDK version that can be found. function Find-RequiredSDK { + <# + .SYNOPSIS + Returns the installed .NET SDK version that best satisfies the required version. + .DESCRIPTION + Lists installed SDKs with 'dotnet --list-sdks'. Returns the required version + string if it is installed; otherwise returns the newest installed SDK version. + .PARAMETER requiredSdkVersion + The exact .NET SDK version string to search for. + .OUTPUTS + System.String. The matched or newest installed SDK version string. + #> param( [Parameter(Mandatory, Position = 0)] [string] $requiredSdkVersion @@ -2604,6 +3078,28 @@ function Find-RequiredSDK { } function Start-DevPowerShell { + <# + .SYNOPSIS + Launches a PowerShell session using the locally built pwsh. + .DESCRIPTION + Starts a new pwsh process from the build output directory, optionally setting + the DEVPATH environment variable, redirecting PSModulePath to the built Modules + directory, and loading or suppressing the user profile. + .PARAMETER ArgumentList + Additional arguments passed to the pwsh process. + .PARAMETER LoadProfile + When specified, the user profile is loaded (by default -noprofile is prepended). + .PARAMETER Configuration + Build configuration whose output directory to use (ConfigurationParamSet). + .PARAMETER BinDir + Explicit path to the directory containing the pwsh binary (BinDirParamSet). + .PARAMETER NoNewWindow + Runs pwsh in the current console window instead of a new one. + .PARAMETER Command + A command string passed to pwsh via -command. + .PARAMETER KeepPSModulePath + Preserves the existing PSModulePath instead of redirecting it to the build output. + #> [CmdletBinding(DefaultParameterSetName='ConfigurationParamSet')] param( [string[]]$ArgumentList = @(), @@ -2671,6 +3167,16 @@ function Start-DevPowerShell { function Start-TypeGen { + <# + .SYNOPSIS + Generates the CorePsTypeCatalog type-catalog file. + .DESCRIPTION + Invokes the TypeCatalogGen .NET tool to produce CorePsTypeCatalog.cs, which maps + .NET types to their containing assemblies. The output .inc file name varies by + runtime to allow simultaneous builds on Windows and WSL. + .PARAMETER IncFileName + Name of the .inc file listing dependent assemblies. Defaults to 'powershell.inc'. + #> [CmdletBinding()] param ( @@ -2699,6 +3205,13 @@ function Start-TypeGen function Start-ResGen { + <# + .SYNOPSIS + Regenerates C# resource bindings from resx files. + .DESCRIPTION + Runs the ResGen .NET tool in src/ResGen to produce strongly-typed resource classes + for all resx files in the PowerShell project. + #> [CmdletBinding()] param() @@ -2714,6 +3227,17 @@ function Start-ResGen } function Find-Dotnet { + <# + .SYNOPSIS + Ensures the required .NET SDK is available on PATH. + .DESCRIPTION + Checks whether the dotnet currently on PATH can locate the required SDK version. + If not, prepends the user-local dotnet installation directory to PATH. + Optionally sets DOTNET_ROOT and adds the global tools directory to PATH. + .PARAMETER SetDotnetRoot + When specified, sets the DOTNET_ROOT environment variable and adds the + .NET global tools path to PATH. + #> param ( [switch] $SetDotnetRoot ) @@ -2795,6 +3319,14 @@ function Convert-TxtResourceToXml } function script:Use-MSBuild { + <# + .SYNOPSIS + Ensures that the msbuild command is available in the current scope. + .DESCRIPTION + If msbuild is not found in PATH, creates a script-scoped alias pointing to the + .NET Framework 4 MSBuild at its standard Windows location. Throws if neither + location provides a usable msbuild. + #> # TODO: we probably should require a particular version of msbuild, if we are taking this dependency # msbuild v14 and msbuild v4 behaviors are different for XAML generation $frameworkMsBuildLocation = "${env:SystemRoot}\Microsoft.Net\Framework\v4.0.30319\msbuild" @@ -2814,6 +3346,18 @@ function script:Use-MSBuild { function script:Write-Log { + <# + .SYNOPSIS + Writes a colored message to the host, with optional error annotation. + .DESCRIPTION + In GitHub Actions, error messages are emitted as workflow error annotations + using the '::error::' command. Normal messages are written in green; errors + in red. Console colors are reset after each call. + .PARAMETER message + The text to write. + .PARAMETER isError + When specified, writes the message as an error (red / GitHub Actions annotation). + #> param ( [Parameter(Position=0, Mandatory)] @@ -2841,6 +3385,18 @@ function script:Write-Log } function script:Write-LogGroup { + <# + .SYNOPSIS + Emits a titled group of log messages wrapped in log-group markers. + .DESCRIPTION + Calls Write-LogGroupStart, writes each message line via Write-Log, then calls + Write-LogGroupEnd. In GitHub Actions this creates a collapsible group; on other + hosts it adds BEGIN/END banners. + .PARAMETER Message + One or more message lines to write inside the group. + .PARAMETER Title + The title displayed for the log group. + #> param ( [Parameter(Position = 0, Mandatory)] @@ -2863,6 +3419,15 @@ function script:Write-LogGroup { $script:logGroupColor = [System.ConsoleColor]::Cyan function script:Write-LogGroupStart { + <# + .SYNOPSIS + Opens a collapsible log group section. + .DESCRIPTION + In GitHub Actions emits '::group::'. On other hosts writes a colored + begin banner using the script-level log group color. + .PARAMETER Title + The label for the group. + #> param ( [Parameter(Mandatory)] @@ -2878,6 +3443,15 @@ function script:Write-LogGroupStart { } function script:Write-LogGroupEnd { + <# + .SYNOPSIS + Closes a collapsible log group section. + .DESCRIPTION + In GitHub Actions emits '::endgroup::'. On other hosts writes a colored + end banner using the script-level log group color. + .PARAMETER Title + The group label (used only in non-GitHub-Actions output). + #> param ( [Parameter(Mandatory)] @@ -2893,6 +3467,20 @@ function script:Write-LogGroupEnd { } function script:precheck([string]$command, [string]$missedMessage) { + <# + .SYNOPSIS + Tests whether a command exists on PATH and optionally emits a warning if missing. + .DESCRIPTION + Uses Get-Command to locate the specified command. Returns $true if found, + $false otherwise. If the command is absent and a message is provided, + Write-Warning is called with that message. + .PARAMETER command + The command name to look for. + .PARAMETER missedMessage + Warning text to emit when the command is not found. Pass $null to suppress it. + .OUTPUTS + System.Boolean. $true when the command is found; $false otherwise. + #> $c = Get-Command $command -ErrorAction Ignore if (-not $c) { if (-not [string]::IsNullOrEmpty($missedMessage)) @@ -2908,6 +3496,13 @@ function script:precheck([string]$command, [string]$missedMessage) { # Cleans the PowerShell repo - everything but the root folder function Clear-PSRepo { + <# + .SYNOPSIS + Cleans all subdirectories of the PowerShell repository using 'git clean -fdX'. + .DESCRIPTION + Iterates over every top-level directory under the repository root and removes all + files that are not tracked by git, including ignored files. + #> [CmdletBinding()] param() @@ -2920,6 +3515,20 @@ function Clear-PSRepo # Install PowerShell modules such as PackageManagement, PowerShellGet function Copy-PSGalleryModules { + <# + .SYNOPSIS + Copies PowerShell Gallery modules from the NuGet cache to a Modules directory. + .DESCRIPTION + Reads the PackageReference items in the specified csproj file, resolves each + package from the NuGet global cache, and copies it to the destination directory. + Package nupkg and metadata files are excluded from the copy. + .PARAMETER CsProjPath + Path to the csproj file whose PackageReference items describe Gallery modules. + .PARAMETER Destination + Destination Modules directory. Must end with 'Modules'. + .PARAMETER Force + Forces NuGet package restore even if packages are already present. + #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] @@ -2979,6 +3588,22 @@ function Copy-PSGalleryModules function Merge-TestLogs { + <# + .SYNOPSIS + Merges xUnit and NUnit test log files into a single xUnit XML file. + .DESCRIPTION + Converts NUnit Pester logs to xUnit assembly format and appends them, along with + any additional xUnit logs, to the primary xUnit log. The merged result is saved + to the specified output path. + .PARAMETER XUnitLogPath + Path to the primary xUnit XML log file. + .PARAMETER NUnitLogPath + One or more NUnit (Pester) XML log file paths to merge in. + .PARAMETER AdditionalXUnitLogPath + Optional additional xUnit XML log files to append. + .PARAMETER OutputLogPath + Path for the merged xUnit output file. + #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] @@ -3020,6 +3645,23 @@ function Merge-TestLogs } function ConvertFrom-PesterLog { + <# + .SYNOPSIS + Converts Pester NUnit XML log files to xUnit assembly format. + .DESCRIPTION + Accepts one or more NUnit log files produced by Pester, or existing xUnit logs, + and converts them to an in-memory xUnit assembly object model. If multiple logs + are provided and -MultipleLog is not set, they are combined into a single + assemblies object. + .PARAMETER Logfile + Path(s) to the NUnit or xUnit log file(s) to convert. Accepts pipeline input. + .PARAMETER IncludeEmpty + When specified, includes test assemblies that contain zero test cases. + .PARAMETER MultipleLog + When specified, returns one assemblies object per log file instead of combining. + .OUTPUTS + assemblies. One or more xUnit assemblies objects containing converted test data. + #> [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, Mandatory = $true, Position = 0)] @@ -3027,21 +3669,6 @@ function ConvertFrom-PesterLog { [Parameter()][switch]$IncludeEmpty, [Parameter()][switch]$MultipleLog ) - <# -Convert our test logs to -xunit schema - top level assemblies -Pester conversion -foreach $r in "test-results"."test-suite".results."test-suite" -assembly - name = $r.Description - config-file = log file (this is the only way we can determine between admin/nonadmin log) - test-framework = Pester - environment = top-level "test-results.environment.platform - run-date = date (doesn't exist in pester except for beginning) - run-time = time - time = -#> - BEGIN { # CLASSES class assemblies { @@ -3388,6 +4015,17 @@ assembly # Save PSOptions to be restored by Restore-PSOptions function Save-PSOptions { + <# + .SYNOPSIS + Persists the current PSOptions to a JSON file. + .DESCRIPTION + Serializes the current build options (or the supplied Options object) to JSON + and writes them to the specified path. Defaults to psoptions.json in the repo root. + .PARAMETER PSOptionsPath + Path to the JSON file to write. Defaults to '$PSScriptRoot/psoptions.json'. + .PARAMETER Options + PSOptions object to save. Defaults to the current build options. + #> param( [ValidateScript({$parent = Split-Path $_;if($parent){Test-Path $parent}else{return $true}})] [ValidateNotNullOrEmpty()] @@ -3405,6 +4043,17 @@ function Save-PSOptions { # Restore PSOptions # Optionally remove the PSOptions file function Restore-PSOptions { + <# + .SYNOPSIS + Loads saved PSOptions from a JSON file and makes them the active build options. + .DESCRIPTION + Reads the JSON file produced by Save-PSOptions, reconstructs a PSOptions + hashtable, and stores it via Set-PSOptions. Optionally deletes the file afterward. + .PARAMETER PSOptionsPath + Path to the JSON file to read. Defaults to '$PSScriptRoot/psoptions.json'. + .PARAMETER Remove + When specified, deletes the JSON file after loading. + #> param( [ValidateScript({Test-Path $_})] [string] @@ -3437,6 +4086,31 @@ function Restore-PSOptions { function New-PSOptionsObject { + <# + .SYNOPSIS + Constructs the PSOptions hashtable from individual build-option components. + .DESCRIPTION + Assembles the hashtable consumed by Start-PSBuild, Restore-PSPackage, and related + commands. Prefer New-PSOptions, which auto-computes fields such as the output path. + .PARAMETER RootInfo + PSCustomObject with repo root path validation metadata. + .PARAMETER Top + Path to the top-level project directory (pwsh source directory). + .PARAMETER Runtime + The .NET runtime identifier (RID) for the build. + .PARAMETER Configuration + The build configuration: Debug, Release, CodeCoverage, or StaticAnalysis. + .PARAMETER PSModuleRestore + Whether Gallery modules should be restored to the build output. + .PARAMETER Framework + The target .NET framework moniker, e.g. 'net11.0'. + .PARAMETER Output + Full path to the output pwsh executable. + .PARAMETER ForMinimalSize + Whether this is a minimal-size build. + .OUTPUTS + System.Collections.Hashtable. A PSOptions hashtable. + #> param( [PSCustomObject] $RootInfo, @@ -3607,6 +4281,17 @@ $script:RESX_TEMPLATE = @' '@ function Get-UniquePackageFolderName { + <# + .SYNOPSIS + Returns a unique temporary folder path for a test package under the specified root. + .DESCRIPTION + Tries the path '<Root>/TestPackage' first, then appends a random numeric suffix + until an unused path is found. Throws if a unique name cannot be found in 10 tries. + .PARAMETER Root + The parent directory under which the unique folder name is generated. + .OUTPUTS + System.String. A path under Root that does not yet exist. + #> param( [Parameter(Mandatory)] $Root ) @@ -3633,6 +4318,18 @@ function Get-UniquePackageFolderName { function New-TestPackage { + <# + .SYNOPSIS + Creates a zip archive containing all test content and test tools. + .DESCRIPTION + Builds and publishes test tools, copies the test directory, assets directory, + and resx resource directories into a temporary staging folder, then zips the + staging folder to TestPackage.zip in the specified destination directory. + .PARAMETER Destination + Directory where the TestPackage.zip file is created. + .PARAMETER Runtime + The .NET runtime identifier (RID) used when publishing test tool executables. + #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] @@ -3709,6 +4406,16 @@ class NugetPackageSource { } function New-NugetPackageSource { + <# + .SYNOPSIS + Creates a NugetPackageSource object with the given URL and name. + .PARAMETER Url + The NuGet feed URL. + .PARAMETER Name + The feed name used as the key in nuget.config. + .OUTPUTS + NugetPackageSource. An object with Url and Name properties. + #> param( [Parameter(Mandatory = $true)] [string]$Url, [Parameter(Mandatory = $true)] [string] $Name @@ -3719,6 +4426,22 @@ function New-NugetPackageSource { $script:NuGetEndpointCredentials = [System.Collections.Generic.Dictionary[String,System.Object]]::new() function New-NugetConfigFile { + <# + .SYNOPSIS + Generates a nuget.config file at the specified destination. + .DESCRIPTION + Creates a nuget.config XML file with the supplied package sources and optional + credentials. The generated file is marked as skip-worktree in git to prevent + accidental commits of feed credentials. + .PARAMETER NugetPackageSource + One or more NugetPackageSource objects defining the feeds to include. + .PARAMETER Destination + Directory where nuget.config is written. + .PARAMETER UserName + Username for authenticated feed access. + .PARAMETER ClearTextPAT + Personal access token in clear text for authenticated feed access. + #> param( [Parameter(Mandatory = $true, ParameterSetName ='user')] [Parameter(Mandatory = $true, ParameterSetName ='nouser')] @@ -3800,10 +4523,24 @@ function New-NugetConfigFile { } function Clear-PipelineNugetAuthentication { + <# + .SYNOPSIS + Clears cached NuGet feed credentials used by the pipeline. + .DESCRIPTION + Removes all entries from the script-scoped NuGetEndpointCredentials dictionary. + #> $script:NuGetEndpointCredentials.Clear() } function Set-PipelineNugetAuthentication { + <# + .SYNOPSIS + Publishes cached NuGet feed credentials to the Azure DevOps pipeline. + .DESCRIPTION + Serializes the script-scoped NuGetEndpointCredentials dictionary to JSON and sets + the VSS_NUGET_EXTERNAL_FEED_ENDPOINTS pipeline variable so that subsequent NuGet + operations authenticate automatically. + #> $endpointcredentials = @() foreach ($key in $script:NuGetEndpointCredentials.Keys) { @@ -3818,6 +4555,14 @@ function Set-PipelineNugetAuthentication { function Set-CorrectLocale { + <# + .SYNOPSIS + Configures the Linux locale to en_US.UTF-8 for consistent build behavior. + .DESCRIPTION + On Ubuntu 20+ systems, generates the en_US.UTF-8 locale and sets LC_ALL and LANG + environment variables. Skips execution on non-Linux platforms and Ubuntu versions + earlier than 20. + #> Write-LogGroupStart -Title "Set-CorrectLocale" if (-not $IsLinux) @@ -3854,6 +4599,13 @@ function Set-CorrectLocale } function Write-Locale { + <# + .SYNOPSIS + Writes the current system locale settings to the log output. + .DESCRIPTION + Runs the 'locale' command on Linux or macOS and writes the output inside a + collapsible log group. Does nothing on Windows. + #> if (-not $IsLinux -and -not $IsMacOS) { Write-Verbose -Message "only supported on Linux and macOS" -Verbose return @@ -3865,6 +4617,13 @@ function Write-Locale { } function Install-AzCopy { + <# + .SYNOPSIS + Downloads and installs AzCopy v10 on Windows. + .DESCRIPTION + Downloads the AzCopy v10 zip archive from the official Microsoft URL and extracts + it to the Agent tools directory. Skips installation if AzCopy is already present. + #> $testPath = "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy\AzCopy.exe" if (Test-Path $testPath) { Write-Verbose "AzCopy already installed" -Verbose @@ -3879,6 +4638,15 @@ function Install-AzCopy { } function Find-AzCopy { + <# + .SYNOPSIS + Locates the AzCopy executable on the system. + .DESCRIPTION + Searches several well-known installation paths for AzCopy.exe and falls back to + Get-Command if none of the paths contain the executable. + .OUTPUTS + System.String. The full path to the AzCopy executable. + #> $searchPaths = @('$(Agent.ToolsDirectory)\azcopy10\AzCopy.exe', "C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy\AzCopy.exe", "C:\azcopy10\AzCopy.exe") foreach ($filter in $searchPaths) { @@ -3894,6 +4662,16 @@ function Find-AzCopy { function Clear-NativeDependencies { + <# + .SYNOPSIS + Removes unnecessary native dependency files from the publish output. + .DESCRIPTION + Strips architecture-specific DiaSym reader DLLs that are not needed for the + target runtime from both the publish folder and the pwsh.deps.json manifest. + Skips fxdependent runtimes where no cleanup is needed. + .PARAMETER PublishFolder + Path to the publish output directory containing pwsh.deps.json. + #> param( [Parameter(Mandatory=$true)] [string] $PublishFolder ) @@ -3960,6 +4738,14 @@ function Clear-NativeDependencies function Update-DotNetSdkVersion { +<# + .SYNOPSIS + Updates the .NET SDK version in global.json and DotnetRuntimeMetadata.json. + .DESCRIPTION + Queries the official .NET SDK feed for the latest version in the current channel + and writes the new version to global.json and DotnetRuntimeMetadata.json. + #> + param() $globalJsonPath = "$PSScriptRoot/global.json" $globalJson = get-content $globalJsonPath | convertfrom-json $oldVersion = $globalJson.sdk.version @@ -3979,6 +4765,17 @@ function Update-DotNetSdkVersion { } function Set-PipelineVariable { + <# + .SYNOPSIS + Sets an Azure DevOps pipeline variable and the corresponding environment variable. + .DESCRIPTION + Emits a ##vso[task.setvariable] logging command so that subsequent pipeline steps + can access the variable, and also sets it in the current process environment. + .PARAMETER Name + The pipeline variable name. + .PARAMETER Value + The value to assign. + #> param( [parameter(Mandatory)] [string] $Name, From 4c932214d44df79e86c31a461ade9b7019d1bf0f Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Thu, 9 Apr 2026 09:57:45 -0700 Subject: [PATCH 100/127] [release/v7.6.1] Redo windows image fix to use latest image (#27217) --- .../variables/PowerShell-Coordinated_Packages-Variables.yml | 2 +- .pipelines/templates/variables/PowerShell-vPack-Variables.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml index de3ac0ba1b6..dd67d509a8a 100644 --- a/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml +++ b/.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml @@ -39,7 +39,7 @@ variables: - name: LinuxContainerImage value: mcr.microsoft.com/onebranch/azurelinux/build:3.0 - name: WindowsContainerImage - value: onebranch.azurecr.io/windows/ltsc2019/vse2022:latest + value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest - name: CDP_DEFINITION_BUILD_COUNT value: $[counter('', 0)] - name: ReleaseTagVar diff --git a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml index 276911a35b3..7f00a5e0e2a 100644 --- a/.pipelines/templates/variables/PowerShell-vPack-Variables.yml +++ b/.pipelines/templates/variables/PowerShell-vPack-Variables.yml @@ -19,7 +19,7 @@ variables: - name: BuildConfiguration value: Release - name: WindowsContainerImage - value: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - name: Codeql.Enabled value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - name: DOTNET_CLI_TELEMETRY_OPTOUT From 02413bbd378295d7d097eac64f315b21bc66d92b Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Thu, 9 Apr 2026 09:58:08 -0700 Subject: [PATCH 101/127] [release/v7.6.1] [StepSecurity] ci: Harden GitHub Actions tokens (#27218) --- .github/workflows/copilot-setup-steps.yml | 64 +++++++++++++++++++ .../workflows/windows-packaging-reusable.yml | 3 + .github/workflows/xunit-tests.yml | 3 + 3 files changed, 70 insertions(+) create mode 100644 .github/workflows/copilot-setup-steps.yml diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 00000000000..7c63c9122a8 --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -0,0 +1,64 @@ +name: "Copilot Setup Steps" + +# Allow testing of the setup steps from your repository's "Actions" tab. +on: + workflow_dispatch: + + pull_request: + branches: + - master + paths: + - ".github/workflows/copilot-setup-steps.yml" + +permissions: + contents: read + +jobs: + # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. + # See https://docs.github.com/en/copilot/customizing-copilot/customizing-the-development-environment-for-copilot-coding-agent + copilot-setup-steps: + runs-on: ubuntu-latest + + permissions: + contents: read + + # You can define any steps you want, and they will run before the agent starts. + # If you do not check out your code, Copilot will do this for you. + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1000 + + - name: Bootstrap + if: success() + run: |- + $title = 'Import Build.psm1' + Write-Host "::group::$title" + Import-Module ./build.psm1 -Verbose -ErrorAction Stop + Write-LogGroupEnd -Title $title + + $title = 'Switch to public feed' + Write-LogGroupStart -Title $title + Switch-PSNugetConfig -Source Public + Write-LogGroupEnd -Title $title + + $title = 'Bootstrap' + Write-LogGroupStart -Title $title + Start-PSBootstrap -Scenario DotNet + Write-LogGroupEnd -Title $title + + $title = 'Install .NET Tools' + Write-LogGroupStart -Title $title + Start-PSBootstrap -Scenario Tools + Write-LogGroupEnd -Title $title + + $title = 'Sync Tags' + Write-LogGroupStart -Title $title + Sync-PSTags -AddRemoteIfMissing + Write-LogGroupEnd -Title $title + + $title = 'Setup .NET environment variables' + Write-LogGroupStart -Title $title + Find-DotNet -SetDotnetRoot + Write-LogGroupEnd -Title $title + shell: pwsh diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 22f5e33314d..1f136636ec5 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -13,6 +13,9 @@ env: SYSTEM_ARTIFACTSDIRECTORY: ${{ github.workspace }}/artifacts BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts +permissions: + contents: read + jobs: package: name: ${{ matrix.architecture }} - ${{ matrix.channel }} diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index 1ab649d5492..668d413481e 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -14,6 +14,9 @@ on: required: false default: testResults-xunit +permissions: + contents: read + jobs: xunit: name: Run xUnit Tests From c6f827883d38630730b1f9b8d2fe371f1ba5ab3e Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Thu, 9 Apr 2026 09:58:35 -0700 Subject: [PATCH 102/127] [release/v7.6.1] Change the display name of PowerShell-LTS package to PowerShell LTS (#27219) --- tools/packaging/packaging.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index c5d67756004..d310344a0fa 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4285,7 +4285,7 @@ function New-MSIXPackage $displayName += ' Preview' } elseif ($LTS) { $ProductName += '-LTS' - $displayName += '-LTS' + $displayName += ' LTS' } Write-Verbose -Verbose "ProductName: $productName" From 0b825b31a0f9dfdce4016eabef66e31a08394f70 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Thu, 9 Apr 2026 15:35:37 -0700 Subject: [PATCH 103/127] [release/v7.6.1] Build, package, and create VPack for the PowerShell-LTS store package within the same `msixbundle-vpack` pipeline (#27237) --- .pipelines/MSIXBundle-vPack-Official.yml | 513 +++++++++++++++--- PowerShell.Common.props | 2 +- .../host/msh/ConsoleHost.cs | 2 +- .../host/msh/ManagedEntrance.cs | 4 +- .../resources/ManagedEntranceStrings.resx | 2 +- .../resources/RemotingErrorIdStrings.resx | 2 +- .../resources/TabCompletionStrings.resx | 4 +- .../utils/Telemetry.cs | 8 +- tools/packaging/packaging.psm1 | 4 +- 9 files changed, 450 insertions(+), 91 deletions(-) diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 876da9c2aff..08edd0367bd 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -1,31 +1,56 @@ trigger: none +pr: none parameters: # parameters are shown up in ADO UI in a build queue time - name: 'createVPack' displayName: 'Create and Submit VPack' type: boolean default: true +- name: 'ReleaseTagVar' + type: string + displayName: 'Release Tag Var:' + default: 'fromBranch' - name: 'debug' displayName: 'Enable debug output' type: boolean default: false -- name: 'ReleaseTagVar' +- name: netiso + displayName: "Network Isolation Policy" type: string - displayName: 'Release Tag Var:' - default: 'fromBranch' + values: + - KS4 + - R1 + - Netlock + default: "R1" -name: msixbundle_vPack_$(date:yyMM).$(date:dd)$(rev:rrr) +name: msixbundle_vPack_$(Build.SourceBranchName)_Prod.True_Create.${{ parameters.createVPack }}_$(date:yyyyMMdd).$(rev:rr) variables: - CDP_DEFINITION_BUILD_COUNT: $[counter('', 0)] - system.debug: ${{ parameters.debug }} - BuildSolution: $(Build.SourcesDirectory)\dirs.proj - ReleaseTagVar: ${{ parameters.ReleaseTagVar }} - BuildConfiguration: Release - WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' - Codeql.Enabled: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack - DOTNET_CLI_TELEMETRY_OPTOUT: 1 - POWERSHELL_TELEMETRY_OPTOUT: 1 + - name: CDP_DEFINITION_BUILD_COUNT + value: $[counter('', 0)] + - name: system.debug + value: ${{ parameters.debug }} + - name: BuildSolution + value: $(Build.SourcesDirectory)\dirs.proj + - name: BuildConfiguration + value: Release + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + - name: Codeql.Enabled + value: false # pipeline is not building artifacts; it repackages existing artifacts into a vpack + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 + - name: POWERSHELL_TELEMETRY_OPTOUT + value: 1 + - name: nugetMultiFeedWarnLevel + value: none + - name: ReleaseTagVar + value: ${{ parameters.ReleaseTagVar }} + - name: netiso + value: ${{ parameters.netiso }} + - group: certificate_logical_to_actual # used within signing task + - group: MSIXSigningProfile + - group: msixTools resources: repositories: @@ -34,27 +59,17 @@ resources: name: OneBranch.Pipelines/GovernedTemplates ref: refs/heads/main - pipelines: - - pipeline: PSPackagesOfficial - source: 'PowerShell-Packages-Official' - trigger: - branches: - include: - - master - - releases/* - extends: template: v2/Microsoft.Official.yml@onebranchTemplates parameters: + platform: + name: 'windows_undocked' # windows undocked featureFlags: WindowsHostVersion: Version: 2022 - platform: - name: 'windows_undocked' # windows undocked - + Network: ${{ variables.netiso }} cloudvault: enabled: false - globalSdl: useCustomPolicy: true # for signing code disableLegacyManifest: true @@ -78,71 +93,417 @@ extends: tsaOptionsFile: .config/tsaoptions.json stages: - - stage: build + - stage: Build_MSIX_Package + displayName: 'Build and create MSIX packages' + dependsOn: [] jobs: - - job: main + - job: Build pool: type: windows + strategy: + matrix: + x64: + Architecture: x64 + arm64: + Architecture: arm64 + variables: + ArtifactPlatform: 'windows' ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_artifactBaseName: drop_build_$(Architecture) + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true + + # The env variable 'ReleaseTagVar' will be updated in this step. + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: yes + + - pwsh: | + $releaseTag = '$(ReleaseTagVar)' + if ($releaseTag -match '-') { + throw "Never release msixbundle vpack for a preview build. Current version: $releaseTag" + } + + # Check if release tag matches the expected format v#.#.# + $matched = $releaseTag -match '^v\d+\.(\d+)\.\d+$' + if (-not $matched) { + throw "Release tag must be in the format v#.#.#, such as 'v7.4.3'. Current version: $releaseTag" + } + + # Extract minor version and verify it's even (LTS versions only) + $minorVersion = [int]$Matches[1] + if($minorVersion % 2 -ne 0) { + throw "Only release msixbundle vpack for LTS releases. Current version: $releaseTag" + } + displayName: Stop any preview release + env: + ob_restore_phase: true + + ### START BUILD ### + + # Clone the checked out PowerShell repo to '/PowerShell' and set the variable 'PowerShellRoot'. + - template: /.pipelines/templates/cloneToOfficialPath.yml@self + + - template: /.pipelines/templates/insert-nuget-config-azfeed.yml@self + parameters: + repoRoot: $(PowerShellRoot) + + # Add CodeQL Init task right before your 'Build' step. + - task: CodeQL3000Init@0 + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + inputs: + Enabled: true + # AnalyzeInPipeline: false = upload results + # AnalyzeInPipeline: true = do not upload results + AnalyzeInPipeline: false + Language: csharp + + - template: /.pipelines/templates/install-dotnet.yml@self + + - pwsh: | + $runtime = switch ($env:Architecture) + { + "x64" { "win7-x64" } + "arm64" { "win-arm64" } + } + + $vstsCommandString = "vso[task.setvariable variable=Runtime]$runtime" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + + Write-Verbose -Message "Building PowerShell with Runtime: $runtime for '$env:BuildConfiguration' configuration" + Import-Module -Name $(PowerShellRoot)/build.psm1 -Force + $buildWithSymbolsPath = New-Item -ItemType Directory -Path $(Pipeline.Workspace)/Symbols_$(Architecture) -Force + + Start-PSBootstrap -Scenario Package + $null = New-Item -ItemType Directory -Path $buildWithSymbolsPath -Force -Verbose + + Start-PSBuild -Runtime $runtime -Configuration Release -Output $buildWithSymbolsPath -Clean -PSModuleRestore -ReleaseTag $(ReleaseTagVar) + + $refFolderPath = Join-Path $buildWithSymbolsPath 'ref' + Write-Verbose -Verbose "refFolderPath: $refFolderPath" + $outputPath = Join-Path '$(ob_outputDirectory)' 'psoptions' + $null = New-Item -ItemType Directory -Path $outputPath -Force + $psOptPath = "$outputPath/psoptions.json" + Save-PSOptions -PSOptionsPath $psOptPath + + Write-Verbose -Verbose "Verifying pdbs exist in build folder" + $pdbs = Get-ChildItem -Path $buildWithSymbolsPath -Recurse -Filter *.pdb + if ($pdbs.Count -eq 0) { + throw "No pdbs found in build folder" + } + else { + Write-Verbose -Verbose "Found $($pdbs.Count) pdbs in build folder" + $pdbs | ForEach-Object { + Write-Verbose -Verbose "Pdb: $($_.FullName)" + } + + $pdbs | Compress-Archive -DestinationPath '$(ob_outputDirectory)\symbols-$(Architecture).zip' -Update + } + + Write-Verbose -Verbose "Completed building PowerShell for '$env:BuildConfiguration' configuration" + displayName: 'Build Windows Universal - $(Architecture)-$(BuildConfiguration) Symbols folder' + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + # Add CodeQL Finalize task right after your 'Build' step. + - task: CodeQL3000Finalize@0 + env: + ob_restore_phase: true # Set ob_restore_phase to run this step before '🔒 Setup Signing' step. + + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + inputs: + sourceScanPath: '$(PowerShellRoot)\src' + ob_restore_phase: true + + # The signed files will be put in '$(ob_outputDirectory)\Signed-$(Runtime)' after this step. + - template: /.pipelines/templates/obp-file-signing.yml@self + parameters: + binPath: '$(Pipeline.Workspace)/Symbols_$(Architecture)' + OfficialBuild: true + + ### END OF BUILD ### + + - pwsh: | + Get-ChildItem -Path '$(ob_outputDirectory)\Signed-$(Runtime)' -Recurse | Out-String -Width 9999 + displayName: Capture signed files + condition: succeededOrFailed() + + - pwsh: | + Get-ChildItem -Path env: | Out-String -Width 9999 + displayName: Capture Environment + condition: succeededOrFailed() + + ### START Packaging ### + + - template: /.pipelines/templates/shouldSign.yml@self + parameters: + ob_restore_phase: false + + - pwsh: | + Write-Verbose -Verbose "runtime = '$(Runtime)'" + Write-Verbose -Verbose "RepoRoot = '$(PowerShellRoot)'" + + $runtime = '$(Runtime)' + $repoRoot = '$(PowerShellRoot)' + Import-Module "$repoRoot\build.psm1" + Import-Module "$repoRoot\tools\packaging" + + Find-Dotnet + + $signedFilesPath = '$(ob_outputDirectory)\Signed-$(Runtime)' + $psoptionsFilePath = '$(ob_outputDirectory)\psoptions\psoptions.json' + + Write-Verbose -Verbose "signedFilesPath: $signedFilesPath" + Write-Verbose -Verbose "psoptionsFilePath: $psoptionsFilePath" + + Write-Verbose -Message "checking pwsh exists in $signedFilesPath" -Verbose + if (-not (Test-Path $signedFilesPath\pwsh.exe)) { + throw "pwsh.exe not found in $signedFilesPath" + } + + Write-Verbose -Message "Restoring PSOptions from $psoptionsFilePath" -Verbose + + Restore-PSOptions -PSOptionsPath "$psoptionsFilePath" + Get-PSOptions | Write-Verbose -Verbose + + ## Generated packages are placed in the current directory by default. + Set-Location $repoRoot + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS + + $msixPkgNameFilter = "PowerShell*.msix" + $msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -File + $msixPkgPath = $msixPkgFile.FullName + Write-Verbose -Verbose "Unsigned msix package: $msixPkgPath" + + $pkgDir = '$(ob_outputDirectory)\pkgs' + $null = New-Item -ItemType Directory -Path $pkgDir -Force + Copy-Item -Path $msixPkgPath -Destination $pkgDir -Force -Verbose + displayName: 'Build MSIX Package (Unsigned)' + + ### END OF Packaging ### + + - pwsh: | + Get-ChildItem -Path '$(ob_outputDirectory)\pkgs' -Recurse + displayName: 'List Unsigned Package' + + - stage: Pack_MSIXBundle_And_Sign + displayName: 'Pack and sign MSIXBundle' + dependsOn: [Build_MSIX_Package] + jobs: + - job: Bundle + pool: + type: windows + variables: + ArtifactPlatform: 'windows' + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_artifactBaseName: drop_pack_msixbundle ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_packagename: 'PowerShell.app' + ob_createvpack_packagename: 'PowerShell7.Store.app' ob_createvpack_owneralias: 'dongbow' - ob_createvpack_description: 'VPack for the PowerShell Application' - ob_createvpack_targetDestinationDirectory: '$(Destination)' + ob_createvpack_description: 'VPack for the PowerShell 7 Store Application' + ob_createvpack_targetDestinationDirectory: '$(Destination)' ## The value is from the 'CreateVpack' task, used when pulling the generated VPack. ob_createvpack_propsFile: false ob_createvpack_provData: true ob_createvpack_metadata: '$(Build.SourceVersion)' ob_createvpack_versionAs: string - ob_createvpack_version: '$(version)' + ob_createvpack_version: '$(Version)' ob_createvpack_verbose: true steps: - - template: .pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - - - pwsh: | - Write-Verbose -Verbose 'PowerShell Version: $(version)' - if('$(version)' -match '-') { - throw "Don't release a preview build msixbundle package" - } - displayName: Stop any preview release - - - download: PSPackagesOfficial - artifact: 'drop_msixbundle_CreateMSIXBundle' - displayName: Download package - - - pwsh: | - $payloadDir = '$(Pipeline.Workspace)\PSPackagesOfficial\drop_msixbundle_CreateMSIXBundle' - Get-ChildItem $payloadDir -Recurse | Out-String -Width 150 - $vstsCommandString = "vso[task.setvariable variable=PayloadDir]$payloadDir" - Write-Host "sending " + $vstsCommandString - Write-Host "##$vstsCommandString" - displayName: 'Capture Artifact Listing' - - - pwsh: | - $bundlePackage = Get-ChildItem '$(PayloadDir)\*.msixbundle' - Write-Verbose -Verbose ("MSIX bundle package: " + $bundlePackage.FullName -join ', ') - if ($bundlePackage.Count -ne 1) { - throw "Expected to find 1 MSIX bundle package, but found $($bundlePackage.Count)" - } + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true - if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { - $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop - } + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no - $targetPath = Join-Path '$(ob_outputDirectory)' 'Microsoft.PowerShell_8wekyb3d8bbwe.msixbundle' - Copy-Item -Verbose -Path $bundlePackage.FullName -Destination $targetPath - displayName: 'Stage msixbundle for vpack' + - template: /.pipelines/templates/shouldSign.yml@self - - pwsh: | - Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - $vpackFiles = Get-ChildItem -Path $(ob_outputDirectory)\* -Recurse - if($vpackFiles.Count -eq 0) { - throw "No files found in $(ob_outputDirectory)" - } - $vpackFiles | Out-String -Width 150 - displayName: Debug Output Directory and Version - condition: succeededOrFailed() + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_x64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for x64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_arm64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for arm64 + + # Finds the makeappx tool on the machine. + - pwsh: | + Write-Verbose -Verbose 'PowerShell Version: $(Version)' + $cmd = Get-Command makeappx.exe -ErrorAction Ignore + if ($cmd) { + Write-Verbose -Verbose 'makeappx available in PATH' + $exePath = $cmd.Source + } else { + $makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' | + Where-Object { $_.DirectoryName -match 'x64' } | + Select-Object -Last 1 + $exePath = $makeappx.FullName + Write-Verbose -Verbose "makeappx was found: $exePath" + } + $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Find makeappx tool + retryCountOnTaskFailure: 1 + + - pwsh: | + $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' + $null = New-Item -Path $sourceDir -ItemType Directory -Force + + $msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse + foreach ($msixFile in $msixFiles) { + $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose + } + + $file = Get-ChildItem $sourceDir | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $pkgName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating $pkgName" + + $makeappx = '$(MakeAppxPath)' + $outputDir = "$sourceDir\output" + New-Item $outputDir -Type Directory -Force > $null + & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" + if ($LASTEXITCODE -ne 0) { + throw "makeappx bundle failed with exit code $LASTEXITCODE" + } + + Get-ChildItem -Path $sourceDir -Recurse | Out-String -Width 200 + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Create MsixBundle + retryCountOnTaskFailure: 1 + + - task: onebranch.pipeline.signing@1 + displayName: Sign MsixBundle + inputs: + command: 'sign' + signing_profile: $(MSIXProfile) + files_to_sign: '**/*.msixbundle' + search_root: '$(BundleDir)' + + - pwsh: | + $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File + Write-Verbose -Verbose "Signed bundle: $signedBundle" + + $signature = Get-AuthenticodeSignature -FilePath $signedBundle.FullName + if ($signature.Status -ne 'Valid') { + throw "The bundle file doesn't have a valid signature. Signature status: $($signature.Status)" + } + + if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { + $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop + } + + $targetPath = Join-Path '$(ob_outputDirectory)' 'Microsoft.PowerShell-LTS_8wekyb3d8bbwe.msixbundle' + Copy-Item -Verbose -Path $signedBundle.FullName -Destination $targetPath + + Write-Verbose -Verbose "Uploaded Bundle:" + Get-ChildItem -Path $(ob_outputDirectory) | Out-String -Width 200 -Stream | Write-Verbose -Verbose + displayName: 'Stage msixbundle for VPack' + + - pwsh: | + Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose + $vpackFiles = Get-ChildItem -Path '$(ob_outputDirectory)\*' -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(ob_outputDirectory)" + } + $vpackFiles | Out-String -Width 200 + displayName: Debug Output Directory and Version + condition: succeededOrFailed() + + - stage: Publish_Symbols + displayName: 'Publish Symbols' + dependsOn: [Pack_MSIXBundle_And_Sign] + jobs: + - job: PublishSymbols + pool: + type: windows + variables: + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true + + - pwsh: | + Get-ChildItem Env: | Out-String -Width 9999 + displayName: 'Capture Environment Variables' + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_x64 + itemPattern: | + **/symbols-*.zip + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download symbols for x64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_arm64 + itemPattern: | + **/symbols-*.zip + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download symbols for arm64 + + - pwsh: | + $downloadDir = '$(Build.ArtifactStagingDirectory)\downloads' + Write-Verbose -Verbose "Enumerating $downloadDir" + $downloadedArtifacts = Get-ChildItem -Path $downloadDir -Recurse -Filter 'symbols-*.zip' + $downloadedArtifacts | Out-String -Width 9999 + + $expandedRoot = New-Item -Path "$(Pipeline.Workspace)\expanded" -ItemType Directory -Verbose + $downloadedArtifacts | ForEach-Object { + $expandDir = Join-Path $expandedRoot $_.BaseName + Write-Verbose -Verbose "Expanding $($_.FullName) to $expandDir" + $null = New-Item -Path $expandDir -ItemType Directory -Verbose + Expand-Archive -Path $_.FullName -DestinationPath $expandDir -Force + } + + Write-Verbose -Verbose "Enumerating $expandedRoot" + Get-ChildItem -Path $expandedRoot -Recurse | Out-String -Width 9999 + $vstsCommandString = "vso[task.setvariable variable=SymbolsPath]$expandedRoot" + Write-Verbose -Message "$vstsCommandString" -Verbose + Write-Host -Object "##$vstsCommandString" + displayName: Expand and capture symbols folders + + - task: PublishSymbols@2 + condition: and(succeeded(), ${{ parameters.createVPack }}) + inputs: + symbolsFolder: '$(SymbolsPath)' + searchPattern: '**/*.pdb' + indexSources: false + publishSymbols: true + symbolServerType: TeamServices + detailedLog: true diff --git a/PowerShell.Common.props b/PowerShell.Common.props index dfc16f830d7..0b40b8d717f 100644 --- a/PowerShell.Common.props +++ b/PowerShell.Common.props @@ -163,7 +163,7 @@ <PropertyGroup> <DefineConstants>$(DefineConstants);CORECLR</DefineConstants> - <IsWindows Condition="'$(IsWindows)' =='true' or ( '$(IsWindows)' == '' and '$(OS)' == 'Windows_NT')">true</IsWindows> + <IsWindows Condition="'$(IsWindows)' == 'true' or ('$(IsWindows)' == '' and '$(OS)' == 'Windows_NT')">true</IsWindows> </PropertyGroup> <!-- Define non-windows, all configuration properties --> diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index bcc1d45da49..a84d18e6684 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -318,7 +318,7 @@ internal static int Start( } s_theConsoleHost.BindBreakHandler(); - PSHost.IsStdOutputRedirected = Console.IsOutputRedirected; + IsStdOutputRedirected = Console.IsOutputRedirected; // Send startup telemetry for ConsoleHost startup ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("Normal", s_cpp.ParametersUsedAsDouble); diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs index 6dfd5d54e6f..acfdea07153 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs @@ -86,9 +86,9 @@ public static int Start([MarshalAs(UnmanagedType.LPArray, ArraySubType = Unmanag int exitCode = 0; try { - var banner = string.Format( + string banner = string.Format( CultureInfo.InvariantCulture, - ManagedEntranceStrings.ShellBannerNonWindowsPowerShell, + ManagedEntranceStrings.ShellBannerPowerShell, PSVersionInfo.GitCommitId); ConsoleHost.DefaultInitialSessionState = InitialSessionState.CreateDefault2(); diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx index 2c0b0154757..44ebf0fb538 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx @@ -117,7 +117,7 @@ <resheader name="writer"> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> - <data name="ShellBannerNonWindowsPowerShell" xml:space="preserve"> + <data name="ShellBannerPowerShell" xml:space="preserve"> <value>PowerShell {0}</value> </data> <data name="ShellBannerCLMode" xml:space="preserve"> diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx index 819270da259..b5905f1cf7a 100644 --- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx +++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx @@ -849,7 +849,7 @@ Note that 'Start-Job' is not supported by design in scenarios where PowerShell i <value>The WriteEvents parameter cannot be used without the Wait parameter.</value> </data> <data name="PowerShellVersionNotSupported" xml:space="preserve"> - <value>PowerShell remoting endpoint versioning is not supported on PowerShell Core.</value> + <value>PowerShell remoting endpoint versioning is not supported on PowerShell 7+.</value> </data> <data name="JobManagerRegistrationConstructorError" xml:space="preserve"> <value>The following type cannot be instantiated because its constructor is not public: {0}.</value> diff --git a/src/System.Management.Automation/resources/TabCompletionStrings.resx b/src/System.Management.Automation/resources/TabCompletionStrings.resx index 751e04cfd2b..298de92da3c 100644 --- a/src/System.Management.Automation/resources/TabCompletionStrings.resx +++ b/src/System.Management.Automation/resources/TabCompletionStrings.resx @@ -457,10 +457,10 @@ This must be the last parameter on the #requires statement line.</value> Specifies the minimum version of PowerShell that the script requires.</value> </data> <data name="RequiresPsEditionCoreDescription" xml:space="preserve"> - <value>Specifies that the script requires PowerShell Core to run.</value> + <value>Specifies that the script requires PowerShell 7+ to run.</value> </data> <data name="RequiresPsEditionDesktopDescription" xml:space="preserve"> - <value>Specifies that the script requires Windows PowerShell to run.</value> + <value>Specifies that the script requires Windows PowerShell 5.1 to run.</value> </data> <data name="RequiresModuleSpecModuleNameDescription" xml:space="preserve"> <value>[string] diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index 5cd728e6c55..8ab34950f60 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -164,7 +164,7 @@ public static class ApplicationInsightsTelemetry private static readonly HashSet<string> s_knownSubsystemNames; /// <summary>Gets a value indicating whether telemetry can be sent.</summary> - public static bool CanSendTelemetry { get; private set; } = false; + public static bool CanSendTelemetry { get; private set; } /// <summary> /// Initializes static members of the <see cref="ApplicationInsightsTelemetry"/> class. @@ -768,11 +768,11 @@ internal static void SendUseTelemetry(string featureName, string detail, double if (string.Compare(featureName, s_subsystemRegistration, true) == 0) { - ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, GetSubsystemName(detail)), value); + SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, GetSubsystemName(detail)), value); } else { - ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, detail), value); + SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, detail), value); } } @@ -788,7 +788,7 @@ internal static void SendExperimentalUseData(string featureName, string detail) return; } - ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.ExperimentalFeatureUse, string.Join(":", featureName, detail)); + SendTelemetryMetric(TelemetryType.ExperimentalFeatureUse, string.Join(":", featureName, detail)); } // Get the experimental feature name. If we can report it, we'll return the name of the feature, otherwise, we'll return "anonymous" diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index d310344a0fa..b0131d39ebf 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -4318,8 +4318,7 @@ function New-MSIXPackage Write-Verbose "Using LTS assets" -Verbose } - # Appx manifest needs to be in root of source path, but the embedded version needs to be updated - # cp-459155 is 'CN=Microsoft Windows Store Publisher (Store EKU), O=Microsoft Corporation, L=Redmond, S=Washington, C=US' + # Appx manifest needs to be in root of source path, but the embedded version needs to be updated. # authenticodeFormer is 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US' $releasePublisher = 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US' @@ -4361,7 +4360,6 @@ function New-MSIXPackage else { Copy-Item -Path "$RepoRoot\assets\$_.png" -Destination "$ProductSourcePath\assets\" } - } if ($PSCmdlet.ShouldProcess("Create .msix package?")) { From 10dccb06953f9cc9f4a0ef2d423be433eccf1574 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Thu, 9 Apr 2026 15:35:58 -0700 Subject: [PATCH 104/127] [release/v7.6.1] [StepSecurity] ci: Harden GitHub Actions tags (#27236) --- .github/actions/build/ci/action.yml | 4 ++-- .../get-changed-files/action.yml | 2 +- .../infrastructure/path-filters/action.yml | 2 +- .../actions/test/linux-packaging/action.yml | 8 ++++---- .github/actions/test/nix/action.yml | 6 +++--- .../test/process-pester-results/action.yml | 2 +- .github/actions/test/windows/action.yml | 4 ++-- .github/workflows/analyze-reusable.yml | 2 +- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/labels.yml | 4 ++-- .github/workflows/linux-ci.yml | 18 +++++++++--------- .github/workflows/macos-ci.yml | 18 +++++++++--------- .github/workflows/verify-markdown-links.yml | 2 +- .github/workflows/windows-ci.yml | 12 ++++++------ .../workflows/windows-packaging-reusable.yml | 6 +++--- .github/workflows/xunit-tests.yml | 6 +++--- 16 files changed, 49 insertions(+), 49 deletions(-) diff --git a/.github/actions/build/ci/action.yml b/.github/actions/build/ci/action.yml index be9c0ecd20b..65331fb3185 100644 --- a/.github/actions/build/ci/action.yml +++ b/.github/actions/build/ci/action.yml @@ -13,7 +13,7 @@ runs: if: github.event_name != 'PullRequest' run: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))" shell: pwsh - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: global-json-file: ./global.json - name: Bootstrap @@ -34,7 +34,7 @@ runs: Invoke-CIBuild shell: pwsh - name: Upload build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: build path: ${{ runner.workspace }}/build diff --git a/.github/actions/infrastructure/get-changed-files/action.yml b/.github/actions/infrastructure/get-changed-files/action.yml index c897d4f388d..51631cfe141 100644 --- a/.github/actions/infrastructure/get-changed-files/action.yml +++ b/.github/actions/infrastructure/get-changed-files/action.yml @@ -21,7 +21,7 @@ runs: steps: - name: Get changed files id: get-files - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: script: | const eventTypes = '${{ inputs.event-types }}'.split(',').map(t => t.trim()); diff --git a/.github/actions/infrastructure/path-filters/action.yml b/.github/actions/infrastructure/path-filters/action.yml index 656719262b2..af23540256d 100644 --- a/.github/actions/infrastructure/path-filters/action.yml +++ b/.github/actions/infrastructure/path-filters/action.yml @@ -39,7 +39,7 @@ runs: - name: Check if GitHubWorkflowChanges is present id: filter - uses: actions/github-script@v7.0.1 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 env: FILES_JSON: ${{ steps.get-files.outputs.files }} with: diff --git a/.github/actions/test/linux-packaging/action.yml b/.github/actions/test/linux-packaging/action.yml index ef9ba23e799..7a06e3feb17 100644 --- a/.github/actions/test/linux-packaging/action.yml +++ b/.github/actions/test/linux-packaging/action.yml @@ -11,7 +11,7 @@ runs: Show-Environment shell: pwsh - - uses: actions/setup-dotnet@v5 + - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json @@ -97,21 +97,21 @@ runs: shell: pwsh - name: Upload deb packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: packages-deb path: ${{ runner.workspace }}/packages/*.deb if-no-files-found: ignore - name: Upload rpm packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: packages-rpm path: ${{ runner.workspace }}/packages/*.rpm if-no-files-found: ignore - name: Upload tar.gz packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: packages-tar path: ${{ runner.workspace }}/packages/*.tar.gz diff --git a/.github/actions/test/nix/action.yml b/.github/actions/test/nix/action.yml index 7f68e71c1f5..ab30e0d9ce6 100644 --- a/.github/actions/test/nix/action.yml +++ b/.github/actions/test/nix/action.yml @@ -29,7 +29,7 @@ runs: shell: pwsh - name: Download Build Artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: path: "${{ github.workspace }}" @@ -42,7 +42,7 @@ runs: Write-LogGroupEnd -Title 'Artifacts Directory' shell: pwsh - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: global-json-file: ./global.json @@ -101,7 +101,7 @@ runs: Write-LogGroupEnd -Title 'Bootstrap' - name: Extract Files - uses: actions/github-script@v7.0.0 + uses: actions/github-script@e69ef5462fd455e02edcaf4dd7708eda96b9eda0 # v7.0.0 env: DESTINATION_FOLDER: "${{ github.workspace }}/bins" ARCHIVE_FILE_PATTERNS: "${{ github.workspace }}/build/build.zip" diff --git a/.github/actions/test/process-pester-results/action.yml b/.github/actions/test/process-pester-results/action.yml index 27b94f6ebcb..44f2037626f 100644 --- a/.github/actions/test/process-pester-results/action.yml +++ b/.github/actions/test/process-pester-results/action.yml @@ -21,7 +21,7 @@ runs: - name: Upload testResults artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: junit-pester-${{ inputs.name }} path: ${{ runner.workspace }}/testResults diff --git a/.github/actions/test/windows/action.yml b/.github/actions/test/windows/action.yml index 2c41f6aac5c..ddc5da4d664 100644 --- a/.github/actions/test/windows/action.yml +++ b/.github/actions/test/windows/action.yml @@ -29,7 +29,7 @@ runs: shell: pwsh - name: Download Build Artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: path: "${{ github.workspace }}" @@ -42,7 +42,7 @@ runs: Write-LogGroupEnd -Title 'Artifacts Directory' shell: pwsh - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: global-json-file: .\global.json diff --git a/.github/workflows/analyze-reusable.yml b/.github/workflows/analyze-reusable.yml index 75886342851..aca43b54ca9 100644 --- a/.github/workflows/analyze-reusable.yml +++ b/.github/workflows/analyze-reusable.yml @@ -41,7 +41,7 @@ jobs: with: fetch-depth: '0' - - uses: actions/setup-dotnet@v5 + - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 7c63c9122a8..d78e745a4a9 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -25,7 +25,7 @@ jobs: # You can define any steps you want, and they will run before the agent starts. # If you do not check out your code, Copilot will do this for you. steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index cd0a1d31726..27ceac59bbd 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -18,11 +18,11 @@ jobs: steps: - name: Check out the repository - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Verify PR has label starting with 'cl-' id: verify-labels - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | const labels = context.payload.pull_request.labels.map(label => label.name.toLowerCase()); diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index 4146725fbb1..ed9dcf2d9d2 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -57,7 +57,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -76,7 +76,7 @@ jobs: contents: read steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check for merge conflict markers uses: "./.github/actions/infrastructure/merge-conflict-checker" @@ -88,7 +88,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 @@ -103,7 +103,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Unelevated CI @@ -121,7 +121,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Elevated CI @@ -139,7 +139,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Unelevated Others @@ -157,7 +157,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Linux Elevated Others @@ -181,7 +181,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 @@ -238,7 +238,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - name: Linux Packaging diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index de5f7318660..bcaa2aa4061 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -57,7 +57,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Change Detection id: filter @@ -72,7 +72,7 @@ jobs: if: ${{ needs.changes.outputs.source == 'true' || needs.changes.outputs.buildModuleChanged == 'true' }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Build @@ -86,7 +86,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Unelevated CI @@ -104,7 +104,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Elevated CI @@ -122,7 +122,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Unelevated Others @@ -140,7 +140,7 @@ jobs: runs-on: macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: macOS Elevated Others @@ -167,10 +167,10 @@ jobs: - macos-15-large steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json - name: Bootstrap packaging @@ -229,7 +229,7 @@ jobs: testResultsFolder: "${{ runner.workspace }}/testResults" - name: Upload package artifact if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: macos-package path: "*.pkg" diff --git a/.github/workflows/verify-markdown-links.yml b/.github/workflows/verify-markdown-links.yml index 713160dea21..3a10b96fc1a 100644 --- a/.github/workflows/verify-markdown-links.yml +++ b/.github/workflows/verify-markdown-links.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Verify markdown links id: verify diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index df23d5b3c48..3a68fa7ab3f 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -60,7 +60,7 @@ jobs: packagingChanged: ${{ steps.filter.outputs.packagingChanged }} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Change Detection id: filter @@ -75,7 +75,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Build @@ -89,7 +89,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Unelevated CI @@ -107,7 +107,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Elevated CI @@ -125,7 +125,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Unelevated Others @@ -143,7 +143,7 @@ jobs: runs-on: windows-latest steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Windows Elevated Others diff --git a/.github/workflows/windows-packaging-reusable.yml b/.github/workflows/windows-packaging-reusable.yml index 1f136636ec5..8d0255d4443 100644 --- a/.github/workflows/windows-packaging-reusable.yml +++ b/.github/workflows/windows-packaging-reusable.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 @@ -64,7 +64,7 @@ jobs: shell: pwsh - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json @@ -84,7 +84,7 @@ jobs: - name: Upload Build Artifacts if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: windows-packaging-${{ matrix.architecture }}-${{ matrix.channel }} path: | diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml index 668d413481e..c643917edd0 100644 --- a/.github/workflows/xunit-tests.yml +++ b/.github/workflows/xunit-tests.yml @@ -23,12 +23,12 @@ jobs: runs-on: ${{ inputs.runner_os }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1000 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: global-json-file: ./global.json @@ -49,7 +49,7 @@ jobs: Write-Host "Completed xUnit test run." - name: Upload xUnit results - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: always() with: name: ${{ inputs.test_results_artifact_name }} From e0b41c95e4bae7f4463c2d31e6a0e3823f31269c Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Thu, 9 Apr 2026 16:42:55 -0700 Subject: [PATCH 105/127] [release/v7.6.1] Pin ready-to-merge.yml reusable workflow to commit SHA (#27245) --- .github/workflows/linux-ci.yml | 2 +- .github/workflows/macos-ci.yml | 2 +- .github/workflows/windows-ci.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index ed9dcf2d9d2..0cbf2986c68 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -257,6 +257,6 @@ jobs: - infrastructure_tests # - analyze if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0 with: needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index bcaa2aa4061..9a92a450e66 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -243,6 +243,6 @@ jobs: - macos_test_unelevated_ci - macos_test_unelevated_others if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0 with: needs_context: ${{ toJson(needs) }} diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 3a68fa7ab3f..98bbe344ea4 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -189,6 +189,6 @@ jobs: - analyze - windows_packaging if: always() - uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@v1.0.0 + uses: PowerShell/compliance/.github/workflows/ready-to-merge.yml@c8b3ad5819ad7078f3e375519b4f8c6232d1cbdf # v1.0.0 with: needs_context: ${{ toJson(needs) }} From 8bb8de7266074d53aba983d3e4a2a8b16d8a4624 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Fri, 10 Apr 2026 15:28:39 -0700 Subject: [PATCH 106/127] [release/v7.6.1] Fix package pipeline by adding in PDP-Media directory (#27257) --- .pipelines/store/PDP/PDP-Media/en-US/.gitkeep | 0 .pipelines/templates/package-store-package.yml | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 .pipelines/store/PDP/PDP-Media/en-US/.gitkeep diff --git a/.pipelines/store/PDP/PDP-Media/en-US/.gitkeep b/.pipelines/store/PDP/PDP-Media/en-US/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/.pipelines/templates/package-store-package.yml b/.pipelines/templates/package-store-package.yml index 7667b1361e7..6abddae6851 100644 --- a/.pipelines/templates/package-store-package.yml +++ b/.pipelines/templates/package-store-package.yml @@ -195,6 +195,7 @@ jobs: contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - task: MS-RDX-MRO.windows-store-publish.package-task.store-package@3 displayName: 'Create StoreBroker Package (Stable/LTS)' @@ -206,6 +207,7 @@ jobs: contents: '*.msixBundle' outSBName: 'PowerShellStorePackage' pdpPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP' + pdpMediaPath: '$(System.DefaultWorkingDirectory)/PowerShell/.pipelines/store/PDP/PDP-Media' - pwsh: | $outputDirectory = "$(ob_outputDirectory)" From 8b54b1dd8fa0461d3a78c2114622af61ffd9ea78 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Fri, 17 Apr 2026 13:33:03 -0400 Subject: [PATCH 107/127] [release/v7.6.1] Update branch for release (#27287) --- CHANGELOG/v7.6/dependencychanges.json | 53 +++++++++++++++++++ DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- .../Microsoft.PowerShell.SDK.csproj | 9 ++-- test/tools/TestService/TestService.csproj | 4 +- tools/cgmanifest/main/cgmanifest.json | 6 +-- 6 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 CHANGELOG/v7.6/dependencychanges.json diff --git a/CHANGELOG/v7.6/dependencychanges.json b/CHANGELOG/v7.6/dependencychanges.json new file mode 100644 index 00000000000..0189431db77 --- /dev/null +++ b/CHANGELOG/v7.6/dependencychanges.json @@ -0,0 +1,53 @@ +[ + { + "ChangeType": "Security", + "Branch": "release/v7.6.1", + "PackageId": "System.Security.Cryptography.Xml", + "FromVersion": "10.0.5", + "ToVersion": "10.0.6", + "VulnerabilityId": [ + "GHSA-W3X6-4M5H-CXQF", + "CVE-2026-26171", + "GHSA-37GX-XXP4-5RGX", + "CVE-2026-33116" + ], + "Severity": [ + "high" + ], + "VulnerableRanges": [ + "[10.0.0, 10.0.5]" + ], + "AdvisoryUrls": [ + "https://github.com/advisories/GHSA-w3x6-4m5h-cxqf", + "https://github.com/advisories/GHSA-37gx-xxp4-5rgx" + ], + "Justification": null, + "TimestampUtc": "2026-04-16T23:13:21.4575733Z" + }, + { + "ChangeType": "NonSecurity", + "Branch": "release/v7.6.1", + "PackageId": ".NET SDK", + "FromVersion": "10.0.201", + "ToVersion": "10.0.202", + "VulnerabilityId": [], + "Severity": [], + "VulnerableRanges": [], + "AdvisoryUrls": [], + "Justification": "Updated .NET SDK. Building with the latest SDK is required.", + "TimestampUtc": "2026-04-16T23:13:22.4500098Z" + }, + { + "ChangeType": "NonSecurity", + "Branch": "release/v7.6.1", + "PackageId": "System.Security.Cryptography.Pkcs", + "FromVersion": "10.0.5", + "ToVersion": "10.0.6", + "VulnerabilityId": [], + "Severity": [], + "VulnerableRanges": [], + "AdvisoryUrls": [], + "Justification": "Required dependency of System.Security.Cryptography.Xml.", + "TimestampUtc": "2026-04-16T23:13:22.4500098Z" + } +] diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 89ea4c44790..8b1ed423288 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.201", + "sdkImageVersion": "10.0.202", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index ce67766bbb5..5ee7b7cb062 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.201" + "version": "10.0.202" } } diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj index 290786be1e1..82f0a2ebf9a 100644 --- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj +++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj @@ -58,9 +58,9 @@ <PackageReference Include="System.Net.Http.WinHttpHandler" Version="10.0.5" /> <PackageReference Include="System.Reflection.Context" Version="10.0.5" /> <PackageReference Include="System.Runtime.Caching" Version="10.0.5" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="10.0.5" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="10.0.6" /> <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="10.0.5" /> - <PackageReference Include="System.Security.Cryptography.Xml" Version="10.0.5" /> + <PackageReference Include="System.Security.Cryptography.Xml" Version="10.0.6" /> <PackageReference Include="System.Security.Permissions" Version="10.0.5" /> <!-- the following package(s) are from https://github.com/dotnet/wcf --> <PackageReference Include="System.ServiceModel.Http" Version="10.0.652802" /> @@ -85,14 +85,13 @@ dotnet msbuild ./dummy.csproj /t:ResolveAssemblyReferencesDesignTime /fileLogger /noconsolelogger /v:diag 3. Search '_ReferencesFromRAR' in the produced 'msbuild.log' file. --> - <Target Name="_GetDependencies" - DependsOnTargets="ResolveAssemblyReferencesDesignTime"> + <Target Name="_GetDependencies" DependsOnTargets="ResolveAssemblyReferencesDesignTime"> <ItemGroup> <!-- Excludes 'Microsoft.Management.Infrastructure' from the type catalog reference list, as it is provided separately at runtime and must not be included in the generated catalog. --> - <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/> + <_RefAssemblyPath Include="%(_ReferencesFromRAR.OriginalItemSpec)%3B" Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' " /> </ItemGroup> <WriteLinesToFile File="$(_DependencyFile)" Lines="@(_RefAssemblyPath)" Overwrite="true" /> </Target> diff --git a/test/tools/TestService/TestService.csproj b/test/tools/TestService/TestService.csproj index 1b2c5aa03a4..0a5eaf8d6fd 100644 --- a/test/tools/TestService/TestService.csproj +++ b/test/tools/TestService/TestService.csproj @@ -53,9 +53,9 @@ <PackageReference Include="System.Management" Version="10.0.5" /> <PackageReference Include="System.Reflection.Context" Version="10.0.5" /> <PackageReference Include="System.Runtime.Caching" Version="10.0.5" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="10.0.5" /> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="10.0.6" /> <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="10.0.5" /> - <PackageReference Include="System.Security.Cryptography.Xml" Version="10.0.5" /> + <PackageReference Include="System.Security.Cryptography.Xml" Version="10.0.6" /> <PackageReference Include="System.Security.Permissions" Version="10.0.5" /> <PackageReference Include="System.ServiceModel.Syndication" Version="10.0.5" /> <PackageReference Include="System.ServiceProcess.ServiceController" Version="10.0.5" /> diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index 4004daffd93..fd645029d33 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/component-detection-manifest.json", "Registrations": [ { "Component": { @@ -645,7 +646,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Xml", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false @@ -750,6 +751,5 @@ }, "DevelopmentDependency": false } - ], - "$schema": "https://json.schemastore.org/component-detection-manifest.json" + ] } From fb32ab04df59569f4e6d8f0670a82f27e22a1d7e Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Tue, 21 Apr 2026 12:37:22 -0700 Subject: [PATCH 108/127] Update Changelog for release v7.6.1 (#27313) --- CHANGELOG/7.6.md | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/CHANGELOG/7.6.md b/CHANGELOG/7.6.md index fb1037f7e24..a4d81683321 100644 --- a/CHANGELOG/7.6.md +++ b/CHANGELOG/7.6.md @@ -1,5 +1,50 @@ # 7.6 Changelog +## [7.6.1] + +### General Cmdlet Updates and Fixes + +- Delay update notification for one week to ensure all packages become available (#27215) + +### Tests + +- Fix the `PSNativeCommandArgumentPassing` test (#27179) + +### Build and Packaging Improvements + +<details> + +<summary> + +<p>Update to .NET SDK 10.0.202</p> + +</summary> + +<ul> +<li>Fix PMC Repo URL for RHEL10 (#27061) (#27062)</li> +<li>Update branch for release (#27287)</li> +<li>Fix package pipeline by adding in PDP-Media directory (#27257)</li> +<li>Pin ready-to-merge.yml reusable workflow to commit SHA (#27245)</li> +<li>[StepSecurity] ci: Harden GitHub Actions tags (#27236)</li> +<li>Build, package, and create VPack for the PowerShell-LTS store package within the same <code>msixbundle-vpack</code> pipeline (#27237)</li> +<li>Change the display name of PowerShell-LTS package to PowerShell LTS (#27219)</li> +<li>[StepSecurity] ci: Harden GitHub Actions tokens (#27218)</li> +<li>Redo windows image fix to use latest image (#27217)</li> +<li>Add comment-based help documentation to build.psm1 functions (#27216)</li> +<li>Separate Store Package Creation, Skip Polling for Store Publish, Clean up PDP-Media (#27214)</li> +<li>Bump github/codeql-action from 4.34.1 to 4.35.1 (#27184)</li> +<li>Bump github/codeql-action from 4.32.6 to 4.34.1 (#27182)</li> +<li>Select New MSIX Package Name (#27183)</li> +<li>Update the PhoneProductId to be the official LTS id used by Store (#27181)</li> +<li>release-upload-buildinfo: replace version-comparison channel gating with metadata flags (#27180)</li> +<li>Move <code>_GetDependencies</code> MSBuild target from dynamic generation in <code>build.psm1</code> into <code>Microsoft.PowerShell.SDK.csproj</code> (#27177)</li> +<li>Separate Official and NonOfficial templates for ADO pipelines (#27176)</li> +</ul> + +</details> + +[7.6.1]: https://github.com/PowerShell/PowerShell/compare/v7.6.0...v7.6.1 + ## [7.6.0] - 2026-03-12 ### General Cmdlet Updates and Fixes @@ -804,4 +849,4 @@ name, the **ThreadJob** v2.1.0 module is a proxy module that points to the - Update changelog and `metadata.json` for v7.4.5 release (#24183) - Bring 7.2 changelogs back to master (#24158) -[7.6.0-preview.1]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-rc.1...v7.6.0-preview.1 +[7.6.0-preview.1]: https://github.com/PowerShell/PowerShell/compare/v7.5.0-rc.1...v7.6.0-preview.1 \ No newline at end of file From 8140b68773e0fba7b478836348a4506d38525b83 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Tue, 21 Apr 2026 13:36:36 -0700 Subject: [PATCH 109/127] [release/v7.6.1] Correct Variable Template Reference in NonOfficial Pipeline Templates (#27317) Co-authored-by: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Co-authored-by: Justin Chung <chungjustin@microsoft.com> --- .github/agents/SplitADOPipelines.agent.md | 52 ++++++++++++------- ...Shell-Coordinated_Packages-NonOfficial.yml | 5 +- .../PowerShell-Packages-NonOfficial.yml | 4 +- .../PowerShell-Release-Azure-NonOfficial.yml | 2 +- .../PowerShell-Release-NonOfficial.yml | 4 +- .../PowerShell-vPack-NonOfficial.yml | 4 +- .../stages/PowerShell-vPack-Stages.yml | 2 +- 7 files changed, 45 insertions(+), 28 deletions(-) diff --git a/.github/agents/SplitADOPipelines.agent.md b/.github/agents/SplitADOPipelines.agent.md index 8322f473e7b..9454670061f 100644 --- a/.github/agents/SplitADOPipelines.agent.md +++ b/.github/agents/SplitADOPipelines.agent.md @@ -6,7 +6,7 @@ tools: ['vscode', 'execute', 'read', 'agent', 'edit', 'search', 'todo'] This agent will implement and restructure the repository's existing ADO pipelines into Official and NonOfficial pipelines. -A repository will have under the ./pipelines directory a series of yaml files that define the ADO pipelines for the repository. +A repository will have under the .pipelines directory a series of yaml files that define the ADO pipelines for the repository. First confirm if the pipelines are using a toggle switch for Official and NonOfficial. This will look something like this @@ -25,15 +25,31 @@ extends: This is an indicator that this work needs to be done. This toggle switch is no longer allowed and the templates need to be hard coded. +## Template Reference Convention (MUST follow) + +All `- template:` references to files **inside this repo** must use the **absolute** form anchored at the repo root, with the `@self` suffix: + +```yaml +- template: /.pipelines/templates/<path>/<file>.yml@self +``` + +Do **not** use relative paths such as `templates/...`, `../templates/...`, or bare filenames. Rationale: + +- Absolute paths resolve identically regardless of where the referring file lives, so moving a pipeline file between directories (for example, into `.pipelines/NonOfficial/`) does not silently break includes. +- Relative paths are resolved by Azure DevOps against the directory of the referring file, which has caused real outages in this repo when a relative include was composed into a nonexistent nested path like `.pipelines/templates/stages/.pipelines/templates/...`. +- The majority of existing includes already use the absolute form; keeping new work consistent reduces review burden. + +The only acceptable non-absolute references are to external repositories resolved via the `resources.repositories` block, for example `v2/OneBranch.Official.CrossPlat.yml@onebranchTemplates`. + ## Refactoring Steps ### Step 1: Extract Shared Templates -For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Packages.yml`): +For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Packages-Official.yml`): -1. Create a `./pipelines/templates` directory if it doesn't exist -2. Extract the **variables section** into `./pipelines/templates/PowerShell-Packages-Variables.yml` -3. Extract the **stages section** into `./pipelines/templates/PowerShell-Packages-Stages.yml` +1. Create the `.pipelines/templates/variables` and `.pipelines/templates/stages` directories if they don't exist +2. Extract the **variables section** into `.pipelines/templates/variables/PowerShell-Packages-Variables.yml` +3. Extract the **stages section** into `.pipelines/templates/stages/PowerShell-Packages-Stages.yml` **IMPORTANT**: Only extract the `variables:` and `stages:` sections. All other sections (parameters, resources, extends, etc.) remain in the pipeline files. @@ -41,7 +57,7 @@ For each pipeline file that uses the toggle switch pattern (e.g., `PowerShell-Pa The original toggle-based file becomes the Official pipeline: -1. **Keep the file in its original location** (e.g., `./pipelines/PowerShell-Packages.yml` stays where it is) +1. **Keep the file in its original location** (e.g., `.pipelines/PowerShell-Packages-Official.yml` stays where it is) 2. Remove the toggle switch parameter (`templateFile` parameter) 3. Hard-code the Official template reference: ```yaml @@ -51,18 +67,18 @@ The original toggle-based file becomes the Official pipeline: 4. Replace the `variables:` section with a template reference: ```yaml variables: - - template: templates/PowerShell-Packages-Variables.yml + - template: /.pipelines/templates/variables/PowerShell-Packages-Variables.yml@self ``` 5. Replace the `stages:` section with a template reference: ```yaml stages: - - template: templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self ``` ### Step 3: Create NonOfficial Pipeline -1. Create `./pipelines/NonOfficial` directory if it doesn't exist -2. Create the NonOfficial pipeline file (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`) +1. Create `.pipelines/NonOfficial` directory if it doesn't exist +2. Create the NonOfficial pipeline file (e.g., `.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`) 3. Copy the structure from the refactored Official pipeline 4. Hard-code the NonOfficial template reference: ```yaml @@ -72,13 +88,13 @@ The original toggle-based file becomes the Official pipeline: 5. Reference the same shared templates: ```yaml variables: - - template: ../templates/PowerShell-Packages-Variables.yml + - template: /.pipelines/templates/variables/PowerShell-Packages-Variables.yml@self stages: - - template: ../templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self ``` -**Note**: The NonOfficial pipeline uses `../templates/` because it's one directory deeper than the Official pipeline. +**Note**: Always use **absolute** template paths of the form `/.pipelines/templates/...@self`. Do not use relative paths like `templates/...` or `../templates/...`. Absolute paths are anchored at the repo root and resolve consistently from any referring file, preventing breakage when files are moved between directories. ### Step 4: Link NonOfficial Pipelines to NonOfficial Dependencies @@ -124,29 +140,29 @@ Then you must configure the `ob_release_environment` parameter when referencing #### Official Pipeline Configuration -In the Official pipeline (e.g., `./pipelines/PowerShell-Packages.yml`): +In the Official pipeline (e.g., `.pipelines/PowerShell-Packages-Official.yml`): ```yaml stages: - - template: templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: ob_release_environment: Production ``` #### NonOfficial Pipeline Configuration -In the NonOfficial pipeline (e.g., `./pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`): +In the NonOfficial pipeline (e.g., `.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml`): ```yaml stages: - - template: ../templates/PowerShell-Packages-Stages.yml + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: ob_release_environment: Test ``` #### Update Stages Template to Accept Parameter -The extracted stages template (e.g., `./pipelines/templates/PowerShell-Packages-Stages.yml`) must declare the parameter at the top: +The extracted stages template (e.g., `.pipelines/templates/stages/PowerShell-Packages-Stages.yml`) must declare the parameter at the top: ```yaml parameters: diff --git a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml index 0b417df5c05..69506750c34 100644 --- a/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Coordinated_Packages-NonOfficial.yml @@ -45,7 +45,7 @@ resources: ref: refs/heads/main variables: - - template: ./pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Coordinated_Packages-Variables.yml@self parameters: InternalSDKBlobURL: ${{ parameters.InternalSDKBlobURL }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -61,6 +61,7 @@ extends: LinuxHostVersion: Network: KS3 WindowsHostVersion: + Version: 2022 Network: KS3 incrementalSDLBinaryAnalysis: true globalSdl: @@ -90,7 +91,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-Coordinated_Packages-Stages.yml@self parameters: RUN_WINDOWS: ${{ parameters.RUN_WINDOWS }} RUN_TEST_AND_RELEASE: ${{ parameters.RUN_TEST_AND_RELEASE }} diff --git a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml index 9419d3f29b5..0993cd69546 100644 --- a/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Packages-NonOfficial.yml @@ -31,7 +31,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: pkgs-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ./pipelines/templates/variables/PowerShell-Packages-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Packages-Variables.yml@self parameters: debug: ${{ parameters.debug }} ForceAzureBlobDelete: ${{ parameters.ForceAzureBlobDelete }} @@ -92,6 +92,6 @@ extends: enabled: false tsaOptionsFile: .config\tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-Packages-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-Packages-Stages.yml@self parameters: OfficialBuild: false diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml index b524cb0ff81..4d406fbf9d5 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -17,7 +17,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: ev2-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ./pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Release-Azure-Variables.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml index 7864513fc2c..ebfc599e42a 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: release-$(BUILD.SOURCEBRANCHNAME)-nonofficial-$(Build.BuildId) variables: - - template: ./pipelines/templates/variables/PowerShell-Release-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-Release-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -98,7 +98,7 @@ extends: tsaOptionsFile: .config\tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-Release-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-Release-Stages.yml@self parameters: releaseEnvironment: Test SkipPublish: ${{ parameters.SkipPublish }} diff --git a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml index f1f4211ca8f..071db02cff8 100644 --- a/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-vPack-NonOfficial.yml @@ -33,7 +33,7 @@ parameters: # parameters are shown up in ADO UI in a build queue time name: vPack_$(Build.SourceBranchName)_NonOfficial_Create.${{ parameters.createVPack }}_Name.${{ parameters.vPackName}}_$(date:yyyyMMdd).$(rev:rr) variables: - - template: ./pipelines/templates/variables/PowerShell-vPack-Variables.yml@self + - template: /.pipelines/templates/variables/PowerShell-vPack-Variables.yml@self parameters: debug: ${{ parameters.debug }} ReleaseTagVar: ${{ parameters.ReleaseTagVar }} @@ -82,7 +82,7 @@ extends: enabled: false tsaOptionsFile: .config/tsaoptions.json stages: - - template: ./pipelines/templates/stages/PowerShell-vPack-Stages.yml@self + - template: /.pipelines/templates/stages/PowerShell-vPack-Stages.yml@self parameters: createVPack: ${{ parameters.createVPack }} vPackName: ${{ parameters.vPackName }} diff --git a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml index f0d49e8b489..01a83a5b161 100644 --- a/.pipelines/templates/stages/PowerShell-vPack-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-vPack-Stages.yml @@ -50,7 +50,7 @@ stages: env: ob_restore_phase: true - - template: .pipelines/templates/SetVersionVariables.yml@self + - template: /.pipelines/templates/SetVersionVariables.yml@self parameters: ReleaseTagVar: $(ReleaseTagVar) CreateJson: yes From 6404717a8c5afcd03d2df4f03e143d97b5de11aa Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan <adityap@microsoft.com> Date: Tue, 21 Apr 2026 15:37:11 -0700 Subject: [PATCH 110/127] PMC release: Use slash instead of back-slash for Linux container (#27319) --- .pipelines/templates/release-prep-for-ev2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index e644bece68f..f73caa10450 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -23,7 +23,7 @@ stages: - group: 'mscodehub-code-read-akv' - group: 'packages.microsoft.com' - name: ob_sdl_credscan_suppressionsFile - value: $(Build.SourcesDirectory)\PowerShell\.config\suppress.json + value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json steps: - checkout: self ## the global setting on lfs didn't work lfs: false From 57a6c424036bb4d3a6164fa03b7214b29abf0a71 Mon Sep 17 00:00:00 2001 From: Justin Chung <124807742+jshigetomi@users.noreply.github.com> Date: Wed, 22 Apr 2026 15:32:55 -0500 Subject: [PATCH 111/127] [release/v7.6.1] Download PMC Packages through `TemplateContext` (#27331) Co-authored-by: Justin Chung <chungjustin@microsoft.com> --- .../PowerShell-Release-Azure-NonOfficial.yml | 8 ++- .../PowerShell-Release-Official-Azure.yml | 2 +- .pipelines/templates/release-prep-for-ev2.yml | 46 ++++++------- .pipelines/templates/release-publish-pmc.yml | 65 ++++++++++++------- 4 files changed, 70 insertions(+), 51 deletions(-) diff --git a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml index 4d406fbf9d5..b0bb4d79b39 100644 --- a/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml +++ b/.pipelines/NonOfficial/PowerShell-Release-Azure-NonOfficial.yml @@ -67,10 +67,16 @@ extends: exactToolVersion: 4.4.2 policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' - tsaOptionsFile: .config\tsaoptions.json + tsaOptionsFile: $(Build.SourcesDirectory)\.config\tsaoptions.json stages: - template: /.pipelines/templates/release-prep-for-ev2.yml@self parameters: skipPublish: ${{ parameters.skipPublish }} + # NonOfficial: run the publish stage to verify templateContext artifact download, + # but skip the actual Ev2 push to PMC. - template: /.pipelines/templates/release-publish-pmc.yml@self + parameters: + releaseEnvironment: Test + stagePrefix: Test + skipEv2Push: true diff --git a/.pipelines/PowerShell-Release-Official-Azure.yml b/.pipelines/PowerShell-Release-Official-Azure.yml index 24040a2463d..b5f57438925 100644 --- a/.pipelines/PowerShell-Release-Official-Azure.yml +++ b/.pipelines/PowerShell-Release-Official-Azure.yml @@ -67,7 +67,7 @@ extends: exactToolVersion: 4.4.2 policheck: break: true # always break the build on policheck issues. You can disable it by setting to 'false' - tsaOptionsFile: .config\tsaoptions.json + tsaOptionsFile: $(Build.SourcesDirectory)\.config\tsaoptions.json stages: - template: /.pipelines/templates/release-prep-for-ev2.yml@self parameters: diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index f73caa10450..3ad716a3af4 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -11,6 +11,20 @@ stages: displayName: 'Copy EV2 Files to Artifact' pool: type: linux + templateContext: + inputs: + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_deb + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_rpm + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_mariner_x64 + - input: pipelineArtifact + pipeline: PSPackagesOfficial + artifactName: drop_linux_package_mariner_arm64 variables: - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' @@ -24,6 +38,8 @@ stages: - group: 'packages.microsoft.com' - name: ob_sdl_credscan_suppressionsFile value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json + - name: ob_sdl_tsa_configFile + value: $(Build.SourcesDirectory)/PowerShell/.config/tsaoptions.json steps: - checkout: self ## the global setting on lfs didn't work lfs: false @@ -99,39 +115,17 @@ stages: env: ob_restore_phase: true - - download: PSPackagesOfficial - artifact: 'drop_linux_package_deb' - displayName: 'Download artifact containing .deb_amd64.deb file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - - download: PSPackagesOfficial - artifact: 'drop_linux_package_rpm' - displayName: 'Download artifact containing .rh.x64_86.rpm file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - - download: PSPackagesOfficial - artifact: 'drop_linux_package_mariner_x64' - displayName: 'Download artifact containing .cm.x86_64.rpm file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - - download: PSPackagesOfficial - artifact: 'drop_linux_package_mariner_arm64' - displayName: 'Download artifact containing .cm.aarch64.rpm file from PSPackagesOfficial triggering pipeline' - env: - ob_restore_phase: true - - pwsh: | Write-Verbose -Verbose "Copy ESRP signed .deb and .rpm packages" - $downloadedPipelineFolder = Join-Path '$(Pipeline.Workspace)' -ChildPath 'PSPackagesOfficial' + # templateContext.inputs places the PSPackagesOfficial pipelineArtifact files + # directly under $(Pipeline.Workspace), not in per-artifact subfolders. + $downloadedPipelineFolder = '$(Pipeline.Workspace)' $srcFilesFolder = Join-Path -Path '$(Pipeline.Workspace)' -ChildPath 'SourceFiles' New-Item -Path $srcFilesFolder -ItemType Directory $packagesFolder = Join-Path -Path $srcFilesFolder -ChildPath 'packages' New-Item -Path $packagesFolder -ItemType Directory - $packageFiles = Get-ChildItem -Path $downloadedPipelineFolder -Recurse -Directory -Filter "drop_*" | Get-ChildItem -File -Include *.deb, *.rpm + $packageFiles = Get-ChildItem -Path $downloadedPipelineFolder -File | Where-Object { $_.Extension -in '.deb', '.rpm' } foreach ($file in $packageFiles) { Write-Verbose -Verbose "copying file: $($file.FullName)" diff --git a/.pipelines/templates/release-publish-pmc.yml b/.pipelines/templates/release-publish-pmc.yml index d5454845211..dc7fc8534e3 100644 --- a/.pipelines/templates/release-publish-pmc.yml +++ b/.pipelines/templates/release-publish-pmc.yml @@ -1,37 +1,56 @@ +parameters: +- name: releaseEnvironment + type: string + default: Production + values: + - Production + - PPE + - Test +- name: approvalServiceEnvironment + type: string + default: Production + values: + - Production + - PPE + - Test +# OneBranch requires the stage name to be prefixed with the release environment. +# Official uses 'Prod' for Production; NonProd validators require '<env>' (e.g. 'Test', 'PPE'). +- name: stagePrefix + type: string + default: Prod +# When true, the Ev2 push step is skipped. Useful for NonOfficial dry-runs that +# only want to validate artifact download via templateContext.inputs. +- name: skipEv2Push + type: boolean + default: false + stages: -- stage: 'Prod_Release' +- stage: ${{ parameters.stagePrefix }}_Release displayName: 'Deploy packages to PMC with EV2' dependsOn: - PrepForEV2 variables: - name: ob_release_environment - value: "Production" + value: ${{ parameters.releaseEnvironment }} - name: repoRoot value: $(Build.SourcesDirectory) jobs: - - job: Prod_ReleaseJob + - job: ${{ parameters.stagePrefix }}_ReleaseJob displayName: Publish to PMC pool: type: release - - steps: - - task: DownloadPipelineArtifact@2 + templateContext: inputs: - targetPath: '$(Pipeline.Workspace)' - artifact: drop_PrepForEV2_CopyEv2FilesToArtifact - displayName: 'Download drop_PrepForEV2_CopyEv2FilesToArtifact artifact that has all files needed' + - input: pipelineArtifact + artifactName: drop_PrepForEV2_CopyEv2FilesToArtifact - - task: DownloadPipelineArtifact@2 - inputs: - buildType: 'current' - targetPath: '$(Pipeline.Workspace)' - displayName: 'Download to get EV2 Files' - - - task: vsrm-ev2.vss-services-ev2.adm-release-task.ExpressV2Internal@1 - displayName: 'Ev2: Push to PMC' - inputs: - UseServerMonitorTask: true - EndpointProviderType: ApprovalService - ApprovalServiceEnvironment: Production - ServiceRootPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEV2FilesToArtifact/EV2Specs/ServiceGroupRoot' - RolloutSpecPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEV2FilesToArtifact/EV2Specs/ServiceGroupRoot/RolloutSpec.json' + steps: + - ${{ if not(parameters.skipEv2Push) }}: + - task: vsrm-ev2.vss-services-ev2.adm-release-task.ExpressV2Internal@1 + displayName: 'Ev2: Push to PMC' + inputs: + UseServerMonitorTask: true + EndpointProviderType: ApprovalService + ApprovalServiceEnvironment: ${{ parameters.approvalServiceEnvironment }} + ServiceRootPath: '$(Pipeline.Workspace)/EV2Specs/ServiceGroupRoot' + RolloutSpecPath: '$(Pipeline.Workspace)/EV2Specs/ServiceGroupRoot/RolloutSpec.json' From eafd0921ed34aec45bf0ec03122f52d6824e30ab Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 14:47:02 -0700 Subject: [PATCH 112/127] [release/v7.6.2] Add `appLicensing` capability to Appx manifest (#27437) --- assets/AppxManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/AppxManifest.xml b/assets/AppxManifest.xml index 50a8c7af45d..dfcd95935d9 100644 --- a/assets/AppxManifest.xml +++ b/assets/AppxManifest.xml @@ -43,6 +43,7 @@ <Capabilities> <Capability Name="internetClient" /> + <rescap:Capability Name="appLicensing" /> <rescap:Capability Name="runFullTrust" /> <rescap:Capability Name="unvirtualizedResources" /> <rescap:Capability Name="packageManagement" /> From cd8c725645621457f18532db8a7d1a6d9bb29b92 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 14:52:57 -0700 Subject: [PATCH 113/127] [release/v7.6.2] Externalize `findMissingNotices` target framework selection with ordered Windows fallback (#27424) --- tools/findMissingNotices.ps1 | 113 ++++++++++++++++++++++---- tools/findMissingNotices.targets.json | 5 ++ 2 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 tools/findMissingNotices.targets.json diff --git a/tools/findMissingNotices.ps1 b/tools/findMissingNotices.ps1 index 456b77df0ba..5ed931c5caa 100644 --- a/tools/findMissingNotices.ps1 +++ b/tools/findMissingNotices.ps1 @@ -16,6 +16,45 @@ Import-Module "$PSScriptRoot\..\.github\workflows\GHWorkflowHelper" -Force . "$PSScriptRoot\..\tools\buildCommon\startNativeExecution.ps1" . "$PSScriptRoot\clearlyDefined\Find-LastHarvestedVersion.ps1" +$targetsConfigPath = Join-Path -Path $PSScriptRoot -ChildPath 'findMissingNotices.targets.json' +if (-not (Test-Path -LiteralPath $targetsConfigPath)) { + throw "Missing target framework config file '$targetsConfigPath'. Add '/tools/findMissingNotices.targets.json' with 'dotnetTargetName' and 'windowsTargetNames' entries." +} + +try { + $targetsConfig = Get-Content -LiteralPath $targetsConfigPath -Raw -ErrorAction Stop | ConvertFrom-Json -AsHashtable -ErrorAction Stop +} catch { + throw "Failed to load target framework config from '$targetsConfigPath'. Ensure the file contains valid JSON. Error: $($_.Exception.Message)" +} + +if ($targetsConfig -isnot [hashtable]) { + throw "Invalid target framework config '$targetsConfigPath': expected a JSON object with 'dotnetTargetName' and 'windowsTargetNames'." +} + +if (-not $targetsConfig.ContainsKey('dotnetTargetName') -or [string]::IsNullOrWhiteSpace($targetsConfig['dotnetTargetName'])) { + throw "Invalid target framework config '$targetsConfigPath': 'dotnetTargetName' must be a non-empty string." +} + +if (-not $targetsConfig.ContainsKey('windowsTargetNames')) { + throw "Invalid target framework config '$targetsConfigPath': 'windowsTargetNames' must be present and must be an array." +} + +if ($null -eq $targetsConfig['windowsTargetNames'] -or $targetsConfig['windowsTargetNames'] -isnot [array]) { + throw "Invalid target framework config '$targetsConfigPath': 'windowsTargetNames' must be an array (empty array is allowed)." +} + +$script:dotnetTargetName = [string]$targetsConfig['dotnetTargetName'] +$script:windowsTargetNames = @() +foreach ($windowsTargetName in $targetsConfig['windowsTargetNames']) { + if ($windowsTargetName -isnot [string] -or [string]::IsNullOrWhiteSpace($windowsTargetName)) { + throw "Invalid target framework config '$targetsConfigPath': every entry in 'windowsTargetNames' must be a non-empty string." + } + + $script:windowsTargetNames += $windowsTargetName +} + +# Empty windowsTargetNames is valid and means "use base target fallback only". + $packageSourceName = 'findMissingNoticesNugetOrg' if (!(Get-PackageSource -Name $packageSourceName -ErrorAction SilentlyContinue)) { $null = Register-PackageSource -Name $packageSourceName -Location https://www.nuget.org/api/v2 -ProviderName NuGet @@ -195,8 +234,7 @@ function Get-CGRegistrations { $registrationChanged = $false - $dotnetTargetName = 'net10.0' - $dotnetTargetNameWin7 = 'net10.0-windows8.0' + $baseTargetName = $script:dotnetTargetName $unixProjectName = 'powershell-unix' $windowsProjectName = 'powershell-win-core' $actualRuntime = $Runtime @@ -204,35 +242,30 @@ function Get-CGRegistrations { switch -regex ($Runtime) { "alpine-.*" { $folder = $unixProjectName - $target = "$dotnetTargetName|$Runtime" - $neutralTarget = "$dotnetTargetName" + $target = "$baseTargetName|$Runtime" + $neutralTarget = "$baseTargetName" } "linux-.*" { $folder = $unixProjectName - $target = "$dotnetTargetName|$Runtime" - $neutralTarget = "$dotnetTargetName" + $target = "$baseTargetName|$Runtime" + $neutralTarget = "$baseTargetName" } "osx-.*" { $folder = $unixProjectName - $target = "$dotnetTargetName|$Runtime" - $neutralTarget = "$dotnetTargetName" - } - "win-x*" { - $sdkToUse = $winDesktopSdk - $folder = $windowsProjectName - $target = "$dotnetTargetNameWin7|$Runtime" - $neutralTarget = "$dotnetTargetNameWin7" + $target = "$baseTargetName|$Runtime" + $neutralTarget = "$baseTargetName" } "win-.*" { + $sdkToUse = $winDesktopSdk $folder = $windowsProjectName - $target = "$dotnetTargetNameWin7|$Runtime" - $neutralTarget = "$dotnetTargetNameWin7" + $target = "$baseTargetName|$actualRuntime" + $neutralTarget = "$baseTargetName" } "modules" { $folder = "modules" $actualRuntime = 'linux-x64' - $target = "$dotnetTargetName|$actualRuntime" - $neutralTarget = "$dotnetTargetName" + $target = "$baseTargetName|$actualRuntime" + $neutralTarget = "$baseTargetName" } Default { throw "Invalid runtime name: $Runtime" @@ -247,6 +280,50 @@ function Get-CGRegistrations { dotnet restore --runtime $actualRuntime "/property:SDKToUse=$sdkToUse" } $null = New-PADrive -Path $PSScriptRoot\..\src\$folder\obj\project.assets.json -Name $folder + + if ($Runtime -like "win-*") { + # Windows target selection is optional and ordered: + # 1. Try full Windows TFMs from config in order. + # 2. Fall back to the base non-Windows TFM if present. + try { + $availableTargets = @(Get-ChildItem -Path "${folder}:/targets" -ErrorAction Stop | Select-Object -ExpandProperty Name) + } catch { + throw "Unable to enumerate available targets for runtime '$Runtime' in '$folder'. Ensure dotnet restore succeeded and project.assets.json contains target data. Error: $($_.Exception.Message)" + } + + $selectedTargetName = $null + + foreach ($windowsTargetName in $script:windowsTargetNames) { + if ($windowsTargetName -in $availableTargets) { + $selectedTargetName = $windowsTargetName + break + } + } + + if (-not $selectedTargetName -and $baseTargetName -in $availableTargets) { + Write-Verbose "No configured windows target matched for '$Runtime'. Falling back to base target '$baseTargetName'." -Verbose + $selectedTargetName = $baseTargetName + } + + if (-not $selectedTargetName) { + Write-Verbose "Available targets for '$folder': $($availableTargets -join ', ')" -Verbose + if ($script:windowsTargetNames.Count -eq 0) { + throw "Unable to find a target for '$Runtime'. Tried fallback base target '$baseTargetName' (no windowsTargetNames configured). Ensure project.assets.json contains this target or update dotnetTargetName in '$targetsConfigPath'." + } + + throw "Unable to find a target for '$Runtime'. Tried configured windowsTargetNames '$($script:windowsTargetNames -join "', '")' and fallback base target '$baseTargetName'. Update '$targetsConfigPath' with a valid windows target from the available list." + } + + $target = "$selectedTargetName|$actualRuntime" + $neutralTarget = $selectedTargetName + } + + # Defensive check: non-Windows paths set targets in the switch block, + # Windows path may override them after inspecting available assets targets. + if (-not $target -or -not $neutralTarget) { + throw "Unable to determine restore targets for runtime '$Runtime'." + } + try { $targets = Get-ChildItem -Path "${folder}:/targets/$target" -ErrorAction Stop | Where-Object { $_.Type -eq 'package' } | select-object -ExpandProperty name $targets += Get-ChildItem -Path "${folder}:/targets/$neutralTarget" -ErrorAction Stop | Where-Object { $_.Type -eq 'project' } | select-object -ExpandProperty name diff --git a/tools/findMissingNotices.targets.json b/tools/findMissingNotices.targets.json new file mode 100644 index 00000000000..9e5ced685c2 --- /dev/null +++ b/tools/findMissingNotices.targets.json @@ -0,0 +1,5 @@ +{ + "dotnetTargetName": "net10.0", + "windowsTargetNames": [ + ] +} From 4aab6230a38af9c4173e03c85f1d3e34b0865e37 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 14:56:49 -0700 Subject: [PATCH 114/127] [release/v7.6.2] Add macOS binary code signing and package notarization (#27434) --- .pipelines/templates/mac.yml | 8 ++++++++ assets/macos-entitlements.plist | 14 ++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 assets/macos-entitlements.plist diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index 1699207c657..cb82a7bf4c0 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -69,6 +69,14 @@ jobs: $psOptPath = "$(OB_OUTPUTDIRECTORY)/psoptions.json" Save-PSOptions -PSOptionsPath $psOptPath + $entitlements = "$(PowerShellRoot)/assets/macos-entitlements.plist" + $pwshBin = "$(OB_OUTPUTDIRECTORY)/pwsh" + Write-Verbose -Verbose "Applying entitlements to $pwshBin" + codesign --sign - --force --options runtime --entitlements $entitlements $pwshBin + if ($LASTEXITCODE -ne 0) { + throw "codesign failed with exit code $LASTEXITCODE" + } + # Since we are using custom pool for macOS, we need to use artifact.upload to publish the artifacts Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName]$(OB_OUTPUTDIRECTORY)" diff --git a/assets/macos-entitlements.plist b/assets/macos-entitlements.plist new file mode 100644 index 00000000000..9d534f4f4bf --- /dev/null +++ b/assets/macos-entitlements.plist @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.security.cs.allow-jit</key> + <true/> + <key>com.apple.security.cs.allow-unsigned-executable-memory</key> + <true/> + <key>com.apple.security.cs.allow-dyld-environment-variables</key> + <true/> + <key>com.apple.security.cs.disable-library-validation</key> + <true/> +</dict> +</plist> From 901bf012d4f7b6ca4fe439bdaa646d76e8849d57 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 14:57:26 -0700 Subject: [PATCH 115/127] [release/v7.6.2] Create PowerShell package for arm debian distribution (#27433) --- .pipelines/templates/linux-package-build.yml | 1 + .../release-validate-packagenames.yml | 2 +- .../stages/PowerShell-Packages-Stages.yml | 7 ++++ .../linux/package-validation.tests.ps1 | 33 ++++++++++--------- tools/packaging/packaging.psm1 | 24 ++++++++++++-- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index bb7ed723f42..1487455107e 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -124,6 +124,7 @@ jobs: 'tar' { 'Signed-linux-x64', 'powershell*.tar.gz' } 'tar-alpine-fxdependent' { 'Signed-fxdependent-noopt-linux-musl-x64', 'powershell*.tar.gz' } 'deb' { 'Signed-linux-x64', 'powershell*.deb' } + 'deb-arm64' { 'Signed-linux-arm64', 'powershell*.deb' } 'rpm-fxdependent' { 'Signed-fxdependent-linux-x64', 'powershell*.rpm' } 'rpm-fxdependent-arm64' { 'Signed-fxdependent-linux-arm64', 'powershell*.rpm' } 'rpm' { 'Signed-linux-x64', 'powershell*.rpm' } diff --git a/.pipelines/templates/release-validate-packagenames.yml b/.pipelines/templates/release-validate-packagenames.yml index 6344418cd8f..5bce4361669 100644 --- a/.pipelines/templates/release-validate-packagenames.yml +++ b/.pipelines/templates/release-validate-packagenames.yml @@ -109,7 +109,7 @@ jobs: - pwsh: | $message = @() Get-ChildItem $(System.ArtifactsDirectory)\* -recurse -filter *.deb | ForEach-Object { - if($_.Name -notmatch 'powershell(-preview|-lts)?_\d+\.\d+\.\d+([\-~][a-z]*.\d+)?-\d\.deb_amd64\.deb') + if($_.Name -notmatch 'powershell(-preview|-lts)?_\d+\.\d+\.\d+([\-~][a-z]*.\d+)?-\d\.deb_(amd64|arm64)\.deb') { $messageInstance = "$($_.Name) is not a valid package name" $message += $messageInstance diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml index b1efb2a8097..285a9035d0a 100644 --- a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -87,6 +87,13 @@ stages: packageType: deb jobName: deb + - template: /.pipelines/templates/linux-package-build.yml@self + parameters: + unsignedDrop: 'drop_linux_build_linux_arm64' + signedDrop: 'drop_linux_sign_linux_arm64' + packageType: deb-arm64 + jobName: deb_arm64 + - template: /.pipelines/templates/linux-package-build.yml@self parameters: unsignedDrop: 'drop_linux_build_linux_fxd_x64_mariner' diff --git a/test/packaging/linux/package-validation.tests.ps1 b/test/packaging/linux/package-validation.tests.ps1 index 594a729fa77..3b961120f2f 100644 --- a/test/packaging/linux/package-validation.tests.ps1 +++ b/test/packaging/linux/package-validation.tests.ps1 @@ -9,20 +9,20 @@ Describe "Linux Package Name Validation" { } else { $env:SYSTEM_ARTIFACTSDIRECTORY } - + if (-not $artifactsDir) { throw "Artifacts directory not found. GITHUB_WORKSPACE or SYSTEM_ARTIFACTSDIRECTORY must be set." } - + Write-Verbose "Artifacts directory: $artifactsDir" -Verbose } - + Context "RPM Package Names" { It "Should have valid RPM package names" { $rpmPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.rpm -ErrorAction SilentlyContinue - + $rpmPackages.Count | Should -BeGreaterThan 0 -Because "At least one RPM package should exist in the artifacts directory" - + $invalidPackages = @() # Regex pattern for valid RPM package names. # Breakdown: @@ -42,25 +42,26 @@ Describe "Linux Package Name Validation" { Write-Warning "$($package.Name) is not a valid RPM package name" } } - + if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } } } - + Context "DEB Package Names" { It "Should have valid DEB package names" { $debPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.deb -ErrorAction SilentlyContinue - + $debPackages.Count | Should -BeGreaterThan 0 -Because "At least one DEB package should exist in the artifacts directory" - + $invalidPackages = @() # Regex pattern for valid DEB package names. # Valid examples: # - powershell-preview_7.6.0-preview.6-1.deb_amd64.deb # - powershell-lts_7.4.13-1.deb_amd64.deb # - powershell_7.4.13-1.deb_amd64.deb + # - powershell_7.6.0-1.deb_arm64.deb # Breakdown: # ^powershell : Starts with 'powershell' # (-preview|-lts)? : Optionally '-preview' or '-lts' @@ -78,19 +79,19 @@ Describe "Linux Package Name Validation" { Write-Warning "$($package.Name) is not a valid DEB package name" } } - + if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } } } - + Context "Tar.Gz Package Names" { It "Should have valid tar.gz package names" { $tarPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.tar.gz -ErrorAction SilentlyContinue - + $tarPackages.Count | Should -BeGreaterThan 0 -Because "At least one tar.gz package should exist in the artifacts directory" - + $invalidPackages = @() foreach ($package in $tarPackages) { # Pattern matches: powershell-7.6.0-preview.6-linux-x64.tar.gz or powershell-7.6.0-linux-x64.tar.gz @@ -100,17 +101,17 @@ Describe "Linux Package Name Validation" { Write-Warning "$($package.Name) is not a valid tar.gz package name" } } - + if ($invalidPackages.Count -gt 0) { throw ($invalidPackages | Out-String) } } } - + Context "Package Existence" { It "Should find at least one package in artifacts directory" { $allPackages = Get-ChildItem -Path $artifactsDir -Recurse -Include *.rpm, *.tar.gz, *.deb -ErrorAction SilentlyContinue - + $allPackages.Count | Should -BeGreaterThan 0 -Because "At least one package should exist in the artifacts directory" } } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index b0131d39ebf..641299df382 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -52,7 +52,7 @@ function Start-PSPackage { [string]$Name = "powershell", # Ubuntu, CentOS, Fedora, macOS, and Windows packages are supported - [ValidateSet("msix", "deb", "osxpkg", "rpm", "rpm-fxdependent", "rpm-fxdependent-arm64", "msi", "zip", "zip-pdb", "tar", "tar-arm", "tar-arm64", "tar-alpine", "fxdependent", "fxdependent-win-desktop", "min-size", "tar-alpine-fxdependent")] + [ValidateSet("msix", "deb", "deb-arm64", "osxpkg", "rpm", "rpm-fxdependent", "rpm-fxdependent-arm64", "msi", "zip", "zip-pdb", "tar", "tar-arm", "tar-arm64", "tar-alpine", "fxdependent", "fxdependent-win-desktop", "min-size", "tar-alpine-fxdependent")] [string[]]$Type, # Generate windows downlevel package @@ -641,6 +641,24 @@ function Start-PSPackage { } } } + 'deb-arm64' { + $Arguments = @{ + Type = 'deb' + PackageSourcePath = $Source + Name = $Name + Version = $Version + Force = $Force + NoSudo = $NoSudo + LTS = $LTS + HostArchitecture = "arm64" + } + foreach ($Distro in $Script:DebianDistributions) { + $Arguments["Distribution"] = $Distro + if ($PSCmdlet.ShouldProcess("Create DEB Package for $Distro")) { + New-UnixPackage @Arguments + } + } + } 'rpm' { $Arguments = @{ Type = 'rpm' @@ -1060,7 +1078,7 @@ function New-UnixPackage { # This is a string because strings are appended to it [string]$Iteration = "1", - # Host architecture values allowed for deb type packages: amd64 + # Host architecture values allowed for deb type packages: amd64, arm64 # Host architecture values allowed for rpm type packages include: x86_64, aarch64, native, all, noarch, any # Host architecture values allowed for osxpkg type packages include: x86_64, arm64 [string] @@ -5806,4 +5824,4 @@ function Test-IsProductFile { } return $false -} +} \ No newline at end of file From 783caca811dcca6c9e622ff8fbfb404f58de3d50 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 14:58:02 -0700 Subject: [PATCH 116/127] [release/v7.6.2] Fix checks for local user config file paths (#27432) --- .../host/msh/ConsoleHost.cs | 13 +- .../host/msh/UpdatesNotification.cs | 4 +- .../CoreCLR/CorePsPlatform.cs | 46 +- .../engine/CommandDiscovery.cs | 10 +- .../engine/Modules/AnalysisCache.cs | 7 +- .../engine/PSConfiguration.cs | 10 +- .../engine/hostifaces/HostUtilities.cs | 9 +- .../engine/hostifaces/MshHostUserInterface.cs | 5 + .../utils/Telemetry.cs | 927 +++++++++--------- 9 files changed, 552 insertions(+), 479 deletions(-) diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index a84d18e6684..857c8f6345d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -148,13 +148,16 @@ internal static int Start( try { string profileDir = Platform.CacheDirectory; -#if !UNIX - if (!Directory.Exists(profileDir)) + if (!string.IsNullOrEmpty(profileDir)) { - Directory.CreateDirectory(profileDir); - } +#if !UNIX + if (!Directory.Exists(profileDir)) + { + Directory.CreateDirectory(profileDir); + } #endif - ProfileOptimization.SetProfileRoot(profileDir); + ProfileOptimization.SetProfileRoot(profileDir); + } } catch { diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs index d0b1ed4572c..eb4557c04d2 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs @@ -60,12 +60,12 @@ internal static class UpdatesNotification static UpdatesNotification() { s_notificationType = GetNotificationType(); - CanNotifyUpdates = s_notificationType != NotificationType.Off; + CanNotifyUpdates = s_notificationType != NotificationType.Off + && Platform.TryDeriveFromCache(PSVersionInfo.GitCommitId, out s_cacheDirectory); if (CanNotifyUpdates) { s_enumOptions = new EnumerationOptions(); - s_cacheDirectory = Path.Combine(Platform.CacheDirectory, PSVersionInfo.GitCommitId); // Build the template/pattern strings for the configured notification type. string typeNum = ((int)s_notificationType).ToString(); diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index dc5db5f2c48..530493f320a 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -167,8 +167,13 @@ public static bool IsStaSupported internal static readonly string ConfigDirectory = Platform.SelectProductNameForDirectory(Platform.XDG_Type.CONFIG); #else // Gets the location for cache and config folders. - internal static readonly string CacheDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\PowerShell"; - internal static readonly string ConfigDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\PowerShell"; + internal static readonly string CacheDirectory = SafeDeriveFromSpecialFolder( + Environment.SpecialFolder.LocalApplicationData, + @"Microsoft\PowerShell"); + + internal static readonly string ConfigDirectory = SafeDeriveFromSpecialFolder( + Environment.SpecialFolder.Personal, + @"PowerShell"); private static readonly Lazy<bool> _isStaSupported = new Lazy<bool>(() => { @@ -189,6 +194,30 @@ public static bool IsStaSupported private static bool? _isWindowsDesktop = null; #endif + internal static bool TryDeriveFromCache(string path1, out string result) + { + if (CacheDirectory is null or []) + { + result = null; + return false; + } + + result = Path.Combine(CacheDirectory, path1); + return true; + } + + internal static bool TryDeriveFromCache(string path1, string path2, out string result) + { + if (CacheDirectory is null or []) + { + result = null; + return false; + } + + result = Path.Combine(CacheDirectory, path1, path2); + return true; + } + // format files internal static readonly string[] FormatFileNames = new string[] { @@ -218,6 +247,17 @@ internal static class CommonEnvVariableNames #endif } + private static string SafeDeriveFromSpecialFolder(Environment.SpecialFolder specialFolder, string subPath) + { + string basePath = Environment.GetFolderPath(specialFolder, Environment.SpecialFolderOption.DoNotVerify); + if (string.IsNullOrWhiteSpace(basePath)) + { + return string.Empty; + } + + return Path.Join(basePath, subPath); + } + #if UNIX private static string s_tempHome = null; @@ -360,7 +400,7 @@ internal static string GetFolderPath(Environment.SpecialFolder folder) _ => throw new NotSupportedException() }; #else - return Environment.GetFolderPath(folder); + return Environment.GetFolderPath(folder, Environment.SpecialFolderOption.DoNotVerify); #endif } diff --git a/src/System.Management.Automation/engine/CommandDiscovery.cs b/src/System.Management.Automation/engine/CommandDiscovery.cs index cf4f561c983..9ca87f4c834 100644 --- a/src/System.Management.Automation/engine/CommandDiscovery.cs +++ b/src/System.Management.Automation/engine/CommandDiscovery.cs @@ -1231,11 +1231,17 @@ internal LookupPathCollection GetLookupDirectoryPaths() string tempDir = directory.TrimStart(); if (tempDir.EqualsOrdinalIgnoreCase("~")) { - tempDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + tempDir = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile, + Environment.SpecialFolderOption.DoNotVerify); } else if (tempDir.StartsWith("~" + Path.DirectorySeparatorChar)) { - tempDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + Path.DirectorySeparatorChar + tempDir.Substring(2); + tempDir = Environment.GetFolderPath( + Environment.SpecialFolder.UserProfile, + Environment.SpecialFolderOption.DoNotVerify) + + Path.DirectorySeparatorChar + + tempDir.Substring(2); } _cachedPath.Add(tempDir); diff --git a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs index 44dc9f1b610..962022e1c54 100644 --- a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs +++ b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs @@ -664,6 +664,11 @@ private static byte[] GetHeader() public void QueueSerialization() { + if (string.IsNullOrEmpty(s_cacheStoreLocation)) + { + return; + } + // We expect many modules to rapidly call for serialization. // Instead of doing it right away, we'll queue a task that starts writing // after it seems like we've stopped adding stuff to write out. This is @@ -1121,7 +1126,7 @@ static AnalysisCacheData() cacheFileName = string.Create(CultureInfo.InvariantCulture, $"{cacheFileName}-{hashString}"); } - s_cacheStoreLocation = Path.Combine(Platform.CacheDirectory, cacheFileName); + Platform.TryDeriveFromCache(cacheFileName, out s_cacheStoreLocation); } } diff --git a/src/System.Management.Automation/engine/PSConfiguration.cs b/src/System.Management.Automation/engine/PSConfiguration.cs index e321423f768..419a4cae95f 100644 --- a/src/System.Management.Automation/engine/PSConfiguration.cs +++ b/src/System.Management.Automation/engine/PSConfiguration.cs @@ -89,7 +89,10 @@ private PowerShellConfig() // Note: This directory may or may not exist depending upon the execution scenario. // Writes will attempt to create the directory if it does not already exist. perUserConfigDirectory = Platform.ConfigDirectory; - perUserConfigFile = Path.Combine(perUserConfigDirectory, ConfigFileName); + if (!string.IsNullOrEmpty(perUserConfigDirectory)) + { + perUserConfigFile = Path.Combine(perUserConfigDirectory, ConfigFileName); + } emptyConfig = new JObject(); configRoots = new JObject[2]; @@ -387,6 +390,11 @@ internal PSKeyword GetLogKeywords() private T ReadValueFromFile<T>(ConfigScope scope, string key, T defaultValue = default) { string fileName = GetConfigFilePath(scope); + if (string.IsNullOrEmpty(fileName)) + { + return defaultValue; + } + JObject configData = configRoots[(int)scope]; if (configData == null) diff --git a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs index f06399e09d2..8e5d30be71f 100644 --- a/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs +++ b/src/System.Management.Automation/engine/hostifaces/HostUtilities.cs @@ -148,10 +148,11 @@ internal static string GetFullProfileFileName(string shellId, bool forCurrentUse else { basePath = GetAllUsersFolderPath(shellId); - if (string.IsNullOrEmpty(basePath)) - { - return string.Empty; - } + } + + if (string.IsNullOrEmpty(basePath)) + { + return string.Empty; } string profileName = useTestProfile ? "profile_test.ps1" : "profile.ps1"; diff --git a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs index 29fc5fa1f7f..5f51ba15751 100644 --- a/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs +++ b/src/System.Management.Automation/engine/hostifaces/MshHostUserInterface.cs @@ -1156,6 +1156,11 @@ internal static string GetTranscriptPath(string baseDirectory, bool includeDate) } } + if (string.IsNullOrEmpty(baseDirectory)) + { + return string.Empty; + } + if (includeDate) { baseDirectory = Path.Combine(baseDirectory, DateTime.Now.ToString("yyyyMMdd", CultureInfo.InvariantCulture)); diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index 8ab34950f60..9a67f4bb6ed 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -163,6 +163,8 @@ public static class ApplicationInsightsTelemetry private static readonly HashSet<string> s_knownSubsystemNames; + private static readonly string s_uuidPath; + /// <summary>Gets a value indicating whether telemetry can be sent.</summary> public static bool CanSendTelemetry { get; private set; } @@ -176,470 +178,474 @@ public static class ApplicationInsightsTelemetry static ApplicationInsightsTelemetry() { // If we can't send telemetry, there's no reason to do any of this - CanSendTelemetry = !Utils.GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false); - if (CanSendTelemetry) + CanSendTelemetry = !Utils.GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false) + && Platform.TryDeriveFromCache("telemetry.uuid", out s_uuidPath); + + if (!CanSendTelemetry) { - s_sessionId = Guid.NewGuid().ToString(); - TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault(); - configuration.ConnectionString = "InstrumentationKey=" + _psCoreTelemetryKey; + return; + } - // Set this to true to reduce latency during development - configuration.TelemetryChannel.DeveloperMode = false; + s_sessionId = Guid.NewGuid().ToString(); + TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault(); + configuration.ConnectionString = "InstrumentationKey=" + _psCoreTelemetryKey; - // Be sure to obscure any information about the client node name. - configuration.TelemetryInitializers.Add(new NameObscurerTelemetryInitializer()); + // Set this to true to reduce latency during development + configuration.TelemetryChannel.DeveloperMode = false; - s_telemetryClient = new TelemetryClient(configuration); + // Be sure to obscure any information about the client node name. + configuration.TelemetryInitializers.Add(new NameObscurerTelemetryInitializer()); - // use a hashset when looking for module names, it should be quicker than a string comparison - s_knownModules = new HashSet<string>(StringComparer.OrdinalIgnoreCase) - { - "AADRM", - "activedirectory", - "adcsadministration", - "adcsdeployment", - "addsadministration", - "addsdeployment", - "adfs", - "adrms", - "adrmsadmin", - "agpm", - "AIShell", - "appbackgroundtask", - "applocker", - "appv", - "appvclient", - "appvsequencer", - "appvserver", - "appx", - "assignedaccess", - "Az", - "Az.Accounts", - "Az.Advisor", - "Az.Aks", - "Az.AlertsManagement", - "Az.AnalysisServices", - "Az.ApiManagement", - "Az.ApplicationInsights", - "Az.Attestation", - "Az.Automation", - "Az.Batch", - "Az.Billing", - "Az.Blueprint", - "Az.Cdn", - "Az.CognitiveServices", - "Az.Compute", - "Az.ContainerInstance", - "Az.ContainerRegistry", - "Az.DataBox", - "Az.DataFactory", - "Az.DataLakeAnalytics", - "Az.DataLakeStore", - "Az.DataMigration", - "Az.DataShare", - "Az.DeploymentManager", - "Az.DeviceProvisioningServices", - "Az.DevSpaces", - "Az.DevTestLabs", - "Az.Dns", - "Az.EventGrid", - "Az.EventHub", - "Az.FrontDoor", - "Az.GuestConfiguration", - "Az.HDInsight", - "Az.HealthcareApis", - "Az.IotCentral", - "Az.IotHub", - "Az.KeyVault", - "Az.Kusto", - "Az.LogicApp", - "Az.MachineLearning", - "Az.ManagedServiceIdentity", - "Az.ManagedServices", - "Az.ManagementPartner", - "Az.Maps", - "Az.MarketplaceOrdering", - "Az.Media", - "Az.MixedReality", - "Az.Monitor", - "Az.NetAppFiles", - "Az.Network", - "Az.NotificationHubs", - "Az.OperationalInsights", - "Az.Peering", - "Az.PolicyInsights", - "Az.PowerBIEmbedded", - "Az.PrivateDns", - "Az.RecoveryServices", - "Az.RedisCache", - "Az.Relay", - "Az.Reservations", - "Az.ResourceGraph", - "Az.Resources", - "Az.Search", - "Az.Security", - "Az.ServiceBus", - "Az.ServiceFabric", - "Az.SignalR", - "Az.Sql", - "Az.Storage", - "Az.StorageSync", - "Az.StorageTable", - "Az.StreamAnalytics", - "Az.Subscription", - "Az.Tools.Predictor", - "Az.TrafficManager", - "Az.Websites", - "Azs.Azurebridge.Admin", - "Azs.Backup.Admin", - "Azs.Commerce.Admin", - "Azs.Compute.Admin", - "Azs.Fabric.Admin", - "Azs.Gallery.Admin", - "Azs.Infrastructureinsights.Admin", - "Azs.Keyvault.Admin", - "Azs.Network.Admin", - "Azs.Storage.Admin", - "Azs.Subscriptions", - "Azs.Subscriptions.Admin", - "Azs.Update.Admin", - "AzStorageTable", - "Azure", - "Azure.AnalysisServices", - "Azure.Storage", - "AzureAD", - "AzureInformationProtection", - "AzureRM.Aks", - "AzureRM.AnalysisServices", - "AzureRM.ApiManagement", - "AzureRM.ApplicationInsights", - "AzureRM.Automation", - "AzureRM.Backup", - "AzureRM.Batch", - "AzureRM.Billing", - "AzureRM.Cdn", - "AzureRM.CognitiveServices", - "AzureRm.Compute", - "AzureRM.Compute.ManagedService", - "AzureRM.Consumption", - "AzureRM.ContainerInstance", - "AzureRM.ContainerRegistry", - "AzureRM.DataFactories", - "AzureRM.DataFactoryV2", - "AzureRM.DataLakeAnalytics", - "AzureRM.DataLakeStore", - "AzureRM.DataMigration", - "AzureRM.DeploymentManager", - "AzureRM.DeviceProvisioningServices", - "AzureRM.DevSpaces", - "AzureRM.DevTestLabs", - "AzureRm.Dns", - "AzureRM.EventGrid", - "AzureRM.EventHub", - "AzureRM.FrontDoor", - "AzureRM.HDInsight", - "AzureRm.Insights", - "AzureRM.IotCentral", - "AzureRM.IotHub", - "AzureRm.Keyvault", - "AzureRM.LocationBasedServices", - "AzureRM.LogicApp", - "AzureRM.MachineLearning", - "AzureRM.MachineLearningCompute", - "AzureRM.ManagedServiceIdentity", - "AzureRM.ManagementPartner", - "AzureRM.Maps", - "AzureRM.MarketplaceOrdering", - "AzureRM.Media", - "AzureRM.Network", - "AzureRM.NotificationHubs", - "AzureRM.OperationalInsights", - "AzureRM.PolicyInsights", - "AzureRM.PowerBIEmbedded", - "AzureRM.Profile", - "AzureRM.RecoveryServices", - "AzureRM.RecoveryServices.Backup", - "AzureRM.RecoveryServices.SiteRecovery", - "AzureRM.RedisCache", - "AzureRM.Relay", - "AzureRM.Reservations", - "AzureRM.ResourceGraph", - "AzureRM.Resources", - "AzureRM.Scheduler", - "AzureRM.Search", - "AzureRM.Security", - "AzureRM.ServerManagement", - "AzureRM.ServiceBus", - "AzureRM.ServiceFabric", - "AzureRM.SignalR", - "AzureRM.SiteRecovery", - "AzureRM.Sql", - "AzureRm.Storage", - "AzureRM.StorageSync", - "AzureRM.StreamAnalytics", - "AzureRM.Subscription", - "AzureRM.Subscription.Preview", - "AzureRM.Tags", - "AzureRM.TrafficManager", - "AzureRm.UsageAggregates", - "AzureRm.Websites", - "AzureRmStorageTable", - "bestpractices", - "bitlocker", - "bitstransfer", - "booteventcollector", - "branchcache", - "CimCmdlets", - "clusterawareupdating", - "CompatPowerShellGet", - "configci", - "ConfigurationManager", - "CompletionPredictor", - "DataProtectionManager", - "dcbqos", - "deduplication", - "defender", - "devicehealthattestation", - "dfsn", - "dfsr", - "dhcpserver", - "directaccessclient", - "directaccessclientcomponent", - "directaccessclientcomponents", - "dism", - "dnsclient", - "dnsserver", - "ElasticDatabaseJobs", - "EventTracingManagement", - "failoverclusters", - "fileserverresourcemanager", - "FIMAutomation", - "GPRegistryPolicy", - "grouppolicy", - "hardwarecertification", - "hcs", - "hgsattestation", - "hgsclient", - "hgsdiagnostics", - "hgskeyprotection", - "hgsserver", - "hnvdiagnostics", - "hostcomputeservice", - "hpc", - "HPC.ACM", - "HPC.ACM.API.PS", - "HPCPack2016", - "hyper-v", - "IISAdministration", - "international", - "ipamserver", - "iscsi", - "iscsitarget", - "ISE", - "kds", - "Microsoft.MBAM", - "Microsoft.MEDV", - "MgmtSvcAdmin", - "MgmtSvcConfig", - "MgmtSvcMySql", - "MgmtSvcSqlServer", - "Microsoft.AzureStack.ReadinessChecker", - "Microsoft.Crm.PowerShell", - "Microsoft.DiagnosticDataViewer", - "Microsoft.DirectoryServices.MetadirectoryServices.Config", - "Microsoft.Dynamics.Nav.Apps.Management", - "Microsoft.Dynamics.Nav.Apps.Tools", - "Microsoft.Dynamics.Nav.Ide", - "Microsoft.Dynamics.Nav.Management", - "Microsoft.Dynamics.Nav.Model.Tools", - "Microsoft.Dynamics.Nav.Model.Tools.Crm", - "Microsoft.EnterpriseManagement.Warehouse.Cmdlets", - "Microsoft.Medv.Administration.Commands.WorkspacePackager", - "Microsoft.PowerApps.Checker.PowerShell", - "Microsoft.PowerShell.Archive", - "Microsoft.PowerShell.ConsoleGuiTools", - "Microsoft.PowerShell.Core", - "Microsoft.PowerShell.Crescendo", - "Microsoft.PowerShell.Diagnostics", - "Microsoft.PowerShell.Host", - "Microsoft.PowerShell.LocalAccounts", - "Microsoft.PowerShell.Management", - "Microsoft.PowerShell.ODataUtils", - "Microsoft.PowerShell.Operation.Validation", - "Microsoft.PowerShell.PSAdapter", - "Microsoft.PowerShell.PSResourceGet", - "Microsoft.PowerShell.RemotingTools", - "Microsoft.PowerShell.SecretManagement", - "Microsoft.PowerShell.SecretStore", - "Microsoft.PowerShell.Security", - "Microsoft.PowerShell.TextUtility", - "Microsoft.PowerShell.Utility", - "Microsoft.SharePoint.Powershell", - "Microsoft.SystemCenter.ServiceManagementAutomation", - "Microsoft.Windows.ServerManager.Migration", - "Microsoft.WSMan.Management", - "Microsoft.Xrm.OnlineManagementAPI", - "Microsoft.Xrm.Tooling.CrmConnector.PowerShell", - "Microsoft.Xrm.Tooling.PackageDeployment", - "Microsoft.Xrm.Tooling.PackageDeployment.Powershell", - "Microsoft.Xrm.Tooling.Testing", - "MicrosoftPowerBIMgmt", - "MicrosoftPowerBIMgmt.Data", - "MicrosoftPowerBIMgmt.Profile", - "MicrosoftPowerBIMgmt.Reports", - "MicrosoftPowerBIMgmt.Workspaces", - "MicrosoftStaffHub", - "MicrosoftTeams", - "MIMPAM", - "mlSqlPs", - "MMAgent", - "MPIO", - "MsDtc", - "MSMQ", - "MSOnline", - "MSOnlineBackup", - "WmsCmdlets", - "WmsCmdlets3", - "NanoServerImageGenerator", - "NAVWebClientManagement", - "NetAdapter", - "NetConnection", - "NetEventPacketCapture", - "Netlbfo", - "Netldpagent", - "NetNat", - "Netqos", - "NetSecurity", - "NetSwitchtTeam", - "Nettcpip", - "Netwnv", - "NetworkConnectivity", - "NetworkConnectivityStatus", - "NetworkController", - "NetworkControllerDiagnostics", - "NetworkloadBalancingClusters", - "NetworkSwitchManager", - "NetworkTransition", - "NFS", - "NPS", - "OfficeWebapps", - "OperationsManager", - "PackageManagement", - "PartnerCenter", - "pcsvdevice", - "pef", - "Pester", - "pkiclient", - "platformidentifier", - "pnpdevice", - "PowerShellEditorServices", - "PowerShellGet", - "powershellwebaccess", - "printmanagement", - "ProcessMitigations", - "provisioning", - "PSDesiredStateConfiguration", - "PSDiagnostics", - "PSReadLine", - "PSScheduledJob", - "PSScriptAnalyzer", - "PSWorkflow", - "PSWorkflowUtility", - "RemoteAccess", - "RemoteDesktop", - "RemoteDesktopServices", - "ScheduledTasks", - "Secureboot", - "ServerCore", - "ServerManager", - "ServerManagerTasks", - "ServerMigrationcmdlets", - "ServiceFabric", - "Microsoft.Online.SharePoint.PowerShell", - "shieldedvmdatafile", - "shieldedvmprovisioning", - "shieldedvmtemplate", - "SkypeOnlineConnector", - "SkypeForBusinessHybridHealth", - "smbshare", - "smbwitness", - "smisconfig", - "softwareinventorylogging", - "SPFAdmin", - "Microsoft.SharePoint.MigrationTool.PowerShell", - "sqlps", - "SqlServer", - "StartLayout", - "StartScreen", - "Storage", - "StorageDsc", - "storageqos", - "Storagereplica", - "Storagespaces", - "Syncshare", - "System.Center.Service.Manager", - "TLS", - "TroubleshootingPack", - "TrustedPlatformModule", - "UEV", - "UpdateServices", - "UserAccessLogging", - "vamt", - "VirtualMachineManager", - "vpnclient", - "WasPSExt", - "WDAC", - "WDS", - "WebAdministration", - "WebAdministrationDsc", - "WebApplicationProxy", - "WebSites", - "Whea", - "WhiteboardAdmin", - "WindowsDefender", - "WindowsDefenderDsc", - "WindowsDeveloperLicense", - "WindowsDiagnosticData", - "WindowsErrorReporting", - "WindowServerRackup", - "WindowsSearch", - "WindowsServerBackup", - "WindowsUpdate", - "WinGetCommandNotFound", - "wsscmdlets", - "wsssetup", - "wsus", - "xActiveDirectory", - "xBitLocker", - "xDefender", - "xDhcpServer", - "xDismFeature", - "xDnsServer", - "xHyper-V", - "xHyper-VBackup", - "xPSDesiredStateConfiguration", - "xSmbShare", - "xSqlPs", - "xStorage", - "xWebAdministration", - "xWindowsUpdate", - }; - - // use a hashset when looking for module names, it should be quicker than a string comparison - s_knownModuleTags = new HashSet<string>(StringComparer.OrdinalIgnoreCase) - { - "CrescendoBuilt", - }; + s_telemetryClient = new TelemetryClient(configuration); - s_uniqueUserIdentifier = GetUniqueIdentifier().ToString(); - s_knownSubsystemNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) - { - "Completion", - "General Feedback", - "Windows Package Manager - WinGet", - "Az Predictor" - }; - } + // use a hashset when looking for module names, it should be quicker than a string comparison + s_knownModules = new HashSet<string>(StringComparer.OrdinalIgnoreCase) + { + "AADRM", + "activedirectory", + "adcsadministration", + "adcsdeployment", + "addsadministration", + "addsdeployment", + "adfs", + "adrms", + "adrmsadmin", + "agpm", + "AIShell", + "appbackgroundtask", + "applocker", + "appv", + "appvclient", + "appvsequencer", + "appvserver", + "appx", + "assignedaccess", + "Az", + "Az.Accounts", + "Az.Advisor", + "Az.Aks", + "Az.AlertsManagement", + "Az.AnalysisServices", + "Az.ApiManagement", + "Az.ApplicationInsights", + "Az.Attestation", + "Az.Automation", + "Az.Batch", + "Az.Billing", + "Az.Blueprint", + "Az.Cdn", + "Az.CognitiveServices", + "Az.Compute", + "Az.ContainerInstance", + "Az.ContainerRegistry", + "Az.DataBox", + "Az.DataFactory", + "Az.DataLakeAnalytics", + "Az.DataLakeStore", + "Az.DataMigration", + "Az.DataShare", + "Az.DeploymentManager", + "Az.DeviceProvisioningServices", + "Az.DevSpaces", + "Az.DevTestLabs", + "Az.Dns", + "Az.EventGrid", + "Az.EventHub", + "Az.FrontDoor", + "Az.GuestConfiguration", + "Az.HDInsight", + "Az.HealthcareApis", + "Az.IotCentral", + "Az.IotHub", + "Az.KeyVault", + "Az.Kusto", + "Az.LogicApp", + "Az.MachineLearning", + "Az.ManagedServiceIdentity", + "Az.ManagedServices", + "Az.ManagementPartner", + "Az.Maps", + "Az.MarketplaceOrdering", + "Az.Media", + "Az.MixedReality", + "Az.Monitor", + "Az.NetAppFiles", + "Az.Network", + "Az.NotificationHubs", + "Az.OperationalInsights", + "Az.Peering", + "Az.PolicyInsights", + "Az.PowerBIEmbedded", + "Az.PrivateDns", + "Az.RecoveryServices", + "Az.RedisCache", + "Az.Relay", + "Az.Reservations", + "Az.ResourceGraph", + "Az.Resources", + "Az.Search", + "Az.Security", + "Az.ServiceBus", + "Az.ServiceFabric", + "Az.SignalR", + "Az.Sql", + "Az.Storage", + "Az.StorageSync", + "Az.StorageTable", + "Az.StreamAnalytics", + "Az.Subscription", + "Az.Tools.Predictor", + "Az.TrafficManager", + "Az.Websites", + "Azs.Azurebridge.Admin", + "Azs.Backup.Admin", + "Azs.Commerce.Admin", + "Azs.Compute.Admin", + "Azs.Fabric.Admin", + "Azs.Gallery.Admin", + "Azs.Infrastructureinsights.Admin", + "Azs.Keyvault.Admin", + "Azs.Network.Admin", + "Azs.Storage.Admin", + "Azs.Subscriptions", + "Azs.Subscriptions.Admin", + "Azs.Update.Admin", + "AzStorageTable", + "Azure", + "Azure.AnalysisServices", + "Azure.Storage", + "AzureAD", + "AzureInformationProtection", + "AzureRM.Aks", + "AzureRM.AnalysisServices", + "AzureRM.ApiManagement", + "AzureRM.ApplicationInsights", + "AzureRM.Automation", + "AzureRM.Backup", + "AzureRM.Batch", + "AzureRM.Billing", + "AzureRM.Cdn", + "AzureRM.CognitiveServices", + "AzureRm.Compute", + "AzureRM.Compute.ManagedService", + "AzureRM.Consumption", + "AzureRM.ContainerInstance", + "AzureRM.ContainerRegistry", + "AzureRM.DataFactories", + "AzureRM.DataFactoryV2", + "AzureRM.DataLakeAnalytics", + "AzureRM.DataLakeStore", + "AzureRM.DataMigration", + "AzureRM.DeploymentManager", + "AzureRM.DeviceProvisioningServices", + "AzureRM.DevSpaces", + "AzureRM.DevTestLabs", + "AzureRm.Dns", + "AzureRM.EventGrid", + "AzureRM.EventHub", + "AzureRM.FrontDoor", + "AzureRM.HDInsight", + "AzureRm.Insights", + "AzureRM.IotCentral", + "AzureRM.IotHub", + "AzureRm.Keyvault", + "AzureRM.LocationBasedServices", + "AzureRM.LogicApp", + "AzureRM.MachineLearning", + "AzureRM.MachineLearningCompute", + "AzureRM.ManagedServiceIdentity", + "AzureRM.ManagementPartner", + "AzureRM.Maps", + "AzureRM.MarketplaceOrdering", + "AzureRM.Media", + "AzureRM.Network", + "AzureRM.NotificationHubs", + "AzureRM.OperationalInsights", + "AzureRM.PolicyInsights", + "AzureRM.PowerBIEmbedded", + "AzureRM.Profile", + "AzureRM.RecoveryServices", + "AzureRM.RecoveryServices.Backup", + "AzureRM.RecoveryServices.SiteRecovery", + "AzureRM.RedisCache", + "AzureRM.Relay", + "AzureRM.Reservations", + "AzureRM.ResourceGraph", + "AzureRM.Resources", + "AzureRM.Scheduler", + "AzureRM.Search", + "AzureRM.Security", + "AzureRM.ServerManagement", + "AzureRM.ServiceBus", + "AzureRM.ServiceFabric", + "AzureRM.SignalR", + "AzureRM.SiteRecovery", + "AzureRM.Sql", + "AzureRm.Storage", + "AzureRM.StorageSync", + "AzureRM.StreamAnalytics", + "AzureRM.Subscription", + "AzureRM.Subscription.Preview", + "AzureRM.Tags", + "AzureRM.TrafficManager", + "AzureRm.UsageAggregates", + "AzureRm.Websites", + "AzureRmStorageTable", + "bestpractices", + "bitlocker", + "bitstransfer", + "booteventcollector", + "branchcache", + "CimCmdlets", + "clusterawareupdating", + "CompatPowerShellGet", + "configci", + "ConfigurationManager", + "CompletionPredictor", + "DataProtectionManager", + "dcbqos", + "deduplication", + "defender", + "devicehealthattestation", + "dfsn", + "dfsr", + "dhcpserver", + "directaccessclient", + "directaccessclientcomponent", + "directaccessclientcomponents", + "dism", + "dnsclient", + "dnsserver", + "ElasticDatabaseJobs", + "EventTracingManagement", + "failoverclusters", + "fileserverresourcemanager", + "FIMAutomation", + "GPRegistryPolicy", + "grouppolicy", + "hardwarecertification", + "hcs", + "hgsattestation", + "hgsclient", + "hgsdiagnostics", + "hgskeyprotection", + "hgsserver", + "hnvdiagnostics", + "hostcomputeservice", + "hpc", + "HPC.ACM", + "HPC.ACM.API.PS", + "HPCPack2016", + "hyper-v", + "IISAdministration", + "international", + "ipamserver", + "iscsi", + "iscsitarget", + "ISE", + "kds", + "Microsoft.MBAM", + "Microsoft.MEDV", + "MgmtSvcAdmin", + "MgmtSvcConfig", + "MgmtSvcMySql", + "MgmtSvcSqlServer", + "Microsoft.AzureStack.ReadinessChecker", + "Microsoft.Crm.PowerShell", + "Microsoft.DiagnosticDataViewer", + "Microsoft.DirectoryServices.MetadirectoryServices.Config", + "Microsoft.Dynamics.Nav.Apps.Management", + "Microsoft.Dynamics.Nav.Apps.Tools", + "Microsoft.Dynamics.Nav.Ide", + "Microsoft.Dynamics.Nav.Management", + "Microsoft.Dynamics.Nav.Model.Tools", + "Microsoft.Dynamics.Nav.Model.Tools.Crm", + "Microsoft.EnterpriseManagement.Warehouse.Cmdlets", + "Microsoft.Medv.Administration.Commands.WorkspacePackager", + "Microsoft.PowerApps.Checker.PowerShell", + "Microsoft.PowerShell.Archive", + "Microsoft.PowerShell.ConsoleGuiTools", + "Microsoft.PowerShell.Core", + "Microsoft.PowerShell.Crescendo", + "Microsoft.PowerShell.Diagnostics", + "Microsoft.PowerShell.Host", + "Microsoft.PowerShell.LocalAccounts", + "Microsoft.PowerShell.Management", + "Microsoft.PowerShell.ODataUtils", + "Microsoft.PowerShell.Operation.Validation", + "Microsoft.PowerShell.PSAdapter", + "Microsoft.PowerShell.PSResourceGet", + "Microsoft.PowerShell.RemotingTools", + "Microsoft.PowerShell.SecretManagement", + "Microsoft.PowerShell.SecretStore", + "Microsoft.PowerShell.Security", + "Microsoft.PowerShell.TextUtility", + "Microsoft.PowerShell.Utility", + "Microsoft.SharePoint.Powershell", + "Microsoft.SystemCenter.ServiceManagementAutomation", + "Microsoft.Windows.ServerManager.Migration", + "Microsoft.WSMan.Management", + "Microsoft.Xrm.OnlineManagementAPI", + "Microsoft.Xrm.Tooling.CrmConnector.PowerShell", + "Microsoft.Xrm.Tooling.PackageDeployment", + "Microsoft.Xrm.Tooling.PackageDeployment.Powershell", + "Microsoft.Xrm.Tooling.Testing", + "MicrosoftPowerBIMgmt", + "MicrosoftPowerBIMgmt.Data", + "MicrosoftPowerBIMgmt.Profile", + "MicrosoftPowerBIMgmt.Reports", + "MicrosoftPowerBIMgmt.Workspaces", + "MicrosoftStaffHub", + "MicrosoftTeams", + "MIMPAM", + "mlSqlPs", + "MMAgent", + "MPIO", + "MsDtc", + "MSMQ", + "MSOnline", + "MSOnlineBackup", + "WmsCmdlets", + "WmsCmdlets3", + "NanoServerImageGenerator", + "NAVWebClientManagement", + "NetAdapter", + "NetConnection", + "NetEventPacketCapture", + "Netlbfo", + "Netldpagent", + "NetNat", + "Netqos", + "NetSecurity", + "NetSwitchtTeam", + "Nettcpip", + "Netwnv", + "NetworkConnectivity", + "NetworkConnectivityStatus", + "NetworkController", + "NetworkControllerDiagnostics", + "NetworkloadBalancingClusters", + "NetworkSwitchManager", + "NetworkTransition", + "NFS", + "NPS", + "OfficeWebapps", + "OperationsManager", + "PackageManagement", + "PartnerCenter", + "pcsvdevice", + "pef", + "Pester", + "pkiclient", + "platformidentifier", + "pnpdevice", + "PowerShellEditorServices", + "PowerShellGet", + "powershellwebaccess", + "printmanagement", + "ProcessMitigations", + "provisioning", + "PSDesiredStateConfiguration", + "PSDiagnostics", + "PSReadLine", + "PSScheduledJob", + "PSScriptAnalyzer", + "PSWorkflow", + "PSWorkflowUtility", + "RemoteAccess", + "RemoteDesktop", + "RemoteDesktopServices", + "ScheduledTasks", + "Secureboot", + "ServerCore", + "ServerManager", + "ServerManagerTasks", + "ServerMigrationcmdlets", + "ServiceFabric", + "Microsoft.Online.SharePoint.PowerShell", + "shieldedvmdatafile", + "shieldedvmprovisioning", + "shieldedvmtemplate", + "SkypeOnlineConnector", + "SkypeForBusinessHybridHealth", + "smbshare", + "smbwitness", + "smisconfig", + "softwareinventorylogging", + "SPFAdmin", + "Microsoft.SharePoint.MigrationTool.PowerShell", + "sqlps", + "SqlServer", + "StartLayout", + "StartScreen", + "Storage", + "StorageDsc", + "storageqos", + "Storagereplica", + "Storagespaces", + "Syncshare", + "System.Center.Service.Manager", + "TLS", + "TroubleshootingPack", + "TrustedPlatformModule", + "UEV", + "UpdateServices", + "UserAccessLogging", + "vamt", + "VirtualMachineManager", + "vpnclient", + "WasPSExt", + "WDAC", + "WDS", + "WebAdministration", + "WebAdministrationDsc", + "WebApplicationProxy", + "WebSites", + "Whea", + "WhiteboardAdmin", + "WindowsDefender", + "WindowsDefenderDsc", + "WindowsDeveloperLicense", + "WindowsDiagnosticData", + "WindowsErrorReporting", + "WindowServerRackup", + "WindowsSearch", + "WindowsServerBackup", + "WindowsUpdate", + "WinGetCommandNotFound", + "wsscmdlets", + "wsssetup", + "wsus", + "xActiveDirectory", + "xBitLocker", + "xDefender", + "xDhcpServer", + "xDismFeature", + "xDnsServer", + "xHyper-V", + "xHyper-VBackup", + "xPSDesiredStateConfiguration", + "xSmbShare", + "xSqlPs", + "xStorage", + "xWebAdministration", + "xWindowsUpdate", + }; + + // use a hashset when looking for module names, it should be quicker than a string comparison + s_knownModuleTags = new HashSet<string>(StringComparer.OrdinalIgnoreCase) + { + "CrescendoBuilt", + }; + + s_uniqueUserIdentifier = GetUniqueIdentifier().ToString(); + s_knownSubsystemNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) + { + "Completion", + "General Feedback", + "Windows Package Manager - WinGet", + "Az Predictor" + }; } /// <summary> @@ -984,8 +990,7 @@ private static Guid GetUniqueIdentifier() // Try to get the unique id. If this returns false, we'll // create/recreate the telemetry.uuid file to persist for next startup. Guid id = Guid.Empty; - string uuidPath = Path.Join(Platform.CacheDirectory, "telemetry.uuid"); - if (TryGetIdentifier(uuidPath, out id)) + if (TryGetIdentifier(s_uuidPath, out id)) { return id; } @@ -1000,7 +1005,7 @@ private static Guid GetUniqueIdentifier() m.WaitOne(); try { - return CreateUniqueIdentifierAndFile(uuidPath); + return CreateUniqueIdentifierAndFile(s_uuidPath); } finally { From e3133e0a09718604eaffdad023bbd011dd5d8d51 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 14:59:50 -0700 Subject: [PATCH 117/127] [release/v7.6.2] Update `Microsoft.PowerShell.Native` to the latest GA version (#27436) --- .../System.Management.Automation.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj index 63dc69e5119..09e80684d43 100644 --- a/src/System.Management.Automation/System.Management.Automation.csproj +++ b/src/System.Management.Automation/System.Management.Automation.csproj @@ -43,7 +43,7 @@ <PackageReference Include="System.Security.Permissions" Version="10.0.5" /> <!-- the following package(s) are from the powershell org --> <PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" /> - <PackageReference Include="Microsoft.PowerShell.Native" Version="700.0.0-rc.1" /> + <PackageReference Include="Microsoft.PowerShell.Native" Version="700.0.0" /> <!-- Signing APIs --> <PackageReference Include="Microsoft.Security.Extensions" Version="1.4.0" /> <PackageReference Include="System.Windows.Extensions" Version="10.0.5" /> From 32c5b651e19edfcaff99a450e61d692969c9f423 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 15:01:57 -0700 Subject: [PATCH 118/127] [release/v7.6.2] Update the MSIXBundle-VPack pipeline to create VPack for both LTS and Stable channel packages (#27435) --- .pipelines/MSIXBundle-vPack-Official.yml | 199 +++++------------- .../templates/create-msixbundle-vpack.yml | 178 ++++++++++++++++ 2 files changed, 230 insertions(+), 147 deletions(-) create mode 100644 .pipelines/templates/create-msixbundle-vpack.yml diff --git a/.pipelines/MSIXBundle-vPack-Official.yml b/.pipelines/MSIXBundle-vPack-Official.yml index 08edd0367bd..2461d3cd310 100644 --- a/.pipelines/MSIXBundle-vPack-Official.yml +++ b/.pipelines/MSIXBundle-vPack-Official.yml @@ -138,12 +138,6 @@ extends: if (-not $matched) { throw "Release tag must be in the format v#.#.#, such as 'v7.4.3'. Current version: $releaseTag" } - - # Extract minor version and verify it's even (LTS versions only) - $minorVersion = [int]$Matches[1] - if($minorVersion % 2 -ne 0) { - throw "Only release msixbundle vpack for LTS releases. Current version: $releaseTag" - } displayName: Stop any preview release env: ob_restore_phase: true @@ -270,7 +264,7 @@ extends: Write-Verbose -Message "checking pwsh exists in $signedFilesPath" -Verbose if (-not (Test-Path $signedFilesPath\pwsh.exe)) { - throw "pwsh.exe not found in $signedFilesPath" + throw "pwsh.exe not found in $signedFilesPath" } Write-Verbose -Message "Restoring PSOptions from $psoptionsFilePath" -Verbose @@ -278,166 +272,77 @@ extends: Restore-PSOptions -PSOptionsPath "$psoptionsFilePath" Get-PSOptions | Write-Verbose -Verbose - ## Generated packages are placed in the current directory by default. - Set-Location $repoRoot - Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS - - $msixPkgNameFilter = "PowerShell*.msix" - $msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -File - $msixPkgPath = $msixPkgFile.FullName - Write-Verbose -Verbose "Unsigned msix package: $msixPkgPath" - - $pkgDir = '$(ob_outputDirectory)\pkgs' - $null = New-Item -ItemType Directory -Path $pkgDir -Force - Copy-Item -Path $msixPkgPath -Destination $pkgDir -Force -Verbose - displayName: 'Build MSIX Package (Unsigned)' - - ### END OF Packaging ### - - - pwsh: | - Get-ChildItem -Path '$(ob_outputDirectory)\pkgs' -Recurse - displayName: 'List Unsigned Package' - - - stage: Pack_MSIXBundle_And_Sign - displayName: 'Pack and sign MSIXBundle' - dependsOn: [Build_MSIX_Package] - jobs: - - job: Bundle - pool: - type: windows - variables: - ArtifactPlatform: 'windows' - ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' - ob_artifactBaseName: drop_pack_msixbundle - ob_createvpack_enabled: ${{ parameters.createVPack }} - ob_createvpack_packagename: 'PowerShell7.Store.app' - ob_createvpack_owneralias: 'dongbow' - ob_createvpack_description: 'VPack for the PowerShell 7 Store Application' - ob_createvpack_targetDestinationDirectory: '$(Destination)' ## The value is from the 'CreateVpack' task, used when pulling the generated VPack. - ob_createvpack_propsFile: false - ob_createvpack_provData: true - ob_createvpack_metadata: '$(Build.SourceVersion)' - ob_createvpack_versionAs: string - ob_createvpack_version: '$(Version)' - ob_createvpack_verbose: true - - steps: - - checkout: self - displayName: Checkout source code - during restore - clean: true - path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. - env: - ob_restore_phase: true + $metadata = Get-Content "$repoRoot\tools\metadata.json" -Raw | ConvertFrom-Json + Write-Verbose -Verbose "metadata:" + $metadata | Out-String | Write-Verbose -Verbose - - template: /.pipelines/templates/SetVersionVariables.yml@self - parameters: - ReleaseTagVar: $(ReleaseTagVar) - CreateJson: no + $publishLTS = $metadata.LTSRelease.PublishToChannels + $publishStable = $metadata.StableRelease.PublishToChannels - - template: /.pipelines/templates/shouldSign.yml@self + Write-Verbose -Verbose "Publish LTS: $publishLTS" + Write-Verbose -Verbose "Publish Stable: $publishStable" - - task: DownloadPipelineArtifact@2 - inputs: - artifactName: drop_build_x64 - itemPattern: | - **/*.msix - targetPath: '$(Build.ArtifactStagingDirectory)\downloads' - displayName: Download msix for x64 + if (-not $publishLTS -and -not $publishStable) { + throw "metadata.json indicates no channels to publish to." + } - - task: DownloadPipelineArtifact@2 - inputs: - artifactName: drop_build_arm64 - itemPattern: | - **/*.msix - targetPath: '$(Build.ArtifactStagingDirectory)\downloads' - displayName: Download msix for arm64 + ## Generated packages are placed in the current directory by default. + Set-Location $repoRoot + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath -LTS:$publishLTS - # Finds the makeappx tool on the machine. - - pwsh: | - Write-Verbose -Verbose 'PowerShell Version: $(Version)' - $cmd = Get-Command makeappx.exe -ErrorAction Ignore - if ($cmd) { - Write-Verbose -Verbose 'makeappx available in PATH' - $exePath = $cmd.Source - } else { - $makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' | - Where-Object { $_.DirectoryName -match 'x64' } | - Select-Object -Last 1 - $exePath = $makeappx.FullName - Write-Verbose -Verbose "makeappx was found: $exePath" + if ($publishLTS -and $publishStable) { + $enabledChannels = "LTS,Stable" + Write-Verbose -Verbose "Publish to both LTS and Stable channels. Building additional Stable MSIX." + Start-PSPackage -Type msix -SkipReleaseChecks -WindowsRuntime $runtime -ReleaseTag $(ReleaseTagVar) -PackageBinPath $signedFilesPath } - $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" - Write-Host ("sending " + $vstsCommandString) - Write-Host "##$vstsCommandString" - displayName: Find makeappx tool - retryCountOnTaskFailure: 1 - - pwsh: | - $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' - $null = New-Item -Path $sourceDir -ItemType Directory -Force + $msixPkgNameFilter = "PowerShell*.msix" + $msixPkgFile = Get-ChildItem -Path $repoRoot -Filter $msixPkgNameFilter -Recurse -File | ForEach-Object FullName + Write-Verbose -Verbose "Unsigned msix package(s): $msixPkgFile" - $msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse - foreach ($msixFile in $msixFiles) { - $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose - } + $pkgDir = '$(ob_outputDirectory)\pkgs' + $null = New-Item -ItemType Directory -Path $pkgDir -Force + Copy-Item -Path $msixPkgFile -Destination $pkgDir -Force -Verbose - $file = Get-ChildItem $sourceDir | Select-Object -First 1 - $prefix = ($file.BaseName -split "-win")[0] - $pkgName = "$prefix.msixbundle" - Write-Verbose -Verbose "Creating $pkgName" - - $makeappx = '$(MakeAppxPath)' - $outputDir = "$sourceDir\output" - New-Item $outputDir -Type Directory -Force > $null - & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" - if ($LASTEXITCODE -ne 0) { - throw "makeappx bundle failed with exit code $LASTEXITCODE" + if (-not $enabledChannels) { + $enabledChannels = $publishLTS ? 'LTS' : ($publishStable ? 'Stable' : 'None') } - Get-ChildItem -Path $sourceDir -Recurse | Out-String -Width 200 - $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" + ## Create an output variable for the enabled channels so that downstream stages can use it. + $vstsCommandString = "vso[task.setvariable variable=EnabledChannels;isOutput=true]$enabledChannels" Write-Host ("sending " + $vstsCommandString) Write-Host "##$vstsCommandString" - displayName: Create MsixBundle - retryCountOnTaskFailure: 1 + name: BuildMSIXPackage + displayName: 'Build MSIX Package (Unsigned)' - - task: onebranch.pipeline.signing@1 - displayName: Sign MsixBundle - inputs: - command: 'sign' - signing_profile: $(MSIXProfile) - files_to_sign: '**/*.msixbundle' - search_root: '$(BundleDir)' + ### END OF Packaging ### - pwsh: | - $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File - Write-Verbose -Verbose "Signed bundle: $signedBundle" - - $signature = Get-AuthenticodeSignature -FilePath $signedBundle.FullName - if ($signature.Status -ne 'Valid') { - throw "The bundle file doesn't have a valid signature. Signature status: $($signature.Status)" - } + Get-ChildItem -Path '$(ob_outputDirectory)\pkgs' -Recurse + displayName: 'List Unsigned Package' - if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { - $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop - } + - pwsh: | + $signedFilesPath = '$(ob_outputDirectory)\Signed-$(Runtime)' + Remove-Item -Path $signedFilesPath -Recurse -Force -Verbose + displayName: 'Remove Signed-$(Runtime) folder' - $targetPath = Join-Path '$(ob_outputDirectory)' 'Microsoft.PowerShell-LTS_8wekyb3d8bbwe.msixbundle' - Copy-Item -Verbose -Path $signedBundle.FullName -Destination $targetPath + - stage: Pack_MSIXBundle_And_Sign + displayName: 'Pack and sign MSIXBundle' + dependsOn: [Build_MSIX_Package] - Write-Verbose -Verbose "Uploaded Bundle:" - Get-ChildItem -Path $(ob_outputDirectory) | Out-String -Width 200 -Stream | Write-Verbose -Verbose - displayName: 'Stage msixbundle for VPack' + variables: + EnabledChannels: $[ stageDependencies.Build_MSIX_Package.Build.outputs['x64.BuildMSIXPackage.EnabledChannels'] ] - - pwsh: | - Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose - $vpackFiles = Get-ChildItem -Path '$(ob_outputDirectory)\*' -Recurse - if($vpackFiles.Count -eq 0) { - throw "No files found in $(ob_outputDirectory)" - } - $vpackFiles | Out-String -Width 200 - displayName: Debug Output Directory and Version - condition: succeededOrFailed() + jobs: + - template: /.pipelines/templates/create-msixbundle-vpack.yml@self + parameters: + Channel: 'LTS' + createVPack: ${{ parameters.createVPack }} + + - template: /.pipelines/templates/create-msixbundle-vpack.yml@self + parameters: + Channel: 'Stable' + createVPack: ${{ parameters.createVPack }} - stage: Publish_Symbols displayName: 'Publish Symbols' diff --git a/.pipelines/templates/create-msixbundle-vpack.yml b/.pipelines/templates/create-msixbundle-vpack.yml new file mode 100644 index 00000000000..df46523675f --- /dev/null +++ b/.pipelines/templates/create-msixbundle-vpack.yml @@ -0,0 +1,178 @@ +parameters: + - name: Channel + type: string + - name: createVPack + type: boolean + +jobs: +- job: Bundle_${{ parameters.Channel }} + condition: contains(variables['EnabledChannels'], '${{ parameters.Channel }}') + pool: + type: windows + + variables: + ArtifactPlatform: 'windows' + Channel: ${{ parameters.Channel }} + ob_outputDirectory: '$(BUILD.SOURCESDIRECTORY)\out' + ob_artifactBaseName: 'drop_pack_$(Channel)' + ob_createvpack_enabled: ${{ parameters.createVPack }} + ob_createvpack_packagename: 'PowerShell7-$(Channel).Store.app' + ob_createvpack_owneralias: 'dongbow' + ob_createvpack_description: 'VPack for the PowerShell 7 Store Application ($(Channel))' + ob_createvpack_targetDestinationDirectory: '$(Destination)' ## The value is from the 'CreateVpack' task, used when pulling the generated VPack. + ob_createvpack_propsFile: false + ob_createvpack_provData: true + ob_createvpack_metadata: '$(Build.SourceVersion)' + ob_createvpack_versionAs: string + ob_createvpack_version: '$(Version)' + ob_createvpack_verbose: true + + steps: + - checkout: self + displayName: Checkout source code - during restore + clean: true + path: s ## $(Build.SourcesDirectory) is at '$(Pipeline.Workspace)\s', so we need to check out repo to the 's' folder. + env: + ob_restore_phase: true + + - template: /.pipelines/templates/SetVersionVariables.yml@self + parameters: + ReleaseTagVar: $(ReleaseTagVar) + CreateJson: no + + - template: /.pipelines/templates/shouldSign.yml@self + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_x64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for x64 + + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: drop_build_arm64 + itemPattern: | + **/*.msix + targetPath: '$(Build.ArtifactStagingDirectory)\downloads' + displayName: Download msix for arm64 + + # Finds the makeappx tool on the machine. + - pwsh: | + Write-Verbose -Verbose 'PowerShell Version: $(Version)' + $cmd = Get-Command makeappx.exe -ErrorAction Ignore + if ($cmd) { + Write-Verbose -Verbose 'makeappx available in PATH' + $exePath = $cmd.Source + } else { + $makeappx = Get-ChildItem -Recurse 'C:\Program Files (x86)\Windows Kits\10\makeappx.exe' | + Where-Object { $_.DirectoryName -match 'x64' } | + Select-Object -Last 1 + $exePath = $makeappx.FullName + Write-Verbose -Verbose "makeappx was found: $exePath" + } + $vstsCommandString = "vso[task.setvariable variable=MakeAppxPath]$exePath" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Find makeappx tool + retryCountOnTaskFailure: 1 + + - pwsh: | + $sourceDir = '$(Pipeline.Workspace)\releasePipeline\msix' + $null = New-Item -Path $sourceDir -ItemType Directory -Force + + $channel = '$(Channel)' + if ($channel -eq 'LTS') { + Write-Verbose -Verbose "LTS channel. Remove Stable MSIX packages" + $stablePkgs = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse | + Where-Object { $_.FullName -notlike '*-LTS-*.msix' } | ForEach-Object FullName + + if ($stablePkgs) { + Remove-Item -Path $stablePkgs -Force -Verbose -ErrorAction Stop + } else { + Write-Verbose -Verbose "No Stable MSIX package was found." + } + } + else { + Write-Verbose -Verbose "Stable channel. Remove LTS MSIX packages" + $ltsPkgs = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse | + Where-Object { $_.FullName -like '*-LTS-*.msix' } | ForEach-Object FullName + + if ($ltsPkgs) { + Remove-Item -Path $ltsPkgs -Force -Verbose -ErrorAction Stop + } else { + Write-Verbose -Verbose "No LTS MSIX package was found." + } + } + + $msixFiles = Get-ChildItem -Path "$(Build.ArtifactStagingDirectory)\downloads\*.msix" -Recurse + foreach ($msixFile in $msixFiles) { + $null = Copy-Item -Path $msixFile.FullName -Destination $sourceDir -Force -Verbose + } + + $file = Get-ChildItem $sourceDir | Select-Object -First 1 + $prefix = ($file.BaseName -split "-win")[0] + $pkgName = "$prefix.msixbundle" + Write-Verbose -Verbose "Creating $pkgName" + + $makeappx = '$(MakeAppxPath)' + $outputDir = "$sourceDir\output" + New-Item $outputDir -Type Directory -Force > $null + & $makeappx bundle /d $sourceDir /p "$outputDir\$pkgName" + if ($LASTEXITCODE -ne 0) { + throw "makeappx bundle failed with exit code $LASTEXITCODE" + } + + Get-ChildItem -Path $sourceDir -Recurse | Out-String -Width 200 + $vstsCommandString = "vso[task.setvariable variable=BundleDir]$outputDir" + Write-Host ("sending " + $vstsCommandString) + Write-Host "##$vstsCommandString" + displayName: Create MsixBundle + retryCountOnTaskFailure: 1 + + - task: onebranch.pipeline.signing@1 + displayName: Sign MsixBundle + inputs: + command: 'sign' + signing_profile: $(MSIXProfile) + files_to_sign: '**/*.msixbundle' + search_root: '$(BundleDir)' + + - pwsh: | + $signedBundle = Get-ChildItem -Path $(BundleDir) -Filter "*.msixbundle" -File + Write-Verbose -Verbose "Signed bundle: $signedBundle" + + $signature = Get-AuthenticodeSignature -FilePath $signedBundle.FullName + if ($signature.Status -ne 'Valid') { + throw "The bundle file doesn't have a valid signature. Signature status: $($signature.Status)" + } + + if (-not (Test-Path '$(ob_outputDirectory)' -PathType Container)) { + $null = New-Item '$(ob_outputDirectory)' -ItemType Directory -ErrorAction Stop + } + + $channel = '$(Channel)' + $targetFileName = if ($channel -eq 'LTS') { + 'Microsoft.PowerShell-LTS_8wekyb3d8bbwe.msixbundle' + } else { + 'Microsoft.PowerShell_8wekyb3d8bbwe.msixbundle' + } + $targetPath = Join-Path '$(ob_outputDirectory)' $targetFileName + Copy-Item -Verbose -Path $signedBundle.FullName -Destination $targetPath + + Write-Verbose -Verbose "Uploaded Bundle:" + Get-ChildItem -Path $(ob_outputDirectory) | Out-String -Width 200 -Stream | Write-Verbose -Verbose + displayName: 'Stage msixbundle for VPack' + + - pwsh: | + Write-Verbose "VPack enabled: $(ob_createvpack_enabled)" -Verbose + Write-Verbose "VPack Name: $(ob_createvpack_packagename)" -Verbose + Write-Verbose "VPack Version: $(ob_createvpack_version)" -Verbose + + $vpackFiles = Get-ChildItem -Path '$(ob_outputDirectory)\*' -Recurse + if($vpackFiles.Count -eq 0) { + throw "No files found in $(ob_outputDirectory)" + } + $vpackFiles | Out-String -Width 200 + displayName: Debug Output Directory and Version From 712231cad42e12f1642ec9cfbb9fce9da9914456 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 15:02:40 -0700 Subject: [PATCH 119/127] [release/v7.6.2] Remove package verification from the notice pipeline (#27425) --- .pipelines/apiscan-gen-notice.yml | 4 ---- .pipelines/templates/compliance/generateNotice.yml | 7 ------- 2 files changed, 11 deletions(-) diff --git a/.pipelines/apiscan-gen-notice.yml b/.pipelines/apiscan-gen-notice.yml index 9cc83e7136a..df5ebaac091 100644 --- a/.pipelines/apiscan-gen-notice.yml +++ b/.pipelines/apiscan-gen-notice.yml @@ -8,9 +8,6 @@ parameters: displayName: Debugging - Enable CodeQL and set cadence to 1 hour type: boolean default: false - - name: SkipVerifyPackages - type: boolean - default: false variables: # PAT permissions NOTE: Declare a SymbolServerPAT variable in this group with a 'microsoft' organizanization scoped PAT with 'Symbols' Read permission. @@ -112,4 +109,3 @@ extends: - template: /.pipelines/templates/compliance/generateNotice.yml@self parameters: parentJobs: [] - SkipVerifyPackages: ${{ parameters.SkipVerifyPackages }} diff --git a/.pipelines/templates/compliance/generateNotice.yml b/.pipelines/templates/compliance/generateNotice.yml index 90fd08dd8d9..aec44b9b8f6 100644 --- a/.pipelines/templates/compliance/generateNotice.yml +++ b/.pipelines/templates/compliance/generateNotice.yml @@ -4,8 +4,6 @@ parameters: - name: parentJobs type: jobList - - name: SkipVerifyPackages - type: boolean jobs: - job: generateNotice @@ -57,11 +55,6 @@ jobs: inputs: sourceScanPath: '$(repoRoot)\tools\cgmanifest\tpn' - - pwsh: | - $(repoRoot)/tools/clearlyDefined/ClearlyDefined.ps1 -TestAndHarvest - displayName: Verify that packages have license data - condition: eq(${{ parameters.SkipVerifyPackages }}, false) - - task: msospo.ospo-extension.8d7f9abb-6896-461d-9e25-4f74ed65ddb2.notice@0 displayName: 'NOTICE File Generator' inputs: From 8afbd5fc9b59ae566c71e8fc2066228979e6ed5c Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 15:03:23 -0700 Subject: [PATCH 120/127] [release/v7.6.2] Enable usage in AppContainers (#27423) --- .../engine/Modules/ModuleIntrinsics.cs | 4 ++- .../namespaces/FileSystemProvider.cs | 27 +++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs index b687e502763..6d37de883d1 100644 --- a/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs +++ b/src/System.Management.Automation/engine/Modules/ModuleIntrinsics.cs @@ -967,7 +967,9 @@ internal static string GetPersonalModulePath() #if UNIX return Platform.SelectProductNameForDirectory(Platform.XDG_Type.USER_MODULES); #else - string myDocumentsPath = InternalTestHooks.SetMyDocumentsSpecialFolderToBlank ? string.Empty : Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + string myDocumentsPath = InternalTestHooks.SetMyDocumentsSpecialFolderToBlank + ? string.Empty + : Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify); return string.IsNullOrEmpty(myDocumentsPath) ? null : Path.Combine(myDocumentsPath, Utils.ModuleDirectory); #endif } diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index c5df7a9339a..bb66c0697e9 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -569,7 +569,7 @@ protected override PSDriveInfo NewDrive(PSDriveInfo drive) if (driveIsFixed) { // Since the drive is fixed, ensure the root is valid. - validDrive = Directory.Exists(drive.Root); + validDrive = SafeDoesPathExist(drive.Root); } if (validDrive) @@ -908,7 +908,7 @@ protected override Collection<PSDriveInfo> InitializeDefaultDrives() if (newDrive.DriveType == DriveType.Fixed) { - if (!newDrive.RootDirectory.Exists) + if (!SafeDoesPathExist(newDrive.RootDirectory.FullName)) { continue; } @@ -1227,6 +1227,29 @@ protected override void GetItem(string path) } } + private static bool SafeDoesPathExist(string rootDirectory) + { + if (Directory.Exists(rootDirectory)) + { + return true; + } + + try + { + return (File.GetAttributes(rootDirectory) & FileAttributes.Directory) is not 0; + } + // In some scenarios (like AppContainers) direct access to the root directory may + // be prevented, but more specific paths may be accessible. + catch (UnauthorizedAccessException) + { + return true; + } + catch + { + return false; + } + } + private FileSystemInfo GetFileSystemItem(string path, ref bool isContainer, bool showHidden) { path = NormalizePath(path); From c031a106f9b1e45dd45f8cda6cf454fdfec9aab7 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 15:04:20 -0700 Subject: [PATCH 121/127] [release/v7.6.2] Remove mariner2.0 from PMC mapping (#27422) --- tools/packages.microsoft.com/mapping.json | 32 ----------------------- 1 file changed, 32 deletions(-) diff --git a/tools/packages.microsoft.com/mapping.json b/tools/packages.microsoft.com/mapping.json index 154a9582872..7cb212ffee3 100644 --- a/tools/packages.microsoft.com/mapping.json +++ b/tools/packages.microsoft.com/mapping.json @@ -28,38 +28,6 @@ ], "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.rh.x86_64.rpm" }, - { - "url": "cbl-mariner-2.0-prod-Microsoft-aarch64", - "distribution": [ - "bionic" - ], - "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.aarch64.rpm", - "channel": "stable" - }, - { - "url": "cbl-mariner-2.0-prod-Microsoft-x86_64", - "distribution": [ - "bionic" - ], - "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.x86_64.rpm", - "channel": "stable" - }, - { - "url": "cbl-mariner-2.0-preview-Microsoft-aarch64", - "distribution": [ - "bionic" - ], - "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.aarch64.rpm", - "channel": "preview" - }, - { - "url": "cbl-mariner-2.0-preview-Microsoft-x86_64", - "distribution": [ - "bionic" - ], - "PackageFormat": "PACKAGE_NAME-POWERSHELL_RELEASE-1.cm.x86_64.rpm", - "channel": "preview" - }, { "url": "azurelinux-3.0-prod-ms-oss-aarch64", "distribution": [ From 4c698487466a5b7f45d6005062f4f23de41a73be Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 16:11:54 -0700 Subject: [PATCH 122/127] [release/v7.6.2] Specify linux-arm64 runtime if package type is deb-arm64 in packaging.psm1 (#27440) --- tools/packaging/packaging.psm1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 641299df382..b5f88e8ba6c 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -121,6 +121,9 @@ function Start-PSPackage { elseif ($Type.Count -eq 1 -and $Type[0] -eq "tar-alpine-fxdependent") { New-PSOptions -Configuration "Release" -Runtime 'fxdependent-noopt-linux-musl-x64' -WarningAction SilentlyContinue | ForEach-Object { $_.Runtime, $_.Configuration } } + elseif ($Type.Count -eq 1 -and $Type[0] -eq "deb-arm64") { + New-PSOptions -Configuration "Release" -Runtime 'linux-arm64' -WarningAction SilentlyContinue | ForEach-Object { $_.Runtime, $_.Configuration } + } else { New-PSOptions -Configuration "Release" -WarningAction SilentlyContinue | ForEach-Object { $_.Runtime, $_.Configuration } } From b1fbe52e37f942cd31d94411ffcbba8d80bd4169 Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 16:12:43 -0700 Subject: [PATCH 123/127] [release/v7.6.2] Fix *nix permissions and use `certificate_logical_to_actual` (#27439) --- .pipelines/templates/linux-package-build.yml | 23 ++++-- .pipelines/templates/mac-package-build.yml | 71 +++++++++++++++---- .pipelines/templates/mac.yml | 32 +++++++++ .pipelines/templates/nupkg.yml | 5 +- .pipelines/templates/shouldSign.yml | 6 +- .../stages/PowerShell-Packages-Stages.yml | 2 - .pipelines/templates/windows-hosted-build.yml | 2 +- tools/packaging/packaging.psd1 | 1 + tools/packaging/packaging.psm1 | 24 ++++++- 9 files changed, 141 insertions(+), 25 deletions(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index 1487455107e..e37d8555533 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -1,9 +1,8 @@ parameters: unsignedDrop: 'drop_linux_build_linux_x64' - signedeDrop: 'drop_linux_sign_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' packageType: deb jobName: 'deb' - signingProfile: 'CP-450779-pgpdetached' jobs: - job: ${{ parameters.jobName }} @@ -20,6 +19,7 @@ jobs: - name: skipNugetSecurityAnalysis value: true - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -34,8 +34,16 @@ jobs: value: $(Build.SourcesDirectory)/PowerShell/.config/tsaoptions.json - name: ob_sdl_credscan_suppressionsFile value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json - - name: SigningProfile - value: ${{ parameters.signingProfile }} + # PGP signing profile selection: Mariner (Azure Linux) packages ship through + # a different distribution channel and must be signed with the Mariner release + # key; all other Linux packages use the standard PowerShell Linux key. Both + # key codes come from the `certificate_logical_to_actual` variable group. + - ${{ if startsWith(parameters.jobName, 'mariner') }}: + - name: SigningProfile + value: $(pgp_release_cert_id) + - ${{ else }}: + - name: SigningProfile + value: $(pgp_linux_cert_id) steps: - checkout: self @@ -193,6 +201,13 @@ jobs: $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgFilter -Recurse -File | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "pkgPath: $pkgPath" Copy-Item -Path $pkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + + if ($pkgPath -like '*.tar.gz') { + $entry = & tar -tzvf $pkgPath | Where-Object { $_ -match '\spwsh$' } | Select-Object -First 1 + if ($entry -notmatch '^-..x') { + throw "pwsh is not executable in $pkgPath : $entry" + } + } displayName: 'Copy artifacts to output directory' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 6585773c743..89dab90aa04 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -22,6 +22,7 @@ jobs: - name: skipNugetSecurityAnalysis value: true - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -76,6 +77,14 @@ jobs: # Diagnostics is not critical it passes every time it runs continueOnError: true + - pwsh: | + $signedDir = "$(Pipeline.Workspace)/CoOrdinatedBuildPipeline/drop_macos_sign_${{ parameters.buildArchitecture }}/Signed-${{ parameters.buildArchitecture }}" + Get-ChildItem $signedDir -Recurse -Include 'pwsh', '*.dylib' | ForEach-Object { + codesign --verify --deep --strict --verbose=4 $_.FullName + if ($LASTEXITCODE -ne 0) { throw "codesign verification failed for $($_.FullName)" } + } + displayName: 'Verify Apple codesign on signed binaries' + - pwsh: | # Add -SkipReleaseChecks as a mitigation to unblock release. # macos-10.15 does not allow creating a folder under root. Hence, moving the folder. @@ -154,11 +163,20 @@ jobs: foreach($t in $tarPkgPath) { $file = $t.FullName + $entry = & tar -tzvf $file | Where-Object { $_ -match '\spwsh$' } | Select-Object -First 1 + if ($entry -notmatch '^-..x') { + throw "pwsh is not executable in $file : $entry" + } Write-Verbose -verbose "Uploading $file to macos-pkgs" Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" } + $packageInfo = Get-MacOSPackageIdentifierInfo -Version '$(Version)' -LTS:$LTS + Write-Verbose -Verbose "BundleId: $($packageInfo.PackageIdentifier)" + Write-Host "##vso[task.setvariable variable=BundleId;isOutput=true]$($packageInfo.PackageIdentifier)" + displayName: 'Package ${{ parameters.buildArchitecture}}' + name: packageStep env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) @@ -170,6 +188,7 @@ jobs: type: windows variables: + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -178,7 +197,8 @@ jobs: value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json - name: BuildArch value: ${{ parameters.buildArchitecture }} - - group: mscodehub-macos-package-signing + - name: BundleId + value: $[ dependencies.package_macOS_${{ parameters.buildArchitecture }}.outputs['packageStep.BundleId'] ] steps: - download: current @@ -216,32 +236,59 @@ jobs: inline_operation: | [ { - "KeyCode": "$(KeyCode)", + "KeyCode": "$(apple_cert_id)", "OperationCode": "MacAppDeveloperSign", "ToolName": "sign", "ToolVersion": "1.0", "Parameters": { - "Hardening": "Enable", - "OpusInfo": "http://microsoft.com" + "Hardening": "--options=runtime" + } + } + ] + + - task: onebranch.pipeline.signing@1 + displayName: 'OneBranch Notarize Package' + inputs: + command: 'sign' + files_to_sign: '**/*-osx-*.zip' + search_root: '$(Pipeline.Workspace)' + inline_operation: | + [ + { + "KeyCode": "$(apple_cert_id)", + "OperationCode": "MacAppNotarize", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": { + "BundleId": "$(BundleId)" } } ] + timeoutInMinutes: 120 - pwsh: | $signedPkg = Get-ChildItem -Path $(Pipeline.Workspace) -Filter "*osx*.zip" -File + if (-not (Test-Path $(ob_outputDirectory))) { + $null = New-Item -Path $(ob_outputDirectory) -ItemType Directory + } + + $expandDir = "$(Pipeline.Workspace)/pkgExpand" + $null = New-Item -Path $expandDir -ItemType Directory -Force + $signedPkg | ForEach-Object { Write-Verbose -Verbose "Signed package zip: $_" + Expand-Archive -Path $_ -DestinationPath $expandDir -Verbose + } - if (-not (Test-Path $_)) { - throw "Package not found: $_" - } - - if (-not (Test-Path $(ob_outputDirectory))) { - $null = New-Item -Path $(ob_outputDirectory) -ItemType Directory - } + # ESRP's signing pipeline nests the PKG inside a '<hash>.zip.unzipped' subfolder + $pkgFile = Get-ChildItem -Path $expandDir -Filter '*.pkg' -Recurse -File + if (-not $pkgFile) { + throw "Package not found in: $signedPkg" + } - Expand-Archive -Path $_ -DestinationPath $(ob_outputDirectory) -Verbose + $pkgFile | ForEach-Object { + Move-Item -Path $_ -Destination $(ob_outputDirectory) -Verbose } Write-Verbose -Verbose "Expanded pkg file:" diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index cb82a7bf4c0..cd492994617 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -152,4 +152,36 @@ jobs: binPath: $(DropRootPath) OfficialBuild: $(ps_official_build) + # Apple-sign the Mach-O binaries inside the signed output. + - pwsh: | + $signedDir = "$(ob_outputDirectory)/Signed-$(Runtime)" + $zipFile = "$(Pipeline.Workspace)/macho-$(BuildArchitecture).zip" + Compress-Archive -Path "$signedDir/*" -DestinationPath $zipFile -Force + displayName: Compress signed folder for Apple signing + + - task: onebranch.pipeline.signing@1 + displayName: Apple CodeSign Mach-O binaries + inputs: + command: 'sign' + files_to_sign: 'macho-$(BuildArchitecture).zip' + search_root: '$(Pipeline.Workspace)' + inline_operation: | + [ + { + "KeyCode": "$(apple_cert_id)", + "OperationCode": "MacAppDeveloperSign", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": { + "Hardening": "--options=runtime" + } + } + ] + + - pwsh: | + $signedDir = "$(ob_outputDirectory)/Signed-$(Runtime)" + $zipFile = "$(Pipeline.Workspace)/macho-$(BuildArchitecture).zip" + Expand-Archive -Path $zipFile -DestinationPath $signedDir -Force -Verbose + displayName: Expand Apple-signed Mach-O binaries into signed output + - template: /.pipelines/templates/step/finalize.yml@self diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index 3558c949402..c77b3a285c7 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -23,6 +23,7 @@ jobs: - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual steps: - checkout: self @@ -208,7 +209,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(Pipeline.Workspace)\nupkg' @@ -268,7 +269,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(Pipeline.Workspace)\globaltools' diff --git a/.pipelines/templates/shouldSign.yml b/.pipelines/templates/shouldSign.yml index 551297f3aaa..f3701acbc97 100644 --- a/.pipelines/templates/shouldSign.yml +++ b/.pipelines/templates/shouldSign.yml @@ -6,11 +6,11 @@ parameters: steps: - powershell: | $shouldSign = $true - $authenticodeCert = 'CP-230012' - $msixCert = 'CP-230012' + $authenticodeCert = '$(authenticode_cert_id)' + $msixCert = '$(authenticode_cert_id)' if($env:IS_DAILY -eq 'true') { - $authenticodeCert = 'CP-460906' + $authenticodeCert = '$(authenticode_test_cert_id)' } if($env:SKIP_SIGNING -eq 'Yes') { diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml index 285a9035d0a..399d242aa4b 100644 --- a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -100,7 +100,6 @@ stages: signedDrop: 'drop_linux_sign_linux_fxd_x64_mariner' packageType: rpm-fxdependent #mariner-x64 jobName: mariner_x64 - signingProfile: 'CP-459159-pgpdetached' - template: /.pipelines/templates/linux-package-build.yml@self parameters: @@ -108,7 +107,6 @@ stages: signedDrop: 'drop_linux_sign_linux_fxd_arm64_mariner' packageType: rpm-fxdependent-arm64 #mariner-arm64 jobName: mariner_arm64 - signingProfile: 'CP-459159-pgpdetached' - template: /.pipelines/templates/linux-package-build.yml@self parameters: diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index 83c6b32cdfd..99f1042b17e 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -315,7 +315,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(ob_outputDirectory)\globaltool' condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) diff --git a/tools/packaging/packaging.psd1 b/tools/packaging/packaging.psd1 index 0053428a481..e5b7fb84dfc 100644 --- a/tools/packaging/packaging.psd1 +++ b/tools/packaging/packaging.psd1 @@ -26,6 +26,7 @@ 'Test-PackageManifest' 'Update-PSSignedBuildFolder' 'Test-Bom' + 'Get-MacOSPackageIdentifierInfo' ) RootModule = "packaging.psm1" RequiredModules = @("build") diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index b5f88e8ba6c..2aecee36d27 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -825,6 +825,18 @@ function New-TarballPackage { $Staging = "$PSScriptRoot/staging" New-StagingFolder -StagingPath $Staging -PackageSourcePath $PackageSourcePath -R2RVerification $R2RVerification + # Ensure PowerShell executable has correct permissions in tarball + $pwshInStaging = Join-Path $Staging 'pwsh' + if (Test-Path -LiteralPath $pwshInStaging) { + Start-NativeExecution { chmod 755 $pwshInStaging } + } + + # Included .NET executable for producing crash dumps + $createdumpInStaging = Join-Path $Staging 'createdump' + if (Test-Path -LiteralPath $createdumpInStaging) { + Start-NativeExecution { chmod 755 $createdumpInStaging } + } + if (Get-Command -Name tar -CommandType Application -ErrorAction Ignore) { if ($Force -or $PSCmdlet.ShouldProcess("Create tarball package")) { $options = "-czf" @@ -1243,7 +1255,11 @@ function New-UnixPackage { find $Staging -type f | xargs chmod 644 chmod 644 $ManGzipInfo.GzipFile # refers to executable, does not vary by channel - chmod 755 "$Staging/pwsh" #only the executable file should be granted the execution permission + chmod 755 "$Staging/pwsh" # only the executable file should be granted the execution permission + # Included .NET executable for producing crash dumps + if (Test-Path "$Staging/createdump") { + chmod 755 "$Staging/createdump" + } } } @@ -1923,6 +1939,12 @@ $(if ($extendedDescription) { $extendedDescription + "`n" }) Start-NativeExecution { chmod 755 $pwshPath } } + # Included .NET executable for producing crash dumps + $createdumpPath = "$targetPath/createdump" + if (Test-Path $createdumpPath) { + Start-NativeExecution { chmod 755 $createdumpPath } + } + # Calculate md5sums for all files in data directory (excluding symlinks) $md5sumsFile = Join-Path $debianDir "md5sums" $md5Content = "" From 0ceb11ad68464a8202f4bf5e82e5ffded755249d Mon Sep 17 00:00:00 2001 From: Dongbo Wang <dongbow@microsoft.com> Date: Wed, 13 May 2026 16:13:41 -0700 Subject: [PATCH 124/127] [release/v7.6.2] Update PowerShell telemetry to respect the diagnostics and feedback setting on Windows (#27438) --- .../PowerShell.Core.Instrumentation.man | 202 +++++++++++++++--- .../CoreCLR/CorePsPlatform.cs | 9 +- .../engine/remoting/common/PSETWTracer.cs | 4 + .../utils/Telemetry.cs | 10 +- .../utils/WindowsDataCollectionSetting.cs | 185 ++++++++++++++++ .../engine/Basic/Telemetry.Tests.ps1 | 50 +++++ 6 files changed, 427 insertions(+), 33 deletions(-) create mode 100644 src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs diff --git a/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man b/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man index fb221cfe964..bb4e15351e5 100644 --- a/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man +++ b/src/PowerShell.Core.Instrumentation/PowerShell.Core.Instrumentation.man @@ -121,6 +121,18 @@ value="0x3002" version="1" /> + <!--Telemetry events--> + <event + channel="C_OPERATIONAL" + level="win:Error" + message="$(string.PS_PROVIDER.event.E_O_TelemetrySettingError.message)" + opcode="Exception" + symbol="TelemetrySettingError" + task="Telemetry" + template="T_TelemetrySettingError" + value="0x3011" + version="1" + /> <!--M3P events--> <event channel="C_ANALYTIC" @@ -2208,17 +2220,41 @@ value="0x6017" version="1" /> - <event - channel="C_ANALYTIC" - keywords="AmsiState" - level="win:Verbose" - message="$(string.PS_PROVIDER.event.E_A_AmsiState.message)" - opcode="Method" - symbol="AmsiState" - task="Amsi" - template="T_AmsiState" - value="0x4001" - version="1" + <event + channel="C_ANALYTIC" + keywords="AmsiState" + level="win:Verbose" + message="$(string.PS_PROVIDER.event.E_A_AmsiState.message)" + opcode="Method" + symbol="AmsiState" + task="Amsi" + template="T_AmsiState" + value="0x4001" + version="1" + /> + <event + channel="C_ANALYTIC" + keywords="WDACQuery" + level="win:Verbose" + message="$(string.PS_PROVIDER.event.E_A_WDACQuery.message)" + opcode="Method" + symbol="WDACQuery" + task="WDAC" + template="T_WDACQuery" + value="0x4002" + version="1" + /> + <event + channel="C_ANALYTIC" + keywords="WDACAudit" + level="win:Verbose" + message = "$(string.PS_PROVIDER.event.E_A_WDACAudit.message)" + opcode="Method" + symbol="WDACAudit" + task="WDACAudit" + template="T_WDACAudit" + value="0x4003" + version="1" /> </events> <channels> @@ -2409,6 +2445,12 @@ symbol="T_EXPERIMENTALFEATURE" value="107" /> + <task + message="$(string.PS_PROVIDER.task.T_Telemetry.message)" + name="Telemetry" + symbol="T_TELEMETRY" + value="108" + /> <task message="$(string.PS_PROVIDER.task.T_ScheduledJob.message)" name="ScheduledJob" @@ -2427,11 +2469,23 @@ symbol="T_ISEOperation" value="120" /> - <task - message="$(string.PS_PROVIDER.task.T_AmsiState.message)" - name="Amsi" - symbol="T_Amsi" - value="130" + <task + message="$(string.PS_PROVIDER.task.T_AmsiState.message)" + name="Amsi" + symbol="T_Amsi" + value="130" + /> + <task + message="$(string.PS_PROVIDER.task.T_WDACQuery.message)" + name="WDAC" + symbol="T_WDAC" + value="131" + /> + <task + message="$(string.PS_PROVIDER.task.T_WDACAudit.message)" + name="WDACAudit" + symbol="T_WDACAudit" + value="132" /> </tasks> <opcodes> @@ -2593,11 +2647,23 @@ name="PSWorkflow" symbol="K_PSWORKFLOW" /> - <keyword - mask="0x400" - message="$(string.PS_PROVIDER.keyword.K_AmsiState.message)" - name="AmsiState" - symbol="K_AmsiState" + <keyword + mask="0x400" + message="$(string.PS_PROVIDER.keyword.K_AmsiState.message)" + name="AmsiState" + symbol="K_AmsiState" + /> + <keyword + mask="0x800" + message="$(string.PS_PROVIDER.keyword.K_WDACQuery.message)" + name="WDACQuery" + symbol="K_WDACQuery" + /> + <keyword + mask="0x1000" + message="$(string.PS_PROVIDER.keyword.K_WDACAudit.message)" + name="WDACAudit" + symbol="K_WDACAudit" /> </keywords> <maps> @@ -4004,6 +4070,20 @@ name="StackTrace" /> </template> + <template tid="T_TelemetrySettingError"> + <data + inType="win:UnicodeString" + name="Name" + /> + <data + inType="win:UnicodeString" + name="Message" + /> + <data + inType="win:UnicodeString" + name="StackTrace" + /> + </template> <template tid="T_TrackingGuid"> <data inType="win:GUID" @@ -4080,16 +4160,48 @@ name="FileName" /> </template> - <template tid="T_AmsiState"> - <data - inType="win:UnicodeString" - name="Action" + <template tid="T_AmsiState"> + <data + inType="win:UnicodeString" + name="Action" /> - <data - inType="win:UnicodeString" - name="AmsiContext" + <data + inType="win:UnicodeString" + name="AmsiContext" /> - </template> + </template> + <template tid="T_WDACQuery"> + <data + inType="win:UnicodeString" + name="QueryName" + /> + <data + inType="win:UnicodeString" + name="FileName" + /> + <data + inType="win:Int32" + name="QuerySuccess" + /> + <data + inType="win:Int32" + name="QuerySResult" + /> + </template> + <template tid="T_WDACAudit"> + <data + inType="win:UnicodeString" + name="Title" + /> + <data + inType="win:UnicodeString" + name="Message" + /> + <data + inType="win:UnicodeString" + name="FullyQualifiedId" + /> + </template> </templates> </provider> </events> @@ -5535,6 +5647,14 @@ id="PS_PROVIDER.task.T_ExperimentalFeature.message" value="PowerShell Experimental Features" /> + <string + id="PS_PROVIDER.event.E_O_TelemetrySettingError.message" + value="Failed to retrieve diagnostics and feedback setting from Windows.%n Exception: %1 %n Message: %2 %n StackTrace: %3 %n" + /> + <string + id="PS_PROVIDER.task.T_Telemetry.message" + value="PowerShell Telemetry" + /> <string id="PS_PROVIDER.task.T_NamedPipe.message" value="PowerShell Named Pipe IPC" @@ -5719,6 +5839,30 @@ id="PS_PROVIDER.event.E_O_REMOTE_NAMEDPIPE_DISCONNECT.message" value="PowerShell IPC disconnect on process: %1 in AppDomain: %2 for User: %3." /> + <string + id="PS_PROVIDER.event.E_A_WDACQuery.message" + value="WDAC Query. %n %t Query: %1 %n %t File: %2 %n %t SuccessCode: %3 %n %t ResultCode: %4" + /> + <string + id="PS_PROVIDER.keyword.K_WDACQuery.message" + value="WDAC Query" + /> + <string + id="PS_PROVIDER.task.T_WDACQuery.message" + value="WDAC Query" + /> + <string + id="PS_PROVIDER.event.E_A_WDACAudit.message" + value="WDAC Audit. %n %t Title: %1 %n %t Message: %2 %n %t FullyQualifiedId: %3" + /> + <string + id="PS_PROVIDER.keyword.K_WDACAudit.message" + value="WDAC Audit" + /> + <string + id="PS_PROVIDER.task.T_WDACAudit.message" + value="WDAC Audit" + /> </stringTable> </resources> </localization> diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 530493f320a..36a6be4074b 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -179,9 +179,12 @@ public static bool IsStaSupported { int result = Interop.Windows.CoInitializeEx(IntPtr.Zero, Interop.Windows.COINIT_APARTMENTTHREADED); - // If 0 is returned the thread has been initialized for the first time - // as an STA and thus supported and needs to be uninitialized. - if (result > 0) + // Per COM documentation: Each successful call to CoInitializeEx (including S_FALSE) + // must be balanced by a corresponding call to CoUninitialize. + // - S_OK (0) means we initialized for the first time. + // - S_FALSE (1) means already initialized, but still increments the reference count. + // Both require CoUninitialize to decrement the reference count. + if (result >= 0) { Interop.Windows.CoUninitialize(); } diff --git a/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs b/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs index 2fd2dc0a913..989ad33e987 100644 --- a/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs +++ b/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs @@ -166,6 +166,9 @@ internal enum PSEventId : int ExperimentalFeature_InvalidName = 0x3001, ExperimentalFeature_ReadConfig_Error = 0x3002, + // Windows Diagnostics And Usage Data Settings + Telemetry_Setting_Error = 0x3011, + // Scheduled Jobs ScheduledJob_Start = 0xD001, ScheduledJob_Complete = 0xD002, @@ -240,6 +243,7 @@ internal enum PSTask : int ProviderStop = 0x69, ExecutePipeline = 0x6A, ExperimentalFeature = 0x6B, + Telemetry = 0x6C, ScheduledJob = 0x6E, NamedPipe = 0x6F, ISEOperation = 0x78, diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs index 9a67f4bb6ed..fbb7f588283 100644 --- a/src/System.Management.Automation/utils/Telemetry.cs +++ b/src/System.Management.Automation/utils/Telemetry.cs @@ -177,12 +177,20 @@ public static class ApplicationInsightsTelemetry /// </summary> static ApplicationInsightsTelemetry() { - // If we can't send telemetry, there's no reason to do any of this CanSendTelemetry = !Utils.GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false) && Platform.TryDeriveFromCache("telemetry.uuid", out s_uuidPath); +#if !UNIX + if (CanSendTelemetry) + { + // Respect the diagnostics and feedback setting in Windows. + CanSendTelemetry = WindowsDataCollectionSetting.CanCollectDiagnostics(PlatformDataCollectionLevel.Enhanced); + } +#endif + if (!CanSendTelemetry) { + // Avoid the initialization work if we can't send telemetry. return; } diff --git a/src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs b/src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs new file mode 100644 index 00000000000..5f8b607550a --- /dev/null +++ b/src/System.Management.Automation/utils/WindowsDataCollectionSetting.cs @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#if !UNIX + +using System; +using System.Management.Automation.Internal; +using System.Management.Automation.Tracing; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +namespace Microsoft.PowerShell.Telemetry; + +internal enum PlatformDataCollectionLevel : int +{ + /// <summary> + /// Minimum — only security-related data. Enterprise/education editions only. + /// </summary> + Security = 0, + + /// <summary> + /// Device info, capabilities, and basic reliability data. + /// </summary> + Basic = 1, + + /// <summary> + /// More detailed usage and reliability data, including app/feature usage patterns. + /// Removed as a user-facing option in Windows 11 (collapsed into Full). + /// </summary> + Enhanced = 2, + + /// <summary> + /// All of the above plus advanced diagnostics data that can help Microsoft fix problems. + /// </summary> + Full = 3, +} + +/// <summary> +/// Minimal projection of <c>IInspectable</c>, the base interface for all WinRT objects. +/// Slots 3–5 in every WinRT interface vtable (after <c>IUnknown</c>'s QueryInterface/AddRef/Release). +/// </summary> +[GeneratedComInterface] +[Guid("AF86E2E0-B12D-4C6A-9C5A-D7AA65101E90")] +internal partial interface IInspectable +{ + void GetIids(out uint iidCount, out nint iids); + + nint GetRuntimeClassName(); + + int GetTrustLevel(); +} + +/// <summary> +/// Projection of the WinRT interface <c>Windows.System.Profile.IPlatformDiagnosticsAndUsageDataSettingsStatics</c> +/// (IID B6E24C1B-7B1C-4B32-8C62-A66597CE723A). +/// Vtable slots 6–9, following the three <c>IInspectable</c> slots. +/// </summary> +[GeneratedComInterface] +[Guid("B6E24C1B-7B1C-4B32-8C62-A66597CE723A")] +internal partial interface IPlatformDiagnosticsAndUsageDataSettingsStatics : IInspectable +{ + PlatformDataCollectionLevel GetCollectionLevel(); + + long AddCollectionLevelChanged(nint handler); + + void RemoveCollectionLevelChanged(long token); + + // WinRT marshals bool as a byte; use byte to avoid any MarshalAs ambiguity with the source generator. + byte CanCollectDiagnostics(PlatformDataCollectionLevel level); +} + +/// <summary> +/// Wraps <c>Windows.System.Profile.PlatformDiagnosticsAndUsageDataSettings</c> using compile-time COM interop +/// and source-generated P/Invoke. No extra runtime DLLs are required. +/// </summary> +internal static partial class WindowsDataCollectionSetting +{ + /// <summary> + /// Returns <see langword="true"/> if the device's diagnostic data collection policy permits collecting at or above <paramref name="level"/>. + /// </summary> + /// <param name="level">The minimum <see cref="PlatformDataCollectionLevel"/> to test against.</param> + internal static bool CanCollectDiagnostics(PlatformDataCollectionLevel level) + { + const string ClassName = "Windows.System.Profile.PlatformDiagnosticsAndUsageDataSettings"; + + // When initializing WinRT on the calling thread, use the multi-threaded apartment (MTA). + // This is to cover the case where PowerShell gets used in a thread-pool thread. + // See the doc at https://learn.microsoft.com/windows/win32/api/roapi/ne-roapi-ro_init_type + const int RO_INIT_MULTITHREADED = 1; + + // Return values for 'RoInitialize': + // - S_OK (0) - we successfully initialized; must call 'RoUninitialize'. + // - S_FALSE (1) - already initialized with the same apartment type; must still call 'RoUninitialize'. + // - RPC_E_CHANGED_MODE - already initialized with a different apartment type; WinRT still works, do NOT call 'RoUninitialize'. + const int RPC_E_CHANGED_MODE = unchecked((int)0x80010106); + + int initHr = -1; + nint hstring = default; + nint factoryPtr = default; + + try + { + // Initialize WinRT on the calling thread. 'RoGetActivationFactory' requires it. + initHr = RoInitialize(RO_INIT_MULTITHREADED); + if (initHr < 0 && initHr != RPC_E_CHANGED_MODE) + { + // The call to initialize the Windows Runtime failed. + // Throw an exception with the HRESULT error code to provide more context on the failure. + Marshal.ThrowExceptionForHR(initHr); + } + + Marshal.ThrowExceptionForHR( + WindowsCreateString(ClassName, (uint)ClassName.Length, out hstring)); + + Guid iid = new("B6E24C1B-7B1C-4B32-8C62-A66597CE723A"); + Marshal.ThrowExceptionForHR( + RoGetActivationFactory(hstring, ref iid, out factoryPtr)); + + var comWrappers = new StrategyBasedComWrappers(); + var comObject = comWrappers.GetOrCreateObjectForComInstance(factoryPtr, CreateObjectFlags.None); + var platformSetting = (IPlatformDiagnosticsAndUsageDataSettingsStatics)comObject; + + return platformSetting.CanCollectDiagnostics(level) != 0; + } + catch (Exception ex) + { + // Log any exceptions that occur during this process, but swallow them and return false to disable telemetry rather than crashing the product. + // This API is only used to gate telemetry collection, so failure should be non-fatal. + PSEtwLog.LogOperationalError( + PSEventId.Telemetry_Setting_Error, + PSOpcode.Exception, + PSTask.Telemetry, + PSKeyword.UseAlwaysOperational, + ex.GetType().FullName, + ex.Message, + ex.StackTrace); + + return false; + } + finally + { + if (factoryPtr != default) + { + Marshal.Release(factoryPtr); + } + + if (hstring != default) + { + _ = WindowsDeleteString(hstring); + } + + // Per COM documentation: Each successful call to 'RoInitialize' (including S_FALSE) + // must be balanced by a corresponding call to 'RoUninitialize'. + if (initHr >= 0) + { + RoUninitialize(); + } + } + } + + [LibraryImport("api-ms-win-core-winrt-string-l1-1-0.dll", StringMarshalling = StringMarshalling.Utf16)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int WindowsCreateString( + string sourceString, + uint length, + out nint hstring); + + [LibraryImport("api-ms-win-core-winrt-string-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int WindowsDeleteString(nint hstring); + + [LibraryImport("api-ms-win-core-winrt-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int RoGetActivationFactory(nint activatableClassId, ref Guid iid, out nint factory); + + [LibraryImport("api-ms-win-core-winrt-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial int RoInitialize(int initType); + + [LibraryImport("api-ms-win-core-winrt-l1-1-0.dll")] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static partial void RoUninitialize(); +} + +#endif diff --git a/test/powershell/engine/Basic/Telemetry.Tests.ps1 b/test/powershell/engine/Basic/Telemetry.Tests.ps1 index 2378b9e5a66..0da08316a56 100644 --- a/test/powershell/engine/Basic/Telemetry.Tests.ps1 +++ b/test/powershell/engine/Basic/Telemetry.Tests.ps1 @@ -5,8 +5,53 @@ # these tests aren't going to check that telemetry is being sent # only that we're not treating the telemetry.uuid file correctly +function Get-OSTelemetryLevel { + <# + .SYNOPSIS + Returns the effective Windows Telemetry level (0-3). + Logic: Checks GPO overrides, then System preferences, then defaults to 1. + #> + + $gpoPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection" + $sysPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection" + $valueName = "AllowTelemetry" + + # 1. Check the "Managed" Policy (Group Policy) + if (Test-Path $gpoPath) { + $gpoValue = Get-ItemProperty -Path $gpoPath -Name $valueName -ErrorAction SilentlyContinue + if ($gpoValue -and $gpoValue.$valueName) { + return [int]$gpoValue.$valueName + } + } + + # 2. Check the "User/System" Preference (Settings App) + if (Test-Path $sysPath) { + $sysValue = Get-ItemProperty -Path $sysPath -Name $valueName -ErrorAction SilentlyContinue + if ($sysValue -and $sysValue.$valueName) { + return [int]$sysValue.$valueName + } + } + + # 3. Fallback to OS Default (Basic/Required) + return 1 +} + Describe "Telemetry for shell startup" -Tag CI { BeforeAll { + $skipTelemetryTests = $false + + if ($IsWindows) { + ## Skip telemetry tests if the OS telemetry level is less than 2 (Enhanced) -- PS telemetry is disabled in this case. + $osTelemetryLevel = Get-OSTelemetryLevel + $skipTelemetryTests = $osTelemetryLevel -lt 2 + } + + if ($skipTelemetryTests) { + $originalDefaultParameterValues = $PSDefaultParameterValues.Clone() + $PSDefaultParameterValues["it:skip"] = $true + return + } + # if the telemetry file exists, move it out of the way # the member is internal, but we can retrieve it via reflection $cacheDir = [System.Management.Automation.Platform].GetField("CacheDirectory","NonPublic,Static").GetValue($null) @@ -23,6 +68,11 @@ Describe "Telemetry for shell startup" -Tag CI { } AfterAll { + if ($skipTelemetryTests) { + $global:PSDefaultParameterValues = $originalDefaultParameterValues + return + } + # check and reset the telemetry.uuid file if ( $uuidFileExists ) { if ( Test-Path -Path "${uuidPath}.original" ) { From 43da485fafefaf6bfc2a622e1728a5ccf83a5efe Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 14 May 2026 15:30:03 -0400 Subject: [PATCH 125/127] [release/v7.6.2] Update branch for release (#27446) --- CHANGELOG/v7.6/dependencychanges.json | 13 +++++++++++++ DotnetRuntimeMetadata.json | 2 +- global.json | 2 +- tools/cgmanifest/main/cgmanifest.json | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG/v7.6/dependencychanges.json b/CHANGELOG/v7.6/dependencychanges.json index 0189431db77..a0122c94ac6 100644 --- a/CHANGELOG/v7.6/dependencychanges.json +++ b/CHANGELOG/v7.6/dependencychanges.json @@ -49,5 +49,18 @@ "AdvisoryUrls": [], "Justification": "Required dependency of System.Security.Cryptography.Xml.", "TimestampUtc": "2026-04-16T23:13:22.4500098Z" + }, + { + "ChangeType": "NonSecurity", + "Branch": "release/v7.6.2", + "PackageId": ".NET SDK", + "FromVersion": "10.0.202", + "ToVersion": "10.0.300", + "VulnerabilityId": [], + "Severity": [], + "VulnerableRanges": [], + "AdvisoryUrls": [], + "Justification": "Updated .NET SDK. Building with the latest SDK is required.", + "TimestampUtc": "2026-05-14T17:53:01.1430124Z" } ] diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json index 8b1ed423288..a09be0f382c 100644 --- a/DotnetRuntimeMetadata.json +++ b/DotnetRuntimeMetadata.json @@ -4,7 +4,7 @@ "quality": "daily", "qualityFallback": "preview", "packageVersionPattern": "9.0.0-preview.6", - "sdkImageVersion": "10.0.202", + "sdkImageVersion": "10.0.300", "nextChannel": "9.0.0-preview.7", "azureFeed": "", "sdkImageOverride": "" diff --git a/global.json b/global.json index 5ee7b7cb062..9769786b11b 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "10.0.202" + "version": "10.0.300" } } diff --git a/tools/cgmanifest/main/cgmanifest.json b/tools/cgmanifest/main/cgmanifest.json index fd645029d33..e06492f2e75 100644 --- a/tools/cgmanifest/main/cgmanifest.json +++ b/tools/cgmanifest/main/cgmanifest.json @@ -626,7 +626,7 @@ "Type": "nuget", "Nuget": { "Name": "System.Security.Cryptography.Pkcs", - "Version": "10.0.5" + "Version": "10.0.6" } }, "DevelopmentDependency": false From 0d3c290a8737d4252ee75c052d16190ffcdb7d19 Mon Sep 17 00:00:00 2001 From: PowerShell Team Bot <69177312+pwshBot@users.noreply.github.com> Date: Thu, 21 May 2026 13:59:17 -0400 Subject: [PATCH 126/127] Update 7.6 changelog for v7.6.2 (#27471) --- CHANGELOG/7.6.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/CHANGELOG/7.6.md b/CHANGELOG/7.6.md index a4d81683321..da1370779cc 100644 --- a/CHANGELOG/7.6.md +++ b/CHANGELOG/7.6.md @@ -1,5 +1,47 @@ # 7.6 Changelog +## [7.6.2] + +### Engine Updates and Fixes + +- Enable usage in AppContainers (#27423) +- Fix checks for local user config file paths (#27432) + +### General Cmdlet Updates and Fixes + +- Update PowerShell telemetry to respect the diagnostics and feedback setting on Windows (#27438) + +### Build and Packaging Improvements + +<details> + +<summary> + +<p>Update to .NET SDK 10.0.300</p> + +</summary> + +<ul> +<li>Update branch for release (#27446)</li> +<li>Fix *nix permissions and use <code>certificate_logical_to_actual</code> (#27439)</li> +<li>Specify linux-arm64 runtime if package type is deb-arm64 in packaging.psm1 (#27440)</li> +<li>Remove mariner2.0 from PMC mapping (#27422)</li> +<li>Remove package verification from the notice pipeline (#27425)</li> +<li>Update the MSIXBundle-VPack pipeline to create VPack for both LTS and Stable channel packages (#27435)</li> +<li>Update <code>Microsoft.PowerShell.Native</code> to the latest GA version (#27436)</li> +<li>Create PowerShell package for arm debian distribution (#27433)</li> +<li>Add macOS binary code signing and package notarization (#27434)</li> +<li>Externalize <code>findMissingNotices</code> target framework selection with ordered Windows fallback (#27424)</li> +<li>Add <code>appLicensing</code> capability to Appx manifest (#27437)</li> +<li>Download PMC Packages through <code>TemplateContext</code> (#27331)</li> +<li>PMC release: Use slash instead of back-slash for Linux container (#27319)</li> +<li>Correct Variable Template Reference in NonOfficial Pipeline Templates (#27317)</li> +</ul> + +</details> + +[7.6.2]: https://github.com/PowerShell/PowerShell/compare/v7.6.1...v7.6.2 + ## [7.6.1] ### General Cmdlet Updates and Fixes From aa424e47ad4f5c84d2da9c01fbfb77b25b27fcce Mon Sep 17 00:00:00 2001 From: Patrick Meinecke <SeeminglyScience@users.noreply.github.com> Date: Thu, 21 May 2026 20:22:48 -0400 Subject: [PATCH 127/127] [release/v7.6.2] Remove unused step to clone Internal-PowerShellTeam-Tools repo in PMC publish pipeline (#27496) Co-authored-by: Anam Navied <anam.naviyou@gmail.com> --- .pipelines/templates/release-prep-for-ev2.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.pipelines/templates/release-prep-for-ev2.yml b/.pipelines/templates/release-prep-for-ev2.yml index 3ad716a3af4..ace2b8f7df4 100644 --- a/.pipelines/templates/release-prep-for-ev2.yml +++ b/.pipelines/templates/release-prep-for-ev2.yml @@ -59,20 +59,6 @@ stages: env: ob_restore_phase: true - - pwsh: | - $branch = 'mirror-target' - $gitArgs = "clone", - "--verbose", - "--branch", - "$branch", - "https://$(mscodehubCodeReadPat)@mscodehub.visualstudio.com/PowerShellCore/_git/Internal-PowerShellTeam-Tools", - '$(Pipeline.Workspace)/tools' - $gitArgs | Write-Verbose -Verbose - git $gitArgs - displayName: Clone Internal-PowerShellTeam-Tools from MSCodeHub - env: - ob_restore_phase: true - - pwsh: | Get-ChildItem Env: | Out-String -Stream | write-Verbose -Verbose displayName: 'Capture Environment Variables'