From f664c367adbd1118248344e68db3f217b892225f Mon Sep 17 00:00:00 2001 From: Mike Goldsmith Date: Fri, 8 May 2026 13:03:53 +0100 Subject: [PATCH 1/3] introduce towncrier to generate changelog from fragments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace manual CHANGELOG.md editing with towncrier fragment-based changelog management. Each PR adds a small text file in .changelog/ instead of editing the changelog directly, eliminating merge conflicts. Changes: - Add towncrier configuration in pyproject.toml with 5 fragment types (added, changed, deprecated, removed, fixed) - Replace sed-based changelog generation in release workflows with towncrier build - Add changelog backport step to patch release workflow - Update CI to use towncrier check for fragment validation - Add pre-commit check via scripts/check_changelog_fragment.py - Add tox environments: changelog (preview) and new-changelog (create) - Add contributor documentation in CONTRIBUTING.md - Convert existing unreleased entries to fragment files - Add custom Jinja2 template for changelog output Based on the proof-of-concept in #4382 by @emdneto. Co-authored-by: Emídio Neto <9735060+emdneto@users.noreply.github.com> Assisted-by: Claude Opus 4.6 --- .changelog/.gitignore | 1 + .changelog/4907.added | 1 + .changelog/4917.added | 1 + .changelog/4990.added | 1 + .changelog/4996.added | 1 + .changelog/5003.added | 1 + .changelog/5072.fixed | 1 + .changelog/5076.removed | 1 + .changelog/5083.fixed | 1 + .changelog/5088.added | 1 + .changelog/5091.fixed | 1 + .changelog/5093.added | 1 + .changelog/5096.changed | 1 + .changelog/5119.changed | 1 + .changelog/5120.fixed | 1 + .changelog/5131.added | 1 + .changelog/5133.changed | 1 + .changelog/5135.fixed | 1 + .changelog/5145.changed | 1 + .changelog/5149.fixed | 1 + .changelog/5163.changed | 1 + .changelog/5177.changed | 1 + .github/workflows/changelog.yml | 48 ++++++++---- .github/workflows/prepare-patch-release.yml | 43 ++++++++--- .github/workflows/prepare-release-branch.yml | 26 ++----- .pre-commit-config.yaml | 8 ++ CHANGELOG.md | 45 +---------- CONTRIBUTING.md | 39 ++++++++++ pyproject.toml | 35 +++++++++ scripts/changelog_template.j2 | 24 ++++++ scripts/check_changelog_fragment.py | 81 ++++++++++++++++++++ tox.ini | 24 ++++++ 32 files changed, 309 insertions(+), 86 deletions(-) create mode 100644 .changelog/.gitignore create mode 100644 .changelog/4907.added create mode 100644 .changelog/4917.added create mode 100644 .changelog/4990.added create mode 100644 .changelog/4996.added create mode 100644 .changelog/5003.added create mode 100644 .changelog/5072.fixed create mode 100644 .changelog/5076.removed create mode 100644 .changelog/5083.fixed create mode 100644 .changelog/5088.added create mode 100644 .changelog/5091.fixed create mode 100644 .changelog/5093.added create mode 100644 .changelog/5096.changed create mode 100644 .changelog/5119.changed create mode 100644 .changelog/5120.fixed create mode 100644 .changelog/5131.added create mode 100644 .changelog/5133.changed create mode 100644 .changelog/5135.fixed create mode 100644 .changelog/5145.changed create mode 100644 .changelog/5149.fixed create mode 100644 .changelog/5163.changed create mode 100644 .changelog/5177.changed create mode 100644 scripts/changelog_template.j2 create mode 100644 scripts/check_changelog_fragment.py diff --git a/.changelog/.gitignore b/.changelog/.gitignore new file mode 100644 index 0000000000..f935021a8f --- /dev/null +++ b/.changelog/.gitignore @@ -0,0 +1 @@ +!.gitignore diff --git a/.changelog/4907.added b/.changelog/4907.added new file mode 100644 index 0000000000..e09de088a8 --- /dev/null +++ b/.changelog/4907.added @@ -0,0 +1 @@ +logs: add exception support to Logger emit and LogRecord attributes diff --git a/.changelog/4917.added b/.changelog/4917.added new file mode 100644 index 0000000000..fff01bc690 --- /dev/null +++ b/.changelog/4917.added @@ -0,0 +1 @@ +`opentelemetry-exporter-otlp-proto-grpc`: make retryable gRPC error codes configurable for gRPC exporters diff --git a/.changelog/4990.added b/.changelog/4990.added new file mode 100644 index 0000000000..83da399881 --- /dev/null +++ b/.changelog/4990.added @@ -0,0 +1 @@ +`opentelemetry-sdk`: Add `create_logger_provider`/`configure_logger_provider` to declarative file configuration diff --git a/.changelog/4996.added b/.changelog/4996.added new file mode 100644 index 0000000000..ca0c259fe3 --- /dev/null +++ b/.changelog/4996.added @@ -0,0 +1 @@ +`opentelemetry-exporter-otlp-json-common`: add 'opentelemetry-exporter-otlp-json-common' package for OTLP JSON exporters diff --git a/.changelog/5003.added b/.changelog/5003.added new file mode 100644 index 0000000000..bf1b364aa2 --- /dev/null +++ b/.changelog/5003.added @@ -0,0 +1 @@ +`opentelemetry-sdk`: Add `service` resource detector support to declarative file configuration diff --git a/.changelog/5072.fixed b/.changelog/5072.fixed new file mode 100644 index 0000000000..6219ae328b --- /dev/null +++ b/.changelog/5072.fixed @@ -0,0 +1 @@ +Fix incorrect code example in `create_tracer()` docstring diff --git a/.changelog/5076.removed b/.changelog/5076.removed new file mode 100644 index 0000000000..461f9bb978 --- /dev/null +++ b/.changelog/5076.removed @@ -0,0 +1 @@ +Drop Python 3.9 support diff --git a/.changelog/5083.fixed b/.changelog/5083.fixed new file mode 100644 index 0000000000..98d76b6d80 --- /dev/null +++ b/.changelog/5083.fixed @@ -0,0 +1 @@ +`opentelemetry-sdk`: Fix `ProcessResourceDetector` to use `sys.orig_argv` diff --git a/.changelog/5088.added b/.changelog/5088.added new file mode 100644 index 0000000000..d2e770a3ce --- /dev/null +++ b/.changelog/5088.added @@ -0,0 +1 @@ +Add WeaverLiveCheck test util diff --git a/.changelog/5091.fixed b/.changelog/5091.fixed new file mode 100644 index 0000000000..4f2e9d9612 --- /dev/null +++ b/.changelog/5091.fixed @@ -0,0 +1 @@ +`opentelemetry-sdk`: fix YAML structure injection via environment variable substitution in declarative file configuration diff --git a/.changelog/5093.added b/.changelog/5093.added new file mode 100644 index 0000000000..ba63d6ce4d --- /dev/null +++ b/.changelog/5093.added @@ -0,0 +1 @@ +`opentelemetry-sdk`: add `load_entry_point` shared utility to declarative file configuration for loading plugins via entry points diff --git a/.changelog/5096.changed b/.changelog/5096.changed new file mode 100644 index 0000000000..2a353c0d15 --- /dev/null +++ b/.changelog/5096.changed @@ -0,0 +1 @@ +`opentelemetry-semantic-conventions`: use `X | Y` union annotation diff --git a/.changelog/5119.changed b/.changelog/5119.changed new file mode 100644 index 0000000000..210d574006 --- /dev/null +++ b/.changelog/5119.changed @@ -0,0 +1 @@ +`opentelemetry-api`: update `EnvironmentGetter` and `EnvironmentSetter` to use normalized environment variable names diff --git a/.changelog/5120.fixed b/.changelog/5120.fixed new file mode 100644 index 0000000000..5e32b8addc --- /dev/null +++ b/.changelog/5120.fixed @@ -0,0 +1 @@ +`opentelemetry-sdk`: make resource detector ordering deterministic diff --git a/.changelog/5131.added b/.changelog/5131.added new file mode 100644 index 0000000000..cea96df940 --- /dev/null +++ b/.changelog/5131.added @@ -0,0 +1 @@ +`opentelemetry-sdk`: add `additional_properties` support to generated config models via custom `datamodel-codegen` template diff --git a/.changelog/5133.changed b/.changelog/5133.changed new file mode 100644 index 0000000000..85a97b78e2 --- /dev/null +++ b/.changelog/5133.changed @@ -0,0 +1 @@ +Apply fixes for `UP` ruff rule diff --git a/.changelog/5135.fixed b/.changelog/5135.fixed new file mode 100644 index 0000000000..d415f31326 --- /dev/null +++ b/.changelog/5135.fixed @@ -0,0 +1 @@ +Fix incorrect type annotation on `detectors` parameter of `get_aggregated_resources` diff --git a/.changelog/5145.changed b/.changelog/5145.changed new file mode 100644 index 0000000000..49e6f9def9 --- /dev/null +++ b/.changelog/5145.changed @@ -0,0 +1 @@ +`opentelemetry-sdk`: only load entrypoints for resource detectors if they are configured via `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS` diff --git a/.changelog/5149.fixed b/.changelog/5149.fixed new file mode 100644 index 0000000000..205826cc62 --- /dev/null +++ b/.changelog/5149.fixed @@ -0,0 +1 @@ +ci: wait for tracecontext server readiness instead of a fixed sleep diff --git a/.changelog/5163.changed b/.changelog/5163.changed new file mode 100644 index 0000000000..d810f3aa5d --- /dev/null +++ b/.changelog/5163.changed @@ -0,0 +1 @@ +`opentelemetry-api`: Enforce W3C Baggage size limits on outbound propagation in `W3CBaggagePropagator.inject()` diff --git a/.changelog/5177.changed b/.changelog/5177.changed new file mode 100644 index 0000000000..c02b345837 --- /dev/null +++ b/.changelog/5177.changed @@ -0,0 +1 @@ +Switch to SPDX license headers and add CI enforcement diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 39fc5f8e63..877fa3903a 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -1,6 +1,6 @@ -# This action requires that any PR targeting the main branch should touch at -# least one CHANGELOG file. If a CHANGELOG entry is not required, add the "Skip -# Changelog" label to disable this action. +# This action requires that any PR targeting the main branch should add a +# changelog fragment file in the .changelog/ directory. If a changelog entry +# is not required, add the "Skip Changelog" label to disable this action. name: changelog @@ -22,18 +22,40 @@ jobs: steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - - name: Check for CHANGELOG changes + - name: Fetch base branch + run: git fetch origin ${{ github.base_ref }} --depth=1 + + - name: Ensure no direct changes to CHANGELOG.md run: | - # Only the latest commit of the feature branch is available - # automatically. To diff with the base branch, we need to - # fetch that too (and we only need its latest commit). - git fetch origin ${{ github.base_ref }} --depth=1 - if [[ $(git diff --name-only FETCH_HEAD | grep CHANGELOG) ]] + if [[ $(git diff --name-only FETCH_HEAD -- 'CHANGELOG.md') ]] then - echo "A CHANGELOG was modified. Looks good!" - else - echo "No CHANGELOG was modified." - echo "Please add a CHANGELOG entry, or add the \"Skip Changelog\" label if not required." + echo "CHANGELOG.md should not be directly modified." + echo "Please add a changelog fragment file to the .changelog/ directory instead." + echo "" + echo "Create a fragment with:" + echo " tox -e new-changelog -- ${{ github.event.pull_request.number }} TYPE \"Description\"" + echo "where TYPE is one of: added, changed, deprecated, removed, fixed" + echo "" + echo "Or add the \"Skip Changelog\" label if this job should be skipped." + false + fi + + - name: Install towncrier + run: pip install towncrier + + - name: Check for changelog fragment + run: | + if ! towncrier check --compare-with origin/${{ github.base_ref }}; then + echo "" + echo "No changelog fragment found for this PR." + echo "" + echo "Create a fragment with:" + echo " tox -e new-changelog -- ${{ github.event.pull_request.number }} TYPE \"Description\"" + echo "where TYPE is one of: added, changed, deprecated, removed, fixed" + echo "" + echo "Or add the \"Skip Changelog\" label if this job should be skipped." false fi diff --git a/.github/workflows/prepare-patch-release.yml b/.github/workflows/prepare-patch-release.yml index 8414d82111..a4856eafdd 100644 --- a/.github/workflows/prepare-patch-release.yml +++ b/.github/workflows/prepare-patch-release.yml @@ -14,8 +14,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install toml - run: pip install toml + - name: Install dependencies + run: pip install toml towncrier - run: | if [[ ! $GITHUB_REF_NAME =~ ^release/v[0-9]+\.[0-9]+\.x-0\.[0-9]+bx$ ]]; then @@ -23,11 +23,6 @@ jobs: exit 1 fi - if ! grep --quiet "^## Unreleased$" CHANGELOG.md; then - echo the change log is missing an \"Unreleased\" section - exit 1 - fi - - name: Set environment variables run: | stable_version=$(./scripts/eachdist.py version --mode stable) @@ -62,10 +57,8 @@ jobs: - name: Update version run: .github/scripts/update-version-patch.sh $STABLE_VERSION $UNSTABLE_VERSION $STABLE_VERSION_PREV $UNSTABLE_VERSION_PREV - - name: Update the change log with the approximate release date - run: | - date=$(date "+%Y-%m-%d") - sed -Ei "s/^## Unreleased$/## Version ${STABLE_VERSION}\/${UNSTABLE_VERSION} ($date)/" CHANGELOG.md + - name: Generate changelog + run: towncrier build --yes --version "$STABLE_VERSION/$UNSTABLE_VERSION" - name: Use CLA approved github bot run: .github/scripts/use-cla-approved-github-bot.sh @@ -99,3 +92,31 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh pr edit ${{ steps.create_pr.outputs.pr_url }} --add-label "prepare-release" + + - uses: actions/checkout@v4 + with: + ref: main + + - name: Use CLA approved github bot + run: .github/scripts/use-cla-approved-github-bot.sh + + - name: Backport patch release changelog to main + env: + GITHUB_TOKEN: ${{ steps.otelbot-token.outputs.token }} + run: | + release_branch="otelbot/prepare-release-${STABLE_VERSION}-${UNSTABLE_VERSION}" + message="Backport ${STABLE_VERSION}/${UNSTABLE_VERSION} changelog" + body="Backport \`${STABLE_VERSION}/${UNSTABLE_VERSION}\` changelog" + branch="otelbot/backport-changelog-from-${STABLE_VERSION}-${UNSTABLE_VERSION}" + + git fetch origin $release_branch + + # Copy the updated CHANGELOG.md from the release branch + git checkout $release_branch -- CHANGELOG.md + git commit -m "$message" + + git push origin HEAD:$branch + gh pr create --title "$message" \ + --body "$body" \ + --head $branch \ + --base main diff --git a/.github/workflows/prepare-release-branch.yml b/.github/workflows/prepare-release-branch.yml index ee8e971caf..47874581a3 100644 --- a/.github/workflows/prepare-release-branch.yml +++ b/.github/workflows/prepare-release-branch.yml @@ -27,11 +27,6 @@ jobs: exit 1 fi - if ! grep --quiet "^## Unreleased$" CHANGELOG.md; then - echo the change log is missing an \"Unreleased\" section - exit 1 - fi - if [[ ! -z $PRERELEASE_VERSION ]]; then stable_version=$(./scripts/eachdist.py version --mode stable) stable_version=${stable_version//.dev/} @@ -50,8 +45,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install toml - run: pip install toml + - name: Install dependencies + run: pip install toml towncrier - name: Create release branch env: @@ -88,10 +83,8 @@ jobs: - name: Update version run: .github/scripts/update-version.sh $STABLE_VERSION $UNSTABLE_VERSION - - name: Update the change log with the approximate release date - run: | - date=$(date "+%Y-%m-%d") - sed -Ei "s/^## Unreleased$/## Version ${STABLE_VERSION}\/${UNSTABLE_VERSION} ($date)/" CHANGELOG.md + - name: Generate changelog + run: towncrier build --yes --version "$STABLE_VERSION/$UNSTABLE_VERSION" - name: Use CLA approved github bot run: .github/scripts/use-cla-approved-github-bot.sh @@ -135,8 +128,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install toml - run: pip install toml + - name: Install dependencies + run: pip install toml towncrier - name: Set environment variables env: @@ -184,11 +177,8 @@ jobs: - name: Update version run: .github/scripts/update-version.sh $STABLE_NEXT_VERSION $UNSTABLE_NEXT_VERSION - - name: Update the change log on main - run: | - # the actual release date on main will be updated at the end of the release workflow - date=$(date "+%Y-%m-%d") - sed -Ei "s/^## Unreleased$/## Unreleased\n\n## Version ${STABLE_VERSION}\/${UNSTABLE_VERSION} ($date)/" CHANGELOG.md + - name: Generate changelog + run: towncrier build --yes --version "$STABLE_VERSION/$UNSTABLE_VERSION" - name: Use CLA approved github bot run: .github/scripts/use-cla-approved-github-bot.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 01486fbda9..f98002134c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,3 +19,11 @@ repos: - id: rstcheck additional_dependencies: ['rstcheck[sphinx]'] args: ["--report-level", "warning"] + - repo: local + hooks: + - id: changelog + name: changelog fragment check + language: system + entry: python scripts/check_changelog_fragment.py + pass_filenames: false + always_run: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 91aaf9a7bc..56d2181922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,50 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 > [!IMPORTANT] > We are working on stabilizing the Log signal that would require making deprecations and breaking changes. We will try to reduce the releases that may require an update to your code, especially for instrumentations or for sdk developers. -## Unreleased - -- Apply fixes for `UP` ruff rule - ([#5133](https://github.com/open-telemetry/opentelemetry-python/pull/5133)) -- Switch to SPDX license headers and add CI enforcement - ([#5177](https://github.com/open-telemetry/opentelemetry-python/pull/5177)) -- `opentelemetry-api`: Enforce W3C Baggage size limits on outbound propagation in `W3CBaggagePropagator.inject()`. Previously only inbound extraction enforced limits; now inject also caps entries at 180, individual pairs at 4096 bytes, and total header at 8192 bytes per the W3C Baggage spec. The extract path max_pairs limit now counts all size-valid entries rather than only successfully parsed ones. - ([#5163](https://github.com/open-telemetry/opentelemetry-python/pull/5163)) -- `opentelemetry-sdk`: add `additional_properties` support to generated config models via custom `datamodel-codegen` template, enabling plugin/custom component names to flow through typed dataclasses - ([#5131](https://github.com/open-telemetry/opentelemetry-python/pull/5131)) -- Fix incorrect code example in `create_tracer()` docstring - ([#5072](https://github.com/open-telemetry/opentelemetry-python/issues/5072)) -- `opentelemetry-sdk`: add `load_entry_point` shared utility to declarative file configuration for loading plugins via entry points; refactor propagator loading to use it - ([#5093](https://github.com/open-telemetry/opentelemetry-python/pull/5093)) -- `opentelemetry-sdk`: fix YAML structure injection via environment variable substitution in declarative file configuration; values containing newlines are now emitted as quoted YAML scalars per spec requirement - ([#5091](https://github.com/open-telemetry/opentelemetry-python/pull/5091)) -- `opentelemetry-sdk`: Add `create_logger_provider`/`configure_logger_provider` to declarative file configuration, enabling LoggerProvider instantiation from config files without reading env vars - ([#4990](https://github.com/open-telemetry/opentelemetry-python/pull/4990)) -- `opentelemetry-sdk`: Add `service` resource detector support to declarative file configuration via `detection_development.detectors[].service` - ([#5003](https://github.com/open-telemetry/opentelemetry-python/pull/5003)) -- logs: add exception support to Logger emit and LogRecord attributes - ([#4907](https://github.com/open-telemetry/opentelemetry-python/issues/4907)) -- Drop Python 3.9 support - ([#5076](https://github.com/open-telemetry/opentelemetry-python/pull/5076)) -- `opentelemetry-semantic-conventions`: use `X | Y` union annotation - ([#5096](https://github.com/open-telemetry/opentelemetry-python/pull/5096)) -- `opentelemetry-sdk`: Fix `ProcessResourceDetector` to use `sys.orig_argv` so that `process.command`, `process.command_line`, and `process.command_args` reflect the original invocation for `python -m ` runs (where `sys.argv[0]` is rewritten to the module path) - ([#5083](https://github.com/open-telemetry/opentelemetry-python/pull/5083)) -- `opentelemetry-sdk`: make resource detector ordering deterministic - ([#5120](https://github.com/open-telemetry/opentelemetry-python/pull/5120)) -- Add WeaverLiveCheck test util - ([#5088](https://github.com/open-telemetry/opentelemetry-python/pull/5088)) -- Fix incorrect type annotation on `detectors` parameter of `get_aggregated_resources` - ([#5135](https://github.com/open-telemetry/opentelemetry-python/pull/5135)) -- ci: wait for tracecontext server readiness instead of a fixed sleep in `scripts/tracecontext-integration-test.sh` - ([#5149](https://github.com/open-telemetry/opentelemetry-python/pull/5149)) -- `opentelemetry-api`: update `EnvironmentGetter` and `EnvironmentSetter` to use normalized environment variable names - ([#5119](https://github.com/open-telemetry/opentelemetry-python/pull/5119)) -- `opentelemetry-sdk`: only load entrypoints for resource detectors if they are configured via `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS` - ([#5145](https://github.com/open-telemetry/opentelemetry-python/pull/5145)) -- `opentelemetry-exporter-otlp-json-common`: add 'opentelemetry-exporter-otlp-json-common' package for OTLP JSON exporters - ([#4996](https://github.com/open-telemetry/opentelemetry-python/pull/4996)) -- `opentelemetry-exporter-otlp-proto-grpc`: make retryable gRPC error codes configurable for gRPC exporters - ([#4917](https://github.com/open-telemetry/opentelemetry-python/pull/4917)) + ## Version 1.41.0/0.62b0 (2026-04-09) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 820c0f3e10..84ae63973a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,6 +73,45 @@ You can run `tox` with the following arguments: - `tox -e tracecontext` to run integration tests for tracecontext. - `tox -e precommit` to run all `pre-commit` actions +### Changelog + +This project uses [towncrier](https://towncrier.readthedocs.io/) to manage the changelog. Instead of editing `CHANGELOG.md` directly, each PR should include a changelog fragment file in the `.changelog/` directory. + +**Creating a changelog fragment:** + +```console +tox -e new-changelog -- PR_NUMBER TYPE "Description of the change" +``` + +Where `TYPE` is one of: `added`, `changed`, `deprecated`, `removed`, `fixed`. + +For example: + +```console +tox -e new-changelog -- 1234 added "`opentelemetry-sdk`: add support for new feature" +``` + +This creates a file `.changelog/1234.added` containing the description. You can also create the file manually — it's just a text file with the description on one line. + +**Writing a good changelog entry:** + +- Write in imperative tone, as if completing the phrase "This change will..." +- Keep entries concise — ideally under 80 characters +- Prefix with the affected package name when applicable (e.g. `` `opentelemetry-sdk`: ... ``) +- Don't include the PR number — towncrier adds it automatically + +**Preview the changelog:** + +```console +tox -e changelog +``` + +Running `tox -e precommit` will check that a changelog fragment exists for your branch and remind you to create one if missing. + +The CI will also verify that a changelog fragment exists and that `CHANGELOG.md` is not directly modified. + +If your change does not need a changelog entry, add the "Skip Changelog" label to the PR. + `ruff check` and `ruff format` are executed when `tox -e ruff` is run. We strongly recommend you to configure [pre-commit](https://pre-commit.com/) locally to run `ruff` and `rstcheck` automatically before each commit by installing it as git hooks. You just need to [install pre-commit](https://pre-commit.com/#install) in your environment: ```console diff --git a/pyproject.toml b/pyproject.toml index 83b489aa94..66e4a17920 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -165,6 +165,40 @@ target-python-version = "3.10" custom-template-dir = "opentelemetry-sdk/codegen" additional-imports = "typing.ClassVar,opentelemetry.sdk._configuration._common._additional_properties" +[tool.towncrier] +directory = ".changelog" +filename = "CHANGELOG.md" +start_string = "\n" +template = "scripts/changelog_template.j2" +issue_format = "[#{issue}](https://github.com/open-telemetry/opentelemetry-python/pull/{issue})" +wrap = true # wrap fragments to 79 char line length +issue_pattern = "^(\\d+)" # only PR numbers as fragment prefix (e.g. 1234.fixed) + +[[tool.towncrier.type]] +directory = "added" +name = "Added" +showcontent = true + +[[tool.towncrier.type]] +directory = "changed" +name = "Changed" +showcontent = true + +[[tool.towncrier.type]] +directory = "deprecated" +name = "Deprecated" +showcontent = true + +[[tool.towncrier.type]] +directory = "removed" +name = "Removed" +showcontent = true + +[[tool.towncrier.type]] +directory = "fixed" +name = "Fixed" +showcontent = true + [dependency-groups] dev = [ "tox", @@ -172,4 +206,5 @@ dev = [ "pre-commit", "datamodel-code-generator[http]", "datamodel-code-generator[ruff]", + "towncrier", ] diff --git a/scripts/changelog_template.j2 b/scripts/changelog_template.j2 new file mode 100644 index 0000000000..55ac56fe53 --- /dev/null +++ b/scripts/changelog_template.j2 @@ -0,0 +1,24 @@ +## Version {{ versiondata.version }} ({{ versiondata.date }}) + +{% for section, _ in sections.items() %} +{%- if section %}{{ section }}{% endif -%} + +{% if sections[section] %} +{% for category, val in definitions.items() if category in sections[section] %} +### {{ definitions[category]['name'] }} + +{% for text, values in sections[section][category].items() %} +{% if "\n - " in text or '\n * ' in text %} +{%- set main_text, sub_items = text.split('\n', 1) %} +- {{ main_text }} ({{ values|join(', ') }}) +{% if sub_items %} + {{- sub_items }} +{% endif %} +{% else %} +- {{ text }} ({{ values|join(', ') }}) +{% endif %} +{% endfor %} + +{% endfor %} +{% endif %} +{% endfor %} diff --git a/scripts/check_changelog_fragment.py b/scripts/check_changelog_fragment.py new file mode 100644 index 0000000000..b1c34b78d9 --- /dev/null +++ b/scripts/check_changelog_fragment.py @@ -0,0 +1,81 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Check for changelog fragments on feature branches. + +Used as a pre-commit hook via .pre-commit-config.yaml (runs with tox -e precommit). +""" + +import subprocess +import sys + + +def main(): + # Find the merge base with origin/main + try: + merge_base = subprocess.run( + ["git", "merge-base", "origin/main", "HEAD"], + capture_output=True, + text=True, + check=True, + ).stdout.strip() + except subprocess.CalledProcessError: + # Can't determine merge base (e.g. shallow clone, no remote) + return 0 + + # Check if we're on main itself + try: + current_ref = subprocess.run( + ["git", "rev-parse", "HEAD"], + capture_output=True, + text=True, + check=True, + ).stdout.strip() + except subprocess.CalledProcessError: + return 0 + + if merge_base == current_ref: + # On main or no divergence, skip check + return 0 + + # Check if any changelog fragments have been added + try: + diff_output = subprocess.run( + [ + "git", + "diff", + "--diff-filter=A", + "--name-only", + merge_base, + "--", + ".changelog/", + ], + capture_output=True, + text=True, + check=True, + ).stdout.strip() + except subprocess.CalledProcessError: + return 0 + + if diff_output: + # Fragment(s) found + return 0 + + print("⚠ No changelog fragment found on this branch.") + print() + print("Create one with:") + print( + ' tox -e new-changelog -- PR_NUMBER TYPE "Description"' + ) + print( + " where TYPE is one of: added, changed, deprecated, removed, fixed" + ) + print() + print( + "Or skip this check with: SKIP=changelog tox -e precommit" + ) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tox.ini b/tox.ini index 22bdbbd77d..c79ee2389e 100644 --- a/tox.ini +++ b/tox.ini @@ -103,6 +103,8 @@ envlist = lint-opentelemetry-test-utils lint-license-header-check + changelog + new-changelog spellcheck tracecontext typecheck @@ -355,6 +357,28 @@ commands = commands_post = docker-compose down -v +[testenv:changelog] +description = Preview the changelog that would be generated from current fragments +deps = + towncrier +commands = + towncrier build --draft --version Unreleased {posargs} + +[testenv:new-changelog] +description = Create a new changelog fragment: tox -e new-changelog -- PR_NUMBER TYPE "DESCRIPTION" +deps = +allowlist_externals = + python +commands = + python -c "import sys; \ + args = sys.argv[1:]; \ + len(args) >= 3 or sys.exit('Usage: tox -e new-changelog -- PR_NUMBER TYPE DESCRIPTION\\nTYPE must be one of: added, changed, deprecated, removed, fixed'); \ + pr, typ, desc = args[0], args[1], ' '.join(args[2:]); \ + typ in ('added', 'changed', 'deprecated', 'removed', 'fixed') or sys.exit(f'Invalid type: {{typ}}. Must be one of: added, changed, deprecated, removed, fixed'); \ + open(f'.changelog/{{pr}}.{{typ}}', 'w').write(desc + '\\n'); \ + print(f'Created .changelog/{{pr}}.{{typ}}')" \ + {posargs} + [testenv:lint-license-header-check] commands = python {toxinidir}/scripts/check_license_header.py From fd3eef6e0bd8581de4121f45c793a035635e602d Mon Sep 17 00:00:00 2001 From: Mike Goldsmith Date: Fri, 8 May 2026 13:19:27 +0100 Subject: [PATCH 2/3] keep existing unreleased entries, add marker above them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Existing ## Unreleased entries stay in CHANGELOG.md — the towncrier marker is placed above them. Fragment migration can happen at the next release. Assisted-by: Claude Opus 4.6 --- .changelog/4907.added | 1 - .changelog/4917.added | 1 - .changelog/4990.added | 1 - .changelog/4996.added | 1 - .changelog/5003.added | 1 - .changelog/5072.fixed | 1 - .changelog/5076.removed | 1 - .changelog/5083.fixed | 1 - .changelog/5088.added | 1 - .changelog/5091.fixed | 1 - .changelog/5093.added | 1 - .changelog/5096.changed | 1 - .changelog/5119.changed | 1 - .changelog/5120.fixed | 1 - .changelog/5131.added | 1 - .changelog/5133.changed | 1 - .changelog/5135.fixed | 1 - .changelog/5145.changed | 1 - .changelog/5149.fixed | 1 - .changelog/5163.changed | 1 - .changelog/5177.changed | 1 - CHANGELOG.md | 45 +++++++++++++++++++++++++++++++++++++++++ 22 files changed, 45 insertions(+), 21 deletions(-) delete mode 100644 .changelog/4907.added delete mode 100644 .changelog/4917.added delete mode 100644 .changelog/4990.added delete mode 100644 .changelog/4996.added delete mode 100644 .changelog/5003.added delete mode 100644 .changelog/5072.fixed delete mode 100644 .changelog/5076.removed delete mode 100644 .changelog/5083.fixed delete mode 100644 .changelog/5088.added delete mode 100644 .changelog/5091.fixed delete mode 100644 .changelog/5093.added delete mode 100644 .changelog/5096.changed delete mode 100644 .changelog/5119.changed delete mode 100644 .changelog/5120.fixed delete mode 100644 .changelog/5131.added delete mode 100644 .changelog/5133.changed delete mode 100644 .changelog/5135.fixed delete mode 100644 .changelog/5145.changed delete mode 100644 .changelog/5149.fixed delete mode 100644 .changelog/5163.changed delete mode 100644 .changelog/5177.changed diff --git a/.changelog/4907.added b/.changelog/4907.added deleted file mode 100644 index e09de088a8..0000000000 --- a/.changelog/4907.added +++ /dev/null @@ -1 +0,0 @@ -logs: add exception support to Logger emit and LogRecord attributes diff --git a/.changelog/4917.added b/.changelog/4917.added deleted file mode 100644 index fff01bc690..0000000000 --- a/.changelog/4917.added +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-exporter-otlp-proto-grpc`: make retryable gRPC error codes configurable for gRPC exporters diff --git a/.changelog/4990.added b/.changelog/4990.added deleted file mode 100644 index 83da399881..0000000000 --- a/.changelog/4990.added +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-sdk`: Add `create_logger_provider`/`configure_logger_provider` to declarative file configuration diff --git a/.changelog/4996.added b/.changelog/4996.added deleted file mode 100644 index ca0c259fe3..0000000000 --- a/.changelog/4996.added +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-exporter-otlp-json-common`: add 'opentelemetry-exporter-otlp-json-common' package for OTLP JSON exporters diff --git a/.changelog/5003.added b/.changelog/5003.added deleted file mode 100644 index bf1b364aa2..0000000000 --- a/.changelog/5003.added +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-sdk`: Add `service` resource detector support to declarative file configuration diff --git a/.changelog/5072.fixed b/.changelog/5072.fixed deleted file mode 100644 index 6219ae328b..0000000000 --- a/.changelog/5072.fixed +++ /dev/null @@ -1 +0,0 @@ -Fix incorrect code example in `create_tracer()` docstring diff --git a/.changelog/5076.removed b/.changelog/5076.removed deleted file mode 100644 index 461f9bb978..0000000000 --- a/.changelog/5076.removed +++ /dev/null @@ -1 +0,0 @@ -Drop Python 3.9 support diff --git a/.changelog/5083.fixed b/.changelog/5083.fixed deleted file mode 100644 index 98d76b6d80..0000000000 --- a/.changelog/5083.fixed +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-sdk`: Fix `ProcessResourceDetector` to use `sys.orig_argv` diff --git a/.changelog/5088.added b/.changelog/5088.added deleted file mode 100644 index d2e770a3ce..0000000000 --- a/.changelog/5088.added +++ /dev/null @@ -1 +0,0 @@ -Add WeaverLiveCheck test util diff --git a/.changelog/5091.fixed b/.changelog/5091.fixed deleted file mode 100644 index 4f2e9d9612..0000000000 --- a/.changelog/5091.fixed +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-sdk`: fix YAML structure injection via environment variable substitution in declarative file configuration diff --git a/.changelog/5093.added b/.changelog/5093.added deleted file mode 100644 index ba63d6ce4d..0000000000 --- a/.changelog/5093.added +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-sdk`: add `load_entry_point` shared utility to declarative file configuration for loading plugins via entry points diff --git a/.changelog/5096.changed b/.changelog/5096.changed deleted file mode 100644 index 2a353c0d15..0000000000 --- a/.changelog/5096.changed +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-semantic-conventions`: use `X | Y` union annotation diff --git a/.changelog/5119.changed b/.changelog/5119.changed deleted file mode 100644 index 210d574006..0000000000 --- a/.changelog/5119.changed +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-api`: update `EnvironmentGetter` and `EnvironmentSetter` to use normalized environment variable names diff --git a/.changelog/5120.fixed b/.changelog/5120.fixed deleted file mode 100644 index 5e32b8addc..0000000000 --- a/.changelog/5120.fixed +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-sdk`: make resource detector ordering deterministic diff --git a/.changelog/5131.added b/.changelog/5131.added deleted file mode 100644 index cea96df940..0000000000 --- a/.changelog/5131.added +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-sdk`: add `additional_properties` support to generated config models via custom `datamodel-codegen` template diff --git a/.changelog/5133.changed b/.changelog/5133.changed deleted file mode 100644 index 85a97b78e2..0000000000 --- a/.changelog/5133.changed +++ /dev/null @@ -1 +0,0 @@ -Apply fixes for `UP` ruff rule diff --git a/.changelog/5135.fixed b/.changelog/5135.fixed deleted file mode 100644 index d415f31326..0000000000 --- a/.changelog/5135.fixed +++ /dev/null @@ -1 +0,0 @@ -Fix incorrect type annotation on `detectors` parameter of `get_aggregated_resources` diff --git a/.changelog/5145.changed b/.changelog/5145.changed deleted file mode 100644 index 49e6f9def9..0000000000 --- a/.changelog/5145.changed +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-sdk`: only load entrypoints for resource detectors if they are configured via `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS` diff --git a/.changelog/5149.fixed b/.changelog/5149.fixed deleted file mode 100644 index 205826cc62..0000000000 --- a/.changelog/5149.fixed +++ /dev/null @@ -1 +0,0 @@ -ci: wait for tracecontext server readiness instead of a fixed sleep diff --git a/.changelog/5163.changed b/.changelog/5163.changed deleted file mode 100644 index d810f3aa5d..0000000000 --- a/.changelog/5163.changed +++ /dev/null @@ -1 +0,0 @@ -`opentelemetry-api`: Enforce W3C Baggage size limits on outbound propagation in `W3CBaggagePropagator.inject()` diff --git a/.changelog/5177.changed b/.changelog/5177.changed deleted file mode 100644 index c02b345837..0000000000 --- a/.changelog/5177.changed +++ /dev/null @@ -1 +0,0 @@ -Switch to SPDX license headers and add CI enforcement diff --git a/CHANGELOG.md b/CHANGELOG.md index 56d2181922..feb1ed62e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,51 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 +## Unreleased + +- Apply fixes for `UP` ruff rule + ([#5133](https://github.com/open-telemetry/opentelemetry-python/pull/5133)) +- Switch to SPDX license headers and add CI enforcement + ([#5177](https://github.com/open-telemetry/opentelemetry-python/pull/5177)) +- `opentelemetry-api`: Enforce W3C Baggage size limits on outbound propagation in `W3CBaggagePropagator.inject()`. Previously only inbound extraction enforced limits; now inject also caps entries at 180, individual pairs at 4096 bytes, and total header at 8192 bytes per the W3C Baggage spec. The extract path max_pairs limit now counts all size-valid entries rather than only successfully parsed ones. + ([#5163](https://github.com/open-telemetry/opentelemetry-python/pull/5163)) +- `opentelemetry-sdk`: add `additional_properties` support to generated config models via custom `datamodel-codegen` template, enabling plugin/custom component names to flow through typed dataclasses + ([#5131](https://github.com/open-telemetry/opentelemetry-python/pull/5131)) +- Fix incorrect code example in `create_tracer()` docstring + ([#5072](https://github.com/open-telemetry/opentelemetry-python/issues/5072)) +- `opentelemetry-sdk`: add `load_entry_point` shared utility to declarative file configuration for loading plugins via entry points; refactor propagator loading to use it + ([#5093](https://github.com/open-telemetry/opentelemetry-python/pull/5093)) +- `opentelemetry-sdk`: fix YAML structure injection via environment variable substitution in declarative file configuration; values containing newlines are now emitted as quoted YAML scalars per spec requirement + ([#5091](https://github.com/open-telemetry/opentelemetry-python/pull/5091)) +- `opentelemetry-sdk`: Add `create_logger_provider`/`configure_logger_provider` to declarative file configuration, enabling LoggerProvider instantiation from config files without reading env vars + ([#4990](https://github.com/open-telemetry/opentelemetry-python/pull/4990)) +- `opentelemetry-sdk`: Add `service` resource detector support to declarative file configuration via `detection_development.detectors[].service` + ([#5003](https://github.com/open-telemetry/opentelemetry-python/pull/5003)) +- logs: add exception support to Logger emit and LogRecord attributes + ([#4907](https://github.com/open-telemetry/opentelemetry-python/issues/4907)) +- Drop Python 3.9 support + ([#5076](https://github.com/open-telemetry/opentelemetry-python/pull/5076)) +- `opentelemetry-semantic-conventions`: use `X | Y` union annotation + ([#5096](https://github.com/open-telemetry/opentelemetry-python/pull/5096)) +- `opentelemetry-sdk`: Fix `ProcessResourceDetector` to use `sys.orig_argv` so that `process.command`, `process.command_line`, and `process.command_args` reflect the original invocation for `python -m ` runs (where `sys.argv[0]` is rewritten to the module path) + ([#5083](https://github.com/open-telemetry/opentelemetry-python/pull/5083)) +- `opentelemetry-sdk`: make resource detector ordering deterministic + ([#5120](https://github.com/open-telemetry/opentelemetry-python/pull/5120)) +- Add WeaverLiveCheck test util + ([#5088](https://github.com/open-telemetry/opentelemetry-python/pull/5088)) +- Fix incorrect type annotation on `detectors` parameter of `get_aggregated_resources` + ([#5135](https://github.com/open-telemetry/opentelemetry-python/pull/5135)) +- ci: wait for tracecontext server readiness instead of a fixed sleep in `scripts/tracecontext-integration-test.sh` + ([#5149](https://github.com/open-telemetry/opentelemetry-python/pull/5149)) +- `opentelemetry-api`: update `EnvironmentGetter` and `EnvironmentSetter` to use normalized environment variable names + ([#5119](https://github.com/open-telemetry/opentelemetry-python/pull/5119)) +- `opentelemetry-sdk`: only load entrypoints for resource detectors if they are configured via `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS` + ([#5145](https://github.com/open-telemetry/opentelemetry-python/pull/5145)) +- `opentelemetry-exporter-otlp-json-common`: add 'opentelemetry-exporter-otlp-json-common' package for OTLP JSON exporters + ([#4996](https://github.com/open-telemetry/opentelemetry-python/pull/4996)) +- `opentelemetry-exporter-otlp-proto-grpc`: make retryable gRPC error codes configurable for gRPC exporters + ([#4917](https://github.com/open-telemetry/opentelemetry-python/pull/4917)) + ## Version 1.41.0/0.62b0 (2026-04-09) From 9f096aa87bfe43f46521bd691c7296d92b0d2788 Mon Sep 17 00:00:00 2001 From: Mike Goldsmith Date: Fri, 8 May 2026 13:35:50 +0100 Subject: [PATCH 3/3] fix CI: regenerate workflows, update uv.lock, format script - Regenerate misc.yml for new changelog/new-changelog tox envs - Update uv.lock for towncrier dependency - Apply ruff formatting to check_changelog_fragment.py Assisted-by: Claude Opus 4.6 --- .github/workflows/misc.yml | 38 +++++++++++++++++++++++++++++ scripts/check_changelog_fragment.py | 12 +++------ uv.lock | 16 ++++++++++++ 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/.github/workflows/misc.yml b/.github/workflows/misc.yml index 7c5d4285f9..6ee2df60e7 100644 --- a/.github/workflows/misc.yml +++ b/.github/workflows/misc.yml @@ -29,6 +29,44 @@ env: jobs: + changelog: + name: changelog + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -e changelog + + new-changelog: + name: new-changelog + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repo @ SHA - ${{ github.sha }} + uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install tox + run: pip install tox-uv + + - name: Run tests + run: tox -e new-changelog + spellcheck: name: spellcheck runs-on: ubuntu-latest diff --git a/scripts/check_changelog_fragment.py b/scripts/check_changelog_fragment.py index b1c34b78d9..6a45f30598 100644 --- a/scripts/check_changelog_fragment.py +++ b/scripts/check_changelog_fragment.py @@ -64,16 +64,10 @@ def main(): print("⚠ No changelog fragment found on this branch.") print() print("Create one with:") - print( - ' tox -e new-changelog -- PR_NUMBER TYPE "Description"' - ) - print( - " where TYPE is one of: added, changed, deprecated, removed, fixed" - ) + print(' tox -e new-changelog -- PR_NUMBER TYPE "Description"') + print(" where TYPE is one of: added, changed, deprecated, removed, fixed") print() - print( - "Or skip this check with: SKIP=changelog tox -e precommit" - ) + print("Or skip this check with: SKIP=changelog tox -e precommit") return 1 diff --git a/uv.lock b/uv.lock index e3402bd70b..0a37927e0a 100644 --- a/uv.lock +++ b/uv.lock @@ -1054,6 +1054,7 @@ dependencies = [ dev = [ { name = "datamodel-code-generator", extra = ["http", "ruff"] }, { name = "pre-commit" }, + { name = "towncrier" }, { name = "tox" }, { name = "tox-uv" }, ] @@ -1082,6 +1083,7 @@ dev = [ { name = "datamodel-code-generator", extras = ["http"] }, { name = "datamodel-code-generator", extras = ["ruff"] }, { name = "pre-commit" }, + { name = "towncrier" }, { name = "tox" }, { name = "tox-uv", specifier = ">=1" }, ] @@ -1750,6 +1752,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, ] +[[package]] +name = "towncrier" +version = "25.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "jinja2" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/eb/5bf25a34123698d3bbab39c5bc5375f8f8bcbcc5a136964ade66935b8b9d/towncrier-25.8.0.tar.gz", hash = "sha256:eef16d29f831ad57abb3ae32a0565739866219f1ebfbdd297d32894eb9940eb1", size = 76322, upload-time = "2025-08-30T11:41:55.393Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/06/8ba22ec32c74ac1be3baa26116e3c28bc0e76a5387476921d20b6fdade11/towncrier-25.8.0-py3-none-any.whl", hash = "sha256:b953d133d98f9aeae9084b56a3563fd2519dfc6ec33f61c9cd2c61ff243fb513", size = 65101, upload-time = "2025-08-30T11:41:53.644Z" }, +] + [[package]] name = "tox" version = "4.52.1"