Streamline github error handling

This commit is contained in:
Sam Becker 2025-02-15 17:49:02 -06:00
parent 13b8cdcf62
commit 7027e85530
4 changed files with 32 additions and 66 deletions

View File

@ -1,50 +1,44 @@
import { import {
getGitHubMetaWithFallback, getGitHubMeta,
getGitHubPublicFork, getGitHubPublicFork,
} from '@/platforms/github'; } from '@/platforms/github';
import { TEMPLATE_REPO_OWNER, TEMPLATE_REPO_NAME } from '@/app-core/config'; import { TEMPLATE_REPO_OWNER, TEMPLATE_REPO_NAME } from '@/app-core/config';
describe('GitHub', () => { describe('GitHub', () => {
it('fetches base repo meta', async () => { it('fetches base repo meta', async () => {
const meta = await getGitHubMetaWithFallback({ const meta = await getGitHubMeta({
owner: TEMPLATE_REPO_OWNER, owner: TEMPLATE_REPO_OWNER,
repo: TEMPLATE_REPO_NAME, repo: TEMPLATE_REPO_NAME,
}); });
expect(meta).toBeDefined(); expect(meta).toBeDefined();
expect(meta.urlRepo).toBeDefined(); expect(meta.urlRepo).toBeDefined();
expect(meta.isForkedFromBase).toEqual(false); expect(meta.isForkedFromBase).toEqual(false);
expect(meta.label).toBeDefined();
expect(meta.description).toBeDefined();
expect(meta.isBehind).toEqual(false); expect(meta.isBehind).toEqual(false);
expect(meta.isBaseRepo).toBe(true); expect(meta.isBaseRepo).toBe(true);
}); });
it('fetches fork meta', async () => { it('fetches fork meta', async () => {
const fork = await getGitHubPublicFork(); const fork = await getGitHubPublicFork();
const metaFork = await getGitHubMetaWithFallback(fork); const metaFork = await getGitHubMeta(fork);
expect(metaFork.isForkedFromBase).toEqual(true); expect(metaFork.isForkedFromBase).toEqual(true);
}); });
it('handles nonexistent repos', async () => { it('handles nonexistent repos', async () => {
const meta = await getGitHubMetaWithFallback({ const meta = await getGitHubMeta({
owner: 'nonexistent', owner: 'nonexistent',
repo: 'nonexistent', repo: 'nonexistent',
}); });
expect(meta).toBeDefined(); expect(meta).toBeDefined();
expect(meta.urlRepo).toBeDefined(); expect(meta.urlRepo).toBeDefined();
expect(meta.isForkedFromBase).toEqual(false); expect(meta.isForkedFromBase).toEqual(false);
expect(meta.label).toEqual('Unknown');
expect(meta.description).toEqual('Unknown');
expect(meta.isBehind).toBeUndefined(); expect(meta.isBehind).toBeUndefined();
}); });
it('handles fetch errors', async () => { it('handles fetch errors', async () => {
const meta = await getGitHubMetaWithFallback({ const meta = await getGitHubMeta({
owner: 'gibberish / / *', owner: 'gibberish / / *',
repo: 'bad text for a url.com', repo: 'bad text for a url.com',
}); });
expect(meta).toBeDefined(); expect(meta).toBeDefined();
expect(meta.urlRepo).toBeDefined(); expect(meta.urlRepo).toBeDefined();
expect(meta.isForkedFromBase).toEqual(false); expect(meta.isForkedFromBase).toEqual(false);
expect(meta.label).toEqual('Unknown');
expect(meta.description).toEqual('Unknown');
expect(meta.isBehind).toBeUndefined(); expect(meta.isBehind).toBeUndefined();
}); });
}); });

View File

@ -19,7 +19,7 @@ import {
VERCEL_GIT_REPO_OWNER, VERCEL_GIT_REPO_OWNER,
VERCEL_GIT_REPO_SLUG, VERCEL_GIT_REPO_SLUG,
} from '@/app-core/config'; } from '@/app-core/config';
import { getGitHubMetaWithFallback } from '../../platforms/github'; import { getGitHubMeta } from '../../platforms/github';
import { OUTDATED_THRESHOLD } from '@/photo'; import { OUTDATED_THRESHOLD } from '@/photo';
const BASIC_PHOTO_INSTALLATION_COUNT = 32; const BASIC_PHOTO_INSTALLATION_COUNT = 32;
@ -50,7 +50,7 @@ export default async function AdminAppInsights() {
getUniqueFilmSimulations(), getUniqueFilmSimulations(),
getUniqueLenses(), getUniqueLenses(),
IS_VERCEL_GIT_PROVIDER_GITHUB || IS_DEVELOPMENT IS_VERCEL_GIT_PROVIDER_GITHUB || IS_DEVELOPMENT
? getGitHubMetaWithFallback({ ? getGitHubMeta({
owner, owner,
repo, repo,
branch, branch,

View File

@ -11,7 +11,7 @@ import { HiOutlinePhotograph } from 'react-icons/hi';
import { MdAspectRatio } from 'react-icons/md'; import { MdAspectRatio } from 'react-icons/md';
import { PiWarningBold } from 'react-icons/pi'; import { PiWarningBold } from 'react-icons/pi';
import { TbCone, TbSparkles } from 'react-icons/tb'; import { TbCone, TbSparkles } from 'react-icons/tb';
import { getGitHubMetaWithFallback } from '../../platforms/github'; import { getGitHubMeta } from '../../platforms/github';
import { BiGitBranch, BiGitCommit, BiLogoGithub } from 'react-icons/bi'; import { BiGitBranch, BiGitCommit, BiLogoGithub } from 'react-icons/bi';
import { import {
TEMPLATE_REPO_BRANCH, TEMPLATE_REPO_BRANCH,
@ -74,7 +74,7 @@ export default function AdminAppInsightsClient({
}, },
debug, debug,
}: { }: {
codeMeta?: Awaited<ReturnType<typeof getGitHubMetaWithFallback>> codeMeta?: Awaited<ReturnType<typeof getGitHubMeta>>
insights: AdminAppInsights insights: AdminAppInsights
photoStats: PhotoStats photoStats: PhotoStats
debug?: boolean debug?: boolean

View File

@ -5,7 +5,6 @@ import {
} from '@/app-core/config'; } from '@/app-core/config';
const DEFAULT_BRANCH = 'main'; const DEFAULT_BRANCH = 'main';
const FALLBACK_TEXT = 'Unknown';
const CACHE_GITHUB_REQUESTS = false; const CACHE_GITHUB_REQUESTS = false;
// Cache all results for 2 minutes to avoid rate limiting // Cache all results for 2 minutes to avoid rate limiting
@ -130,7 +129,7 @@ export const getGitHubPublicFork = async (): Promise<RepoParams> => {
}; };
}; };
const getGitHubMeta = async (params: RepoParams) => { export const getGitHubMeta = async (params: RepoParams) => {
const urlOwner = getGitHubUrlOwner(params); const urlOwner = getGitHubUrlOwner(params);
const urlRepo = getGitHubUrlRepo(params); const urlRepo = getGitHubUrlRepo(params);
const urlBranch = getGitHubUrlBranch(params); const urlBranch = getGitHubUrlBranch(params);
@ -138,33 +137,29 @@ const getGitHubMeta = async (params: RepoParams) => {
const isBaseRepo = isRepoBaseRepo(params); const isBaseRepo = isRepoBaseRepo(params);
const [ let isForkedFromBase: boolean | undefined;
isForkedFromBase, let isBehind: boolean | undefined;
behindBy, let behindBy: number | undefined;
] = await Promise.all([ let didError: boolean = false;
try {
const results = await Promise.all([
getIsRepoForkedFromBase(params), getIsRepoForkedFromBase(params),
isBaseRepo && params.commit isBaseRepo && params.commit
? getGitHubCommitsBehindFromCommit(params) ? getGitHubCommitsBehindFromCommit(params)
: getGitHubCommitsBehindFromRepo(params), : getGitHubCommitsBehindFromRepo(params),
]); ]);
const isBehind = behindBy === undefined isForkedFromBase = results[0];
behindBy = results[1];
isBehind = behindBy === undefined
? undefined ? undefined
: behindBy > 0; : behindBy > 0;
} catch (error) {
const label = isBehind === undefined didError = true;
? FALLBACK_TEXT console.error('Error retrieving GitHub meta', { params, error });
: isBehind }
? `${behindBy} Behind`
: 'Synced';
const description = isBehind === undefined
? FALLBACK_TEXT
: isBehind
? `This fork is ${behindBy} commit${behindBy === 1 ? '' : 's'} behind.`
: isBaseRepo
? 'This build is up to date.'
: 'This fork is up to date.';
return { return {
...params, ...params,
@ -176,29 +171,6 @@ const getGitHubMeta = async (params: RepoParams) => {
isBaseRepo, isBaseRepo,
behindBy, behindBy,
isBehind, isBehind,
label, didError,
description,
didError: false,
}; };
}; };
export const getGitHubMetaWithFallback = (params: RepoParams) =>
getGitHubMeta(params)
.catch(e => {
console.error('Error retrieving GitHub meta', { params, error: e });
return {
...params,
commitMessage: undefined,
urlOwner: undefined,
urlRepo: undefined,
urlBranch: undefined,
urlCommit: undefined,
isForkedFromBase: false,
isBaseRepo: undefined,
behindBy: undefined,
isBehind: undefined,
label: FALLBACK_TEXT,
description: 'Could not connect to GitHub.',
didError: true,
};
});