From 4d9babd8fb4564e3ab5271f39b9dfab32dd3508d Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Fri, 6 Mar 2026 18:37:16 +0800 Subject: [PATCH 01/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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 From 5bfdb8cf5e52f58540614f9e1ff87ad121c7bb85 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Wed, 18 Mar 2026 13:47:14 +0800 Subject: [PATCH 11/16] chore: migrate from tower-lsp to tower-lsp-server Upgrade the LSP implementation to use the tower-lsp-server crate, which provides better maintenance and updated APIs. --- Cargo.toml | 2 +- ci/Cargo.toml | 2 +- codeinput/Cargo.toml | 2 +- codeinput/src/core/commands/lsp.rs | 4 +-- codeinput/src/core/commands/mod.rs | 2 +- codeinput/src/lib.rs | 2 +- codeinput/src/lsp/commands.rs | 4 +-- codeinput/src/lsp/handlers.rs | 52 +++++++++++++++++------------- codeinput/src/lsp/server.rs | 15 +++++---- 9 files changed, 46 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2d8a428..29b3fc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ tabled = "0.20.0" terminal_size = "0.4.3" clap = { version = "4.5.60", features = ["cargo", "derive"] } chrono = { version = "0.4.44", features = ["serde"] } -tower-lsp = "0.20" +tower-lsp-server = "0.23.0" tokio = { version = "1.49.0", features = ["full"] } url = "2.5.8" diff --git a/ci/Cargo.toml b/ci/Cargo.toml index a8346b2..0ae8033 100644 --- a/ci/Cargo.toml +++ b/ci/Cargo.toml @@ -21,7 +21,7 @@ default = ["termlog"] termlog = ["codeinput/termlog"] journald = ["codeinput/journald"] syslog = ["codeinput/syslog"] -lsp = ["codeinput/tower-lsp", "codeinput/tokio", "tokio"] +lsp = ["codeinput/tower-lsp-server", "codeinput/tokio", "tokio"] [dependencies] codeinput = { version = "0.1.0", path = "../codeinput" } diff --git a/codeinput/Cargo.toml b/codeinput/Cargo.toml index e021398..ab0956e 100644 --- a/codeinput/Cargo.toml +++ b/codeinput/Cargo.toml @@ -94,7 +94,7 @@ tabled = { workspace = true, optional = true } terminal_size = { workspace = true, optional = true } clap = { workspace = true, optional = true } chrono = { version = "0.4.44", features = ["serde"], optional = true } -tower-lsp = { workspace = true, optional = true } +tower-lsp-server = { workspace = true, optional = true } tokio = { workspace = true, optional = true } url = { workspace = true, optional = true } diff --git a/codeinput/src/core/commands/lsp.rs b/codeinput/src/core/commands/lsp.rs index 033a459..3c6ddc3 100644 --- a/codeinput/src/core/commands/lsp.rs +++ b/codeinput/src/core/commands/lsp.rs @@ -4,11 +4,11 @@ use crate::utils::error::Result; -#[cfg(feature = "tower-lsp")] +#[cfg(feature = "tower-lsp-server")] use crate::lsp::server::{run_lsp_server, run_lsp_server_tcp}; /// Run the LSP server -#[cfg(feature = "tower-lsp")] +#[cfg(feature = "tower-lsp-server")] pub fn run(port: Option) -> Result<()> { let rt = tokio::runtime::Runtime::new()?; rt.block_on(async { diff --git a/codeinput/src/core/commands/mod.rs b/codeinput/src/core/commands/mod.rs index 60ac098..7f09015 100644 --- a/codeinput/src/core/commands/mod.rs +++ b/codeinput/src/core/commands/mod.rs @@ -7,5 +7,5 @@ pub mod list_rules; pub mod list_tags; pub mod parse; -#[cfg(feature = "tower-lsp")] +#[cfg(feature = "tower-lsp-server")] pub mod lsp; diff --git a/codeinput/src/lib.rs b/codeinput/src/lib.rs index fe44923..8cd4e2b 100644 --- a/codeinput/src/lib.rs +++ b/codeinput/src/lib.rs @@ -12,5 +12,5 @@ pub mod core; pub mod utils; // LSP server module (requires full features - not just types) -#[cfg(all(not(feature = "types"), feature = "tokio", feature = "tower-lsp"))] +#[cfg(all(not(feature = "types"), feature = "tokio", feature = "tower-lsp-server"))] pub mod lsp; diff --git a/codeinput/src/lsp/commands.rs b/codeinput/src/lsp/commands.rs index ab541d1..08da70e 100644 --- a/codeinput/src/lsp/commands.rs +++ b/codeinput/src/lsp/commands.rs @@ -1,4 +1,4 @@ -use tower_lsp::jsonrpc::Result as LspResult; +use tower_lsp_server::jsonrpc::Result as LspResult; use url::Url; use crate::core::types::{CodeownersCache, OwnerType}; @@ -9,7 +9,7 @@ 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")); + return Err(tower_lsp_server::jsonrpc::Error::invalid_params("Invalid URI")); }; Ok(self.get_file_ownership(&uri).await) } diff --git a/codeinput/src/lsp/handlers.rs b/codeinput/src/lsp/handlers.rs index 9be0de3..8b2fd21 100644 --- a/codeinput/src/lsp/handlers.rs +++ b/codeinput/src/lsp/handlers.rs @@ -1,20 +1,20 @@ 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_server::LanguageServer; +use tower_lsp_server::jsonrpc::Result as LspResult; +use tower_lsp_server::ls_types::*; use url::Url; use super::server::{LspServer, is_codeowners_file, uri_to_path}; -#[tower_lsp::async_trait] impl LanguageServer for LspServer { async fn initialize(&self, params: InitializeParams) -> LspResult { // Initialize workspaces from workspace folders let workspace_folders = params.workspace_folders.unwrap_or_default(); for folder in workspace_folders { - if let Err(e) = self.initialize_workspace(folder.uri, None).await { + let Ok(uri_url) = Url::parse(folder.uri.as_str()) else { continue; }; + if let Err(e) = self.initialize_workspace(uri_url, None).await { self.client .log_message( MessageType::WARNING, @@ -25,18 +25,23 @@ impl LanguageServer for LspServer { } // If no workspace folders, try to use root_uri - if let Some(root_uri) = params.root_uri { - if let Err(e) = self.initialize_workspace(root_uri, None).await { - self.client - .log_message( - MessageType::WARNING, - format!("Failed to initialize root workspace: {}", e), - ) - .await; + #[allow(deprecated)] + let root_uri = params.root_uri; + if let Some(root_uri) = root_uri { + if let Ok(uri_url) = Url::parse(root_uri.as_str()) { + if let Err(e) = self.initialize_workspace(uri_url, None).await { + self.client + .log_message( + MessageType::WARNING, + format!("Failed to initialize root workspace: {}", e), + ) + .await; + } } } Ok(InitializeResult { + offset_encoding: None, capabilities: ServerCapabilities { text_document_sync: Some(TextDocumentSyncCapability::Kind( TextDocumentSyncKind::FULL, @@ -87,7 +92,7 @@ impl LanguageServer for LspServer { } async fn did_open(&self, params: DidOpenTextDocumentParams) { - let file_uri = params.text_document.uri; + let Ok(file_uri) = Url::parse(params.text_document.uri.as_str()) else { return; }; // Check if this is a CODEOWNERS file and refresh cache if so if is_codeowners_file(&file_uri) { @@ -120,7 +125,7 @@ impl LanguageServer for LspServer { } async fn did_save(&self, params: DidSaveTextDocumentParams) { - let file_uri = params.text_document.uri; + let Ok(file_uri) = Url::parse(params.text_document.uri.as_str()) else { return; }; // If CODEOWNERS file was saved, refresh the cache if is_codeowners_file(&file_uri) { @@ -147,7 +152,7 @@ impl LanguageServer for LspServer { } async fn hover(&self, params: HoverParams) -> LspResult> { - let file_uri = params.text_document_position_params.text_document.uri; + let Ok(file_uri) = Url::parse(params.text_document_position_params.text_document.uri.as_str()) else { return Ok(None); }; // Get ownership info for this file if let Some(info) = self.get_file_ownership(&file_uri).await { @@ -194,7 +199,7 @@ impl LanguageServer for LspServer { } async fn code_lens(&self, params: CodeLensParams) -> LspResult>> { - let file_uri = params.text_document.uri; + let Ok(file_uri) = Url::parse(params.text_document.uri.as_str()) else { return Ok(None); }; // Get ownership info for this file if let Some(info) = self.get_file_ownership(&file_uri).await { @@ -267,7 +272,7 @@ impl LanguageServer for LspServer { } async fn inlay_hint(&self, params: InlayHintParams) -> LspResult>> { - let file_uri = params.text_document.uri; + let Ok(file_uri) = Url::parse(params.text_document.uri.as_str()) else { return Ok(None); }; let path = uri_to_path(&file_uri); let file_path = match path { @@ -358,7 +363,7 @@ impl LanguageServer for LspServer { async fn did_change_workspace_folders(&self, params: DidChangeWorkspaceFoldersParams) { // Handle removed workspaces - collect URIs first, then remove them - let removed_uris: Vec = params.event.removed.iter().map(|f| f.uri.clone()).collect(); + let removed_uris: Vec = params.event.removed.iter().filter_map(|f| Url::parse(f.uri.as_str()).ok()).collect(); { let mut workspaces = self.workspaces.write().await; for uri in removed_uris { @@ -368,7 +373,8 @@ impl LanguageServer for LspServer { // Handle added workspaces for folder in params.event.added { - if let Err(e) = self.initialize_workspace(folder.uri, None).await { + let Ok(uri_url) = Url::parse(folder.uri.as_str()) else { continue; }; + if let Err(e) = self.initialize_workspace(uri_url, None).await { self.client .log_message( MessageType::WARNING, @@ -382,7 +388,7 @@ impl LanguageServer for LspServer { async fn execute_command(&self, params: ExecuteCommandParams) -> LspResult> { fn to_value(v: T) -> LspResult { serde_json::to_value(v) - .map_err(|e| tower_lsp::jsonrpc::Error::invalid_params(e.to_string())) + .map_err(|e| tower_lsp_server::jsonrpc::Error::invalid_params(e.to_string())) } match params.command.as_str() { @@ -392,7 +398,7 @@ impl LanguageServer for LspServer { .first() .and_then(|v| v.as_str()) .ok_or_else(|| { - tower_lsp::jsonrpc::Error::invalid_params( + tower_lsp_server::jsonrpc::Error::invalid_params( "Expected a single URI string argument", ) })?; @@ -411,7 +417,7 @@ impl LanguageServer for LspServer { let result = self.list_tags(None).await?; to_value(result).map(Some) } - _ => Err(tower_lsp::jsonrpc::Error::method_not_found()), + _ => Err(tower_lsp_server::jsonrpc::Error::method_not_found()), } } } diff --git a/codeinput/src/lsp/server.rs b/codeinput/src/lsp/server.rs index 54351c9..10c4a02 100644 --- a/codeinput/src/lsp/server.rs +++ b/codeinput/src/lsp/server.rs @@ -3,8 +3,8 @@ use std::path::PathBuf; use std::sync::Arc; use tokio::sync::RwLock; -use tower_lsp::lsp_types::*; -use tower_lsp::Client; +use tower_lsp_server::ls_types::*; +use tower_lsp_server::Client; use url::Url; use crate::core::cache::sync_cache; @@ -138,8 +138,9 @@ impl LspServer { // Publish diagnostics for this workspace for (file_uri, file_diagnostics) in diagnostics { + let Ok(ls_uri) = file_uri.as_str().parse::() else { continue; }; self.client - .publish_diagnostics(file_uri, file_diagnostics, None) + .publish_diagnostics(ls_uri, file_diagnostics, None) .await; } } @@ -163,9 +164,9 @@ pub async fn run_lsp_server() -> Result<()> { let stdin = tokio::io::stdin(); let stdout = tokio::io::stdout(); - let (service, socket) = tower_lsp::LspService::new(|client| LspServer::new(client)); + let (service, socket) = tower_lsp_server::LspService::new(|client| LspServer::new(client)); - tower_lsp::Server::new(stdin, stdout, socket) + tower_lsp_server::Server::new(stdin, stdout, socket) .serve(service) .await; @@ -184,8 +185,8 @@ pub async fn run_lsp_server_tcp(port: u16) -> Result<()> { loop { let (stream, _) = listener.accept().await?; let (read, write) = tokio::io::split(stream); - let (service, socket) = tower_lsp::LspService::new(|client| LspServer::new(client)); + let (service, socket) = tower_lsp_server::LspService::new(|client| LspServer::new(client)); - tokio::spawn(tower_lsp::Server::new(read, write, socket).serve(service)); + tokio::spawn(tower_lsp_server::Server::new(read, write, socket).serve(service)); } } From c2800dc1568c83d145d995ca7262c8dff41c09b2 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Tue, 14 Apr 2026 10:29:55 +0700 Subject: [PATCH 12/16] chore: update organization name --- README.md | 18 +++++++++--------- SECURITY.md | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6a48d06..3519923 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@
-[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/CodeInputCorp/cli/blob/master/LICENSE) -[![Tests](https://github.com/CodeInputCorp/cli/actions/workflows/tests.yml/badge.svg)](https://github.com/CodeInputCorp/cli/actions/workflows/tests.yml) -[![Build](https://github.com/CodeInputCorp/cli/actions/workflows/build.yml/badge.svg)](https://github.com/CodeInputCorp/cli/actions/workflows/build.yml) +[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/code-input/cli/blob/master/LICENSE) +[![Tests](https://github.com/code-input/cli/actions/workflows/tests.yml/badge.svg)](https://github.com/code-input/cli/actions/workflows/tests.yml) +[![Build](https://github.com/code-input/cli/actions/workflows/build.yml/badge.svg)](https://github.com/code-input/cli/actions/workflows/build.yml) `codeinput` is a CLI tool for parsing, analyzing, and managing CODEOWNERS files across your repository. It provides advanced querying capabilities, ownership analysis, and tag-based file organization. @@ -61,11 +61,11 @@ **Latest Release: `0.1.0`** -- **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) +- **Linux x86_64**: [Download](https://github.com/code-input/cli/releases/download/v0.1.0/ci-linux-x86_64) +- **Linux ARM64**: [Download](https://github.com/code-input/cli/releases/download/v0.1.0/ci-linux-aarch64) +- **Windows x86_64**: [Download](https://github.com/code-input/cli/releases/download/v0.1.0/ci-windows-x86_64.exe) +- **macOS Intel**: [Download](https://github.com/code-input/cli/releases/download/v0.1.0/ci-macos-x86_64) +- **macOS Apple Silicon**: [Download](https://github.com/code-input/cli/releases/download/v0.1.0/ci-macos-aarch64) #### Installation Instructions @@ -87,7 +87,7 @@ cargo install ci ### From Source ```bash -git clone https://github.com/CodeInputCorp/cli.git +git clone https://github.com/code-input/cli.git cd cli cargo build --release --bin ci sudo cp target/release/ci /usr/local/bin/ diff --git a/SECURITY.md b/SECURITY.md index ca12e19..4515d6d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,4 +8,4 @@ Remediation of security vulnerabilities is prioritized by the project team. The ## Security advisories -The project team is committed to transparency in the security issue disclosure process. We announce security issues via [project Github Release notes](https://github.com/CodeInputCorp/cli/releases). +The project team is committed to transparency in the security issue disclosure process. We announce security issues via [project Github Release notes](https://github.com/code-input/cli/releases). From 0a61813da26424c06f596ce1dd302c21c5ba5d42 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Tue, 14 Apr 2026 19:43:12 +0700 Subject: [PATCH 13/16] feat: add AUR publishing support with CI workflow Add PKGBUILD and .SRCINFO templates for codeinput and codeinput-bin AUR packages, a GitHub Actions workflow to automate publishing on release, and a helper script to regenerate .SRCINFO from PKGBUILDs. --- .github/scripts/generate-srcinfo.sh | 75 +++++++++++++++++++++++ .github/workflows/publish-aur.yml | 93 +++++++++++++++++++++++++++++ README.md | 9 +++ dist/aur/codeinput-bin/.SRCINFO | 17 ++++++ dist/aur/codeinput-bin/PKGBUILD | 19 ++++++ dist/aur/codeinput/.SRCINFO | 15 +++++ dist/aur/codeinput/PKGBUILD | 27 +++++++++ 7 files changed, 255 insertions(+) create mode 100755 .github/scripts/generate-srcinfo.sh create mode 100644 .github/workflows/publish-aur.yml create mode 100644 dist/aur/codeinput-bin/.SRCINFO create mode 100644 dist/aur/codeinput-bin/PKGBUILD create mode 100644 dist/aur/codeinput/.SRCINFO create mode 100644 dist/aur/codeinput/PKGBUILD diff --git a/.github/scripts/generate-srcinfo.sh b/.github/scripts/generate-srcinfo.sh new file mode 100755 index 0000000..ad9a394 --- /dev/null +++ b/.github/scripts/generate-srcinfo.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# Generate .SRCINFO from a PKGBUILD file. +# Usage: generate-srcinfo.sh +# +# Sources the PKGBUILD in a restricted subshell and outputs .SRCINFO format. + +set -uo pipefail + +if [ $# -lt 1 ]; then + echo "Usage: $0 " >&2 + exit 1 +fi + +pkgbuild="$1" + +if [ ! -f "$pkgbuild" ]; then + echo "Error: $pkgbuild not found" >&2 + exit 1 +fi + +( + # Override functions that might cause side effects + build() { :; } + package() { :; } + prepare() { :; } + check() { :; } + + source "$pkgbuild" + + # Determine pkgbase (defaults to first pkgname) + base="${pkgbase:-${pkgname[0]:-${pkgname:-}}}" + + # pkgbase section + echo "pkgbase = ${base}" + [ -n "${pkgdesc:-}" ] && printf '\tpkgdesc = %s\n' "$pkgdesc" + [ -n "${pkgver:-}" ] && printf '\tpkgver = %s\n' "$pkgver" + [ -n "${pkgrel:-}" ] && printf '\tpkgrel = %s\n' "$pkgrel" + [ -n "${url:-}" ] && printf '\turl = %s\n' "$url" + + # Array fields + for v in "${arch[@]}"; do printf '\tarch = %s\n' "$v"; done 2>/dev/null || true + for v in "${license[@]}"; do printf '\tlicense = %s\n' "$v"; done 2>/dev/null || true + for v in "${depends[@]}"; do printf '\tdepends = %s\n' "$v"; done 2>/dev/null || true + for v in "${makedepends[@]}"; do printf '\tmakedepends = %s\n' "$v"; done 2>/dev/null || true + for v in "${checkdepends[@]}"; do printf '\tcheckdepends = %s\n' "$v"; done 2>/dev/null || true + for v in "${optdepends[@]}"; do printf '\toptdepends = %s\n' "$v"; done 2>/dev/null || true + for v in "${provides[@]}"; do printf '\tprovides = %s\n' "$v"; done 2>/dev/null || true + for v in "${conflicts[@]}"; do printf '\tconflicts = %s\n' "$v"; done 2>/dev/null || true + for v in "${replaces[@]}"; do printf '\treplaces = %s\n' "$v"; done 2>/dev/null || true + for v in "${groups[@]}"; do printf '\tgroups = %s\n' "$v"; done 2>/dev/null || true + for v in "${options[@]}"; do printf '\toptions = %s\n' "$v"; done 2>/dev/null || true + for v in "${source[@]}"; do printf '\tsource = %s\n' "$v"; done 2>/dev/null || true + for v in "${sha256sums[@]}"; do printf '\tsha256sums = %s\n' "$v"; done 2>/dev/null || true + for v in "${sha512sums[@]}"; do printf '\tsha512sums = %s\n' "$v"; done 2>/dev/null || true + for v in "${md5sums[@]}"; do printf '\tmd5sums = %s\n' "$v"; done 2>/dev/null || true + + # Architecture-specific arrays + for v in "${source_x86_64[@]}"; do printf '\tsource_x86_64 = %s\n' "$v"; done 2>/dev/null || true + for v in "${source_aarch64[@]}"; do printf '\tsource_aarch64 = %s\n' "$v"; done 2>/dev/null || true + for v in "${sha256sums_x86_64[@]}"; do printf '\tsha256sums_x86_64 = %s\n' "$v"; done 2>/dev/null || true + for v in "${sha256sums_aarch64[@]}"; do printf '\tsha256sums_aarch64 = %s\n' "$v"; done 2>/dev/null || true + for v in "${sha512sums_x86_64[@]}"; do printf '\tsha512sums_x86_64 = %s\n' "$v"; done 2>/dev/null || true + for v in "${sha512sums_aarch64[@]}"; do printf '\tsha512sums_aarch64 = %s\n' "$v"; done 2>/dev/null || true + + echo "" + + # pkgname sections + if declare -p pkgname 2>/dev/null | grep -q 'declare -a'; then + for name in "${pkgname[@]}"; do + echo "pkgname = ${name}" + done + else + echo "pkgname = ${pkgname}" + fi +) 2>/dev/null diff --git a/.github/workflows/publish-aur.yml b/.github/workflows/publish-aur.yml new file mode 100644 index 0000000..50a45f9 --- /dev/null +++ b/.github/workflows/publish-aur.yml @@ -0,0 +1,93 @@ +name: Publish to AUR + +on: + release: + types: [published] + +jobs: + publish-aur: + name: Publish ${{ matrix.package }} to AUR + runs-on: ubuntu-latest + strategy: + matrix: + include: + - package: codeinput-bin + subdir: codeinput-bin + - package: codeinput + subdir: codeinput + steps: + - name: Checkout Source + uses: actions/checkout@v4 + + - name: Get version + id: version + run: | + tag="${GITHUB_REF#refs/tags/}" + version="${tag#v}" + echo "tag=${tag}" >> $GITHUB_OUTPUT + echo "version=${version}" >> $GITHUB_OUTPUT + + - name: Compute binary checksums + if: matrix.package == 'codeinput-bin' + id: checksums + run: | + curl -sL "https://github.com/code-input/cli/releases/download/${{ steps.version.outputs.tag }}/ci-linux-x86_64" -o ci-linux-x86_64 + echo "sha256_x86_64=$(sha256sum ci-linux-x86_64 | cut -d' ' -f1)" >> $GITHUB_OUTPUT + curl -sL "https://github.com/code-input/cli/releases/download/${{ steps.version.outputs.tag }}/ci-linux-aarch64" -o ci-linux-aarch64 + echo "sha256_aarch64=$(sha256sum ci-linux-aarch64 | cut -d' ' -f1)" >> $GITHUB_OUTPUT + + - name: Compute source checksum + if: matrix.package == 'codeinput' + id: src_checksum + run: | + curl -sL "https://github.com/code-input/cli/archive/refs/tags/${{ steps.version.outputs.tag }}.tar.gz" -o source.tar.gz + echo "sha256=$(sha256sum source.tar.gz | cut -d' ' -f1)" >> $GITHUB_OUTPUT + + - name: Update PKGBUILD + working-directory: dist/aur/${{ matrix.subdir }} + run: | + sed -i "s/^pkgver=.*/pkgver=${{ steps.version.outputs.version }}/" PKGBUILD + sed -i "s/^pkgrel=.*/pkgrel=1/" PKGBUILD + + if [ "${{ matrix.package }}" = "codeinput-bin" ]; then + sed -i "s/^sha256sums_x86_64=.*/sha256sums_x86_64=('${{ steps.checksums.outputs.sha256_x86_64 }}')/" PKGBUILD + sed -i "s/^sha256sums_aarch64=.*/sha256sums_aarch64=('${{ steps.checksums.outputs.sha256_aarch64 }}')/" PKGBUILD + else + sed -i "s/^sha256sums=.*/sha256sums=('${{ steps.src_checksum.outputs.sha256 }}')/" PKGBUILD + fi + + - name: Generate .SRCINFO + working-directory: dist/aur/${{ matrix.subdir }} + run: | + bash "${{ github.workspace }}/.github/scripts/generate-srcinfo.sh" PKGBUILD > .SRCINFO + + - name: Publish to AUR + env: + AUR_USERNAME: ${{ secrets.AUR_USERNAME }} + AUR_EMAIL: ${{ secrets.AUR_EMAIL }} + AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }} + PACKAGE: ${{ matrix.package }} + SUBDIR: ${{ matrix.subdir }} + run: | + # Setup SSH + mkdir -p ~/.ssh + echo "$AUR_SSH_PRIVATE_KEY" > ~/.ssh/aur + chmod 600 ~/.ssh/aur + cat >> ~/.ssh/config < +pkgname=codeinput-bin +pkgver=0.1.0 +pkgrel=1 +pkgdesc="A powerful CLI tool for parsing, analyzing, and managing CODEOWNERS files" +arch=('x86_64' 'aarch64') +url="https://codeinput.com/cli" +license=('MIT') +provides=('codeinput') +conflicts=('codeinput') +options=('!strip') +source_x86_64=("https://github.com/code-input/cli/releases/download/v${pkgver}/ci-linux-x86_64") +source_aarch64=("https://github.com/code-input/cli/releases/download/v${pkgver}/ci-linux-aarch64") +sha256sums_x86_64=('SKIP') +sha256sums_aarch64=('SKIP') + +package() { + install -Dm755 "${srcdir}/ci-linux-${CARCH}" "${pkgdir}/usr/bin/ci" +} diff --git a/dist/aur/codeinput/.SRCINFO b/dist/aur/codeinput/.SRCINFO new file mode 100644 index 0000000..20f39b5 --- /dev/null +++ b/dist/aur/codeinput/.SRCINFO @@ -0,0 +1,15 @@ +pkgbase = codeinput + pkgdesc = A powerful CLI tool for parsing, analyzing, and managing CODEOWNERS files + pkgver = 0.1.0 + pkgrel = 1 + url = https://codeinput.com/cli + arch = x86_64 + arch = aarch64 + license = MIT + depends = gcc + depends = openssl + makedepends = cargo + source = codeinput-0.1.0.tar.gz::https://github.com/code-input/cli/archive/refs/tags/v0.1.0.tar.gz + sha256sums = SKIP + +pkgname = codeinput diff --git a/dist/aur/codeinput/PKGBUILD b/dist/aur/codeinput/PKGBUILD new file mode 100644 index 0000000..4fb3625 --- /dev/null +++ b/dist/aur/codeinput/PKGBUILD @@ -0,0 +1,27 @@ +# Maintainer: Abid Omar +pkgname=codeinput +pkgver=0.1.0 +pkgrel=1 +pkgdesc="A powerful CLI tool for parsing, analyzing, and managing CODEOWNERS files" +arch=('x86_64' 'aarch64') +url="https://codeinput.com/cli" +license=('MIT') +depends=('gcc' 'openssl') +makedepends=('cargo') +source=("${pkgname}-${pkgver}.tar.gz::https://github.com/code-input/cli/archive/refs/tags/v${pkgver}.tar.gz") +sha256sums=('SKIP') + +prepare() { + cd "cli-${pkgver}" + cargo fetch --locked --target "$CARCH-unknown-linux-gnu" +} + +build() { + cd "cli-${pkgver}" + cargo build --release --bin ci +} + +package() { + cd "cli-${pkgver}" + install -Dm755 "target/release/ci" "${pkgdir}/usr/bin/ci" +} From d701e41e9e9472d88af3c0b4e35283d7e2a01921 Mon Sep 17 00:00:00 2001 From: omarabid Date: Tue, 14 Apr 2026 12:46:19 +0000 Subject: [PATCH 14/16] chore(docs): update TOC --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 902a511..5a3a240 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ - [Installation Instructions](#installation-instructions) - [From Cargo](#from-cargo) - [From Source](#from-source) + - [Arch Linux (AUR)](#arch-linux-aur) - [From NPM](#from-npm) - [Quick Start](#quick-start) - [Commands](#commands) From 861207cc66e1d83436ec81749a43126112cf0b09 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Thu, 16 Apr 2026 00:20:38 +0700 Subject: [PATCH 15/16] chore: pypi wrapper/action --- .github/workflows/publish-pypi.yml | 60 +++++++++++++++++ ci/Cargo.toml | 1 + codeinput/Cargo.toml | 1 + dist/pypi/pyproject.toml | 36 +++++++++++ dist/pypi/src/codeinput/__init__.py | 8 +++ dist/pypi/src/codeinput/cli.py | 99 +++++++++++++++++++++++++++++ 6 files changed, 205 insertions(+) create mode 100644 .github/workflows/publish-pypi.yml create mode 100644 dist/pypi/pyproject.toml create mode 100644 dist/pypi/src/codeinput/__init__.py create mode 100644 dist/pypi/src/codeinput/cli.py diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml new file mode 100644 index 0000000..1ef1d56 --- /dev/null +++ b/.github/workflows/publish-pypi.yml @@ -0,0 +1,60 @@ +name: Publish to PyPI + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version: + description: "Version to publish (e.g. 0.1.0)" + required: true + default: "0.1.0" + +jobs: + publish-pypi: + name: Publish to PyPI + runs-on: ubuntu-latest + environment: pypi + permissions: + id-token: write # Trusted publisher (OIDC) + steps: + - name: Checkout Source + uses: actions/checkout@v4 + + - name: Get version + id: version + run: | + if [ -n "${{ github.event.inputs.version }}" ]; then + version="${{ github.event.inputs.version }}" + tag="v${version}" + else + tag="${GITHUB_REF#refs/tags/}" + version="${tag#v}" + fi + echo "tag=${tag}" >> $GITHUB_OUTPUT + echo "version=${version}" >> $GITHUB_OUTPUT + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Update version in packaging files + working-directory: dist/pypi + run: | + sed -i "s/^version = \".*\"/version = \"${{ steps.version.outputs.version }}\"/" pyproject.toml + + - name: Build package + working-directory: dist/pypi + run: | + python -m pip install --upgrade build + python -m build + + - name: Publish to PyPI + working-directory: dist/pypi + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | + python -m pip install --upgrade twine + twine upload dist/* diff --git a/ci/Cargo.toml b/ci/Cargo.toml index 0ae8033..9ab91b8 100644 --- a/ci/Cargo.toml +++ b/ci/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Abid Omar "] edition = "2021" repository = "https://github.com/code-input/cli" +homepage = "https://codeinput.com" readme = "../README.md" license = "MIT" keywords = ["cli", "codeowners", "git", "tooling", "binary"] diff --git a/codeinput/Cargo.toml b/codeinput/Cargo.toml index ab0956e..c6d45fc 100644 --- a/codeinput/Cargo.toml +++ b/codeinput/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Abid Omar "] edition = "2021" repository = "https://github.com/code-input/cli" +homepage = "https://codeinput.com" readme = "../README.md" license = "MIT" keywords = ["codeowners", "git", "parsing", "analysis", "tooling"] diff --git a/dist/pypi/pyproject.toml b/dist/pypi/pyproject.toml new file mode 100644 index 0000000..145cd4e --- /dev/null +++ b/dist/pypi/pyproject.toml @@ -0,0 +1,36 @@ +[build-system] +requires = ["setuptools>=68.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "codeinput" +version = "0.1.0" +description = "A powerful CLI tool for parsing, analyzing, and managing CODEOWNERS files" +readme = "README.md" +license = "MIT" +requires-python = ">=3.8" +authors = [ + { name = "Abid Omar", email = "contact@omarabid.com" }, +] +keywords = ["codeowners", "cli", "git", "github", "ownership"] +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Rust", + "Topic :: Software Development :: Version Control :: Git", + "Topic :: Utilities", +] + +[project.urls] +Homepage = "https://codeinput.com" +Repository = "https://github.com/code-input/cli" +Issues = "https://github.com/code-input/cli/issues" + +[project.scripts] +ci = "codeinput.cli:main" + +[tool.setuptools.packages.find] +where = ["src"] diff --git a/dist/pypi/src/codeinput/__init__.py b/dist/pypi/src/codeinput/__init__.py new file mode 100644 index 0000000..28ee34c --- /dev/null +++ b/dist/pypi/src/codeinput/__init__.py @@ -0,0 +1,8 @@ +"""CodeInput CLI - A powerful CLI tool for CODEOWNERS file management.""" + +try: + from importlib.metadata import version as _version + + __version__ = _version("codeinput") +except Exception: + __version__ = "0.0.0" diff --git a/dist/pypi/src/codeinput/cli.py b/dist/pypi/src/codeinput/cli.py new file mode 100644 index 0000000..cf39691 --- /dev/null +++ b/dist/pypi/src/codeinput/cli.py @@ -0,0 +1,99 @@ +"""CodeInput CLI wrapper that downloads and runs the native binary.""" + +import platform +import stat +import subprocess +import sys +from importlib.metadata import version as get_version +from pathlib import Path + +BINARY_DIR = Path.home() / ".cache" / "codeinput" +GITHUB_REPO = "code-input/cli" +VERSION = get_version("codeinput") + + +def _get_platform_info(): + """Detect the current platform and return (os, arch) tuple.""" + system = platform.system().lower() + machine = platform.machine().lower() + + if system == "linux": + os_name = "linux" + elif system == "darwin": + os_name = "macos" + elif system == "windows": + os_name = "windows" + else: + raise RuntimeError(f"Unsupported operating system: {system}") + + if machine in ("x86_64", "amd64"): + arch = "x86_64" + elif machine in ("aarch64", "arm64"): + arch = "aarch64" + else: + raise RuntimeError(f"Unsupported architecture: {machine}") + + return os_name, arch + + +def _get_binary_name(os_name, arch): + """Return the binary filename for the given platform.""" + if os_name == "windows": + return f"ci-{os_name}-{arch}.exe" + return f"ci-{os_name}-{arch}" + + +def _get_binary_path(): + """Return the local path where the binary should be stored.""" + os_name, arch = _get_platform_info() + binary_name = _get_binary_name(os_name, arch) + return BINARY_DIR / VERSION / binary_name + + +def _download_binary(): + """Download the binary from GitHub releases.""" + os_name, arch = _get_platform_info() + binary_name = _get_binary_name(os_name, arch) + url = f"https://github.com/{GITHUB_REPO}/releases/download/v{VERSION}/{binary_name}" + + binary_path = _get_binary_path() + binary_path.parent.mkdir(parents=True, exist_ok=True) + + import urllib.request + import urllib.error + + try: + urllib.request.urlretrieve(url, binary_path) + except urllib.error.HTTPError as e: + print(f"Error downloading binary: {e}", file=sys.stderr) + print(f"URL: {url}", file=sys.stderr) + sys.exit(1) + + if os_name != "windows": + binary_path.chmod(binary_path.stat().st_mode | stat.S_IEXEC) + + return binary_path + + +def _ensure_binary(): + """Ensure the binary is available, downloading if necessary.""" + binary_path = _get_binary_path() + if binary_path.exists(): + return binary_path + return _download_binary() + + +def main(): + """Run the CodeInput CLI.""" + try: + binary_path = _ensure_binary() + except Exception as e: + print(f"Error setting up CodeInput binary: {e}", file=sys.stderr) + sys.exit(1) + + result = subprocess.run([str(binary_path)] + sys.argv[1:]) + sys.exit(result.returncode) + + +if __name__ == "__main__": + main() From 023757662c2e4bf3c21424051f3845846aed5996 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Thu, 16 Apr 2026 00:38:19 +0700 Subject: [PATCH 16/16] fix(actions): copy README file for pypi action --- .github/workflows/publish-pypi.yml | 3 +++ dist/pypi/pyproject.toml | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 1ef1d56..963d1cf 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -44,6 +44,9 @@ jobs: run: | sed -i "s/^version = \".*\"/version = \"${{ steps.version.outputs.version }}\"/" pyproject.toml + - name: Copy README + run: cp README.md dist/pypi/README.md + - name: Build package working-directory: dist/pypi run: | diff --git a/dist/pypi/pyproject.toml b/dist/pypi/pyproject.toml index 145cd4e..db9325f 100644 --- a/dist/pypi/pyproject.toml +++ b/dist/pypi/pyproject.toml @@ -6,8 +6,8 @@ build-backend = "setuptools.build_meta" name = "codeinput" version = "0.1.0" description = "A powerful CLI tool for parsing, analyzing, and managing CODEOWNERS files" -readme = "README.md" license = "MIT" +license-files = [] requires-python = ">=3.8" authors = [ { name = "Abid Omar", email = "contact@omarabid.com" }, @@ -17,7 +17,7 @@ classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", "Programming Language :: Rust", "Topic :: Software Development :: Version Control :: Git",