Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add support for labels and section headers (features, fixes, etc.) #48

Merged
merged 20 commits into from
Nov 2, 2023
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
65 changes: 65 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Test

on:
push:
branches:
- main
pull_request:
types:
- opened
- synchronize
workflow_dispatch:
inputs:
debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
default: 'false'

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false

steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
- uses: actions/cache@v3
id: cache
with:
path: ${{ env.pythonLocation }}
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('requirements.txt', 'requirements-test.txt') }}-v0
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: python -m pip install -r requirements-test.txt
- run: mkdir coverage
- name: Test
run: bash scripts/test.sh
- run: coverage html --show-contexts --title "Coverage for ${{ github.sha }}"

- name: Store coverage HTML
uses: actions/upload-artifact@v3
with:
name: coverage-html
path: htmlcov

# https://github.com/marketplace/actions/alls-green#why
alls-green: # This job does nothing and is only used for the branch protection
if: always()
needs:
- test
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
with:
jobs: ${{ toJSON(needs) }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
.mypy_cache
.vscode
*.pyc
.DS_Store
.coverage
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.7
FROM python:3.10

COPY ./requirements.txt /app/requirements.txt

Expand Down
92 changes: 66 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
```

**Note**: you can also use the GitHub action directly intead of with Docker, but that would take an extra minute:
**Note**: you can also use the GitHub action directly instead of with Docker, but that would take an extra minute:

```YAML
# - uses: docker://tiangolo/latest-changes:0.0.3
Expand All @@ -53,12 +53,8 @@ After merging a PR to the main branch, it will:

```Markdown
### Latest Changes


```

...including the two breaking lines.

* Right after that, it will add a new list item with the changes:
* Using the title from the PR.
* **Tip**: make sure the PR has the title you want before merging it.
Expand All @@ -77,6 +73,40 @@ You can see an example of how it works in this same file, at the bottom, in [Lat

As the changes are simply written to a file in your repo, you can later tweak them however you want. You can add links, extend the information, remove irrelevant changes, etc. ✨

## Using Labels

You can also use labels in the PRs to configure which sections they should show up in the release notes.

By default, it will use these labels and headers:

* `breaking`: `#### Breaking Changes`
* `security`: `#### Security Fixes`
* `feature`: `#### Features`
* `bug`: `#### Fixes`
* `refactor`: `#### Refactors`
* `upgrade`: `#### Upgrades`
* `docs`: `#### Docs`
* `lang-all`: `#### Translations`
* `internal`: `#### Internal`

So, if you have a PR with a label `feature`, by default, it will show up in the section about features, like:

> ### Latest Changes
>
> #### Features
>
> * ✨ Add support for Jinja2 templates for latest changes messages. PR [#23](https://github.com/tiangolo/latest-changes/pull/23) by [@tiangolo](https://github.com/tiangolo).

You can configure the labels and headers used in the GitHub Action `labels` workflow configuration.

It takes a JSON array of JSON objects that contain a key `label` with the label you would add to each PR, and a key `header` with the header text that should be added to the release notes for that label.

The order is important, the first label from the list that is found in your PR is the one that will be used. So, if you have a PR that has both labels `feature` and `bug`, if you use the default configuration, it will show up in the section for features as that comes first, if you want it to show up in the section for bugs you would need to change the order of the list of this configuration to have `bug` first.

Note that this JSON has to be passed as a string because that's the only thing that GitHub Actions support for configurations.

See the example below in the configuration section.

## Existing PRs - Running Manually

For this GitHub Action to work automatically, the workflow file has to be in the repository _before_ the PR is created, so that the PR also includes it. That's just how GitHub Actions work.
Expand All @@ -96,9 +126,12 @@ So, in those cases, it won't do everything automatically, you will have to manua
You can configure:

* `latest_changes_file`: The file to modify with the latest changes. For example: `./docs/latest-changes.rst`.
* `latest_changes_header`: The header to look for before adding a new message. for example: `# CHANGELOG \n\n`.
* `latest_changes_header`: The header to look for before adding a new message. for example: `# CHANGELOG`.
* `template_file`: A custom Jinja2 template file to use to generate the message, you could use this to generate a different message or to use a different format, for example, HTML instead of the default Markdown.
* `end_regex`: A RegEx string that marks the end of this release, so it normally matches the start of the header of the next release section, normally the same header level as `latest_changes_header`, so, if the `latest_changes_header` is `### Latest Changes`, the content for the next release below is probably something like `### 0.2.0`, then the `end_regex` should be `^### `.
* `debug_logs`: Set to `'true'` to show logs with the current settings.
* `labels`: A JSON array of JSON objects with a `label` that you would put in each PR and the `header` that would be used in the release notes. See the example below.
* `next_section_start`: A RegEx for the start of the next label header section. If the headers start with `#### ` (as in `#### Features`), then this RegEx should match that, like `^#### `.

## Configuration example

Expand All @@ -108,16 +141,12 @@ You could have a custom Jinja2 template with the message to write at `./.github/

```Jinja2
This changed: {{pr.title}}. Done by [the GitHub user {{pr.user.login}}]({{pr.user.html_url}}). Check the [Pull Request {{pr.number}} with the changes and stuff]({{pr.html_url}}). now back to code. 🤓


```

**Note**: you can use any location in your repository for the Jinja2 template.

**Tip**: The `pr` object is a [PyGitHub `PullRequest` object](https://pygithub.readthedocs.io/en/latest/github_objects/PullRequest.html), you can extract any other information you need from it.

Notice that the Jinja2 template has 2 trailing newlines. Jinja2 we need one so that the next message shows below, instead of the same line, and Jinja2 eats one 🤷, so we put 2.

Then you could have a workflow like:

```YAML
Expand All @@ -144,9 +173,29 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }}
latest_changes_file: docs/release-notes.md
latest_changes_header: '# Release Notes\n\n'
latest_changes_header: '# Release Notes'
template_file: ./.github/workflows/release-notes.jinja2
# The next release will start with this RegEx, for example "## 0.2.0"
end_regex: '^## '
debug_logs: true
# Here we use a yaml multiline string to pass a JSON array of JSON objects in a more readable way
# In these case we use the same default labels and the same header titles, but the headers use 3 hash symbols instead of the default of 4
# We also add a custom last label "egg" for PRs with easter eggs.
labels: >
[
{"label": "breaking", "header": "### Breaking Changes"},
{"label": "security", "header": "### Security Fixes"},
{"label": "feature", "header": "### Features"},
{"label": "bug", "header": "### Fixes"},
{"label": "refactor", "header": "### Refactors"},
{"label": "upgrade", "header": "### Upgrades"},
{"label": "docs", "header": "### Docs"},
{"label": "lang-all", "header": "### Translations"},
{"label": "internal", "header": "### Internal"},
{"label": "egg", "header": "### Easter Eggs"}
]
# This should match the start of the label headers
next_section_start: '^### '
```

In this custom config:
Expand All @@ -171,11 +220,9 @@ docker://tiangolo/latest-changes:0.0.3

```Markdown
# Release Notes


```

**Note**: The `latest_changes_header` is a [regular expression](https://regex101.com/). In this case it has two newlines, and the mesage will be added right after that (without adding an extra newline).
**Note**: The `latest_changes_header` is a [regular expression](https://regex101.com/). In this case it has two newlines, and the message will be added right after that (without adding an extra newline).

So it will generate messages like:

Expand All @@ -191,21 +238,13 @@ And that Markdown will be shown like:
>
> * This changed: ✨ Add support for Jinja2 templates for changes notes. Done by [the GitHub user tiangolo](https://github.com/tiangolo). Check the [Pull Request 23 with the changes and stuff](https://github.com/tiangolo/latest-changes/pull/23). now back to code. 🤓

**Note**: if you use the default of `### Latest Changes\n\n`, or add one like the one in this example with two newlines, this GitHub action will expect the two newlines to exist. But if your release notes are empty and the file only contains:

```Markdown
# Release Notes
```

then this action won't be able to add the first message. So, make sure the latest changes file has the format expected, for example with the two newlines:

```Markdown
# Release Notes
* It will expect that the end of the content starts with the regular expression `^## `, normally because that's how the next release starts. This will be used to organize the content in the sections with the headers from the `labels` configuration.

* It will show a lot of debugging information.

```
* It will use the same default labels and headers plus another one for easter eggs, but with 3 hash symbols instead of the default of 4.

* Lastly, it will show a lot of debugging information.
* It will detect the start of each header section (the ones from the labels) with the regular expression `^### `.

## Protected Branches

Expand Down Expand Up @@ -281,6 +320,7 @@ So, the commits will still be shown as made by `github-actions`.
* 🔥 Remove config pushing to custom branch for debugging. PR [#47](https://github.com/tiangolo/latest-changes/pull/47) by [@tiangolo](https://github.com/tiangolo).
* 🚀 Publish amd64 and arm64 versions, and publish to GitHub Container Registry, fix git in containers. PR [#46](https://github.com/tiangolo/latest-changes/pull/46) by [@tiangolo](https://github.com/tiangolo).
* 📝 Add docs for using latest-changes with protected branches. PR [#43](https://github.com/tiangolo/latest-changes/pull/43) by [@tiangolo](https://github.com/tiangolo).

### 0.0.3

* 🚚 Update Python module name to latest_changes to avoid conflicts with any repo directory "app". PR [#37](https://github.com/tiangolo/latest-changes/pull/37) by [@tiangolo](https://github.com/tiangolo).
Expand Down
32 changes: 27 additions & 5 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,51 @@
name: Tiangolo's Latest Changes
author: Sebastián Ramírez <tiangolo@gmail.com>
description: Update the release notes with the "latest changes" right after a PR is merged
description: Update the release notes with the "latest changes" right after a PR is merged.
inputs:
token:
description: Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}
description: Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}.
required: true
number:
description: Optional PR number to call this GitHub Action manually in a workflow.
required: false
latest_changes_file:
description: The file to add the latest changes
description: The file to add the latest changes.
default: README.md
required: false
latest_changes_header:
description: Header to search for in the latest changes file, this action will add the changes right after that string (including newlines)
default: '### Latest Changes\n\n'
description: Header to search for in the latest changes file, this action will add the changes right after that string.
default: '### Latest Changes'
required: false
template_file:
description: To override the default message with a custom Jinja2 template, use a path relative to the repo.
required: false
default: /app/latest_changes/latest-changes.jinja2
end_regex:
description: A RegEx string that marks the end of this release, so it normally matches the start of the header of the next release section, normally the same header level as `latest_changes_header`, so, if the `latest_changes_header` is `### Latest Changes`, the content for the next release below is probably something like `### 0.2.0`, then the `end_regex` should be `^### `.
default: '^### '
required: false
debug_logs:
description: Use debug=True to enable more logging, useful to see the object shape for custom Jinja2 templates
required: false
default: 'false'
labels:
description: A JSON array of JSON objects that contain a key `label` with the label you would add to each PR, and a key `header` with the header text that should be added to the release notes for that label. The order is important, the first label from the list that is found in your PR is the one that will be used. So, if you have a PR that has both labels `feature` and `bug`, if you use the default configuration, it will show up in the section for features, if you want it to show up in the section for bugs you would need to change the order of the list of this configuration to have `bug` first. Note that this JSON has to be passed as a string because that's the only thing that GitHub Actions support for configurations.
required: false
default: >
[
{"label": "breaking", "header": "#### Breaking Changes"},
{"label": "security", "header": "#### Security Fixes"},
{"label": "feature", "header": "#### Features"},
{"label": "bug", "header": "#### Fixes"},
{"label": "refactor", "header": "#### Refactors"},
{"label": "upgrade", "header": "#### Upgrades"},
{"label": "docs", "header": "#### Docs"},
{"label": "lang-all", "header": "#### Translations"},
{"label": "internal", "header": "#### Internal"}
]
next_section_start:
description: A RegEx for the start of the next label header section. If the headers start with `#### ` (as in `#### Features`), then this RegEx should match that, like `^#### `.
default: '^#### '
runs:
using: docker
image: Dockerfile
Expand Down
Loading
Loading