From 3692e70b7a9cb27c3380215378dcaa8825154b5e Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 14:43:06 -0500 Subject: [PATCH 01/16] Fix #229: Auto-refresh UI when a new workflow run is triggered --- src/commands/triggerWorkflowRun.ts | 46 ++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/commands/triggerWorkflowRun.ts b/src/commands/triggerWorkflowRun.ts index 3deba5b..c85adf2 100644 --- a/src/commands/triggerWorkflowRun.ts +++ b/src/commands/triggerWorkflowRun.ts @@ -43,6 +43,22 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext) { return; } + const relativeWorkflowPath = vscode.workspace.asRelativePath(workflowUri, false); + let latestRunId: number | undefined; + try { + const result = await gitHubRepoContext.client.actions.listWorkflowRuns({ + owner: gitHubRepoContext.owner, + repo: gitHubRepoContext.name, + workflow_id: relativeWorkflowPath, + per_page: 1 + }); + latestRunId = result.data.workflow_runs[0]?.id; + } catch (e) { + // Ignore error + } + + let dispatched = false; + let selectedEvent: string | undefined; if (workflow.events.workflow_dispatch !== undefined && workflow.events.repository_dispatch !== undefined) { selectedEvent = await vscode.window.showQuickPick(["repository_dispatch", "workflow_dispatch"], { @@ -85,8 +101,6 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext) { } try { - const relativeWorkflowPath = vscode.workspace.asRelativePath(workflowUri, false); - await gitHubRepoContext.client.actions.createWorkflowDispatch({ owner: gitHubRepoContext.owner, repo: gitHubRepoContext.name, @@ -95,6 +109,7 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext) { inputs }); + dispatched = true; vscode.window.setStatusBarMessage(`GitHub Actions: Workflow event dispatched`, 2000); } catch (error) { return vscode.window.showErrorMessage(`Could not create workflow dispatch: ${(error as Error)?.message}`); @@ -134,10 +149,37 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext) { client_payload: {} }); + dispatched = true; vscode.window.setStatusBarMessage(`GitHub Actions: Repository event '${event_type}' dispatched`, 2000); } } + if (dispatched) { + vscode.window.withProgress({ + location: vscode.ProgressLocation.Window, + title: "Waiting for workflow run to start..." + }, async () => { + for (let i = 0; i < 20; i++) { + await new Promise(resolve => setTimeout(resolve, 1000)); + try { + const result = await gitHubRepoContext.client.actions.listWorkflowRuns({ + owner: gitHubRepoContext.owner, + repo: gitHubRepoContext.name, + workflow_id: relativeWorkflowPath, + per_page: 1 + }); + const newLatestRunId = result.data.workflow_runs[0]?.id; + if (newLatestRunId && newLatestRunId !== latestRunId) { + await vscode.commands.executeCommand("github-actions.explorer.refresh"); + break; + } + } catch (e) { + // Ignore + } + } + }); + } + return vscode.commands.executeCommand("github-actions.explorer.refresh"); } ) From f7cfef85a43e2f0a5d9b62552ea8367c1e4b8044 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 14:46:04 -0500 Subject: [PATCH 02/16] Add test plan for auto-refresh feature in GitHub Actions extension --- TEST_PLAN.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 TEST_PLAN.md diff --git a/TEST_PLAN.md b/TEST_PLAN.md new file mode 100644 index 0000000..bf6489d --- /dev/null +++ b/TEST_PLAN.md @@ -0,0 +1,52 @@ +# Test Plan for Issue #229 Fix + +## Objective +Verify that the GitHub Actions extension automatically refreshes the workflow run list after a user manually triggers a workflow run. + +## Prerequisites +1. A GitHub repository with GitHub Actions enabled. +2. A workflow file in that repository that supports `workflow_dispatch` (manual trigger). + * Example `workflow_dispatch` configuration in `.github/workflows/test.yml`: + ```yaml + name: Manual Test + on: workflow_dispatch + jobs: + build: + runs-on: ubuntu-latest + steps: + - run: echo "Hello World" + ``` +3. The repository is cloned locally and opened in VS Code. + +## Manual Test Steps + +1. **Launch Extension in Debug Mode**: + * Open the `vscode-github-actions` project in VS Code. + * Press `F5` or go to "Run and Debug" and select "Watch & Launch Extension". + * This will open a new "Extension Development Host" window. + +2. **Open Test Repository**: + * In the Extension Development Host window, open the folder of your test repository (from Prerequisites). + +3. **Navigate to GitHub Actions View**: + * Click on the GitHub Actions icon in the Activity Bar (sidebar). + * Expand the "Workflows" section. + * Find your manual workflow (e.g., "Manual Test"). + +4. **Trigger Workflow Run**: + * Right-click on the workflow name. + * Select **"Run Workflow"**. + * (Optional) If prompted for branch or inputs, provide them and confirm. + +5. **Verify Behavior**: + * **Immediate Feedback**: Look for a status bar message or notification saying "Waiting for workflow run to start...". + * **Auto-Refresh**: Watch the "Workflows" list. Within 1-20 seconds, the list should automatically refresh. + * **New Run**: A new workflow run (likely in "Queued" or "In Progress" state) should appear at the top of the list under the workflow. + +## Expected Result +* The user does **not** need to manually click the refresh button. +* The UI updates automatically once the new run is created on GitHub. + +## Troubleshooting +* If the run doesn't appear after 20 seconds, check if the workflow actually started on GitHub.com. +* Check the "Output" panel (select "GitHub Actions" in the dropdown) for any error logs. From 0e7ed6183974b130f6de4f9b6f44e247752fcf77 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 14:52:39 -0500 Subject: [PATCH 03/16] Fix #229: Poll new workflow run for status updates --- src/commands/triggerWorkflowRun.ts | 4 +++- src/extension.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/commands/triggerWorkflowRun.ts b/src/commands/triggerWorkflowRun.ts index c85adf2..c7c7488 100644 --- a/src/commands/triggerWorkflowRun.ts +++ b/src/commands/triggerWorkflowRun.ts @@ -4,13 +4,14 @@ import {getGitHead, getGitHubContextForWorkspaceUri, GitHubRepoContext} from ".. import {getWorkflowUri, parseWorkflowFile} from "../workflow/workflow"; import {Workflow} from "../model"; +import {RunStore} from "../store/store"; interface TriggerRunCommandOptions { wf?: Workflow; gitHubRepoContext: GitHubRepoContext; } -export function registerTriggerWorkflowRun(context: vscode.ExtensionContext) { +export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, store: RunStore) { context.subscriptions.push( vscode.commands.registerCommand( "github-actions.explorer.triggerRun", @@ -171,6 +172,7 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext) { const newLatestRunId = result.data.workflow_runs[0]?.id; if (newLatestRunId && newLatestRunId !== latestRunId) { await vscode.commands.executeCommand("github-actions.explorer.refresh"); + store.pollRun(newLatestRunId, gitHubRepoContext, 1000, 20); break; } } catch (e) { diff --git a/src/extension.ts b/src/extension.ts index 210c954..d1fdd50 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -73,7 +73,7 @@ export async function activate(context: vscode.ExtensionContext) { registerOpenWorkflowFile(context); registerOpenWorkflowJobLogs(context); registerOpenWorkflowStepLogs(context); - registerTriggerWorkflowRun(context); + registerTriggerWorkflowRun(context, store); registerReRunWorkflowRun(context); registerCancelWorkflowRun(context); From decdefa55c2a743ca749bd67101e0acde25ca380 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 14:58:54 -0500 Subject: [PATCH 04/16] Fix #229: Improve polling duration and stop condition --- src/commands/triggerWorkflowRun.ts | 3 ++- src/store/store.ts | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/commands/triggerWorkflowRun.ts b/src/commands/triggerWorkflowRun.ts index c7c7488..ff3f879 100644 --- a/src/commands/triggerWorkflowRun.ts +++ b/src/commands/triggerWorkflowRun.ts @@ -172,7 +172,8 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, sto const newLatestRunId = result.data.workflow_runs[0]?.id; if (newLatestRunId && newLatestRunId !== latestRunId) { await vscode.commands.executeCommand("github-actions.explorer.refresh"); - store.pollRun(newLatestRunId, gitHubRepoContext, 1000, 20); + // Poll for 15 minutes (225 * 4s) + store.pollRun(newLatestRunId, gitHubRepoContext, 4000, 225); break; } } catch (e) { diff --git a/src/store/store.ts b/src/store/store.ts index 44918f3..4fa769e 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -84,5 +84,12 @@ export class RunStore extends EventEmitter { const run = result.data; this.addRun(updater.repoContext, run); + + if (run.status === "completed" || run.status === "cancelled" || run.status === "failure" || run.status === "success" || run.status === "skipped" || run.status === "timed_out") { + if (updater.handle) { + clearInterval(updater.handle); + } + this.updaters.delete(updater.runId); + } } } From ba66672ec2fde72630328778af33a70012d09c08 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 15:04:14 -0500 Subject: [PATCH 05/16] Fix #229: Force job refresh on run update and add logging --- src/store/store.ts | 1 + src/store/workflowRun.ts | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/store/store.ts b/src/store/store.ts index 4fa769e..46cb312 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -83,6 +83,7 @@ export class RunStore extends EventEmitter { }); const run = result.data; + logDebug("Polled run:", run.id, "Status:", run.status, "Conclusion:", run.conclusion); this.addRun(updater.repoContext, run); if (run.status === "completed" || run.status === "cancelled" || run.status === "failure" || run.status === "success" || run.status === "skipped" || run.status === "timed_out") { diff --git a/src/store/workflowRun.ts b/src/store/workflowRun.ts index 1001bc2..25eb5fe 100644 --- a/src/store/workflowRun.ts +++ b/src/store/workflowRun.ts @@ -35,11 +35,9 @@ abstract class WorkflowRunBase { } updateRun(run: model.WorkflowRun) { - if (this._run.status !== "completed" || this._run.updated_at !== run.updated_at) { - // Refresh jobs if the run is not completed or it was updated (i.e. re-run) - // For in-progress runs, we can't rely on updated at to change when jobs change - this._jobs = undefined; - } + // Always clear jobs cache when updating run to ensure we get latest job status + // This is critical for polling to work correctly for in-progress runs + this._jobs = undefined; this._run = run; } From 89fbe5a12b64a6d94fb4640ecf50b1f86679a211 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 15:13:27 -0500 Subject: [PATCH 06/16] Fix #229: Add verbose logging for debugging polling issues --- src/commands/triggerWorkflowRun.ts | 5 ++++- src/store/store.ts | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/commands/triggerWorkflowRun.ts b/src/commands/triggerWorkflowRun.ts index ff3f879..253bdd0 100644 --- a/src/commands/triggerWorkflowRun.ts +++ b/src/commands/triggerWorkflowRun.ts @@ -6,6 +6,8 @@ import {getWorkflowUri, parseWorkflowFile} from "../workflow/workflow"; import {Workflow} from "../model"; import {RunStore} from "../store/store"; +import {log} from "../log"; + interface TriggerRunCommandOptions { wf?: Workflow; gitHubRepoContext: GitHubRepoContext; @@ -171,13 +173,14 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, sto }); const newLatestRunId = result.data.workflow_runs[0]?.id; if (newLatestRunId && newLatestRunId !== latestRunId) { + log(`Found new workflow run: ${newLatestRunId}. Triggering refresh and polling.`); await vscode.commands.executeCommand("github-actions.explorer.refresh"); // Poll for 15 minutes (225 * 4s) store.pollRun(newLatestRunId, gitHubRepoContext, 4000, 225); break; } } catch (e) { - // Ignore + log(`Error checking for new run: ${(e as Error).message}`); } } }); diff --git a/src/store/store.ts b/src/store/store.ts index 46cb312..d09f1fc 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -1,7 +1,7 @@ import {setInterval} from "timers"; import {EventEmitter} from "vscode"; import {GitHubRepoContext} from "../git/repository"; -import {logDebug} from "../log"; +import {log, logDebug} from "../log"; import * as model from "../model"; import {WorkflowRun} from "./workflowRun"; @@ -46,6 +46,7 @@ export class RunStore extends EventEmitter { * Start polling for updates for the given run */ pollRun(runId: number, repoContext: GitHubRepoContext, intervalMs: number, attempts = 10) { + log(`Starting polling for run ${runId} every ${intervalMs}ms for ${attempts} attempts`); const existingUpdater: Updater | undefined = this.updaters.get(runId); if (existingUpdater && existingUpdater.handle) { clearInterval(existingUpdater.handle); @@ -65,7 +66,7 @@ export class RunStore extends EventEmitter { } private async fetchRun(updater: Updater) { - logDebug("Updating run: ", updater.runId); + log(`Fetching run update: ${updater.runId}. Remaining attempts: ${updater.remainingAttempts}`); updater.remainingAttempts--; if (updater.remainingAttempts === 0) { @@ -83,7 +84,7 @@ export class RunStore extends EventEmitter { }); const run = result.data; - logDebug("Polled run:", run.id, "Status:", run.status, "Conclusion:", run.conclusion); + log(`Polled run: ${run.id} Status: ${run.status} Conclusion: ${run.conclusion}`); this.addRun(updater.repoContext, run); if (run.status === "completed" || run.status === "cancelled" || run.status === "failure" || run.status === "success" || run.status === "skipped" || run.status === "timed_out") { From 0b5c87db1390fcfcc6691db1ffae667f99f6cf62 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 15:17:39 -0500 Subject: [PATCH 07/16] Fix #229: Use workflow ID or filename for polling, fix path issue --- src/commands/triggerWorkflowRun.ts | 64 ++++++++++++++++++------------ 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/src/commands/triggerWorkflowRun.ts b/src/commands/triggerWorkflowRun.ts index 253bdd0..084390b 100644 --- a/src/commands/triggerWorkflowRun.ts +++ b/src/commands/triggerWorkflowRun.ts @@ -1,3 +1,4 @@ +import {basename} from "path"; import * as vscode from "vscode"; import {getGitHead, getGitHubContextForWorkspaceUri, GitHubRepoContext} from "../git/repository"; @@ -19,11 +20,15 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, sto "github-actions.explorer.triggerRun", async (args: TriggerRunCommandOptions | vscode.Uri) => { let workflowUri: vscode.Uri | null = null; + let workflowIdForApi: number | string | undefined; + if (args instanceof vscode.Uri) { workflowUri = args; + workflowIdForApi = basename(workflowUri.fsPath); } else if (args.wf) { const wf: Workflow = args.wf; workflowUri = getWorkflowUri(args.gitHubRepoContext, wf.path); + workflowIdForApi = wf.id; } if (!workflowUri) { @@ -47,17 +52,23 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, sto } const relativeWorkflowPath = vscode.workspace.asRelativePath(workflowUri, false); + if (!workflowIdForApi) { + workflowIdForApi = basename(workflowUri.fsPath); + } + let latestRunId: number | undefined; try { + log(`Fetching latest run for workflow: ${workflowIdForApi}`); const result = await gitHubRepoContext.client.actions.listWorkflowRuns({ owner: gitHubRepoContext.owner, repo: gitHubRepoContext.name, - workflow_id: relativeWorkflowPath, + workflow_id: workflowIdForApi, per_page: 1 }); latestRunId = result.data.workflow_runs[0]?.id; + log(`Latest run ID before trigger: ${latestRunId}`); } catch (e) { - // Ignore error + log(`Error fetching latest run: ${(e as Error).message}`); } let dispatched = false; @@ -158,32 +169,35 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, sto } if (dispatched) { - vscode.window.withProgress({ - location: vscode.ProgressLocation.Window, - title: "Waiting for workflow run to start..." - }, async () => { - for (let i = 0; i < 20; i++) { - await new Promise(resolve => setTimeout(resolve, 1000)); - try { - const result = await gitHubRepoContext.client.actions.listWorkflowRuns({ - owner: gitHubRepoContext.owner, - repo: gitHubRepoContext.name, - workflow_id: relativeWorkflowPath, - per_page: 1 - }); - const newLatestRunId = result.data.workflow_runs[0]?.id; - if (newLatestRunId && newLatestRunId !== latestRunId) { - log(`Found new workflow run: ${newLatestRunId}. Triggering refresh and polling.`); - await vscode.commands.executeCommand("github-actions.explorer.refresh"); - // Poll for 15 minutes (225 * 4s) - store.pollRun(newLatestRunId, gitHubRepoContext, 4000, 225); - break; + vscode.window.withProgress( + { + location: vscode.ProgressLocation.Window, + title: "Waiting for workflow run to start..." + }, + async () => { + for (let i = 0; i < 20; i++) { + await new Promise(resolve => setTimeout(resolve, 1000)); + try { + const result = await gitHubRepoContext.client.actions.listWorkflowRuns({ + owner: gitHubRepoContext.owner, + repo: gitHubRepoContext.name, + workflow_id: workflowIdForApi!, + per_page: 1 + }); + const newLatestRunId = result.data.workflow_runs[0]?.id; + if (newLatestRunId && newLatestRunId !== latestRunId) { + log(`Found new workflow run: ${newLatestRunId}. Triggering refresh and polling.`); + await vscode.commands.executeCommand("github-actions.explorer.refresh"); + // Poll for 15 minutes (225 * 4s) + store.pollRun(newLatestRunId, gitHubRepoContext, 4000, 225); + break; + } + } catch (e) { + log(`Error checking for new run: ${(e as Error).message}`); } - } catch (e) { - log(`Error checking for new run: ${(e as Error).message}`); } } - }); + ); } return vscode.commands.executeCommand("github-actions.explorer.refresh"); From a62d2e03df1cd334948ee7e57988a6df020b6d02 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 15:20:51 -0500 Subject: [PATCH 08/16] Fix #229: Add even more verbose logging for polling loop --- src/commands/triggerWorkflowRun.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/commands/triggerWorkflowRun.ts b/src/commands/triggerWorkflowRun.ts index 084390b..923b010 100644 --- a/src/commands/triggerWorkflowRun.ts +++ b/src/commands/triggerWorkflowRun.ts @@ -175,16 +175,20 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, sto title: "Waiting for workflow run to start..." }, async () => { + log("Starting loop to check for new workflow run..."); for (let i = 0; i < 20; i++) { await new Promise(resolve => setTimeout(resolve, 1000)); try { + log(`Checking for new run (attempt ${i + 1}/20)...`); const result = await gitHubRepoContext.client.actions.listWorkflowRuns({ owner: gitHubRepoContext.owner, repo: gitHubRepoContext.name, - workflow_id: workflowIdForApi!, + workflow_id: workflowIdForApi!, per_page: 1 }); const newLatestRunId = result.data.workflow_runs[0]?.id; + log(`Latest run ID found: ${newLatestRunId} (Previous: ${latestRunId})`); + if (newLatestRunId && newLatestRunId !== latestRunId) { log(`Found new workflow run: ${newLatestRunId}. Triggering refresh and polling.`); await vscode.commands.executeCommand("github-actions.explorer.refresh"); From 964065cb5993097f95f00d10e1d3712056c3456e Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 15:24:14 -0500 Subject: [PATCH 09/16] Fix #229: Auto-poll active runs and respect window focus --- src/extension.ts | 7 +++++++ src/store/store.ts | 19 ++++++++++++++++++- src/treeViews/workflowRunTreeDataProvider.ts | 12 ++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index d1fdd50..dbee6d2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -62,6 +62,13 @@ export async function activate(context: vscode.ExtensionContext) { const store = new RunStore(); + // Handle focus changes to pause/resume polling + context.subscriptions.push( + vscode.window.onDidChangeWindowState(e => { + store.setFocused(e.focused); + }) + ); + // Pinned workflows await initPinnedWorkflows(store); diff --git a/src/store/store.ts b/src/store/store.ts index d09f1fc..414101a 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -20,6 +20,12 @@ type Updater = { export class RunStore extends EventEmitter { private runs = new Map(); private updaters = new Map(); + private _isFocused = true; + + setFocused(focused: boolean) { + this._isFocused = focused; + logDebug(`[Store]: Focus state changed to ${focused}`); + } getRun(runId: number): WorkflowRun | undefined { return this.runs.get(runId); @@ -66,6 +72,10 @@ export class RunStore extends EventEmitter { } private async fetchRun(updater: Updater) { + if (!this._isFocused) { + return; + } + log(`Fetching run update: ${updater.runId}. Remaining attempts: ${updater.remainingAttempts}`); updater.remainingAttempts--; @@ -87,7 +97,14 @@ export class RunStore extends EventEmitter { log(`Polled run: ${run.id} Status: ${run.status} Conclusion: ${run.conclusion}`); this.addRun(updater.repoContext, run); - if (run.status === "completed" || run.status === "cancelled" || run.status === "failure" || run.status === "success" || run.status === "skipped" || run.status === "timed_out") { + if ( + run.status === "completed" || + run.status === "cancelled" || + run.status === "failure" || + run.status === "success" || + run.status === "skipped" || + run.status === "timed_out" + ) { if (updater.handle) { clearInterval(updater.handle); } diff --git a/src/treeViews/workflowRunTreeDataProvider.ts b/src/treeViews/workflowRunTreeDataProvider.ts index 4ce67dd..9627c9f 100644 --- a/src/treeViews/workflowRunTreeDataProvider.ts +++ b/src/treeViews/workflowRunTreeDataProvider.ts @@ -24,6 +24,18 @@ export abstract class WorkflowRunTreeDataProvider { ): WorkflowRunNode[] { return runData.map(runData => { const workflowRun = this.store.addRun(gitHubRepoContext, runData); + + // Auto-poll active runs + if ( + workflowRun.run.status === "in_progress" || + workflowRun.run.status === "queued" || + workflowRun.run.status === "waiting" || + workflowRun.run.status === "requested" + ) { + // Poll every 4 seconds for up to 15 minutes (225 attempts) + this.store.pollRun(workflowRun.run.id, gitHubRepoContext, 4000, 225); + } + const node = new WorkflowRunNode( this.store, gitHubRepoContext, From 6fdb2edfcd383aa4f2a0874616fce962794632d7 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 15:29:35 -0500 Subject: [PATCH 10/16] Fix #229: Pause polling when Workflows view is not visible --- src/store/store.ts | 8 +++++++- src/treeViews/treeViews.ts | 10 +++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/store/store.ts b/src/store/store.ts index 414101a..036639a 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -21,12 +21,18 @@ export class RunStore extends EventEmitter { private runs = new Map(); private updaters = new Map(); private _isFocused = true; + private _isViewVisible = true; setFocused(focused: boolean) { this._isFocused = focused; logDebug(`[Store]: Focus state changed to ${focused}`); } + setViewVisible(visible: boolean) { + this._isViewVisible = visible; + logDebug(`[Store]: View visibility changed to ${visible}`); + } + getRun(runId: number): WorkflowRun | undefined { return this.runs.get(runId); } @@ -72,7 +78,7 @@ export class RunStore extends EventEmitter { } private async fetchRun(updater: Updater) { - if (!this._isFocused) { + if (!this._isFocused || !this._isViewVisible) { return; } diff --git a/src/treeViews/treeViews.ts b/src/treeViews/treeViews.ts index 6261b1b..2596d96 100644 --- a/src/treeViews/treeViews.ts +++ b/src/treeViews/treeViews.ts @@ -11,7 +11,15 @@ import {WorkflowsTreeProvider} from "./workflows"; export async function initTreeViews(context: vscode.ExtensionContext, store: RunStore): Promise { const workflowTreeProvider = new WorkflowsTreeProvider(store); - context.subscriptions.push(vscode.window.registerTreeDataProvider("github-actions.workflows", workflowTreeProvider)); + const workflowTreeView = vscode.window.createTreeView("github-actions.workflows", { + treeDataProvider: workflowTreeProvider + }); + context.subscriptions.push(workflowTreeView); + + store.setViewVisible(workflowTreeView.visible); + workflowTreeView.onDidChangeVisibility(e => { + store.setViewVisible(e.visible); + }); const settingsTreeProvider = new SettingsTreeProvider(); context.subscriptions.push(vscode.window.registerTreeDataProvider("github-actions.settings", settingsTreeProvider)); From 4c04b43f523f2c998225a2fa5563ef86143e58fb Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 15:39:30 -0500 Subject: [PATCH 11/16] Fix #229: Improve logging for focus and visibility state changes; refine run polling log output --- src/store/store.ts | 15 ++++----------- src/treeViews/workflows.ts | 3 ++- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/store/store.ts b/src/store/store.ts index 036639a..ea02570 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -25,12 +25,12 @@ export class RunStore extends EventEmitter { setFocused(focused: boolean) { this._isFocused = focused; - logDebug(`[Store]: Focus state changed to ${focused}`); + logDebug(`[Store]: Focus state changed to ${String(focused)}`); } setViewVisible(visible: boolean) { this._isViewVisible = visible; - logDebug(`[Store]: View visibility changed to ${visible}`); + logDebug(`[Store]: View visibility changed to ${String(visible)}`); } getRun(runId: number): WorkflowRun | undefined { @@ -100,17 +100,10 @@ export class RunStore extends EventEmitter { }); const run = result.data; - log(`Polled run: ${run.id} Status: ${run.status} Conclusion: ${run.conclusion}`); + log(`Polled run: ${run.id} Status: ${run.status || "null"} Conclusion: ${run.conclusion || "null"}`); this.addRun(updater.repoContext, run); - if ( - run.status === "completed" || - run.status === "cancelled" || - run.status === "failure" || - run.status === "success" || - run.status === "skipped" || - run.status === "timed_out" - ) { + if (run.status === "completed") { if (updater.handle) { clearInterval(updater.handle); } diff --git a/src/treeViews/workflows.ts b/src/treeViews/workflows.ts index b91a55b..51f4bcd 100644 --- a/src/treeViews/workflows.ts +++ b/src/treeViews/workflows.ts @@ -18,9 +18,10 @@ import {WorkflowNode} from "./workflows/workflowNode"; import {getWorkflowNodes, WorkflowsRepoNode} from "./workflows/workflowsRepoNode"; import {WorkflowStepNode} from "./workflows/workflowStepNode"; -type WorkflowsTreeNode = +export type WorkflowsTreeNode = | AuthenticationNode | NoGitHubRepositoryNode + | WorkflowsRepoNode | WorkflowNode | WorkflowRunNode | PreviousAttemptsNode From fc52ae598ef0a254379204bb9c46004a3054ed20 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Thu, 18 Dec 2025 15:48:01 -0500 Subject: [PATCH 12/16] Remove TEST_PLAN.md --- TEST_PLAN.md | 52 ---------------------------------------------------- 1 file changed, 52 deletions(-) delete mode 100644 TEST_PLAN.md diff --git a/TEST_PLAN.md b/TEST_PLAN.md deleted file mode 100644 index bf6489d..0000000 --- a/TEST_PLAN.md +++ /dev/null @@ -1,52 +0,0 @@ -# Test Plan for Issue #229 Fix - -## Objective -Verify that the GitHub Actions extension automatically refreshes the workflow run list after a user manually triggers a workflow run. - -## Prerequisites -1. A GitHub repository with GitHub Actions enabled. -2. A workflow file in that repository that supports `workflow_dispatch` (manual trigger). - * Example `workflow_dispatch` configuration in `.github/workflows/test.yml`: - ```yaml - name: Manual Test - on: workflow_dispatch - jobs: - build: - runs-on: ubuntu-latest - steps: - - run: echo "Hello World" - ``` -3. The repository is cloned locally and opened in VS Code. - -## Manual Test Steps - -1. **Launch Extension in Debug Mode**: - * Open the `vscode-github-actions` project in VS Code. - * Press `F5` or go to "Run and Debug" and select "Watch & Launch Extension". - * This will open a new "Extension Development Host" window. - -2. **Open Test Repository**: - * In the Extension Development Host window, open the folder of your test repository (from Prerequisites). - -3. **Navigate to GitHub Actions View**: - * Click on the GitHub Actions icon in the Activity Bar (sidebar). - * Expand the "Workflows" section. - * Find your manual workflow (e.g., "Manual Test"). - -4. **Trigger Workflow Run**: - * Right-click on the workflow name. - * Select **"Run Workflow"**. - * (Optional) If prompted for branch or inputs, provide them and confirm. - -5. **Verify Behavior**: - * **Immediate Feedback**: Look for a status bar message or notification saying "Waiting for workflow run to start...". - * **Auto-Refresh**: Watch the "Workflows" list. Within 1-20 seconds, the list should automatically refresh. - * **New Run**: A new workflow run (likely in "Queued" or "In Progress" state) should appear at the top of the list under the workflow. - -## Expected Result -* The user does **not** need to manually click the refresh button. -* The UI updates automatically once the new run is created on GitHub. - -## Troubleshooting -* If the run doesn't appear after 20 seconds, check if the workflow actually started on GitHub.com. -* Check the "Output" panel (select "GitHub Actions" in the dropdown) for any error logs. From a65e12fbae8124c0ca363b9c6135dff65bd2f378 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Fri, 19 Dec 2025 10:45:31 -0500 Subject: [PATCH 13/16] Fix lint errors: await promise, remove non-null assertion, fix template expression --- src/commands/triggerWorkflowRun.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/triggerWorkflowRun.ts b/src/commands/triggerWorkflowRun.ts index 923b010..d3339bd 100644 --- a/src/commands/triggerWorkflowRun.ts +++ b/src/commands/triggerWorkflowRun.ts @@ -169,7 +169,7 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, sto } if (dispatched) { - vscode.window.withProgress( + await vscode.window.withProgress( { location: vscode.ProgressLocation.Window, title: "Waiting for workflow run to start..." @@ -183,11 +183,11 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, sto const result = await gitHubRepoContext.client.actions.listWorkflowRuns({ owner: gitHubRepoContext.owner, repo: gitHubRepoContext.name, - workflow_id: workflowIdForApi!, + workflow_id: workflowIdForApi as string | number, per_page: 1 }); const newLatestRunId = result.data.workflow_runs[0]?.id; - log(`Latest run ID found: ${newLatestRunId} (Previous: ${latestRunId})`); + log(`Latest run ID found: ${newLatestRunId} (Previous: ${latestRunId ?? 'none'})`); if (newLatestRunId && newLatestRunId !== latestRunId) { log(`Found new workflow run: ${newLatestRunId}. Triggering refresh and polling.`); From a08153ab159f3e33bbb42774f080bf83d24af744 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Fri, 19 Dec 2025 10:47:00 -0500 Subject: [PATCH 14/16] Fix prettier formatting --- src/commands/triggerWorkflowRun.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/triggerWorkflowRun.ts b/src/commands/triggerWorkflowRun.ts index d3339bd..ee2f33c 100644 --- a/src/commands/triggerWorkflowRun.ts +++ b/src/commands/triggerWorkflowRun.ts @@ -187,7 +187,7 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, sto per_page: 1 }); const newLatestRunId = result.data.workflow_runs[0]?.id; - log(`Latest run ID found: ${newLatestRunId} (Previous: ${latestRunId ?? 'none'})`); + log(`Latest run ID found: ${newLatestRunId} (Previous: ${latestRunId ?? "none"})`); if (newLatestRunId && newLatestRunId !== latestRunId) { log(`Found new workflow run: ${newLatestRunId}. Triggering refresh and polling.`); From c358f6ee5444698bf73d5711bdb7d798749da2da Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Fri, 19 Dec 2025 10:51:12 -0500 Subject: [PATCH 15/16] Update src/commands/triggerWorkflowRun.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/commands/triggerWorkflowRun.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/commands/triggerWorkflowRun.ts b/src/commands/triggerWorkflowRun.ts index ee2f33c..9035d92 100644 --- a/src/commands/triggerWorkflowRun.ts +++ b/src/commands/triggerWorkflowRun.ts @@ -177,7 +177,9 @@ export function registerTriggerWorkflowRun(context: vscode.ExtensionContext, sto async () => { log("Starting loop to check for new workflow run..."); for (let i = 0; i < 20; i++) { - await new Promise(resolve => setTimeout(resolve, 1000)); + if (i > 0) { + await new Promise(resolve => setTimeout(resolve, 1000)); + } try { log(`Checking for new run (attempt ${i + 1}/20)...`); const result = await gitHubRepoContext.client.actions.listWorkflowRuns({ From a909e5938e667f5d1fabc826e935185de764b852 Mon Sep 17 00:00:00 2001 From: Shayne Boyer Date: Fri, 19 Dec 2025 10:54:03 -0500 Subject: [PATCH 16/16] Update src/treeViews/treeViews.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/treeViews/treeViews.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/treeViews/treeViews.ts b/src/treeViews/treeViews.ts index 2596d96..f75c569 100644 --- a/src/treeViews/treeViews.ts +++ b/src/treeViews/treeViews.ts @@ -17,9 +17,11 @@ export async function initTreeViews(context: vscode.ExtensionContext, store: Run context.subscriptions.push(workflowTreeView); store.setViewVisible(workflowTreeView.visible); - workflowTreeView.onDidChangeVisibility(e => { - store.setViewVisible(e.visible); - }); + context.subscriptions.push( + workflowTreeView.onDidChangeVisibility(e => { + store.setViewVisible(e.visible); + }) + ); const settingsTreeProvider = new SettingsTreeProvider(); context.subscriptions.push(vscode.window.registerTreeDataProvider("github-actions.settings", settingsTreeProvider));