feat: implement optimization #1 - unpushed tags detection
Added unpushed tag detection to release status command to prevent
forgotten tag pushes (the critical issue from v0.10.0 release).
**Implementation**:
- Added `get_unpushed_tags()` method to GitManager
- Compares local tags with remote tags (git ls-remote)
- Handles annotated tags correctly (strips ^{} suffix)
- Added unpushed_tags to repository status dict
**CLI Enhancement**:
- `release status` now shows unpushed tags with warning emoji
- Lists all unpushed tags
- Provides helpful command to push them
**Output Example**:
```
⚠️ Unpushed Tags: 2 tag(s) not pushed to origin
- v0.9.0
- v0.10.0
💡 Push tags with: git push origin v0.9.0 v0.10.0
Or push all tags: git push --tags
```
**Testing**: Verified with current repo (no unpushed tags after push)
**Files Modified**:
- capabilities/release-management/src/release_management/git/manager.py
- capabilities/release-management/src/release_management/cli/main.py
**Documentation**: Added comprehensive IMPLEMENTATION_PLAN.md with
all 9 optimizations detailed (13.5 hours total estimated)
This solves the #1 critical issue from OPTIMIZATION_ASSESSMENT.md.
This commit is contained in:
@@ -55,6 +55,15 @@ def status(ctx):
|
||||
print(f"Latest Commit: {status_info['latest_commit']}")
|
||||
print(f"Latest Tag: {status_info['latest_tag'] or 'None'}")
|
||||
print(f"Uncommitted Changes: {'Yes' if status_info['has_changes'] else 'No'}")
|
||||
|
||||
# Show unpushed tags
|
||||
unpushed_tags = status_info.get('unpushed_tags', [])
|
||||
if unpushed_tags:
|
||||
print(f"\n⚠️ Unpushed Tags: {len(unpushed_tags)} tag(s) not pushed to origin")
|
||||
for tag in unpushed_tags:
|
||||
print(f" - {tag}")
|
||||
print(f"\n💡 Push tags with: git push origin {' '.join(unpushed_tags)}")
|
||||
print(f" Or push all tags: git push --tags")
|
||||
else:
|
||||
print("Git Repository: Not available")
|
||||
|
||||
|
||||
@@ -48,12 +48,16 @@ class GitManager:
|
||||
except subprocess.CalledProcessError:
|
||||
latest_tag = None
|
||||
|
||||
# Get unpushed tags
|
||||
unpushed_tags = self.get_unpushed_tags()
|
||||
|
||||
return {
|
||||
'is_repo': True,
|
||||
'branch': current_branch,
|
||||
'has_changes': has_changes,
|
||||
'latest_commit': latest_commit,
|
||||
'latest_tag': latest_tag
|
||||
'latest_tag': latest_tag,
|
||||
'unpushed_tags': unpushed_tags
|
||||
}
|
||||
except subprocess.CalledProcessError:
|
||||
return {'is_repo': False}
|
||||
@@ -178,6 +182,47 @@ class GitManager:
|
||||
except subprocess.CalledProcessError:
|
||||
return None
|
||||
|
||||
def get_unpushed_tags(self, remote: str = 'origin') -> List[str]:
|
||||
"""Get list of tags that exist locally but not on remote.
|
||||
|
||||
Args:
|
||||
remote: Remote name to compare against (default: 'origin')
|
||||
|
||||
Returns:
|
||||
List of unpushed tag names
|
||||
"""
|
||||
try:
|
||||
# Get local tags
|
||||
local_result = self._run_command(['git', 'tag', '-l'])
|
||||
local_tags = set(tag.strip() for tag in local_result.stdout.strip().split('\n') if tag.strip())
|
||||
|
||||
# Get remote tags
|
||||
try:
|
||||
remote_result = self._run_command(['git', 'ls-remote', '--tags', remote])
|
||||
remote_lines = remote_result.stdout.strip().split('\n')
|
||||
|
||||
# Parse remote tags (format: "hash refs/tags/tagname")
|
||||
remote_tags = set()
|
||||
for line in remote_lines:
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split('refs/tags/')
|
||||
if len(parts) > 1:
|
||||
# Remove ^{} suffix for annotated tags
|
||||
tag_name = parts[1].replace('^{}', '')
|
||||
remote_tags.add(tag_name)
|
||||
|
||||
# Find tags that are local but not remote
|
||||
unpushed = sorted(local_tags - remote_tags)
|
||||
return unpushed
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
# Remote not available, assume all tags are unpushed
|
||||
return sorted(local_tags)
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
return []
|
||||
|
||||
def _run_command(self, cmd: List[str]) -> subprocess.CompletedProcess:
|
||||
"""Run a git command.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user