Skip to content

Commit

Permalink
feat(ignore): Add .repopackignore support
Browse files Browse the repository at this point in the history
  • Loading branch information
yamadashy committed Jul 27, 2024
1 parent 3a15b21 commit ad64661
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 106 deletions.
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ Create a `repopack.config.json` file in your project root for custom configurati
|`output.removeComments`| Whether to remove comments from supported file types | `false` |
|`output.topFilesLength`| Number of top files to display in the summary. If set to 0, no summary will be displayed |`5`|
|`output.showLineNumbers`| Whether to add line numbers to each line in the output |`false`|
|`ignore.useGitignorePatterns`| Whether to use patterns from `.gitignore` files |`true`|
|`ignore.useDefaultPatterns`| Whether to use default ignore patterns |`true`|
|`ignore.customPatterns`| Additional patterns to ignore |`[]`|

Expand All @@ -161,23 +162,28 @@ Example configuration:
"showLineNumbers": false
},
"ignore": {
"useGitignorePatterns": true,
"useDefaultPatterns": true,
"customPatterns": ["additional-folder", "*.log"]
}
}
```

### Default Ignore Patterns
### Ignore Patterns
Repopack offers multiple methods to set ignore patterns for excluding specific files or directories during the packing process:

Repopack automatically ignores certain files and directories by default:
- **.gitignore**: By default, patterns listed in your project's `.gitignore` file are used. This behavior can be controlled with the `ignore.useGitignorePatterns` setting.
- **Default patterns**: Repopack includes a default list of commonly excluded files and directories (e.g., node_modules, .git, binary files). This feature can be controlled with the `ignore.useDefaultPatterns` setting. Please see [defaultIgnore.ts](src/utils/defaultIgnore.ts) for more details.
- **.repopackignore**: You can create a `.repopackignore` file in your project root to define Repopack-specific ignore patterns. This file follows the same format as `.gitignore`.
- **Custom patterns**: Additional ignore patterns can be specified using the `ignore.customPatterns` option in the configuration file. You can overwrite this setting with the `-i, --ignore` command line option.

- All patterns specified in your project's `.gitignore` file
- Git-related files and directories (e.g., `.git`, `.gitattributes`)
- Binary files (e.g., images, executables)
- Common build output and dependency directories (e.g., `node_modules`, `dist`)
- System and IDE-specific files (e.g., `.DS_Store`, `.vscode`)
Priority Order (from highest to lowest):
1. Custom patterns `ignore.customPatterns`
2. `.repopackignore`
3. `.gitignore` (if `ignore.useGitignorePatterns` is true)
4. Default patterns (if `ignore.useDefaultPatterns` is true)

This ensures that only relevant source code is included in the packed file. You can add additional ignore patterns using the `ignore.customPatterns` configuration option or the `-i` command line flag.
This approach allows for flexible file exclusion configuration based on your project's needs. It helps optimize the size of the generated pack file by ensuring the exclusion of security-sensitive files and large binary files, while preventing the leakage of confidential information.

### Comment Removal

Expand Down
1 change: 1 addition & 0 deletions repopack.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"showLineNumbers": false
},
"ignore": {
"useGitignorePatterns": true,
"useDefaultPatterns": true,
"customPatterns": []
}
Expand Down
1 change: 1 addition & 0 deletions src/config/defaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const defaultConfig: RepopackConfigDefault = {
showLineNumbers: false,
},
ignore: {
useGitignorePatterns: true,
useDefaultPatterns: true,
customPatterns: [],
},
Expand Down
23 changes: 5 additions & 18 deletions src/core/packager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@ import type { SecretLintCoreResult } from '@secretlint/types';
import { RepopackConfigMerged } from '../types/index.js';
import { processFile as defaultProcessFile } from '../utils/fileHandler.js';
import {
getGitignorePatterns as defaultGetGitignorePatterns,
getAllIgnorePatterns as defaultGetAllIgnorePatterns,
createIgnoreFilter as defaultCreateIgnoreFilter,
IgnoreFilter,
} from '../utils/gitignoreUtils.js';
} from '../utils/ignoreUtils.js';
import { generateOutput as defaultGenerateOutput } from './outputGenerator.js';
import { defaultIgnoreList } from '../utils/defaultIgnore.js';
import { checkFileWithSecretLint, createSecretLintConfig } from '../utils/secretLintUtils.js';
import { logger } from '../utils/logger.js';

export interface Dependencies {
getGitignorePatterns: typeof defaultGetGitignorePatterns;
getAllIgnorePatterns: typeof defaultGetAllIgnorePatterns;
createIgnoreFilter: typeof defaultCreateIgnoreFilter;
processFile: typeof defaultProcessFile;
generateOutput: typeof defaultGenerateOutput;
Expand All @@ -36,15 +35,14 @@ export async function pack(
rootDir: string,
config: RepopackConfigMerged,
deps: Dependencies = {
getGitignorePatterns: defaultGetGitignorePatterns,
getAllIgnorePatterns: defaultGetAllIgnorePatterns,
createIgnoreFilter: defaultCreateIgnoreFilter,
processFile: defaultProcessFile,
generateOutput: defaultGenerateOutput,
},
): Promise<PackResult> {
// Get ignore patterns
const gitignorePatterns = await deps.getGitignorePatterns(rootDir);
const ignorePatterns = getIgnorePatterns(gitignorePatterns, config);
const ignorePatterns = await deps.getAllIgnorePatterns(rootDir, config);
const ignoreFilter = deps.createIgnoreFilter(ignorePatterns);

// Get all file paths in the directory
Expand Down Expand Up @@ -73,17 +71,6 @@ export async function pack(
};
}

function getIgnorePatterns(gitignorePatterns: string[], config: RepopackConfigMerged): string[] {
let ignorePatterns = [...gitignorePatterns];
if (config.ignore.useDefaultPatterns) {
ignorePatterns = [...ignorePatterns, ...defaultIgnoreList];
}
if (config.ignore.customPatterns) {
ignorePatterns = [...ignorePatterns, ...config.ignore.customPatterns];
}
return ignorePatterns;
}

async function getFilePaths(dir: string, relativePath: string, ignoreFilter: IgnoreFilter): Promise<string[]> {
const entries = await fs.readdir(dir, { withFileTypes: true });
const filePaths: string[] = [];
Expand Down
4 changes: 4 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface RepopackConfigBase {
showLineNumbers?: boolean;
};
ignore?: {
useGitignorePatterns?: boolean;
useDefaultPatterns?: boolean;
customPatterns?: string[];
};
Expand All @@ -21,6 +22,7 @@ export type RepopackConfigDefault = RepopackConfigBase & {
showLineNumbers: boolean;
};
ignore: {
useGitignorePatterns: boolean;
useDefaultPatterns: boolean;
customPatterns?: string[];
};
Expand All @@ -35,6 +37,7 @@ export type RepopackConfigFile = RepopackConfigBase & {
showLineNumbers?: boolean;
};
ignore?: {
useGitignorePatterns?: boolean;
useDefaultPatterns?: boolean;
customPatterns?: string[];
};
Expand All @@ -49,6 +52,7 @@ export type RepopackConfigCli = RepopackConfigBase & {
showLineNumbers?: boolean;
};
ignore?: {
useGitignorePatterns?: boolean;
useDefaultPatterns?: boolean;
customPatterns?: string[];
};
Expand Down
29 changes: 0 additions & 29 deletions src/utils/gitignoreUtils.ts

This file was deleted.

53 changes: 53 additions & 0 deletions src/utils/ignoreUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import * as fs from 'fs/promises';
import path from 'path';
import ignore from 'ignore';
import { logger } from './logger.js';
import { RepopackConfigMerged } from '../types/index.js';
import { defaultIgnoreList } from './defaultIgnore.js';

export async function getIgnorePatterns(filename: string, rootDir: string, fsModule = fs): Promise<string[]> {
const ignorePath = path.join(rootDir, filename);
try {
const ignoreContent = await fsModule.readFile(ignorePath, 'utf-8');
return parseIgnoreContent(ignoreContent);
} catch (error) {
logger.debug(`No ${filename} file found or unable to read it.`);
return [];
}
}

export function parseIgnoreContent(content: string): string[] {
return content
.split('\n')
.map((line) => line.trim())
.filter((line) => line && !line.startsWith('#'));
}

export type IgnoreFilter = (path: string) => boolean;

export function createIgnoreFilter(patterns: string[]): IgnoreFilter {
const ig = ignore.default().add(patterns);
return ig.createFilter();
}

export async function getAllIgnorePatterns(rootDir: string, config: RepopackConfigMerged): Promise<string[]> {
let ignorePatterns: string[] = [];

if (config.ignore.useDefaultPatterns) {
ignorePatterns = [...ignorePatterns, ...defaultIgnoreList];
}

const gitignorePatterns = await getIgnorePatterns('.gitignore', rootDir);
if (config.ignore.useGitignorePatterns) {
ignorePatterns = [...ignorePatterns, ...gitignorePatterns];
}

const repopackIgnorePatterns = await getIgnorePatterns('.repopackignore', rootDir);
ignorePatterns = [...ignorePatterns, ...repopackIgnorePatterns];

if (config.ignore.customPatterns) {
ignorePatterns = [...ignorePatterns, ...config.ignore.customPatterns];
}

return ignorePatterns;
}
12 changes: 5 additions & 7 deletions tests/core/outputGenerator.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { expect, test, vi, describe, beforeEach } from 'vitest';
import { generateOutput, generateFileHeader } from '../../src/core/outputGenerator.js';
import { RepopackConfigMerged } from '../../src/types/index.js';
import * as fs from 'fs/promises';
import path from 'path';
import { createMockConfig } from '../testing/testUtils.js';

vi.mock('fs/promises');

Expand All @@ -12,10 +12,9 @@ describe('outputGenerator', () => {
});

test('generateOutput should write correct content to file', async () => {
const mockConfig: RepopackConfigMerged = {
const mockConfig = createMockConfig({
output: { filePath: 'output.txt', topFilesLength: 2, showLineNumbers: false },
ignore: { useDefaultPatterns: true },
};
});
const mockPackedFiles = [
{ path: 'file1.txt', content: 'content1' },
{ path: 'dir/file2.txt', content: 'content2' },
Expand All @@ -35,15 +34,14 @@ describe('outputGenerator', () => {
});

test('generateFileHeader should include user-provided header text', () => {
const mockConfig: RepopackConfigMerged = {
const mockConfig = createMockConfig({
output: {
filePath: 'output.txt',
headerText: 'Custom header text',
topFilesLength: 2,
showLineNumbers: false,
},
ignore: { useDefaultPatterns: true },
};
});

const header = generateFileHeader(mockConfig, []);

Expand Down
12 changes: 6 additions & 6 deletions tests/core/packager.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { expect, test, vi, describe, beforeEach } from 'vitest';
import { pack, Dependencies } from '../../src/core/packager.js';
import { RepopackConfigMerged } from '../../src/types/index.js';
import path from 'path';
import * as fs from 'fs/promises';
import { Dirent } from 'fs';
import { createMockConfig } from '../testing/testUtils.js';

vi.mock('fs/promises');

Expand All @@ -13,18 +13,15 @@ describe('packager', () => {
beforeEach(() => {
vi.resetAllMocks();
mockDeps = {
getGitignorePatterns: vi.fn().mockResolvedValue([]),
getAllIgnorePatterns: vi.fn().mockResolvedValue([]),
createIgnoreFilter: vi.fn().mockReturnValue(() => true),
processFile: vi.fn().mockResolvedValue('processed content'),
generateOutput: vi.fn().mockResolvedValue(undefined),
};
});

test('pack should process files and generate output', async () => {
const mockConfig: RepopackConfigMerged = {
output: { filePath: 'output.txt', topFilesLength: 2, showLineNumbers: false },
ignore: { useDefaultPatterns: true },
};
const mockConfig = createMockConfig();

vi.mocked(fs.readdir)
.mockResolvedValueOnce([
Expand All @@ -39,6 +36,9 @@ describe('packager', () => {
expect(vi.mocked(fs.readdir).mock.calls[0][0]).toBe('root');
expect(vi.mocked(fs.readdir).mock.calls[1][0]).toBe(path.join('root', 'dir1'));

expect(mockDeps.getAllIgnorePatterns).toHaveBeenCalledWith('root', mockConfig);
expect(mockDeps.createIgnoreFilter).toHaveBeenCalled();
expect(mockDeps.processFile).toHaveBeenCalledTimes(2);
expect(mockDeps.generateOutput).toHaveBeenCalledWith('root', mockConfig, [
{ path: 'file1.txt', content: 'processed content' },
{ path: path.join('dir1', 'file2.txt'), content: 'processed content' },
Expand Down
9 changes: 9 additions & 0 deletions tests/testing/testUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { defaultConfig } from '../../src/config/defaultConfig.js';
import { RepopackConfigMerged } from '../../src/types/index.js';

export const createMockConfig = (config: Partial<RepopackConfigMerged> = {}): RepopackConfigMerged => {
return {
output: config.output || defaultConfig.output,
ignore: config.ignore || defaultConfig.ignore,
};
};
7 changes: 2 additions & 5 deletions tests/utils/fileHandler.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, test, vi, describe, beforeEach } from 'vitest';
import { processFile, preprocessContent } from '../../src/utils/fileHandler.js';
import * as fs from 'fs/promises';
import { RepopackConfigMerged } from '../../src/types/index.js';
import { createMockConfig } from '../testing/testUtils.js';

vi.mock('fs/promises');

Expand All @@ -14,10 +14,7 @@ describe('fileHandler', () => {
const mockContent = ' Some file content \n';
vi.mocked(fs.readFile).mockResolvedValue(mockContent);

const mockConfig: RepopackConfigMerged = {
output: { filePath: 'output.txt', topFilesLength: 2, showLineNumbers: false },
ignore: { useDefaultPatterns: true },
};
const mockConfig = createMockConfig();
const result = await processFile('/path/to/file.txt', mockConfig);

expect(fs.readFile).toHaveBeenCalledWith('/path/to/file.txt');
Expand Down
Loading

0 comments on commit ad64661

Please sign in to comment.