Skip to content

Changelog poc/initial test - #40

Open
fivetran-catfritz wants to merge 29 commits into
mainfrom
changelog-poc/initial-test
Open

fivetran-catfritz wants to merge 29 commits into
mainfrom
changelog-poc/initial-test

Conversation

@fivetran-catfritz

@fivetran-catfritz fivetran-catfritz commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

POC for GA-1035597: a structured YAML → CHANGELOG.md pipeline, so release notes are generated from data instead of written by hand each time.

  • .github/scripts/update_changelog.py — reads a single pending .changes/*.yml release file, renders it into the standard CHANGELOG sections (Schema/Data Change table, Feature Update, Bug Fix, Dependency Updates, Under the Hood, Contributors), and prepends it to CHANGELOG.md. Resyncs from origin/main before writing so re-runs (relabel, retry) are idempotent instead of stacking duplicate entries. Prunes .changes/*.yml files older than 30 days.
  • generate-docs.yml — now runs the changelog update as part of the same job that regenerates docs, so there's one checkout/commit/push instead of two workflows racing to push to the same PR branch.
  • check-docs-current.yml — repurposed from a single docs-staleness check into three independent checks (docs regenerated, CHANGELOG.md updated, .changes/*.yml present), and reports specifically which are missing rather than a generic pass/fail.

Trigger: the existing docs:ready label — no new label introduced.

Known limitations / follow-ups

  • Once merged, check-docs-current.yml's new changelog-entry check will fail for any repo that hasn't adopted .changes/ yet on their next PR push - expected, since the team will be required to use the new format going forward, and this check only runs on new PR activity (not retroactively).

Test plan

  • Live end-to-end test in dbt_amazon_ads#52 (draft), repointed to this branch.
  • Verified locally: idempotent re-runs, retention pruning, multi-model/breaking schema table rendering, structured dependencies/contributors, missing .changes/ directory no longer breaks docs generation for repos that haven't adopted the convention yet.

🤖 Generated with Claude Code

fivetran-catfritz and others added 24 commits September 1, 2026 15:53
Reusable workflows called via `uses:` only pull in the workflow YAML
itself, not the calling repo's other files - so the script path never
existed on the runner when invoked from a downstream repo. Since this
repo is public, curl the raw script instead of checking out the whole
repo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
github.workflow_ref reflects the top-level caller's own workflow ref
(e.g. a PR merge ref in dbt_amazon_ads), not this reusable workflow's
ref in dbt_package_automations, so it can't be used to derive the
script URL dynamically. Hardcoding for the POC; revisit once this
lands on main.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The insertion logic assumed any leading '#' lines were a document
title to skip past, but dbt_amazon_ads has no separate title - its
newest entry itself is an H1 (e.g. "# dbt_amazon_ads v1.3.1"). That
caused new entries to land inside the existing top entry instead of
above it. Now only skip a leading '#' line if it doesn't look like a
version header (no "vX.Y.Z"), and stop immediately once one is found.

Also switched rendering to match the real downstream package
convention observed in dbt_amazon_ads: "# {package} v{version}" (no
injected date or breaking-change tag), a "[PR #N](url) includes the
following updates:" line, and H2 sections instead of H3. Dependency
bumps fold into Under the Hood since there's no separate category for
them in the standard section list.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Per ~/.claude/package_contents/the_changelog.md and existing Fivetran
package changelogs (dbt_apple_store, dbt_asana): contributors get
their own "## Contributors" section with linked GitHub handles, and
schema/data changes render as a table with a total/breaking-change
summary line, breaking changes sorted first.

schema_data_changes.entries is now a list of structured objects
(model, change_type, old, new, notes, breaking) instead of flat
strings, to populate the table columns.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Real Fivetran package changelogs (ad_reporting, google_ads, hubspot,
klaviyo, shopify, zendesk, ...) consistently use a "## Dependency
Updates" section rather than folding bumps into Under the Hood.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
new_features used {title, description}, bug_fixes used {description}
only, and dependencies/under_the_hood were bare strings - inconsistent
shapes across otherwise-identical bullet sections. All four now go
through a shared render_bullets() helper: every item is either a
plain string or {description, title?, details?}, where details
renders as indented sub-bullets under the main bullet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Per the design in GA-1035597:
- Add .changes/config.yaml (package, repo_url, per-section headings)
  and have update_changelog.py read it instead of hardcoding those
  values, falling back to GITHUB_REPOSITORY/defaults when absent.
- schema_data_changes entries take a `models` list (was singular
  `model`), matching the "same change across multiple models -> one
  row" rule, and use `is_breaking` instead of `breaking` for naming
  consistency with the rest of the schema.
- dependencies accepts structured {package, old_version, new_version,
  description} bump records, rendering as "Bumps `pkg` from X to Y",
  in addition to plain strings.
- contributors accepts structured {name, github_handle, is_fivetran,
  contribution} records alongside bare handles.
- hide_from_docs is accepted throughout (schema entries, features,
  bug fixes, dependencies, under_the_hood, contributors, top-level)
  but intentionally has no effect on CHANGELOG.md rendering - it's
  metadata for the future JSON/docs consumer, not this pipeline.
- Updated .changes/1.6.1.yaml to exercise every field.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Without an explicit token, actions/checkout falls back to the default
GITHUB_TOKEN, which authenticates as the github-actions[bot] app
installation. Setting git config user.name/email only changes the
commit author/committer metadata - it doesn't change who GitHub
attributes the push (and the resulting PR "synchronize" event) to.
generate-docs.yml already does this correctly via secrets.GH_TOKEN;
this brings update-changelog.yml in line with it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Matches the format update made in dbt_amazon_ads's .changes/1.3.2.yaml:
pr: {number: N} is now a flat pr_number field, and a contributor's own
pr_number (when they contributed via a different PR than the one
driving this release) overrides the release-level pr_number for their
Contributors line.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
dbt_package_automations is tooling, not a dbt package released through
this pipeline, so it has no releases of its own to track here. The
example/test YAML and config.yaml moved to dbt_amazon_ads, which is
what actually exercises them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
dbt_amazon_ads renamed its .changes/ files from .yaml to .yml, which
the script's hardcoded "*.yaml" globs silently missed - it kept
reporting "nothing to add" since no file matched. release_yaml_files()
now globs both extensions (excluding config.yml/config.yaml by stem),
and load_config() checks config.yml before falling back to config.yaml.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
.yaml support was unneeded complexity - the pipeline only needs to
recognize one extension, and .yml is the established convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… table

Comma-joining models in the Data Model(s) cell reads poorly once
there's more than one; <br> puts each on its own line within the
cell. The (Breaking) tag now gets its own line too instead of being
appended inline.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reuses the label generate-docs.yml already listens for, rather than
introducing a separate changelog:ready label for downstream repos to
manage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Was a list of {name: ...} objects - one key wrapping one string, for
no benefit, and it doubled up the dash-list nesting in an already
list-heavy structure. models is now just a flat list of model name
strings.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Section headings and package/repo_url derivation now live directly in
update_changelog.py (SECTION_HEADINGS, repo_info()) instead of being
overridable per-repo via .changes/config.yml. Keeps every package's
changelog using the same standard section names.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
….yml

Both workflows were separately triggered by pull_request labeled and
independently checked out/committed/pushed to the same PR branch,
risking a push race (one job's push getting rejected as non-fast-
forward by the other's). Running the changelog update as steps inside
generate-docs.yml's existing job means one checkout, one CHANGELOG.md
update, one git add/commit/push - no more race, since it's now
strictly serial within a single job. Both docs and changelog updates
land in the same commit.

update_changelog.py itself is unchanged and still lives at
.github/scripts/update_changelog.py; only the standalone reusable
workflow that called it on its own is removed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
git add on a nonexistent pathspec fails (exit 128), and Actions runs
steps under bash -e, so `git add docs/ .changes/ CHANGELOG.md` would
abort the whole commit step - and therefore fail docs generation
entirely - for any repo that hasn't adopted the .changes/ convention
yet (every repo except dbt_amazon_ads today). mkdir -p .changes first
guarantees the pathspec always resolves; an empty directory just adds
nothing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…anges/*.yml

Was a single docs-staleness check. Now runs the same "relevant changes
since this path was last touched" logic against docs/, CHANGELOG.md,
and .changes/ independently, and reports specifically which of the
three are missing/stale in the docs/generated status description
(e.g. "Missing: CHANGELOG.md update, a .changes/*.yml entry") instead
of a generic pass/fail. Still removes the docs:ready label if anything
is missing, and keeps the same "docs/generated" status context so
existing branch protection rules aren't affected.

Verified against four scenarios locally: only-model-changed (all three
flagged), everything current (success), stale-again after a later
relevant change (all three flagged again), and irrelevant-only changes
(success).

Note: for any repo that hasn't adopted .changes/ yet, this will always
report the changelog-entry check as missing whenever a relevant change
is made, since no commit has ever touched that path. That's correct
enforcement once a repo opts in, but means this shouldn't go to @main
until repos are ready to adopt the .changes/ convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This repo doesn't do dbt-style releases, but tracking this change is
worth it given its scope: the new update_changelog.py pipeline, its
merge into generate-docs.yml, and the repurposed three-way
check-docs-current.yml check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@fivetran-joemarkiewicz fivetran-joemarkiewicz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@fivetran-catfritz great work on this. A few changes before approving.

# Update this ref once that work lands on main.
run: |
curl -sSfL \
"https://raw.githubusercontent.com/fivetran/dbt_package_automations/refs/heads/changelog-poc/initial-test/.github/scripts/update_changelog.py" \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reminder to update before merging

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

reminder to update before merging

Comment thread .github/scripts/update_changelog.py Outdated
Comment thread .github/workflows/generate-docs.yml
Comment thread .github/scripts/update_changelog.py Outdated
Comment thread .github/scripts/update_changelog.py Outdated
fivetran-catfritz and others added 3 commits October 5, 2026 16:49
… README

- Bump RETENTION_DAYS 30 -> 45: docs publish monthly, and 30 days risked
  pruning a .changes/*.yml file before a busy month's docs run picked it up.
- Fix release_yaml_files() to sort by parsed version tuple instead of
  lexically - sorted() alone put "1.10.1.yml" before "1.9.0.yml".
- Remove is_fivetran from the contributor schema - never read by
  render_contributor_bullets, and there's no case for differentiating
  internal/external credit.
- Add a .changes/*.yml field reference table to the README, documenting
  every supported field and explicitly flagging which ones (hide_from_docs
  everywhere, is_breaking on a dependency item) are accepted but inert for
  CHANGELOG.md rendering - reserved for a future docs-side consumer.

Pre-release version handling (e.g. "1.2.0-beta.1") is intentionally left
open pending input on whether/how Fivetran packages ship those.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Answers the open question from review: Fivetran packages use -a1, -a2
for pre-releases and -b1, -b2 for betas. _version_sort_key now parses
that suffix and ranks pre-releases before that version's final release
(1.3.0-a1 < 1.3.0-a2 < 1.3.0-b1 < 1.3.0-b2 < 1.3.0), instead of lumping
every non-plain-numeric filename at the end indiscriminately.

Verified end-to-end with a -b1 release file rendering correctly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The field reference table alone doesn't show how the pieces fit
together. Adds a complete worked example exercising every field,
verified by running it through update_changelog.py directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nt the README example

- templates/changes-template.yml: a blank, copy-paste-ready .changes/*.yml
  with inline comments for every field.
- check-docs-current.yml: when a .changes/*.yml entry is specifically what's
  missing, the docs/generated failure status's target_url now points to
  that template, so the link is directly actionable from the PR's status
  checks instead of just saying what's missing. Switched status payload
  construction to jq -n (matches the pattern already used in
  auto-release.yml) instead of manual string interpolation.
- README: the example .changes/1.3.0.yml now carries inline field comments
  in the same style used for `vars:` blocks in package READMEs, rather than
  relying solely on the separate reference table. Links to the new template.

Verified: both the commented README example and the template parse and
render identically to the uncommented version through update_changelog.py.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread .github/scripts/update_changelog.py
Comment thread README.md
Comment thread .github/scripts/update_changelog.py
Comment thread .github/scripts/update_changelog.py
@fivetran-catfritz

Copy link
Copy Markdown
Contributor Author

@fivetran-joemarkiewicz made the updates, and also updated the branch protections!

@fivetran-joemarkiewicz fivetran-joemarkiewicz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Two small comments before approval

Comment thread README.md Outdated
Comment thread .github/scripts/update_changelog.py Outdated
discover_pending_yaml used a plain substring check (f"v{version}" not in
changelog_text), so once a pre-release like v1.3.0-a1 was published,
the final v1.3.0 release would be silently treated as already-released
and skipped - "v1.3.0" is a substring of "v1.3.0-a1". Replaced with
_version_already_released(), which requires the match not be followed
by another version-continuation character (digit, ".", or "-").

Verified: v1.3.0 is no longer falsely matched against v1.3.0-a1 or
v1.3.0-b10 vs v1.3.0-b1, a genuine v1.3.0 header still matches
correctly, and a full pipeline run now correctly renders a pending
v1.3.0 entry even with v1.3.0-a1 already in CHANGELOG.md.

Also reworded the retention note in the README: pruning happens as
part of the next invocation of this action (triggered by any release
in the repo), not on a separate schedule.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread README.md
Comment thread .github/scripts/update_changelog.py

@fivetran-joemarkiewicz fivetran-joemarkiewicz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved. Hold off merging.

# Update this ref once that work lands on main.
run: |
curl -sSfL \
"https://raw.githubusercontent.com/fivetran/dbt_package_automations/refs/heads/changelog-poc/initial-test/.github/scripts/update_changelog.py" \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

reminder to update before merging

# Update this ref once that work lands on main.
run: |
curl -sSfL \
"https://raw.githubusercontent.com/fivetran/dbt_package_automations/refs/heads/changelog-poc/initial-test/.github/scripts/update_changelog.py" \

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
"https://raw.githubusercontent.com/fivetran/dbt_package_automations/refs/heads/changelog-poc/initial-test/.github/scripts/update_changelog.py" \
"https://raw.githubusercontent.com/fivetran/dbt_package_automations/refs/heads/main/.github/scripts/update_changelog.py" \

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.

2 participants