[![PyPI](https://img.shields.io/pypi/v/Braumeister.svg)](https://pypi.python.org/pypi/Braumeister/)
[![Build Status](https://travis-ci.org/talentsconnect/braumeister.svg?branch=master)](https://travis-ci.org/talentsconnect/braumeister)
```none
,---. ,---. .--. .-. .-. ,---. ,-. .---. _______ ,---. ,---.
| .-.\ | .-.\ / /\ \ | | | ||\ /| | .-' |(| ( .-._)|__ __|| .-' | .-.\
| |-' \ | `-'/ / /__\ \| | | ||(\ / | | `-. (_) (_) \ )| | | `-. | `-'/
| |--. \| ( | __ || | | |(_)\/ | | .-' | | _ \ \ (_) | | .-' | (
| |`-' /| |\ \ | | |)|| `-')|| \ / | | `--.| |( `-' ) | | | `--.| |\ \
/( `--' |_| \)\|_| (_)`---(_)| |\/| | /( __.'`-' `----' `-' /( __.'|_| \)\
(__) (__) '-' '-'(__) (__) (__)
```
`braumeister` is a release-candidate preparation tool for git and JIRA users.
Given a fix-version, it gathers git branches mentioned in JIRA issues targetting this fix-version and merges them in a release-candidate branch.
# Installation
**The `braumeister` requires at least Python `3.5`**
Install with:
```sh
pip3 install braumeister
```
# Configuration
You can initialize the `braumeister` inside the root directory of a git repository like this:
```sh
braumeister init
```
The `braumeister` will create a `.braumeister` configuration file in the current directory. The configuration may look like this:
```ini
[general]
verbose = false
[git]
main_branch_name = main
[jira]
url = https://your-domain.atlassian.net
username = my-user
password = my-api-token
destination_transition = Merged
branch_custom_field_id = customfield_5711
```
|Section|key|default value|description|
|-------|---|-----|---|
|general|verbose|false|Verbose output|
|git|main_branch_name|master|Define the main branch name for your git project|
|jira|url|None|JIRA Base URL|
|jira|username|None|A JIRA User|
|jira|password|None|The password for the user|
|jira|destination_transition|None|Workflow Transition name for the ticket after merging, if executed with `-u`|
|jira|branch_custom_field_id|None|The JIRA Custom Field where we should read the branch from|
We'll be looking for a configuration file at the following places
```
[CURRENT-DIRECTORY]/.braumeister
~/.braumeister
```
**It's recommended to add the following files to your `.gitignore`**
```gitignore
.braumeister
release_state.json
```
## JIRA Configuration
### Custom Field für Branch anlegen
In JIRA, press `gg` (or `.`) to open the "Quick Actions" > Type `Custom Fields` > `Add custom field` > `Text field (single line)` > `Next`
```
Name: Branch
Description: git Branch
```
In the next screen, you need to assign the created field to one or more screens.
The `branch_custom_field_id` is `customfield_[ID]` whereas the `ID` is the number in the URL behind the `customFieldId=`.
e.g.:
```none
https://jira.dev/secure/admin/ConfigureCustomField!default.jspa?customFieldId=57111
```
Here, the JIRA Custom Field Id is `5711`, so the `braumeister` configuration for `branch_custom_field_id` would be `customfield_5711`.
# Description
The `braumeister` requests all issues from JIRA with the given release name as `Fix Version`.
In theses tickets, we'll search for the configured custom field (eg Branch) containing the git branch.
The release branch will be created like this:
```
release/[cleaned_release_name]_RC_[LATEST_RC + 1]
```
If the `braumeister` discovered a branch with the same name, we'll increase the `RC` part with 1 (with leading zeros). The first release branch will have the RC `001`.
For each of theses branches, the following commands will be executed:
```sh
$ git checkout $branch
$ git pull
$ git merge origin/main
$ git push origin $branch
$ git checkout $release_branch
$ git merge origin/$branch
$ git branch -D $branch
```
After merging all branches to the release branch, the branch will be pushed to `origin`.
## Conflicts
If there are any conflicts during the merge of a branch, the `braumeister` will stop and write the current state to a `release_state.json` file. The output may looks like this:
```sh
$ braumeister -n "Barking Dog" candidate
[*] Requesting all issues with fixVersion: Barking Dog
[+] Requesting issue: https://jira.dev/rest/api/2/issue/5711
[+] Requesting issue: https://jira.dev/rest/api/2/issue/5712
[+] Requesting issue: https://jira.dev/rest/api/2/issue/5713
[+] The last branch for RC Barking Dog is: release/Barking_Dog_RC_002
[+] Creating new branch 'release/Barking_Dog_RC_003' from master
Branch 'release/Barking_Dog_RC_003' set up to track remote branch 'master' from 'origin'.
Switched to a new branch 'release/Barking_Dog_RC_003'
[🍻 ] Merging feature-2...
[🍻 ] Branch 'feature-2' merged
[🍻 ] Merging feature-1...
Writing state json!
A merge error occured while merging feature into release/Barking_Dog_RC_003
Please do the following steps:
* Resolve the conflicts
* Commit the changes
* Call the script again with the option -r
```
The `braumeister` will stay in the current release branch to let you resolve the conflict. After the conflict has been resolved, you can rerun the `braumeister` with `-r` to resume where we stopped.
```sh
$ braumeister -n "Barking Dog" -r candidate
Reading state json!
Resuming with feature-1
[🍻 ] Merging feature-1...
[🍻 ] Branch 'feature-1' merged
[🍻 ] Merging affe...
[🍻 ] Branch 'affe' merged
Deleting state json!
[🍻 ] All done. Grab a 🍺
```
## Examples
### Release Candidate
#### New release candidate
```sh
$ braumeister -n "Barking Dog" candidate
[*] Requesting all issues with fixVersion: Barking Dog
[+] Requesting issue: https://jira.dev/rest/api/2/issue/5711
[+] Creating new branch 'release/Barking_Dog_RC_001' from master
Branch 'release/Barking_Dog_RC_001' set up to track remote branch 'master' from 'origin'.
Switched to a new branch 'release/Barking_Dog_RC_001'
[🍻 ] Merging affe...
[🍻 ] Branch 'affe' merged
[🍻 ] All done. Grab a 🍺
```
#### Existing release candidate
When you execute the `braumeister` with the same release name again, a new release candidate will be created (increasing the `RC` part with 1).
```sh
$ braumeister -n "Barking Dog" candidate
[*] Requesting all issues with fixVersion: Barking Dog
[+] Requesting issue: https://jira.dev/rest/api/2/issue/5711
[+] The last branch for RC Barking Dog is: release/Barking_Dog_RC_001
[+] Creating new branch 'release/Barking_Dog_RC_002' from master
Branch 'release/Barking_Dog_RC_002' set up to track remote branch 'master' from 'origin'.
Switched to a new branch 'release/Barking_Dog_RC_002'
[🍻 ] Merging affe...
[🍻 ] Branch 'affe' merged
[🍻 ] All done. Grab a 🍺
```
#### Update JIRA issue
Executing the `braumeister` with `-u` will also execute the configured transition on all related issues.
```sh
$ braumeister -n "Barking Dog" -u candidate
[*] Requesting all issues with fixVersion: Barking Dog
[+] Requesting issue: https://jira.dev/rest/api/2/issue/31300
[+] Requesting issue: https://jira.dev/rest/api/2/issue/30209
[+] The last branch for RC Barking Dog is: release/Barking_Dog_RC_004
[+] Creating new branch 'release/Barking_Dog_RC_005' from master
Branch 'release/Barking_Dog_RC_005' set up to track remote branch 'master' from 'origin'.
Switched to a new branch 'release/Barking_Dog_RC_005'
[🍻 ] Merging feature-1...
[🍻 ] Branch 'feature-1' merged
[🍻 ] Merging affe...
[🍻 ] Branch 'affe' merged
Deleting state json!
------------------------------------
[+] Update status to Merged on all related jira issues!
------------------------------------
Requesting all transitions for: DEV-1
Updating jira status on DEV-1 to Staging Needed
------------------------------------
Requesting all transitions for: DEV-2
Updating jira status on DEV-2 to Staging Needed
[🍻 ] All done. Grab a 🍺
```
### Release
#### New release
```sh
$ braumeister -n "Barking Dog" release
[*] Requesting all issues with fixVersion: Barking Dog
[+] Requesting issue: https://jira.dev/rest/api/2/issue/5711
[+] Creating new branch 'release/Barking_Dog_GA' from master
Branch 'release/Barking_Dog_GA' set up to track remote branch 'master' from 'origin'.
Switched to a new branch 'release/Barking_Dog_GA'
[🍻 ] Merging affe...
[🍻 ] Branch 'affe' merged
[🍻 ] All done. Grab a 🍺
```
#### Finalize a release
When you execute the `braumeister` with the `finalize` action it will merge the given branch back to define main branch (e.g. `origin/main`).
THIS CHANGES YOUR REMOTE REPOSITORY, HANDLE WITH CARE!
```sh
$ braumeister -n "Barking Dog" finalize
[+] Merging branch 'release/Barking_Dog_GA' to origin/master
[🍻 ] Merging release/Barking_Dog_GA...
[🍻 ] Branch 'release/Barking_Dog_GA' merged
[🍻 ] All done. Grab a 🍺
```
#### Cleanup after a release
When you execute the `braumeister` with the `cleanup` action it will delete all branches associated with tickets in your `fixVersion`.
THIS CHANGES YOUR REMOTE REPOSITORY, HANDLE WITH CARE!
```sh
$ braumeister -n "Barking Dog" cleanup
[+] Cleaning up after release of Barking Dog
[🍻 ] Deleting origin/feature-nifty...
[🍻 ] Deleting origin/feature-seven...
[🍻 ] Deleting origin/feature-eleven...
[🍻 ] Brewhouse all clean again. Grab a 🍺
```
# Development
Running tests
```sh
make test
```