Files
repomix-mirror/tests/core/git/gitHubArchiveApi.test.ts
Kazuki Yamada bea8df18bb feat(git): Use HEAD instead of hardcoded main branch for GitHub archives
Replace hardcoded 'main' branch with 'HEAD' to automatically use the repository's default branch, eliminating issues with repositories that use different default branch names like 'master' or custom branches.

Changes:
- buildGitHubArchiveUrl now uses HEAD.zip instead of refs/heads/main.zip
- getArchiveFilename defaults to HEAD instead of main
- Updated corresponding tests to reflect the new behavior
2025-08-26 01:01:01 +09:00

184 lines
7.0 KiB
TypeScript

import { describe, expect, test } from 'vitest';
import {
buildGitHubArchiveUrl,
buildGitHubMasterArchiveUrl,
buildGitHubTagArchiveUrl,
checkGitHubResponse,
getArchiveFilename,
} from '../../../src/core/git/gitHubArchiveApi.js';
import { parseGitHubRepoInfo } from '../../../src/core/git/gitRemoteParse.js';
import { RepomixError } from '../../../src/shared/errorHandle.js';
describe('GitHub Archive API', () => {
describe('buildGitHubArchiveUrl', () => {
test('should build URL for default branch (HEAD)', () => {
const repoInfo = { owner: 'user', repo: 'repo' };
const url = buildGitHubArchiveUrl(repoInfo);
expect(url).toBe('https://github.com/user/repo/archive/HEAD.zip');
});
test('should build URL for specific branch', () => {
const repoInfo = { owner: 'user', repo: 'repo', ref: 'develop' };
const url = buildGitHubArchiveUrl(repoInfo);
expect(url).toBe('https://github.com/user/repo/archive/refs/heads/develop.zip');
});
test('should build URL for commit SHA', () => {
const repoInfo = { owner: 'user', repo: 'repo', ref: 'abc123def456' };
const url = buildGitHubArchiveUrl(repoInfo);
expect(url).toBe('https://github.com/user/repo/archive/abc123def456.zip');
});
test('should build URL for full commit SHA', () => {
const repoInfo = { owner: 'user', repo: 'repo', ref: 'abc123def456789012345678901234567890abcd' };
const url = buildGitHubArchiveUrl(repoInfo);
expect(url).toBe('https://github.com/user/repo/archive/abc123def456789012345678901234567890abcd.zip');
});
});
describe('buildGitHubMasterArchiveUrl', () => {
test('should build URL for master branch fallback', () => {
const repoInfo = { owner: 'user', repo: 'repo' };
const url = buildGitHubMasterArchiveUrl(repoInfo);
expect(url).toBe('https://github.com/user/repo/archive/refs/heads/master.zip');
});
test('should return null when ref is specified', () => {
const repoInfo = { owner: 'user', repo: 'repo', ref: 'develop' };
const url = buildGitHubMasterArchiveUrl(repoInfo);
expect(url).toBeNull();
});
});
describe('buildGitHubTagArchiveUrl', () => {
test('should build URL for tag', () => {
const repoInfo = { owner: 'user', repo: 'repo', ref: 'v1.0.0' };
const url = buildGitHubTagArchiveUrl(repoInfo);
expect(url).toBe('https://github.com/user/repo/archive/refs/tags/v1.0.0.zip');
});
test('should return null for commit SHA', () => {
const repoInfo = { owner: 'user', repo: 'repo', ref: 'abc123def456' };
const url = buildGitHubTagArchiveUrl(repoInfo);
expect(url).toBeNull();
});
test('should return null for no ref', () => {
const repoInfo = { owner: 'user', repo: 'repo' };
const url = buildGitHubTagArchiveUrl(repoInfo);
expect(url).toBeNull();
});
});
describe('getArchiveFilename', () => {
test('should generate filename for default branch (HEAD)', () => {
const repoInfo = { owner: 'user', repo: 'myrepo' };
const filename = getArchiveFilename(repoInfo);
expect(filename).toBe('myrepo-HEAD.zip');
});
test('should generate filename for specific branch', () => {
const repoInfo = { owner: 'user', repo: 'myrepo', ref: 'develop' };
const filename = getArchiveFilename(repoInfo);
expect(filename).toBe('myrepo-develop.zip');
});
test('should generate filename for tag with slash', () => {
const repoInfo = { owner: 'user', repo: 'myrepo', ref: 'release/v1.0' };
const filename = getArchiveFilename(repoInfo);
expect(filename).toBe('myrepo-v1.0.zip');
});
test('should generate filename for commit SHA', () => {
const repoInfo = { owner: 'user', repo: 'myrepo', ref: 'abc123' };
const filename = getArchiveFilename(repoInfo);
expect(filename).toBe('myrepo-abc123.zip');
});
});
describe('checkGitHubResponse', () => {
test('should not throw for successful response', () => {
const mockResponse = new Response('', { status: 200 });
expect(() => checkGitHubResponse(mockResponse)).not.toThrow();
});
test('should throw RepomixError for 404', () => {
const mockResponse = new Response('', { status: 404 });
expect(() => checkGitHubResponse(mockResponse)).toThrow(RepomixError);
expect(() => checkGitHubResponse(mockResponse)).toThrow('Repository not found or is private');
});
test('should throw RepomixError for 403 with rate limit', () => {
const mockResponse = new Response('', {
status: 403,
headers: { 'X-RateLimit-Remaining': '0', 'X-RateLimit-Reset': '1234567890' },
});
expect(() => checkGitHubResponse(mockResponse)).toThrow(RepomixError);
expect(() => checkGitHubResponse(mockResponse)).toThrow('GitHub API rate limit exceeded');
});
test('should throw RepomixError for 403 without rate limit', () => {
const mockResponse = new Response('', { status: 403 });
expect(() => checkGitHubResponse(mockResponse)).toThrow(RepomixError);
expect(() => checkGitHubResponse(mockResponse)).toThrow('Access denied');
});
test('should throw RepomixError for server errors', () => {
const mockResponse = new Response('', { status: 500 });
expect(() => checkGitHubResponse(mockResponse)).toThrow(RepomixError);
expect(() => checkGitHubResponse(mockResponse)).toThrow('GitHub server error');
});
test('should throw RepomixError for other errors', () => {
const mockResponse = new Response('', { status: 400 });
expect(() => checkGitHubResponse(mockResponse)).toThrow(RepomixError);
expect(() => checkGitHubResponse(mockResponse)).toThrow('GitHub API error');
});
});
describe('parseGitHubRepoInfo integration', () => {
test('should parse shorthand format', () => {
const result = parseGitHubRepoInfo('yamadashy/repomix');
expect(result).toEqual({
owner: 'yamadashy',
repo: 'repomix',
});
});
test('should parse HTTPS URL', () => {
const result = parseGitHubRepoInfo('https://github.com/yamadashy/repomix.git');
expect(result).toEqual({
owner: 'yamadashy',
repo: 'repomix',
});
});
test('should parse SSH URL', () => {
const result = parseGitHubRepoInfo('git@github.com:yamadashy/repomix.git');
expect(result).toEqual({
owner: 'yamadashy',
repo: 'repomix',
});
});
test('should parse URL with branch', () => {
const result = parseGitHubRepoInfo('https://github.com/yamadashy/repomix/tree/develop');
expect(result).toEqual({
owner: 'yamadashy',
repo: 'repomix',
ref: 'develop',
});
});
test('should return null for non-GitHub URLs', () => {
const result = parseGitHubRepoInfo('https://gitlab.com/user/repo.git');
expect(result).toBeNull();
});
test('should return null for invalid format', () => {
const result = parseGitHubRepoInfo('invalid-format');
expect(result).toBeNull();
});
});
});