Skip to content

Commit e9c1723

Browse files
r-pedrazaclaudefinxo
authored
feat: Add foundation for Jira issue creation workflow (#166)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: finxo <alejandro.lopezr@masmovil.com>
1 parent 7ecea9d commit e9c1723

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+3581
-292
lines changed

.codex

Whitespace-only changes.

plugins/titan-plugin-git/titan_plugin_git/steps/create_branch_step.py

Lines changed: 70 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
Create a new Git branch.
33
"""
44

5+
import traceback
6+
57
from titan_cli.engine import WorkflowContext, WorkflowResult, Success, Error
6-
from titan_plugin_git.exceptions import GitError
8+
from titan_cli.core.result import ClientSuccess, ClientError
79
from ..operations import (
810
check_branch_exists,
911
determine_safe_checkout_target,
@@ -54,46 +56,63 @@ def create_branch_step(ctx: WorkflowContext) -> WorkflowResult:
5456
ctx.textual.dim_text(f"From: {start_point}")
5557

5658
# Check if branch exists using operations
57-
all_branches = ctx.git.get_branches()
58-
branch_names = [b.name for b in all_branches]
59-
branch_exists = check_branch_exists(new_branch, branch_names)
59+
branches_result = ctx.git.get_branches()
60+
61+
match branches_result:
62+
case ClientSuccess(data=all_branches):
63+
branch_names = [b.name for b in all_branches]
64+
branch_exists = check_branch_exists(new_branch, branch_names)
65+
case ClientError(error_message=err):
66+
ctx.textual.error_text(f"Failed to get branches: {err}")
67+
ctx.textual.end_step("error")
68+
return Error(f"Failed to get branches: {err}")
6069

6170
# Delete if exists and requested using operations
6271
if should_delete_before_create(branch_exists, delete_if_exists):
6372
ctx.textual.text("")
6473
ctx.textual.warning_text(f"Branch {new_branch} exists, deleting...")
6574

6675
# If we're on the branch, checkout another one first using operations
67-
current_branch = ctx.git.get_current_branch()
68-
safe_target = determine_safe_checkout_target(
69-
current_branch=current_branch,
70-
branch_to_delete=new_branch,
71-
main_branch=ctx.git.main_branch,
72-
all_branches=branch_names
73-
)
74-
75-
if safe_target:
76-
try:
77-
ctx.git.checkout(safe_target)
78-
ctx.textual.dim_text(f"Switched to {safe_target}")
79-
except GitError as e:
80-
ctx.textual.error_text(f"Failed to checkout {safe_target}: {str(e)}")
76+
current_branch_result = ctx.git.get_current_branch()
77+
78+
match current_branch_result:
79+
case ClientSuccess(data=current_branch):
80+
safe_target = determine_safe_checkout_target(
81+
current_branch=current_branch,
82+
branch_to_delete=new_branch,
83+
main_branch=ctx.git.main_branch,
84+
all_branches=branch_names
85+
)
86+
87+
if safe_target:
88+
checkout_result = ctx.git.checkout(safe_target)
89+
match checkout_result:
90+
case ClientSuccess():
91+
ctx.textual.dim_text(f"Switched to {safe_target}")
92+
case ClientError(error_message=err):
93+
ctx.textual.error_text(f"Failed to checkout {safe_target}: {err}")
94+
ctx.textual.end_step("error")
95+
return Error(f"Cannot checkout {safe_target}: {err}")
96+
elif current_branch == new_branch:
97+
# Cannot delete current branch and no safe target available
98+
ctx.textual.error_text(f"Cannot delete current branch {new_branch}")
99+
ctx.textual.end_step("error")
100+
return Error("Cannot delete current branch")
101+
102+
# Delete the branch
103+
delete_result = ctx.git.safe_delete_branch(new_branch, force=True)
104+
match delete_result:
105+
case ClientSuccess():
106+
ctx.textual.success_text(f"✓ Deleted existing branch {new_branch}")
107+
case ClientError(error_message=err):
108+
ctx.textual.error_text(f"Failed to delete {new_branch}: {err}")
109+
ctx.textual.end_step("error")
110+
return Error(f"Failed to delete branch: {err}")
111+
112+
case ClientError(error_message=err):
113+
ctx.textual.error_text(f"Failed to get current branch: {err}")
81114
ctx.textual.end_step("error")
82-
return Error(f"Cannot checkout {safe_target}: {str(e)}")
83-
elif current_branch == new_branch:
84-
# Cannot delete current branch and no safe target available
85-
ctx.textual.error_text(f"Cannot delete current branch {new_branch}")
86-
ctx.textual.end_step("error")
87-
return Error("Cannot delete current branch")
88-
89-
# Delete the branch
90-
try:
91-
ctx.git.safe_delete_branch(new_branch, force=True)
92-
ctx.textual.success_text(f"✓ Deleted existing branch {new_branch}")
93-
except GitError as e:
94-
ctx.textual.error_text(f"Failed to delete {new_branch}: {str(e)}")
95-
ctx.textual.end_step("error")
96-
return Error(f"Failed to delete branch: {str(e)}")
115+
return Error(f"Failed to get current branch: {err}")
97116

98117
elif branch_exists:
99118
ctx.textual.error_text(f"Branch {new_branch} already exists")
@@ -103,21 +122,23 @@ def create_branch_step(ctx: WorkflowContext) -> WorkflowResult:
103122

104123
# Create the branch
105124
ctx.textual.text("")
106-
try:
107-
ctx.git.create_branch(new_branch, start_point=start_point)
108-
ctx.textual.success_text(f"✓ Created branch {new_branch}")
109-
except GitError as e:
110-
ctx.textual.error_text(f"Failed to create {new_branch}: {str(e)}")
111-
ctx.textual.end_step("error")
112-
return Error(f"Failed to create branch: {str(e)}")
125+
create_result = ctx.git.create_branch(new_branch, start_point=start_point)
126+
match create_result:
127+
case ClientSuccess():
128+
ctx.textual.success_text(f"✓ Created branch {new_branch}")
129+
case ClientError(error_message=err):
130+
ctx.textual.error_text(f"Failed to create {new_branch}: {err}")
131+
ctx.textual.end_step("error")
132+
return Error(f"Failed to create branch: {err}")
113133

114134
# Checkout if requested
115135
if checkout:
116-
try:
117-
ctx.git.checkout(new_branch)
118-
ctx.textual.success_text(f"✓ Checked out {new_branch}")
119-
except GitError as e:
120-
ctx.textual.warning_text(f"Branch created but failed to checkout: {str(e)}")
136+
checkout_result = ctx.git.checkout(new_branch)
137+
match checkout_result:
138+
case ClientSuccess():
139+
ctx.textual.success_text(f"✓ Checked out {new_branch}")
140+
case ClientError(error_message=err):
141+
ctx.textual.warning_text(f"Branch created but failed to checkout: {err}")
121142

122143
ctx.textual.text("")
123144
ctx.textual.end_step("success")
@@ -131,9 +152,13 @@ def create_branch_step(ctx: WorkflowContext) -> WorkflowResult:
131152
)
132153

133154
except Exception as e:
155+
tb = traceback.format_exc()
134156
ctx.textual.text("")
135157
ctx.textual.error_text(f"Failed to create branch: {str(e)}")
136158
ctx.textual.text("")
159+
ctx.textual.dim_text("Full traceback:")
160+
for line in tb.split('\n'):
161+
ctx.textual.dim_text(line)
137162
ctx.textual.end_step("error")
138163
return Error(f"Failed to create branch: {str(e)}")
139164

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Custom Templates for Issues
2+
3+
The **Create JIRA Issue** workflow allows using custom templates to generate issue descriptions.
4+
5+
## Template Locations
6+
7+
### Project Template (Recommended)
8+
9+
Create your custom template at:
10+
11+
```
12+
.titan/templates/issue_templates/default.md.j2
13+
```
14+
15+
This template will be automatically used when you run the workflow.
16+
17+
### Plugin Default Template
18+
19+
If no project template exists, the plugin's default template is used:
20+
21+
```
22+
plugins/titan-plugin-jira/titan_plugin_jira/config/templates/generic_issue.md.j2
23+
```
24+
25+
## Template Format
26+
27+
Templates use **Jinja2** and receive the following variables from the AI:
28+
29+
| Variable | Type | Description |
30+
|----------|------|-------------|
31+
| `description` | string | Extended task description |
32+
| `objective` | string | Issue objective |
33+
| `acceptance_criteria` | string | Acceptance criteria (checkboxes) |
34+
| `technical_notes` | string or None | Technical notes (optional) |
35+
| `dependencies` | string or None | Dependencies (optional) |
36+
37+
## Custom Template Example
38+
39+
```jinja2
40+
## 📋 Description
41+
42+
{{ description }}
43+
44+
## 🎯 Objective
45+
46+
{{ objective }}
47+
48+
## ✅ Acceptance Criteria
49+
50+
{{ acceptance_criteria }}
51+
52+
{% if technical_notes %}
53+
---
54+
55+
### 🔧 Technical Notes
56+
57+
{{ technical_notes }}
58+
{% endif %}
59+
60+
{% if dependencies %}
61+
---
62+
63+
### 🔗 Dependencies
64+
65+
{{ dependencies }}
66+
{% endif %}
67+
68+
---
69+
70+
*Created with Titan CLI*
71+
```
72+
73+
## Creating Your Custom Template
74+
75+
1. **Create the directory** (if it doesn't exist):
76+
77+
```bash
78+
mkdir -p .titan/templates/issue_templates
79+
```
80+
81+
2. **Create the template**:
82+
83+
```bash
84+
cat > .titan/templates/issue_templates/default.md.j2 << 'EOF'
85+
## Description
86+
87+
{{ description }}
88+
89+
## Objective
90+
91+
{{ objective }}
92+
93+
## Acceptance Criteria
94+
95+
{{ acceptance_criteria }}
96+
97+
{% if technical_notes %}
98+
### Technical Notes
99+
100+
{{ technical_notes }}
101+
{% endif %}
102+
EOF
103+
```
104+
105+
3. **Run the workflow**:
106+
107+
The workflow will automatically detect and use your template.
108+
109+
## Tips
110+
111+
- **Use Markdown**: Templates support full Markdown
112+
- **Optional sections**: Use `{% if variable %}` for conditional content
113+
- **Clean format**: The AI generates the content, your template structures it
114+
- **Emojis**: Add emojis for better readability (optional)
115+
- **Commits**: Version your template with Git to share it with the team
116+
117+
## Advanced Example: Template with QA Checklist
118+
119+
```jinja2
120+
## 📋 Description
121+
122+
{{ description }}
123+
124+
## 🎯 Objective
125+
126+
{{ objective }}
127+
128+
## ✅ Acceptance Criteria
129+
130+
{{ acceptance_criteria }}
131+
132+
{% if technical_notes %}
133+
---
134+
135+
### 🔧 Implementation
136+
137+
{{ technical_notes }}
138+
{% endif %}
139+
140+
{% if dependencies %}
141+
---
142+
143+
### 🔗 Dependencies
144+
145+
{{ dependencies }}
146+
{% endif %}
147+
148+
---
149+
150+
## 🧪 QA Checklist
151+
152+
- [ ] Unit tests implemented
153+
- [ ] Integration tests passing
154+
- [ ] Documentation updated
155+
- [ ] Code review approved
156+
- [ ] Works in staging
157+
158+
---
159+
160+
*Automatically generated by Titan CLI*
161+
```
162+
163+
## Hooks and Extensibility
164+
165+
This workflow is extensible via hooks in Titan. You can add custom steps before or after any workflow step.
166+
167+
Refer to Titan documentation for more information about hooks.

0 commit comments

Comments
 (0)