standup-cli-tool 0.1.0__tar.gz → 0.3.0__tar.gz
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.
- {standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/PKG-INFO +79 -16
- {standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/README.md +88 -25
- {standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/pyproject.toml +2 -2
- standup_cli_tool-0.3.0/standup_cli/main.py +459 -0
- {standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/standup_cli_tool.egg-info/PKG-INFO +79 -16
- standup_cli_tool-0.1.0/standup_cli/main.py +0 -117
- {standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/setup.cfg +0 -0
- {standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/standup_cli_tool.egg-info/SOURCES.txt +0 -0
- {standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/standup_cli_tool.egg-info/dependency_links.txt +0 -0
- {standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/standup_cli_tool.egg-info/entry_points.txt +0 -0
- {standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/standup_cli_tool.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: standup-cli-tool
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: ⚡ Generate your daily standup from git commits — right in your terminal
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/muhtalhakhan/standup-cli
|
|
@@ -21,10 +21,12 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
|
|
22
22
|
Never manually write a standup again. `standup-cli` scans your git commits from the last 24 hours, asks what you're working on today and if you have blockers, then formats a clean standup message ready to paste anywhere.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
```bash
|
|
25
27
|
$ standup
|
|
26
28
|
|
|
27
|
-
⚡ standup-cli
|
|
29
|
+
⚡ standup-cli-tool
|
|
28
30
|
Generate your daily standup in seconds
|
|
29
31
|
|
|
30
32
|
🔍 Scanning git commits from last 24hrs...
|
|
@@ -53,20 +55,22 @@ $ standup
|
|
|
53
55
|
|
|
54
56
|
## Install
|
|
55
57
|
|
|
56
|
-
**via npm
|
|
58
|
+
**via npm**:
|
|
59
|
+
|
|
57
60
|
```bash
|
|
58
|
-
npm install -g standup-cli
|
|
61
|
+
npm install -g standup-cli-tool
|
|
59
62
|
```
|
|
60
63
|
|
|
61
|
-
**via pip
|
|
64
|
+
**via pip**:
|
|
65
|
+
|
|
62
66
|
```bash
|
|
63
|
-
pip install standup-cli
|
|
67
|
+
pip install standup-cli-tool
|
|
64
68
|
```
|
|
65
69
|
|
|
66
70
|
## Usage
|
|
67
71
|
|
|
68
72
|
```bash
|
|
69
|
-
# Default (plain
|
|
73
|
+
# Default (plain output, current repo, clipboard on)
|
|
70
74
|
standup
|
|
71
75
|
|
|
72
76
|
# Slack-ready output
|
|
@@ -74,14 +78,71 @@ standup --format slack
|
|
|
74
78
|
|
|
75
79
|
# Markdown output
|
|
76
80
|
standup --format markdown
|
|
81
|
+
|
|
82
|
+
# Team label
|
|
83
|
+
standup --team "Platform"
|
|
84
|
+
|
|
85
|
+
# Disable auto-copy
|
|
86
|
+
standup --no-copy
|
|
87
|
+
|
|
88
|
+
# Scan multiple repositories
|
|
89
|
+
standup --repo . --repo ../another-repo
|
|
90
|
+
|
|
91
|
+
# Weekly summary mode
|
|
92
|
+
standup --weekly
|
|
77
93
|
```
|
|
78
94
|
|
|
79
|
-
##
|
|
95
|
+
## What It Includes
|
|
96
|
+
|
|
97
|
+
- Conventional Commit parsing (`feat`, `fix`, `docs`, etc.) into grouped sections
|
|
98
|
+
- Files changed count per repository (last 24h or weekly window)
|
|
99
|
+
- Output grouped by repository
|
|
100
|
+
- Clipboard auto-copy by default
|
|
101
|
+
- `.standuprc` support for defaults
|
|
102
|
+
- Weekly summaries with `--weekly`
|
|
103
|
+
|
|
104
|
+
## .standuprc
|
|
80
105
|
|
|
81
|
-
|
|
106
|
+
Place `.standuprc` in the current project or your home directory.
|
|
107
|
+
|
|
108
|
+
JSON format:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"format": "slack",
|
|
113
|
+
"team": "Platform",
|
|
114
|
+
"copy": true,
|
|
115
|
+
"weekly": false,
|
|
116
|
+
"repos": [".", "../service-api"]
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Key-value format is also supported:
|
|
121
|
+
|
|
122
|
+
```ini
|
|
123
|
+
format=plain
|
|
124
|
+
team=Platform
|
|
125
|
+
copy=true
|
|
126
|
+
weekly=false
|
|
127
|
+
repos=.,../service-api
|
|
82
128
|
```
|
|
83
|
-
|
|
84
|
-
|
|
129
|
+
|
|
130
|
+
## Output Example (plain)
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
Team: Platform
|
|
134
|
+
Yesterday:
|
|
135
|
+
standup-cli (3 commits, 9 files changed):
|
|
136
|
+
Features:
|
|
137
|
+
- Add repo grouping support
|
|
138
|
+
Fixes:
|
|
139
|
+
- Handle empty commit logs
|
|
140
|
+
|
|
141
|
+
service-api (2 commits, 4 files changed):
|
|
142
|
+
Docs:
|
|
143
|
+
- Update API usage notes
|
|
144
|
+
|
|
145
|
+
Today: Finish release checks
|
|
85
146
|
Blockers: None
|
|
86
147
|
```
|
|
87
148
|
|
|
@@ -112,14 +173,16 @@ None
|
|
|
112
173
|
2. Prompts you for today's focus and any blockers
|
|
113
174
|
3. Formats and prints your standup
|
|
114
175
|
|
|
176
|
+
Use `--weekly` to scan commits from the last 7 days and label the summary as `Last week` / `Next`.
|
|
177
|
+
|
|
115
178
|
> **Tip:** Run it from your project root for best results. Works with any git repo.
|
|
116
179
|
|
|
117
180
|
## Roadmap (v1 ideas)
|
|
118
181
|
|
|
119
|
-
- [
|
|
120
|
-
- [
|
|
121
|
-
- [
|
|
122
|
-
- [
|
|
182
|
+
- [x] Copy to clipboard automatically
|
|
183
|
+
- [x] Support multiple repos
|
|
184
|
+
- [x] `.standuprc` config file for team name, format preference
|
|
185
|
+
- [x] Weekly summary mode
|
|
123
186
|
|
|
124
187
|
## License
|
|
125
188
|
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
> Generate your daily standup from git commits — right in your terminal.
|
|
4
4
|
|
|
5
|
-
Never manually write a standup again. `standup-cli` scans your git commits from the last 24 hours, asks what you're working on today and if you have blockers, then formats a clean standup message ready to paste anywhere.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
Never manually write a standup again. `standup-cli` scans your git commits from the last 24 hours, asks what you're working on today and if you have blockers, then formats a clean standup message ready to paste anywhere.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
$ standup
|
|
11
|
+
|
|
12
|
+
⚡ standup-cli-tool
|
|
11
13
|
Generate your daily standup in seconds
|
|
12
14
|
|
|
13
15
|
🔍 Scanning git commits from last 24hrs...
|
|
@@ -36,20 +38,22 @@ $ standup
|
|
|
36
38
|
|
|
37
39
|
## Install
|
|
38
40
|
|
|
39
|
-
**via npm
|
|
41
|
+
**via npm**:
|
|
42
|
+
|
|
40
43
|
```bash
|
|
41
|
-
npm install -g standup-cli
|
|
44
|
+
npm install -g standup-cli-tool
|
|
42
45
|
```
|
|
43
46
|
|
|
44
|
-
**via pip
|
|
47
|
+
**via pip**:
|
|
48
|
+
|
|
45
49
|
```bash
|
|
46
|
-
pip install standup-cli
|
|
50
|
+
pip install standup-cli-tool
|
|
47
51
|
```
|
|
48
52
|
|
|
49
53
|
## Usage
|
|
50
54
|
|
|
51
55
|
```bash
|
|
52
|
-
# Default (plain
|
|
56
|
+
# Default (plain output, current repo, clipboard on)
|
|
53
57
|
standup
|
|
54
58
|
|
|
55
59
|
# Slack-ready output
|
|
@@ -57,14 +61,71 @@ standup --format slack
|
|
|
57
61
|
|
|
58
62
|
# Markdown output
|
|
59
63
|
standup --format markdown
|
|
64
|
+
|
|
65
|
+
# Team label
|
|
66
|
+
standup --team "Platform"
|
|
67
|
+
|
|
68
|
+
# Disable auto-copy
|
|
69
|
+
standup --no-copy
|
|
70
|
+
|
|
71
|
+
# Scan multiple repositories
|
|
72
|
+
standup --repo . --repo ../another-repo
|
|
73
|
+
|
|
74
|
+
# Weekly summary mode
|
|
75
|
+
standup --weekly
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## What It Includes
|
|
79
|
+
|
|
80
|
+
- Conventional Commit parsing (`feat`, `fix`, `docs`, etc.) into grouped sections
|
|
81
|
+
- Files changed count per repository (last 24h or weekly window)
|
|
82
|
+
- Output grouped by repository
|
|
83
|
+
- Clipboard auto-copy by default
|
|
84
|
+
- `.standuprc` support for defaults
|
|
85
|
+
- Weekly summaries with `--weekly`
|
|
86
|
+
|
|
87
|
+
## .standuprc
|
|
88
|
+
|
|
89
|
+
Place `.standuprc` in the current project or your home directory.
|
|
90
|
+
|
|
91
|
+
JSON format:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"format": "slack",
|
|
96
|
+
"team": "Platform",
|
|
97
|
+
"copy": true,
|
|
98
|
+
"weekly": false,
|
|
99
|
+
"repos": [".", "../service-api"]
|
|
100
|
+
}
|
|
60
101
|
```
|
|
61
102
|
|
|
62
|
-
|
|
103
|
+
Key-value format is also supported:
|
|
63
104
|
|
|
64
|
-
|
|
105
|
+
```ini
|
|
106
|
+
format=plain
|
|
107
|
+
team=Platform
|
|
108
|
+
copy=true
|
|
109
|
+
weekly=false
|
|
110
|
+
repos=.,../service-api
|
|
65
111
|
```
|
|
66
|
-
|
|
67
|
-
|
|
112
|
+
|
|
113
|
+
## Output Example (plain)
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
Team: Platform
|
|
117
|
+
Yesterday:
|
|
118
|
+
standup-cli (3 commits, 9 files changed):
|
|
119
|
+
Features:
|
|
120
|
+
- Add repo grouping support
|
|
121
|
+
Fixes:
|
|
122
|
+
- Handle empty commit logs
|
|
123
|
+
|
|
124
|
+
service-api (2 commits, 4 files changed):
|
|
125
|
+
Docs:
|
|
126
|
+
- Update API usage notes
|
|
127
|
+
|
|
128
|
+
Today: Finish release checks
|
|
68
129
|
Blockers: None
|
|
69
130
|
```
|
|
70
131
|
|
|
@@ -91,19 +152,21 @@ None
|
|
|
91
152
|
|
|
92
153
|
## How it works
|
|
93
154
|
|
|
94
|
-
1. Runs `git log --since="24 hours ago"` in your current directory
|
|
95
|
-
2. Prompts you for today's focus and any blockers
|
|
96
|
-
3. Formats and prints your standup
|
|
97
|
-
|
|
98
|
-
|
|
155
|
+
1. Runs `git log --since="24 hours ago"` in your current directory
|
|
156
|
+
2. Prompts you for today's focus and any blockers
|
|
157
|
+
3. Formats and prints your standup
|
|
158
|
+
|
|
159
|
+
Use `--weekly` to scan commits from the last 7 days and label the summary as `Last week` / `Next`.
|
|
160
|
+
|
|
161
|
+
> **Tip:** Run it from your project root for best results. Works with any git repo.
|
|
99
162
|
|
|
100
163
|
## Roadmap (v1 ideas)
|
|
101
164
|
|
|
102
|
-
- [
|
|
103
|
-
- [
|
|
104
|
-
- [
|
|
105
|
-
- [
|
|
165
|
+
- [x] Copy to clipboard automatically
|
|
166
|
+
- [x] Support multiple repos
|
|
167
|
+
- [x] `.standuprc` config file for team name, format preference
|
|
168
|
+
- [x] Weekly summary mode
|
|
106
169
|
|
|
107
170
|
## License
|
|
108
171
|
|
|
109
|
-
MIT © [Muhammad Talha Khan](https://github.com/muhtalhakhan)
|
|
172
|
+
MIT © [Muhammad Talha Khan](https://github.com/muhtalhakhan)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "standup-cli-tool"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "⚡ Generate your daily standup from git commits — right in your terminal"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -24,4 +24,4 @@ standup = "standup_cli.main:main"
|
|
|
24
24
|
[project.urls]
|
|
25
25
|
Homepage = "https://github.com/muhtalhakhan/standup-cli"
|
|
26
26
|
Repository = "https://github.com/muhtalhakhan/standup-cli"
|
|
27
|
-
Issues = "https://github.com/muhtalhakhan/standup-cli/issues"
|
|
27
|
+
Issues = "https://github.com/muhtalhakhan/standup-cli/issues"
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
# ANSI colors
|
|
12
|
+
RESET = "\x1b[0m"
|
|
13
|
+
BOLD = "\x1b[1m"
|
|
14
|
+
DIM = "\x1b[2m"
|
|
15
|
+
CYAN = "\x1b[36m"
|
|
16
|
+
GREEN = "\x1b[32m"
|
|
17
|
+
YELLOW = "\x1b[33m"
|
|
18
|
+
MAGENTA = "\x1b[35m"
|
|
19
|
+
GRAY = "\x1b[90m"
|
|
20
|
+
|
|
21
|
+
TYPE_ORDER = [
|
|
22
|
+
"feat",
|
|
23
|
+
"fix",
|
|
24
|
+
"refactor",
|
|
25
|
+
"perf",
|
|
26
|
+
"docs",
|
|
27
|
+
"test",
|
|
28
|
+
"chore",
|
|
29
|
+
"build",
|
|
30
|
+
"ci",
|
|
31
|
+
"style",
|
|
32
|
+
"other",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
TYPE_LABELS = {
|
|
36
|
+
"feat": "Features",
|
|
37
|
+
"fix": "Fixes",
|
|
38
|
+
"refactor": "Refactors",
|
|
39
|
+
"perf": "Performance",
|
|
40
|
+
"docs": "Docs",
|
|
41
|
+
"test": "Tests",
|
|
42
|
+
"chore": "Chores",
|
|
43
|
+
"build": "Build",
|
|
44
|
+
"ci": "CI",
|
|
45
|
+
"style": "Style",
|
|
46
|
+
"other": "Other",
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def paint(color, text):
|
|
51
|
+
return f"{color}{text}{RESET}"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def parse_bool(value, default):
|
|
55
|
+
if value is None:
|
|
56
|
+
return default
|
|
57
|
+
if isinstance(value, bool):
|
|
58
|
+
return value
|
|
59
|
+
raw = str(value).strip().lower()
|
|
60
|
+
if raw in ("1", "true", "yes", "on"):
|
|
61
|
+
return True
|
|
62
|
+
if raw in ("0", "false", "no", "off"):
|
|
63
|
+
return False
|
|
64
|
+
return default
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def normalize_repos(value):
|
|
68
|
+
if value is None:
|
|
69
|
+
return []
|
|
70
|
+
if isinstance(value, str):
|
|
71
|
+
return [v.strip() for v in value.split(",") if v.strip()]
|
|
72
|
+
if isinstance(value, list):
|
|
73
|
+
return [str(v).strip() for v in value if str(v).strip()]
|
|
74
|
+
return []
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def load_config():
|
|
78
|
+
paths = [
|
|
79
|
+
os.path.join(os.getcwd(), ".standuprc"),
|
|
80
|
+
os.path.join(os.path.expanduser("~"), ".standuprc"),
|
|
81
|
+
]
|
|
82
|
+
for path in paths:
|
|
83
|
+
if not os.path.isfile(path):
|
|
84
|
+
continue
|
|
85
|
+
try:
|
|
86
|
+
with open(path, "r", encoding="utf-8") as handle:
|
|
87
|
+
raw = handle.read().strip()
|
|
88
|
+
if not raw:
|
|
89
|
+
return {}
|
|
90
|
+
if raw.lstrip().startswith("{"):
|
|
91
|
+
data = json.loads(raw)
|
|
92
|
+
else:
|
|
93
|
+
data = {}
|
|
94
|
+
for line in raw.splitlines():
|
|
95
|
+
line = line.strip()
|
|
96
|
+
if not line or line.startswith("#") or "=" not in line:
|
|
97
|
+
continue
|
|
98
|
+
key, value = line.split("=", 1)
|
|
99
|
+
data[key.strip()] = value.strip()
|
|
100
|
+
config = {}
|
|
101
|
+
config["format"] = data.get("format")
|
|
102
|
+
config["team"] = data.get("team")
|
|
103
|
+
config["copy"] = parse_bool(data.get("copy"), True)
|
|
104
|
+
config["weekly"] = parse_bool(data.get("weekly"), False)
|
|
105
|
+
if "no_copy" in data:
|
|
106
|
+
config["copy"] = not parse_bool(data.get("no_copy"), False)
|
|
107
|
+
config["repos"] = normalize_repos(data.get("repos"))
|
|
108
|
+
return config
|
|
109
|
+
except Exception:
|
|
110
|
+
return {}
|
|
111
|
+
return {}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def parse_commit_subject(subject):
|
|
115
|
+
subject = subject.strip()
|
|
116
|
+
match = re.match(
|
|
117
|
+
r"^(?P<type>[a-zA-Z]+)(\((?P<scope>[^)]+)\))?(?P<breaking>!)?:\s*(?P<msg>.+)$",
|
|
118
|
+
subject,
|
|
119
|
+
)
|
|
120
|
+
if match:
|
|
121
|
+
ctype = match.group("type").lower()
|
|
122
|
+
scope = match.group("scope")
|
|
123
|
+
msg = match.group("msg").strip()
|
|
124
|
+
else:
|
|
125
|
+
ctype = "other"
|
|
126
|
+
scope = None
|
|
127
|
+
msg = subject
|
|
128
|
+
msg = msg.rstrip(".")
|
|
129
|
+
if msg:
|
|
130
|
+
msg = msg[0].upper() + msg[1:]
|
|
131
|
+
if scope:
|
|
132
|
+
msg = f"{scope}: {msg}"
|
|
133
|
+
return {"type": ctype, "message": msg}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def parse_git_log_with_numstat(raw):
|
|
137
|
+
commits = []
|
|
138
|
+
current = None
|
|
139
|
+
for line in raw.splitlines():
|
|
140
|
+
if line.startswith("__COMMIT__\x1f"):
|
|
141
|
+
if current is not None:
|
|
142
|
+
commits.append(current)
|
|
143
|
+
subject = line.split("\x1f", 1)[1].strip()
|
|
144
|
+
parsed = parse_commit_subject(subject)
|
|
145
|
+
current = {
|
|
146
|
+
"type": parsed["type"],
|
|
147
|
+
"message": parsed["message"],
|
|
148
|
+
"files_changed": 0,
|
|
149
|
+
}
|
|
150
|
+
continue
|
|
151
|
+
|
|
152
|
+
if not line.strip():
|
|
153
|
+
continue
|
|
154
|
+
|
|
155
|
+
if current is None:
|
|
156
|
+
continue
|
|
157
|
+
|
|
158
|
+
parts = line.split("\t")
|
|
159
|
+
if len(parts) >= 3:
|
|
160
|
+
current["files_changed"] += 1
|
|
161
|
+
|
|
162
|
+
if current is not None:
|
|
163
|
+
commits.append(current)
|
|
164
|
+
|
|
165
|
+
return commits
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def get_repo_summary(repo_path, since):
|
|
169
|
+
abs_path = os.path.abspath(repo_path)
|
|
170
|
+
repo_name = os.path.basename(abs_path.rstrip("\\/")) or abs_path
|
|
171
|
+
try:
|
|
172
|
+
result = subprocess.run(
|
|
173
|
+
[
|
|
174
|
+
"git",
|
|
175
|
+
"-C",
|
|
176
|
+
abs_path,
|
|
177
|
+
"log",
|
|
178
|
+
f"--since={since}",
|
|
179
|
+
"--no-merges",
|
|
180
|
+
"--pretty=format:__COMMIT__%x1f%s",
|
|
181
|
+
"--numstat",
|
|
182
|
+
],
|
|
183
|
+
capture_output=True,
|
|
184
|
+
text=True,
|
|
185
|
+
)
|
|
186
|
+
if result.returncode != 0:
|
|
187
|
+
stderr = (result.stderr or "") + "\n" + (result.stdout or "")
|
|
188
|
+
if "detected dubious ownership in repository" in stderr.lower():
|
|
189
|
+
return {
|
|
190
|
+
"error": "dubious_ownership",
|
|
191
|
+
"path": abs_path,
|
|
192
|
+
"fix": f'git config --global --add safe.directory "{abs_path}"',
|
|
193
|
+
}
|
|
194
|
+
return None
|
|
195
|
+
commits = parse_git_log_with_numstat(result.stdout.strip())
|
|
196
|
+
return {
|
|
197
|
+
"name": repo_name,
|
|
198
|
+
"path": abs_path,
|
|
199
|
+
"commits": commits,
|
|
200
|
+
"commit_count": len(commits),
|
|
201
|
+
"files_changed": sum(c["files_changed"] for c in commits),
|
|
202
|
+
}
|
|
203
|
+
except FileNotFoundError:
|
|
204
|
+
return None
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def summarize_commits(commits, empty_message):
|
|
208
|
+
if not commits:
|
|
209
|
+
return [empty_message]
|
|
210
|
+
|
|
211
|
+
seen = set()
|
|
212
|
+
grouped = {k: [] for k in TYPE_ORDER}
|
|
213
|
+
|
|
214
|
+
for commit in commits:
|
|
215
|
+
message = commit["message"]
|
|
216
|
+
key = message.lower()
|
|
217
|
+
if key in seen:
|
|
218
|
+
continue
|
|
219
|
+
seen.add(key)
|
|
220
|
+
ctype = commit["type"] if commit["type"] in grouped else "other"
|
|
221
|
+
grouped[ctype].append(message)
|
|
222
|
+
|
|
223
|
+
lines = []
|
|
224
|
+
for ctype in TYPE_ORDER:
|
|
225
|
+
items = grouped[ctype]
|
|
226
|
+
if not items:
|
|
227
|
+
continue
|
|
228
|
+
lines.append(f"{TYPE_LABELS.get(ctype, 'Other')}:")
|
|
229
|
+
for item in items:
|
|
230
|
+
lines.append(f"- {item}")
|
|
231
|
+
return lines
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def format_output(repo_summaries, today, blockers, fmt, mode, team=None):
|
|
235
|
+
repo_lines = []
|
|
236
|
+
if not repo_summaries:
|
|
237
|
+
repo_lines.append("No repositories scanned")
|
|
238
|
+
for repo in repo_summaries:
|
|
239
|
+
repo_lines.append(
|
|
240
|
+
f"{repo['name']} ({repo['commit_count']} commits, {repo['files_changed']} files changed):"
|
|
241
|
+
)
|
|
242
|
+
repo_lines.extend(summarize_commits(repo["commits"], mode["empty_message"]))
|
|
243
|
+
repo_lines.append("")
|
|
244
|
+
if repo_lines and repo_lines[-1] == "":
|
|
245
|
+
repo_lines.pop()
|
|
246
|
+
|
|
247
|
+
if fmt == "slack":
|
|
248
|
+
lines = []
|
|
249
|
+
if team:
|
|
250
|
+
lines.append(f"*Team:* {team}")
|
|
251
|
+
lines.append(f"*{mode['history_label']}:*")
|
|
252
|
+
for line in repo_lines:
|
|
253
|
+
if not line:
|
|
254
|
+
lines.append("")
|
|
255
|
+
elif line.endswith(":"):
|
|
256
|
+
lines.append(f"*{line}*")
|
|
257
|
+
else:
|
|
258
|
+
lines.append(f"- {line[2:]}" if line.startswith("- ") else f"- {line}")
|
|
259
|
+
lines.append(f"*{mode['next_label']}:* {today}")
|
|
260
|
+
lines.append(f"*Blockers:* {blockers or 'None'}")
|
|
261
|
+
return "\n".join(lines)
|
|
262
|
+
|
|
263
|
+
if fmt == "markdown":
|
|
264
|
+
lines = [f"### {mode['title']}", ""]
|
|
265
|
+
if team:
|
|
266
|
+
lines.extend(["**Team:**", team, ""])
|
|
267
|
+
lines.append(f"**{mode['history_label']}:**")
|
|
268
|
+
for line in repo_lines:
|
|
269
|
+
lines.append(line)
|
|
270
|
+
lines.extend(
|
|
271
|
+
["", f"**{mode['next_label']}:**", today, "", "**Blockers:**", blockers or "None"]
|
|
272
|
+
)
|
|
273
|
+
return "\n".join(lines)
|
|
274
|
+
|
|
275
|
+
lines = []
|
|
276
|
+
if team:
|
|
277
|
+
lines.append(f"Team: {team}")
|
|
278
|
+
lines.append(f"{mode['history_label']}:")
|
|
279
|
+
lines.extend(repo_lines)
|
|
280
|
+
lines.append(f"{mode['next_label']}: {today}")
|
|
281
|
+
lines.append(f"Blockers: {blockers or 'None'}")
|
|
282
|
+
return "\n".join(lines)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def copy_to_clipboard(text):
|
|
286
|
+
if not text:
|
|
287
|
+
return False
|
|
288
|
+
try:
|
|
289
|
+
if sys.platform.startswith("win"):
|
|
290
|
+
subprocess.run(["clip"], input=text, text=True, check=True)
|
|
291
|
+
return True
|
|
292
|
+
if sys.platform == "darwin" and shutil.which("pbcopy"):
|
|
293
|
+
subprocess.run(["pbcopy"], input=text, text=True, check=True)
|
|
294
|
+
return True
|
|
295
|
+
if shutil.which("xclip"):
|
|
296
|
+
subprocess.run(
|
|
297
|
+
["xclip", "-selection", "clipboard"],
|
|
298
|
+
input=text,
|
|
299
|
+
text=True,
|
|
300
|
+
check=True,
|
|
301
|
+
)
|
|
302
|
+
return True
|
|
303
|
+
if shutil.which("xsel"):
|
|
304
|
+
subprocess.run(
|
|
305
|
+
["xsel", "--clipboard", "--input"], input=text, text=True, check=True
|
|
306
|
+
)
|
|
307
|
+
return True
|
|
308
|
+
except Exception:
|
|
309
|
+
return False
|
|
310
|
+
return False
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def collect_repo_paths(config, cli_repos):
|
|
314
|
+
source = cli_repos if cli_repos else config.get("repos") or [os.getcwd()]
|
|
315
|
+
seen = set()
|
|
316
|
+
ordered = []
|
|
317
|
+
for repo in source:
|
|
318
|
+
abs_path = os.path.abspath(repo)
|
|
319
|
+
key = abs_path.lower()
|
|
320
|
+
if key in seen:
|
|
321
|
+
continue
|
|
322
|
+
seen.add(key)
|
|
323
|
+
ordered.append(abs_path)
|
|
324
|
+
return ordered
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def main():
|
|
328
|
+
config = load_config()
|
|
329
|
+
|
|
330
|
+
parser = argparse.ArgumentParser(
|
|
331
|
+
prog="standup", description="Generate your daily standup from git commits"
|
|
332
|
+
)
|
|
333
|
+
parser.add_argument(
|
|
334
|
+
"--format",
|
|
335
|
+
"-f",
|
|
336
|
+
choices=["plain", "slack", "markdown"],
|
|
337
|
+
default=None,
|
|
338
|
+
help="Output format (default: plain)",
|
|
339
|
+
)
|
|
340
|
+
parser.add_argument("--team", "-t", default=None, help="Team name for standup header")
|
|
341
|
+
parser.add_argument(
|
|
342
|
+
"--repo",
|
|
343
|
+
action="append",
|
|
344
|
+
default=[],
|
|
345
|
+
help="Repository path to scan (repeatable). Defaults to cwd or .standuprc repos.",
|
|
346
|
+
)
|
|
347
|
+
parser.add_argument(
|
|
348
|
+
"--weekly",
|
|
349
|
+
action="store_true",
|
|
350
|
+
help="Scan the last 7 days and format a weekly summary",
|
|
351
|
+
)
|
|
352
|
+
parser.add_argument("--no-copy", action="store_true", help="Disable clipboard auto-copy")
|
|
353
|
+
args = parser.parse_args()
|
|
354
|
+
|
|
355
|
+
fmt = args.format or config.get("format") or "plain"
|
|
356
|
+
team = args.team or config.get("team")
|
|
357
|
+
copy_enabled = (not args.no_copy) and config.get("copy", True)
|
|
358
|
+
repo_paths = collect_repo_paths(config, args.repo)
|
|
359
|
+
weekly = args.weekly or bool(config.get("weekly"))
|
|
360
|
+
mode = (
|
|
361
|
+
{
|
|
362
|
+
"title": "Weekly Standup",
|
|
363
|
+
"since": "7 days ago",
|
|
364
|
+
"scan_label": "last 7 days",
|
|
365
|
+
"history_label": "Last week",
|
|
366
|
+
"next_label": "Next",
|
|
367
|
+
"prompt": " What are you working on next?\n ",
|
|
368
|
+
"empty_message": "No commits in the last 7 days",
|
|
369
|
+
}
|
|
370
|
+
if weekly
|
|
371
|
+
else {
|
|
372
|
+
"title": "Daily Standup",
|
|
373
|
+
"since": "24 hours ago",
|
|
374
|
+
"scan_label": "last 24hrs",
|
|
375
|
+
"history_label": "Yesterday",
|
|
376
|
+
"next_label": "Today",
|
|
377
|
+
"prompt": " What are you working on today?\n ",
|
|
378
|
+
"empty_message": "No commits in the last 24 hours",
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
print()
|
|
383
|
+
print(paint(BOLD + CYAN, " standup-cli"))
|
|
384
|
+
print(paint(GRAY, " Generate your daily standup in seconds\n"))
|
|
385
|
+
|
|
386
|
+
print(paint(DIM, f" Scanning git commits from {mode['scan_label']}..."))
|
|
387
|
+
repo_summaries = []
|
|
388
|
+
skipped = []
|
|
389
|
+
dubious = []
|
|
390
|
+
for repo_path in repo_paths:
|
|
391
|
+
summary = get_repo_summary(repo_path, mode["since"])
|
|
392
|
+
if summary is None:
|
|
393
|
+
skipped.append(repo_path)
|
|
394
|
+
continue
|
|
395
|
+
if "error" in summary:
|
|
396
|
+
if summary["error"] == "dubious_ownership":
|
|
397
|
+
dubious.append(summary)
|
|
398
|
+
else:
|
|
399
|
+
skipped.append(repo_path)
|
|
400
|
+
continue
|
|
401
|
+
repo_summaries.append(summary)
|
|
402
|
+
print(
|
|
403
|
+
paint(
|
|
404
|
+
GREEN,
|
|
405
|
+
f" {summary['name']}: {summary['commit_count']} commit(s), "
|
|
406
|
+
f"{summary['files_changed']} file(s) changed",
|
|
407
|
+
)
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
for issue in dubious:
|
|
411
|
+
print(
|
|
412
|
+
paint(
|
|
413
|
+
YELLOW,
|
|
414
|
+
f" Warning: Git safe.directory blocked repo {issue['path']}",
|
|
415
|
+
)
|
|
416
|
+
)
|
|
417
|
+
print(paint(YELLOW, f" Run: {issue['fix']}"))
|
|
418
|
+
if skipped:
|
|
419
|
+
for repo_path in skipped:
|
|
420
|
+
print(paint(YELLOW, f" Warning: skipped non-git repo {repo_path}"))
|
|
421
|
+
print()
|
|
422
|
+
|
|
423
|
+
today = input(paint(BOLD, mode["prompt"]) + "> ").strip()
|
|
424
|
+
print()
|
|
425
|
+
blockers = input(paint(BOLD, ' Any blockers? (press Enter for "None")\n ') + "> ").strip()
|
|
426
|
+
print()
|
|
427
|
+
|
|
428
|
+
output = format_output(
|
|
429
|
+
repo_summaries,
|
|
430
|
+
today or "(not specified)",
|
|
431
|
+
blockers,
|
|
432
|
+
fmt,
|
|
433
|
+
mode,
|
|
434
|
+
team=team,
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
divider = paint(GRAY, " " + "-" * 50)
|
|
438
|
+
fmt_label = paint(MAGENTA, f"[{fmt}]")
|
|
439
|
+
|
|
440
|
+
print(divider)
|
|
441
|
+
print(paint(BOLD + GREEN, f" Your Standup {fmt_label}\n"))
|
|
442
|
+
for line in output.split("\n"):
|
|
443
|
+
print(" " + line)
|
|
444
|
+
print()
|
|
445
|
+
print(divider)
|
|
446
|
+
print()
|
|
447
|
+
print(paint(GRAY, " Tip: use --format slack | markdown | plain"))
|
|
448
|
+
print()
|
|
449
|
+
|
|
450
|
+
if copy_enabled:
|
|
451
|
+
if copy_to_clipboard(output):
|
|
452
|
+
print(paint(GREEN, " Copied standup to clipboard"))
|
|
453
|
+
else:
|
|
454
|
+
print(paint(YELLOW, " Warning: clipboard copy unavailable"))
|
|
455
|
+
print()
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
if __name__ == "__main__":
|
|
459
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: standup-cli-tool
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: ⚡ Generate your daily standup from git commits — right in your terminal
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/muhtalhakhan/standup-cli
|
|
@@ -21,10 +21,12 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
|
|
22
22
|
Never manually write a standup again. `standup-cli` scans your git commits from the last 24 hours, asks what you're working on today and if you have blockers, then formats a clean standup message ready to paste anywhere.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
```bash
|
|
25
27
|
$ standup
|
|
26
28
|
|
|
27
|
-
⚡ standup-cli
|
|
29
|
+
⚡ standup-cli-tool
|
|
28
30
|
Generate your daily standup in seconds
|
|
29
31
|
|
|
30
32
|
🔍 Scanning git commits from last 24hrs...
|
|
@@ -53,20 +55,22 @@ $ standup
|
|
|
53
55
|
|
|
54
56
|
## Install
|
|
55
57
|
|
|
56
|
-
**via npm
|
|
58
|
+
**via npm**:
|
|
59
|
+
|
|
57
60
|
```bash
|
|
58
|
-
npm install -g standup-cli
|
|
61
|
+
npm install -g standup-cli-tool
|
|
59
62
|
```
|
|
60
63
|
|
|
61
|
-
**via pip
|
|
64
|
+
**via pip**:
|
|
65
|
+
|
|
62
66
|
```bash
|
|
63
|
-
pip install standup-cli
|
|
67
|
+
pip install standup-cli-tool
|
|
64
68
|
```
|
|
65
69
|
|
|
66
70
|
## Usage
|
|
67
71
|
|
|
68
72
|
```bash
|
|
69
|
-
# Default (plain
|
|
73
|
+
# Default (plain output, current repo, clipboard on)
|
|
70
74
|
standup
|
|
71
75
|
|
|
72
76
|
# Slack-ready output
|
|
@@ -74,14 +78,71 @@ standup --format slack
|
|
|
74
78
|
|
|
75
79
|
# Markdown output
|
|
76
80
|
standup --format markdown
|
|
81
|
+
|
|
82
|
+
# Team label
|
|
83
|
+
standup --team "Platform"
|
|
84
|
+
|
|
85
|
+
# Disable auto-copy
|
|
86
|
+
standup --no-copy
|
|
87
|
+
|
|
88
|
+
# Scan multiple repositories
|
|
89
|
+
standup --repo . --repo ../another-repo
|
|
90
|
+
|
|
91
|
+
# Weekly summary mode
|
|
92
|
+
standup --weekly
|
|
77
93
|
```
|
|
78
94
|
|
|
79
|
-
##
|
|
95
|
+
## What It Includes
|
|
96
|
+
|
|
97
|
+
- Conventional Commit parsing (`feat`, `fix`, `docs`, etc.) into grouped sections
|
|
98
|
+
- Files changed count per repository (last 24h or weekly window)
|
|
99
|
+
- Output grouped by repository
|
|
100
|
+
- Clipboard auto-copy by default
|
|
101
|
+
- `.standuprc` support for defaults
|
|
102
|
+
- Weekly summaries with `--weekly`
|
|
103
|
+
|
|
104
|
+
## .standuprc
|
|
80
105
|
|
|
81
|
-
|
|
106
|
+
Place `.standuprc` in the current project or your home directory.
|
|
107
|
+
|
|
108
|
+
JSON format:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"format": "slack",
|
|
113
|
+
"team": "Platform",
|
|
114
|
+
"copy": true,
|
|
115
|
+
"weekly": false,
|
|
116
|
+
"repos": [".", "../service-api"]
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Key-value format is also supported:
|
|
121
|
+
|
|
122
|
+
```ini
|
|
123
|
+
format=plain
|
|
124
|
+
team=Platform
|
|
125
|
+
copy=true
|
|
126
|
+
weekly=false
|
|
127
|
+
repos=.,../service-api
|
|
82
128
|
```
|
|
83
|
-
|
|
84
|
-
|
|
129
|
+
|
|
130
|
+
## Output Example (plain)
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
Team: Platform
|
|
134
|
+
Yesterday:
|
|
135
|
+
standup-cli (3 commits, 9 files changed):
|
|
136
|
+
Features:
|
|
137
|
+
- Add repo grouping support
|
|
138
|
+
Fixes:
|
|
139
|
+
- Handle empty commit logs
|
|
140
|
+
|
|
141
|
+
service-api (2 commits, 4 files changed):
|
|
142
|
+
Docs:
|
|
143
|
+
- Update API usage notes
|
|
144
|
+
|
|
145
|
+
Today: Finish release checks
|
|
85
146
|
Blockers: None
|
|
86
147
|
```
|
|
87
148
|
|
|
@@ -112,14 +173,16 @@ None
|
|
|
112
173
|
2. Prompts you for today's focus and any blockers
|
|
113
174
|
3. Formats and prints your standup
|
|
114
175
|
|
|
176
|
+
Use `--weekly` to scan commits from the last 7 days and label the summary as `Last week` / `Next`.
|
|
177
|
+
|
|
115
178
|
> **Tip:** Run it from your project root for best results. Works with any git repo.
|
|
116
179
|
|
|
117
180
|
## Roadmap (v1 ideas)
|
|
118
181
|
|
|
119
|
-
- [
|
|
120
|
-
- [
|
|
121
|
-
- [
|
|
122
|
-
- [
|
|
182
|
+
- [x] Copy to clipboard automatically
|
|
183
|
+
- [x] Support multiple repos
|
|
184
|
+
- [x] `.standuprc` config file for team name, format preference
|
|
185
|
+
- [x] Weekly summary mode
|
|
123
186
|
|
|
124
187
|
## License
|
|
125
188
|
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
import subprocess
|
|
4
|
-
import sys
|
|
5
|
-
import argparse
|
|
6
|
-
|
|
7
|
-
# ANSI colors
|
|
8
|
-
RESET = "\x1b[0m"
|
|
9
|
-
BOLD = "\x1b[1m"
|
|
10
|
-
DIM = "\x1b[2m"
|
|
11
|
-
CYAN = "\x1b[36m"
|
|
12
|
-
GREEN = "\x1b[32m"
|
|
13
|
-
YELLOW = "\x1b[33m"
|
|
14
|
-
MAGENTA= "\x1b[35m"
|
|
15
|
-
GRAY = "\x1b[90m"
|
|
16
|
-
|
|
17
|
-
def paint(color, text):
|
|
18
|
-
return f"{color}{text}{RESET}"
|
|
19
|
-
|
|
20
|
-
def get_git_commits():
|
|
21
|
-
try:
|
|
22
|
-
result = subprocess.run(
|
|
23
|
-
["git", "log", '--since=24 hours ago', '--pretty=format:%s', '--no-merges'],
|
|
24
|
-
capture_output=True, text=True
|
|
25
|
-
)
|
|
26
|
-
if result.returncode != 0:
|
|
27
|
-
return None
|
|
28
|
-
lines = [l.strip() for l in result.stdout.strip().split('\n') if l.strip()]
|
|
29
|
-
return lines
|
|
30
|
-
except FileNotFoundError:
|
|
31
|
-
return None
|
|
32
|
-
|
|
33
|
-
def format_output(commits, today, blockers, fmt):
|
|
34
|
-
yesterday = ', '.join(
|
|
35
|
-
c[0].upper() + c[1:] for c in commits
|
|
36
|
-
) if commits else 'No commits in the last 24 hours'
|
|
37
|
-
|
|
38
|
-
if fmt == 'slack':
|
|
39
|
-
return '\n'.join([
|
|
40
|
-
f"*📋 Yesterday:* {yesterday}",
|
|
41
|
-
f"*🚀 Today:* {today}",
|
|
42
|
-
f"*🚧 Blockers:* {blockers or 'None'}",
|
|
43
|
-
])
|
|
44
|
-
elif fmt == 'markdown':
|
|
45
|
-
return '\n'.join([
|
|
46
|
-
"### Daily Standup",
|
|
47
|
-
"",
|
|
48
|
-
"**Yesterday:**",
|
|
49
|
-
yesterday,
|
|
50
|
-
"",
|
|
51
|
-
"**Today:**",
|
|
52
|
-
today,
|
|
53
|
-
"",
|
|
54
|
-
"**Blockers:**",
|
|
55
|
-
blockers or 'None',
|
|
56
|
-
])
|
|
57
|
-
else: # plain
|
|
58
|
-
return '\n'.join([
|
|
59
|
-
f"Yesterday: {yesterday}",
|
|
60
|
-
f"Today: {today}",
|
|
61
|
-
f"Blockers: {blockers or 'None'}",
|
|
62
|
-
])
|
|
63
|
-
|
|
64
|
-
def main():
|
|
65
|
-
parser = argparse.ArgumentParser(
|
|
66
|
-
prog='standup',
|
|
67
|
-
description='⚡ Generate your daily standup from git commits'
|
|
68
|
-
)
|
|
69
|
-
parser.add_argument(
|
|
70
|
-
'--format', '-f',
|
|
71
|
-
choices=['plain', 'slack', 'markdown'],
|
|
72
|
-
default='plain',
|
|
73
|
-
help='Output format (default: plain)'
|
|
74
|
-
)
|
|
75
|
-
args = parser.parse_args()
|
|
76
|
-
fmt = args.format
|
|
77
|
-
|
|
78
|
-
print()
|
|
79
|
-
print(paint(BOLD + CYAN, ' ⚡ standup-cli'))
|
|
80
|
-
print(paint(GRAY, ' Generate your daily standup in seconds\n'))
|
|
81
|
-
|
|
82
|
-
print(paint(DIM, ' 🔍 Scanning git commits from last 24hrs...'))
|
|
83
|
-
commits = get_git_commits()
|
|
84
|
-
|
|
85
|
-
if commits is None:
|
|
86
|
-
print(paint(YELLOW, ' ⚠️ Not a git repo — skipping commit scan.\n'))
|
|
87
|
-
commits = []
|
|
88
|
-
elif len(commits) == 0:
|
|
89
|
-
print(paint(YELLOW, ' ⚠️ No commits found in the last 24hrs.\n'))
|
|
90
|
-
else:
|
|
91
|
-
print(paint(GREEN, f' ✅ Found {len(commits)} commit(s):\n'))
|
|
92
|
-
for msg in commits:
|
|
93
|
-
print(paint(GRAY, f' • {msg}'))
|
|
94
|
-
print()
|
|
95
|
-
|
|
96
|
-
today = input(paint(BOLD, ' 🚀 What are you working on today?\n ') + '> ').strip()
|
|
97
|
-
print()
|
|
98
|
-
blockers = input(paint(BOLD, ' 🚧 Any blockers? (press Enter for "None")\n ') + '> ').strip()
|
|
99
|
-
print()
|
|
100
|
-
|
|
101
|
-
output = format_output(commits, today or '(not specified)', blockers, fmt)
|
|
102
|
-
|
|
103
|
-
divider = paint(GRAY, ' ' + '─' * 50)
|
|
104
|
-
fmt_label = paint(MAGENTA, f'[{fmt}]')
|
|
105
|
-
|
|
106
|
-
print(divider)
|
|
107
|
-
print(paint(BOLD + GREEN, f' ✅ Your Standup {fmt_label}\n'))
|
|
108
|
-
for line in output.split('\n'):
|
|
109
|
-
print(' ' + line)
|
|
110
|
-
print()
|
|
111
|
-
print(divider)
|
|
112
|
-
print()
|
|
113
|
-
print(paint(GRAY, ' 💡 Tip: use --format slack | markdown | plain'))
|
|
114
|
-
print()
|
|
115
|
-
|
|
116
|
-
if __name__ == '__main__':
|
|
117
|
-
main()
|
|
File without changes
|
|
File without changes
|
{standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/standup_cli_tool.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{standup_cli_tool-0.1.0 → standup_cli_tool-0.3.0}/standup_cli_tool.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|