diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fc2fb94..f3111bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,6 +51,29 @@ jobs: with: fetch-depth: 0 + - name: Generate release notes + id: release-notes + shell: pwsh + run: | + $releaseJson = gh release list ` + --repo "$env:GITHUB_REPOSITORY" ` + --limit 1 ` + --json tagName + if ($LASTEXITCODE -ne 0) { + throw "Could not determine the previous release." + } + $releases = @($releaseJson | ConvertFrom-Json) + $previousTag = if ($releases.Count -gt 0) { $releases[0].tagName } else { "" } + $notesPath = Join-Path $env:RUNNER_TEMP "captail-$env:VERSION-release-notes.md" + ./tools/New-ReleaseNotes.ps1 ` + -Version $env:VERSION ` + -PreviousTag $previousTag ` + -Repository $env:GITHUB_REPOSITORY ` + -OutputPath $notesPath + "path=$notesPath" >> $env:GITHUB_OUTPUT + env: + GH_TOKEN: ${{ github.token }} + - name: Set up .NET uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6 with: @@ -200,19 +223,6 @@ jobs: - name: Publish GitHub Release shell: pwsh run: | - $intro = @" - > [!WARNING] - > Captail $env:VERSION is an early public preview. Bugs and hardware-specific issues are expected. - - **Recommended:** download the Setup EXE. It includes Captail, .NET, and required libobs components and creates a Windows uninstaller. - - **Portable:** extract the entire ZIP before launching `Captail.exe`. - - Tested on NVIDIA GeForce RTX 40 and RTX 50 series. Older NVIDIA, AMD, and Intel hardware still needs broader public testing. Please report results and bugs through GitHub Issues. - - Release binaries are not Authenticode-signed. Verify `SHA256SUMS.txt` and GitHub build provenance. - "@ - $assets = @( (Join-Path $env:RELEASE_DIR "Captail-$env:VERSION-Portable-win-x64.zip"), (Join-Path $env:RELEASE_DIR "Captail-$env:VERSION-Setup-win-x64.exe"), @@ -224,8 +234,7 @@ jobs: "--repo", $env:GITHUB_REPOSITORY, "--target", $env:GITHUB_SHA, "--title", "Captail v$env:VERSION", - "--notes", $intro, - "--generate-notes" + "--notes-file", '${{ steps.release-notes.outputs.path }}' ) if ('${{ inputs.prerelease }}' -eq 'true') { $arguments += "--prerelease" diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ac1cf3..976babd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,29 @@ All notable user-facing changes are documented here. - Update downloads now close their file handles before promoting verified packages or replacing an invalid cached package, preventing Windows file-lock errors during one-click updates. -### Upgrade note +### Upgrade notes - Captail 0.1.3 and 0.1.4 cannot complete an in-app update because the bug is inside those installed versions. Download and run the 0.1.5 Setup EXE once; later in-app updates will work normally. +## [0.1.4] - 2026-08-02 + +### Added + +- Replay library with every saved clip in a vertically scrollable list. +- Built-in clip editor with responsive video preview, a single trim range, separate system/game and microphone track controls, save-as-copy, and confirmed overwrite. +- Clip details showing estimated trimmed size, original size, resolution, frame rate, and codec. +- Automatic desktop-to-game capture switching, plus a game-only mode that leaves the desktop out of recordings. + +### Changed + +- Replay cards now reveal compact actions on hover instead of using a large edge glow. +- FFmpeg and FFplay are included with Captail, so clip preview and trimming need no separate download. + +### Fixed + +- Clean installations now receive the FFmpeg runtime required by the editor. +- Preview rendering keeps the complete frame visible instead of showing only its upper-left region. + ## [0.1.3] - 2026-07-26 ### Added diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md new file mode 100644 index 0000000..11b19b2 --- /dev/null +++ b/docs/RELEASE_NOTES.md @@ -0,0 +1,91 @@ +# Writing Captail release notes + +Release notes answer three user questions: + +1. What changed? +2. Why does it matter to me? +3. Must I do anything before or after updating? + +`CHANGELOG.md` is the source for GitHub Release descriptions. The release workflow extracts the matching version section and adds package, compatibility, verification, and full-changelog links automatically. + +## Before writing + +Review every commit and merged pull request since the previous tag. For each user-visible change, record: + +- what changed; +- which users or workflows it affects; +- the practical benefit or resolved problem; +- any required upgrade action; +- limitations that remain. + +Do not infer a feature from a filename or commit title. Check the implementation, pull request description, or validation evidence. + +## Required changelog format + +Move completed entries from `[Unreleased]` into a version section before starting the release workflow: + +```markdown +## [0.2.0] - 2026-08-15 + +### Added + +- **Replay search:** Find saved clips by game or filename without browsing folders manually. + +### Improved + +- **Game detection:** Games are recognized sooner after launch, reducing desktop footage at the start of a clip. + +### Fixed + +- Fixed microphone audio disappearing after its device reconnects. + +### Upgrade notes + +- **Action required:** Install this version manually if updating from 0.1.3 or 0.1.4. +``` + +The version must match the workflow input exactly. Use `YYYY-MM-DD` for the date. Omit empty categories. + +## Categories + +- `Added`: new user-facing capabilities. +- `Improved`: an existing workflow became faster, clearer, or more capable. +- `Fixed`: a user-visible problem no longer occurs. +- `Upgrade notes`: users must take an action or should expect a one-time behavior. +- `Breaking changes`: existing settings, files, hotkeys, or workflows stop being compatible. +- `Known limitations`: important constraints still present in this release. + +## Writing rules + +- Lead with user impact, not implementation details. +- Use one bullet per change and keep it to one or two sentences. +- Use plain language. Explain technical terms only when users need them to act. +- Be specific about affected versions, capture modes, codecs, or hardware. +- Include measured performance only when the test setup and result are recorded. +- State uncertainty directly. Do not claim untested GPU or codec support. +- Do not paste commit titles, ticket numbers, validation logs, or dependency bumps into user notes. +- Do not describe routine refactoring unless it changes behavior, reliability, security, or performance. +- Do not use promotional claims such as “best,” “perfect,” or “production-ready.” + +## Generate a local preview + +```powershell +.\tools\New-ReleaseNotes.ps1 ` + -Version 0.2.0 ` + -PreviousTag v0.1.5 ` + -OutputPath "$env:TEMP\captail-release-notes.md" + +Get-Content "$env:TEMP\captail-release-notes.md" +``` + +Check that the preview: + +- begins with the changes rather than build-system details; +- includes every required user action; +- contains no empty heading; +- uses correct package names and compare links; +- matches the English wording used in Captail. + +## After publishing + +Open the release page and confirm its version, text, assets, checksums, prerelease state, and full-changelog link. Never replace binaries under an existing tag; publish a new patch version instead. diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 93190ae..3d7b561 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -11,6 +11,24 @@ Each release contains: ## Create a release +Before running the workflow: + +1. Review changes since the previous tag. +2. Move completed entries from `[Unreleased]` into a dated version section in `CHANGELOG.md`. +3. Follow [RELEASE_NOTES.md](RELEASE_NOTES.md) for categories, wording, and required upgrade notices. +4. Preview the generated GitHub Release description locally: + +```powershell +.\tools\New-ReleaseNotes.ps1 ` + -Version 0.1.6 ` + -PreviousTag v0.1.5 ` + -OutputPath "$env:TEMP\captail-release-notes.md" +``` + +Commit and merge the changelog before dispatching the release. The workflow stops if it cannot find a non-empty section matching the requested version. + +Then start the release from GitHub: + From GitHub: 1. Open **Actions**. @@ -29,7 +47,14 @@ gh workflow run release.yml ` -f prerelease=true ``` -The workflow validates the version, builds and verifies both packages, creates tag `v0.1.1`, and publishes the GitHub Release. +The workflow validates the version, builds and verifies both packages, creates tag `v0.1.1`, and publishes the GitHub Release using the matching changelog section. + +After publishing, verify: + +- release title, version, and prerelease status; +- Installer, Portable ZIP, and `SHA256SUMS.txt` assets; +- generated release notes and full-changelog link; +- GitHub build-provenance attestations. ## Local package build diff --git a/tools/New-ReleaseNotes.ps1 b/tools/New-ReleaseNotes.ps1 new file mode 100644 index 0000000..053c277 --- /dev/null +++ b/tools/New-ReleaseNotes.ps1 @@ -0,0 +1,78 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory)] + [ValidatePattern('^\d+\.\d+\.\d+$')] + [string]$Version, + + [Parameter(Mandatory)] + [string]$OutputPath, + + [string]$ChangelogPath = "", + + [string]$Repository = "FaulMit/captail", + + [string]$PreviousTag = "" +) + +$ErrorActionPreference = "Stop" +$repoRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..")) +if (-not $ChangelogPath) { + $ChangelogPath = Join-Path $repoRoot "CHANGELOG.md" +} + +if (-not (Test-Path -LiteralPath $ChangelogPath -PathType Leaf)) { + throw "Changelog not found: $ChangelogPath" +} + +$changelog = Get-Content -LiteralPath $ChangelogPath -Raw +$escapedVersion = [Regex]::Escape($Version) +$pattern = "(?ms)^## \[$escapedVersion\] - (?\d{4}-\d{2}-\d{2})\r?\n(?.*?)(?=^## \[|\z)" +$match = [Regex]::Match($changelog, $pattern) +if (-not $match.Success) { + throw "CHANGELOG.md has no release section for [$Version]." +} + +$changeBody = $match.Groups["body"].Value.Trim() +if (-not $changeBody) { + throw "CHANGELOG.md release section [$Version] is empty." +} + +# Changelog entries are nested below version headings. Promote their headings +# one level when the entry becomes a standalone GitHub Release description. +$changeBody = [Regex]::Replace($changeBody, '(?m)^### ', '## ') + +$lines = [Collections.Generic.List[string]]::new() +$lines.Add("> [!WARNING]") +$lines.Add("> Captail $Version is an early public preview. Bugs and hardware-specific issues are expected.") +$lines.Add("") +$lines.Add($changeBody) +$lines.Add("") +$lines.Add("## Downloads") +$lines.Add("") +$lines.Add("- **Installer (recommended):** ``Captail-$Version-Setup-win-x64.exe`` includes Captail, .NET, libobs, FFmpeg, and an uninstaller.") +$lines.Add("- **Portable:** extract the entire ``Captail-$Version-Portable-win-x64.zip`` before launching ``Captail.exe``.") +$lines.Add("") +$lines.Add("## Compatibility and feedback") +$lines.Add("") +$lines.Add("Captail is tested on NVIDIA GeForce RTX 40 and RTX 50 series. Older NVIDIA, AMD, and Intel hardware needs broader public testing. Report problems through [GitHub Issues](https://github.com/$Repository/issues).") +$lines.Add("") +$lines.Add("Release binaries are not Authenticode-signed yet. Windows may show an unknown-publisher or SmartScreen warning. Use ``SHA256SUMS.txt`` and GitHub build provenance to verify the download.") + +if ($PreviousTag) { + $lines.Add("") + $lines.Add("**Full changelog:** https://github.com/$Repository/compare/$PreviousTag...v$Version") +} + +$outputFullPath = [IO.Path]::GetFullPath($OutputPath) +$outputDirectory = [IO.Path]::GetDirectoryName($outputFullPath) +if ($outputDirectory) { + [IO.Directory]::CreateDirectory($outputDirectory) | Out-Null +} + +$notes = ($lines -join [Environment]::NewLine).TrimEnd() + [Environment]::NewLine +[IO.File]::WriteAllText( + $outputFullPath, + $notes, + [Text.UTF8Encoding]::new($false)) + +Write-Host "Release notes written to $outputFullPath"