Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 87 additions & 26 deletions tools/releaseTools.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ $Script:powershell_team = @(
"dependabot-preview[bot]"
"dependabot[bot]"
"github-actions[bot]"
"Copilot"
"Anam Navied"
"Andrew Schwartzmeyer"
"Jason Helmick"
Expand All @@ -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 = @(
Comment thread
daxian-dbw marked this conversation as resolved.
'andyleejordan'
'TravisEz13'
'daxian-dbw'
'adityapatwardhan'
'SteveL-MSFT'
'dependabot[bot]'
'pwshBot'
'jshigetomi'
'SeeminglyScience'
'anamnavi'
'sdwheeler'
'Copilot'
Copy link
Copy Markdown
Collaborator

@iSazonov iSazonov Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot is not the real author. He should have been replaced by the true initiator.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We won't go that far. The initiator is not necessarily the one that drives it to the end, so it would be tricky to determine who should actually get the credit. Given that MS spends compute resources for a Copilot PR, we may just consider it MS' credit 😆

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe "Assignees" property of PR contains right value if remove Copilot. Is this the same that you do here for backport?

Copy link
Copy Markdown
Member Author

@daxian-dbw daxian-dbw Dec 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, for backport PRs, the description template has Triggered by @<user-doing-backport> on behalf of @<original-author>. This PR simply matches that pattern from the backport PR description to get the original author.

'copilot-swe-agent'
'app/copilot-swe-agent'
'StevenBucher98'
'alerickson'
'tgauth'
)
Comment thread
daxian-dbw marked this conversation as resolved.

# 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"
Expand All @@ -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'
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name dependabot[bot] is already included in powershell_team, so this check is no longer needed. Also, the email has now changed to <numbers>+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,
Expand Down Expand Up @@ -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
}
}
Comment thread
daxian-dbw marked this conversation as resolved.

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"
Comment thread
daxian-dbw marked this conversation as resolved.
}

$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"
Comment thread
daxian-dbw marked this conversation as resolved.
Comment thread
daxian-dbw marked this conversation as resolved.
}
}

if ($commit.AuthorGitHubLogin) {
if ($script:psteam_logins -contains $commit.AuthorGitHubLogin) {
Comment thread
daxian-dbw marked this conversation as resolved.
$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))
}

Expand All @@ -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-"}
Expand Down Expand Up @@ -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'" }
}
}
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -867,8 +928,8 @@ function Invoke-PRBackport {
)
$continue = $false
while(!$continue) {
$input= Read-Host -Prompt ($Message + "`nType 'Yes<enter>' to continue 'No<enter>' to exit")
switch($input) {
$value = Read-Host -Prompt ($Message + "`nType 'Yes<enter>' to continue 'No<enter>' to exit")
switch($value) {
'yes' {
$continue= $true
}
Expand Down
Loading