feat: 同步构建真实状态并支持在列表停止在途任务
- Gitea 运行未结束时探测作业级结论,修复前置作业失败后可复用工作流父作业/等待标签作业长期挂起导致状态永远构建中 - 打开我的构建/管理仪表盘时主动向构建平台同步在途任务状态;创建超 6 小时仍在途的任务判超时 - 构建中任务列表增加停止按钮(Gitea 需 1.28+ 取消 API,旧版本提示去运行页手动 Cancel),终态任务保留删除 - GitHub/Gitea 后端统一 cancel_run 接口
This commit is contained in:
@@ -31,7 +31,12 @@ def staff_required(view_func):
|
||||
|
||||
@login_required
|
||||
def my_builds(request):
|
||||
builds = GithubRun.objects.filter(created_by=request.user)
|
||||
builds = list(GithubRun.objects.filter(created_by=request.user))
|
||||
# 列表打开时向构建平台同步在途任务的真实状态(Gitea 可能不主动回调终态)
|
||||
from .views import refresh_active_run
|
||||
for run in builds:
|
||||
if not run.is_finished():
|
||||
refresh_active_run(run)
|
||||
return render(request, 'my_builds.html', {'builds': builds})
|
||||
|
||||
|
||||
@@ -48,7 +53,7 @@ def delete_my_build(request, run_id):
|
||||
"""用户删除自己的已结束任务;进行中的任务不允许删除(避免与 GitHub 回调竞态)。"""
|
||||
run = get_object_or_404(GithubRun, pk=run_id, created_by=request.user)
|
||||
if not run.is_finished():
|
||||
messages.error(request, "该任务仍在进行中,请等待结束(或先在 GitHub Actions 中取消)后再删除。")
|
||||
messages.error(request, "该任务仍在进行中,请先点「停止」取消构建(或等待结束)后再删除。")
|
||||
else:
|
||||
_remove_run_artifacts(run)
|
||||
run.delete()
|
||||
@@ -56,6 +61,49 @@ def delete_my_build(request, run_id):
|
||||
return redirect('my_builds')
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def stop_build(request, run_id):
|
||||
"""停止自己的在途构建:调用构建平台取消运行,并把任务标记为已取消。"""
|
||||
run = get_object_or_404(GithubRun, pk=run_id, created_by=request.user)
|
||||
if run.is_finished():
|
||||
messages.info(request, "该任务已经结束,无需停止。")
|
||||
return redirect('my_builds')
|
||||
if not run.github_run_id:
|
||||
messages.error(request, "该任务尚未获得构建平台的运行编号,暂时无法停止,请稍后重试。")
|
||||
return redirect('my_builds')
|
||||
|
||||
from . import build_backends
|
||||
from .build_backends.base import BackendError
|
||||
backend = build_backends.get_backend(run.backend or 'github')
|
||||
try:
|
||||
backend.cancel_run(run.github_run_id)
|
||||
except BackendError as e:
|
||||
if e.kind == 'finished':
|
||||
# 平台侧已结束:立即拉一次真实状态,避免本地仍显示构建中
|
||||
from .views import refresh_active_run
|
||||
refresh_active_run(run)
|
||||
if run.is_finished():
|
||||
messages.info(request, f"构建平台上该任务实际已结束({run.status_label()}),列表状态已同步。")
|
||||
else:
|
||||
messages.error(request, str(e))
|
||||
elif e.kind == 'unsupported':
|
||||
# 平台版本不支持远程取消(如 Gitea ≤ 1.27):给出运行页,本地状态保持构建中
|
||||
log_link = backend.log_url(run.github_run_id)
|
||||
messages.error(
|
||||
request,
|
||||
f"无法远程停止:{e.message} 运行页面:{log_link}",
|
||||
)
|
||||
else:
|
||||
messages.error(request, f"停止失败:{e.message}")
|
||||
return redirect('my_builds')
|
||||
|
||||
run.status = 'cancelled'
|
||||
run.save(update_fields=['status', 'updated_at'])
|
||||
messages.success(request, f"已请求{run.backend_label}停止构建任务「{run.filename or run.short_uuid()}」。")
|
||||
return redirect('my_builds')
|
||||
|
||||
|
||||
@login_required
|
||||
@require_POST
|
||||
def retry_build(request, run_id):
|
||||
@@ -118,7 +166,12 @@ def delete_token(request, key):
|
||||
|
||||
@staff_required
|
||||
def dashboard(request):
|
||||
builds = GithubRun.objects.select_related('created_by').all()[:100]
|
||||
builds = list(GithubRun.objects.select_related('created_by').all()[:100])
|
||||
# 打开仪表盘时同步在途任务的真实状态
|
||||
from .views import refresh_active_run
|
||||
for run in builds:
|
||||
if not run.is_finished():
|
||||
refresh_active_run(run)
|
||||
stats = {
|
||||
'total': GithubRun.objects.count(),
|
||||
'in_progress': GithubRun.objects.exclude(
|
||||
|
||||
Reference in New Issue
Block a user