8000 Merge pull request #36 from synek/release/v0.1 · rorybyrne/git-plan@e1b6827 · GitHub
[go: up one dir, main page]

Skip to content

Commit

Permalink
Merge pull request #36 from synek/release/v0.1
Browse files Browse the repository at this point in the history
v0.1
  • Loading branch information
rorybyrne authored Mar 8, 2021
2 parents d9f56a1 + c89cc75 commit e1b6827
Show file tree
Hide file tree
Showing 19 changed files with 247 additions and 122 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ SHARE_DIR=${BASE_DIR}/share/git-plan
SYSTEMD_DIR=${BASE_DIR}/share/systemd/user

EXEC_FILES=git-plan
EXEC_FILES+=gp
SHARE_FILES=PLAN_TEMPLATE
SHARE_FILES+=EDIT_TEMPLATE
SERVICE_FILE=gitplan-oracle.service
Expand All @@ -25,6 +26,7 @@ install: check-env check-dirs
@echo "Installing to $(INSTALL_DIR)"
install -d $(INSTALL_DIR)
install -m 0755 scripts/* $(INSTALL_DIR)
ln -s $(INSTALL_DIR)/git-plan $(INSTALL_DIR)/gp
install -d $(SHARE_DIR)
install -m 0644 assets/share/* $(SHARE_DIR)
#install -d $(SYSTEMD_DIR)
Expand All @@ -38,7 +40,6 @@ uninstall:
@echo "Deleting executable files..."
@test -d $(INSTALL_DIR) && \
cd $(INSTALL_DIR) && \
(test -e $(EXEC_FILES) || echo "No executable files found") && \
rm -f $(EXEC_FILES) && \
echo "Done..."
@echo "Deleting share files..."
Expand Down
35 changes: 17 additions & 18 deletions README.md
8000
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,20 @@ A better workflow for git.
</p>

<p>
Git plan allows you to write your commit message before you start writing code.
</p>

<p>
The most frustrating part of using git is untangling unrelated changes into multiple commits. This is encouraged
by the git workflow of "write code -> stage changes -> commit changes", and then we are punished by git
when the time comes to commit.
</p>
<p>
Git plan allows you to write your commit message in advance via <code>git plan</code>, and then run <code>git plan commit</code>
to use that message as a template for your commit once you're ready.
Git plan inverts the git workflow so that you can write your commit message first, before you start writing code.
This makes it easier to plan your work and stay on-track.
</p>
<p>
You can even run <code>git plan add</code> to add more pre-planned commits, and then choose which one you want to
commit via <code>git plan commit</code>.
To use the tool, run <code>git plan init</code> (or simply <code>gp [command]</code>) to initialize, and then
<code>git plan add</code> to plan a new commit. Then when you have finished writing the code, use
<code>git plan commit</code> to use the plan as a template for your commit message.
</p>
<p>
<b>This tool is in <i>very early</i> alpha stages, so please make an issue or let me know if anything breaks.</b>
<b>This tool is in <b>early alpha</b> stage, so be careful and please make an issue or let me know if anything breaks.</b>
</p>

<h2>Installation</h2>
<p><code>python3.8</code> is required.</p>
<p><code>python3.8</code> is required for now.</p>
<ol>
<li><code>git clone https://github.com/synek/git-plan</code></li>
<li><code>cd git-plan</code></li>
Expand All @@ -47,14 +39,21 @@ A better workflow for git.

<h2>Usage</h2>
<ul>
<li><code>git plan</code> - plan your first commit, or list existing plans</li>
<li><code>git plan init</code> - initialize git plan in the current .git/ directory</li>
<li><code>git plan [--long]</code> - plan your first commit, or list existing plans</li>
<li><code>git plan help</code> - show the help message</li>
<li><code>git plan list</code> - list existing plans</li>
<li><code>git plan list [--long]</code> - list existing plans</li>
<li><code>git plan add</code> - plan a new commit</li>
<li><code>git plan edit</code> - edit an existing plan</li>
<li><code>git plan delete</code> - delete an existing plan</li>
<li><code>git plan commit</code> - commit one of your plans (launches <code>git commit</code> with your plan as a template)</li>
</ul>

<h2>Background</h2>
<p>
Here is an interesting <a href="https://arialdomartini.wordpress.com/2012/09/03/pre-emptive-commit-comments/">blog post</a>
about pre-emptive commit comments.
</p>

<h2>Contributing</h2>
<p>Give me a shout - rory@rory.bio</p>
<p>Give me a shout - rory@rory.bio or @ryrobyrne</p>
34 changes: 25 additions & 9 deletions git_plan/__cli__.py
8000
8000
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,44 @@

from git_plan.cli.cli import CLI
from git_plan.containers import Application
from git_plan.exceptions import ProjectNotInitialized

HOME = str(Path.home())
CONFIG_DIR = os.path.join(HOME, '.local', 'share', 'git-plan')


@inject
def main(args: List[str], cli: CLI = Provide[Application.cli]):
def main():
"""Entrypoint"""
app = Application()
configure(app)
app.wire(modules=[sys.modules[__name__]]) # What is this? Who knows, but it works.

try:
args = sys.argv[1:] # Might be []
launch_cli(args)
except ProjectNotInitialized as e:
print("Git plan is not initialized.\n\tPlease run `git plan init`")


@inject
def launch_cli(args: List[str], cli: CLI = Provide[Application.cli]):
cli.parse(args)


if __name__ == "__main__":
def configure(app: Application):
working_dir = os.getcwd()
args = sys.argv[1:] # Might be []

app = Application()
config_file = os.path.join(CONFIG_DIR, 'config.yaml')
if not os.path.exists(config_file):
raise RuntimeError(f'Config file not found at: "{config_file}"')

app.config.from_yaml(config_file)
app.config.set('app.plan_home', app.config.app.plan_home().replace('$HOME', HOME))
plan_home = app.config.app.plan_home().replace('$HOME', HOME)
app.config.set('app.plan_home', plan_home)
app.config.set('project.working_dir', working_dir)
app.wire(modules=[sys.modules[__name__]]) # What is this? Who knows, but it works.
app.config.set('app.edit_template_file', os.path.join(plan_home, app.config.app.edit_template_file()))
app.config.set('app.commit_template_file', os.path.join(plan_home, app.config.app.commit_template_file()))
app.config.set('app.projects_file', os.path.join(plan_home, app.config.app.projects_file()))


main(args)
if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion git_plan/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __init__(self, commands: List[Command]):

self._parser = argparse.ArgumentParser(prog='git-plan', description='A better workflow for git.')
self._parser.add_argument('subcommand', type=str, nargs='?', help='The subcommand to run')
self._parser.add_argument('--short', dest='short', action='store_true')
self._parser.add_argument('--long', dest='long', action='store_true')
subparsers = self._parser.add_subparsers(dest='subcommand')

for command in commands:
Expand Down
15 changes: 9 additions & 6 deletions git_plan/cli/commands/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,32 @@
from typing import Any

from git_plan.cli.commands.command import Command
from git_plan.model.project import Project
from git_plan.exceptions import PlanEmpty
from git_plan.service.plan import PlanService
from git_plan.util.decorators import requires_initialized


@requires_initialized
class Add(Command):
"""Add a new commit"""

subcommand = 'add'

def __init__(self, plan_service: PlanService, working_dir: str):
super().__init__()
def __init__(self, plan_service: PlanService, **kwargs):
super().__init__(**kwargs)
assert plan_service, "Plan service not injected"
assert working_dir, "Working dir not injected"
self._plan_service = plan_service
self._project = Project.from_working_dir(working_dir)

def pre_command(self):
"""Perhaps some validation?"""
pass

def command(self, **kwargs):
"""Create a new commit"""
self._plan_service.add_commit(self._project)
try:
self._plan_service.add_commit(self._project)
except PlanEmpty:
self._ui.bold('Plan empty, abandoning.')

def register_subparser(self, subparsers: Any):
subparsers.add_parser(Add.subcommand, help='Add a new commit plan.')
9 changes: 8 additions & 1 deletion git_plan/cli/commands/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Optional, List, Any

from git_plan.model.project import Project
from git_plan.service.ui import UIService

if TYPE_CHECKING:
from git_plan.cli.cli import CLI

Expand All @@ -13,8 +16,12 @@ class Command(ABC):

subcommand: str = None

def __init__(self):
def __init__(self, project: Project = None, ui_service: UIService = None, *args, **kwargs):
assert project, "Project missing."
assert ui_service, "UI service missing"
self._cli: Optional[CLI] = None
self._project = project
self._ui = ui_service

def run(self, context: dict):
self.pre_command()
Expand Down
14 changes: 5 additions & 9 deletions git_plan/cli/commands/commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,23 @@

from git_plan.cli.commands.command import Command
from git_plan.exceptions import CommitAbandoned
from git_plan.model.project import Project
from git_plan.service.git import GitService
from git_plan.service.plan import PlanService
from git_plan.service.ui import UIService
from git_plan.util.decorators import requires_initialized


@requires_initialized
class Commit(Command):
"""Commit a planned commit"""

subcommand = 'commit'

def __init__(self, plan_service: PlanService, working_dir: str, ui_service: UIService, git_service: GitService):
super().__init__()
def __init__(self, plan_service: PlanService, git_service: GitService, **kwargs):
super().__init__(**kwargs)
assert plan_service, "Plan service not injected"
assert git_service, "Git service not injected"
assert ui_service, "UI service not injected"
assert working_dir, "Working dir not injected"
self._plan_service = plan_service
self._git_service = git_service
self._ui_service = ui_service
self._project = Project.from_working_dir(working_dir)

def pre_command(self):
"""Perhaps some validation?"""
Expand All @@ -43,7 +39,7 @@ def command(self, **kwargs):
print("No staged files.")
return

chosen_commit = self._ui_service.choose_commit(commits, 'Which plan do you want to commit?')
chosen_commit = self._ui.choose_commit(commits, 'Which plan do you want to commit?')
try:
self._git_service.commit(chosen_commit)
self._plan_service.delete_commit(chosen_commit)
Expand Down
23 changes: 10 additions & 13 deletions git_plan/cli/commands/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,20 @@
from typing import Any

from git_plan.cli.commands.command import Command
from git_plan.model.project import Project
from git_plan.service.plan import PlanService
from git_plan.service.ui import UIService
from git_plan.util.decorators import requires_initialized


@requires_initialized
class Delete(Command):
"""Delete an existing commit"""

subcommand = 'delete'

def __init__(self, plan_service: PlanService, working_dir: str, ui_service: UIService):
super().__init__()
def __init__(self, plan_service: PlanService, **kwargs):
super().__init__(**kwargs)
assert plan_service, "Plan service not injected"
assert working_dir, "Working dir not injected"
self._plan_service = plan_service
self._ui_service = ui_service
self._project = Project.from_working_dir(working_dir)

def pre_command(self):
"""Perhaps some validation?"""
Expand All @@ -31,19 +28,19 @@ def command(self, **kwargs):
"""Create a new commit"""
commits = self._plan_service.get_commits(self._project)
if not commits:
print("No commits found.")
self._ui.bold('No commits found.')
return

chosen_commit = self._ui_service.choose_commit(commits, 'Which plan do you want to delete?')
chosen_commit = self._ui.choose_commit(co 10000 mmits, 'Which plan do you want to delete?')

self._ui_service.bold(f'{chosen_commit.message.headline}\n')
self._ui.bold(f'{chosen_commit.message.headline}\n')
confirm_msg = f'Are you sure you want to delete this commit?'
if not self._ui_service.confirm(confirm_msg):
print("Stopped.")
if not self._ui.confirm(confirm_msg):
self._ui.bold("Stopped.")
return

self._plan_service.delete_commit(chosen_commit)
print('Deleted.')
self._ui.bold('Deleted.')

def register_subparser(self, subparsers: Any):
subparsers.add_parser(Delete.subcommand, help='Delete a planned commit.')
14 changes: 6 additions & 8 deletions git_plan/cli/commands/edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,21 @@
from typing import Any

from git_plan.cli.commands.command import Command
from git_plan.model.project import Project
from git_plan.service.plan import PlanService
from git_plan.service.ui import UIService
from git_plan.util.decorators import requires_initialized


@requires_initialized
class Edit(Command):
"""Edit an existing commit"""

subcommand = 'edit'

def __init__(self, plan_service: PlanService, working_dir: str, ui_service: UIService):
super().__init__()
def __init__(self, plan_service: PlanService, **kwargs):
super().__init__(**kwargs)
assert plan_service, "Plan service not injected"
assert working_dir, "Working dir not injected"
self._plan_service = plan_service
self._ui_service = ui_service
self._project = Project.from_working_dir(working_dir)

def pre_command(self):
"""Perhaps some validation?"""
Expand All @@ -31,10 +29,10 @@ def command(self, **kwargs):
"""Create a new commit"""
commits = self._plan_service.get_commits(self._project)
if not commits:
print("No commits to edit.")
self._ui.bold('No commits to edit.')
return

chosen_commit = self._ui_service.choose_commit(commits, 'Which plan do you want to edit?')
chosen_commit = self._ui.choose_commit(commits, 'Which plan do you want to edit?')

self._plan_service.edit_commit(chosen_commit)

Expand Down
2 changes: 1 addition & 1 deletion git_plan/cli/commands/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Help(Command):
subcommand = 'help'

def __init__(self):
super().__init__()
pass

def pre_command(self):
"""Perhaps some validation?"""
Expand Down
39 changes: 39 additions & 0 deletions git_plan/cli/commands/init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Init command
@author Rory Byrne <rory@rory.bio>
"""
from typing import Any

from git_plan.cli.commands.command import Command
from git_plan.service.project import ProjectService
from git_plan.service.ui import UIService


class Init(Command):
"""Initialize git plan in the directory."""

subcommand = 'init'

def __init__(self, project_service: ProjectService, **kwargs):
super().__init__(**kwargs)
assert project_service, "Project service not injected"
self._project_service = project_service

def pre_command(self):
"""Check whether a plan already exists?"""
pass

def command(self, **kwargs):
"""Initialize the project if it is not already initialized"""
if not self._project.is_git_repository():
self._ui.bold("Not in a git repository.")
return

if self._project.is_initialized():
self._ui.bold("Git plan is already initialized.")
else:
self._project_service.initialize(self._project)
self._ui.bold("Initialized git plan.")

def register_subparser(self, subparsers: Any):
subparsers.add_parser(Init.subcommand, help='Initialize git plan.')
Loading

0 comments on commit e1b6827

Please sign in to comment.
0