Skip to content

Conversation

@aiday-mar
Copy link
Contributor

No description provided.

Copilot AI review requested due to automatic review settings December 5, 2025 12:54
@aiday-mar aiday-mar self-assigned this Dec 5, 2025
Copilot finished reviewing on behalf of aiday-mar December 5, 2025 12:58
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new VS Code extension for Slack workspace integration that enables code review workflows directly within VS Code. The extension provides a tree view to display Slack messages from a #codereview channel, with special handling for GitHub pull request links.

Key changes:

  • Complete extension implementation with authentication, message fetching, and PR integration
  • OAuth-based Slack authentication with session management
  • GitHub API integration for fetching PR metadata
  • Tree view UI for displaying code review messages

Reviewed changes

Copilot reviewed 14 out of 16 changed files in this pull request and generated 28 comments.

Show a summary per file
File Description
tsconfig.json TypeScript configuration for the extension
src/test/extension.test.ts Placeholder test suite (needs comprehensive tests)
src/slackTreeDataProvider.ts Tree view data provider for Slack messages UI
src/slackService.ts Core service for Slack API communication and GitHub integration
src/slackAuthenticationProvider.ts OAuth authentication provider for Slack
src/extension.ts Extension entry point with command and view registration
package.json Extension manifest with commands, views, and dependencies
oauth-redirect/index.html OAuth callback page for handling Slack authentication
oauth-redirect/.gitignore Ignore file for deployment artifacts
eslint.config.mjs ESLint configuration
esbuild.js Build configuration with environment variable injection
.vscode/launch.json VS Code debugging configuration
.gitignore Added .env files to gitignore

Comment on lines 149 to 163
async fetchMessages(): Promise<void> {
this.isLoading = true;
this.errorMessage = undefined;
this.refresh();

try {
this.messages = await this.slackService.getMessages();
} catch (error) {
this.errorMessage = error instanceof Error ? error.message : 'Unknown error';
this.messages = [];
} finally {
this.isLoading = false;
this.refresh();
this.onMessageCountChanged?.(this.messages.length);
}
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential race condition: if fetchMessages() is called multiple times concurrently (e.g., from auto-refresh and manual refresh), the isLoading flag could be set incorrectly. The second call would set isLoading = true again, but when either call completes, it sets isLoading = false, potentially allowing a third call to start before all previous calls have completed.

Consider using a promise-based approach to prevent concurrent fetches, or check if a fetch is already in progress before starting a new one.

Suggested change
async fetchMessages(): Promise<void> {
this.isLoading = true;
this.errorMessage = undefined;
this.refresh();
try {
this.messages = await this.slackService.getMessages();
} catch (error) {
this.errorMessage = error instanceof Error ? error.message : 'Unknown error';
this.messages = [];
} finally {
this.isLoading = false;
this.refresh();
this.onMessageCountChanged?.(this.messages.length);
}
private fetchMessagesPromise: Promise<void> | null = null;
async fetchMessages(): Promise<void> {
// Prevent concurrent fetches
if (this.fetchMessagesPromise) {
return this.fetchMessagesPromise;
}
this.isLoading = true;
this.errorMessage = undefined;
this.refresh();
this.fetchMessagesPromise = (async () => {
try {
this.messages = await this.slackService.getMessages();
} catch (error) {
this.errorMessage = error instanceof Error ? error.message : 'Unknown error';
this.messages = [];
} finally {
this.isLoading = false;
this.refresh();
this.onMessageCountChanged?.(this.messages.length);
this.fetchMessagesPromise = null;
}
})();
return this.fetchMessagesPromise;

Copilot uses AI. Check for mistakes.
Comment on lines 8 to 14
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');

test('Sample test', () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test suite only contains a basic sample test that doesn't test any actual functionality of the extension. Consider adding tests for the key functionality including:

  • SlackService authentication flows
  • SlackTreeDataProvider message fetching and display
  • Command handlers (sign in/out, open PR, refresh)
  • PR URL extraction and GitHub API integration
  • OAuth flow and state management

Copilot uses AI. Check for mistakes.

return session;
} catch (error) {
console.error('Failed to get Slack session:', error);
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Console.error statements should not be used in production code. Use a proper logging framework or VS Code output channels instead.

Copilot uses AI. Check for mistakes.
Comment on lines 3 to 16

export interface SlackMessage {
id: string;
author: string;
text: string;
timestamp: string;
prUrl?: string;
prTitle?: string;
prAuthor?: string;
prOwner?: string;
prRepo?: string;
prNumber?: number;
prAdditions?: number;
prDeletions?: number;
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing JSDoc documentation for the public interface SlackMessage and its properties. Since this interface is exported and used across multiple files, it should have documentation explaining the purpose of each field.

Example:

/**
 * Represents a message from the Slack code review channel.
 */
export interface SlackMessage {
    /** Unique identifier for the message (Slack timestamp) */
    id: string;
    /** Display name of the message author */
    author: string;
    // ... etc
}
Suggested change
export interface SlackMessage {
id: string;
author: string;
text: string;
timestamp: string;
prUrl?: string;
prTitle?: string;
prAuthor?: string;
prOwner?: string;
prRepo?: string;
prNumber?: number;
prAdditions?: number;
prDeletions?: number;
/**
* Represents a message from the Slack code review channel.
*/
export interface SlackMessage {
/** Unique identifier for the message (Slack timestamp) */
id: string;
/** Display name of the message author */
author: string;
/** The text content of the message */
text: string;
/** The timestamp of the message (ISO string or Slack format) */
timestamp: string;
/** The URL of the related pull request, if any */
prUrl?: string;
/** The title of the related pull request, if any */
prTitle?: string;
/** The author of the pull request (GitHub handle), if any */
prAuthor?: string;
/** The owner of the repository for the pull request, if any */
prOwner?: string;
/** The name of the repository for the pull request, if any */
prRepo?: string;
/** The pull request number, if any */
prNumber?: number;
/** Number of additions in the pull request, if any */
prAdditions?: number;
/** Number of deletions in the pull request, if any */
prDeletions?: number;
/** Number of changed files in the pull request, if any */

Copilot uses AI. Check for mistakes.
Comment on lines 34 to 41
export class SlackAuthenticationProvider implements vscode.AuthenticationProvider, vscode.Disposable {
private _sessionChangeEmitter = new vscode.EventEmitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
private _disposable: vscode.Disposable;
private _sessions: vscode.AuthenticationSession[] = [];
private _pendingAuth: PendingAuth | undefined;
private _sessionsLoaded: boolean = false;

constructor(private readonly context: vscode.ExtensionContext) {
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing JSDoc documentation for the exported SlackAuthenticationProvider class. This class implements the VS Code authentication provider interface and should document how it handles OAuth flow, session management, and URI callbacks.

Copilot uses AI. Check for mistakes.
try {
await vscode.env.openExternal(vscode.Uri.parse(item.message.prUrl));
} catch (error) {
console.error('Failed to open PR in browser:', error);
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Console.error statements should not be used in production code. Use a proper logging framework or VS Code output channels instead.

Copilot uses AI. Check for mistakes.
Comment on lines 24 to 53
"commands": [
{
"command": "vs-code-codereview.helloWorld",
"title": "Hello World"
},
{
"command": "vs-code-codereview.refreshMessages",
"title": "Refresh Messages",
"icon": "$(refresh)"
},
{
"command": "vs-code-codereview.signIn",
"title": "Sign in to Slack",
"icon": "$(sign-in)"
},
{
"command": "vs-code-codereview.signOut",
"title": "Sign out from Slack",
"icon": "$(sign-out)"
},
{
"command": "vs-code-codereview.openPrLocally",
"title": "Open PR Locally",
"icon": "$(link-external)"
},
{
"command": "vs-code-codereview.openPrInBrowser",
"title": "Open PR in Browser",
"icon": "$(globe)"
}
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The command naming convention is inconsistent with the extension ID. The commands use 'vs-code-codereview' prefix while the package name is 'vs-code-codereview', but the authentication provider and internal references use different variations. For consistency, consider standardizing on a single naming scheme throughout (e.g., all commands should use the same prefix format as defined in the package.json name).

Copilot uses AI. Check for mistakes.
Comment on lines 258 to 259
} catch {
// Fall back to username if user info fetch fails
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error handling swallows the actual error without logging it. At minimum, the error should be logged to help with debugging when fetching additional user details fails.

Suggested change
} catch {
// Fall back to username if user info fetch fails
} catch (err) {
// Fall back to username if user info fetch fails
console.error('Failed to fetch additional Slack user details:', err);

Copilot uses AI. Check for mistakes.
if (sessionsJson) {
try {
this._sessions = JSON.parse(sessionsJson);
} catch {
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error handling swallows the actual error without logging it. At minimum, the error should be logged to help with debugging when session loading fails.

Suggested change
} catch {
} catch (err) {
console.error('Failed to parse Slack sessions from secrets:', err);

Copilot uses AI. Check for mistakes.
Comment on lines 125 to 136
// Auto-refresh messages every 60 seconds
const REFRESH_INTERVAL_MS = 60 * 1000; // 1 minute
const autoRefreshInterval = setInterval(async () => {
const isAuthenticated = await slackService.isAuthenticated();
if (isAuthenticated) {
await slackTreeDataProvider.fetchMessages();
}
}, REFRESH_INTERVAL_MS);

// Clean up the interval when the extension is deactivated
context.subscriptions.push({
dispose: () => clearInterval(autoRefreshInterval)
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded 60-second refresh interval may be too aggressive for production use. Consider making this configurable via VS Code settings to allow users to adjust the polling frequency based on their needs. Frequent API calls could hit rate limits on both Slack and GitHub APIs.

Suggested change
// Auto-refresh messages every 60 seconds
const REFRESH_INTERVAL_MS = 60 * 1000; // 1 minute
const autoRefreshInterval = setInterval(async () => {
const isAuthenticated = await slackService.isAuthenticated();
if (isAuthenticated) {
await slackTreeDataProvider.fetchMessages();
}
}, REFRESH_INTERVAL_MS);
// Clean up the interval when the extension is deactivated
context.subscriptions.push({
dispose: () => clearInterval(autoRefreshInterval)
// Auto-refresh messages at a configurable interval
let refreshIntervalSeconds = vscode.workspace.getConfiguration('codereview-slack').get<number>('refreshIntervalSeconds', 60);
let autoRefreshInterval: NodeJS.Timeout | undefined;
const startAutoRefresh = () => {
if (autoRefreshInterval) {
clearInterval(autoRefreshInterval);
}
autoRefreshInterval = setInterval(async () => {
const isAuthenticated = await slackService.isAuthenticated();
if (isAuthenticated) {
await slackTreeDataProvider.fetchMessages();
}
}, refreshIntervalSeconds * 1000);
};
startAutoRefresh();
// Listen for configuration changes to update the interval dynamically
const configChangeDisposable = vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('codereview-slack.refreshIntervalSeconds')) {
refreshIntervalSeconds = vscode.workspace.getConfiguration('codereview-slack').get<number>('refreshIntervalSeconds', 60);
startAutoRefresh();
}
});
context.subscriptions.push(configChangeDisposable);
// Clean up the interval when the extension is deactivated
context.subscriptions.push({
dispose: () => {
if (autoRefreshInterval) {
clearInterval(autoRefreshInterval);
}
}

Copilot uses AI. Check for mistakes.
…build scripts, and add esbuild configuration

- Removed the "Hello World" command from package.json.
- Updated build scripts in package.json to use Gulp for compilation and watching.
- Added esbuild.mjs for building the extension with environment variable support.
- Enhanced command disposal in commands.ts and view.ts to call super.dispose().
- Updated mcp.json to include configuration for vscode-playwright-mcp server.
- Updated command identifiers for opening PRs to improve clarity.
- Removed the authentication provider implementation and moved it to a new file for better organization.
- Simplified command registration by reducing dependencies on the Slack service.
- Enhanced error handling and user feedback during authentication.
- Implemented auto-refresh for message fetching in the Slack tree data provider.
- Improved session management and caching for user and pull request data.
- Consolidated authentication variables into a dedicated module for easier configuration.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants