From 7544998d9368fdcc2380f3c3793b9c31f93cc340 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 21 Oct 2024 10:17:08 +0200 Subject: [PATCH] * feat(extension.ts): add support for localization in Gitea Git Clone extension * feat(extension.ts): add command to clone a repository from Gitea --- gitea-git-clone/i18n/package.nls.de.json | 33 +++++ gitea-git-clone/i18n/package.nls.json | 33 +++++ gitea-git-clone/package-lock.json | 17 ++- gitea-git-clone/package.json | 7 +- gitea-git-clone/src/extension.ts | 150 +++++++++++++++++++---- 5 files changed, 212 insertions(+), 28 deletions(-) create mode 100644 gitea-git-clone/i18n/package.nls.de.json create mode 100644 gitea-git-clone/i18n/package.nls.json diff --git a/gitea-git-clone/i18n/package.nls.de.json b/gitea-git-clone/i18n/package.nls.de.json new file mode 100644 index 0000000..1c68104 --- /dev/null +++ b/gitea-git-clone/i18n/package.nls.de.json @@ -0,0 +1,33 @@ +{ + "giteaClone.configMissing": "Gitea URL oder Token ist nicht konfiguriert.", + "giteaClone.noValidRepo": "Kein gültiges Git-Repository im aktuellen Workspace gefunden.", + "giteaClone.noRemoteUrl": "Konnte die Git-Remote-URL nicht abrufen.", + "giteaClone.noBranch": "Branch konnte nicht ermittelt werden.", + "giteaClone.pullRequestCreated": "Pull-Request erfolgreich erstellt und im Browser geöffnet.", + "giteaClone.pullRequestError": "Fehler beim Erstellen des Pull Requests: {0}", + "giteaClone.commitError": "Fehler beim Abrufen des letzten Commits.", + "giteaClone.branchError": "Fehler beim Abrufen des Branches.", + "giteaClone.defaultBranchError": "Konnte den base-Branch nicht ermitteln. Standardmäßig wird \"main\" verwendet.", + "giteaClone.createPullRequest": "Gitea PR erstellen", + "giteaClone.createPullRequestTooltip": "Pull Request in Gitea erstellen", + "giteaClone.authSuccess": "Authentifizierung erfolgreich: {0}", + "giteaClone.authFailed": "Authentifizierung fehlgeschlagen.", + "giteaClone.configUpdated": "Gitea-Konfiguration aktualisiert.", + "giteaClone.enterInstanceUrl": "Gitea-Instanz-URL eingeben", + "giteaClone.enterToken": "Gitea Personal Access Token eingeben", + "giteaClone.repoError": "Fehler beim Abrufen der Repositories.", + "giteaClone.apiError": "Fehler bei der Verbindung mit der Gitea API.", + "giteaClone.noRepos": "Keine Repositories gefunden.", + "giteaClone.selectRepo": "Wähle ein Repository zum Klonen aus", + "giteaClone.noRepoSelected": "Kein Repository ausgewählt.", + "giteaClone.selectFolder": "Ordner zum Klonen auswählen", + "giteaClone.cloningRepo": "Klonen von {0}", + "giteaClone.cloningProgress": "Klonvorgang läuft...", + "giteaClone.cloneComplete": "Repository erfolgreich geklont.", + "giteaClone.cloneSuccess": "Repository {0} erfolgreich geklont.", + "giteaClone.cloneError": "Fehler beim Klonen des Repositories.", + "giteaClone.noFolderSelected": "Kein Zielordner ausgewählt.", + "giteaClone.noSshUrl": "Konnte die SSH-Klon-URL nicht finden.", + "giteaClone.openRepoError": "Fehler beim Öffnen des geklonten Repositories." + } + \ No newline at end of file diff --git a/gitea-git-clone/i18n/package.nls.json b/gitea-git-clone/i18n/package.nls.json new file mode 100644 index 0000000..064d654 --- /dev/null +++ b/gitea-git-clone/i18n/package.nls.json @@ -0,0 +1,33 @@ +{ + "giteaClone.configMissing": "Gitea URL or Token is not configured.", + "giteaClone.noValidRepo": "No valid Git repository found in the current workspace.", + "giteaClone.noRemoteUrl": "Could not retrieve Git remote URL.", + "giteaClone.noBranch": "Could not determine the branch.", + "giteaClone.pullRequestCreated": "Pull request created successfully and opened in the browser.", + "giteaClone.pullRequestError": "Error creating pull request: {0}", + "giteaClone.commitError": "Error retrieving the last commit.", + "giteaClone.branchError": "Error retrieving the branch.", + "giteaClone.defaultBranchError": "Could not determine the base branch. Defaulting to \"main\".", + "giteaClone.createPullRequest": "Create Gitea PR", + "giteaClone.createPullRequestTooltip": "Create a Pull Request in Gitea", + "giteaClone.authSuccess": "Authentication successful: {0}", + "giteaClone.authFailed": "Authentication failed.", + "giteaClone.configUpdated": "Gitea configuration updated.", + "giteaClone.enterInstanceUrl": "Enter Gitea instance URL", + "giteaClone.enterToken": "Enter Gitea Personal Access Token", + "giteaClone.repoError": "Error retrieving repositories.", + "giteaClone.apiError": "Error connecting to Gitea API.", + "giteaClone.noRepos": "No repositories found.", + "giteaClone.selectRepo": "Select a repository to clone", + "giteaClone.noRepoSelected": "No repository selected.", + "giteaClone.selectFolder": "Select folder to clone into", + "giteaClone.cloningRepo": "Cloning {0}", + "giteaClone.cloningProgress": "Cloning in progress...", + "giteaClone.cloneComplete": "Repository cloned successfully.", + "giteaClone.cloneSuccess": "Repository {0} cloned successfully.", + "giteaClone.cloneError": "Error cloning the repository.", + "giteaClone.noFolderSelected": "No target folder selected.", + "giteaClone.noSshUrl": "Could not find SSH clone URL.", + "giteaClone.openRepoError": "Error opening the cloned repository." + } + \ No newline at end of file diff --git a/gitea-git-clone/package-lock.json b/gitea-git-clone/package-lock.json index 07c397e..df9b830 100644 --- a/gitea-git-clone/package-lock.json +++ b/gitea-git-clone/package-lock.json @@ -1,15 +1,16 @@ { - "name": "gitea-git-clone", - "version": "0.0.1", + "name": "gitea-workflow", + "version": "1.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "gitea-git-clone", - "version": "0.0.1", + "name": "gitea-workflow", + "version": "1.0.2", "dependencies": { "axios": "^1.7.7", - "open": "^10.1.0" + "open": "^10.1.0", + "vscode-nls": "^5.2.0" }, "devDependencies": { "@types/mocha": "^10.0.8", @@ -4077,6 +4078,12 @@ "node": ">=10.12.0" } }, + "node_modules/vscode-nls": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", + "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", + "license": "MIT" + }, "node_modules/watchpack": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", diff --git a/gitea-git-clone/package.json b/gitea-git-clone/package.json index 06ab578..3906225 100644 --- a/gitea-git-clone/package.json +++ b/gitea-git-clone/package.json @@ -15,7 +15,9 @@ "Other" ], "icon": "media/vscode_gitea_plugin.png", - "activationEvents": ["onStartupFinished"], + "activationEvents": [ + "onStartupFinished" + ], "main": "./dist/extension.js", "contributes": { "commands": [ @@ -79,6 +81,7 @@ }, "dependencies": { "axios": "^1.7.7", - "open": "^10.1.0" + "open": "^10.1.0", + "vscode-nls": "^5.2.0" } } diff --git a/gitea-git-clone/src/extension.ts b/gitea-git-clone/src/extension.ts index e9e95aa..0be0d20 100644 --- a/gitea-git-clone/src/extension.ts +++ b/gitea-git-clone/src/extension.ts @@ -1,6 +1,10 @@ import * as vscode from 'vscode'; import axios from 'axios'; import { exec } from 'child_process'; +import * as nls from 'vscode-nls'; + +// Initialisiere die Lokalisierung +const localize = nls.config({ messageFormat: nls.MessageFormat.file })(); // Funktion zum Erstellen eines Pull Requests async function createGiteaPullRequest() { @@ -8,21 +12,21 @@ async function createGiteaPullRequest() { const token = vscode.workspace.getConfiguration().get('gitea.personalAccessToken'); if (!instanceUrl || !token) { - vscode.window.showErrorMessage('Gitea URL oder Token ist nicht konfiguriert.'); + vscode.window.showErrorMessage(localize('giteaClone.configMissing', 'Gitea URL or Token is not configured.')); return; } // Aktuellen Git-Ordner abrufen const currentWorkspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath; if (!currentWorkspaceFolder) { - vscode.window.showErrorMessage('Kein gültiges Git-Repository im aktuellen Workspace gefunden.'); + vscode.window.showErrorMessage(localize('giteaClone.noValidRepo', 'No valid Git repository found in the current workspace.')); return; } // Git-Repository-Informationen abrufen exec(`git config --get remote.origin.url`, { cwd: currentWorkspaceFolder }, async (error, stdout, stderr) => { if (error || !stdout) { - vscode.window.showErrorMessage('Konnte die Git-Remote-URL nicht abrufen.'); + vscode.window.showErrorMessage(localize('giteaClone.noRemoteUrl', 'Could not retrieve Git remote URL.')); return; } @@ -47,7 +51,7 @@ async function createGiteaPullRequest() { const branch = await getCurrentBranch(currentWorkspaceFolder); if (!branch) { - vscode.window.showErrorMessage('Branch konnte nicht ermittelt werden.'); + vscode.window.showErrorMessage(localize('giteaClone.noBranch', 'Could not determine the branch.')); return; } @@ -80,10 +84,10 @@ async function createGiteaPullRequest() { // Öffne die URL des erstellten PRs im Browser vscode.env.openExternal(vscode.Uri.parse(prUrl)); - vscode.window.showInformationMessage('Pull-Request erfolgreich erstellt und im Browser geöffnet.'); + vscode.window.showInformationMessage(localize('giteaClone.pullRequestCreated', 'Pull request created successfully and opened in the browser.')); } catch (err: any) { - vscode.window.showErrorMessage(`Fehler beim Erstellen des Pull Requests: ${err.message}`); - console.error('Fehler beim Erstellen des PRs:', err); + vscode.window.showErrorMessage(localize('giteaClone.pullRequestError', `Error creating pull request: ${err.message}`)); + console.error('Error creating PR:', err); } }); } @@ -93,7 +97,7 @@ async function getLastCommit(folderPath: string): Promise<{ title: string, body: return new Promise((resolve, reject) => { exec(`git log -1 --pretty=format:"%s%n%b"`, { cwd: folderPath }, (error, stdout) => { if (error) { - reject('Fehler beim Abrufen des letzten Commits.'); + reject(localize('giteaClone.commitError', 'Error retrieving the last commit.')); } else { const output = stdout.split('\n'); const title = output[0]; // Commit-Message als Titel @@ -109,7 +113,7 @@ async function getCurrentBranch(folderPath: string): Promise { return new Promise((resolve, reject) => { exec(`git rev-parse --abbrev-ref HEAD`, { cwd: folderPath }, (error, stdout) => { if (error) { - reject('Fehler beim Abrufen des Branches.'); + reject(localize('giteaClone.branchError', 'Error retrieving the branch.')); } else { resolve(stdout.trim()); } @@ -129,20 +133,120 @@ async function getDefaultBranch(instanceUrl: string, owner: string, repo: string if (response.status === 200 && response.data.default_branch) { return response.data.default_branch; } else { - vscode.window.showErrorMessage('Konnte den base-Branch nicht ermitteln. Standardmäßig "main" verwendet.'); + vscode.window.showErrorMessage(localize('giteaClone.defaultBranchError', 'Could not determine the base branch. Defaulting to "main".')); return 'main'; } } catch (error) { - vscode.window.showErrorMessage('Fehler beim Abrufen des base-Branches. Standardmäßig "main" verwendet.'); + vscode.window.showErrorMessage(localize('giteaClone.defaultBranchError', 'Error retrieving the base branch. Defaulting to "main".')); return 'main'; } } +// Funktion zum Abrufen der Repositories des Benutzers von Gitea +async function getGiteaRepositories(): Promise { + const instanceUrl = vscode.workspace.getConfiguration().get('gitea.instanceUrl'); + const token = vscode.workspace.getConfiguration().get('gitea.personalAccessToken'); + + if (!instanceUrl || !token) { + vscode.window.showErrorMessage(localize('giteaClone.configMissing', 'Gitea URL or Token is not configured.')); + return []; + } + + try { + const response = await axios.get(`${instanceUrl}/api/v1/user/repos`, { + headers: { + 'Authorization': `token ${token}` + } + }); + + if (response.status === 200) { + return response.data; + } else { + vscode.window.showErrorMessage(localize('giteaClone.repoError', 'Error retrieving repositories.')); + return []; + } + } catch (error) { + vscode.window.showErrorMessage(localize('giteaClone.apiError', 'Error connecting to Gitea API.')); + console.error(error); + return []; + } +} + +// Funktion zum Klonen eines Repositories via SSH +async function cloneGiteaRepository() { + const repos = await getGiteaRepositories(); + + if (repos.length === 0) { + vscode.window.showInformationMessage(localize('giteaClone.noRepos', 'No repositories found.')); + return; + } + + const repoNames = repos.map(repo => repo.full_name); + const selectedRepo = await vscode.window.showQuickPick(repoNames, { + placeHolder: localize('giteaClone.selectRepo', 'Select a repository to clone') + }); + + if (!selectedRepo) { + vscode.window.showInformationMessage(localize('giteaClone.noRepoSelected', 'No repository selected.')); + return; + } + + const repo = repos.find(r => r.full_name === selectedRepo); + + if (repo && repo.ssh_url) { + const folderUri = await vscode.window.showOpenDialog({ + canSelectFiles: false, + canSelectFolders: true, + canSelectMany: false, + openLabel: localize('giteaClone.selectFolder', 'Select folder to clone into') + }); + + if (folderUri && folderUri[0]) { + const folderPath = folderUri[0].fsPath; + + vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: localize('giteaClone.cloningRepo', `Cloning ${selectedRepo}`), + cancellable: false + }, async (progress, token) => { + progress.report({ message: localize('giteaClone.cloningProgress', 'Cloning in progress...'), increment: 0 }); + + return new Promise((resolve, reject) => { + exec(`git clone ${repo.ssh_url} ${folderPath}`, (error, stdout, stderr) => { + if (error) { + vscode.window.showErrorMessage(localize('giteaClone.cloneError', 'Error cloning the repository.')); + console.error(stderr); + reject(error); + } else { + progress.report({ message: localize('giteaClone.cloneComplete', 'Repository cloned successfully.'), increment: 100 }); + vscode.window.showInformationMessage(localize('giteaClone.cloneSuccess', `Repository ${selectedRepo} cloned successfully.`)); + + // Öffne das geklonte Repository im VSCode + try { + vscode.commands.executeCommand('vscode.openFolder', vscode.Uri.file(folderPath), true) + .then(() => resolve()); + } catch (err: unknown) { + vscode.window.showErrorMessage(localize('giteaClone.openRepoError', 'Error opening the cloned repository.')); + console.error(err); + reject(err); + } + } + }); + }); + }); + } else { + vscode.window.showInformationMessage(localize('giteaClone.noFolderSelected', 'No target folder selected.')); + } + } else { + vscode.window.showErrorMessage(localize('giteaClone.noSshUrl', 'Could not find SSH clone URL.')); + } +} + // Funktion zum Hinzufügen des Statusbar-Icons function addStatusBarIcon() { const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); - statusBar.text = `$(git-pull-request) Create Gitea PR`; - statusBar.tooltip = 'Create a Pull Request in Gitea'; + statusBar.text = `$(git-pull-request) ${localize('giteaClone.createPullRequest', 'Create Gitea PR')}`; + statusBar.tooltip = localize('giteaClone.createPullRequestTooltip', 'Create a Pull Request in Gitea'); statusBar.command = 'gitea.createPullRequest'; statusBar.show(); // Sofortiges Anzeigen des Icons in der Statusleiste return statusBar; @@ -154,7 +258,7 @@ async function authenticateGitea() { const token = vscode.workspace.getConfiguration().get('gitea.personalAccessToken'); if (!instanceUrl || !token) { - vscode.window.showErrorMessage('Gitea URL oder Token ist nicht konfiguriert.'); + vscode.window.showErrorMessage(localize('giteaClone.configMissing', 'Gitea URL or Token is not configured.')); return; } @@ -166,10 +270,10 @@ async function authenticateGitea() { }); if (response.status === 200) { - vscode.window.showInformationMessage(`Authentifizierung erfolgreich: ${response.data.username}`); + vscode.window.showInformationMessage(localize('giteaClone.authSuccess', `Authentication successful: ${response.data.username}`)); } } catch (error) { - vscode.window.showErrorMessage('Authentifizierung fehlgeschlagen.'); + vscode.window.showErrorMessage(localize('giteaClone.authFailed', 'Authentication failed.')); console.error(error); } } @@ -177,20 +281,20 @@ async function authenticateGitea() { // Funktion zur Konfiguration der Gitea-Instanz und des Tokens über die Command Palette async function configureGitea() { const instanceUrl = await vscode.window.showInputBox({ - prompt: "Gitea Instanz-URL eingeben", - placeHolder: "https://your-gitea-instance.com" + prompt: localize('giteaClone.enterInstanceUrl', 'Enter Gitea instance URL'), + placeHolder: 'https://your-gitea-instance.com' }); const token = await vscode.window.showInputBox({ - prompt: "Gitea Personal Access Token eingeben", - placeHolder: "token", + prompt: localize('giteaClone.enterToken', 'Enter Gitea Personal Access Token'), + placeHolder: 'token', password: true }); if (instanceUrl && token) { await vscode.workspace.getConfiguration().update('gitea.instanceUrl', instanceUrl, vscode.ConfigurationTarget.Global); await vscode.workspace.getConfiguration().update('gitea.personalAccessToken', token, vscode.ConfigurationTarget.Global); - vscode.window.showInformationMessage('Gitea Konfiguration aktualisiert.'); + vscode.window.showInformationMessage(localize('giteaClone.configUpdated', 'Gitea configuration updated.')); } } @@ -211,6 +315,10 @@ export function activate(context: vscode.ExtensionContext) { // Statusbar-Icon sofort anzeigen const statusBar = addStatusBarIcon(); // Icon wird sofort beim Aktivieren angezeigt context.subscriptions.push(statusBar); + + // Befehl zum Klonen eines Repositories + let cloneCommand = vscode.commands.registerCommand('gitea.cloneRepository', cloneGiteaRepository); + context.subscriptions.push(cloneCommand); } // Deaktivierungsfunktion des Plugins