719032b19f
Update Schema / Update configuration json schema (push) Has been cancelled
Memory Benchmark / Memory Test (Full Analysis) (push) Has been cancelled
CI Quality / Lint GitHub Actions (actionlint) (push) Has been cancelled
CI Quality / Lint GitHub Actions (zizmor) (push) Has been cancelled
CI Quality / Check typos (push) Has been cancelled
CI / Test coverage (push) Has been cancelled
CI / Test (22.x, windows-latest) (push) Has been cancelled
CI / Test (24.x, macos-latest) (push) Has been cancelled
CI / Test (24.x, ubuntu-latest) (push) Has been cancelled
CI / Test (24.x, windows-latest) (push) Has been cancelled
CI / Test (26.x, macos-latest) (push) Has been cancelled
CI / Test (26.x, ubuntu-latest) (push) Has been cancelled
CI / Test (26.x, windows-latest) (push) Has been cancelled
CI / Test with Bun (latest, macos-latest) (push) Has been cancelled
CI / Test with Bun (latest, ubuntu-latest) (push) Has been cancelled
CI / Test with Bun (latest, windows-latest) (push) Has been cancelled
CI / Build and run (22.x, macos-latest) (push) Has been cancelled
CI / Build and run (22.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (22.x, windows-latest) (push) Has been cancelled
autofix.ci / autofix (push) Has been cancelled
CI Browser Extension / Lint Browser Extension (push) Has been cancelled
CI Browser Extension / Test Browser Extension (push) Has been cancelled
Memory Benchmark / Memory Test (push) Has been cancelled
CI Website / Lint Website Client (push) Has been cancelled
CI Website / Lint Website Server (push) Has been cancelled
CI Website / Test Website Server (push) Has been cancelled
CI Website / Bundle Website Server (push) Has been cancelled
CI / Lint Biome (push) Has been cancelled
CI / Lint oxlint (push) Has been cancelled
CI / Lint TypeScript (push) Has been cancelled
CI / Lint Secretlint (push) Has been cancelled
CI / Test (22.x, macos-latest) (push) Has been cancelled
CI / Test (22.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (24.x, macos-latest) (push) Has been cancelled
CI / Build and run (24.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (24.x, windows-latest) (push) Has been cancelled
CI / Build and run (26.x, macos-latest) (push) Has been cancelled
CI / Build and run (26.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (26.x, windows-latest) (push) Has been cancelled
CI / Build and run with Bun (latest, macos-latest) (push) Has been cancelled
CI / Build and run with Bun (latest, ubuntu-latest) (push) Has been cancelled
CI / Build and run with Bun (latest, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Docker / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Docker / build (linux/arm/v7, ubuntu-24.04-arm) (push) Has been cancelled
Docker / build (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker / merge (push) Has been cancelled
Pack repository with Repomix / pack-repo (push) Has been cancelled
Performance Benchmark History / Benchmark (macos-latest) (push) Has been cancelled
Performance Benchmark History / Benchmark (ubuntu-latest) (push) Has been cancelled
Performance Benchmark History / Benchmark (windows-latest) (push) Has been cancelled
Performance Benchmark History / Store Results (push) Has been cancelled
Test Repomix Action / Test Node.js 22 (push) Has been cancelled
Test Repomix Action / Test Node.js 24 (push) Has been cancelled
Test Repomix Action / Test Node.js 26 (push) Has been cancelled
228 lines
8.8 KiB
TypeScript
228 lines
8.8 KiB
TypeScript
import fs from 'node:fs/promises';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import process from 'node:process';
|
|
import { afterEach, beforeEach, describe, expect, test } from 'vitest';
|
|
|
|
// Mock globby worker for integration tests to avoid worker file loading issues
|
|
|
|
import { loadFileConfig, mergeConfigs } from '../../src/config/configLoad.js';
|
|
import type { RepomixConfigFile, RepomixConfigMerged, RepomixOutputStyle } from '../../src/config/configSchema.js';
|
|
import { collectFiles } from '../../src/core/file/fileCollect.js';
|
|
import { resolveFileLevel } from '../../src/core/file/fileLevelResolve.js';
|
|
import { readRawFile } from '../../src/core/file/fileRead.js';
|
|
import { searchFiles } from '../../src/core/file/fileSearch.js';
|
|
import type { ProcessedFile } from '../../src/core/file/fileTypes.js';
|
|
import fileProcessWorker from '../../src/core/file/workers/fileProcessWorker.js';
|
|
import type { GitDiffResult } from '../../src/core/git/gitDiffHandle.js';
|
|
import { produceOutput } from '../../src/core/packager/produceOutput.js';
|
|
import { pack } from '../../src/core/packager.js';
|
|
import { filterOutUntrustedFiles } from '../../src/core/security/filterOutUntrustedFiles.js';
|
|
import { validateFileSafety } from '../../src/core/security/validateFileSafety.js';
|
|
|
|
import { isWindows } from '../testing/testUtils.js';
|
|
|
|
const fixturesDir = path.join(__dirname, 'fixtures', 'packager');
|
|
const inputsDir = path.join(fixturesDir, 'inputs');
|
|
const outputsDir = path.join(fixturesDir, 'outputs');
|
|
|
|
describe.runIf(!isWindows)('packager integration', () => {
|
|
const testCases = [
|
|
{
|
|
desc: 'simple plain style',
|
|
input: 'simple-project',
|
|
output: 'simple-project-output.txt',
|
|
config: {
|
|
output: { style: 'plain', filePath: 'simple-project-output.txt' },
|
|
},
|
|
},
|
|
{
|
|
desc: 'simple xml style',
|
|
input: 'simple-project',
|
|
output: 'simple-project-output.xml',
|
|
config: {
|
|
output: { style: 'xml', filePath: 'simple-project-output.xml' },
|
|
},
|
|
},
|
|
{
|
|
desc: 'simple markdown style',
|
|
input: 'simple-project',
|
|
output: 'simple-project-output.md',
|
|
config: {
|
|
output: { style: 'markdown', filePath: 'simple-project-output.md' },
|
|
},
|
|
},
|
|
{
|
|
desc: 'simple json style',
|
|
input: 'simple-project',
|
|
output: 'simple-project-output.json',
|
|
config: {
|
|
output: { style: 'json', filePath: 'simple-project-output.json' },
|
|
},
|
|
},
|
|
];
|
|
|
|
let tempDir: string;
|
|
|
|
beforeEach(async () => {
|
|
// Create a temporary directory for each test
|
|
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'repomix-test-'));
|
|
});
|
|
|
|
afterEach(async () => {
|
|
// Clean up the temporary directory after each test
|
|
await fs.rm(tempDir, { recursive: true, force: true });
|
|
});
|
|
|
|
for (const { desc, input, output, config } of testCases) {
|
|
test(`should correctly pack ${desc}`, async () => {
|
|
const inputDir = path.join(inputsDir, input);
|
|
const expectedOutputPath = path.join(outputsDir, output);
|
|
const actualOutputPath = path.join(tempDir, output);
|
|
|
|
const fileConfig: RepomixConfigFile = await loadFileConfig(inputDir, null);
|
|
const mergedConfig: RepomixConfigMerged = mergeConfigs(process.cwd(), fileConfig, {
|
|
output: {
|
|
filePath: actualOutputPath,
|
|
style: (config.output?.style || 'plain') as RepomixOutputStyle,
|
|
git: { sortByChanges: false },
|
|
},
|
|
});
|
|
|
|
// Run the pack function
|
|
await pack([inputDir], mergedConfig, () => {}, {
|
|
searchFiles,
|
|
sortPaths: (filePaths) => filePaths,
|
|
collectFiles: (filePaths, rootDir, config, progressCallback) => {
|
|
return collectFiles(filePaths, rootDir, config, progressCallback, {
|
|
readRawFile,
|
|
});
|
|
},
|
|
processFiles: async (rawFiles, config, _progressCallback) => {
|
|
const processedFiles: ProcessedFile[] = [];
|
|
for (const rawFile of rawFiles) {
|
|
const level = resolveFileLevel(rawFile.path, config.output);
|
|
processedFiles.push(await fileProcessWorker({ rawFile, config, level }));
|
|
}
|
|
return processedFiles;
|
|
},
|
|
validateFileSafety: (rawFiles, progressCallback, config) => {
|
|
const gitDiffMock: GitDiffResult = {
|
|
workTreeDiffContent: '',
|
|
stagedDiffContent: '',
|
|
};
|
|
return validateFileSafety(rawFiles, progressCallback, config, gitDiffMock, undefined, {
|
|
runSecurityCheck: async () => [],
|
|
filterOutUntrustedFiles,
|
|
});
|
|
},
|
|
produceOutput,
|
|
createMetricsTaskRunner: () => ({
|
|
taskRunner: {
|
|
run: async () => 0,
|
|
cleanup: async () => {},
|
|
},
|
|
warmupPromise: Promise.resolve(),
|
|
}),
|
|
calculateMetrics: async (
|
|
processedFiles,
|
|
_output,
|
|
_progressCallback,
|
|
_config,
|
|
_gitDiffResult,
|
|
_gitLogResult,
|
|
) => {
|
|
return {
|
|
totalFiles: processedFiles.length,
|
|
totalCharacters: processedFiles.reduce((acc, file) => acc + file.content.length, 0),
|
|
totalTokens: processedFiles.reduce((acc, file) => acc + file.content.split(/\s+/).length, 0),
|
|
gitDiffTokenCount: 0,
|
|
gitLogTokenCount: 0,
|
|
fileCharCounts: processedFiles.reduce(
|
|
(acc, file) => {
|
|
acc[file.path] = file.content.length;
|
|
return acc;
|
|
},
|
|
{} as Record<string, number>,
|
|
),
|
|
fileTokenCounts: processedFiles.reduce(
|
|
(acc, file) => {
|
|
acc[file.path] = file.content.split(/\s+/).length;
|
|
return acc;
|
|
},
|
|
{} as Record<string, number>,
|
|
),
|
|
suspiciousFilesResults: [],
|
|
suspiciousGitDiffResults: [],
|
|
};
|
|
},
|
|
});
|
|
|
|
// Read the actual and expected outputs
|
|
const actualOutput = await fs.readFile(actualOutputPath, 'utf-8');
|
|
|
|
// Compare the outputs - styles (e.g., XML, plain, markdown) may differ
|
|
expect(actualOutput).toContain('This file is a merged representation of the entire codebase');
|
|
|
|
// Common assertions for all styles
|
|
expect(actualOutput).toContain('resources/');
|
|
expect(actualOutput).toContain('src/');
|
|
expect(actualOutput).toContain('This repository is simple-project');
|
|
|
|
switch (config.output?.style) {
|
|
case 'xml':
|
|
expect(actualOutput).toContain('<file_summary>');
|
|
expect(actualOutput).toContain('<user_provided_header>');
|
|
expect(actualOutput).toContain('</user_provided_header>');
|
|
expect(actualOutput).toContain('<directory_structure>');
|
|
expect(actualOutput).toContain('<file path="src/index.js">');
|
|
expect(actualOutput).toContain('function main() {');
|
|
expect(actualOutput).toContain('<file path="src/utils.js">');
|
|
expect(actualOutput).toContain('function greet(name) {');
|
|
break;
|
|
|
|
case 'markdown':
|
|
expect(actualOutput).toContain('# File Summary');
|
|
expect(actualOutput).toContain('# User Provided Header');
|
|
expect(actualOutput).toContain('# Directory Structure');
|
|
expect(actualOutput).toContain('## File: src/index.js');
|
|
expect(actualOutput).toContain('````javascript\nconst { greet }');
|
|
expect(actualOutput).toContain('## File: src/utils.js');
|
|
expect(actualOutput).toContain('````javascript\nfunction greet(name) {');
|
|
break;
|
|
|
|
case 'plain':
|
|
expect(actualOutput).toContain('File Summary');
|
|
expect(actualOutput).toContain('User Provided Header');
|
|
expect(actualOutput).toContain('Directory Structure');
|
|
expect(actualOutput).toContain('File: src/index.js');
|
|
expect(actualOutput).toContain('function main() {');
|
|
expect(actualOutput).toContain('File: src/utils.js');
|
|
expect(actualOutput).toContain('function greet(name) {');
|
|
break;
|
|
|
|
case 'json': {
|
|
// Validate it's valid JSON
|
|
const jsonOutput = JSON.parse(actualOutput);
|
|
expect(jsonOutput.fileSummary).toBeDefined();
|
|
expect(jsonOutput.userProvidedHeader).toBeDefined();
|
|
expect(jsonOutput.directoryStructure).toBeDefined();
|
|
expect(jsonOutput.files).toBeDefined();
|
|
expect(jsonOutput.files['src/index.js']).toContain('function main() {');
|
|
expect(jsonOutput.files['src/utils.js']).toContain('function greet(name) {');
|
|
break;
|
|
}
|
|
|
|
default:
|
|
throw new Error(`Unsupported style: ${config.output?.style}`);
|
|
}
|
|
|
|
// Optionally, update the expected output if explicitly requested
|
|
if (process.env.UPDATE_EXPECTED_OUTPUT) {
|
|
await fs.writeFile(expectedOutputPath, actualOutput);
|
|
console.log(`Updated expected output for ${desc}`);
|
|
}
|
|
});
|
|
}
|
|
});
|