Skip to content

Commit 2400be3

Browse files
Add release.yml.
1 parent ec70ad3 commit 2400be3

1 file changed

Lines changed: 130 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- '*'
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
issues: write
12+
13+
jobs:
14+
release:
15+
runs-on: windows-latest
16+
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
with:
21+
fetch-depth: 0
22+
persist-credentials: true
23+
24+
- name: Get tag and commit message
25+
id: tag-info
26+
shell: pwsh
27+
run: |
28+
$tag = ($env:GITHUB_REF -split '/')[ -1 ]
29+
Write-Host "Tag: $tag"
30+
git fetch --tags
31+
$commit = (git rev-list -n 1 $tag).Trim()
32+
Write-Host "Commit: $commit"
33+
$rawBody = git show -s --format=%B $commit
34+
# Strip the first non-blank line (commit summary) and any intervening blank lines,
35+
# starting notes from the second non-blank line onward.
36+
$lines = $rawBody -split '(?:\r\n|\n|\r)'
37+
$nonBlank = @()
38+
for ($i = 0; $i -lt $lines.Count; $i++) {
39+
if ($lines[$i].Trim() -ne '') { $nonBlank += $i }
40+
}
41+
if ($nonBlank.Count -ge 2) {
42+
$start = $nonBlank[1]
43+
$notesLines = $lines[$start..($lines.Count - 1)]
44+
$body = ($notesLines -join "`n")
45+
} else {
46+
# No body content beyond a single-line summary
47+
$body = ''
48+
}
49+
$norm = $tag -replace '^v',''
50+
# Use a unique delimiter for multiline output to GITHUB_OUTPUT to avoid collisions
51+
$delim = [guid]::NewGuid().ToString()
52+
Add-Content -Path $env:GITHUB_OUTPUT -Value "tag=$tag"
53+
Add-Content -Path $env:GITHUB_OUTPUT -Value "body<<$delim"
54+
Add-Content -Path $env:GITHUB_OUTPUT -Value $body
55+
Add-Content -Path $env:GITHUB_OUTPUT -Value $delim
56+
Add-Content -Path $env:GITHUB_OUTPUT -Value "norm_tag=$norm"
57+
58+
- name: Create GitHub release
59+
uses: actions/create-release@v1
60+
env:
61+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
62+
with:
63+
tag_name: ${{ steps.tag-info.outputs.tag }}
64+
release_name: ${{ steps.tag-info.outputs.norm_tag }}
65+
body: ${{ steps.tag-info.outputs.body }}
66+
draft: false
67+
prerelease: false
68+
69+
- name: Update docs/CHANGELOG.html and close milestone
70+
shell: pwsh
71+
env:
72+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
73+
run: |
74+
$tag = '${{ steps.tag-info.outputs.tag }}'
75+
$norm = '${{ steps.tag-info.outputs.norm_tag }}'
76+
git fetch --tags --prune
77+
$commit = (git rev-list -n 1 $tag).Trim()
78+
$rawBody = git show -s --format=%B $commit
79+
# Strip the first non-blank line (commit summary) and any intervening blank lines,
80+
# starting notes from the second non-blank line onward.
81+
$lines = $rawBody -split '(?:\r\n|\n|\r)'
82+
$nonBlank = @()
83+
for ($i = 0; $i -lt $lines.Count; $i++) {
84+
if ($lines[$i].Trim() -ne '') { $nonBlank += $i }
85+
}
86+
if ($nonBlank.Count -ge 2) {
87+
$start = $nonBlank[1]
88+
$notesLines = $lines[$start..($lines.Count - 1)]
89+
$body = ($notesLines -join "`n")
90+
} else {
91+
$body = ''
92+
}
93+
$path = 'Prefix/docs/CHANGELOG.html'
94+
if (-not (Test-Path $path)) { Write-Error "$path not found"; exit 1 }
95+
$text = Get-Content -Raw -Encoding UTF8 $path
96+
$regex = [regex]::new('(?s)(<script id="md" type="text/markdown">\s*)(?<md>.*?)(\s*</script>)')
97+
$match = $regex.Match($text)
98+
if (-not $match.Success) { Write-Error "Embedded markdown block not found in $path"; exit 1 }
99+
$prefix = $match.Groups[1].Value
100+
$md = $match.Groups['md'].Value
101+
$suffix = $match.Groups[3].Value
102+
if ($md -match '(?m)^\s*##\s*' + [regex]::Escape($norm) + '\s*$') {
103+
Write-Host "CHANGELOG already contains $norm; skipping update."
104+
exit 0
105+
}
106+
$sepMatches = [regex]::Matches($md, '^[ \t]*---[ \t]*$', [System.Text.RegularExpressions.RegexOptions]::Multiline)
107+
if ($sepMatches.Count -ge 2) { $insIndex = $sepMatches[1].Index + $sepMatches[1].Length } elseif ($sepMatches.Count -ge 1) { $insIndex = $sepMatches[0].Index + $sepMatches[0].Length } else { $insIndex = 0 }
108+
# Insert the commit message body exactly as provided (no added headers or placeholders).
109+
$sectionBody = $body
110+
$section = "## $norm`n`n" + $sectionBody + "`n`n---`n`n"
111+
$new_md = $md.Substring(0, $insIndex) + $section + $md.Substring($insIndex)
112+
$new_text = $text.Substring(0,$match.Index) + $prefix + $new_md + $suffix + $text.Substring($match.Index + $match.Length)
113+
Set-Content -Path $path -Value $new_text -Encoding UTF8
114+
git config user.name "github-actions[bot]"
115+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
116+
git add $path
117+
git commit -m "chore(release): update CHANGELOG for $tag" || Write-Host "No changelog changes"
118+
git remote set-head origin --auto
119+
$default_branch = (git symbolic-ref refs/remotes/origin/HEAD).Replace('refs/remotes/origin/','')
120+
git push origin HEAD:$default_branch
121+
# close matching open milestone (exact title match)
122+
$repo = $env:GITHUB_REPOSITORY
123+
$token = $env:GITHUB_TOKEN
124+
$miles = Invoke-RestMethod -Headers @{ Authorization = "token $token"; 'User-Agent' = 'github-actions' } -Uri "https://api.github.com/repos/$repo/milestones?state=open&per_page=100" -Method Get
125+
foreach ($m in $miles) {
126+
if ($m.title -eq $norm) {
127+
Write-Host "Closing milestone $($m.title) (number $($m.number))"
128+
Invoke-RestMethod -Headers @{ Authorization = "token $token"; 'User-Agent' = 'github-actions' } -Method Patch -Uri "https://api.github.com/repos/$repo/milestones/$($m.number)" -Body (@{ state = 'closed' } | ConvertTo-Json)
129+
}
130+
}

0 commit comments

Comments
 (0)