diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml index d2f659e..25af023 100644 --- a/.github/workflows/publish-package.yml +++ b/.github/workflows/publish-package.yml @@ -78,28 +78,10 @@ jobs: --api-key "$NUGET_AUTH_TOKEN" \ --skip-duplicate - - name: Generate release notes - shell: pwsh - run: >- - ./scripts/generate-release-notes.ps1 - -Tag "${{ github.ref_name }}" - -Repository "${{ github.repository }}" - -OutputPath "artifacts/release-notes.md" - - name: Create or update GitHub Release - shell: bash - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - package="artifacts/packages/Darp.DLL.SerialPortStream.Native.${{ needs.version.outputs.value }}.nupkg" - if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then - gh release edit "$GITHUB_REF_NAME" \ - --title "$GITHUB_REF_NAME" \ - --notes-file "artifacts/release-notes.md" - gh release upload "$GITHUB_REF_NAME" "$package" --clobber - else - gh release create "$GITHUB_REF_NAME" "$package" \ - --verify-tag \ - --title "$GITHUB_REF_NAME" \ - --notes-file "artifacts/release-notes.md" - fi + uses: softprops/action-gh-release@c12583777ecdfd3be55c69cf75464299dc01057e # v3 + with: + name: ${{ github.ref_name }} + generate_release_notes: true + files: artifacts/packages/Darp.DLL.SerialPortStream.Native.${{ needs.version.outputs.value }}.nupkg + fail_on_unmatched_files: true diff --git a/README.md b/README.md index ec47f38..e45347e 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,8 @@ git push origin v1.2.3 The tag must match `vMAJOR.MINOR.PATCH`. The publishing workflow removes the leading `v`, passes the resulting version to the existing build workflow, and publishes only after the package tests pass on Linux x64 and arm64. It also -creates a GitHub Release, generates its sections from conventional commits -since the preceding version tag, and attaches the `.nupkg`. +uses GitHub's generated release notes to create a GitHub Release and attaches +the `.nupkg`. ## Updating upstream diff --git a/scripts/generate-release-notes.ps1 b/scripts/generate-release-notes.ps1 deleted file mode 100644 index 8354183..0000000 --- a/scripts/generate-release-notes.ps1 +++ /dev/null @@ -1,120 +0,0 @@ -param( - [Parameter(Mandatory = $true)] - [string]$Tag, - - [Parameter(Mandatory = $true)] - [string]$Repository, - - [Parameter(Mandatory = $true)] - [string]$OutputPath -) - -$ErrorActionPreference = "Stop" -Set-StrictMode -Version Latest - -$tagCommit = (& git rev-list -n 1 $Tag).Trim() -if ($LASTEXITCODE -ne 0 -or !$tagCommit) { - throw "Could not resolve tag '$Tag'." -} - -$previousTag = & git tag --merged "$Tag^" --list "v[0-9]*" --sort=-v:refname | - Select-Object -First 1 -if ($LASTEXITCODE -ne 0) { - throw "Could not find the tag preceding '$Tag'." -} - -$range = if ($previousTag) { "$previousTag..$Tag" } else { $Tag } -$commits = @(& git log $range --reverse --no-merges --format="%H%x09%s") -if ($LASTEXITCODE -ne 0) { - throw "Could not read commits for '$range'." -} - -$sections = [ordered]@{ - "Breaking changes" = @() - "Features" = @() - "Fixes" = @() - "Performance" = @() - "Documentation" = @() - "Build" = @() - "Continuous integration" = @() - "Refactoring" = @() - "Tests" = @() - "Maintenance" = @() - "Initial release" = @() - "Other changes" = @() -} - -foreach ($commit in $commits) { - if (!$commit) { continue } - - $parts = $commit -split "`t", 2 - $hash = $parts[0] - $subject = if ($parts.Length -eq 2) { $parts[1] } else { $hash } - $shortHash = $hash.Substring(0, 7) - $body = (& git show -s --format="%b" $hash) -join "`n" - if ($LASTEXITCODE -ne 0) { throw "Could not read commit '$hash'." } - - $type = "" - $scope = "" - $description = $subject - $breaking = $body -match "(?m)^BREAKING CHANGE:\s*" - - if ($subject -match "^(?[A-Za-z]+)(?:\((?[^)]+)\))?(?!)?:\s+(?.+)$") { - $type = $Matches.type.ToLowerInvariant() - $scope = if ($Matches.ContainsKey("scope")) { $Matches.scope } else { "" } - $description = $Matches.description - $breaking = $breaking -or ($Matches.ContainsKey("breaking") -and [bool]$Matches.breaking) - } - - $category = if ($breaking) { - "Breaking changes" - } else { - switch ($type) { - "feat" { "Features" } - "fix" { "Fixes" } - "perf" { "Performance" } - "docs" { "Documentation" } - "build" { "Build" } - "ci" { "Continuous integration" } - "refactor" { "Refactoring" } - "test" { "Tests" } - "chore" { "Maintenance" } - "init" { "Initial release" } - default { "Other changes" } - } - } - - $entry = "- " - if ($scope) { $entry += "**${scope}:** " } - $entry += "$description [$shortHash](https://github.com/$Repository/commit/$hash)" - $sections[$category] += $entry -} - -$notes = [System.Collections.Generic.List[string]]::new() -foreach ($section in $sections.GetEnumerator()) { - if ($section.Value.Count -eq 0) { continue } - $notes.Add("## $($section.Key)") - $notes.Add("") - foreach ($entry in $section.Value) { $notes.Add($entry) } - $notes.Add("") -} - -if ($notes.Count -eq 0) { - $notes.Add("No commits were found for this release.") - $notes.Add("") -} - -if ($previousTag) { - $notes.Add("**Full changelog:** [$previousTag...$Tag](https://github.com/$Repository/compare/$previousTag...$Tag)") -} else { - $notes.Add("**Commit history:** [$Tag](https://github.com/$Repository/commits/$Tag)") -} - -$outputDirectory = Split-Path -Parent $OutputPath -if ($outputDirectory) { - New-Item -ItemType Directory -Force -Path $outputDirectory | Out-Null -} -$notes | Set-Content -LiteralPath $OutputPath -Encoding utf8 - -Write-Host "Generated release notes for $Tag from $($commits.Count) commit(s)." -if ($previousTag) { Write-Host "Previous tag: $previousTag" }