Template engine for (currently) Jira and Email. Uses yaml and jinja2. It helps you create multiple (possibly cross-linked) jira issues and emails from a template.
- Download Workflow_Templater_${version}.exe from the latest release on Releases page.
- Install it.
- Now
workflow-templater
executable should be available from Windows Command Prompt (cmd.exe
) and from Powershell. - (Optional, recommended) Install Windows Terminal and use it instead of default console.
- Install python ≥ 3.10.
- Using official Python installer:
- Install python ≥ 3.10 from https://python.org/ ("macOS 64-bit installer")
- Install CA certificates for python, execute in Terminal:
Alternatively, you can double-click on
/Applications/Python\ 3.7/Install\ Certificates.command
Install Certificates.command
in Finder
- Or using Homebrew:
brew install python
- Using official Python installer:
-
pip3 install workflow-templater
- Make sure that python ≥ 3.10 is installed
-
pip3 install workflow-templater
-
pipx run workflow-templater
- Clone this repo
- Install dependencies if required
pip3 install -r requirements.txt
- You can execute the script directly:
Or install/build/whatever it with
cd workflow_templater ./workflow_templater/__init__.py --help
python3 setup.py
See
workflow-templater --help
To avoid typing same command line arguments each time, it is possible to specify them in configuration file. Configuration file location is OS-specific, to find out correct location for your os, execute workflow-templater --help
, you'll see message "--config CONFIG overwrite config file path, default is ${location}" where ${location} is the location of configuration file on your OS. You can create this file and specify values of command-line arguments omitting --
and replacing -
with _
, for example, --jira-user j_wayne
becomes jira_user: j_wayne
, --dry-run
becomes dry_run: true
and so on. You can also use jinja2 in configuration file which evaluates using variables from itself.
Example ~/.config/workflow-templater/config.yaml
:
dry_run: true
verbose: true
user: j_wayne
jira: https://jira.example.com/
jira_user: '{{ user }}'
email_user: '{{ user }}'
email_from: '{{ user }}@example.com'
email_smtp: 'smtp.example.com:587'
# avoid typing in the same password for jira and email
jira_keyring_service_name: 'MyCorp LDAP'
email_keyring_service_name: 'MyCorp LDAP'
-
Whole workflow template is a directory.
-
There should be one file with variables named
0_common.yaml
,00_common.yaml
orcommon.yaml
. Alternatively, you can name this file as you wish and specify its name with--vars
argument. -
There may be any amount of "issue" files:
- ending with ".jira.yaml" for jira issue
- All fields in each jira.issue file are send as is to Jira via API in
fields
fileld with the exception of following fields:watchers
: it's impossible to add watchers during create so it handled separately via this API method.update
: its content is sent inupdate
via API- global special fields (see below)
- All fields in each jira.issue file are send as is to Jira via API in
- ending with ".email.yaml" for email.
- ending with ".jira.yaml" for jira issue
-
There may be optional file named
mutate.py
with functionmutate
which accepts variables, modifies them and returns the result wich can be used in templates.Basic example:
def mutate(variables): variables['new_variable'] = f'{variables["old_var1"]} and {variables["old_var2"]}' return variables
Security note: if you concerned that this feature introduces an ability to execute arbitrary code from the templates, that's correct. However, this is also possible with bare jinja templates (see pallets/jinja#549), so you should make sure that your templates come from trusted sources anyway.
-
Each "issue" file is yaml file where each string value is rendered with Jinja2 using variables from
*common.yaml
file. -
Special variables available for use in jinja:
issuekey_self
: Jira issue key or Message-ID of current issue or email.issuekey_<name>
: Jira issue key or Message-ID of issue or email named<name>
. For example, for issue in filenamesomething.jira.yaml
this variable name would beissuekey_something
and it can be used in all templates.
-
Global special fields:
foreach
: list, create one issue per item in this list. List items should be strings or dicts (in case of dicts you must specifyforeach_namevar
too, see below). In case of strings, issuekey_ variable would be namedissuekey_<name>_<list_value>
Example:would finally evaluate to following issues:foreach: - Android - iOS summary: 'Release application for {{ item }}' ...
summary: 'Release application for Android' ...
summary: 'Release application for iOS' ...
foreach_fromvar
: if content forforeach
variable is shared between several templates, it's better to specify it in*common.yaml
file and specify here the name of the variable in this file. Example:common.yaml
:OSes: - Android - iOS ...
build.jira.yaml
:foreach_fromvar: OSes summary: 'Build clients for {{ item }}' ...
release.jira.yaml
:foreach_fromvar: OSes summary: 'Release application for {{ item }}' ...
foreach_key
: if you don't like default variable name (item
) for each item inforeach
list, you may specify it here. Examplewould finally evaluate to following issues:foreach: - Android - iOS foreach_key: os summary: 'Release application for {{ os }}' ...
summary: 'Release application for Android' ...
summary: 'Release application for iOS' ...
foreach_namevar
: when foreach is in use, workflow-templater would generate issuekey_ variable name as follows:issuekey_<name>_<list_value>
. If you use dicts as foreach values, you need to specify key name in this dicts which will be appended to the end of this variable name. Examplerelease.jira.yaml
file:Now in any other (or the same) issue you can link to this issues as follows:foreach: - name: Android date: !!timestamp 2019-10-24 06:30:00.0 - name: iOS date: !!timestamp 2019-10-24 10:50:00.0 foreach_namevar: name summary: 'Release application for {{ item.name }}' ...
summary: 'Notify community' description: | Android release task: {{ issuekey_release_Android }} iOS release task: {{ issuekey_release_iOS }}
if
: if this variable value evaluates to empty string (''
),false
orno
, this template will be completely ignored. Note: value for this variable is calculated for each item separately whenforeach
orforeach_fromvar
is in use. Example:would finally evaluate to following issue (only one, obviously):foreach: - Android - iOS foreach_key: os if: '{{ os in ["Android", "GNU/Linux"] }}' summary: 'Release application for {{ os }}' ...
summary: 'Release application for Android' ...
See basic release example for basic example.