Skip to content
Merged
Show file tree
Hide file tree
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
41 changes: 26 additions & 15 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,29 +31,40 @@ jobs:
env:
BEFORE_SHA: ${{ github.event.before }}
run: |
$headingPattern = '^####\s+(\S+)'
$currentHeading = Get-Content RELEASE_NOTES.md | Select-String -Pattern $headingPattern | Select-Object -First 1
if (-not $currentHeading) {
throw 'RELEASE_NOTES.md has no #### release heading.'
function Get-CurrentRelease([string[]] $lines) {
$releasePattern = '^####\s+(?<version>\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)\b'
$headingPattern = '^####\s+'
$start = 0..($lines.Count - 1) | Where-Object { $lines[$_] -match $releasePattern } | Select-Object -First 1
if ($null -eq $start) {
throw 'RELEASE_NOTES.md has no versioned #### release heading.'
}

$match = [regex]::Match($lines[$start], $releasePattern)
$end = (($start + 1)..($lines.Count - 1) | Where-Object { $lines[$_] -match $headingPattern } | Select-Object -First 1)
if ($null -eq $end) { $end = $lines.Count }

return [pscustomobject]@{
Version = $match.Groups['version'].Value
Content = ($lines[$start..($end - 1)] -join "`n").TrimEnd()
}
}

$version = $currentHeading.Matches[0].Groups[1].Value
$previousVersion = $null
$currentRelease = Get-CurrentRelease (Get-Content RELEASE_NOTES.md)
$previousRelease = $null
if ($env:BEFORE_SHA -and $env:BEFORE_SHA -notmatch '^0+$') {
$previousNotes = git show "${env:BEFORE_SHA}:RELEASE_NOTES.md" 2>$null
if ($LASTEXITCODE -eq 0) {
$previousHeading = $previousNotes | Select-String -Pattern $headingPattern | Select-Object -First 1
if ($previousHeading) {
$previousVersion = $previousHeading.Matches[0].Groups[1].Value
}
$previousRelease = Get-CurrentRelease $previousNotes
}
}

$isRelease = $version -ne $previousVersion
$isRelease = $null -eq $previousRelease -or
$currentRelease.Version -cne $previousRelease.Version -or
$currentRelease.Content -cne $previousRelease.Content
"is-release=$($isRelease.ToString().ToLowerInvariant())" >> $env:GITHUB_OUTPUT
"version=$version" >> $env:GITHUB_OUTPUT
"prerelease=$($version.Contains('-').ToString().ToLowerInvariant())" >> $env:GITHUB_OUTPUT
Write-Host "Current release: $version; previous release: $previousVersion; publish: $isRelease"
"version=$($currentRelease.Version)" >> $env:GITHUB_OUTPUT
"prerelease=$($currentRelease.Version.Contains('-').ToString().ToLowerInvariant())" >> $env:GITHUB_OUTPUT
Write-Host "Current release: $($currentRelease.Version); previous release: $($previousRelease.Version); publish: $isRelease"

release:
name: Build and publish ${{ needs.detect-release.outputs.version }}
Expand Down Expand Up @@ -121,7 +132,7 @@ jobs:
shell: pwsh
run: |
$lines = Get-Content RELEASE_NOTES.md
$start = 0..($lines.Count - 1) | Where-Object { $lines[$_] -match '^####\s+' } | Select-Object -First 1
$start = 0..($lines.Count - 1) | Where-Object { $lines[$_] -match '^####\s+\d+\.\d+\.\d+' } | Select-Object -First 1
$end = (($start + 1)..($lines.Count - 1) | Where-Object { $lines[$_] -match '^####\s+' } | Select-Object -First 1)
if ($null -eq $end) { $end = $lines.Count }
$body = $lines[($start + 1)..($end - 1)] -join "`n"
Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ The exact F# compile order is declared in each `.fsproj`. When adding or moving

## Release Notes

`RELEASE_NOTES.md` is shipped to users: `build.fsx` reads the first entry for the version number and embeds its bullets as `PackageReleaseNotes` in the published packages.
`RELEASE_NOTES.md` is shipped to users: `build.fsx` reads the first versioned entry after the optional `#### Unreleased` section and embeds its bullets as `PackageReleaseNotes` in the published packages.

- Every change to shipped behavior (bug fix, feature, performance improvement, change to a dependency of the published packages) adds one bullet to the **topmost** entry. Keep the entry's version line; only maintainers bump the version.
- Every change to shipped behavior (bug fix, feature, performance improvement, change to a dependency of the published packages) adds one bullet to `#### Unreleased`. Maintainers move those bullets into a versioned section to trigger a release.
- Internal changes get no entry: build scripts, CI and workflows, tests-only, docs-only, tooling, warning cleanups.
- Format: `* <one-line summary> - <link>`. Link to the issue being fixed (`https://github.com/fsprojects/Paket/issues/<N>`), or to the pull request when there is no issue and its number is known; omit the link otherwise. Match the wording of the existing entries: imperative summary, no trailing period.
- If the topmost entry has already been published (a git tag or GitHub release with that version exists), add a new entry above it: `#### <next patch version> - <YYYY-MM-DD>`.
- To release, add or update the first versioned entry below `#### Unreleased` as `#### <version> - <YYYY-MM-DD>`. A change to that version or its section content triggers publication.

## Build and Test

Expand Down
3 changes: 3 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#### Unreleased

#### 11.0.0-alpha001 - 2026-09-12
* Automate GitHub and NuGet releases from RELEASE_NOTES.md using NuGet trusted publishing - https://github.com/fsprojects/Paket/pull/4436
* Upgrade to .NET 10: SDK 10.0.400 and target frameworks from net9 to net10.0. The `paket` .NET tool now requires the .NET 10 runtime; the merged `paket.exe` still targets net461.
* Allow a whole `source` line in paket.dependencies to come from an environment variable (`source %FEED_URL%`) - https://github.com/fsprojects/Paket/pull/4374
* Fall back to User/Machine scoped environment variables in paket.dependencies - https://github.com/fsprojects/Paket/pull/4406
Expand Down
11 changes: 10 additions & 1 deletion build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,16 @@ System.Environment.CurrentDirectory <- __SOURCE_DIRECTORY__

// Read additional information from the release notes document
let releaseNotesData =
File.read "RELEASE_NOTES.md"
let lines = System.IO.File.ReadAllLines "RELEASE_NOTES.md"
let firstRelease =
lines
|> Array.tryFindIndex (fun line ->
line.StartsWith("#### ", StringComparison.Ordinal)
&& line.Length > 5
&& Char.IsDigit line.[5])
|> Option.defaultWith (fun () -> failwith "RELEASE_NOTES.md has no released version heading")

lines.[firstRelease..]
|> ReleaseNotes.parseAll

let release = List.head releaseNotesData
Expand Down
4 changes: 2 additions & 2 deletions tests/Paket.Tests/Packaging/PackageProcessSpecs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ let ``Loading assembly metadata works``() =

let paketReleaseNotesVersion =
tryFindFileInHeirarchy workingDir "RELEASE_NOTES.md"
|> Option.map (File.ReadLines >> Seq.head)
|> Option.map (fun line -> line.Split(' ').[1]) // format is ### <VERSION> - <DATE>, so taking second element of array is the version
|> Option.bind (File.ReadLines >> Seq.tryFind (fun line -> line.Length > 5 && line.StartsWith("#### ") && System.Char.IsDigit line.[5]))
|> Option.map (fun line -> line.Split(' ').[1]) // format is #### <VERSION> - <DATE>, so taking second element of array is the version
|> Option.defaultWith (fun _ -> failwithf "unable to parse current version from RELEASE_NOTES.md in the directory heirarchy of %s" workingDir.FullName)

let assemblyReader, id, versionFromAssembly, _fileName = PackageMetaData.readAssemblyFromProjFile config "" projFile
Expand Down
Loading