diff --git a/gitea-git-clone/CHANGELOG.md b/gitea-git-clone/CHANGELOG.md index 8ab2cec..b4a44f6 100644 --- a/gitea-git-clone/CHANGELOG.md +++ b/gitea-git-clone/CHANGELOG.md @@ -2,7 +2,19 @@ All notable changes to the “gitea-workflow” extension will be documented in this file. -### 1.4.1 +## 1.5.0 + +### Added +- **Gitea Actions Integration**: + - Displays the current Action status (running, success, failure) in the status bar. + - Clicking on the icon opens the Action run in the browser. + - Updates periodically and on focus change. + +### Changed +- **Dependencies**: Ensure your Gitea instance supports Gitea Actions for this feature to work. + + +## 1.4.1 ### Changed diff --git a/gitea-git-clone/README.md b/gitea-git-clone/README.md index 32cc04c..9f2ca76 100644 --- a/gitea-git-clone/README.md +++ b/gitea-git-clone/README.md @@ -13,6 +13,14 @@ Create and view Pull Requests (PRs), manage multiple Gitea instances, and view b - **Create Pull Requests**: Create Pull Requests (PRs) directly from your workspace. - **Enhanced Status Bar Integration**: View the current branch status and build status directly from the VSCode status bar. - **Create Repositories**: Create new repositories in Gitea directly from VSCode, with options for organization, visibility, and .gitignore templates. +- **Gitea Actions Support**:This extension now displays the status of the latest Gitea Action run in the status bar: + - **Running** (with a spinner icon). + - **Success** (with a checkmark). + - **Failure** (with an error icon). + - **Unknown** (with a question mark icon). + Clicking on the icon opens the current action run in your default browser. + _Note_: Gitea Actions must be enabled on your Gitea instance, and you may need a sufficiently recent version of Gitea that supports the `/api/v1/repos/{owner}/{repo}/actions/runs` endpoint. + ## Commands diff --git a/gitea-git-clone/i18n/package.nls.de.json b/gitea-git-clone/i18n/package.nls.de.json index eadedec..aa3420a 100644 --- a/gitea-git-clone/i18n/package.nls.de.json +++ b/gitea-git-clone/i18n/package.nls.de.json @@ -46,5 +46,7 @@ "giteaClone.selectGitignore": ".gitignore-Template auswählen (optional)", "giteaClone.repoCreated": "Repository '{0}' erfolgreich erstellt.", "giteaClone.createRepoError": "Fehler beim Erstellen des Repositories: {0}", - "giteaClone.invalidRepoName": "Ungültiger Repository-Name." + "giteaClone.invalidRepoName": "Ungültiger Repository-Name.", + "giteaClone.actionStatusTooltip": "Gitea Action Status", + "giteaClone.noActionRun": "Keine aktuelle Action-Run-URL gefunden." } diff --git a/gitea-git-clone/i18n/package.nls.json b/gitea-git-clone/i18n/package.nls.json index bcd42fc..71ba534 100644 --- a/gitea-git-clone/i18n/package.nls.json +++ b/gitea-git-clone/i18n/package.nls.json @@ -46,5 +46,7 @@ "giteaClone.selectGitignore": "Select a .gitignore template (optional)", "giteaClone.repoCreated": "Repository '{0}' created successfully.", "giteaClone.createRepoError": "Error creating repository: {0}", - "giteaClone.invalidRepoName": "Invalid repository name." + "giteaClone.invalidRepoName": "Invalid repository name.", + "giteaClone.actionStatusTooltip": "Gitea Action Status", + "giteaClone.noActionRun": "No current action run URL found." } diff --git a/gitea-git-clone/package.json b/gitea-git-clone/package.json index bffc0b1..057057f 100644 --- a/gitea-git-clone/package.json +++ b/gitea-git-clone/package.json @@ -2,7 +2,7 @@ "name": "gitea-workflow", "displayName": "Gitea Workflow", "description": "Clone from Gitea instances; Create PRs", - "version": "1.4.1", + "version": "1.5.0", "publisher": "computerliebe", "engines": { "vscode": "^1.94.0" @@ -21,6 +21,10 @@ "main": "./dist/extension.js", "contributes": { "commands": [ + { + "command": "gitea.openActionRun", + "title": "Gitea: Open Current Action Run" + }, { "command": "gitea.createPullRequest", "title": "Create Pull Request", diff --git a/gitea-git-clone/src/extension.ts b/gitea-git-clone/src/extension.ts index 61037d3..c687832 100644 --- a/gitea-git-clone/src/extension.ts +++ b/gitea-git-clone/src/extension.ts @@ -35,7 +35,18 @@ let prStatusBarItem: vscode.StatusBarItem | null = null; let branchStatusBarItem: vscode.StatusBarItem | null = null; let buildStatusBarItem: vscode.StatusBarItem | null = null; -// Hilfsfunktion, um die Gitea-Instanzen zu laden +// Neues Statusleisten-Icon für Actions +let actionStatusBarItem: vscode.StatusBarItem | null = null; + +/** + * Variable zum Speichern der aktuellen Action-URL. + * Wird genutzt, um beim Klick auf das Status-Icon die Action-Seite zu öffnen. + */ +let currentActionRunUrl: string | null = null; + +/** + * Hilfsfunktion, um die Gitea-Instanzen zu laden + */ function getGiteaInstances(): GiteaInstance[] { const instances = vscode.workspace.getConfiguration().get('gitea.instances'); if (!instances) { @@ -48,7 +59,9 @@ function getGiteaInstances(): GiteaInstance[] { })); } -// Hilfsfunktion, um die passende Gitea-Instanz basierend auf der Remote-URL zu ermitteln +/** + * Hilfsfunktion, um die passende Gitea-Instanz basierend auf der Remote-URL zu ermitteln + */ async function getMatchingGiteaInstance(folderPath: string): Promise { const instances = getGiteaInstances(); if (instances.length === 0) { @@ -79,7 +92,9 @@ async function getMatchingGiteaInstance(folderPath: string): Promise { return new Promise((resolve) => { exec(`git rev-parse --is-inside-work-tree`, { cwd: folderPath }, (error) => { @@ -88,16 +103,299 @@ async function isGitRepository(folderPath: string): Promise { }); } -// Helper function to slugify the repository name +/** + * Helper function to slugify the repository name + */ function slugify(text: string): string { return text .toString() .toLowerCase() .trim() - .replace(/[\s\W-]+/g, '-'); // Replace spaces and non-word characters with a dash + .replace(/[\\s\\W-]+/g, '-'); // Replace spaces and non-word characters with a dash } -// UPDATED FUNCTION: Creating a Repository in Gitea +/** + * Hilfsfunktion: Ruft den neuesten Gitea Action-Run ab. + * Angepasst für den Endpoint: + * GET /api/v1/repos/{owner}/{repo}/actions/tasks?page=1&limit=1 + */ +async function getGiteaActionStatus( + instanceUrl: string, + owner: string, + repo: string, + token: string +): Promise<{ state: string; html_url: string }> { + try { + // Neuer Endpoint für Gitea Actions + // Wir rufen NUR die letzte Action ab -> page=1&limit=1 + const url = `${instanceUrl}/api/v1/repos/${owner}/${repo}/actions/tasks?page=1&limit=1`; + + // Request mit Axios + const response = await axios.get(url, { + headers: { + Authorization: `token ${token}` + } + }); + + // Wir prüfen, ob wir workflow_runs in der Antwort haben + // Laut Ihrem Beispiel: response.data.workflow_runs (Array) + const runs = response.data?.workflow_runs; + if (response.status === 200 && Array.isArray(runs) && runs.length > 0) { + // Nur das erste Element + const latestRun = runs[0]; + + // status: success | failure | running + const state = latestRun.status ?? 'unknown'; + + // url: hier liegt der Link zur Action + const html_url = latestRun.url ?? ''; + + return { + state: state, + html_url: html_url + }; + } else { + return { state: 'unknown', html_url: '' }; + } + + } catch (error) { + console.error('Error fetching Gitea Action status:', error); + return { state: 'unknown', html_url: '' }; + } +} + + +/** + * Aktualisiert das Action-Statusleisten-Icon. + * Zeigt den neuesten Status an (running, success, failure, unknown). + * Bei Klick wird die Gitea-Webansicht der aktuellen Action geöffnet. + */ +async function updateActionStatusBarItem(context: vscode.ExtensionContext) { + try { + const currentWorkspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath; + if (!currentWorkspaceFolder) { + if (actionStatusBarItem) actionStatusBarItem.hide(); + return; + } + + // Prüfen, ob Git-Repo + const isGitRepoResult = await isGitRepository(currentWorkspaceFolder); + if (!isGitRepoResult) { + if (actionStatusBarItem) actionStatusBarItem.hide(); + return; + } + + // Gitea-Instanz ermitteln + const giteaInstance = await getMatchingGiteaInstance(currentWorkspaceFolder); + if (!giteaInstance) { + if (actionStatusBarItem) actionStatusBarItem.hide(); + return; + } + + // Owner/Repo ermitteln + const { owner, repo } = await getRepoInfo(currentWorkspaceFolder); + if (!owner || !repo) { + if (actionStatusBarItem) actionStatusBarItem.hide(); + return; + } + + // Neuesten Action-Status abrufen + const { state, html_url } = await getGiteaActionStatus( + giteaInstance.url, + owner, + repo, + giteaInstance.token + ); + + // Falls wir noch kein actionStatusBarItem haben, erstellen wir es + if (!actionStatusBarItem) { + actionStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); + // Beim Klick soll die Action-Webseite geöffnet werden + actionStatusBarItem.command = 'gitea.openActionRun'; + context.subscriptions.push(actionStatusBarItem); + } + + // Unterschiedliche Anzeige abhängig vom Status + let icon = 'loading~spin'; // "loading~spin" ist ein VSCode Icon + let message = 'Gitea Action: Running'; + + switch (state) { + case 'success': + icon = 'check'; + message = 'Gitea Action: Success'; + break; + case 'failure': + icon = 'error'; + message = 'Gitea Action: Failure'; + break; + case 'running': + case 'queued': + case 'pending': + icon = 'loading~spin'; + message = 'Gitea Action: Running'; + break; + default: + icon = 'question'; + message = 'Gitea Action: Unknown'; + break; + } + + actionStatusBarItem.text = `$(${icon}) ${message}`; + actionStatusBarItem.tooltip = localize('giteaClone.actionStatusTooltip', 'Gitea Action Status'); + actionStatusBarItem.show(); + + // Merken Sie sich die URL global oder in einem Memento, + // damit wir sie beim Klick aufrufen können. + currentActionRunUrl = html_url; + + } catch (error) { + console.error('Error updating action status bar item:', error); + if (actionStatusBarItem) { + actionStatusBarItem.hide(); + } + } +} + +/** + * Befehl: Öffnet die aktuelle Action-Run-Seite im Browser + */ +async function openCurrentActionRun() { + if (currentActionRunUrl) { + vscode.env.openExternal(vscode.Uri.parse(currentActionRunUrl)); + } else { + vscode.window.showInformationMessage( + localize('giteaClone.noActionRun', 'No current action run URL found.') + ); + } +} + +/** + * Startet den Gitea Actions-Status-Updater (zusätzlich zu den anderen Updatern). + */ +function startGiteaActionsStatusUpdater(context: vscode.ExtensionContext) { + // Initiales Update + updateActionStatusBarItem(context); + + // Update beim Fokuswechsel + vscode.window.onDidChangeWindowState((windowState) => { + if (windowState.focused) { + updateActionStatusBarItem(context); + } + }, null, context.subscriptions); + + // Update alle 2 Minuten + setInterval(() => { + updateActionStatusBarItem(context); + }, 120000); +} + +// ------------------------------------------------------------ +// AB HIER: Ihre übrige Plugin-Logik +// ------------------------------------------------------------ + +/** + * Hilfsfunktion zum Abrufen der Benutzerorganisationen + */ +async function getUserOrganizations(instanceUrl: string, token: string): Promise { + try { + const response = await axios.get(`${instanceUrl}/api/v1/user/orgs`, { + headers: { + 'Authorization': `token ${token}` + } + }); + + if (response.status === 200) { + return response.data; + } else { + return []; + } + } catch (err) { + console.error('Error fetching user organizations:', err); + return []; + } +} + +/** + * Hilfsfunktion zum Abrufen der verfügbaren .gitignore-Templates (derzeit nicht genutzt) + */ +async function getGitignoreTemplates(instanceUrl: string, token: string): Promise { + try { + const response = await axios.get(`${instanceUrl}/api/v1/gitignores`, { + headers: { + 'Authorization': `token ${token}` + } + }); + + if (response.status === 200) { + return response.data; + } else { + return []; + } + } catch (err) { + console.error('Error fetching gitignore templates:', err); + return []; + } +} + +/** + * Funktion zum Klonen eines Repositories (Hilfsfunktion) + */ +async function cloneRepository(sshUrl: string, repoName: string) { + 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; + const targetPath = path.join(folderPath, repoName); + + // Überprüfen, ob das Zielverzeichnis bereits existiert + if (fs.existsSync(targetPath)) { + vscode.window.showErrorMessage(localize('giteaClone.targetExists', `The target directory "${targetPath}" already exists.`)); + return; + } + + vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: localize('giteaClone.cloningRepo', `Cloning ${repoName}`), + cancellable: false + }, async (progress, token) => { + progress.report({ message: localize('giteaClone.cloningProgress', 'Cloning in progress...'), increment: 0 }); + + return new Promise((resolve, reject) => { + exec(`git clone ${sshUrl} "${targetPath}"`, (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 ${repoName} cloned successfully.`)); + + // Öffne das geklonte Repository im VSCode + try { + vscode.commands.executeCommand('vscode.openFolder', vscode.Uri.file(targetPath), 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.')); + } +} + +/** + * Funktion zum Erstellen eines Repositories in Gitea + */ async function createGiteaRepository() { const instances = getGiteaInstances(); @@ -227,101 +525,9 @@ async function createGiteaRepository() { } } -// Hilfsfunktion zum Abrufen der Benutzerorganisationen -async function getUserOrganizations(instanceUrl: string, token: string): Promise { - try { - const response = await axios.get(`${instanceUrl}/api/v1/user/orgs`, { - headers: { - 'Authorization': `token ${token}` - } - }); - - if (response.status === 200) { - return response.data; - } else { - return []; - } - } catch (err) { - console.error('Error fetching user organizations:', err); - return []; - } -} - -// Hilfsfunktion zum Abrufen der verfügbaren .gitignore-Templates -async function getGitignoreTemplates(instanceUrl: string, token: string): Promise { - try { - const response = await axios.get(`${instanceUrl}/api/v1/gitignores`, { - headers: { - 'Authorization': `token ${token}` - } - }); - - if (response.status === 200) { - return response.data; - } else { - return []; - } - } catch (err) { - console.error('Error fetching gitignore templates:', err); - return []; - } -} - -// Hilfsfunktion zum Klonen eines Repositories -async function cloneRepository(sshUrl: string, repoName: string) { - 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; - const targetPath = path.join(folderPath, repoName); - - // Überprüfen, ob das Zielverzeichnis bereits existiert - if (fs.existsSync(targetPath)) { - vscode.window.showErrorMessage(localize('giteaClone.targetExists', `The target directory "${targetPath}" already exists.`)); - return; - } - - vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - title: localize('giteaClone.cloningRepo', `Cloning ${repoName}`), - cancellable: false - }, async (progress, token) => { - progress.report({ message: localize('giteaClone.cloningProgress', 'Cloning in progress...'), increment: 0 }); - - return new Promise((resolve, reject) => { - exec(`git clone ${sshUrl} "${targetPath}"`, (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 ${repoName} cloned successfully.`)); - - // Öffne das geklonte Repository im VSCode - try { - vscode.commands.executeCommand('vscode.openFolder', vscode.Uri.file(targetPath), 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.')); - } -} - -// Funktion zum Erstellen eines Pull Requests +/** + * Funktion zum Erstellen eines Pull Requests + */ async function createGiteaPullRequest() { // Aktuellen Workspace-Ordner abrufen const currentWorkspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath; @@ -403,7 +609,7 @@ async function createGiteaPullRequest() { const prData = { title: truncatedTitle, // Der getrunkierte Titel body: truncatedBody || '', // Der getrunkierte Body - head: branch, // Der aktuelle Branch als "head" + head: branch, // Der aktuelle Branch als \"head\" base: baseBranch // Der ermittelte base-Branch }; @@ -459,23 +665,27 @@ async function createGiteaPullRequest() { }); } -// Hilfsfunktion, um den letzten Commit zu ermitteln +/** + * Hilfsfunktion, um den letzten Commit zu ermitteln + */ async function getLastCommit(folderPath: string): Promise<{ title: string, body: string }> { return new Promise((resolve, reject) => { - exec(`git log -1 --pretty=format:"%s%n%b"`, { cwd: folderPath }, (error, stdout) => { + exec(`git log -1 --pretty=format:\"%s%n%b\"`, { cwd: folderPath }, (error, stdout) => { if (error) { reject(localize('giteaClone.commitError', 'Error retrieving the last commit.')); } else { - const output = stdout.split('\n'); + const output = stdout.split('\\n'); const title = output[0]; // Commit-Message als Titel - const body = output.slice(1).join('\n'); // Commit-Kommentar als Body + const body = output.slice(1).join('\\n'); // Commit-Kommentar als Body resolve({ title: title.trim(), body: body.trim() }); } }); }); } -// Hilfsfunktion, um den aktuellen Branch zu ermitteln +/** + * Hilfsfunktion, um den aktuellen Branch zu ermitteln + */ async function getCurrentBranch(folderPath: string): Promise { return new Promise((resolve, reject) => { exec(`git rev-parse --abbrev-ref HEAD`, { cwd: folderPath }, (error, stdout) => { @@ -488,7 +698,9 @@ async function getCurrentBranch(folderPath: string): Promise { }); } -// Hilfsfunktion, um den base-Branch über die Gitea API zu ermitteln +/** + * Hilfsfunktion, um den base-Branch über die Gitea API zu ermitteln + */ async function getDefaultBranch(instanceUrl: string, owner: string, repo: string, token: string): Promise { try { const response = await axios.get(`${instanceUrl}/api/v1/repos/${owner}/${repo}`, { @@ -500,7 +712,7 @@ 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(localize('giteaClone.defaultBranchError', 'Could not determine the base branch. Defaulting to "main".')); + vscode.window.showErrorMessage(localize('giteaClone.defaultBranchError', 'Could not determine the base branch. Defaulting to \"main\".')); return 'main'; } } catch (err: any) { @@ -526,7 +738,9 @@ async function getDefaultBranch(instanceUrl: string, owner: string, repo: string } } -// Funktion zum Abrufen der Repositories des Benutzers von Gitea +/** + * Funktion zum Abrufen der Repositories des Benutzers von Gitea + */ async function getGiteaRepositories(): Promise { const instances = getGiteaInstances(); @@ -593,7 +807,9 @@ async function getGiteaRepositories(): Promise { } } -// Funktion zum Klonen eines Repositories via SSH +/** + * Funktion zum Klonen eines Repositories via SSH + */ async function cloneGiteaRepository() { const repos = await getGiteaRepositories(); @@ -629,7 +845,7 @@ async function cloneGiteaRepository() { // Überprüfen, ob das Zielverzeichnis bereits existiert if (fs.existsSync(targetPath)) { - vscode.window.showErrorMessage(localize('giteaClone.targetExists', `The target directory "${targetPath}" already exists.`)); + vscode.window.showErrorMessage(localize('giteaClone.targetExists', `The target directory \"${targetPath}\" already exists.`)); return; } @@ -641,7 +857,7 @@ async function cloneGiteaRepository() { progress.report({ message: localize('giteaClone.cloningProgress', 'Cloning in progress...'), increment: 0 }); return new Promise((resolve, reject) => { - exec(`git clone ${repo.ssh_url} "${targetPath}"`, (error, stdout, stderr) => { + exec(`git clone ${repo.ssh_url} \"${targetPath}\"`, (error, stdout, stderr) => { if (error) { vscode.window.showErrorMessage(localize('giteaClone.cloneError', 'Error cloning the repository.')); console.error(stderr); @@ -671,7 +887,9 @@ async function cloneGiteaRepository() { } } -// Funktion zum Hinzufügen des Statusleisten-Icons +/** + * Funktion zum Hinzufügen des Statusleisten-Icons + */ async function addStatusBarIcon() { const currentWorkspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath; if (!currentWorkspaceFolder) { @@ -700,7 +918,9 @@ async function addStatusBarIcon() { return statusBar; } -// Funktion zur Authentifizierung bei Gitea mit dem Personal Access Token (PAT) +/** + * Funktion zur Authentifizierung bei Gitea + */ async function authenticateGitea() { const instances = getGiteaInstances(); @@ -763,7 +983,9 @@ async function authenticateGitea() { } } -// Funktion zur Konfiguration der Gitea-Instanzen und Tokens über die Command Palette +/** + * Funktion zur Konfiguration der Gitea-Instanzen und Tokens über die Command Palette + */ async function configureGitea() { const instances = getGiteaInstances(); @@ -837,7 +1059,9 @@ async function configureGitea() { } } -// Funktion zum Abrufen offener Pull Requests +/** + * Funktion zum Abrufen offener Pull Requests + */ async function getOpenPullRequests(): Promise { // Aktuellen Workspace-Ordner abrufen const currentWorkspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath; @@ -852,7 +1076,6 @@ async function getOpenPullRequests(): Promise { return []; } - // Passende Gitea-Instanz ermitteln const giteaInstance = await getMatchingGiteaInstance(currentWorkspaceFolder); if (!giteaInstance) { // Keine passende Gitea-Instanz gefunden @@ -862,7 +1085,6 @@ async function getOpenPullRequests(): Promise { const instanceUrl = giteaInstance.url; const token = giteaInstance.token; - // Git-Repository-Informationen abrufen const { owner, repo } = await getRepoInfo(currentWorkspaceFolder); if (!owner || !repo) { vscode.window.showErrorMessage(localize('giteaClone.repoInfoError', 'Could not retrieve repository information.')); @@ -909,7 +1131,9 @@ async function getOpenPullRequests(): Promise { } } -// Hilfsfunktion zum Abrufen von Repository-Informationen +/** + * Hilfsfunktion, um Repository-Informationen abzurufen + */ async function getRepoInfo(folderPath: string): Promise<{ owner: string, repo: string }> { return new Promise((resolve, reject) => { exec(`git config --get remote.origin.url`, { cwd: folderPath }, (error, stdout) => { @@ -935,7 +1159,9 @@ async function getRepoInfo(folderPath: string): Promise<{ owner: string, repo: s }); } -// Funktion zum Anzeigen offener Pull Requests +/** + * Funktion zum Anzeigen offener Pull Requests + */ async function showOpenPullRequests() { const pullRequests = await getOpenPullRequests(); @@ -960,7 +1186,9 @@ async function showOpenPullRequests() { } } -// Funktion zum Aktualisieren des PR-Statusleisten-Icons +/** + * Funktion zum Aktualisieren des PR-Statusleisten-Icons + */ async function updatePRStatusBarItem(context: vscode.ExtensionContext) { try { const currentWorkspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath; @@ -975,7 +1203,6 @@ async function updatePRStatusBarItem(context: vscode.ExtensionContext) { return; } - // Passende Gitea-Instanz ermitteln const giteaInstance = await getMatchingGiteaInstance(currentWorkspaceFolder); if (!giteaInstance) { if (prStatusBarItem) prStatusBarItem.hide(); @@ -1002,7 +1229,9 @@ async function updatePRStatusBarItem(context: vscode.ExtensionContext) { } } -// Funktion zum Aktualisieren des Branch-Statusleisten-Icons +/** + * Funktion zum Aktualisieren des Branch-Statusleisten-Icons + */ async function updateBranchStatusBarItem() { try { const currentWorkspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath; @@ -1025,7 +1254,6 @@ async function updateBranchStatusBarItem() { branchStatusBarItem.command = 'git.checkout'; } - // Überprüfen, ob der Branch up-to-date ist const branchStatus = await getBranchStatus(currentWorkspaceFolder, branch); branchStatusBarItem.text = `$(git-branch) ${branch} ${branchStatus}`; @@ -1038,7 +1266,9 @@ async function updateBranchStatusBarItem() { } } -// Hilfsfunktion, um den Branch-Status zu ermitteln +/** + * Hilfsfunktion, um den Branch-Status zu ermitteln + */ async function getBranchStatus(folderPath: string, branch: string): Promise { return new Promise((resolve) => { exec(`git status -sb`, { cwd: folderPath }, (error, stdout) => { @@ -1063,7 +1293,9 @@ async function getBranchStatus(folderPath: string, branch: string): Promise { return new Promise((resolve) => { exec(`git rev-parse HEAD`, { cwd: folderPath }, (error, stdout) => { @@ -1129,7 +1358,9 @@ async function getCurrentCommitHash(folderPath: string): Promise { }); } -// Hilfsfunktion, um den Build-Status von Gitea abzurufen +/** + * Hilfsfunktion, um den Build-Status von Gitea abzurufen + */ async function getBuildStatus(instanceUrl: string, owner: string, repo: string, commitHash: string, token: string): Promise { try { const response = await axios.get(`${instanceUrl}/api/v1/repos/${owner}/${repo}/statuses/${commitHash}`, { @@ -1150,7 +1381,9 @@ async function getBuildStatus(instanceUrl: string, owner: string, repo: string, } } -// Funktion zum Starten des Build- und Branch-Status-Updaters +/** + * Funktion zum Starten des Build- und Branch-Status-Updaters + */ function startStatusBarItemUpdater(context: vscode.ExtensionContext) { updateBranchStatusBarItem(); updateBuildStatusBarItem(); @@ -1170,7 +1403,9 @@ function startStatusBarItemUpdater(context: vscode.ExtensionContext) { }, 120000); // 2 Minuten } -// Aktivierungsfunktion des Plugins +/** + * Aktivierungsfunktion des Plugins + */ export async function activate(context: vscode.ExtensionContext) { // Registriert den Befehl zur Authentifizierung let authCommand = vscode.commands.registerCommand('gitea.authenticate', authenticateGitea); @@ -1196,6 +1431,13 @@ export async function activate(context: vscode.ExtensionContext) { let createRepoCommand = vscode.commands.registerCommand('gitea.createRepository', createGiteaRepository); context.subscriptions.push(createRepoCommand); + // NEUER BEFEHL zum Öffnen der aktuellen Action + let openActionRunCommand = vscode.commands.registerCommand( + 'gitea.openActionRun', + openCurrentActionRun + ); + context.subscriptions.push(openActionRunCommand); + // Statusleisten-Icon erstellen statusBarItem = await addStatusBarIcon(); if (statusBarItem) { @@ -1238,7 +1480,12 @@ export async function activate(context: vscode.ExtensionContext) { // Starten Sie den Branch- und Build-Statusleisten-Updater startStatusBarItemUpdater(context); + + // Starten Sie den Gitea Actions-Status-Updater + startGiteaActionsStatusUpdater(context); } -// Deaktivierungsfunktion des Plugins +/** + * Deaktivierungsfunktion des Plugins + */ export function deactivate() {}