Skip to content
This repository has been archived by the owner on Mar 26, 2023. It is now read-only.

Feat: Add click dependency, branch name check and project structure #4

Merged
merged 18 commits into from
Jun 1, 2020
Merged
Show file tree
Hide file tree
Changes from 15 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
3 changes: 3 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ repos:
- id: gjira
language_version: python3
args: ['--board=EMMENTAL', '--regex=ISSUE-\d+']
- id: gjira-check-branch
language_version: python3
args: ["--regex=^(feat|refactor|fix|chore)/.*$|^(master|dev(elop)?)$"]
10 changes: 9 additions & 1 deletion .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
- id: gjira
name: Jira issue commit message
description: Add the issue ID to the body of the commit
entry: gjira
entry: gjira append-jira
language: python
always_run: true
stages: [prepare-commit-msg]
- id: gjira-check-branch
name: Validate branch format
description: Validates if branch has specified format by the given regex
entry: gjira check-branch
language: python
always_run: true
pass_filenames: false
stages: [push]
47 changes: 38 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ and gives the project manager an insight of the current development workload.

## Setup

### Git commit template
### `prepare-commit-msg`

#### Git commit template

GJira requires a commit template file. GJira supports Jinja2, which allows
customizable templates based on Jira context. For example:
Expand Down Expand Up @@ -63,13 +65,13 @@ issue.fields.timetracking.timeSpentSeconds # may be NULL or integer
Inner issue fields **require** `.` (dot) to be replaced with `__` (double
underscore).

### Branch
#### Branch

GJira find Jira ID by the branch name. You can use a regex to specify the
location for the issue ID, for example: the regex `ISSUE-\d+` will match
`ISSUE-123/branch-name` or `ISSUE-123-branch-name` etc.

### pre-commit
#### pre-commit configuration

Add the following repository to your `.pre-commit-config.yml` file

Expand All @@ -80,10 +82,10 @@ Add the following repository to your `.pre-commit-config.yml` file
- id: gjira
args: ["--board=<board/project name>",
"--template=.commit.template",
"--regex='ISSUE-\d+'"]
"--regex=ISSUE-\d+"]
```

### Environment variables
#### Environment variables

Set the following environment variables:

Expand All @@ -95,20 +97,47 @@ export jirauser="your@email.com"
export jiratoken="token"
```

### Installing the hook
#### Installing the hook

Finally, install the hook with pre-commit: `pre-commit install --hook-type prepare-commit-msg`.

### `pre-push`

GJira has a `pre-push` hook support, which prevents user from pushing to remote
if the current branch is not within the specified format.

#### pre-commit configuration

To enable `pre-push`, set the following to your `.pre-commit-config.yml` file

```yaml
- repo: https://github.com/benmezger/gjira
rev: feat/click-args
hooks:
....
- id: gjira-check-branch
language_version: python3
args: ["--regex=^(feat|refactor|fix|chore)/.*$|^(master|dev(elop)?)$"]
```

#### Installing the hook

Finally, install `pre-push` hook: `pre-commit install --hook-type pre-push`

## Demo

### Using Git in the terminal
### `prepare-commit-msg` sing Git in the terminal
benmezger marked this conversation as resolved.
Show resolved Hide resolved

[![asciicast](https://asciinema.org/a/GGURgGibHGHII9jaIH5a5w3Yq.svg)](https://asciinema.org/a/GGURgGibHGHII9jaIH5a5w3Yq)

### Using Git in VSCode
### `prepare-commit-msg` Git in VSCode

![GJira VScode](images/vscode.gif)

### `pre-push`

[![asciicast](https://asciinema.org/a/WZy78gC9H9GUM5Cptt9ulD3OW.svg)](https://asciinema.org/a/WZy78gC9H9GUM5Cptt9ulD3OW)

## Troubleshooting

- GJira is not appending the issue/story to the commit message.
Expand All @@ -133,7 +162,7 @@ Finally, install the hook with pre-commit: `pre-commit install --hook-type prepa
There are two ways of manually running GJira.

1. `python -m gjira` which will run `main()` in `__main__`
2. Installing the cli to your system `pip install .`
2. You can install the cli to your system `pip install .`

## TODO

Expand Down
62 changes: 2 additions & 60 deletions gjira/__main__.py
Original file line number Diff line number Diff line change
@@ -1,67 +1,9 @@
#!/usr/bin/env python3

import argparse
import pathlib
import sys
import re

from jira import JIRA

from gjira.template import generate_template, get_template_context

from .gjira import (
get_branch_name,
get_issue,
get_jira_from_env,
is_gjira_in_file,
update_commit_message,
)


def arg_parser(argv):
parser = argparse.ArgumentParser()
parser.add_argument("filenames", nargs="+")
parser.add_argument(
"--template",
default=str(pathlib.Path(".").joinpath(".commit.template")),
nargs="?",
)
parser.add_argument("--board")
parser.add_argument("--regex")
return parser.parse_args(argv)


def get_branch_id(regex):
compiled_re = re.compile(regex)
branch = get_branch_name()

if not compiled_re.match(branch):
print(f"Bad branch name. Expected format of '{regex}'. Skipping.")
sys.exit(0)

return compiled_re.findall(branch)[0]
from .commands import cmd_update_commit_msg, cmd_validate_branch_name, cli


def main(argv=None):
args = arg_parser(argv)

if is_gjira_in_file(args.filenames[0]):
print("Duplicated. Skipping")
sys.exit(0)

task_id = get_branch_id(args.regex)
options = get_jira_from_env()

jira = JIRA(**options)

attributes = get_template_context(args.template)
issue = get_issue(jira, task_id, attributes)

if not issue.keys() or not issue.values():
sys.exit(0)

content = generate_template(issue, args.template)
update_commit_message(args.filenames[0], content)
cli()


if __name__ == "__main__":
Expand Down
72 changes: 72 additions & 0 deletions gjira/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import pathlib
import sys
import click

from jira import JIRA
from gjira.template import generate_template, get_template_context

from .gjira import (
get_issue,
get_jira_from_env,
is_gjira_in_file,
update_commit_message,
)

from .git import get_branch_id, get_branch_name, validate_branch_name


@click.command("append-jira")
@click.option("--board", "-b", required=True, type=str)
@click.option("--regex", "-r", required=True, type=str)
@click.option(
"--template",
"-t",
type=click.Path(exists=True, writable=True, readable=True, resolve_path=True),
default=str(pathlib.Path(".").joinpath(".commit.template")),
)
@click.argument("filename")
def cmd_update_commit_msg(filename: str, board: str, regex: str, template: str):
if is_gjira_in_file(filename):
print("Duplicated. Skipping")
sys.exit(0)

task_id = get_branch_id(regex)
options = get_jira_from_env()

jira = JIRA(**options)

attributes = get_template_context(template)
issue = get_issue(jira, task_id, attributes)

if not issue.keys() or not issue.values():
sys.exit(0)

content = generate_template(issue, template)
update_commit_message(filename, content)


@click.command("check-branch")
@click.option(
"--regex",
"-r",
required=True,
type=str,
help="Regex of a branch format to validate",
)
@click.option("--branch", "-b", type=str)
def cmd_validate_branch_name(regex: str, branch: str):
valid = validate_branch_name(branch or get_branch_name(), regex)
if valid is None:
print(f"Branch name requires the format of '{regex}'. Aborting.")
sys.exit(1)

sys.exit(0)


@click.group()
def cli():
pass


cli.add_command(cmd_validate_branch_name)
cli.add_command(cmd_update_commit_msg)
28 changes: 28 additions & 0 deletions gjira/git.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import Union
import re
import subprocess
import sys


def get_branch_name() -> str:
return subprocess.check_output(("git", "rev-parse", "--abbrev-ref", "HEAD")).decode(
"UTF-8"
)


def get_branch_id(regex):
compiled_re = re.compile(regex)
branch = get_branch_name()

if not compiled_re.match(branch):
print(f"Bad branch name. Expected format of '{regex}'. Skipping.")
sys.exit(0)

return compiled_re.findall(branch)[0]


def validate_branch_name(branch: str, regex: str) -> Union[list, None]:
compiled_re = re.compile(regex)
if not compiled_re.match(branch):
return None
return compiled_re.findall(branch)
7 changes: 0 additions & 7 deletions gjira/gjira.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,9 @@
from jira.exceptions import JIRAError

GJIRA_START_TEXT = "Jira information:"

GIT_START_LINES = "# Please enter the commit message for your changes. Lines starting\n"


def get_branch_name() -> str:
return subprocess.check_output(("git", "rev-parse", "--abbrev-ref", "HEAD")).decode(
"UTF-8"
)


def get_jira_from_env() -> dict:
return {
"server": os.environ.get("jiraserver"),
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
jira==2.0.0
Jinja2==2.11.2
click==7.1.2
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ description = Jira commit hook
[options]
packages = find:
install_requires =
jira
jira==2.0.0
Jinja2==2.11.2
click==7.1.2
python_requires=>=3.0.0

[options.entry_points]
Expand Down
20 changes: 20 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import pytest

from jira import JIRA
from click.testing import CliRunner

import random


Expand Down Expand Up @@ -43,3 +45,21 @@ def jira_issue(mocker):
jira_get_issue_mock.return_value = lambda: issue

return issue


@pytest.fixture
def git_branch(mocker):
def _mock_branch(branch=None):
if branch is None:
branch = "master"

subprocess = mocker.patch("subprocess.check_output")
subprocess.return_value = bytes(f"{branch}".encode("UTF-8"))
return subprocess

return _mock_branch


@pytest.fixture
def cli():
return CliRunner()
Loading