diff --git a/.github/workflows/collect-and-screen.yml b/.github/workflows/collect-and-screen.yml index 8a404e350..88eb6d4ec 100644 --- a/.github/workflows/collect-and-screen.yml +++ b/.github/workflows/collect-and-screen.yml @@ -7,10 +7,10 @@ permissions: on: workflow_dispatch: inputs: - since-days: - description: "Look at PRs merged within the last N days" + weeks-ago: + description: "Collect PRs merged during the ISO week N weeks back (1 = last completed week)" required: false - default: "7" + default: "1" type: string repo: description: "Source GitHub repository (OWNER/REPO)" @@ -53,8 +53,15 @@ jobs: run: | $ErrorActionPreference = 'Stop' - $week = [System.Globalization.ISOWeek]::GetWeekOfYear((Get-Date).ToUniversalTime()).ToString('00') - $branch = "dataset/week-$week" + Import-Module ./scripts/BCBenchUtils.psm1 -Force + + # Label the branch/PR with the ISO week the candidates were merged in — the last + # completed week — not the week the job happens to run in. + $window = Get-IsoWeekWindow -WeeksAgo ${{ inputs.weeks-ago || '1' }} + $branch = "dataset/week-$($window.Label)" + $mergedSince = $window.Start.ToString('yyyy-MM-ddTHH:mm:ssZ') + $mergedUntil = $window.End.ToString('yyyy-MM-ddTHH:mm:ssZ') + Write-Host "Collecting PRs merged in ISO week $($window.Label): $mergedSince .. $mergedUntil" git config user.name 'github-actions[bot]' git config user.email 'github-actions[bot]@users.noreply.github.com' @@ -62,12 +69,16 @@ jobs: .\scripts\Collect-And-Screen.ps1 ` -Repo '${{ inputs.repo || 'microsoft/BCApps' }}' ` - -SinceDays ${{ inputs.since-days || '7' }} ` + -MergedSince $mergedSince ` + -MergedUntil $mergedUntil ` -Limit ${{ inputs.limit || '50' }} ` -BaseBranch '${{ inputs.base-branch || 'main' }}' ` -SummaryFile $env:GITHUB_STEP_SUMMARY ` -CollectedFile "$PWD/collected.json" + Add-Content -Path $env:GITHUB_OUTPUT -Value "merged-since=$mergedSince" + Add-Content -Path $env:GITHUB_OUTPUT -Value "merged-until=$mergedUntil" + if (-not (git status --porcelain)) { Write-Host 'No dataset changes; nothing to push.' Add-Content -Path $env:GITHUB_OUTPUT -Value 'branch=' @@ -199,7 +210,9 @@ jobs: -JobsFile jobs.json ` -RunUrl '${{ steps.validate.outputs.run-url }}' ` -Repo $repo ` - -Week $week | Set-Content -Path pr-body.md -Encoding utf8 + -Week $week ` + -MergedSince '${{ steps.run.outputs.merged-since }}' ` + -MergedUntil '${{ steps.run.outputs.merged-until }}' | Set-Content -Path pr-body.md -Encoding utf8 $title = "Dataset refresh: week $week candidates from $repo" $existing = gh pr list --head $branch --state open --json number --jq '.[0].number // empty' diff --git a/scripts/BCBenchUtils.psm1 b/scripts/BCBenchUtils.psm1 index a8a02cf9c..f0900b6c5 100644 --- a/scripts/BCBenchUtils.psm1 +++ b/scripts/BCBenchUtils.psm1 @@ -589,4 +589,44 @@ function Get-LatestReleaseBranch { return $latest.Name } -Export-ModuleMember -Function Get-BCCredential, Invoke-GitCloneWithRetry, Get-EnvironmentVariable, Write-Log, Invoke-GitApplyPatch, Update-AppProjectVersion, Get-BCBenchDatasetPath, Get-BCBenchEntryVersion, Get-RepoCloneInfo, Get-LatestReleaseBranch +<# +.SYNOPSIS + Resolves the UTC bounds and label of a completed ISO-8601 week. +.DESCRIPTION + Returns the Monday 00:00:00 UTC start and Sunday 23:59:59 UTC end of the ISO week that + is $WeeksAgo weeks before $ReferenceDate, so a weekly job labelled "week N" collects + exactly the work merged during week N instead of a trailing window that straddles two + weeks. $ReferenceDate is interpreted as UTC. +.PARAMETER ReferenceDate + Date the window is measured back from. Defaults to now (UTC). +.PARAMETER WeeksAgo + How many weeks back to go. 1 (default) is the last completed week. +.OUTPUTS + PSCustomObject with Year, Week, Label ("2026-29"), Start and End (UTC DateTime). +.EXAMPLE + $window = Get-IsoWeekWindow -WeeksAgo 1 +#> +function Get-IsoWeekWindow { + [CmdletBinding()] + [OutputType([pscustomobject])] + param( + [datetime]$ReferenceDate = [datetime]::UtcNow, + [int]$WeeksAgo = 1 + ) + + $shifted = $ReferenceDate.Date.AddDays(-7 * $WeeksAgo) + $daysSinceMonday = ([int]$shifted.DayOfWeek + 6) % 7 + $start = [datetime]::SpecifyKind($shifted.AddDays(-$daysSinceMonday), [DateTimeKind]::Utc) + $year = [System.Globalization.ISOWeek]::GetYear($start) + $week = [System.Globalization.ISOWeek]::GetWeekOfYear($start) + + [pscustomobject]@{ + Year = $year + Week = $week + Label = '{0}-{1:00}' -f $year, $week + Start = $start + End = $start.AddDays(7).AddSeconds(-1) + } +} + +Export-ModuleMember -Function Get-BCCredential, Invoke-GitCloneWithRetry, Get-EnvironmentVariable, Write-Log, Invoke-GitApplyPatch, Update-AppProjectVersion, Get-BCBenchDatasetPath, Get-BCBenchEntryVersion, Get-RepoCloneInfo, Get-LatestReleaseBranch, Get-IsoWeekWindow diff --git a/scripts/Collect-And-Screen.ps1 b/scripts/Collect-And-Screen.ps1 index 5219b2f0c..f52ff073a 100644 --- a/scripts/Collect-And-Screen.ps1 +++ b/scripts/Collect-And-Screen.ps1 @@ -11,8 +11,17 @@ the working tree. Committing/pushing is left to the caller (e.g. the .PARAMETER Repo Source GitHub repository (OWNER/REPO). Defaults to microsoft/BCApps. -.PARAMETER SinceDays -Look at PRs merged within the last N days. +.PARAMETER MergedSince +Only consider PRs merged at or after this UTC timestamp (yyyy-MM-ddTHH:mm:ssZ). +Defaults to the start of the ISO week selected by -WeeksAgo. + +.PARAMETER MergedUntil +Only consider PRs merged at or before this UTC timestamp (yyyy-MM-ddTHH:mm:ssZ). +Defaults to the end of the ISO week selected by -WeeksAgo. + +.PARAMETER WeeksAgo +Which completed ISO week to collect when -MergedSince/-MergedUntil are omitted. +1 (default) is the last completed week. .PARAMETER Limit Maximum number of merged PRs to consider. @@ -24,13 +33,15 @@ Only consider PRs merged into this base branch. Defaults to main. Optional path to append a markdown summary to (e.g. $env:GITHUB_STEP_SUMMARY). .EXAMPLE -.\scripts\Collect-And-Screen.ps1 -SinceDays 2 -Limit 5 +.\scripts\Collect-And-Screen.ps1 -WeeksAgo 1 -Limit 5 #> [CmdletBinding()] param( [string]$Repo = 'microsoft/BCApps', - [int]$SinceDays = 7, + [string]$MergedSince, + [string]$MergedUntil, + [int]$WeeksAgo = 1, [int]$Limit = 200, [string]$BaseBranch = 'main', [string]$SummaryFile, @@ -41,18 +52,35 @@ $ErrorActionPreference = 'Stop' Import-Module (Join-Path $PSScriptRoot 'BCBenchUtils.psm1') -Force +$window = Get-IsoWeekWindow -WeeksAgo $WeeksAgo +$timestampFormat = 'yyyy-MM-ddTHH:mm:ssZ' +if (-not $MergedSince) { $MergedSince = $window.Start.ToString($timestampFormat) } +if (-not $MergedUntil) { $MergedUntil = $window.End.ToString($timestampFormat) } + +function ConvertTo-UtcDateTime { + param([string]$Value) + [datetime]::Parse($Value, [cultureinfo]::InvariantCulture, + [System.Globalization.DateTimeStyles]::AdjustToUniversal -bor [System.Globalization.DateTimeStyles]::AssumeUniversal) +} + +$sinceUtc = ConvertTo-UtcDateTime $MergedSince +$untilUtc = ConvertTo-UtcDateTime $MergedUntil +if ($untilUtc -le $sinceUtc) { throw "MergedUntil ($MergedUntil) must be after MergedSince ($MergedSince)" } + +$isoWeek = Get-IsoWeekWindow -ReferenceDate $sinceUtc -WeeksAgo 0 +$weekLabel = if ($isoWeek.Start -eq $sinceUtc -and $isoWeek.End -eq $untilUtc) { " (ISO week $($isoWeek.Label))" } else { '' } + $latestRelease = Get-LatestReleaseBranch -Repo $Repo if (-not $latestRelease) { throw "No releases/* branch found in $Repo" } $envVersion = $latestRelease -replace '^releases/', '' Write-Log "Latest release branch in $Repo`: $latestRelease (environment_setup_version=$envVersion)" -Level Info -$since = (Get-Date).ToUniversalTime().AddDays(-$SinceDays).ToString('yyyy-MM-dd') -Write-Log "Searching merged PRs in $Repo (base: $BaseBranch) since $since (limit $Limit)" -Level Info +Write-Log "Searching merged PRs in $Repo (base: $BaseBranch) merged $MergedSince..$MergedUntil$weekLabel (limit $Limit)" -Level Info $requiredLabel = 'AL: Apps (W1)' $jqFilter = "[.[] | select((.labels | length) == 1 and .labels[0].name == `"$requiredLabel`") | .number]" $prsJson = & gh pr list --repo $Repo --state merged --base $BaseBranch --label $requiredLabel ` - --search "merged:>=$since" --limit $Limit --json 'number,labels' --jq $jqFilter + --search "merged:$MergedSince..$MergedUntil" --limit $Limit --json 'number,labels' --jq $jqFilter if ($LASTEXITCODE -ne 0) { throw "gh pr list failed" } [int[]]$prs = ($prsJson | ConvertFrom-Json) @@ -94,7 +122,7 @@ if ($SummaryFile) { $summary += '' $summary += "Env: ``$envVersion``" $summary += '' - $summary += "Window: last $SinceDays day(s) (since $since)" + $summary += "Window: $MergedSince .. $MergedUntil$weekLabel" $summary += '' $summary += "Considered: $($prs.Count)" $summary += '' diff --git a/scripts/New-DatasetPrBody.ps1 b/scripts/New-DatasetPrBody.ps1 index 430014c3a..d33d20867 100644 --- a/scripts/New-DatasetPrBody.ps1 +++ b/scripts/New-DatasetPrBody.ps1 @@ -14,7 +14,9 @@ param( [string]$JobsFile, [string]$RunUrl, [Parameter(Mandatory)][string]$Repo, - [Parameter(Mandatory)][string]$Week + [Parameter(Mandatory)][string]$Week, + [string]$MergedSince, + [string]$MergedUntil ) $ErrorActionPreference = 'Stop' @@ -47,8 +49,10 @@ function Format-EntryLine { $passed = @($entries | Where-Object { $j = $jobMap[[string]$_.Id]; $j -and $j.conclusion -eq 'success' }) $failed = @($entries | Where-Object { $j = $jobMap[[string]$_.Id]; -not ($j -and $j.conclusion -eq 'success') }) +$mergeWindow = if ($MergedSince -and $MergedUntil) { " (merged $MergedSince .. $MergedUntil)" } else { '' } + $lines = @( - "Automated dataset refresh: bug-fix candidates collected from ``$Repo`` for ISO week $Week.", + "Automated dataset refresh: bug-fix candidates collected from ``$Repo`` for ISO week $Week$mergeWindow.", '', '## ✅ Included (passed validation)', '',