Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
# GitHub Actions for VS Code

> **🐛 Actions Job Debugger (Preview):** To try the latest debugger build, download the `.vsix` artifact from the most recent [Build Debugger Extension](https://github.com/github/vscode-github-actions/actions/workflows/debugger-build.yml) workflow run. On the workflow run page, scroll to **Artifacts** and download **vscode-github-actions-debugger**. Then install it in VS Code by running `code --install-extension <path-to-downloaded.vsix>` or via the Extensions view → `⋯` menu → **Install from VSIX…**.
> **🐛 Actions Job Debugger (Preview):** The debugger preview is intentionally off by default. To try the latest debugger build, download the `.vsix` artifact from the most recent [Build Debugger Extension](https://github.com/github/vscode-github-actions/actions/workflows/debugger-build.yml) workflow run. On the workflow run page, scroll to **Artifacts** and download **vscode-github-actions-debugger**. Then install it in VS Code by running `code --install-extension <path-to-downloaded.vsix>` or via the Extensions view → `⋯` menu → **Install from VSIX…**.
>
> Once installed, open the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) and run **GitHub Actions: Connect to Actions Job Debugger…**. Paste the `wss://` tunnel URL from a debug-mode job and the extension will open a full debug session using your current GitHub credentials.
> Next, manually enable the preview in `settings.json`:
>
> ```json
> {
> "github-actions.debugger.enabled": true
> }
> ```
>
> This opt-in is currently settings.json-only, so VS Code may show it as an unknown setting. After saving the change, reload VS Code. If you enable it in an empty or no-folder window, reload manually because the extension cannot prompt until it activates. Once the window reloads, open the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) and run **GitHub Actions: Debug Running Job…**. Paste the Actions job URL from a debug-mode job and the extension will open a full debug session using your current GitHub credentials.

The GitHub Actions extension lets you manage your workflows, view the workflow run history, and helps with authoring workflows.

Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,10 @@
{
"command": "github-actions.sign-in",
"when": "false"
},
{
"command": "github-actions.debugger.connect",
"when": "config.github-actions.debugger.enabled && !isWeb"
}
Comment thread
Copilot marked this conversation as resolved.
]
}
Expand Down
48 changes: 47 additions & 1 deletion src/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ import {resetGitHubContext} from "../git/repository";

const settingsKey = "github-actions";
const DEFAULT_GITHUB_API = "https://api.github.com";
const reloadWindowAction = "Reload Window";
const debuggerEnabledSettingsKey = getSettingsKey("debugger.enabled");

let debuggerSettingReloadPromptVisible = false;

export function initConfiguration(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration(async e => {
if (e.affectsConfiguration(getSettingsKey("workflows.pinned"))) {
pinnedWorkflowsChangeHandlers.forEach(h => h());
} else if (
}

if (
e.affectsConfiguration(getSettingsKey("use-enterprise")) ||
(useEnterprise() &&
(e.affectsConfiguration("github-enterprise.uri") || e.affectsConfiguration(getSettingsKey("remote-name"))))
Expand All @@ -19,6 +25,10 @@ export function initConfiguration(context: vscode.ExtensionContext) {
resetGitHubContext();
await vscode.commands.executeCommand("github-actions.explorer.refresh");
}

if (e.affectsConfiguration(debuggerEnabledSettingsKey)) {
await promptToReloadForDebuggerSettingChange(context);
}
})
);
}
Expand Down Expand Up @@ -64,6 +74,10 @@ export function getRemoteName(): string {
return getConfiguration().get<string>(getSettingsKey("remote-name"), "origin");
}

export function isDebuggerEnabled(): boolean {
return getConfiguration().get<boolean>(debuggerEnabledSettingsKey, false);
}

export function useEnterprise(): boolean {
return getConfiguration().get<boolean>(getSettingsKey("use-enterprise"), false);
}
Expand All @@ -87,3 +101,35 @@ async function updateLanguageServerApiUrl(context: vscode.ExtensionContext) {

await initLanguageServer(context);
}

async function promptToReloadForDebuggerSettingChange(context: vscode.ExtensionContext) {
if (vscode.env.uiKind !== vscode.UIKind.Desktop) {
return;
}

if (debuggerSettingReloadPromptVisible) {
return;
}

debuggerSettingReloadPromptVisible = true;

try {
if (context.extensionMode !== vscode.ExtensionMode.Production) {
await vscode.window.showInformationMessage(
"Reload VS Code manually to apply the GitHub Actions debugger preview setting change. Automatic reload is disabled in the Extension Development Host."
);
return;
}

const selection = await vscode.window.showInformationMessage(
"Reload VS Code to apply the GitHub Actions debugger preview setting change.",
reloadWindowAction
);

if (selection === reloadWindowAction) {
await vscode.commands.executeCommand("workbench.action.reloadWindow");
}
} finally {
debuggerSettingReloadPromptVisible = false;
}
}
43 changes: 42 additions & 1 deletion src/debugger/debugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,34 @@ import * as crypto from "crypto";
import * as vscode from "vscode";
import {getClient} from "../api/api";
import {getSession, newSession} from "../auth/auth";
import {getGitHubApiUri} from "../configuration/configuration";
import {getGitHubApiUri, isDebuggerEnabled} from "../configuration/configuration";
import {log, logDebug, logError} from "../log";
import {parseJobUrl} from "./jobUrl";
import {validateTunnelUrl} from "./tunnelUrl";
import {WebSocketDapAdapter} from "./webSocketDapAdapter";

export const DEBUG_TYPE = "github-actions-job";
const debuggerEnabledSettingSnippet = `"github-actions.debugger.enabled": true`;
const emptyWindowManualReloadMessage =
"If you enable it in an empty window, reload VS Code manually because the extension cannot prompt until it activates.";

let debuggerRegistered = false;

/**
* Extension-private token store keyed by one-time nonce. Tokens are never
* placed in DebugConfiguration (readable by other extensions).
*/
const pendingTokens = new Map<string, string>();

export function registerDebuggerAvailabilityGuard(context: vscode.ExtensionContext): void {
context.subscriptions.push(
vscode.debug.registerDebugConfigurationProvider(DEBUG_TYPE, new ActionsDebugConfigurationProvider())
);
}

export function registerDebugger(context: vscode.ExtensionContext): void {
debuggerRegistered = true;

context.subscriptions.push(
vscode.debug.registerDebugAdapterDescriptorFactory(DEBUG_TYPE, new ActionsDebugAdapterFactory())
);
Expand All @@ -30,6 +43,34 @@ export function registerDebugger(context: vscode.ExtensionContext): void {
);
}

class ActionsDebugConfigurationProvider implements vscode.DebugConfigurationProvider {
resolveDebugConfiguration(
_folder: vscode.WorkspaceFolder | undefined,
debugConfiguration: vscode.DebugConfiguration
): vscode.DebugConfiguration | null {
if (vscode.env.uiKind !== vscode.UIKind.Desktop) {
void vscode.window.showInformationMessage("GitHub Actions job debugging is only available in desktop VS Code.");
return null;
}

if (!isDebuggerEnabled()) {
void vscode.window.showInformationMessage(
`GitHub Actions job debugging is currently disabled. Add ${debuggerEnabledSettingSnippet} to settings.json and reload VS Code to enable it. ${emptyWindowManualReloadMessage}`
);
return null;
}

if (!debuggerRegistered) {
void vscode.window.showInformationMessage(
`GitHub Actions job debugging was enabled, but VS Code must be reloaded before the debugger can be used. ${emptyWindowManualReloadMessage}`
);
return null;
}

return debugConfiguration;
}
}

async function connectToDebugger(): Promise<void> {
const rawUrl = await vscode.window.showInputBox({
title: "Connect to Actions Job Debugger",
Expand Down
8 changes: 5 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {registerAddVariable} from "./commands/variables/addVariable";
import {registerCopyVariable} from "./commands/variables/copyVariable";
import {registerDeleteVariable} from "./commands/variables/deleteVariable";
import {registerUpdateVariable} from "./commands/variables/updateVariable";
import {initConfiguration} from "./configuration/configuration";
import {initConfiguration, isDebuggerEnabled} from "./configuration/configuration";
import {getGitHubContext} from "./git/repository";
import {init as initLogger, log, revealLog} from "./log";
import {LogScheme} from "./logs/constants";
Expand All @@ -34,7 +34,7 @@ import {initResources} from "./treeViews/icons";
import {initTreeViews} from "./treeViews/treeViews";
import {deactivateLanguageServer, initLanguageServer} from "./workflow/languageServer";
import {registerSignIn} from "./commands/signIn";
import {registerDebugger} from "./debugger/debugger";
import {registerDebugger, registerDebuggerAvailabilityGuard} from "./debugger/debugger";

export async function activate(context: vscode.ExtensionContext) {
initLogger();
Expand All @@ -47,6 +47,7 @@ export async function activate(context: vscode.ExtensionContext) {
// Prefetch git repository origin url
const ghContext = hasSession && (await getGitHubContext());
const hasGitHubRepos = ghContext && ghContext.repos.length > 0;
const debuggerEnabled = vscode.env.uiKind === vscode.UIKind.Desktop && isDebuggerEnabled();

await Promise.all([
vscode.commands.executeCommand("setContext", "github-actions.signed-in", hasSession),
Expand Down Expand Up @@ -92,9 +93,10 @@ export async function activate(context: vscode.ExtensionContext) {
registerUnPinWorkflow(context);

registerSignIn(context);
registerDebuggerAvailabilityGuard(context);

// Debugger — only available in Desktop VS Code (requires Node.js for WebSocket)
if (vscode.env.uiKind === vscode.UIKind.Desktop) {
if (debuggerEnabled) {
registerDebugger(context);
}

Expand Down
Loading