From 4823c81f8d07228eee00b1711a30d991ae2e0ac8 Mon Sep 17 00:00:00 2001 From: OCPeyton Date: Wed, 25 Mar 2026 16:48:31 -0400 Subject: [PATCH 1/2] feat: open active job runs from the menubar Co-Authored-By: Claude Opus 4.6 --- Sources/Services/RunnerManager.swift | 21 +++++++++++++++ Sources/Views/MenuBarView.swift | 24 +++++++++++++++++ Tests/MacRunnerTests/MacRunnerTests.swift | 32 +++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/Sources/Services/RunnerManager.swift b/Sources/Services/RunnerManager.swift index 3a6325e..e3a435b 100644 --- a/Sources/Services/RunnerManager.swift +++ b/Sources/Services/RunnerManager.swift @@ -319,6 +319,27 @@ class RunnerManager: ObservableObject { } } + func currentWorkflowJob(for runnerID: UUID) -> WorkflowJobSummary? { + activeWorkflowJobs[runnerID] + } + + func openCurrentWorkflowRun(for runnerID: UUID) { + guard let runURL = Self.currentWorkflowRunURL(from: activeWorkflowJobs[runnerID]) else { + return + } + + NSWorkspace.shared.open(runURL) + } + + static func currentWorkflowRunURL(from job: WorkflowJobSummary?) -> URL? { + job?.run.htmlURL + } + + static func currentWorkflowDisplayName(from job: WorkflowJobSummary?) -> String? { + guard let job else { return nil } + return job.run.name.isEmpty ? job.name : job.run.name + } + private func refreshUpdateStatusMessage() { if let availableUpdate { updateStatusMessage = "Version \(availableUpdate.latestVersion) is available." diff --git a/Sources/Views/MenuBarView.swift b/Sources/Views/MenuBarView.swift index 8f3f72b..60cf945 100644 --- a/Sources/Views/MenuBarView.swift +++ b/Sources/Views/MenuBarView.swift @@ -268,6 +268,25 @@ struct RunnerRow: View { .font(.caption) .foregroundColor(.secondary) + if runner.status == .running, + runner.busy, + let currentJob = runnerManager.currentWorkflowJob(for: runner.id), + let workflowName = RunnerManager.currentWorkflowDisplayName(from: currentJob) { + Button(action: { + runnerManager.openCurrentWorkflowRun(for: runner.id) + }) { + HStack(spacing: 4) { + Image(systemName: "link") + Text("View \(workflowName)") + .lineLimit(1) + } + .font(.caption2) + .foregroundColor(.accentColor) + } + .buttonStyle(.plain) + .help("Open current GitHub Actions run") + } + HStack(spacing: 4) { // Isolation mode indicator if let mode = runner.isolationMode { @@ -348,6 +367,11 @@ struct RunnerRow: View { Button("Stop") { Task { try? await runnerManager.stopRunner(runner.id) } } + if runner.busy, runnerManager.currentWorkflowJob(for: runner.id) != nil { + Button("Open Current Job") { + runnerManager.openCurrentWorkflowRun(for: runner.id) + } + } } else { Button("Start") { Task { try? await runnerManager.startRunner(runner.id) } diff --git a/Tests/MacRunnerTests/MacRunnerTests.swift b/Tests/MacRunnerTests/MacRunnerTests.swift index 8999edc..744ee22 100644 --- a/Tests/MacRunnerTests/MacRunnerTests.swift +++ b/Tests/MacRunnerTests/MacRunnerTests.swift @@ -318,4 +318,36 @@ final class MacRunnerTests: XCTestCase { XCTAssertEqual(payload.body, "omniaura/mac-runner - Nightly (failure)") XCTAssertEqual(payload.runURL, run.htmlURL) } + + func testRunnerManagerCurrentWorkflowHelpersPreferRunNameAndURL() { + let runURL = URL(string: "https://github.com/omniaura/mac-runner/actions/runs/42")! + let job = WorkflowJobSummary( + id: 8, + name: "test", + status: "in_progress", + conclusion: nil, + runnerName: "runner-1", + run: WorkflowRunSummary(id: 42, name: "Nightly", htmlURL: runURL) + ) + + XCTAssertEqual(RunnerManager.currentWorkflowDisplayName(from: job), "Nightly") + XCTAssertEqual(RunnerManager.currentWorkflowRunURL(from: job), runURL) + } + + func testRunnerManagerCurrentWorkflowHelpersFallBackToJobName() { + let job = WorkflowJobSummary( + id: 9, + name: "integration", + status: "in_progress", + conclusion: nil, + runnerName: "runner-1", + run: WorkflowRunSummary( + id: 43, + name: "", + htmlURL: URL(string: "https://github.com/omniaura/mac-runner/actions/runs/43")! + ) + ) + + XCTAssertEqual(RunnerManager.currentWorkflowDisplayName(from: job), "integration") + } } From 104c58a0c22f8f9ad1a1c445fe9761ce47a13acd Mon Sep 17 00:00:00 2001 From: OCPeyton Date: Sat, 2 May 2026 22:22:44 -0400 Subject: [PATCH 2/2] fix: make workflow display helpers nonisolated Co-Authored-By: Claude Opus 4.6 --- Sources/Services/RunnerManager.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Services/RunnerManager.swift b/Sources/Services/RunnerManager.swift index e3a435b..a748d2e 100644 --- a/Sources/Services/RunnerManager.swift +++ b/Sources/Services/RunnerManager.swift @@ -331,11 +331,11 @@ class RunnerManager: ObservableObject { NSWorkspace.shared.open(runURL) } - static func currentWorkflowRunURL(from job: WorkflowJobSummary?) -> URL? { + nonisolated static func currentWorkflowRunURL(from job: WorkflowJobSummary?) -> URL? { job?.run.htmlURL } - static func currentWorkflowDisplayName(from job: WorkflowJobSummary?) -> String? { + nonisolated static func currentWorkflowDisplayName(from job: WorkflowJobSummary?) -> String? { guard let job else { return nil } return job.run.name.isEmpty ? job.name : job.run.name }