This is a command-line tool to retrieve the list of stories from the Shortcut issue tracker which will be deployed in a release, and generate release notes based on a template.
graph TD
A(fa:fa-code-branch Scan commits)--> B(fa:fa-download Get stories)
B --> C(fa:fa-download Get epics)
C -->D(fa:fa-file Build Markdown release notes)
For each repository listed in its configuration file, it scans the commits
which are present in the "next" branch (which is the branch/commit to be
released) and absent from the "release" branch (which the branch/commit already
released). All Shortcut stories matching commits with a message starting with
[sc-<shortcut_id>]
are retrieved from Shortcut, along with the epic they
belong to.
Finally, a Markdown file is generated based on the retrieved data and a template.
Per default, the helper only requires the path to the output file.
./shortcut_release_helper release_notes.md
It also supports additional options:
--version <VERSION>
is the version number of the release. This is the content of theversion
variable in the template.--name <NAME>
is the name of the release. This is the content of thename
variable in the template.--description <DESCRIPTION>
is the description of the release. This is the content of thedescription
variable in the template.--exclude-story-id <STORY_ID>
is the ID of a story which should be ignored. Commits with this story id will be ignored. This option can be used multiple times to ignore multiple stories. Use the numeric id of the story (ie, use--exclude-story-id 130
and not--exclude-story-id sc-130
or--exclude-story-id sc130
)--exclude-story-label <LABEL>
is a story label to ignore. All commits of stories with this label will be ignored. This option can be used multiple times. Has priority over--include-story-label
.--include-story-label <LABEL>
is a story label to include. Only commits of stories with this label will be taken into account. This option can be used multiple times.--exclude-unparsed-commits
is a flag indicating that unparsed commits should not be sent to the template (instead, an empty list will be used).
Ensure that the dependencies below (both utilities and libararies) are present in your system.
- Open API generator.
This will be used to generate the Shortcut client, based on the OpenAPI
definition available from the Shortcut API documentation
site. The project's generator script
expects an
openapi-generator-cli
in thePATH
or innode_modules
if you usenpm install @openapitools/openapi-generator-cli
. - curl, to download the Shortcut OpenAPI definition.
- jq, to patch it.
- git, obviously
- rustc, at least 1.58.0
Clone the repository.
Generate the OpenAPI client via ./bin/generate_openapi_client.sh
.
Build the application via cargo build
$ shortcut_release_helper --version 3.22.1 --name "My new release" notes.md
The software expects a config.toml
configuration file in the current folder.
It has the following format:
# Shortcut API token, see https://help.shortcut.com/hc/en-us/articles/205701199-Shortcut-API-Tokens
api_key = "<your_api_key>"
# Template file, see below
template_file = "template.md.jinja"
# A list of one or more repository
[repositories]
repo1_name = { location = "<path_to_the_repo>", release_branch = "<branch_name_or_commit>", next_branch = "<branch_name_or_commit>" }
repo2_name = { location = "<path_to_the_repo>", release_branch = "<branch_name_or_commit>", next_branch = "<branch_name_or_commit>" }
repo3_name = { location = "<path_to_the_repo>", release_branch = "<branch_name_or_commit>", next_branch = "<branch_name_or_commit>" }
The path_to_the_repo
may be absolute or relative to the current directory.
The template file is a Jinja Markdown template, which lays out the data retrieved from Shortcut.
The template receives the following data:
Field name | Type | Description |
---|---|---|
name |
string or undefined |
the name of the release, passed on the command line |
version |
string or undefined |
the version of the release, passed on the command line |
description |
string or undefined |
the description of the release, passed on the command line |
stories |
list of Shortcut stories |
the list of all stories which been worked in the release |
epics |
list of Shortcut epics |
the list of all Shortcut epics containing at least one of the stories above (note that the epic's stats field relates to all the stories in the epic, not just the ones missing from the "release" branch) |
unparsed_commits |
map string -> list of commits |
a map of repo name to a list of commits with a commit message not starting with a valid Shortcut issue number |
next_heads |
map string -> commit |
a map of repo name to the head commit of the next branch of each repository |
The template receives the following helpers:
Name | Description | Example |
---|---|---|
split_by_epic_stories_state |
Given a list of epics, returns a 2-elements list where the first element contains all epics for which all stories are in a Done state, and the rest of the epics in the second item | {% with done_epics = epics | split_by_epic_stories_state | first %} |
split_by_label |
Given a list of epics or stories and a label name, returns a 2-elements list where the first element contains all items with the label, and the second all items without it | {% with technical_stories = stories | split_by_label("Technical") | first %} |
split_by_epic |
Given a list of stories and an epic id, returns a 2-elements list where the first element contains all stories belonging to the epic, and the second all stories without it | {% with stories_in_epic = stories | split_by_epic(some_epic.id) | first %} |
story_emoji |
Given a story, returns a Github emoji matching the type of story (:sunny: feature, :lady_beetle: bug or :wrench: chore) | {{ story | story_emoji }} |
indent |
Given a string and a number S, indents all lines of the text by S spaces | - {{ commit.message | indent(4) }} |
escape |
Escapes special Markdown characters in the text (useful for Shortcut epic and story titles, as well as Git commit messages) | {{ epic.title | escape }} |
The template receives the following functions:
Name | Description | Example |
---|---|---|
today |
Returns today's date in YYYY-MM-DD format |
{{ today() }} |
epic_emoji |
Returns a 🏁 flag emoji | {{ epic_emoji() }} |
The Markdown template uses a subset of the Jinja 2 syntax, as implemented in the minijinja crate.