commitflow 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,108 @@
1
+ import argparse
2
+ import sys
3
+
4
+ from . import __version__
5
+ from .ui import print_header, error
6
+ from .scheduler import schedule_interactive
7
+
8
+ # modes
9
+ from .modes.interactive import interactive_mode
10
+ from .modes.quick import quick_mode
11
+ from .modes.auto import auto_mode
12
+ from .modes.setup import setup_mode
13
+
14
+
15
+ VERSION = f"CommitFlow {__version__}"
16
+
17
+
18
+ def main():
19
+ """
20
+ Main CLI entrypoint.
21
+ """
22
+
23
+ parser = argparse.ArgumentParser(
24
+ prog="commitflow",
25
+ description="CommitFlow - Daily Git consistency assistant"
26
+ )
27
+
28
+ parser.add_argument(
29
+ "--quick",
30
+ action="store_true",
31
+ help="Quick commit mode using configured repository"
32
+ )
33
+
34
+ parser.add_argument(
35
+ "--auto",
36
+ action="store_true",
37
+ help="Automatic commit mode (used by scheduler)"
38
+ )
39
+
40
+ parser.add_argument(
41
+ "--setup",
42
+ action="store_true",
43
+ help="Run setup wizard"
44
+ )
45
+
46
+ parser.add_argument(
47
+ "--schedule",
48
+ action="store_true",
49
+ help="Create scheduled automation task"
50
+ )
51
+
52
+ parser.add_argument(
53
+ "--version",
54
+ action="store_true",
55
+ help="Show CommitFlow version"
56
+ )
57
+
58
+ args = parser.parse_args()
59
+
60
+ try:
61
+
62
+ # version command
63
+ if args.version:
64
+
65
+ print(VERSION)
66
+ return
67
+
68
+ # setup wizard
69
+ if args.setup:
70
+
71
+ setup_mode()
72
+ return
73
+
74
+ # scheduler setup
75
+ if args.schedule:
76
+
77
+ print_header(VERSION)
78
+ schedule_interactive()
79
+ return
80
+
81
+ # auto mode
82
+ if args.auto:
83
+
84
+ auto_mode()
85
+ return
86
+
87
+ # quick mode
88
+ if args.quick:
89
+
90
+ quick_mode()
91
+ return
92
+
93
+ # default interactive mode
94
+ interactive_mode()
95
+
96
+ except KeyboardInterrupt:
97
+
98
+ print("\nOperation cancelled by user.")
99
+ sys.exit(0)
100
+
101
+ except Exception as e:
102
+
103
+ error(f"Unexpected error: {str(e)}")
104
+ sys.exit(1)
105
+
106
+
107
+ if __name__ == "__main__":
108
+ main()
File without changes
@@ -0,0 +1,118 @@
1
+ import os
2
+ from datetime import datetime
3
+
4
+ from ..config import load_config
5
+ from ..git_utils import (
6
+ is_git_repo,
7
+ get_branch,
8
+ add_files,
9
+ has_changes_to_commit,
10
+ commit_changes,
11
+ push_changes,
12
+ count_staged_files
13
+ )
14
+
15
+ from ..ui import (
16
+ print_header,
17
+ success,
18
+ warning,
19
+ error,
20
+ print_commit_summary
21
+ )
22
+
23
+ from ..logger import (
24
+ log_commit,
25
+ log_info,
26
+ log_warning,
27
+ log_error
28
+ )
29
+
30
+
31
+ def auto_mode():
32
+ """
33
+ Fully automatic commit mode.
34
+ Used by schedulers.
35
+ """
36
+
37
+ try:
38
+
39
+ print_header()
40
+
41
+ config = load_config()
42
+
43
+ repo_path = config.get("repo", "")
44
+ auto_add = config.get("auto_add", ".")
45
+ auto_push = config.get("auto_push", False)
46
+ commit_message = config.get("commit_message", "daily progress update")
47
+
48
+ if not repo_path:
49
+
50
+ error("Repository not configured.")
51
+ log_error("Auto mode failed: repo not configured")
52
+ return
53
+
54
+ if not os.path.isdir(repo_path):
55
+
56
+ error("Configured repository path does not exist.")
57
+ log_error("Auto mode failed: repo path invalid")
58
+ return
59
+
60
+ if not is_git_repo(repo_path):
61
+
62
+ error("Configured path is not a git repository.")
63
+ log_error("Auto mode failed: not a git repo")
64
+ return
65
+
66
+ repo_name = os.path.basename(repo_path)
67
+
68
+ branch = get_branch(repo_path)
69
+
70
+ log_info(f"Auto commit started for repo={repo_name}")
71
+
72
+ add_files(repo_path, auto_add)
73
+
74
+ if not has_changes_to_commit(repo_path):
75
+
76
+ warning("No changes detected. Skipping commit.")
77
+ log_warning("Auto commit skipped: no changes")
78
+ return
79
+
80
+ today = datetime.now().strftime("%Y-%m-%d")
81
+
82
+ message = f"{commit_message} ({today})"
83
+
84
+ commit_changes(repo_path, message)
85
+
86
+ pushed = False
87
+
88
+ if auto_push:
89
+
90
+ push_changes(repo_path)
91
+
92
+ pushed = True
93
+
94
+ files_count = count_staged_files(repo_path)
95
+
96
+ print_commit_summary(
97
+ repo=repo_name,
98
+ branch=branch,
99
+ files=files_count,
100
+ message=message,
101
+ pushed=pushed
102
+ )
103
+
104
+ log_commit(
105
+ repo=repo_name,
106
+ branch=branch,
107
+ files=files_count,
108
+ message=message,
109
+ pushed=pushed
110
+ )
111
+
112
+ success("Auto commit completed successfully.")
113
+
114
+ except Exception as e:
115
+
116
+ error(f"Auto mode failed: {str(e)}")
117
+
118
+ log_error(str(e))
@@ -0,0 +1,172 @@
1
+ import os
2
+ from datetime import datetime
3
+
4
+ from ..git_utils import (
5
+ is_git_repo,
6
+ get_status,
7
+ get_branch,
8
+ get_remote_url,
9
+ add_files,
10
+ preview_staged_changes,
11
+ has_changes_to_commit,
12
+ commit_changes,
13
+ push_changes,
14
+ count_staged_files,
15
+ )
16
+
17
+ from ..repo_scanner import auto_detect_repo
18
+ from ..ui import (
19
+ print_header,
20
+ divider,
21
+ print_repo_info,
22
+ print_git_status,
23
+ show_commit_preview,
24
+ print_commit_summary,
25
+ info,
26
+ success,
27
+ warning,
28
+ error,
29
+ prompt,
30
+ restart_message,
31
+ exit_message,
32
+ )
33
+
34
+ from ..logger import (
35
+ log_info,
36
+ log_error,
37
+ log_commit
38
+ )
39
+
40
+
41
+ def interactive_mode():
42
+ """
43
+ Main interactive workflow.
44
+ """
45
+
46
+ while True:
47
+
48
+ try:
49
+
50
+ print_header()
51
+
52
+ repo_path = prompt("📁 Repo Path (leave blank to scan) ➤ ").strip()
53
+
54
+ if not repo_path:
55
+
56
+ repo_path = auto_detect_repo()
57
+
58
+ if not repo_path:
59
+ error("No repository selected.")
60
+ return
61
+
62
+ if not os.path.isdir(repo_path):
63
+
64
+ error("Invalid repository path.")
65
+ return
66
+
67
+ if not is_git_repo(repo_path):
68
+
69
+ error("Selected directory is not a git repository.")
70
+ return
71
+
72
+ repo_name = os.path.basename(repo_path)
73
+
74
+ branch = get_branch(repo_path)
75
+
76
+ remote = get_remote_url(repo_path)
77
+
78
+ divider()
79
+
80
+ print_repo_info(repo_name, branch, remote)
81
+
82
+ divider()
83
+
84
+ status = get_status(repo_path)
85
+
86
+ print_git_status(status)
87
+
88
+ divider()
89
+
90
+ files = prompt("➕ Files to add ('.' for all) ➤ ").strip()
91
+
92
+ if not files:
93
+ files = "."
94
+
95
+ add_files(repo_path, files)
96
+
97
+ if not has_changes_to_commit(repo_path):
98
+
99
+ warning("Nothing to commit.")
100
+
101
+ return
102
+
103
+ diff = preview_staged_changes(repo_path)
104
+
105
+ show_commit_preview(diff)
106
+
107
+ confirm = prompt("Proceed with commit? (y/n) ➤ ").lower()
108
+
109
+ if confirm != "y":
110
+
111
+ warning("Commit cancelled.")
112
+ return
113
+
114
+ message = prompt("📝 Commit message (Enter for auto) ➤ ").strip()
115
+
116
+ if not message:
117
+
118
+ today = datetime.now().strftime("%Y-%m-%d")
119
+
120
+ message = f"daily progress update ({today})"
121
+
122
+ commit_changes(repo_path, message)
123
+
124
+ success("Commit successful.")
125
+
126
+ pushed = False
127
+
128
+ push = prompt("🚀 Push to remote? (y/n) ➤ ").lower()
129
+
130
+ if push == "y":
131
+
132
+ push_changes(repo_path)
133
+
134
+ pushed = True
135
+
136
+ success("Changes pushed to remote.")
137
+
138
+ files_count = count_staged_files(repo_path)
139
+
140
+ print_commit_summary(
141
+ repo=repo_name,
142
+ branch=branch,
143
+ files=files_count,
144
+ message=message,
145
+ pushed=pushed
146
+ )
147
+
148
+ log_commit(
149
+ repo=repo_name,
150
+ branch=branch,
151
+ files=files_count,
152
+ message=message,
153
+ pushed=pushed
154
+ )
155
+
156
+ restart = prompt("\n🔁 Make another commit? (y/n) ➤ ").lower()
157
+
158
+ if restart != "y":
159
+
160
+ exit_message()
161
+
162
+ break
163
+
164
+ restart_message()
165
+
166
+ except Exception as e:
167
+
168
+ error(f"Unexpected error: {str(e)}")
169
+
170
+ log_error(str(e))
171
+
172
+ return
@@ -0,0 +1,143 @@
1
+ import os
2
+ from datetime import datetime
3
+
4
+ from ..config import get_repo
5
+ from ..git_utils import (
6
+ is_git_repo,
7
+ get_status,
8
+ get_branch,
9
+ get_remote_url,
10
+ add_files,
11
+ preview_staged_changes,
12
+ has_changes_to_commit,
13
+ commit_changes,
14
+ push_changes,
15
+ count_staged_files
16
+ )
17
+
18
+ from ..ui import (
19
+ print_header,
20
+ divider,
21
+ print_repo_info,
22
+ print_git_status,
23
+ show_commit_preview,
24
+ print_commit_summary,
25
+ info,
26
+ success,
27
+ warning,
28
+ error,
29
+ prompt
30
+ )
31
+
32
+ from ..logger import log_commit, log_error
33
+
34
+
35
+ def quick_mode():
36
+ """
37
+ Quick commit mode using repository from config.
38
+ """
39
+
40
+ try:
41
+
42
+ print_header()
43
+
44
+ repo_path = get_repo()
45
+
46
+ if not os.path.isdir(repo_path):
47
+
48
+ error("Configured repository path does not exist.")
49
+ return
50
+
51
+ if not is_git_repo(repo_path):
52
+
53
+ error("Configured directory is not a Git repository.")
54
+ return
55
+
56
+ repo_name = os.path.basename(repo_path)
57
+
58
+ branch = get_branch(repo_path)
59
+
60
+ remote = get_remote_url(repo_path)
61
+
62
+ divider()
63
+
64
+ print_repo_info(repo_name, branch, remote)
65
+
66
+ divider()
67
+
68
+ status = get_status(repo_path)
69
+
70
+ print_git_status(status)
71
+
72
+ divider()
73
+
74
+ files = prompt("➕ Files to add ('.' for all) ➤ ").strip()
75
+
76
+ if not files:
77
+ files = "."
78
+
79
+ add_files(repo_path, files)
80
+
81
+ if not has_changes_to_commit(repo_path):
82
+
83
+ warning("Nothing to commit.")
84
+ return
85
+
86
+ diff = preview_staged_changes(repo_path)
87
+
88
+ show_commit_preview(diff)
89
+
90
+ confirm = prompt("Proceed with commit? (y/n) ➤ ").lower()
91
+
92
+ if confirm != "y":
93
+
94
+ warning("Commit cancelled.")
95
+ return
96
+
97
+ message = prompt("📝 Commit message (Enter for auto) ➤ ").strip()
98
+
99
+ if not message:
100
+
101
+ today = datetime.now().strftime("%Y-%m-%d")
102
+
103
+ message = f"daily progress update ({today})"
104
+
105
+ commit_changes(repo_path, message)
106
+
107
+ success("Commit successful.")
108
+
109
+ pushed = False
110
+
111
+ push = prompt("🚀 Push to remote? (y/n) ➤ ").lower()
112
+
113
+ if push == "y":
114
+
115
+ push_changes(repo_path)
116
+
117
+ pushed = True
118
+
119
+ success("Changes pushed to remote.")
120
+
121
+ files_count = count_staged_files(repo_path)
122
+
123
+ print_commit_summary(
124
+ repo=repo_name,
125
+ branch=branch,
126
+ files=files_count,
127
+ message=message,
128
+ pushed=pushed
129
+ )
130
+
131
+ log_commit(
132
+ repo=repo_name,
133
+ branch=branch,
134
+ files=files_count,
135
+ message=message,
136
+ pushed=pushed
137
+ )
138
+
139
+ except Exception as e:
140
+
141
+ error(f"Unexpected error: {str(e)}")
142
+
143
+ log_error(str(e))
@@ -0,0 +1,90 @@
1
+ import os
2
+
3
+ from ..config import save_config, DEFAULT_CONFIG
4
+ from ..git_utils import is_git_repo
5
+ from ..scheduler import schedule_interactive
6
+ from ..ui import (
7
+ print_header,
8
+ divider,
9
+ success,
10
+ error,
11
+ info,
12
+ prompt
13
+ )
14
+
15
+ from ..logger import log_info
16
+
17
+
18
+ def setup_mode():
19
+ """
20
+ CommitFlow setup wizard.
21
+ """
22
+
23
+ try:
24
+
25
+ print_header()
26
+
27
+ divider()
28
+ info("CommitFlow Setup Wizard")
29
+ divider()
30
+
31
+ # Ask repository path
32
+ repo_path = prompt("📁 Repository path ➤ ").strip()
33
+
34
+ if not repo_path:
35
+ error("Repository path cannot be empty.")
36
+ return
37
+
38
+ if not os.path.isdir(repo_path):
39
+ error("Directory does not exist.")
40
+ return
41
+
42
+ if not is_git_repo(repo_path):
43
+ error("Selected directory is not a Git repository.")
44
+ return
45
+
46
+ # Auto push option
47
+ push_choice = prompt("🚀 Push automatically after commit? (y/n) ➤ ").lower()
48
+ auto_push = push_choice == "y"
49
+
50
+ # Default commit message
51
+ commit_message = prompt(
52
+ "📝 Default commit message (press Enter for default) ➤ "
53
+ ).strip()
54
+
55
+ if not commit_message:
56
+ commit_message = DEFAULT_CONFIG["commit_message"]
57
+
58
+ # Schedule time
59
+ schedule_time = prompt(
60
+ "⏰ Daily commit time (HH:MM) ➤ "
61
+ ).strip()
62
+
63
+ # Create configuration
64
+ config = {
65
+ "repo": repo_path,
66
+ "auto_push": auto_push,
67
+ "auto_add": ".",
68
+ "commit_message": commit_message,
69
+ "schedule_time": schedule_time
70
+ }
71
+
72
+ save_config(config)
73
+
74
+ success("Configuration saved successfully.")
75
+
76
+ divider()
77
+
78
+ # Ask scheduler creation
79
+ schedule_choice = prompt("⚙ Setup automatic scheduler now? (y/n) ➤ ").lower()
80
+
81
+ if schedule_choice == "y":
82
+ schedule_interactive()
83
+
84
+ success("CommitFlow setup completed successfully.")
85
+
86
+ log_info("CommitFlow setup completed")
87
+
88
+ except Exception as e:
89
+
90
+ error(f"Setup failed: {str(e)}")