| |
| |
| |
| |
| |
|
|
| import { debugLogger } from '@google/gemini-cli-core'; |
| import { execSync } from 'node:child_process'; |
| import { ProxyAgent } from 'undici'; |
|
|
| |
| |
| |
| |
| export const isGitHubRepository = (): boolean => { |
| try { |
| const remotes = ( |
| execSync('git remote -v', { |
| encoding: 'utf-8', |
| }) || '' |
| ).trim(); |
|
|
| const pattern = /github\.com/; |
|
|
| return pattern.test(remotes); |
| } catch (error) { |
| |
| debugLogger.debug(`Failed to get git remote:`, error); |
| return false; |
| } |
| }; |
|
|
| |
| |
| |
| |
| |
| export const getGitRepoRoot = (): string => { |
| const gitRepoRoot = ( |
| execSync('git rev-parse --show-toplevel', { |
| encoding: 'utf-8', |
| }) || '' |
| ).trim(); |
|
|
| if (!gitRepoRoot) { |
| throw new Error(`Git repo returned empty value`); |
| } |
|
|
| return gitRepoRoot; |
| }; |
|
|
| |
| |
| |
| |
| export const getLatestGitHubRelease = async ( |
| proxy?: string, |
| ): Promise<string> => { |
| try { |
| const controller = new AbortController(); |
|
|
| const endpoint = `https://api.github.com/repos/google-github-actions/run-gemini-cli/releases/latest`; |
|
|
| const response = await fetch(endpoint, { |
| method: 'GET', |
| headers: { |
| Accept: 'application/vnd.github+json', |
| 'Content-Type': 'application/json', |
| 'X-GitHub-Api-Version': '2022-11-28', |
| }, |
| dispatcher: proxy ? new ProxyAgent(proxy) : undefined, |
| |
| signal: ( |
| AbortSignal as unknown as { |
| any: (signals: AbortSignal[]) => AbortSignal; |
| } |
| ).any([AbortSignal.timeout(30_000), controller.signal]), |
| |
| } as RequestInit); |
|
|
| if (!response.ok) { |
| throw new Error( |
| `Invalid response code: ${response.status} - ${response.statusText}`, |
| ); |
| } |
|
|
| |
| const releaseTag = (await response.json()).tag_name; |
| if (!releaseTag) { |
| throw new Error(`Response did not include tag_name field`); |
| } |
| return typeof releaseTag === 'string' ? releaseTag : ''; |
| } catch (error) { |
| debugLogger.debug( |
| `Failed to determine latest run-gemini-cli release:`, |
| error, |
| ); |
| throw new Error( |
| `Unable to determine the latest run-gemini-cli release on GitHub.`, |
| ); |
| } |
| }; |
|
|
| |
| |
| |
| |
| |
| export function getGitHubRepoInfo(): { owner: string; repo: string } { |
| const remoteUrl = execSync('git remote get-url origin', { |
| encoding: 'utf-8', |
| }).trim(); |
|
|
| |
| let urlToParse = remoteUrl; |
| if (remoteUrl.startsWith('git@github.com:')) { |
| urlToParse = remoteUrl.replace('git@github.com:', ''); |
| } else if (remoteUrl.startsWith('git@')) { |
| |
| throw new Error( |
| `Owner & repo could not be extracted from remote URL: ${remoteUrl}`, |
| ); |
| } |
|
|
| let parsedUrl: URL; |
| try { |
| parsedUrl = new URL(urlToParse, 'https://github.com'); |
| } catch { |
| throw new Error( |
| `Owner & repo could not be extracted from remote URL: ${remoteUrl}`, |
| ); |
| } |
|
|
| if (parsedUrl.host !== 'github.com') { |
| throw new Error( |
| `Owner & repo could not be extracted from remote URL: ${remoteUrl}`, |
| ); |
| } |
|
|
| const parts = parsedUrl.pathname.split('/').filter((part) => part !== ''); |
| if (parts.length !== 2 || !parts[0] || !parts[1]) { |
| throw new Error( |
| `Owner & repo could not be extracted from remote URL: ${remoteUrl}`, |
| ); |
| } |
|
|
| return { owner: parts[0], repo: parts[1].replace(/\.git$/, '') }; |
| } |
|
|