Skip to content
Merged
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
23 changes: 23 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Tests

on:
push:
branches:
- master
pull_request:

jobs:
python-tests:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v5

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'

- name: Run tests
run: python3 -m unittest discover -s tests -v
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Agent Guidelines

- Keep changes small and focused.
- Follow the existing code style.
- Prefer simple, clear solutions.
- Run relevant checks when possible.
- Do not modify unrelated files.
226 changes: 63 additions & 163 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,206 +1,106 @@
# Changelog Action
Github Action to generate a `CHANGELOG.md` on new tags.

This action is split into four steps:
1. [Prepare](#prepare-action) - Collects tag data, PRs, commits, and repository statistics.
2. [Generate](#generate-action) - Uses Claude Code AI to generate a human-readable changelog.
3. [Notify](#notify-action) - Reformats the changelog with Claude Code AI and sends it via Telegram.
4. [Annotate](#annotate-action) - Annotates the new tag on tracking platforms (e.g. Mixpanel).
GitHub Action to generate a `CHANGELOG.md` on new tags, with optional Telegram notifications and Mixpanel annotations.

## Prepare Action
## Breaking changes in 2.x

### Inputs
- The action now lives at the repository root and is used as `Waveful/ChangelogAction@2`.
- The old split actions (`/generate`, `/notify`, `/annotate`) have been removed from the default setup.
- Changelog generation is always the default behavior.
- Telegram notification only runs when `telegram-bot-token`, `telegram-chat-id`, and `changelog-url` are all provided.
- Mixpanel annotation only runs when `mixpanel-project-id` and `mixpanel-token` are provided.

## Inputs

| Name | Description | Value Type | Required | Default Value |
|------|-------------|------------|----------|---------------|
| `github-token` | GitHub Token for Auth | string | Yes | - |

### Outputs
| `target-branch` | Branch where `CHANGELOG.md` will be committed | string | No | `master` |
| `github-token` | GitHub token for checkout, PR queries, and push | string | Yes | - |
| `github-username` | Git author name for the changelog commit | string | No | `Dolful` |
| `github-email` | Git author email for the changelog commit | string | No | `github-bot@waveful.app` |
| `openai-base-url` | Base URL for an OpenAI-compatible provider | string | No | `https://api.openai.com/v1` |
| `openai-api-key` | API key for the configured provider | string | Yes | - |
| `openai-model` | Model name exposed by the configured provider | string | Yes | - |
| `openai-temperature` | Sampling temperature for changelog generation | string | No | `0.2` |
| `openai-auth-header` | Authentication header name for advanced providers | string | No | `Authorization` |
| `openai-auth-prefix` | Prefix prepended to the API key in the auth header | string | No | `Bearer ` |
| `previous-tag` | Optional previous tag override for manual runs | string | No | empty |
| `current-tag` | Optional current tag override for manual runs | string | No | empty |
| `telegram-bot-token` | Telegram bot token for optional notifications | string | No | empty |
| `telegram-chat-id` | Telegram chat ID for optional notifications | string | No | empty |
| `changelog-url` | Public changelog URL used in optional Telegram notifications | string | No | empty |
| `mixpanel-tag-group` | Mixpanel annotation group for optional release annotations | string | No | `github-action` |
| `mixpanel-project-id` | Mixpanel project ID for optional release annotations | string | No | empty |
| `mixpanel-token` | Mixpanel token (Basic Auth) for optional release annotations | string | No | empty |
| `mixpanel-region-domain` | Mixpanel region domain for optional release annotations | string | No | `mixpanel` |

## Outputs

| Name | Description |
|------|-------------|
| `previous-tag` | Previous tag |
| `current-tag` | Current tag |
| `previous-tag` | Previous tag used for the release range |
| `current-tag` | Current tag used for the release range |
| `pr-count` | Number of PRs merged |
| `commit-count` | Number of commits |
| `author-count` | Number of unique authors |
| `files-changed` | Number of files changed |
| `additions` | Number of lines added |
| `deletions` | Number of lines deleted |
| `prs` | PR details with commits and AI summaries (base64 encoded) |
| `commits` | All commits including those not in PRs (base64 encoded, excludes automated changelog commits) |

Note: the `prepare` action automatically excludes commits generated by the `generate` action (`docs: update changelog for ...`) so they are not fed back into the next AI changelog generation.

## Generate Action

### Inputs

| Name | Description | Value Type | Required | Default Value |
|------|-------------|------------|----------|---------------|
| `target-branch` | Target branch | string | No | `master` |
| `github-token` | GitHub Token for Auth | string | Yes | - |
| `github-username` | GitHub Username | string | No | `Dolful` |
| `github-email` | GitHub Email | string | No | `github-bot@waveful.app` |
| `claude-code-oauth-token` | Claude Code OAuth Token | string | Yes | - |
| `previous-tag` | Previous tag | string | Yes | - |
| `current-tag` | Current tag | string | Yes | - |
| `prs` | PR details (base64 encoded, from prepare step) | string | Yes | - |
| `commits` | All commits (base64 encoded, from prepare step) | string | Yes | - |

### Outputs

| Name | Description |
|------|-------------|
| `changelog` | Changelog (base64 encoded) |

## Notify Action

### Inputs

| Name | Description | Value Type | Required | Default Value |
|------|-------------|------------|----------|---------------|
| `changelog` | Changelog (base64 encoded, from generate step) | string | Yes | - |
| `claude-code-oauth-token` | Claude Code OAuth Token | string | Yes | - |
| `telegram-bot-token` | Telegram Bot Token | string | Yes | - |
| `telegram-chat-id` | Telegram Chat ID for notification | string | Yes | - |
| `changelog-url` | URL to the changelog file | string | Yes | - |

### Outputs

This action does not produce any outputs. It sends a notification to Telegram with the changelog summary.

## Annotate Action

### Inputs

| Name | Description | Value Type | Required | Default Value |
|------|-------------|------------|----------|---------------|
| `tag` | Tag to annotate | string | Yes | - |
| `mixpanel-tag-group` | Mixpanel annotation group | string | No | `github-action` |
| `mixpanel-project-id` | Mixpanel Project ID | string | No | - |
| `mixpanel-token` | Mixpanel Token (Basic Auth) | string | No | - |
| `mixpanel-region-domain` | Mixpanel Region Domain | string | No | `mixpanel` |

### Outputs

This action does not produce any outputs. It creates an annotation on the configured tracking platform(s).

## Usage
###### prepare.yml

```yaml
name: Prepare
name: Changelog

on:
push:
tags:
- '*'

permissions:
contents: read
pull-requests: read
actions: write

jobs:
prepare-data:
runs-on: ubuntu-latest
name: Prepare PRs, Commits and Statistics
steps:

- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0 # important! fetches full history & tags

- name: Prepare Data
id: prepare
uses: Waveful/ChangelogAction/prepare@1.2.2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Print Statistics
id: statistics
run: |
echo "Authors: ${{ steps.prepare.outputs.author-count }}"
echo "PRs: ${{ steps.prepare.outputs.pr-count }}"
echo "Commits: ${{ steps.prepare.outputs.commit-count }}"
echo "File changed: ${{ steps.prepare.outputs.files-changed }}"
echo "Additions / Deletions: ${{ steps.prepare.outputs.additions }} / ${{ steps.prepare.outputs.deletions }}"

- name: Trigger Changelog
id: trigger-changelog
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh workflow run changelog.yml \
-f from-ref="${{ steps.prepare.outputs.previous-tag }}" \
-f to-ref="${{ steps.prepare.outputs.current-tag }}" \
-f commits="${{ steps.prepare.outputs.commits }}" \
-f prs="${{ steps.prepare.outputs.prs }}"
```

###### changelog.yml
```yaml
name: Changelog

on:
workflow_dispatch:
inputs:
from-ref:
required: true
type: string
to-ref:
required: true
type: string
commits:
required: true
type: string
prs:
required: true
type: string

permissions:
contents: write
id-token: write
pull-requests: read

jobs:
changelog:
runs-on: ubuntu-latest
name: Generate changelog
steps:

- name: Checkout
uses: actions/checkout@v5

- name: Changelog
steps:
- name: Run changelog action
id: changelog
uses: Waveful/ChangelogAction/generate@1.2.2
uses: Waveful/ChangelogAction@2
with:
target-branch: master
claude-code-oauth-token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
previous-tag: ${{ inputs.from-ref }}
current-tag: ${{ inputs.to-ref }}
commits: ${{ inputs.commits }}
prs: ${{ inputs.prs }}
target-branch: master
openai-base-url: ${{ secrets.OPENAI_BASE_URL }}
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
openai-model: ${{ vars.OPENAI_MODEL }}

telegram-bot-token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
telegram-chat-id: ${{ secrets.TELEGRAM_CHAT_ID }}
changelog-url: 'https://github.com/your-org/your-repo/blob/master/CHANGELOG.md'

- name: Annotate
uses: Waveful/ChangelogAction/annotate@1.2.2
with:
tag: ${{ inputs.to-ref }}
mixpanel-tag-group: github-action
mixpanel-project-id: ${{ secrets.MIXPANEL_PROJECT_ID }}
mixpanel-token: ${{ secrets.MIXPANEL_TOKEN }}

- name: Notify
uses: Waveful/ChangelogAction/notify@1.2.2
with:
changelog: ${{ steps.changelog.outputs.changelog }}
claude-code-oauth-token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
telegram-bot-token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
telegram-chat-id: ${{ secrets.TELEGRAM_CHAT_ID }}
changelog-url: 'https://github.com/your-org/your-repo/blob/master/CHANGELOG.md'
- name: Print statistics
run: |
echo "Authors: ${{ steps.changelog.outputs.author-count }}"
echo "PRs: ${{ steps.changelog.outputs.pr-count }}"
echo "Commits: ${{ steps.changelog.outputs.commit-count }}"
echo "Files changed: ${{ steps.changelog.outputs.files-changed }}"
echo "Additions / Deletions: ${{ steps.changelog.outputs.additions }} / ${{ steps.changelog.outputs.deletions }}"
```

If you use a provider that needs a custom auth header, set `openai-auth-header` and `openai-auth-prefix` accordingly. For example, Azure-style setups can use `openai-auth-header: api-key` and an empty `openai-auth-prefix`.

## Behavior

- The action always generates the changelog entry and updates `CHANGELOG.md`.
- Telegram notification is skipped unless all Telegram inputs are provided.
- Mixpanel annotation is skipped unless both Mixpanel credentials are provided.
- Commits generated by the action (`docs: update changelog for ...`) are excluded from future changelog prompts.

## Credits

_ChangelogAction_ is made with ♥ by [Waveful](https://github.com/Waveful) and it's released under the [Apache License 2.0](./LICENSE).
Loading