Skip to content

Commit 2302a26

Browse files
committed
Updated the documentation for release hinting
1 parent 84b54f9 commit 2302a26

10 files changed

Lines changed: 156 additions & 171 deletions

File tree

docsrc/_static/css/custom.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.sig-prename.descclassname {
1+
.py .sig-prename.descclassname {
22
display: none;
33
}
44
.subheading {

docsrc/configuration.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,32 @@ Some values accept pipelines, which are a chain of actions that transform an inp
297297
- improved-by
298298
- original-patch-by
299299
```
300+
301+
## Release Hinting Options
302+
303+
(configuration-release_hint_rules)=
304+
305+
### release_hint_rules
306+
:YAML type: [`sequence` of `mapping`](https://yaml.org/spec/1.2.2/#21-collections)
307+
308+
:Description: Rules applied to unreleased commits to determine the type of release to suggest.
309+
310+
:Default:
311+
```YAML
312+
release_hint_rules:
313+
- match_result: "patch"
314+
no_match_result: "no-release"
315+
grouping: "Other"
316+
- match_result: "patch"
317+
no_match_result: "no-release"
318+
grouping: "Fixes"
319+
- match_result: "minor"
320+
no_match_result: "no-release"
321+
grouping: "Updates"
322+
- match_result: "minor"
323+
no_match_result: "no-release"
324+
grouping: "New"
325+
- match_result: "major"
326+
no_match_result: "no-release"
327+
grouping: "Breaking Changes"
328+
```

docsrc/generating-release.md

Lines changed: 0 additions & 135 deletions
This file was deleted.

docsrc/how-it-works.md

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,49 @@
1-
# How it works
2-
3-
Assumes versions, or releases, are tags in the git repository.
4-
5-
1. **Get last release:** Obtain the version number corresponding to the last release.
6-
1. Uses `--starting-tag` command line option or `starting_tag_pipeline` configuration to determine starting tag
7-
2. If no starting tag is found, it starts at the beginning
8-
2. **Process commits:** Filter and process commits since a starting point, setting metadata and normalizing information.
9-
1. Uses `tag_pattern` configuration to filter tags since starting commit
10-
2. Groups commits according to their tag or the next tag in the timeline in
11-
3. Commits since the last tag are grouped under a tag placeholder named `HEAD`
12-
4. Each tag is converted to a `VersionContext`. The `HEAD` placeholder is renamed to the `unreleased_label` configuration
13-
5. Each commit within the tag are processed
14-
1. Filtered using `ignore_patterns` configuration
15-
2. The commit's `summary` line is run through the `summary_pipeline` configuration
16-
3. The commit's `body` is run through the `body_pipeline` configuration
17-
4. The commit is assigned a `category` based on the first matching item in the `commit_classifiers` configuration
18-
5. The commit is assigned a `grouping` based on the `group_by` configuration
19-
6. Each commit is converted to a `CommitContext`
20-
6. The processed commits are sorted by their `grouping` attribute
21-
3. **Suggest release hint:** Applies rules to every `CommitContext` in the `unreleased_label` `VersionContext`. If there is not an `unreleased_label` version, or if its commits are empty, a hint of `no-release` is returned
22-
1. Each rule in the `release_hint_rules` configuration is applied to each `CommitContext` in the unreleased `VersionContext` and collected in a unique set of possible release types
23-
2. The commit's possible release types are sorted according to `major` > `minor` > `patch` > `no-release`.
24-
3. The highest possible release type for each commit is assigned to a unique set for the unreleased version
25-
4. The release hint is the maximum release type in the unique set of possible release types
26-
4. **Render changelog and release notes:** Render the `VersionContext`(s) into a document.
27-
1. Create a `ChangelogContext` from the configuration and `VersionContext`(s)
28-
2. For incremental change logs (those with a starting tag), only the `heading.md.jinja` and `versions.md.jinja` are rendered and returned
29-
3. For full change logs, the `base.md.jinja` is rendered and returned
1+
# How Generate Changelog works
2+
3+
Generate Changelog requires a git tag to indicate each version, or release, in the git repository.
4+
5+
The two foundational functions are getting the starting tag and processing the commits from that starting point. From the result of the foundational functions we can suggest a release hint and render a change log and release notes.
6+
7+
## Getting the starting tag
8+
9+
This step uses the {option}`--starting-tag` command line option or the {ref}`configuration-starting_tag_pipeline` configuration to determine the starting point for processing. If no starting tag is found, it starts at the first commit.
10+
11+
## Processing commits
12+
13+
This step filters and processes each commit since a starting point.
14+
15+
For each commit since the starting point:
16+
17+
1. Discard the commit if it matches the {ref}`configuration-ignore_patterns` configuration.
18+
2. Run the `summary` line through the {ref}`configuration-summary_pipeline` configuration.
19+
3. Run the `body` through the {ref}`configuration-body_pipeline` configuration.
20+
4. Assign the commit a `category` based on the first matching item in the {ref}`configuration-commit_classifiers` configuration.
21+
5. Assign the commit a `grouping` based on the {ref}`configuration-group_by` configuration.
22+
6. Create a {class}`~.context.CommitContext` from the commit's processed attributes.
23+
24+
Then we must process the tags and create {class}`~.context.VersionContext`s. This involves gathering the list of tags since the starting point and using the {ref}`configuration-tag_pattern` configuration to filter out unwanted tags. Tags are converted to {class}`~.context.VersionContext`s.
25+
26+
Each {class}`~.context.CommitContext` is assigned a version according to the next valid tag in the timeline (or their own tag, if the underlying commit itself is tagged). {class}`~.context.CommitContext`s since the last tag assigned a version named {ref}`configuration-unreleased_label`.
27+
28+
Each {class}`~.context.VersionContext` sorts its assigned {class}`~.context.CommitContext`s by its `grouping` attribute.
29+
30+
## Suggesting a release type
31+
32+
This optional step applies rules to every {class}`~.context.CommitContext` in the {class}`~.context.VersionContext` labeled {ref}`configuration-unreleased_label` to determine what type of release (e.g. `patch`, `minor`, or `major`) to suggest. A `no-release` suggestion means that no release is warranted. This can happen if there is not an {ref}`configuration-unreleased_label` version, if {ref}`configuration-unreleased_label` version has no commit, or all the rules returned `no-release`.
33+
34+
Essentially this is a map-reduce function where each rule in the {ref}`configuration-release_hint_rules` configuration maps a release hint to each {class}`~.context.CommitContext` in the unreleased {class}`~.context.VersionContext`. The resulting values are reduced to the maximum value according to:
35+
36+
1. no-release
37+
2. alpha
38+
3. beta
39+
4. dev
40+
5. pre-release
41+
6. release-candidate
42+
7. patch
43+
8. minor
44+
9. major
45+
46+
47+
## Rendering the changelog
48+
49+
This involves rendering a complete or partial changelog using [Jinja templates](https://jinja.palletsprojects.com). For incremental change logs (those with a starting tag), only the `heading.md.jinja` and `versions.md.jinja` templates are rendered and returned. For full change logs, the `base.md.jinja` template is rendered and returned.

docsrc/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ caption: Contents
1515
hidden: true
1616
---
1717
Introduction <readme>
18+
how-it-works
1819
Command Line Interface <cli>
20+
release-hinting
1921
configuration
2022
templating/index
2123
actions/index

docsrc/release-hinting.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Generating a release hint
2+
3+
## What is a "release hint?"
4+
5+
A release hint provides guidance on if and what type of software release is warranted. The guidance is based on user-defined rules applied to every {class}`~.context.CommitContext` in the unreleased {class}`~.VersionContext`. Each rule may use how the commit is grouped in the release, the files modified, or both.
6+
7+
You can use this release hint as input to your release tooling.
8+
9+
## Methods of generating the hint
10+
11+
Adding the {option}`--output` option to the command allows you to specify `hint` or `all`. `hint` will return the release hint after updating the change log. `all` will return a JSON object with a `release_hint` key after updating the change log.
12+
13+
If you only want the hint, add the {option}`--skip-output-pipeline` option to `--output hint`.
14+
15+
```console
16+
$ generate-changelog --output hint --skip-output-pipeline
17+
patch
18+
```
19+
20+
## Release rules
21+
22+
There are four parts to a release rule: `match_result`, `no_match_result`, `grouping` and `path`. Only `match_result` is required, but without a `grouping` or `path` value, the rule is ignored. `no_match_result` defaults to `no-release`.
23+
24+
### Match result
25+
26+
This is the hint returned if both the `grouping` and `path` values match. This is required.
27+
28+
### No match result
29+
30+
This is the hint returned if either the `grouping` or `path` values do not match. By default, this is `no-release`.
31+
32+
### Grouping
33+
34+
The {attr}`.CommitContext.grouping` attribute is always a `tuple` with one or more string values.
35+
36+
The value of {attr}`.ReleaseHint.grouping` will match the {attr}`.CommitContext.grouping` differently depending on its value:
37+
38+
:string value:
39+
The value is in the {attr}`.CommitContext.grouping`. For example: `"New"` would match both `("Features", "New", )` and `("New", )`.
40+
41+
:sequence of string values:
42+
The value must match the {attr}`.CommitContext.grouping` exactly. For example `("New", )` would match `("New", )` but not `("Features", "New", )` or `("New", "Features", )`
43+
44+
:sequence of string values ending with a "*":
45+
The value must match the beginning of the {attr}`.CommitContext.grouping`. For example `("New", "*", )` would match `("New", )` and `("New", "Features", )` but not `("Features", "New", )`.
46+
47+
:None:
48+
It will return a match and rely on the {attr}`.ReleaseHint.path` to match or not. This is saying "I don't care about the grouping I only care about the path."
49+
50+
### Path
51+
52+
The {attr}`.CommitContext.files` attribute is a `set` of paths relative to the repository root. The {attr}`.ReleaseHint.path` uses [globbing patterns](https://www.malikbrowne.com/blog/a-beginners-guide-glob-patterns) to match against {attr}`.CommitContext.files`.
53+
54+
## Examples
55+
56+
This will provide a "patch" hint if the grouping contains "Other", but only when a modified file is within the `src` directory. Otherwise it will provide a "no-release" hint.
57+
58+
```yaml
59+
- match_result: "patch"
60+
no_match_result: "no-release"
61+
grouping: "Other"
62+
path: src/*
63+
```

generate_changelog/configuration.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
RELEASE_TYPE_ORDER = (
3030
None,
31+
"no-release",
3132
"alpha",
3233
"beta",
3334
"dev",
@@ -137,24 +138,29 @@
137138
DEFAULT_RELEASE_RULES = [
138139
{
139140
"match_result": "patch",
140-
"no_match_result": None,
141+
"no_match_result": "no-release",
141142
"grouping": "Other",
142143
},
143144
{
144145
"match_result": "patch",
145-
"no_match_result": None,
146+
"no_match_result": "no-release",
146147
"grouping": "Fixes",
147148
},
148149
{
149150
"match_result": "minor",
150-
"no_match_result": None,
151+
"no_match_result": "no-release",
151152
"grouping": "Updates",
152153
},
153154
{
154155
"match_result": "minor",
155156
"no_match_result": None,
156157
"grouping": "New",
157158
},
159+
{
160+
"match_result": "major",
161+
"no_match_result": None,
162+
"grouping": "Breaking Changes",
163+
},
158164
]
159165

160166

generate_changelog/context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class CommitContext:
3636
"""Metadata for this commit parsed from the commit message."""
3737

3838
files: set = field(default_factory=set)
39-
"""The files modified by this commit."""
39+
"""The file paths (relative to the repository root) modified by this commit."""
4040

4141
_authors: Optional[list] = field(init=False) # list of dicts with name and email keys
4242
_author_names: Optional[list] = field(init=False) # list of just the names

generate_changelog/release_hint.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ReleaseRule:
2020
def __init__(
2121
self,
2222
match_result: Optional[str],
23-
no_match_result: Optional[str] = None,
23+
no_match_result: Optional[str] = "no-release",
2424
grouping: Union[str, tuple, list, None] = None,
2525
path: Optional[str] = None,
2626
):

test/test_release_hint.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
},
2121
{
2222
"match_result": "patch",
23-
"no_match_result": None,
23+
"no_match_result": "no-release",
2424
"grouping": "Fixes",
2525
"path": "src/*",
2626
},

0 commit comments

Comments
 (0)