Skip to content
Open
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
1 change: 1 addition & 0 deletions .changelog/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!.gitignore
48 changes: 35 additions & 13 deletions .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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
38 changes: 38 additions & 0 deletions .github/workflows/misc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
43 changes: 32 additions & 11 deletions .github/workflows/prepare-patch-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,15 @@ 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
echo this workflow should only be run against long-term release branches
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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
26 changes: 8 additions & 18 deletions .github/workflows/prepare-release-branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/}
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Copy Markdown
Member

@emdneto emdneto May 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would avoid the pre-commit since some changes do not require changelog updates + you need the PR number in advance. i know you can check the last PR in the repo to see what the next number will be

pass_filenames: false
always_run: true
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ 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.

<!-- changelog start -->

## Unreleased

- Apply fixes for `UP` ruff rule
Expand Down
39 changes: 39 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 35 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,46 @@ 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 = "<!-- changelog start -->\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",
"tox-uv>=1",
"pre-commit",
"datamodel-code-generator[http]",
"datamodel-code-generator[ruff]",
"towncrier",
]
24 changes: 24 additions & 0 deletions scripts/changelog_template.j2
Original file line number Diff line number Diff line change
@@ -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 %}
Loading
Loading