problem: can't get commit count and latest hash from github repo

solution: implement `getCommit()` in lib/helpers.ts

resolve https://github.com/nostrocket/hypergolic/issues/98
This commit is contained in:
Bob
2024-08-19 11:21:41 +08:00
parent a42372f99b
commit 3caa45187f
2 changed files with 95 additions and 50 deletions

View File

@@ -4,7 +4,6 @@
import { Input } from '$lib/components/ui/input/index.js';
import { Label } from '$lib/components/ui/label/index.js';
import * as Alert from '@/components/ui/alert';
import { Checkbox } from '@/components/ui/checkbox';
import Textarea from '@/components/ui/textarea/textarea.svelte';
import { ndk } from '@/ndk';
import { currentUser } from '@/stores/session';
@@ -14,7 +13,7 @@
import Todo from './Todo.svelte';
import { isValidUrl, Rocket } from '@/event_helpers/rockets';
import CalculateSats from './CalculateSats.svelte';
import { isGitHubUrl, parseProblem } from '@/helpers';
import { isGitHubIssuesOrPullUrl, parseProblem } from '@/helpers';
import Login from './Login.svelte';
export let rocket: Rocket;
@@ -50,7 +49,7 @@
}
}
$: if (isGitHubUrl(problem)) {
$: if (isGitHubIssuesOrPullUrl(problem)) {
parseProblem(problem).then((title) => {
if (title) {
problem = `${title}\n\n${problem}`;

View File

@@ -102,59 +102,105 @@ export async function getCuckPrice(): Promise<number> {
});
}
export async function parseProblem(problem: string) {
if (!isGitHubUrl(problem)) {
return;
}
const apiURL = convertToGitHubApiUrl(problem);
if (!apiURL) {
return;
}
const response = await fetch(apiURL);
if (!response.ok) {
return;
}
const { title } = await response.json();
return title;
interface CommitInfo {
count: number;
hash: string;
}
export function isGitHubUrl(str: string): boolean {
let url;
interface GitHubUrlParts {
owner: string;
repo: string;
type?: 'issues' | 'pull';
number?: string;
}
class GitHubApiError extends Error {
constructor(
message: string,
public status?: number
) {
super(message);
this.name = 'GitHubApiError';
}
}
function parseGitHubUrl(url: URL): GitHubUrlParts {
const parts = url.pathname.split('/').filter(Boolean);
if (parts.length < 2) {
throw new Error('Invalid GitHub URL');
}
return {
owner: parts[0],
repo: parts[1],
type: parts[2] as 'issues' | 'pull' | undefined,
number: parts[3]
};
}
async function fetchGitHubApi(apiUrl: URL): Promise<any> {
const response = await fetch(apiUrl);
if (!response.ok) {
throw new GitHubApiError(`HTTP error! status: ${response.status}`, response.status);
}
return response.json();
}
export async function getCommit(url: URL): Promise<CommitInfo> {
try {
url = new URL(str);
const { owner, repo } = parseGitHubUrl(url);
const apiURL = new URL(`https://api.github.com/repos/${owner}/${repo}/commits`);
const json = await fetchGitHubApi(apiURL);
if (!json[0]?.sha) {
throw new GitHubApiError('Failed to fetch commit info: API returned unexpected data');
}
return {
count: json.length,
hash: json[0].sha
};
} catch (error) {
if (error instanceof GitHubApiError) {
throw error;
}
throw new Error(
`Failed to fetch commit info: ${error instanceof Error ? error.message : String(error)}`
);
}
}
export async function parseProblem(problem: string): Promise<string | undefined> {
if (!isGitHubIssuesOrPullUrl(problem)) {
return undefined;
}
try {
const { owner, repo, number } = parseGitHubUrl(new URL(problem));
const apiURL = new URL(`https://api.github.com/repos/${owner}/${repo}/issues/${number}`);
const { title } = await fetchGitHubApi(apiURL);
return title;
} catch (error) {
console.error('Failed to parse problem:', error);
return undefined;
}
}
export function isGitHubIssuesOrPullUrl(str: string): boolean {
try {
const url = new URL(str);
const { owner, repo, type, number } = parseGitHubUrl(url);
return (
url.hostname === 'github.com' &&
!!owner &&
!!repo &&
!!type &&
!!number &&
['issues', 'pull'].includes(type) &&
/^[1-9]\d*$/.test(number)
);
} catch {
return false;
}
const pathParts = url.pathname.split('/').filter(Boolean);
if (url.hostname !== 'github.com') {
return false;
}
if (pathParts.length !== 4) {
return false;
}
if (!['issues', 'pull'].includes(pathParts[2])) {
return false;
}
if (!/^[1-9]\d*$/.test(pathParts[3])) {
return false;
}
return true;
}
function convertToGitHubApiUrl(issueUrl: string): URL | null {
const url = new URL(issueUrl);
const [owner, repo, , issueNumber] = url.pathname.split('/').filter(Boolean);
try {
// Whether it's `issues` or `pull`, the API uses `issues`
return new URL(`https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}`);
} catch (error) {
console.error('URL conversion error:', error);
return null;
}
}
export async function getAuthorizedZapper(rocket: NDKEvent): Promise<string> {