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

♻️ Separate label header prefix from label text with label_header_prefix, this allows re-using the default labels while only changing the header level #58

Merged
merged 4 commits into from
Nov 3, 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
87 changes: 46 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker://tiangolo/latest-changes:0.1.0
- uses: docker://tiangolo/latest-changes:0.2.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
```

**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.1.0
# - uses: docker://tiangolo/latest-changes:0.2.0
# This is slower but also works
- uses: tiangolo/latest-changes@0.1.0
- uses: tiangolo/latest-changes@0.2.0
```

In this minimal example, it uses all the default configurations.
Expand Down Expand Up @@ -79,15 +79,15 @@ You can also use labels in the PRs to configure which sections they should show

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`
* `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:

Expand All @@ -97,15 +97,9 @@ So, if you have a PR with a label `feature`, by default, it will show up in the
>
> * ✨ 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.
You can configure the labels and headers used in the GitHub Action `labels` workflow configuration, and you can configure the header prefix, by default `#### `.

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.
Read more about it in the section about configuration.

## Existing PRs - Running Manually

Expand All @@ -128,10 +122,20 @@ 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`.
* `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 `^### `.
* `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 `^### `. This is used to limit the content updated as this will read the existing sub sections and possibly update them using the labels configuration and the labels in the PR.
* `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 `^#### `.
* `label_header_prefix`: A prefix to put before each label's header. This is also used to detect where the next label header starts. By default it is `#### `, so the headers will look like `#### Features`.

### Configuring Labels

The `labels` configuration 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.

If you want to keep the same default labels but change the header level, so, add or remove hash symbols, you can set the `label_header_prefix` configuration. You could also use it to set a different header prefix, but the common case is changing the section header level.

## Configuration example

Expand Down Expand Up @@ -169,7 +173,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: tiangolo/latest-changes@0.1.0
- uses: tiangolo/latest-changes@0.2.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
latest_changes_file: docs/release-notes.md
Expand All @@ -183,19 +187,20 @@ jobs:
# 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"}
{"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: '^### '
# This will be added to the start of each label's header and
# will be used to detect existing label headers
label_header_prefix: '### '
```

In this custom config:
Expand All @@ -204,13 +209,13 @@ In this custom config:
* It uses the GitHub action directly:

```
tiangolo/latest-changes@0.1.0
tiangolo/latest-changes@0.2.0
```

instead of with Docker:

```
docker://tiangolo/latest-changes:0.1.0
docker://tiangolo/latest-changes:0.2.0
```

**Note**: that would make every run about 1 min slower, but you can do that if you prefer it 🤷.
Expand All @@ -222,7 +227,7 @@ docker://tiangolo/latest-changes:0.1.0
# Release Notes
```

**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).
**Note**: The `latest_changes_header` is a [regular expression](https://regex101.com/).

So it will generate messages like:

Expand All @@ -242,9 +247,9 @@ And that Markdown will be shown like:

* 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.
* It will use the same default labels and headers plus another one for easter eggs.

* It will detect the start of each header section (the ones from the labels) with the regular expression `^### `.
* It will show those section headers from labels with 3 hash symbols instead of the default of 4. And it will also find any existing header checking for that prefix (it will use a regular expression like `^### `).

## Protected Branches

Expand Down Expand Up @@ -293,7 +298,7 @@ jobs:
- uses: actions/checkout@v4
with:
token: ${{ secrets.ACTIONS_TOKEN }}
- uses: docker://tiangolo/latest-changes:0.1.0
- uses: docker://tiangolo/latest-changes:0.2.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
```
Expand Down
24 changes: 12 additions & 12 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@ inputs:
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"}
{"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: '^#### '
label_header_prefix:
description: A prefix to put before each label's header. This is also used to detect where the next label header starts. By default it is `#### `, so the headers will look like `#### Features`.
default: '#### '
runs:
using: docker
image: Dockerfile
Expand Down
35 changes: 21 additions & 14 deletions latest_changes/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ class Settings(BaseSettings):
input_end_regex: str = "^### "
input_debug_logs: Optional[bool] = False
input_labels: List[Section] = [
Section(label="breaking", header="#### Breaking Changes"),
Section(label="security", header="#### Security Fixes"),
Section(label="feature", header="#### Features"),
Section(label="bug", header="#### Fixes"),
Section(label="refactor", header="#### Refactors"),
Section(label="upgrade", header="#### Upgrades"),
Section(label="docs", header="#### Docs"),
Section(label="lang-all", header="#### Translations"),
Section(label="internal", header="#### Internal"),
Section(label="breaking", header="Breaking Changes"),
Section(label="security", header="Security Fixes"),
Section(label="feature", header="Features"),
Section(label="bug", header="Fixes"),
Section(label="refactor", header="Refactors"),
Section(label="upgrade", header="Upgrades"),
Section(label="docs", header="Docs"),
Section(label="lang-all", header="Translations"),
Section(label="internal", header="Internal"),
]
input_next_section_start: str = "^#### "
input_label_header_prefix: str = "#### "


class PartialGitHubEventInputs(BaseModel):
Expand Down Expand Up @@ -108,11 +108,15 @@ def generate_content(
sections: list[SectionContent] = []
sectionless_content = ""
for label in settings.input_labels:
label_match = re.search(label.header, release_content, flags=re.MULTILINE)
label_match = re.search(
f"^{settings.input_label_header_prefix}{label.header}",
release_content,
flags=re.MULTILINE,
)
if not label_match:
continue
next_label_match = re.search(
settings.input_next_section_start,
f"^{settings.input_label_header_prefix}",
release_content[label_match.end() :],
flags=re.MULTILINE,
)
Expand Down Expand Up @@ -161,7 +165,7 @@ def generate_content(
if sectionless_content:
new_release_content = f"{sectionless_content}"
use_sections = [
f"{section.header}\n\n{section.content}"
f"{settings.input_label_header_prefix}{section.header}\n\n{section.content}"
for section in new_sections
if section.content
]
Expand All @@ -172,7 +176,10 @@ def generate_content(
else:
new_release_content = updated_content

new_content = f"{pre_header_content}\n\n{new_release_content}\n\n{post_release_content}".strip() + "\n"
new_content = (
f"{pre_header_content}\n\n{new_release_content}\n\n{post_release_content}".strip()
+ "\n"
)
return new_content


Expand Down
40 changes: 20 additions & 20 deletions tests/test_generate_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -830,18 +830,18 @@ def test_multiple_header_sections():
input_labels=cast(
Any,
[
{"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": "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"},
],
),
input_next_section_start="^### ",
input_label_header_prefix="### ",
)
pr = TemplateDataPR(
title="Demo PR",
Expand Down Expand Up @@ -968,18 +968,18 @@ def test_multiple_header_sections_label():
input_labels=cast(
Any,
[
{"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": "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"},
],
),
input_next_section_start="^### ",
input_label_header_prefix="### ",
)
pr = TemplateDataPR(
title="Demo PR",
Expand Down