deploy: create Codeberg issue when deploy fails and main is unchanged
If the last deploy failed and origin/main has not advanced, opens a Prio/High + State/Ready issue via tea with the failing SHA, commit link, and captured deploy output. Skips duplicate issues (tracked by .last_issue_sha). Cron interval changed to */5. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
8d49a6b267
commit
c259d2dabe
@@ -8,7 +8,8 @@ set -a
|
|||||||
source "$REPO_DIR/.env"
|
source "$REPO_DIR/.env"
|
||||||
set +a
|
set +a
|
||||||
|
|
||||||
# Add task and dagger from nix store if not already in PATH
|
# Add nix profile and nix store tools (task, dagger) to PATH
|
||||||
|
export PATH="$HOME/.nix-profile/bin:$PATH"
|
||||||
for pkg in "*go-task-*/bin/task" "*dagger-*/bin/dagger"; do
|
for pkg in "*go-task-*/bin/task" "*dagger-*/bin/dagger"; do
|
||||||
bin=$(ls -d /nix/store/$pkg 2>/dev/null | sort -V | tail -1)
|
bin=$(ls -d /nix/store/$pkg 2>/dev/null | sort -V | tail -1)
|
||||||
[ -n "$bin" ] && export PATH="$(dirname "$bin"):$PATH"
|
[ -n "$bin" ] && export PATH="$(dirname "$bin"):$PATH"
|
||||||
|
|||||||
+86
-3
@@ -2,13 +2,21 @@
|
|||||||
"""
|
"""
|
||||||
Cron deploy script for sharedinbox website.
|
Cron deploy script for sharedinbox website.
|
||||||
Runs every 15 minutes; skips if origin/main has not changed since last successful deploy.
|
Runs every 15 minutes; skips if origin/main has not changed since last successful deploy.
|
||||||
|
If last deploy failed and main still hasn't changed, creates a Codeberg issue.
|
||||||
"""
|
"""
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
REPO_DIR = Path(__file__).parent.resolve()
|
REPO_DIR = Path(__file__).parent.resolve()
|
||||||
SHA_FILE = REPO_DIR / '.last_deployed_sha'
|
SHA_FILE = REPO_DIR / '.last_deployed_sha'
|
||||||
|
FAILED_SHA_FILE = REPO_DIR / '.last_failed_sha'
|
||||||
|
ERROR_FILE = REPO_DIR / '.last_deploy_error'
|
||||||
|
ISSUE_SHA_FILE = REPO_DIR / '.last_issue_sha'
|
||||||
|
|
||||||
|
REPO = 'guettli/sharedinbox'
|
||||||
|
CODEBERG = 'https://codeberg.org'
|
||||||
|
|
||||||
|
|
||||||
def git(*args):
|
def git(*args):
|
||||||
@@ -18,24 +26,99 @@ def git(*args):
|
|||||||
).stdout.strip()
|
).stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def read(path: Path) -> str:
|
||||||
|
return path.read_text().strip() if path.exists() else ''
|
||||||
|
|
||||||
|
|
||||||
|
def create_issue(failed_sha: str) -> None:
|
||||||
|
error_output = read(ERROR_FILE)
|
||||||
|
tail = '\n'.join(error_output.splitlines()[-40:]) if error_output else '(no output captured)'
|
||||||
|
commit_url = f'{CODEBERG}/{REPO}/commit/{failed_sha}'
|
||||||
|
script_url = f'{CODEBERG}/{REPO}/src/branch/main/deploy_cron.py'
|
||||||
|
timestamp = datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')
|
||||||
|
|
||||||
|
title = f'Deploy failed on {failed_sha[:8]} — main needs a fix'
|
||||||
|
body = f"""\
|
||||||
|
## Deploy failure — action needed
|
||||||
|
|
||||||
|
The automated deploy cron has been failing on commit \
|
||||||
|
[{failed_sha[:8]}]({commit_url}) and `main` has not advanced since the failure.
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **Detected** | {timestamp} |
|
||||||
|
| **Failing commit** | [{failed_sha}]({commit_url}) |
|
||||||
|
| **Deploy script** | [deploy_cron.py]({script_url}) |
|
||||||
|
| **Log file** | `~/si-deploy-cron/deploy.log` |
|
||||||
|
|
||||||
|
### Last deploy output
|
||||||
|
|
||||||
|
```
|
||||||
|
{tail}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Next steps
|
||||||
|
|
||||||
|
Push a fix to `main` — the cron runs every 15 min and will retry automatically.
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
['tea', 'issue', 'create',
|
||||||
|
'--repo', REPO,
|
||||||
|
'--title', title,
|
||||||
|
'--description', body,
|
||||||
|
'--labels', 'State/Ready,Prio/High'],
|
||||||
|
capture_output=True, text=True,
|
||||||
|
)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f'Failed to create issue: {result.stderr}', file=sys.stderr)
|
||||||
|
else:
|
||||||
|
print(f'Issue created: {result.stdout.strip()}')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
git('fetch', 'origin', 'main')
|
git('fetch', 'origin', 'main')
|
||||||
remote_sha = git('rev-parse', 'origin/main')
|
remote_sha = git('rev-parse', 'origin/main')
|
||||||
|
|
||||||
last_sha = SHA_FILE.read_text().strip() if SHA_FILE.exists() else ''
|
last_sha = read(SHA_FILE)
|
||||||
|
last_failed = read(FAILED_SHA_FILE)
|
||||||
|
last_issue = read(ISSUE_SHA_FILE)
|
||||||
|
|
||||||
if remote_sha == last_sha:
|
if remote_sha == last_sha:
|
||||||
print(f'No changes since {remote_sha[:8]}, skipping.')
|
print(f'No changes since {remote_sha[:8]}, skipping.')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if remote_sha == last_failed:
|
||||||
|
if remote_sha != last_issue:
|
||||||
|
print(f'{remote_sha[:8]} failed before and main has not changed — creating issue.')
|
||||||
|
create_issue(remote_sha)
|
||||||
|
ISSUE_SHA_FILE.write_text(remote_sha + '\n')
|
||||||
|
else:
|
||||||
|
print(f'{remote_sha[:8]} still failing, issue already open, skipping.')
|
||||||
|
return
|
||||||
|
|
||||||
print(f'Deploying {remote_sha[:8]} (was {last_sha[:8] or "none"})...')
|
print(f'Deploying {remote_sha[:8]} (was {last_sha[:8] or "none"})...')
|
||||||
git('pull', '--ff-only', 'origin', 'main')
|
git('pull', '--ff-only', 'origin', 'main')
|
||||||
|
|
||||||
result = subprocess.run(['task', 'publish-website'], cwd=REPO_DIR)
|
result = subprocess.run(
|
||||||
|
['task', 'publish-website'],
|
||||||
|
cwd=REPO_DIR,
|
||||||
|
capture_output=True, text=True,
|
||||||
|
)
|
||||||
|
combined = result.stdout + result.stderr
|
||||||
|
print(combined, end='')
|
||||||
|
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
print(f'Deploy failed (exit {result.returncode})', file=sys.stderr)
|
print(f'Deploy failed (exit {result.returncode})', file=sys.stderr)
|
||||||
|
FAILED_SHA_FILE.write_text(remote_sha + '\n')
|
||||||
|
ERROR_FILE.write_text(combined)
|
||||||
|
ISSUE_SHA_FILE.unlink(missing_ok=True)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
SHA_FILE.write_text(remote_sha + '\n')
|
SHA_FILE.write_text(remote_sha + '\n')
|
||||||
|
FAILED_SHA_FILE.unlink(missing_ok=True)
|
||||||
|
ERROR_FILE.unlink(missing_ok=True)
|
||||||
|
ISSUE_SHA_FILE.unlink(missing_ok=True)
|
||||||
print('Deploy complete.')
|
print('Deploy complete.')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user