Skip to content

[chore] Implement chloggen fragment automation for releases (#2787)#2837

Open
harshitt13 wants to merge 4 commits into
open-telemetry:mainfrom
harshitt13:feat/2787-automate-changelog-generation
Open

[chore] Implement chloggen fragment automation for releases (#2787)#2837
harshitt13 wants to merge 4 commits into
open-telemetry:mainfrom
harshitt13:feat/2787-automate-changelog-generation

Conversation

@harshitt13
Copy link
Copy Markdown

Description:

Feature addition - This PR implements a robust, two-part changelog automation system utilizing the standard OpenTelemetry chloggen fragment pattern. It shifts changelog generation left to the PR level and uses deterministic compilation at release time, preventing release-day bottlenecks, merge conflicts, and AI hallucinations.

  • Part 1: Per-PR Generation (.github/workflows/changelog-fragment.yml)
    • Runs on pull_request.
    • Uses the GitHub Models API (gpt-4o-mini) via the built-in GITHUB_TOKEN to generate a .chloggen/pr-{number}.yaml fragment based on the PR title, body, and changed files.
    • Commits the fragment directly to the user's branch using the opentelemetrybot account (or posts a shell-safe generated comment with the YAML for fork PRs).
    • Includes a required status check (validate-fragment running chloggen validate) to ensure fragment correctness.
  • Part 2: Release Compilation (.github/workflows/draft-release-changelog.yml)
    • Manual workflow_dispatch trigger for the Release Captain.
    • Downloads the official chloggen binary, deterministically compiles all fragments into CHANGELOG.md, clears the .chloggen directory, and opens a PR using the opentelemetrybot account to ensure EasyCLA compliance.
  • Configuration: Added .chloggen/config.yaml and .chloggen/TEMPLATE.yaml to standardize the entries.

Existing Issue(s):

Resolves #2787

Testing:

  • Performed strict local YAML parsing validation on all .chloggen configurations and workflow files using Python yaml.safe_load.
  • Validated whitespace and patch integrity via git diff --check.
  • Verified that the GitHub Action workflows are dependency-free, utilizing native jq and yq available on the ubuntu-latest runner.
  • Note for Reviewers: Please review the initial CI run on this PR to confirm the opentelemetrybot permissions and API payload execution behave as expected in the live environment.

Documentation:

  • Added .chloggen/TEMPLATE.yaml which acts as inline documentation for contributors regarding valid change_type enums and required fields.
  • Added comprehensive comments within the GitHub Actions YAML files detailing the bypass logic (e.g., using [chore] or the Skip Changelog label).

Outstanding items:

  • Branch Protection: Once this PR is merged, an admin will need to navigate to Settings -> Branches and add validate-fragment as a Required Status Check for main to enforce the workflow.
  • Contributor Guide: We may want to add a brief note to CONTRIBUTING.md in a future PR explaining how to use the Skip Changelog label or [chore] prefix to intentionally bypass generation for internal tasks.

Copilot AI review requested due to automatic review settings May 15, 2026 07:18
@harshitt13 harshitt13 requested a review from a team as a code owner May 15, 2026 07:18
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a two-stage chloggen-based changelog automation: a per-PR workflow that uses GitHub Models to generate a .chloggen/pr-<num>.yaml fragment (committing to same-repo branches, commenting instructions for forks) and validates it, plus a manual workflow that compiles all fragments into CHANGELOG.md and opens a release PR via opentelemetrybot. Standardizes fragments with .chloggen/config.yaml and .chloggen/TEMPLATE.yaml.

Changes:

  • Add changelog-fragment.yml workflow: AI-generated fragment per PR, with skip rules ([chore], Skip Changelog label) and a validate-fragment job.
  • Add draft-release-changelog.yml manual workflow that runs chloggen update --version <v> and opens a release PR.
  • Add chloggen config.yaml and TEMPLATE.yaml with the supported change_type enum.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.

File Description
.github/workflows/changelog-fragment.yml Per-PR AI fragment generation, fork-fallback comment, and validation job.
.github/workflows/draft-release-changelog.yml Manual release workflow compiling fragments into CHANGELOG.md and opening a PR.
.chloggen/config.yaml chloggen configuration: allowed change_types, entries dir, changelog target.
.chloggen/TEMPLATE.yaml Fragment template documenting valid change_type values.

Comment thread .github/workflows/changelog-fragment.yml Outdated
Comment thread .github/workflows/changelog-fragment.yml Outdated
Comment thread .github/workflows/changelog-fragment.yml
Comment thread .chloggen/TEMPLATE.yaml Outdated
Comment thread .github/workflows/changelog-fragment.yml Outdated
Comment thread .github/workflows/changelog-fragment.yml Outdated
Comment thread .github/workflows/draft-release-changelog.yml Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f4e62c0f0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/changelog-fragment.yml Outdated
Comment thread .github/workflows/changelog-fragment.yml Outdated
@harshitt13 harshitt13 requested a review from Copilot May 15, 2026 08:00
@harshitt13
Copy link
Copy Markdown
Author

@jaydeluca, could you please review the PR whenever you have a moment?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.

Comments suppressed due to low confidence (1)

.github/workflows/changelog-fragment.yml:223

  • Same $GITHUB_PATH timing issue as in the generate-fragment job: go install puts chloggen in $GOPATH/bin, but the echo >> $GITHUB_PATH on line 222 only takes effect for the next step, so the immediately-following chloggen validate call on line 223 will not find the binary. Either split this into a separate install step, prepend $(go env GOPATH)/bin to PATH via export in the same shell, or call chloggen by absolute path.
          go install go.opentelemetry.io/build-tools/chloggen@v0.15.0
          echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"
          chloggen validate --config .chloggen/config.yaml

Comment thread .github/workflows/changelog-fragment.yml Outdated
Comment thread .github/workflows/changelog-fragment.yml
Comment thread .github/workflows/changelog-fragment.yml Outdated
Comment thread .github/workflows/changelog-fragment.yml
Comment thread .github/workflows/changelog-fragment.yml Outdated
Comment thread .github/workflows/draft-release-changelog.yml Outdated
Comment thread .github/workflows/changelog-fragment.yml
Comment thread .github/workflows/changelog-fragment.yml Outdated
Signed-off-by: Harshit Kushwaha <find.harshitkushwaha@gmail.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (6)

.github/workflows/changelog-fragment.yml:188

  • The generate-fragment job's steps are guarded by github.event.pull_request.head.repo.full_name == github.repository, so for PRs opened from forks no fragment is ever produced. However the downstream validate-fragment job (intended to become a required status check) does not include the same fork guard in its skip logic and unconditionally errors out with missing changelog fragment: ... on line 183. This means every fork PR will permanently fail the required status check with no way to recover, which would effectively block all outside contributions once the status check is enforced. The PR description states fork PRs should instead receive a comment containing the generated YAML, but no such comment-posting step exists in the diff — either that fallback needs to be implemented, or validate-fragment needs to treat fork PRs as a skip case (and the maintainer must add the fragment after merging the PR to a same-repo branch).
      - name: Validate fragment
        env:
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: |
          fragment=".chloggen/pr-${PR_NUMBER}.yaml"

          if [[ ! -f "$fragment" ]]; then
            echo "missing changelog fragment: $fragment"
            exit 1
          fi

          go install go.opentelemetry.io/build-tools/chloggen@v0.15.0
          "$(go env GOPATH)/bin/chloggen" validate --config .chloggen/config.yaml

.github/workflows/changelog-fragment.yml:135

  • The PR description states that for fork PRs the workflow "posts a shell-safe generated comment with the YAML for fork PRs," but the diff contains no gh pr comment / actions/github-script / peter-evans/create-or-update-comment step or any other comment-posting step. The fork branch is silently skipped instead. Either the PR description should be corrected, or the fallback fork-PR comment step should be added.
      - name: Generate fragment
        if: ${{ steps.skip.outputs.skip != 'true' && steps.fragment.outputs.exists != 'true' && github.event.pull_request.head.repo.full_name == github.repository }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
          PR_TITLE: ${{ github.event.pull_request.title }}
          PR_BODY: ${{ github.event.pull_request.body }}
          BASE_REF: ${{ github.event.pull_request.base.ref }}
        run: |
          changed_files="$(git diff --name-only "origin/${BASE_REF}"...HEAD)"

          request_payload="$(jq -n \
            --arg title "$PR_TITLE" \
            --arg body "$PR_BODY" \
            --arg changed_files "$changed_files" \
            '{
              model: "gpt-4o-mini",
              response_format: {type: "json_object"},
              messages: [
                {
                  role: "system",
                  content: "Generate a single JSON object for a changelog fragment. Return only valid JSON with these keys: change_type, component, note, issues, subtext, change_logs. change_type must be one of breaking, deprecation, new_component, enhancement, bug_fix. component must be blank if the PR does not clearly map to one component. note must be a brief end-user facing summary. issues must be an array of issue numbers without #. subtext is optional and may be null or omitted. change_logs must be [\"user\"]. Do not add markdown or extra keys."
                },
                {
                  role: "user",
                  content: "PR title: \($title)\n\nPR body:\n\($body)\n\nChanged files:\n\($changed_files)"
                }
              ]
            }')"

          response="$(curl --fail-with-body --silent --show-error https://models.github.ai/inference/chat/completions \
            -H "Accept: application/vnd.github+json" \
            -H "Content-Type: application/json" \
            -H "Authorization: Bearer ${GITHUB_TOKEN}" \
            -d "$request_payload")"

          jq -r '.choices[0].message.content | fromjson' <<<"$response" | "$(go env GOPATH)/bin/yq" -P - > ".chloggen/pr-${PR_NUMBER}.yaml"

      - name: Validate AI Output
        if: ${{ steps.skip.outputs.skip != 'true' && steps.fragment.outputs.exists != 'true' && github.event.pull_request.head.repo.full_name == github.repository }}
        env:
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: |
          fragment=".chloggen/pr-${PR_NUMBER}.yaml"

          if ! "$(go env GOPATH)/bin/yq" -e 'has("change_type") and has("component") and has("note")' "$fragment" >/dev/null; then
            echo "missing required keys: change_type, component, note"
            rm -f "$fragment"
            exit 1
          fi

      - name: Commit
        if: ${{ steps.skip.outputs.skip != 'true' && steps.fragment.outputs.exists != 'true' && github.event.pull_request.head.repo.full_name == github.repository }}
        env:
          PR_NUMBER: ${{ github.event.pull_request.number }}
          PR_BRANCH: ${{ github.head_ref }}
        run: |
          git config user.name opentelemetrybot
          git config user.email 107717825+opentelemetrybot@users.noreply.github.com
          git add ".chloggen/pr-${PR_NUMBER}.yaml"
          git commit -m "Add changelog fragment for PR #${PR_NUMBER}"
          git push origin HEAD:"${PR_BRANCH}"

.github/workflows/changelog-fragment.yml:170

  • The skip-condition logic (dependabot/renovate bot user, [chore] prefix, Skip Changelog label) is duplicated verbatim between the generate-fragment and validate-fragment jobs (lines 33–54 vs. 149–170). Any future tweak (e.g. adding another skip label or another bot account) must be made in both places and will silently desync. Consider extracting the check into its own small job whose output is consumed via needs.<job>.outputs.skip, or factor it into a reusable composite action.
      - name: Check skip conditions
        id: skip
        env:
          PR_TITLE: ${{ github.event.pull_request.title }}
          PR_LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }}
          PR_USER_LOGIN: ${{ github.event.pull_request.user.login }}
        run: |
          skip=false

          if [[ "$PR_USER_LOGIN" == "dependabot[bot]" || "$PR_USER_LOGIN" == "renovate[bot]" ]]; then
            skip=true
          fi

          if [[ "$PR_TITLE" == \[chore\]* ]]; then
            skip=true
          fi

          if jq -e 'index("Skip Changelog")' <<<"$PR_LABELS" >/dev/null; then
            skip=true
          fi

          echo "skip=$skip" >> "$GITHUB_OUTPUT"

.github/workflows/changelog-fragment.yml:188

  • chloggen is installed inside the validation step on every PR run via go install ...@v0.15.0, which downloads and compiles the binary from source on each invocation. This adds latency to a status check that will run on the majority of PRs. Consider caching the Go build cache (e.g. via actions/setup-go with caching enabled) or downloading a pre-built release artifact instead.
          go install go.opentelemetry.io/build-tools/chloggen@v0.15.0
          "$(go env GOPATH)/bin/chloggen" validate --config .chloggen/config.yaml

.github/workflows/changelog-fragment.yml:31

  • yq is installed via go install on every PR run (line 31). Since yq is a popular tool with prebuilt binaries and the runner already has Go available, this still adds noticeable build time on each invocation. Consider downloading a release binary (curl -L https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_amd64 -o ...) or pinning a setup-go action with module caching.
      - name: Install yq
        run: |
          go install github.com/mikefarah/yq/v4@v4.44.3

.github/workflows/draft-release-changelog.yml:40

  • Third-party action peter-evans/create-pull-request@v6 is referenced by a mutable major-version tag. Other workflows in this repository (and the OpenTelemetry OSSF scorecard configuration this repo uses) generally prefer pinning third-party actions to a full commit SHA with the version as a comment, to avoid supply-chain risk if the tag is re-pointed. Consider pinning to a specific commit SHA.
        uses: peter-evans/create-pull-request@v6

Comment thread .github/workflows/changelog-fragment.yml Outdated
Comment thread .github/workflows/draft-release-changelog.yml Outdated
…ror messaging

Signed-off-by: Harshit Kushwaha <find.harshitkushwaha@gmail.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

.github/workflows/draft-release-changelog.yml:52

  • Trailing whitespace at the end of this line.

Comment on lines +125 to +135
- name: Commit
if: ${{ steps.skip.outputs.skip != 'true' && steps.fragment.outputs.exists != 'true' && github.event.pull_request.head.repo.full_name == github.repository }}
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_BRANCH: ${{ github.head_ref }}
run: |
git config user.name opentelemetrybot
git config user.email 107717825+opentelemetrybot@users.noreply.github.com
git add ".chloggen/pr-${PR_NUMBER}.yaml"
git commit -m "Add changelog fragment for PR #${PR_NUMBER}"
git push origin HEAD:"${PR_BRANCH}"
Comment on lines +137 to +187
validate-fragment:
needs: generate-fragment
if: always()
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.head_ref }}
token: ${{ github.token }}
fetch-depth: 0

- name: Check skip conditions
id: skip
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }}
PR_USER_LOGIN: ${{ github.event.pull_request.user.login }}
run: |
skip=false

if [[ "$PR_USER_LOGIN" == "dependabot[bot]" || "$PR_USER_LOGIN" == "renovate[bot]" ]]; then
skip=true
fi

if [[ "$PR_TITLE" == \[chore\]* ]]; then
skip=true
fi

if jq -e 'index("Skip Changelog")' <<<"$PR_LABELS" >/dev/null; then
skip=true
fi

echo "skip=$skip" >> "$GITHUB_OUTPUT"

- name: Exit if skipped
if: ${{ steps.skip.outputs.skip == 'true' }}
run: exit 0

- name: Validate fragment
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
fragment=".chloggen/pr-${PR_NUMBER}.yaml"

if [[ ! -f "$fragment" ]]; then
echo "❌ Missing changelog fragment: $fragment"
echo "If you are contributing from a fork, you must create this file manually."
echo "Copy the contents of .chloggen/TEMPLATE.yaml into a new file named $fragment, fill it out, and commit it to your branch."
exit 1
fi
Comment on lines +149 to +170
- name: Check skip conditions
id: skip
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }}
PR_USER_LOGIN: ${{ github.event.pull_request.user.login }}
run: |
skip=false

if [[ "$PR_USER_LOGIN" == "dependabot[bot]" || "$PR_USER_LOGIN" == "renovate[bot]" ]]; then
skip=true
fi

if [[ "$PR_TITLE" == \[chore\]* ]]; then
skip=true
fi

if jq -e 'index("Skip Changelog")' <<<"$PR_LABELS" >/dev/null; then
skip=true
fi

echo "skip=$skip" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@v4
with:
fetch-depth: 0

Comment thread .chloggen/pr-2837.yaml
Comment on lines +1 to +6
change_type: enhancement
component:
note: Automate changelog generation using fragment pattern
issues: [2787]
subtext:
change_logs: [user]
Copy link
Copy Markdown
Contributor

@breedx-splk breedx-splk left a comment

Choose a reason for hiding this comment

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

I hate chloggen. It's unnecessarily complicated and makes the process of submitting PRs worse.

Who is asking for this? I don't think the maintainers want this.

@jack-berg
Copy link
Copy Markdown
Member

For things like this, please open an issue to gather consensus from the codeowners (approvers + maintainers) before going and opening a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Tooling] Automate changelog generation

4 participants