Skip to content

Commit 8ccf14f

Browse files
committed
ci(release): restore nightly beta publisher [skip changelog] (2026.6.17.1-0DE8)
1 parent a9ee89e commit 8ccf14f

5 files changed

Lines changed: 282 additions & 0 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env pwsh
2+
[CmdletBinding()]
3+
param(
4+
[string] $RepoRoot = (Get-Location).Path,
5+
[datetime] $NowUtc = ([datetime]::UtcNow),
6+
[string] $OutputPath = $env:GITHUB_OUTPUT
7+
)
8+
9+
$ErrorActionPreference = "Stop"
10+
Set-StrictMode -Version Latest
11+
12+
function Invoke-Git {
13+
param([Parameter(Mandatory=$true)][string[]] $Arguments, [switch] $AllowFailure)
14+
15+
$previousPreference = $ErrorActionPreference
16+
$ErrorActionPreference = "Continue"
17+
try {
18+
$output = & git @Arguments 2>$null
19+
$exitCode = $LASTEXITCODE
20+
}
21+
finally {
22+
$ErrorActionPreference = $previousPreference
23+
}
24+
25+
if ($exitCode -ne 0) {
26+
if ($AllowFailure) {
27+
return $null
28+
}
29+
throw "git $($Arguments -join ' ') failed with exit code $exitCode"
30+
}
31+
return @($output)
32+
}
33+
34+
function Get-FirstOutput {
35+
param($Value)
36+
37+
$items = @($Value)
38+
if ($items.Count -eq 0) {
39+
return $null
40+
}
41+
return [string]$items[0]
42+
}
43+
44+
function Get-CentralTimeZone {
45+
foreach ($id in @("Central Standard Time", "America/Chicago")) {
46+
try {
47+
return [System.TimeZoneInfo]::FindSystemTimeZoneById($id)
48+
}
49+
catch {
50+
}
51+
}
52+
throw "Could not resolve the America/Chicago release time zone."
53+
}
54+
55+
function Get-DateStamp {
56+
param([datetime] $Utc)
57+
58+
if ($Utc.Kind -ne [System.DateTimeKind]::Utc) {
59+
$Utc = $Utc.ToUniversalTime()
60+
}
61+
$central = [System.TimeZoneInfo]::ConvertTimeFromUtc($Utc, (Get-CentralTimeZone))
62+
return $central.ToString("yyyy.M.d", [System.Globalization.CultureInfo]::InvariantCulture)
63+
}
64+
65+
function Get-NextRevision {
66+
param([string] $DateStamp)
67+
68+
$escapedDate = [regex]::Escape($DateStamp)
69+
$pattern = "^v$escapedDate\.(\d+)(-[A-Za-z0-9][A-Za-z0-9.-]*)?$"
70+
$tags = @(Invoke-Git -Arguments @("tag", "--list", "v$DateStamp.*"))
71+
$highest = -1
72+
foreach ($tag in $tags) {
73+
if ($tag -match $pattern) {
74+
$value = [int]$Matches[1]
75+
if ($value -gt $highest) {
76+
$highest = $value
77+
}
78+
}
79+
}
80+
return $highest + 1
81+
}
82+
83+
function Write-OutputValue {
84+
param([string] $Name, [string] $Value)
85+
86+
$line = "$Name=$Value"
87+
Write-Host $line
88+
if (-not [string]::IsNullOrWhiteSpace($OutputPath)) {
89+
Add-Content -LiteralPath $OutputPath -Value $line -Encoding UTF8
90+
}
91+
}
92+
93+
$resolvedRoot = (Resolve-Path -LiteralPath $RepoRoot).Path
94+
Push-Location $resolvedRoot
95+
try {
96+
$head = (Get-FirstOutput -Value (Invoke-Git -Arguments @("rev-parse", "HEAD"))).Trim()
97+
$latestTagOutput = Get-FirstOutput -Value (Invoke-Git -Arguments @("describe", "--tags", "--abbrev=0", "--match", "v*", "HEAD") -AllowFailure)
98+
$latestTag = ""
99+
if (-not [string]::IsNullOrWhiteSpace($latestTagOutput)) {
100+
$latestTag = $latestTagOutput.Trim()
101+
}
102+
103+
if ([string]::IsNullOrWhiteSpace($latestTag)) {
104+
$commitCount = [int]((Get-FirstOutput -Value (Invoke-Git -Arguments @("rev-list", "--count", "--no-merges", "HEAD"))).Trim())
105+
} else {
106+
$commitCount = [int]((Get-FirstOutput -Value (Invoke-Git -Arguments @("rev-list", "--count", "--no-merges", "$latestTag..HEAD"))).Trim())
107+
}
108+
109+
$hasChanges = $commitCount -gt 0
110+
$dateStamp = Get-DateStamp -Utc $NowUtc
111+
$revision = Get-NextRevision -DateStamp $dateStamp
112+
$nextTag = "v$dateStamp.$revision-beta"
113+
114+
Write-OutputValue -Name "has_changes" -Value $hasChanges.ToString().ToLowerInvariant()
115+
Write-OutputValue -Name "commit_count" -Value ([string]$commitCount)
116+
Write-OutputValue -Name "latest_tag" -Value $latestTag
117+
Write-OutputValue -Name "head_sha" -Value $head
118+
Write-OutputValue -Name "next_tag" -Value $nextTag
119+
}
120+
finally {
121+
Pop-Location
122+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env pwsh
2+
[CmdletBinding()]
3+
param()
4+
5+
$ErrorActionPreference = "Stop"
6+
7+
$scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
8+
$planner = Join-Path $scriptRoot "Get-NightlyBetaPlan.ps1"
9+
10+
function Invoke-TestGit {
11+
param([string] $RepoRoot, [string[]] $Arguments)
12+
13+
Push-Location $RepoRoot
14+
try {
15+
$output = & git @Arguments
16+
if ($LASTEXITCODE -ne 0) {
17+
throw "git $($Arguments -join ' ') failed with exit code $LASTEXITCODE"
18+
}
19+
return @($output)
20+
}
21+
finally {
22+
Pop-Location
23+
}
24+
}
25+
26+
function New-TestRepo {
27+
$root = Join-Path ([System.IO.Path]::GetTempPath()) ("vrcinventory-nightly-beta-" + [System.Guid]::NewGuid().ToString("N"))
28+
New-Item -ItemType Directory -Path $root | Out-Null
29+
Invoke-TestGit -RepoRoot $root -Arguments @("init", "-q", ".") | Out-Null
30+
Invoke-TestGit -RepoRoot $root -Arguments @("config", "user.name", "VRCInventoryManager Tests") | Out-Null
31+
Invoke-TestGit -RepoRoot $root -Arguments @("config", "user.email", "vrcinventory-tests@example.invalid") | Out-Null
32+
Set-Content -LiteralPath (Join-Path $root "sample.txt") -Value "base" -Encoding ASCII
33+
Invoke-TestGit -RepoRoot $root -Arguments @("add", ".") | Out-Null
34+
Invoke-TestGit -RepoRoot $root -Arguments @("commit", "-q", "-m", "initial") | Out-Null
35+
return $root
36+
}
37+
38+
function Read-Outputs {
39+
param([string] $Path)
40+
41+
$values = @{}
42+
foreach ($line in Get-Content -LiteralPath $Path) {
43+
if ($line -match '^([^=]+)=(.*)$') {
44+
$values[$Matches[1]] = $Matches[2]
45+
}
46+
}
47+
return $values
48+
}
49+
50+
function Invoke-Planner {
51+
param([string] $RepoRoot)
52+
53+
$outputPath = Join-Path $RepoRoot "outputs.txt"
54+
& $planner -RepoRoot $RepoRoot -NowUtc ([datetime]::Parse("2026-06-16T12:00:00Z")) -OutputPath $outputPath | Out-Host
55+
return Read-Outputs -Path $outputPath
56+
}
57+
58+
$tempRoots = New-Object System.Collections.Generic.List[string]
59+
try {
60+
$repo = New-TestRepo
61+
$tempRoots.Add($repo) | Out-Null
62+
$first = Invoke-Planner -RepoRoot $repo
63+
if ($first["has_changes"] -ne "true") { throw "Planner should publish when no tag exists." }
64+
if ($first["next_tag"] -ne "v2026.6.16.0-beta") { throw "Planner chose unexpected first beta tag: $($first["next_tag"])" }
65+
66+
Invoke-TestGit -RepoRoot $repo -Arguments @("tag", "v2026.6.16.0-beta") | Out-Null
67+
Remove-Item -LiteralPath (Join-Path $repo "outputs.txt") -Force
68+
$sameHead = Invoke-Planner -RepoRoot $repo
69+
if ($sameHead["has_changes"] -ne "false") { throw "Planner should skip when latest tag is at HEAD." }
70+
71+
Set-Content -LiteralPath (Join-Path $repo "sample.txt") -Value "changed" -Encoding ASCII
72+
Invoke-TestGit -RepoRoot $repo -Arguments @("add", ".") | Out-Null
73+
Invoke-TestGit -RepoRoot $repo -Arguments @("commit", "-q", "-m", "feat: new nightly input") | Out-Null
74+
Remove-Item -LiteralPath (Join-Path $repo "outputs.txt") -Force
75+
$changed = Invoke-Planner -RepoRoot $repo
76+
if ($changed["has_changes"] -ne "true") { throw "Planner should publish after commits since latest tag." }
77+
if ($changed["next_tag"] -ne "v2026.6.16.1-beta") { throw "Planner chose unexpected second beta tag: $($changed["next_tag"])" }
78+
79+
Write-Host "Nightly beta planner tests passed."
80+
}
81+
finally {
82+
foreach ($tempRoot in $tempRoots) {
83+
if (Test-Path -LiteralPath $tempRoot) {
84+
Remove-Item -LiteralPath $tempRoot -Recurse -Force
85+
}
86+
}
87+
}

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ jobs:
9393
./.github/scripts/Test-UpdateChangelog.ps1
9494
./.github/scripts/Test-GenerateReleaseNotes.ps1
9595
./.github/scripts/Test-ReleaseVersionSequence.ps1
96+
./.github/scripts/Test-NightlyBetaPlan.ps1
9697
9798
- name: Restore
9899
run: dotnet restore VRCInventoryManager.slnx

.github/workflows/nightly-beta.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Nightly Beta Releases
2+
3+
on:
4+
schedule:
5+
- cron: '45 5 * * *'
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: write
10+
11+
concurrency:
12+
group: nightly-beta-release
13+
cancel-in-progress: false
14+
15+
jobs:
16+
tag:
17+
name: create beta tag when app changed
18+
runs-on: windows-2025-vs2026
19+
timeout-minutes: 10
20+
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v6
24+
with:
25+
fetch-depth: 0
26+
persist-credentials: false
27+
28+
- name: Validate planner
29+
shell: pwsh
30+
run: |
31+
./.github/scripts/Test-WorkflowSyntax.ps1
32+
./.github/scripts/Test-NightlyBetaPlan.ps1
33+
./.github/scripts/Test-ReleaseVersionSequence.ps1
34+
35+
- name: Plan nightly beta
36+
id: plan
37+
shell: pwsh
38+
run: |
39+
git fetch --tags --force
40+
./.github/scripts/Get-NightlyBetaPlan.ps1
41+
42+
- name: Report no changes
43+
if: ${{ steps.plan.outputs.has_changes != 'true' }}
44+
shell: pwsh
45+
run: Write-Host "No app changes since the latest release tag."
46+
47+
- name: Push beta tag
48+
if: ${{ steps.plan.outputs.has_changes == 'true' }}
49+
shell: pwsh
50+
env:
51+
RELEASE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52+
TAG_NAME: ${{ steps.plan.outputs.next_tag }}
53+
COMMIT_COUNT: ${{ steps.plan.outputs.commit_count }}
54+
run: |
55+
if ([string]::IsNullOrWhiteSpace($env:RELEASE_TOKEN)) {
56+
throw "GITHUB_TOKEN is required to push beta tags."
57+
}
58+
if ([string]::IsNullOrWhiteSpace($env:TAG_NAME)) {
59+
throw "Planner did not return a beta tag."
60+
}
61+
62+
git config user.name "github-actions[bot]"
63+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
64+
git tag -a $env:TAG_NAME -m "VRCInventoryManager nightly beta $env:TAG_NAME"
65+
if ($LASTEXITCODE -ne 0) { throw "Could not create beta tag $env:TAG_NAME" }
66+
67+
$remote = "https://x-access-token:$env:RELEASE_TOKEN@github.com/${{ github.repository }}.git"
68+
git push $remote "refs/tags/$env:TAG_NAME"
69+
if ($LASTEXITCODE -ne 0) { throw "Could not push beta tag $env:TAG_NAME" }
70+
71+
Write-Host "Pushed $env:TAG_NAME for $env:COMMIT_COUNT commit(s)."

lint.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Invoke-Step -Name "workflow script syntax" -Command {
5252
./.github/scripts/Test-UpdateChangelog.ps1
5353
./.github/scripts/Test-GenerateReleaseNotes.ps1
5454
./.github/scripts/Test-ReleaseVersionSequence.ps1
55+
./.github/scripts/Test-NightlyBetaPlan.ps1
5556
}
5657

5758
if (-not $NoRestore) {

0 commit comments

Comments
 (0)