Skip to content

Commit 91db74f

Browse files
committed
Added combined workflow view
1 parent 8dd807b commit 91db74f

5 files changed

Lines changed: 235 additions & 1 deletion

File tree

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"name": "Watch & Launch extension",
66
"type": "extensionHost",
77
"request": "launch",
8-
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
8+
"args": ["--extensionDevelopmentPath=${workspaceFolder}", "${env:HOME}/theapp"],
99
"preLaunchTask": "npm: watch",
1010
"smartStep": true,
1111
"sourceMaps": true,

CLAUDE.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Github Actions for VSCode - patrickkidd fork
2+
3+
This is a simple fork project to add a combined workflow feature to this extension.
4+
5+
## Problem Description
6+
7+
I have a few repos that work together, common in micro services or backend / frontend / etc decoupling. I push often with continuous delivery. Right now you can only fit a single repo's workflows on screen in the workflows section at a time. There is no tool that simply shows all of your workflow builds in a master dashboard.
8+
9+
## Describe the solution you'd like
10+
11+
I would love to see a combined Workflows view that shows all builds for all repos in a single list, in the order that they were triggered.
12+
Optionally, some repo workflows trigger other workflows in another repo, and it would be great to have a visual representation of that, like an arrow from the triggering to the triggered or something.
13+
14+
## Additional context
15+
16+
Note how I have four related repos but expanding one takes up the entire screen, e.g. you can't even see the third and fourth repo. Further there is no chronological workflow ordering across repos.
17+
18+
## Your attitude and communication style
19+
20+
I am an experienced software architect of 25+ years with experience across many languages, domains, and tools. I am able to read and understand any programming language, having seen so many that they all look the same now. But I have no experience with node apps, let alone vscode plugins. I need a little hand-holding on how the architecture works, how to test the plugin, and and otherwise just want to vibe-code features into it.
21+
22+
## Development Setup & Testing
23+
24+
### First Time Setup
25+
26+
1. Install dependencies:
27+
```bash
28+
npm i
29+
```
30+
31+
### Testing Your Changes
32+
33+
1. Open VSCode in this directory
34+
2. Go to the Debug tab (Run and Debug icon on left sidebar)
35+
3. Select "Watch all & Launch Extension (workspace)" from the dropdown
36+
4. Hit the play button (F5)
37+
- This starts `npm watch` automatically to rebuild on file changes
38+
- Opens a new VSCode window called "Extension Development Host"
39+
5. Make your code changes
40+
6. To see changes, click the refresh button in the debug toolbar (or restart the debugger)
41+
- Wait for `npm watch` to finish rebuilding before testing
42+
7. The new "Combined Workflows" view should appear in the GitHub Actions sidebar
43+
44+
### Manual Build Commands
45+
46+
Build once:
47+
```bash
48+
npm run build
49+
```
50+
51+
Watch for changes:
52+
```bash
53+
npm run watch
54+
```
55+
56+
Run tests:
57+
```bash
58+
npm test
59+
```
60+
61+
Lint:
62+
```bash
63+
npm run lint
64+
```
65+
66+
Format code:
67+
```bash
68+
npm run format
69+
```
70+
71+
### Installing from Development Code
72+
73+
To install this development version as a real extension:
74+
75+
1. Package the extension:
76+
```bash
77+
npm run package
78+
```
79+
80+
2. This creates a `.vsix` file in the root directory
81+
82+
3. Install it in VSCode:
83+
- Open VSCode
84+
- Go to Extensions (Cmd+Shift+X)
85+
- Click the "..." menu at the top
86+
- Select "Install from VSIX..."
87+
- Choose the generated `.vsix` file
88+
89+
### Installing from GitHub (Your Fork)
90+
91+
To install from your GitHub fork instead of the official releases:
92+
93+
1. Push your changes to your fork on GitHub
94+
2. Create a release on your fork:
95+
- Go to your fork on GitHub
96+
- Click "Releases" → "Create a new release"
97+
- Tag it (e.g., `v0.28.2-combined-workflows`)
98+
- Attach the `.vsix` file (build it first with `npm run package`)
99+
3. Install from your release:
100+
- Download the `.vsix` from your release
101+
- Install via "Install from VSIX..." as described above
102+
103+
### Uninstalling
104+
105+
To switch back to the official version or test a fresh install:
106+
- Go to Extensions
107+
- Find "GitHub Actions"
108+
- Click Uninstall
109+
- Then reinstall from Marketplace or your `.vsix` file

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,11 @@
276276
"name": "Workflows",
277277
"when": "github-actions.internet-access && github-actions.signed-in && github-actions.has-repos"
278278
},
279+
{
280+
"id": "github-actions.combined-workflows",
281+
"name": "Combined Workflows",
282+
"when": "github-actions.internet-access && github-actions.signed-in && github-actions.has-repos"
283+
},
279284
{
280285
"id": "github-actions.settings",
281286
"name": "Settings",

src/treeViews/combinedWorkflows.ts

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import * as vscode from "vscode";
2+
3+
import {canReachGitHubAPI} from "../api/canReachGitHubAPI";
4+
import {getGitHubContext} from "../git/repository";
5+
import {logDebug, logError} from "../log";
6+
import {RunStore} from "../store/store";
7+
import {AttemptNode} from "./shared/attemptNode";
8+
import {AuthenticationNode} from "./shared/authenticationNode";
9+
import {ErrorNode} from "./shared/errorNode";
10+
import {GitHubAPIUnreachableNode} from "./shared/gitHubApiUnreachableNode";
11+
import {NoWorkflowJobsNode} from "./shared/noWorkflowJobsNode";
12+
import {PreviousAttemptsNode} from "./shared/previousAttemptsNode";
13+
import {WorkflowJobNode} from "./shared/workflowJobNode";
14+
import {WorkflowRunNode} from "./shared/workflowRunNode";
15+
import {WorkflowRunTreeDataProvider} from "./workflowRunTreeDataProvider";
16+
17+
type CombinedWorkflowsTreeNode =
18+
| AuthenticationNode
19+
| WorkflowRunNode
20+
| PreviousAttemptsNode
21+
| AttemptNode
22+
| WorkflowJobNode
23+
| NoWorkflowJobsNode
24+
| GitHubAPIUnreachableNode;
25+
26+
export class CombinedWorkflowsTreeProvider
27+
extends WorkflowRunTreeDataProvider
28+
implements vscode.TreeDataProvider<CombinedWorkflowsTreeNode>
29+
{
30+
private _onDidChangeTreeData = new vscode.EventEmitter<CombinedWorkflowsTreeNode | null>();
31+
readonly onDidChangeTreeData = this._onDidChangeTreeData.event;
32+
33+
constructor(store: RunStore) {
34+
super(store);
35+
}
36+
37+
protected _updateNode(node: WorkflowRunNode): void {
38+
this._onDidChangeTreeData.fire(node);
39+
}
40+
41+
async refresh(): Promise<void> {
42+
if (await canReachGitHubAPI()) {
43+
this._onDidChangeTreeData.fire(null);
44+
} else {
45+
await vscode.window.showWarningMessage("Unable to refresh, could not reach GitHub API");
46+
}
47+
}
48+
49+
getTreeItem(element: CombinedWorkflowsTreeNode): vscode.TreeItem | Thenable<vscode.TreeItem> {
50+
return element;
51+
}
52+
53+
async getChildren(element?: CombinedWorkflowsTreeNode | undefined): Promise<CombinedWorkflowsTreeNode[]> {
54+
if (!element) {
55+
logDebug("Getting combined workflow runs from all repos");
56+
57+
try {
58+
const gitHubContext = await getGitHubContext();
59+
if (!gitHubContext) {
60+
logDebug("could not get github context for combined workflows");
61+
return [new GitHubAPIUnreachableNode()];
62+
}
63+
64+
if (gitHubContext.repos.length === 0) {
65+
return [];
66+
}
67+
68+
const allRuns: WorkflowRunNode[] = [];
69+
70+
for (const repo of gitHubContext.repos) {
71+
try {
72+
const result = await repo.client.actions.listWorkflowRunsForRepo({
73+
owner: repo.owner,
74+
repo: repo.name,
75+
per_page: 20
76+
});
77+
78+
const runs = this.runNodes(repo, result.data.workflow_runs, true);
79+
allRuns.push(...runs);
80+
} catch (e) {
81+
logError(e as Error, `Failed to fetch runs for ${repo.owner}/${repo.name}`);
82+
}
83+
}
84+
85+
allRuns.sort((a, b) => {
86+
const aTime = new Date(a.run.run.created_at).getTime();
87+
const bTime = new Date(b.run.run.created_at).getTime();
88+
return bTime - aTime;
89+
});
90+
91+
return allRuns;
92+
} catch (e) {
93+
logError(e as Error, "Failed to get GitHub context");
94+
95+
if ((e as Error).message.startsWith("Could not get token from the GitHub authentication provider.")) {
96+
return [new AuthenticationNode()];
97+
}
98+
99+
return [new ErrorNode(`An error has occurred: ${(e as Error).message}`)];
100+
}
101+
}
102+
103+
if (element instanceof WorkflowRunNode) {
104+
return element.getJobs();
105+
} else if (element instanceof PreviousAttemptsNode) {
106+
return element.getAttempts();
107+
} else if (element instanceof AttemptNode) {
108+
return element.getJobs();
109+
} else if (element instanceof WorkflowJobNode) {
110+
return element.getSteps();
111+
}
112+
113+
return [];
114+
}
115+
}

src/treeViews/treeViews.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {executeCacheClearCommand} from "../workflow/languageServer";
55
import {getGitHubContext} from "../git/repository";
66
import {logDebug} from "../log";
77
import {RunStore} from "../store/store";
8+
import {CombinedWorkflowsTreeProvider} from "./combinedWorkflows";
89
import {CurrentBranchTreeProvider} from "./currentBranch";
910
import {SettingsTreeProvider} from "./settings";
1011
import {WorkflowsTreeProvider} from "./workflows";
@@ -13,6 +14,9 @@ export async function initTreeViews(context: vscode.ExtensionContext, store: Run
1314
const workflowTreeProvider = new WorkflowsTreeProvider(store);
1415
context.subscriptions.push(vscode.window.registerTreeDataProvider("github-actions.workflows", workflowTreeProvider));
1516

17+
const combinedWorkflowsTreeProvider = new CombinedWorkflowsTreeProvider(store);
18+
context.subscriptions.push(vscode.window.registerTreeDataProvider("github-actions.combined-workflows", combinedWorkflowsTreeProvider));
19+
1620
const settingsTreeProvider = new SettingsTreeProvider();
1721
context.subscriptions.push(vscode.window.registerTreeDataProvider("github-actions.settings", settingsTreeProvider));
1822

@@ -32,6 +36,7 @@ export async function initTreeViews(context: vscode.ExtensionContext, store: Run
3236

3337
if (canReachAPI && hasGitHubRepos) {
3438
await workflowTreeProvider.refresh();
39+
await combinedWorkflowsTreeProvider.refresh();
3540
await settingsTreeProvider.refresh();
3641
}
3742
await executeCacheClearCommand();

0 commit comments

Comments
 (0)