From 4d9babd8fb4564e3ab5271f39b9dfab32dd3508d Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Fri, 6 Mar 2026 18:37:16 +0800 Subject: [PATCH 01/10] feat(lsp): add getFileOwnership command and refactor inlay hints --- codeinput/src/lsp/commands.rs | 8 ++ codeinput/src/lsp/handlers.rs | 176 +++++++++++----------------------- 2 files changed, 64 insertions(+), 120 deletions(-) diff --git a/codeinput/src/lsp/commands.rs b/codeinput/src/lsp/commands.rs index 2c35a89..ab541d1 100644 --- a/codeinput/src/lsp/commands.rs +++ b/codeinput/src/lsp/commands.rs @@ -7,6 +7,13 @@ use super::server::LspServer; use super::types::*; impl LspServer { + pub async fn get_file_ownership_command(&self, uri_str: String) -> LspResult> { + let Ok(uri) = Url::parse(&uri_str) else { + return Err(tower_lsp::jsonrpc::Error::invalid_params("Invalid URI")); + }; + Ok(self.get_file_ownership(&uri).await) + } + pub async fn list_files(&self, workspace_uri: Option) -> LspResult { let workspaces = self.workspaces.read().await; @@ -107,3 +114,4 @@ impl LspServer { } } + diff --git a/codeinput/src/lsp/handlers.rs b/codeinput/src/lsp/handlers.rs index 4b6d55f..731c44c 100644 --- a/codeinput/src/lsp/handlers.rs +++ b/codeinput/src/lsp/handlers.rs @@ -51,6 +51,7 @@ impl LanguageServer for LspServer { "codeinput.listFiles".to_string(), "codeinput.listOwners".to_string(), "codeinput.listTags".to_string(), + "codeinput.getFileOwnership".to_string(), ], work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None, @@ -287,145 +288,73 @@ impl LanguageServer for LspServer { async fn inlay_hint(&self, params: InlayHintParams) -> LspResult>> { let file_uri = params.text_document.uri; - self.client - .log_message( - MessageType::INFO, - format!("inlay_hint called for: {}", file_uri), - ) - .await; - - // Only show inlay hints in CODEOWNERS files let path = uri_to_path(&file_uri); - if let Ok(path) = path { - let file_name = path - .file_name() - .map(|n| n.to_string_lossy()) - .unwrap_or_default(); - self.client - .log_message(MessageType::INFO, format!("file_name: {}", file_name)) - .await; - if file_name.to_lowercase() != "codeowners" { - self.client - .log_message(MessageType::INFO, "Not a CODEOWNERS file, skipping") - .await; - return Ok(None); - } - } else { - self.client - .log_message(MessageType::WARNING, "Failed to convert URI to path") - .await; + let file_path = match path { + Ok(p) => p, + Err(_) => return Ok(None), + }; + + if file_path.file_name().and_then(|n| n.to_str()).unwrap_or_default().to_lowercase() != "codeowners" { return Ok(None); } let workspaces = self.workspaces.read().await; - self.client - .log_message( - MessageType::INFO, - format!("Workspace count: {}", workspaces.len()), - ) - .await; - // Find the workspace that contains this file - for (root_uri, state) in workspaces.iter() { - self.client - .log_message( - MessageType::INFO, - format!("Checking workspace: {}", root_uri), - ) - .await; - let mut hints = vec![]; + for (_root_uri, state) in workspaces.iter() { + let file_entries: Vec<_> = state.cache.entries.iter() + .filter(|e| e.source_file == file_path) + .collect(); - let file_path = match uri_to_path(&file_uri) { - Ok(p) => p, + if file_entries.is_empty() { + continue; + } + + // Read the CODEOWNERS file content asynchronously to get line lengths + let content = match tokio::fs::read_to_string(&file_path).await { + Ok(c) => c, Err(_) => continue, }; - // Read the CODEOWNERS file content - if let Ok(content) = std::fs::read_to_string(&file_path) { - self.client - .log_message( - MessageType::INFO, - format!("Read CODEOWNERS file, {} lines", content.lines().count()), - ) - .await; - for (line_num, line) in content.lines().enumerate() { - let trimmed = line.trim(); + let lines: Vec<&str> = content.lines().collect(); + let mut hints = vec![]; - // Skip empty lines and comments - if trimmed.is_empty() || trimmed.starts_with('#') { - continue; - } + for entry in file_entries { + let line_idx = if entry.line_number > 0 { entry.line_number - 1 } else { 0 }; + let line_length = lines.get(line_idx).map(|l| l.len() as u32).unwrap_or(0); - // Parse pattern from line - let parts: Vec<&str> = trimmed.split_whitespace().collect(); - if !parts.is_empty() { - let pattern = parts[0]; - - // Count files matching this pattern using the cache - let match_count = state - .cache - .entries - .iter() - .filter(|entry| { - let rel_path = entry.source_file.to_string_lossy(); - // Simple pattern matching - if pattern == "*" { - return true; - } - if pattern.ends_with('/') { - let dir_pattern = &pattern[..pattern.len() - 1]; - rel_path.starts_with(dir_pattern) - } else if pattern.starts_with('*') { - let suffix = &pattern[1..]; - rel_path.ends_with(suffix) - } else if pattern.ends_with("/*") { - let prefix = &pattern[..pattern.len() - 2]; - rel_path.starts_with(prefix) - } else { - rel_path.contains(pattern.trim_start_matches('/')) - } - }) - .count(); - - if match_count > 0 { - let line_length = line.len() as u32; - hints.push(InlayHint { - position: Position::new(line_num as u32, line_length), - label: InlayHintLabel::String(format!( - " {} file{}", - match_count, - if match_count == 1 { "" } else { "s" } - )), - kind: Some(InlayHintKind::TYPE), - text_edits: None, - tooltip: Some(InlayHintTooltip::String(format!( - "This pattern matches {} file(s) in the repository", - match_count - ))), - padding_left: Some(true), - padding_right: Some(false), - data: None, - }); - } + let matcher = crate::core::types::codeowners_entry_to_matcher(entry); + + let mut match_count = 0; + for file_entry in &state.cache.files { + if matcher.override_matcher.matched(&file_entry.path, false).is_whitelist() { + match_count += 1; } } - self.client - .log_message( - MessageType::INFO, - format!("Generated {} inlay hints", hints.len()), - ) - .await; + hints.push(InlayHint { + position: Position::new(line_idx as u32, line_length), + label: InlayHintLabel::String(format!( + " {} file{}", + match_count, + if match_count == 1 { "" } else { "s" } + )), + kind: Some(InlayHintKind::TYPE), + text_edits: None, + tooltip: Some(InlayHintTooltip::String(format!( + "This pattern matches {} file(s) in the repository", + match_count + ))), + padding_left: Some(true), + padding_right: Some(false), + data: None, + }); + } + + if !hints.is_empty() { return Ok(Some(hints)); } } - self.client - .log_message( - MessageType::WARNING, - "No workspace found for CODEOWNERS file", - ) - .await; Ok(None) } @@ -459,6 +388,13 @@ impl LanguageServer for LspServer { } match params.command.as_str() { + "codeinput.getFileOwnership" => { + let uri_val = params.arguments.first().and_then(|v| v.as_str()).ok_or_else(|| { + tower_lsp::jsonrpc::Error::invalid_params("Expected a single URI string argument") + })?; + let result = self.get_file_ownership_command(uri_val.to_string()).await?; + to_value(result).map(Some) + } "codeinput.listFiles" => { let result = self.list_files(None).await?; to_value(result).map(Some) From c25166ce2395ca2e9aa969b6220356bc92fd6aa6 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Fri, 6 Mar 2026 19:16:24 +0800 Subject: [PATCH 02/10] refactor(vscode): simplify extension by removing unused features and streamlining code Remove addOwner command, simplify binary path resolution, use LSP command for ownership info instead of hover parsing, and streamline status bar display. --- extensions/vscode/package.json | 9 ----- extensions/vscode/src/client.ts | 63 +++++------------------------ extensions/vscode/src/extension.ts | 64 ++++++------------------------ extensions/vscode/src/statusbar.ts | 40 ++----------------- 4 files changed, 25 insertions(+), 151 deletions(-) diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json index e728742..e7770d5 100644 --- a/extensions/vscode/package.json +++ b/extensions/vscode/package.json @@ -37,11 +37,6 @@ "title": "Show CODEOWNERS Tags", "category": "CodeInput" }, - { - "command": "codeinput.addOwner", - "title": "Add CODEOWNERS Entry", - "category": "CodeInput" - }, { "command": "codeinput.refreshCache", "title": "Refresh CODEOWNERS Cache", @@ -101,10 +96,6 @@ { "command": "codeinput.showTags", "when": "false" - }, - { - "command": "codeinput.addOwner", - "when": "false" } ] } diff --git a/extensions/vscode/src/client.ts b/extensions/vscode/src/client.ts index 8aa5287..69bf333 100644 --- a/extensions/vscode/src/client.ts +++ b/extensions/vscode/src/client.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; import { + ExecuteCommandRequest, LanguageClient, LanguageClientOptions, ServerOptions, @@ -9,7 +10,7 @@ import { export interface FileOwnershipInfo { path: string; owners: Array<{ identifier: string; owner_type: string }>; - tags: Array<{ 0: string }>; + tags: string[]; is_unowned: boolean; } @@ -97,68 +98,22 @@ export class CodeInputClient { return undefined; } - // Use the hover request to get ownership info try { - const hover = await this.client.sendRequest('textDocument/hover', { - textDocument: { uri: uri.toString() }, - position: { line: 0, character: 0 } - }) as any; + const info = await this.client.sendRequest(ExecuteCommandRequest.type, { + command: 'codeinput.getFileOwnership', + arguments: [uri.toString()] + }) as FileOwnershipInfo | null | undefined; - if (hover && hover.contents) { - // Parse hover contents to extract ownership info - return this.parseHoverContents(hover.contents, uri); + if (info) { + return info; } } catch (error) { - console.error('Error getting file ownership:', error); + console.error('[CodeInput Client] Error:', error); } return undefined; } - private parseHoverContents(contents: any, uri: vscode.Uri): FileOwnershipInfo | undefined { - // The LSP server returns hover contents with owners and tags - // This is a simplified parser - in production you'd want more robust parsing - const info: FileOwnershipInfo = { - path: uri.fsPath, - owners: [], - tags: [], - is_unowned: false - }; - - if (Array.isArray(contents)) { - for (const item of contents) { - if (typeof item === 'string') { - if (item.includes('Owners:')) { - const ownersMatch = item.match(/\*\*Owners:\*\* (.+)/); - if (ownersMatch) { - const ownersStr = ownersMatch[1]; - if (ownersStr !== '(none)') { - info.owners = ownersStr.split(', ').map(o => ({ - identifier: o.replace(/`/g, ''), - owner_type: 'Unknown' - })); - } - } - } - if (item.includes('Tags:')) { - const tagsMatch = item.match(/\*\*Tags:\*\* (.+)/); - if (tagsMatch) { - const tagsStr = tagsMatch[1]; - info.tags = tagsStr.split(', ').map(t => ({ - 0: t.replace(/`#/g, '').replace(/`/g, '') - })); - } - } - if (item.includes('Warning')) { - info.is_unowned = true; - } - } - } - } - - return info; - } - public isRunning(): boolean { return this.client?.isRunning() === true; } diff --git a/extensions/vscode/src/extension.ts b/extensions/vscode/src/extension.ts index 902dd94..2c64616 100644 --- a/extensions/vscode/src/extension.ts +++ b/extensions/vscode/src/extension.ts @@ -12,7 +12,6 @@ async function checkBinary(binaryPath: string): Promise { const proc = spawn(binaryPath, ['lsp', '--help']); proc.on('error', () => resolve(false)); proc.on('exit', (code) => resolve(code === 0)); - // Timeout after 2 seconds setTimeout(() => { proc.kill(); resolve(false); @@ -23,31 +22,19 @@ async function checkBinary(binaryPath: string): Promise { export async function activate(context: vscode.ExtensionContext) { console.log('CodeInput extension is now active'); - // Check if custom binary path is set const config = vscode.workspace.getConfiguration('codeinput'); - const userBinaryPath = config.get('binaryPath', 'ci-lsp'); + const binaryPath = config.get('binaryPath', 'ci-lsp'); let finalBinaryPath: string | undefined; let binarySource = 'unknown'; - // If user set a custom path, use it - if (userBinaryPath !== 'ci-lsp') { - console.log(`[CodeInput] Checking user-specified binary: ${userBinaryPath}`); - const exists = await checkBinary(userBinaryPath); - if (exists) { - finalBinaryPath = userBinaryPath; - binarySource = 'user-config'; - console.log(`[CodeInput] Using user-specified binary: ${finalBinaryPath}`); - } else { - console.error(`[CodeInput] User-specified binary not found: ${userBinaryPath}`); - vscode.window.showErrorMessage( - `Custom binary not found: ${userBinaryPath}. Please check the path or install codeinput-lsp.` - ); - return; - } + const exists = await checkBinary(binaryPath); + if (exists) { + finalBinaryPath = binaryPath; + binarySource = 'config'; + console.log(`[CodeInput] Using binary from config: ${finalBinaryPath}`); } else { - // Try to download ci-lsp first - console.log('[CodeInput] Attempting to download ci-lsp binary...'); + console.log(`[CodeInput] Binary not found at ${binaryPath}, attempting to download...`); const downloader = new BinaryDownloader(context); const downloadedPath = await downloader.ensureBinary(); @@ -56,24 +43,11 @@ export async function activate(context: vscode.ExtensionContext) { binarySource = 'downloaded'; console.log(`[CodeInput] Using downloaded binary: ${finalBinaryPath}`); } else { - console.log('[CodeInput] Download failed, checking for existing ci binary with LSP support...'); - // Download failed, check if `ci` with LSP exists - const ciExists = await checkBinary('ci'); - if (ciExists) { - binarySource = 'fallback-ci'; - finalBinaryPath = 'ci'; - console.log('[CodeInput] Using fallback ci binary with LSP support'); - vscode.window.showInformationMessage( - 'Using existing `ci` binary with LSP support. Consider downloading `ci-lsp` for better performance.' - ); - } else { - // Neither works - console.error('[CodeInput] No usable binary found (tried downloading ci-lsp and using ci)'); - vscode.window.showErrorMessage( - 'codeinput-lsp not found. Please install it: curl -L https://github.com/code-input/cli/releases/latest/download/ci-lsp-linux-x64 -o ~/bin/ci-lsp && chmod +x ~/bin/ci-lsp' - ); - return; - } + console.error('[CodeInput] No usable binary found'); + vscode.window.showErrorMessage( + 'codeinput binary not found. Install it or set codeinput.binaryPath in settings.' + ); + return; } } @@ -152,20 +126,6 @@ export async function activate(context: vscode.ExtensionContext) { }) ); - context.subscriptions.push( - vscode.commands.registerCommand('codeinput.addOwner', async (uri: string) => { - const owner = await vscode.window.showInputBox({ - prompt: 'Enter owner (e.g., @username or @org/team)', - placeHolder: '@username' - }); - - if (owner) { - vscode.window.showInformationMessage(`Would add owner ${owner} to ${uri}`); - // TODO: Implement adding owner to CODEOWNERS file - } - }) - ); - // Handle configuration changes context.subscriptions.push( vscode.workspace.onDidChangeConfiguration(e => { diff --git a/extensions/vscode/src/statusbar.ts b/extensions/vscode/src/statusbar.ts index 40808d7..e3c872a 100644 --- a/extensions/vscode/src/statusbar.ts +++ b/extensions/vscode/src/statusbar.ts @@ -12,7 +12,6 @@ export class StatusBarManager implements vscode.Disposable { vscode.StatusBarAlignment.Right, 100 ); - this.statusBarItem.command = 'codeinput.showInfo'; // Update when active editor changes this.disposables.push( @@ -55,7 +54,6 @@ export class StatusBarManager implements vscode.Disposable { const fileUri = editor.document.uri; - // Only show for file:// URIs if (fileUri.scheme !== 'file') { this.statusBarItem.hide(); return; @@ -66,23 +64,16 @@ export class StatusBarManager implements vscode.Disposable { if (info) { if (info.is_unowned || info.owners.length === 0) { - this.statusBarItem.text = '$(warning) Unowned'; - this.statusBarItem.tooltip = 'This file has no CODEOWNERS assignment\nClick to see details'; + this.statusBarItem.text = '$(alert)'; + this.statusBarItem.tooltip = 'No CODEOWNERS'; this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); } else { - const ownerNames = info.owners.map(o => o.identifier).join(', '); - const ownerInitials = info.owners - .map(o => this.getInitials(o.identifier)) - .join(''); - - this.statusBarItem.text = `$(lock) ${ownerInitials}`; - this.statusBarItem.tooltip = `Owners: ${ownerNames}\nClick to see details`; + this.statusBarItem.text = '$(lock)'; + this.statusBarItem.tooltip = 'Has CODEOWNERS'; this.statusBarItem.backgroundColor = undefined; } - this.statusBarItem.show(); } else { - // No CODEOWNERS info available (file not in cache) this.statusBarItem.hide(); } } catch (error) { @@ -91,29 +82,6 @@ export class StatusBarManager implements vscode.Disposable { } } - private getInitials(identifier: string): string { - // Extract initials from owner identifier - // @org/team -> T, @username -> U, email@domain.com -> E - - if (identifier.startsWith('@')) { - // Handle @org/team format - const parts = identifier.split('/'); - if (parts.length > 1) { - return parts[parts.length - 1].charAt(0).toUpperCase(); - } - // Handle @username format - return identifier.charAt(1).toUpperCase(); - } - - if (identifier.includes('@')) { - // Email format - return identifier.charAt(0).toUpperCase(); - } - - // Fallback - return identifier.charAt(0).toUpperCase(); - } - public dispose(): void { this.statusBarItem.dispose(); this.disposables.forEach(d => d.dispose()); From 03783f2fa33971bb28ca56fa0c77855a00c357aa Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 13:37:49 +0800 Subject: [PATCH 03/10] refactor(lsp): remove unowned file warning CodeLens and apply formatting --- codeinput/src/lsp/handlers.rs | 63 ++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/codeinput/src/lsp/handlers.rs b/codeinput/src/lsp/handlers.rs index 731c44c..9be0de3 100644 --- a/codeinput/src/lsp/handlers.rs +++ b/codeinput/src/lsp/handlers.rs @@ -1,11 +1,11 @@ use serde::Serialize; use serde_json::Value; +use tower_lsp::LanguageServer; use tower_lsp::jsonrpc::Result as LspResult; use tower_lsp::lsp_types::*; -use tower_lsp::LanguageServer; use url::Url; -use super::server::{is_codeowners_file, uri_to_path, LspServer}; +use super::server::{LspServer, is_codeowners_file, uri_to_path}; #[tower_lsp::async_trait] impl LanguageServer for LspServer { @@ -260,25 +260,6 @@ impl LanguageServer for LspServer { } } - // Add unowned warning CodeLens - if info.is_unowned { - // Safely serialize arguments - if let Some(uri_val) = serde_json::to_value(file_uri.to_string()).ok() { - lenses.push(CodeLens { - range: Range { - start: Position::new(0, 0), - end: Position::new(0, 0), - }, - command: Some(Command { - title: "$(warning) Unowned file".to_string(), - command: "codeinput.addOwner".to_string(), - arguments: Some(vec![uri_val]), - }), - data: None, - }); - } - } - return Ok(Some(lenses)); } @@ -294,14 +275,23 @@ impl LanguageServer for LspServer { Err(_) => return Ok(None), }; - if file_path.file_name().and_then(|n| n.to_str()).unwrap_or_default().to_lowercase() != "codeowners" { + if file_path + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or_default() + .to_lowercase() + != "codeowners" + { return Ok(None); } let workspaces = self.workspaces.read().await; for (_root_uri, state) in workspaces.iter() { - let file_entries: Vec<_> = state.cache.entries.iter() + let file_entries: Vec<_> = state + .cache + .entries + .iter() .filter(|e| e.source_file == file_path) .collect(); @@ -319,14 +309,22 @@ impl LanguageServer for LspServer { let mut hints = vec![]; for entry in file_entries { - let line_idx = if entry.line_number > 0 { entry.line_number - 1 } else { 0 }; + let line_idx = if entry.line_number > 0 { + entry.line_number - 1 + } else { + 0 + }; let line_length = lines.get(line_idx).map(|l| l.len() as u32).unwrap_or(0); let matcher = crate::core::types::codeowners_entry_to_matcher(entry); - + let mut match_count = 0; for file_entry in &state.cache.files { - if matcher.override_matcher.matched(&file_entry.path, false).is_whitelist() { + if matcher + .override_matcher + .matched(&file_entry.path, false) + .is_whitelist() + { match_count += 1; } } @@ -389,9 +387,15 @@ impl LanguageServer for LspServer { match params.command.as_str() { "codeinput.getFileOwnership" => { - let uri_val = params.arguments.first().and_then(|v| v.as_str()).ok_or_else(|| { - tower_lsp::jsonrpc::Error::invalid_params("Expected a single URI string argument") - })?; + let uri_val = params + .arguments + .first() + .and_then(|v| v.as_str()) + .ok_or_else(|| { + tower_lsp::jsonrpc::Error::invalid_params( + "Expected a single URI string argument", + ) + })?; let result = self.get_file_ownership_command(uri_val.to_string()).await?; to_value(result).map(Some) } @@ -411,4 +415,3 @@ impl LanguageServer for LspServer { } } } - From e476d37a440aebbb02927e83e6cb5ccb97706efe Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 13:43:57 +0800 Subject: [PATCH 04/10] refactor(vscode): always show status bar item with ownership state --- extensions/vscode/src/statusbar.ts | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/extensions/vscode/src/statusbar.ts b/extensions/vscode/src/statusbar.ts index e3c872a..758ece4 100644 --- a/extensions/vscode/src/statusbar.ts +++ b/extensions/vscode/src/statusbar.ts @@ -62,23 +62,22 @@ export class StatusBarManager implements vscode.Disposable { try { const info = await this.client.getFileOwnership(fileUri); - if (info) { - if (info.is_unowned || info.owners.length === 0) { - this.statusBarItem.text = '$(alert)'; - this.statusBarItem.tooltip = 'No CODEOWNERS'; - this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); - } else { - this.statusBarItem.text = '$(lock)'; - this.statusBarItem.tooltip = 'Has CODEOWNERS'; - this.statusBarItem.backgroundColor = undefined; - } - this.statusBarItem.show(); + if (info && !info.is_unowned && info.owners.length > 0) { + this.statusBarItem.text = '$(lock)'; + this.statusBarItem.tooltip = 'Has CODEOWNERS'; + this.statusBarItem.backgroundColor = undefined; } else { - this.statusBarItem.hide(); + this.statusBarItem.text = '$(alert)'; + this.statusBarItem.tooltip = 'No CODEOWNERS'; + this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); } + this.statusBarItem.show(); } catch (error) { console.error('Error updating status bar:', error); - this.statusBarItem.hide(); + this.statusBarItem.text = '$(alert)'; + this.statusBarItem.tooltip = 'No CODEOWNERS'; + this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); + this.statusBarItem.show(); } } From f2399f7cb66fe5ad2ccaac382399c5fb9d03ec87 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 14:57:26 +0800 Subject: [PATCH 05/10] chore(vscode): prepare v0.1.0 release with docs and metadata --- extensions/vscode/.gitignore | 4 ++ extensions/vscode/.vscodeignore | 2 + extensions/vscode/.yarnrc.yml | 1 + extensions/vscode/CHANGELOG.md | 13 ++++++ extensions/vscode/LICENSE | 21 ++++++++++ extensions/vscode/README.md | 65 +++++++++++++++++++++++++++++ extensions/vscode/icon.png | Bin 0 -> 1634 bytes extensions/vscode/package.json | 33 +++++---------- extensions/vscode/src/extension.ts | 18 -------- 9 files changed, 116 insertions(+), 41 deletions(-) create mode 100644 extensions/vscode/.yarnrc.yml create mode 100644 extensions/vscode/CHANGELOG.md create mode 100644 extensions/vscode/LICENSE create mode 100644 extensions/vscode/README.md create mode 100644 extensions/vscode/icon.png diff --git a/extensions/vscode/.gitignore b/extensions/vscode/.gitignore index d61721c..d67180e 100644 --- a/extensions/vscode/.gitignore +++ b/extensions/vscode/.gitignore @@ -22,6 +22,7 @@ Thumbs.db # IDE .idea/ +.vscode/ *.swp *.swo @@ -31,3 +32,6 @@ coverage/ # Temporary files *.tmp *.temp + +# Yarn cache +.yarn/ diff --git a/extensions/vscode/.vscodeignore b/extensions/vscode/.vscodeignore index 1681d2e..d35f90a 100644 --- a/extensions/vscode/.vscodeignore +++ b/extensions/vscode/.vscodeignore @@ -15,3 +15,5 @@ vsc-extension-quickstart.md **/*.map **/*.ts *.vsix +codeinput-*.vsix +favicon.svg diff --git a/extensions/vscode/.yarnrc.yml b/extensions/vscode/.yarnrc.yml new file mode 100644 index 0000000..3186f3f --- /dev/null +++ b/extensions/vscode/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/extensions/vscode/CHANGELOG.md b/extensions/vscode/CHANGELOG.md new file mode 100644 index 0000000..d83a612 --- /dev/null +++ b/extensions/vscode/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.1.0] - 2026-03-07 + +### Added +- Initial release +- LSP-based CODEOWNERS integration +- Status bar ownership indicator +- File ownership info command +- Automatic binary download +- Tag support for CODEOWNERS diff --git a/extensions/vscode/LICENSE b/extensions/vscode/LICENSE new file mode 100644 index 0000000..3781661 --- /dev/null +++ b/extensions/vscode/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Abid Omar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/extensions/vscode/README.md b/extensions/vscode/README.md new file mode 100644 index 0000000..b0bc7f4 --- /dev/null +++ b/extensions/vscode/README.md @@ -0,0 +1,65 @@ +# CodeInput - CODEOWNERS Integration for VS Code + +A Language Server Protocol (LSP) based extension that provides CODEOWNERS integration for Visual Studio Code. Automatically displays ownership information and tags for files in your workspace. + +## Features + +- **Status Bar Integration**: Shows ownership status at a glance with lock/alert icons +- **File Ownership Info**: View owners and tags for any file via command palette +- **Multi-format Support**: Works with GitHub, GitLab, and Bitbucket CODEOWNERS file locations +- **Tag Support**: Extended CODEOWNERS syntax with tag support (e.g., `*.rs @team #backend #critical`) +- **Automatic Binary Management**: Downloads the required LSP server binary automatically + +## Requirements + +The extension requires the `ci-lsp` binary. It will attempt to download it automatically, or you can specify a custom path in settings. + +## Installation + +1. Install the extension from the VS Code Marketplace +2. Open a workspace containing a CODEOWNERS file +3. The extension will activate automatically + +## Configuration + +| Setting | Description | Default | +| --------------------------- | --------------------------------------- | ------------------- | +| `codeinput.binaryPath` | Path to the codeinput LSP server binary | `ci-lsp` | +| `codeinput.cacheFile` | Name of the cache file | `.codeowners.cache` | +| `codeinput.showInStatusBar` | Show CODEOWNERS info in status bar | `true` | +| `codeinput.showDiagnostics` | Show diagnostics for unowned files | `true` | +| `codeinput.lspTransport` | Transport method for LSP (stdio/tcp) | `stdio` | +| `codeinput.lspPort` | TCP port for LSP communication | `8123` | + +## Commands + +| Command | Description | +| -------------------------------------------------- | ------------------------------------------- | +| `CodeInput: Show CODEOWNERS Info for Current File` | Display owners and tags for the active file | +| `CodeInput: Refresh CODEOWNERS Cache` | Force refresh the ownership cache | + +## CODEOWNERS File Locations + +The extension monitors these locations for CODEOWNERS files: + +- `CODEOWNERS` (root) +- `.github/CODEOWNERS` +- `.gitlab/CODEOWNERS` +- `docs/CODEOWNERS` + +## Extended Syntax + +CodeInput supports an extended CODEOWNERS syntax with tags: + +``` +# Standard GitHub syntax +*.rs @rust-team + +# Extended syntax with tags +src/api/** @backend-team #api #critical +*.md @docs-team #documentation +``` + +## License + +MIT diff --git a/extensions/vscode/icon.png b/extensions/vscode/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7cc06ce75800cd65941a1d88ac00315ba016ce3c GIT binary patch literal 1634 zcmZ{kdo&Y#7{`Be$)vGT5nXtr5@w8HR+M3jvY$9&#R~~^_$VW$OgR z11_9G|8GgA*Y8vWxRpG9oZj7xca+m;K4MEBD@gV~j zgOO*KDG_rSlc?O~xO*IIIyS&0F{0*|1AdrHq`D-s8q0u zuv8a)jN{T!F2`IxcJF(-YR#YXj`?VQe#3SqoN%4sCPUg6=`VPrKzIPz?mK$Q%ph6R%-(!N ze*DbmZb;gaPnsg@@5pmnF9(bR^`Gsl9N2o`#w#TcNl^E`Y00|Zs3IMm)ThK^4%zHr z-SYI%4dHXYT0Ltjo8(}i3&YF~FkK-bnOf-#afseaN+?BnhudypWoO9B**+fH01Ve; zNZiXX*AFDghMfwe!b;VL4R?eVuPjdBOCmQ-{(#{1UN)9$SAUMHf*d|zXYv|$<^F7g zvf`9hvyOfV#6eHdCB_})APq&Tf6=TBmCS3scsbTI2Cj)3k-HsE-T*34`t51oTVQJZ z#-{FAg1inz!D3D`DfszVh8Md$Z2Zqqi5q70jDTt5f^3eEwR*M)kz?$;`L274b5}4< zbTf1})EVL*s!q}^CPLIq?aR=;u$_|D=c3Z8+S{C`mwT^8vZ{Of>@~P?r5pdL>DiS8 z8t({dJhr&)k5sjP*wk04SEU)`npOO7BpgIQN6KK^WQnZIiuG37KAQ^oM%j08< zJ}4GTf|UAQzU_0t?^f&(MS*AI;rX1-+*>5D6fi}{YQ<~?ndPhP3O94=r{8a}FMUvq z2k^{{8FS`cqin-({fQH%m-6?>;Jcm*>a8P^2K?{h%GHaL2rm=FEf5Q3#aUR1M3fWh*FNF+farO{>o RaIXU5B3K>8aSwZ*{}(-6#*Y91 literal 0 HcmV?d00001 diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json index e7770d5..3bf9eb1 100644 --- a/extensions/vscode/package.json +++ b/extensions/vscode/package.json @@ -2,9 +2,18 @@ "name": "codeinput", "displayName": "CodeInput - CODEOWNERS Integration", "description": "LSP-based CODEOWNERS integration for VS Code", - "version": "0.0.1", + "version": "0.1.0", "publisher": "codeinput", "license": "MIT", + "icon": "icon.png", + "repository": { + "type": "git", + "url": "https://github.com/code-input/cli.git" + }, + "bugs": { + "url": "https://github.com/code-input/cli/issues" + }, + "homepage": "https://github.com/code-input/cli#readme", "engines": { "vscode": "^1.74.0" }, @@ -27,16 +36,6 @@ "main": "./out/extension.js", "contributes": { "commands": [ - { - "command": "codeinput.showOwners", - "title": "Show CODEOWNERS Owners", - "category": "CodeInput" - }, - { - "command": "codeinput.showTags", - "title": "Show CODEOWNERS Tags", - "category": "CodeInput" - }, { "command": "codeinput.refreshCache", "title": "Refresh CODEOWNERS Cache", @@ -86,18 +85,6 @@ "description": "TCP port for LSP communication (when using tcp transport)" } } - }, - "menus": { - "commandPalette": [ - { - "command": "codeinput.showOwners", - "when": "false" - }, - { - "command": "codeinput.showTags", - "when": "false" - } - ] } }, "scripts": { diff --git a/extensions/vscode/src/extension.ts b/extensions/vscode/src/extension.ts index 2c64616..166c8a6 100644 --- a/extensions/vscode/src/extension.ts +++ b/extensions/vscode/src/extension.ts @@ -108,24 +108,6 @@ export async function activate(context: vscode.ExtensionContext) { }) ); - context.subscriptions.push( - vscode.commands.registerCommand('codeinput.showOwners', (uri: string, owners: any[]) => { - if (owners && owners.length > 0) { - const ownerList = owners.map(o => o.identifier).join(', '); - vscode.window.showInformationMessage(`Owners: ${ownerList}`); - } - }) - ); - - context.subscriptions.push( - vscode.commands.registerCommand('codeinput.showTags', (uri: string, tags: any[]) => { - if (tags && tags.length > 0) { - const tagList = tags.map(t => `#${t}`).join(', '); - vscode.window.showInformationMessage(`Tags: ${tagList}`); - } - }) - ); - // Handle configuration changes context.subscriptions.push( vscode.workspace.onDidChangeConfiguration(e => { From 97933f3dd561d323624fdbf9eb5db5557450a238 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 16:24:20 +0800 Subject: [PATCH 06/10] chore: release version 0.1.0 --- CHANGELOG.md | 27 +++++++++++++++++++++++++-- README.md | 12 ++++++------ ci/Cargo.toml | 4 ++-- codeinput/Cargo.toml | 2 +- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 120e748..fc98f17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,28 @@ All notable changes to this project will be documented in this file. -## [0.0.5] - 2025-03-02 +## [0.1.0] - 2026-03-07 ### Added + +- **VS Code Extension**: Companion extension for Visual Studio Code with LSP integration +- **Neovim Plugin**: Full Neovim support with telescope integration for browsing files by ownership +- **Vim Plugin**: Vim plugin for CODEOWNERS LSP integration +- **LSP Enhancements**: + - Inlay hints support for CODEOWNERS patterns + - Custom commands: `listFiles`, `listOwners`, `listTags`, `getFileOwnership` + - TCP transport support (`ci lsp --port `) + +### Changed + +- Refactored LSP server into modular structure for better maintainability +- Simplified VS Code extension by removing unused features +- Improved telescope file pickers with proper entry makers + +## [0.0.5] - 2026-03-02 + +### Added + - **LSP Server**: Language Server Protocol implementation for IDE integration - `textDocument/hover`: Shows owners and tags when hovering over files - `textDocument/codeLens`: Displays ownership annotations above files @@ -14,20 +33,24 @@ All notable changes to this project will be documented in this file. - **VS Code Extension**: Companion extension for Visual Studio Code (in `vscode-extension/`) ### Changed + - Upgraded `utoipa` to 5.4.0 with schema fixes - LSP feature is now opt-in via `--features lsp` cargo flag ### Fixed + - Safe serialization of CodeLens arguments - Output redirected to stderr for LSP compatibility -## [0.0.4] - 2024-12-XX +## [0.0.4] - 2025-12-XX ### Added + - `infer-owners` command for intelligent owner inference - ARM64 runners for release builds (Linux, Windows, macOS) ### Changed + - Dependency updates and formatting improvements ## [0.0.3] - Previous Release diff --git a/README.md b/README.md index 26f6dc6..6a48d06 100644 --- a/README.md +++ b/README.md @@ -59,13 +59,13 @@ ### Pre-built Binaries -**Latest Release: `0.0.4`** +**Latest Release: `0.1.0`** -- **Linux x86_64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.0.4/ci-linux-x86_64) -- **Linux ARM64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.0.4/ci-linux-aarch64) -- **Windows x86_64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.0.4/ci-windows-x86_64.exe) -- **macOS Intel**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.0.4/ci-macos-x86_64) -- **macOS Apple Silicon**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.0.4/ci-macos-aarch64) +- **Linux x86_64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.1.0/ci-linux-x86_64) +- **Linux ARM64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.1.0/ci-linux-aarch64) +- **Windows x86_64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.1.0/ci-windows-x86_64.exe) +- **macOS Intel**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.1.0/ci-macos-x86_64) +- **macOS Apple Silicon**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.1.0/ci-macos-aarch64) #### Installation Instructions diff --git a/ci/Cargo.toml b/ci/Cargo.toml index 0e37b2e..a8346b2 100644 --- a/ci/Cargo.toml +++ b/ci/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ci" -version = "0.0.5" +version = "0.1.0" authors = ["Abid Omar "] edition = "2021" repository = "https://github.com/code-input/cli" @@ -24,7 +24,7 @@ syslog = ["codeinput/syslog"] lsp = ["codeinput/tower-lsp", "codeinput/tokio", "tokio"] [dependencies] -codeinput = { version = "0.0.5", path = "../codeinput" } +codeinput = { version = "0.1.0", path = "../codeinput" } human-panic = { workspace = true } better-panic = { workspace = true } log = { workspace = true } diff --git a/codeinput/Cargo.toml b/codeinput/Cargo.toml index ed7f8a8..e021398 100644 --- a/codeinput/Cargo.toml +++ b/codeinput/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "codeinput" -version = "0.0.5" +version = "0.1.0" authors = ["Abid Omar "] edition = "2021" repository = "https://github.com/code-input/cli" From 6a2f176c49371e7aa3646a6c1bc87e78405d4a52 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 17:28:54 +0800 Subject: [PATCH 07/10] chore: fix release action --- .github/workflows/release.yml | 96 ++++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 18 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d319644..f90cb36 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -116,25 +116,85 @@ jobs: with: path: artifacts - - name: Create Release and Upload Assets + - name: Remove Same Release + uses: omarabid-forks/action-rollback@stable + continue-on-error: true + with: + tag: ${{ steps.vars.outputs.package_version }} env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAG: ${{ steps.vars.outputs.package_version }} - PACKAGE_NAME: ${{ steps.vars.outputs.package_name }} - run: | - # Delete existing release if exists - gh release delete "$TAG" --yes || true - - # Create release - gh release create "$TAG" \ - --title "Version $TAG" \ - --notes "$PACKAGE_NAME - $TAG" \ - artifacts/ci-linux-x86_64/ci \ - artifacts/ci-linux-aarch64/ci \ - artifacts/ci-windows-x86_64.exe/ci.exe \ - artifacts/ci-windows-aarch64.exe/ci.exe \ - artifacts/ci-macos-x86_64/ci \ - artifacts/ci-macos-aarch64/ci + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create Release + id: create-release + uses: actions/create-release@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.vars.outputs.package_version }} + release_name: ${{ steps.vars.outputs.package_name }} ${{ steps.vars.outputs.package_version }} + body: ${{ steps.vars.outputs.package_name }} - ${{ steps.vars.outputs.package_version }} + draft: false + prerelease: false + + - name: Upload Linux x86_64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-linux-x86_64/ci + asset_name: ci-linux-x86_64 + asset_content_type: application/octet-stream + + - name: Upload Linux aarch64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-linux-aarch64/ci + asset_name: ci-linux-aarch64 + asset_content_type: application/octet-stream + + - name: Upload Windows x86_64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-windows-x86_64.exe/ci.exe + asset_name: ci-windows-x86_64.exe + asset_content_type: application/octet-stream + + - name: Upload Windows aarch64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-windows-aarch64.exe/ci.exe + asset_name: ci-windows-aarch64.exe + asset_content_type: application/octet-stream + + - name: Upload macOS x86_64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-macos-x86_64/ci + asset_name: ci-macos-x86_64 + asset_content_type: application/octet-stream + + - name: Upload macOS aarch64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-macos-aarch64/ci + asset_name: ci-macos-aarch64 + asset_content_type: application/octet-stream - name: Purge artifacts uses: omarabid-forks/purge-artifacts@v1 From 1f23b8e01b6a7911e634b2e7eb4ee25634b54f5f Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 19:17:12 +0800 Subject: [PATCH 08/10] fix: release action --- .github/workflows/release-lsp.yml | 83 ++++++++++++++----------------- 1 file changed, 37 insertions(+), 46 deletions(-) diff --git a/.github/workflows/release-lsp.yml b/.github/workflows/release-lsp.yml index e087de1..e55ce2b 100644 --- a/.github/workflows/release-lsp.yml +++ b/.github/workflows/release-lsp.yml @@ -1,14 +1,31 @@ name: Release LSP on: - push: - tags: - - '*' + workflow_run: + workflows: ["Release"] + types: + - completed jobs: + get-tag: + name: Get Release Tag + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + outputs: + tag: ${{ steps.get-tag.outputs.tag }} + steps: + - name: Get tag from latest release + id: get-tag + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + TAG=$(gh api repos/${{ github.repository }}/releases/latest --jq '.tag_name') + echo "tag=$TAG" >> $GITHUB_OUTPUT + release: name: Release LSP - ${{ matrix.os }} (${{ matrix.arch }}) runs-on: ${{ matrix.runner }} + needs: get-tag strategy: matrix: include: @@ -52,13 +69,8 @@ jobs: steps: - name: Checkout Source uses: actions/checkout@v4 - - - name: Set variables - id: vars - shell: bash - run: | - echo "package_name=$(sed -En 's/name[[:space:]]*=[[:space:]]*"([^"]+)"/\1/p' Cargo.toml | head -1)" >> $GITHUB_OUTPUT - echo "package_version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + with: + ref: ${{ needs.get-tag.outputs.tag }} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable @@ -97,51 +109,30 @@ jobs: name: ${{ matrix.asset_name }} path: target/${{ matrix.target }}/release/${{ matrix.binary_name }} - create-release: - name: Create LSP Release + upload-lsp-binaries: + name: Upload LSP Binaries runs-on: ubuntu-latest - needs: release + needs: [get-tag, release] steps: - - name: Checkout Source - uses: actions/checkout@v4 - - - name: Set variables - id: vars + - name: Get upload URL + id: get-upload-url + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - echo "package_name=$(sed -En 's/name[[:space:]]*=[[:space:]]*"([^"]+)"/\1/p' Cargo.toml | head -1)" >> $GITHUB_OUTPUT - echo "package_version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + UPLOAD_URL=$(gh release view ${{ needs.get-tag.outputs.tag }} --json uploadUrl --jq '.uploadUrl') + echo "upload_url=$UPLOAD_URL" >> $GITHUB_OUTPUT - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts - - name: Remove Same Release - uses: omarabid-forks/action-rollback@stable - continue-on-error: true - with: - tag: ${{ steps.vars.outputs.package_version }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Create Release - id: create-release - uses: actions/create-release@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ steps.vars.outputs.package_version }} - release_name: LSP Server ${{ steps.vars.outputs.package_version }} - body: ${{ steps.vars.outputs.package_name }} LSP Server - ${{ steps.vars.outputs.package_version }} - draft: false - prerelease: false - - name: Upload Linux x64 binary uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-linux-x64/ci asset_name: ci-lsp-linux-x64 asset_content_type: application/octet-stream @@ -151,7 +142,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-linux-arm64/ci asset_name: ci-lsp-linux-arm64 asset_content_type: application/octet-stream @@ -161,7 +152,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-windows-x64.exe/ci.exe asset_name: ci-lsp-windows-x64.exe asset_content_type: application/octet-stream @@ -171,7 +162,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-windows-arm64.exe/ci.exe asset_name: ci-lsp-windows-arm64.exe asset_content_type: application/octet-stream @@ -181,7 +172,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-darwin-x64/ci asset_name: ci-lsp-darwin-x64 asset_content_type: application/octet-stream @@ -191,7 +182,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-darwin-arm64/ci asset_name: ci-lsp-darwin-arm64 asset_content_type: application/octet-stream From 2eae0c394890d0bb772ad8c59852c89d8af5dd27 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Tue, 10 Mar 2026 20:26:29 +0800 Subject: [PATCH 09/10] chore: fix release action --- .github/workflows/release-lsp.yml | 65 +++++-------------------------- 1 file changed, 9 insertions(+), 56 deletions(-) diff --git a/.github/workflows/release-lsp.yml b/.github/workflows/release-lsp.yml index e55ce2b..ec7d1c0 100644 --- a/.github/workflows/release-lsp.yml +++ b/.github/workflows/release-lsp.yml @@ -1,6 +1,7 @@ name: Release LSP on: + workflow_dispatch: workflow_run: workflows: ["Release"] types: @@ -113,79 +114,31 @@ jobs: name: Upload LSP Binaries runs-on: ubuntu-latest needs: [get-tag, release] + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - name: Get upload URL - id: get-upload-url - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - UPLOAD_URL=$(gh release view ${{ needs.get-tag.outputs.tag }} --json uploadUrl --jq '.uploadUrl') - echo "upload_url=$UPLOAD_URL" >> $GITHUB_OUTPUT - - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts - name: Upload Linux x64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-linux-x64/ci - asset_name: ci-lsp-linux-x64 - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-linux-x64/ci --repo ${{ github.repository }} - name: Upload Linux arm64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-linux-arm64/ci - asset_name: ci-lsp-linux-arm64 - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-linux-arm64/ci --repo ${{ github.repository }} - name: Upload Windows x64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-windows-x64.exe/ci.exe - asset_name: ci-lsp-windows-x64.exe - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-windows-x64.exe/ci.exe --repo ${{ github.repository }} - name: Upload Windows arm64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-windows-arm64.exe/ci.exe - asset_name: ci-lsp-windows-arm64.exe - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-windows-arm64.exe/ci.exe --repo ${{ github.repository }} - name: Upload macOS x64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-darwin-x64/ci - asset_name: ci-lsp-darwin-x64 - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-darwin-x64/ci --repo ${{ github.repository }} - name: Upload macOS arm64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-darwin-arm64/ci - asset_name: ci-lsp-darwin-arm64 - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-darwin-arm64/ci --repo ${{ github.repository }} - name: Purge artifacts uses: omarabid-forks/purge-artifacts@v1 From 70d723c69ed892c375f71f55c78dabad8304c7b2 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Tue, 10 Mar 2026 20:41:59 +0800 Subject: [PATCH 10/10] chore: fix release action --- .github/workflows/release-lsp.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release-lsp.yml b/.github/workflows/release-lsp.yml index ec7d1c0..d93cc42 100644 --- a/.github/workflows/release-lsp.yml +++ b/.github/workflows/release-lsp.yml @@ -123,22 +123,34 @@ jobs: path: artifacts - name: Upload Linux x64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-linux-x64/ci --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-linux-x64/ci ci-lsp-linux-x64 + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-linux-x64 --repo ${{ github.repository }} - name: Upload Linux arm64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-linux-arm64/ci --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-linux-arm64/ci ci-lsp-linux-arm64 + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-linux-arm64 --repo ${{ github.repository }} - name: Upload Windows x64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-windows-x64.exe/ci.exe --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-windows-x64.exe/ci.exe ci-lsp-windows-x64.exe + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-windows-x64.exe --repo ${{ github.repository }} - name: Upload Windows arm64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-windows-arm64.exe/ci.exe --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-windows-arm64.exe/ci.exe ci-lsp-windows-arm64.exe + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-windows-arm64.exe --repo ${{ github.repository }} - name: Upload macOS x64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-darwin-x64/ci --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-darwin-x64/ci ci-lsp-darwin-x64 + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-darwin-x64 --repo ${{ github.repository }} - name: Upload macOS arm64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-darwin-arm64/ci --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-darwin-arm64/ci ci-lsp-darwin-arm64 + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-darwin-arm64 --repo ${{ github.repository }} - name: Purge artifacts uses: omarabid-forks/purge-artifacts@v1