diff --git a/.generated.NoMobile.slnx b/.generated.NoMobile.slnx index bbf67bf776..7efa71bcc3 100644 --- a/.generated.NoMobile.slnx +++ b/.generated.NoMobile.slnx @@ -23,6 +23,7 @@ + @@ -136,6 +137,7 @@ + diff --git a/.github/workflows/changelog-guard.yml b/.github/workflows/changelog-guard.yml new file mode 100644 index 0000000000..1793872b86 --- /dev/null +++ b/.github/workflows/changelog-guard.yml @@ -0,0 +1,19 @@ +name: Changelog Guard + +on: + pull_request: + branches: + - main + - release/** + +permissions: + contents: read + +jobs: + no-manual-unreleased-entries: + name: No manual "## Unreleased" entries + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - name: Verify CHANGELOG.md has no manual "## Unreleased" entries + run: ./scripts/verify-changelog.sh diff --git a/AGENTS.md b/AGENTS.md index bed5cae81d..381286b24b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,17 @@ # Agent Instructions +## Getting Started + +**Check out the submodules first.** The native SDKs and several build/tooling projects live in git submodules under `modules/` (e.g. `sentry-native`, `sentry-cocoa`, `perfview`). Without them, builds, solution-filter generation, and other tooling break in confusing ways — e.g. `scripts/generate-solution-filters.ps1` silently drops the missing projects from the `*.slnf` files. + +The bootstrap step handles this for you (it runs `git submodule update --init --recursive` plus a full restore): + +```sh +./dev.cs cleanslate +``` + +If you only need to sync submodules (e.g. in a fresh worktree), run `./dev.cs subup` or `git submodule update --init --recursive` directly. + ## Build System Uses the .NET SDK (`dotnet` CLI). Key files: diff --git a/CHANGELOG.md b/CHANGELOG.md index 08dd24178d..2816f09939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,5 @@ # Changelog -## Unreleased - -### Features ✨ - -- feat: Add exponential backoff and log deduplication to Spotlight transport by @mattico in [#5025](https://github.com/getsentry/sentry-dotnet/pull/5025) - ## 6.6.0 ### Features ✨ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 008aca9983..ca959b2a07 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -109,28 +109,13 @@ To do that, run the build locally (i.e: `./build.sh` or `build.cmd`) and commit ## Changelog We'd love for users to update the SDK everytime and as soon as we make a new release. But in reality most users rarely update the SDK. -To help users see value in updating the SDK, we maintain a changelog file with entries split between two headings: +To help users see value in updating the SDK, we maintain a changelog file with entries split between headings such as `### Features` and `### Fixes`. -1. `### Features` -2. `### Fixes` +**Do not edit `CHANGELOG.md` manually.** The changelog is generated automatically at release time by [craft](https://github.com/getsentry/craft) (`changelogPolicy: auto` in `.craft.yml`) from the pull requests merged since the previous release. Entries are categorized from your [commit message / PR title](https://develop.sentry.dev/engineering-practices/commit-messages/) (e.g. a `feat:` PR becomes a Feature, a `fix:` PR becomes a Fix), so there's nothing to add by hand. -We add the heading in the first PR that's adding either a feature or fixes in the current release. -After a release, the [changelog file will contain only the last release entries](https://github.com/getsentry/sentry-dotnet/blob/main/CHANGELOG.md). +If the PR title doesn't capture the change well — you want more detail, or a single PR should produce several entries — add a `### Changelog Entry` section to the PR description. craft uses the text under that heading verbatim instead of the PR title. See [Custom changelog entries from PR descriptions](https://craft.sentry.dev/configuration/#custom-changelog-entries-from-pr-descriptions). -When you open a PR in such cases, you need to add a heading 2 named `## Unreleased`, which is replaced during release with the version number chosen. -Below that, you'll add heading 3 mentioned above. For example, if you're adding a feature "Attach screenshots when capturing errors on WPF", right after a release, you'd add to the changelog: - -``` -## Unreleased - -### Features - -- Attach screenshots when capturing errors on WPF (#PR number) -``` - -There's a GitHub action check to verify if an entry was added. -If the entry isn't a user-facing change, you can skip the verification with either `#skip-changelog` written to the PR description or the `skip-changelog` label added to the PR. -The bot writes a comment in the PR with a suggestion entry to the changelog based on the PR title. +If the change isn't user-facing and you'd rather it not appear in the changelog at all, add the `skip-changelog` label to the PR or write `#skip-changelog` in the PR description. ## Naming tests diff --git a/Sentry.slnx b/Sentry.slnx index bbf67bf776..7efa71bcc3 100644 --- a/Sentry.slnx +++ b/Sentry.slnx @@ -23,6 +23,7 @@ + @@ -136,6 +137,7 @@ + diff --git a/scripts/verify-changelog.sh b/scripts/verify-changelog.sh new file mode 100755 index 0000000000..ff8b3b33ac --- /dev/null +++ b/scripts/verify-changelog.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# +# Verifies that CHANGELOG.md has no content under an "## Unreleased" heading. +# +# This repository generates its changelog automatically at release time via +# craft (`changelogPolicy: auto` in .craft.yml), from the pull requests merged +# since the previous release. Craft only regenerates the section when it is +# empty, so a single leftover manual entry under "## Unreleased" suppresses the +# auto-generation and silently drops every other change from the release notes. +# +# Usage: scripts/verify-changelog.sh [path-to-changelog] +set -euo pipefail + +CHANGELOG="${1:-CHANGELOG.md}" + +if [[ ! -f "$CHANGELOG" ]]; then + echo "Changelog file not found: $CHANGELOG" >&2 + exit 2 +fi + +# Find non-blank lines in the "## Unreleased" section -- everything between the +# "## Unreleased" heading and the next "## " (h2) heading; "### " sub-headings +# are not treated as section boundaries. Each match is emitted as +# ":" so reported locations point at CHANGELOG.md. +# +# craft trims the section body and skips auto-generation whenever it is +# non-empty (`if (!changeset.body)` after `.trim()`), so ANY non-whitespace +# content under "## Unreleased" -- a bullet, a stray "### Features" sub-heading, +# or loose text -- suppresses generation. Match that exactly: fail on any +# non-blank line. A bare/empty "## Unreleased" heading is fine (craft +# regenerates it). +offending="$(awk ' + /^## / { + if (in_section) { in_section = 0 } + if (tolower($0) ~ /^## +unreleased/) { in_section = 1; next } + } + in_section && /[^[:space:]]/ { printf "%d:%s\n", NR, $0 } +' "$CHANGELOG")" + +if [[ -n "$offending" ]]; then + echo "::error file=$CHANGELOG::The '## Unreleased' section is not empty." + echo "" + echo "This repository generates its changelog automatically at release time" + echo "(changelogPolicy: auto in .craft.yml). craft only regenerates the" + echo "'## Unreleased' section when it is empty, so ANY leftover content there" + echo "(entries or even a bare sub-heading) suppresses generation and causes the" + echo "rest of the release notes to be dropped." + echo "" + echo "Offending line(s) in $CHANGELOG:" + printf '%s\n' "$offending" + echo "" + echo "Please remove them. Your change is added to the changelog automatically," + echo "based on the PR title / commit message -- or a '### Changelog Entry' section" + echo "in the PR description if you want a more detailed entry. If it is not" + echo "user-facing, add the 'skip-changelog' label or write '#skip-changelog' in the" + echo "PR description." + exit 1 +fi + +echo "OK: '## Unreleased' section is empty."