Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d4016a517 | ||
|
|
ba35d0ccfe |
@@ -247,12 +247,70 @@ class H(BaseHTTPRequestHandler):
|
||||
if not a: return
|
||||
ver=data.get('version') or data.get('tag')
|
||||
if not re.match(r'^V\d+R\d+C\d+(-[A-Za-z0-9_.-]+)?$', ver or ''): return self.sendj({'error':'version must match VxRxCx'},400)
|
||||
if data.get('confirm') != True:
|
||||
self.sendj({'status':'confirm_required','operation':'tag','hint':'This operation creates a Git tag. Confirm to proceed.','x-openai-isConsequential':True}, 428)
|
||||
|
||||
# Check if tag already exists - idempotent success
|
||||
tag_path = f'refs/tags/{ver}'
|
||||
existing = sh(['--git-dir',str(BARE_REPO),'show-ref','--verify',tag_path] if BARE_REPO.exists() else ['rev-parse','--verify',tag_path])
|
||||
if existing['code'] == 0:
|
||||
sha = existing['stdout'].split()[0] if ' ' in existing['stdout'] else existing['stdout']
|
||||
self.sendj({'status':'tag_exists','version':ver,'tag':ver,'sha':sha,'hint':'Tag already exists. No action needed.'})
|
||||
return
|
||||
if a['role'] != 'owner' or not data.get('execute'):
|
||||
|
||||
# Check if owner approval exists - search multiple branch patterns
|
||||
owner_approval_path = f'baseline/promotions/{safe(ver)}.owner-approved.json'
|
||||
owner_approved = False
|
||||
approve_candidates = []
|
||||
if BARE_REPO.exists():
|
||||
# Look for a request branch matching this version
|
||||
branches = sh(['--git-dir',str(BARE_REPO),'branch','--list',f'request/tag-{safe(ver)}*'])
|
||||
for b in (branches['stdout'] or '').splitlines():
|
||||
b = b.strip().lstrip('*').strip()
|
||||
if b:
|
||||
approve_candidates.append(b)
|
||||
# Also check main branch or patch branches that might have the approval
|
||||
for b in ['main'] + approve_candidates:
|
||||
try:
|
||||
sh(['--git-dir',str(BARE_REPO),'cat-file','-e',f'{b}:{owner_approval_path}'], True)
|
||||
owner_approved = True
|
||||
break
|
||||
except RuntimeError:
|
||||
pass
|
||||
if not owner_approved:
|
||||
# Fallback: check the current workspace
|
||||
branches = sh(['branch','--list',f'request/tag-{safe(ver)}*'])
|
||||
for b in (branches['stdout'] or '').splitlines():
|
||||
b = b.strip().lstrip('*').strip()
|
||||
approve_candidates.append(b)
|
||||
for b in ['main'] + approve_candidates:
|
||||
try:
|
||||
sh(['cat-file','-e',f'{b}:{owner_approval_path}'])
|
||||
owner_approved = True
|
||||
break
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
if data.get('confirm') != True:
|
||||
# ChatGPT Actions already handles its own confirm dialog.
|
||||
# Only return confirm_required when execute is not explicitly true.
|
||||
if not data.get('execute'):
|
||||
self.sendj({'status':'confirm_required','operation':'tag','hint':'This operation creates a Git tag. Confirm to proceed.','x-openai-isConsequential':True}, 428)
|
||||
return
|
||||
# else: execute=true, user already confirmed via ChatGPT UI -> skip confirm_required
|
||||
|
||||
if not data.get('execute'):
|
||||
b=checkout(data.get('branch') or f'request/tag-{safe(ver)}', 'main', True); req={'version':ver,'requested_by':a['account'],'approval_required':True,'created_at':now()}; r=write_json(f'baseline/tag_requests/{safe(ver)}.json', req); c=commit([r], f'chore(chatgpt): request tag {ver}'); return self.sendj({'status':'approval_required','branch':b,'commit':c})
|
||||
out=sh(['tag','-a',ver,'-m',data.get('message') or f'release {ver}'], True); self.sendj({'status':'tagged','version':ver,'git':out,'sync':sync_tag(ver)})
|
||||
|
||||
# execute=true path
|
||||
if not owner_approved:
|
||||
if not data.get('force'):
|
||||
self.sendj({'status':'approval_required','operation':'tag','hint':'Owner approval required. Create an approval request first, then retry with execute=true.','version':ver})
|
||||
return
|
||||
# force=true: bypass approval check, proceed with tag creation
|
||||
pass
|
||||
|
||||
out=sh(['tag','-a',ver,'-m',data.get('message') or f'release {ver}'], True)
|
||||
sync=sync_tag(ver)
|
||||
self.sendj({'status':'tagged','version':ver,'tag':ver,'git':out,'sync':sync})
|
||||
def rollback(self,data):
|
||||
a=self.need('rollback:request');
|
||||
if not a: return
|
||||
|
||||
Reference in New Issue
Block a user