mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
fix: stop repeated GitHub PR fetch warnings for non-GitHub repos
When opening a git repository without a GitHub remote, the server logs were spammed with warnings every 5 seconds during worktree polling: WARN [Worktree] Failed to fetch GitHub PRs: Command failed: gh pr list ... no git remotes found This happened because fetchGitHubPRs() ran `gh pr list` without first checking if the project has a GitHub remote configured. Changes: - Add per-project cache for GitHub remote status with 5-minute TTL - Check cache before attempting to fetch PRs, skip silently if no remote - Add forceRefreshGitHub parameter to clear cache on manual refresh - Pass forceRefreshGitHub when user clicks the refresh worktrees button This allows users to add a GitHub remote and immediately detect it by clicking the refresh button, while preventing log spam during normal polling for projects without GitHub remotes.
This commit is contained in:
@@ -16,10 +16,27 @@ import { isGitRepo } from '@automaker/git-utils';
|
||||
import { getErrorMessage, logError, normalizePath, execEnv, isGhCliAvailable } from '../common.js';
|
||||
import { readAllWorktreeMetadata, type WorktreePRInfo } from '../../../lib/worktree-metadata.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import {
|
||||
checkGitHubRemote,
|
||||
type GitHubRemoteStatus,
|
||||
} from '../../github/routes/check-github-remote.js';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
const logger = createLogger('Worktree');
|
||||
|
||||
/**
|
||||
* Cache for GitHub remote status per project path.
|
||||
* This prevents repeated "no git remotes found" warnings when polling
|
||||
* projects that don't have a GitHub remote configured.
|
||||
*/
|
||||
interface GitHubRemoteCacheEntry {
|
||||
status: GitHubRemoteStatus;
|
||||
checkedAt: number;
|
||||
}
|
||||
|
||||
const githubRemoteCache = new Map<string, GitHubRemoteCacheEntry>();
|
||||
const GITHUB_REMOTE_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
interface WorktreeInfo {
|
||||
path: string;
|
||||
branch: string;
|
||||
@@ -121,23 +138,63 @@ async function scanWorktreesDirectory(
|
||||
return discovered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached GitHub remote status for a project, or check and cache it.
|
||||
* Returns null if gh CLI is not available.
|
||||
*/
|
||||
async function getGitHubRemoteStatus(projectPath: string): Promise<GitHubRemoteStatus | null> {
|
||||
// Check if gh CLI is available first
|
||||
const ghAvailable = await isGhCliAvailable();
|
||||
if (!ghAvailable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const cached = githubRemoteCache.get(projectPath);
|
||||
|
||||
// Return cached result if still valid
|
||||
if (cached && now - cached.checkedAt < GITHUB_REMOTE_CACHE_TTL_MS) {
|
||||
return cached.status;
|
||||
}
|
||||
|
||||
// Check GitHub remote and cache the result
|
||||
const status = await checkGitHubRemote(projectPath);
|
||||
githubRemoteCache.set(projectPath, {
|
||||
status,
|
||||
checkedAt: now,
|
||||
});
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch open PRs from GitHub and create a map of branch name to PR info.
|
||||
* This allows detecting PRs that were created outside the app.
|
||||
*
|
||||
* Uses cached GitHub remote status to avoid repeated warnings when the
|
||||
* project doesn't have a GitHub remote configured.
|
||||
*/
|
||||
async function fetchGitHubPRs(projectPath: string): Promise<Map<string, WorktreePRInfo>> {
|
||||
const prMap = new Map<string, WorktreePRInfo>();
|
||||
|
||||
try {
|
||||
// Check if gh CLI is available
|
||||
const ghAvailable = await isGhCliAvailable();
|
||||
if (!ghAvailable) {
|
||||
// Check GitHub remote status (uses cache to avoid repeated warnings)
|
||||
const remoteStatus = await getGitHubRemoteStatus(projectPath);
|
||||
|
||||
// If gh CLI not available or no GitHub remote, return empty silently
|
||||
if (!remoteStatus || !remoteStatus.hasGitHubRemote) {
|
||||
return prMap;
|
||||
}
|
||||
|
||||
// Use -R flag with owner/repo for more reliable PR fetching
|
||||
const repoFlag =
|
||||
remoteStatus.owner && remoteStatus.repo
|
||||
? `-R ${remoteStatus.owner}/${remoteStatus.repo}`
|
||||
: '';
|
||||
|
||||
// Fetch open PRs from GitHub
|
||||
const { stdout } = await execAsync(
|
||||
'gh pr list --state open --json number,title,url,state,headRefName,createdAt --limit 1000',
|
||||
`gh pr list ${repoFlag} --state open --json number,title,url,state,headRefName,createdAt --limit 1000`,
|
||||
{ cwd: projectPath, env: execEnv, timeout: 15000 }
|
||||
);
|
||||
|
||||
@@ -170,9 +227,10 @@ async function fetchGitHubPRs(projectPath: string): Promise<Map<string, Worktree
|
||||
export function createListHandler() {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, includeDetails } = req.body as {
|
||||
const { projectPath, includeDetails, forceRefreshGitHub } = req.body as {
|
||||
projectPath: string;
|
||||
includeDetails?: boolean;
|
||||
forceRefreshGitHub?: boolean;
|
||||
};
|
||||
|
||||
if (!projectPath) {
|
||||
@@ -180,6 +238,12 @@ export function createListHandler() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear GitHub remote cache if force refresh requested
|
||||
// This allows users to re-check for GitHub remote after adding one
|
||||
if (forceRefreshGitHub) {
|
||||
githubRemoteCache.delete(projectPath);
|
||||
}
|
||||
|
||||
if (!(await isGitRepo(projectPath))) {
|
||||
res.json({ success: true, worktrees: [] });
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user