Add background audits of the default branch's newest commit

This commit is contained in:
Ian Gulliver
2026-10-20 21:08:31 -07:00
parent 1d3c4576ff
commit 5823af6ff9
21 changed files with 745 additions and 357 deletions
+4 -3
View File
@@ -125,16 +125,17 @@ func notifyTask(_ store: Store, _ ev: ByreEvent) {
}
let prefs = me.notificationPrefs
let origin = store.api.origin.absoluteString
let background = store.findTask(taskId)?.background == true
switch ev.kind {
case "task.ready" where prefs.ready:
show(store, taskId, "task-\(taskId)@\(origin)", "Ready to merge: \(str(ev.payload.value, "overview") ?? "")")
case "task.discard_suggested" where prefs.discard:
case "task.discard_suggested" where prefs.discard && !background:
show(store, taskId, "task-\(taskId)@\(origin)", "Suggests discard: \(str(ev.payload.value, "reason") ?? "")")
case "task.merge_stopped" where prefs.mergeProblems:
show(store, taskId, "task-\(taskId)@\(origin)", "Merge stopped: \(str(ev.payload.value, "reason") ?? "")")
case "task.merge_after_review_dropped" where prefs.mergeProblems:
show(store, taskId, "task-\(taskId)@\(origin)", "Didn't merge after the review: \(str(ev.payload.value, "reason") ?? "")")
case "task.workflow_finished" where prefs.workflows:
case "task.workflow_finished" where prefs.workflows && !background:
show(store, taskId, "workflow-\(ev.seq)@\(origin)", "Finished \(str(ev.payload.value, "workflow") ?? ""): \(str(ev.payload.value, "output") ?? "")")
default:
break
@@ -151,7 +152,7 @@ func clearTask(_ store: Store, _ taskId: String) {
@MainActor
func notifyTurn(_ store: Store, _ ev: ByreEvent) {
guard let me = store.me, me.notificationPrefs.reports, ev.payload.value["summary"] as? Bool == true, let taskId = ev.taskId, !taskId.isEmpty else {
guard let me = store.me, me.notificationPrefs.reports, ev.payload.value["summary"] as? Bool == true, let taskId = ev.taskId, !taskId.isEmpty, store.findTask(taskId)?.background != true else {
return
}
show(store, taskId, "turn-\(ev.seq)@\(store.api.origin.absoluteString)", str(ev.payload.value, "result") ?? "")
+46 -12
View File
@@ -80,7 +80,7 @@ struct ProjectView: View {
guard let p = store.focusedProject() else {
return
}
let rows = nested(store, (store.tasks[p.id] ?? []).filter { $0.status == .active }).map(\.task.id)
let rows = nested(store, (store.tasks[p.id] ?? []).filter { $0.status == .active && !$0.background }).map(\.task.id)
if rows.isEmpty {
return
}
@@ -110,21 +110,24 @@ struct ProjectView: View {
}
}
private struct ReviewWorkflowMenu: View {
private struct ProjectWorkflowMenu: View {
let project: Project
let audit: Bool
@Environment(Store.self) private var store
@Environment(Overlays.self) private var overlays
@ViewState private var reviewWorkflows: [String] = []
@ViewState private var workflows: [String] = []
var body: some View {
let current = audit ? project.auditWorkflow : project.reviewWorkflow
let kind = audit ? "audits" : "reviews"
Menu {
Button("No reviews") { set("") }
ForEach(reviewWorkflows, id: \.self) { name in
Button("No \(kind)") { set("") }
ForEach(workflows, id: \.self) { name in
Button(name) { set(name) }
}
} label: {
HStack(spacing: 6) {
Text(project.reviewWorkflow.isEmpty ? "no reviews" : "reviews: \(project.reviewWorkflow)")
Text(current.isEmpty ? "no \(kind)" : "\(kind): \(current)")
Image(systemName: "chevron.up.chevron.down")
.font(.system(size: 8, weight: .semibold))
}
@@ -136,12 +139,12 @@ private struct ReviewWorkflowMenu: View {
.buttonStyle(.plain)
.menuIndicator(.hidden)
.fixedSize()
.help("The review workflow whose reviewers review every snapshot of this project's tasks")
.help(audit ? "The workflow byre runs in the background on \(project.defaultBranch)'s newest commit to check the whole codebase" : "The review workflow whose reviewers review every snapshot of this project's tasks")
.task {
do {
reviewWorkflows = try await store.api.client.listWorkflows().ok.body.json.map(\.name)
workflows = try await store.api.client.listWorkflows().ok.body.json.map(\.name)
} catch {
reviewWorkflows = []
workflows = []
}
}
}
@@ -149,7 +152,11 @@ private struct ReviewWorkflowMenu: View {
private func set(_ name: String) {
Task {
do {
_ = try await store.api.client.setReviewWorkflow(path: .init(projectId: project.id), body: .json(.init(workflow: name))).ok.body.json
if audit {
_ = try await store.api.client.setAuditWorkflow(path: .init(projectId: project.id), body: .json(.init(workflow: name))).ok.body.json
} else {
_ = try await store.api.client.setReviewWorkflow(path: .init(projectId: project.id), body: .json(.init(workflow: name))).ok.body.json
}
} catch {
overlays.showAlert(errorText(error))
}
@@ -169,12 +176,17 @@ private struct ProjectBlock: View {
Text(project.name).font(Fonts.font(13, weight: 700))
Text(project.defaultBranch).font(Fonts.font(11)).foregroundStyle(Palette.muted)
Spacer()
ReviewWorkflowMenu(project: project)
ProjectWorkflowMenu(project: project, audit: true)
ProjectWorkflowMenu(project: project, audit: false)
}
.padding(.top, 16)
.padding(.bottom, 6)
heading("Tasks")
TaskRows(active: active)
TaskRows(active: active.filter { !$0.background })
ForEach(active.filter(\.background), id: \.id) { task in
BackgroundRow(task: task)
.id(task.id)
}
heading("TODO")
TodoBlock(project: project, todo: todo, active: active)
}
@@ -293,6 +305,28 @@ private struct TaskRow: View {
}
}
private struct BackgroundRow: View {
let task: ByreTask
@Environment(Store.self) private var store
var body: some View {
let ts = store.taskState(task)
HoverRow(selected: task.id == store.selectedTaskId) {
store.focusTask(task.id)
} content: {
Text(task.name)
.lineLimit(1)
.truncationMode(.tail)
.frame(maxWidth: .infinity, alignment: .leading)
Text(ts.label)
.help(ts.title)
}
.font(Fonts.font(11))
.foregroundStyle(Palette.muted)
.help("Runs in the background until it asks for your attention")
}
}
private struct TodoBlock: View {
let project: Project
let todo: Result<Todo, ApiError>?
+5
View File
@@ -688,6 +688,11 @@ final class Store {
}
case "session.error", "session.rate_limited":
notifyError(self, ev)
if let projectId = ev.projectId {
spawn("load tasks") {
try await self.loadTasks(projectId)
}
}
case "task.merge_stopped", "task.merge_after_review_dropped", "task.workflow_finished":
notifyTask(self, ev)
case "turn.ended":
+3
View File
@@ -196,6 +196,9 @@ final class SwitcherModel {
let visits = store.lastVisits()
let matches = store.activeTasks()
.filter { row in
if row.task.background {
return false
}
if let targets {
return targets.contains { $0.id == row.project.id } && includes(row.task.title.lowercased(), q)
}