Skip to content

Commit

Permalink
Merge pull request #324 from massdo/feat/cli-flags
Browse files Browse the repository at this point in the history
Feat/cli flags
  • Loading branch information
yamadashy authored Jan 28, 2025
2 parents 27a3309 + 157440e commit 3eff6ea
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 4 deletions.
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,10 @@ This format provides a clean, readable structure that is both human-friendly and
- `-o, --output <file>`: Specify the output file name
- `--include <patterns>`: List of include patterns (comma-separated)
- `-i, --ignore <patterns>`: Additional ignore patterns (comma-separated)
- `--no-gitignore`: Disable .gitignore file usage
- `--no-default-patterns`: Disable default patterns
- `-c, --config <path>`: Path to a custom config file
- `--header-text <text>`: Custom text to include in the file header
- `--style <style>`: Specify the output style (`plain`, `xml`, `markdown`)
- `--parsable-style`: Enable parsable output based on the chosen style schema. Note that this can increase token count.
- `--no-file-summary`: Disable file summary section output
Expand All @@ -419,6 +422,8 @@ This format provides a clean, readable structure that is both human-friendly and
- `--no-security-check`: Disable security check
- `--token-count-encoding <encoding>`: Specify token count encoding (e.g., `o200k_base`, `cl100k_base`)
- `--verbose`: Enable verbose logging
- `--instruction-file-path <path>`: Path to a file containing detailed custom instructions
- `--include-empty-directories`: Include empty directories in the output

Examples:

Expand Down Expand Up @@ -579,9 +584,9 @@ Repomix offers multiple methods to set ignore patterns for excluding specific fi
process:

- **.gitignore**: By default, patterns listed in your project's `.gitignore` file are used. This behavior can be
controlled with the `ignore.useGitignore` setting.
controlled with the `ignore.useGitignore` setting or the `--no-gitignore` cli option.
- **Default patterns**: Repomix 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
.git, binary files). This feature can be controlled with the `ignore.useDefaultPatterns` setting or the `--no-default-patterns` cli option. Please
see [defaultIgnore.ts](src/config/defaultIgnore.ts) for more details.
- **.repomixignore**: You can create a `.repomixignore` file in your project root to define Repomix-specific ignore
patterns. This file follows the same format as `.gitignore`.
Expand All @@ -592,8 +597,8 @@ Priority Order (from highest to lowest):

1. Custom patterns `ignore.customPatterns`
2. `.repomixignore`
3. `.gitignore` (if `ignore.useGitignore` is true)
4. Default patterns (if `ignore.useDefaultPatterns` is true)
3. `.gitignore` (if `ignore.useGitignore` is true and `--no-gitignore` is not used)
4. Default patterns (if `ignore.useDefaultPatterns` is true and `--no-default-patterns` is not used)

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
Expand Down
15 changes: 15 additions & 0 deletions src/cli/actions/defaultAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ const buildCliConfig = (options: CliOptions): RepomixConfigCli => {
if (options.ignore) {
cliConfig.ignore = { customPatterns: options.ignore.split(',') };
}
if (options.gitignore !== undefined) {
cliConfig.ignore = { ...cliConfig.ignore, useGitignore: options.gitignore };
}
if (options.defaultPatterns !== undefined) {
cliConfig.ignore = { ...cliConfig.ignore, useDefaultPatterns: options.defaultPatterns };
}
if (options.topFilesLen !== undefined) {
cliConfig.output = { ...cliConfig.output, topFilesLength: options.topFilesLen };
}
Expand Down Expand Up @@ -130,9 +136,18 @@ const buildCliConfig = (options: CliOptions): RepomixConfigCli => {
if (options.removeEmptyLines !== undefined) {
cliConfig.output = { ...cliConfig.output, removeEmptyLines: options.removeEmptyLines };
}
if (options.headerText !== undefined) {
cliConfig.output = { ...cliConfig.output, headerText: options.headerText };
}
if (options.tokenCountEncoding) {
cliConfig.tokenCount = { encoding: options.tokenCountEncoding };
}
if (options.instructionFilePath) {
cliConfig.output = { ...cliConfig.output, instructionFilePath: options.instructionFilePath };
}
if (options.includeEmptyDirectories) {
cliConfig.output = { ...cliConfig.output, includeEmptyDirectories: options.includeEmptyDirectories };
}

try {
return repomixConfigCliSchema.parse(cliConfig);
Expand Down
10 changes: 10 additions & 0 deletions src/cli/cliRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export interface CliOptions extends OptionValues {
output?: string;
include?: string;
ignore?: string;
gitignore?: boolean;
defaultPatterns?: boolean;
config?: string;
copy?: boolean;
verbose?: boolean;
Expand All @@ -28,10 +30,13 @@ export interface CliOptions extends OptionValues {
remoteBranch?: string;
securityCheck?: boolean;
fileSummary?: boolean;
headerText?: string;
directoryStructure?: boolean;
removeComments?: boolean;
removeEmptyLines?: boolean;
tokenCountEncoding?: string;
instructionFilePath?: string;
includeEmptyDirectories?: boolean;
}

export const run = async () => {
Expand All @@ -43,12 +48,15 @@ export const run = async () => {
.option('-o, --output <file>', 'specify the output file name')
.option('--include <patterns>', 'list of include patterns (comma-separated)')
.option('-i, --ignore <patterns>', 'additional ignore patterns (comma-separated)')
.option('--no-gitignore', 'disable .gitignore file usage')
.option('--no-default-patterns', 'disable default patterns')
.option('-c, --config <path>', 'path to a custom config file')
.option('--copy', 'copy generated output to system clipboard')
.option('--top-files-len <number>', 'specify the number of top files to display', Number.parseInt)
.option('--output-show-line-numbers', 'add line numbers to each line in the output')
.option('--style <type>', 'specify the output style (plain, xml, markdown)')
.option('--parsable-style', 'by escaping and formatting, ensure the output is parsable as a document of its type')
.option('--header-text <text>', 'specify the header text')
.option('--no-file-summary', 'disable file summary section output')
.option('--no-directory-structure', 'disable directory structure section output')
.option('--remove-comments', 'remove comments')
Expand All @@ -63,6 +71,8 @@ export const run = async () => {
'specify the remote branch name, tag, or commit hash (defaults to repository default branch)',
)
.option('--no-security-check', 'disable security check')
.option('--instruction-file-path <path>', 'path to a file containing detailed custom instructions')
.option('--include-empty-directories', 'include empty directories in the output')
.action((directory = '.', options: CliOptions = {}) => executeAction(directory, process.cwd(), options));

await program.parseAsync(process.argv);
Expand Down
100 changes: 100 additions & 0 deletions tests/cli/actions/defaultAction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,4 +357,104 @@ describe('defaultAction', () => {
);
});
});

describe('gitignore flag', () => {
it('should handle explicit --no-gitignore flag', async () => {
const options: CliOptions = {
gitignore: false,
};

await runDefaultAction('.', process.cwd(), options);

expect(configLoader.mergeConfigs).toHaveBeenCalledWith(
process.cwd(),
expect.anything(),
expect.objectContaining({
ignore: {
useGitignore: false,
},
}),
);
});
});

describe('defaultPatterns flag', () => {
it('should handle explicit --no-default-patterns flag', async () => {
const options: CliOptions = {
defaultPatterns: false,
};

await runDefaultAction('.', process.cwd(), options);

expect(configLoader.mergeConfigs).toHaveBeenCalledWith(
process.cwd(),
expect.anything(),
expect.objectContaining({
ignore: {
useDefaultPatterns: false,
},
}),
);
});
});

describe('headerText flag', () => {
it('should handle --header-text flag', async () => {
const options: CliOptions = {
headerText: 'Another header text',
};

await runDefaultAction('.', process.cwd(), options);

expect(configLoader.mergeConfigs).toHaveBeenCalledWith(
process.cwd(),
expect.anything(),
expect.objectContaining({
output: {
headerText: 'Another header text',
},
}),
);
});
});

describe('instructionFilePath flag', () => {
it('should handle --instruction-file-path flag', async () => {
const options: CliOptions = {
instructionFilePath: 'path/to/instruction.txt',
};

await runDefaultAction('.', process.cwd(), options);

expect(configLoader.mergeConfigs).toHaveBeenCalledWith(
process.cwd(),
expect.anything(),
expect.objectContaining({
output: {
instructionFilePath: 'path/to/instruction.txt',
},
}),
);
});
});

describe('includeEmptyDirectories flag', () => {
it('should handle --include-empty-directories flag', async () => {
const options: CliOptions = {
includeEmptyDirectories: true,
};

await runDefaultAction('.', process.cwd(), options);

expect(configLoader.mergeConfigs).toHaveBeenCalledWith(
process.cwd(),
expect.anything(),
expect.objectContaining({
output: {
includeEmptyDirectories: true,
},
}),
);
});
});
});
60 changes: 60 additions & 0 deletions tests/cli/cliRun.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,5 +220,65 @@ describe('cliRun', () => {
}),
);
});

test('should handle explicit --no-gitignore flag', async () => {
await executeAction('.', process.cwd(), { gitignore: false });

expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
'.',
process.cwd(),
expect.objectContaining({
gitignore: false,
}),
);
});

test('should handle explicit --no-default-patterns flag', async () => {
await executeAction('.', process.cwd(), { defaultPatterns: false });

expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
'.',
process.cwd(),
expect.objectContaining({
defaultPatterns: false,
}),
);
});

test('should handle explicit --header-text flag', async () => {
await executeAction('.', process.cwd(), { headerText: 'I am a good header text' });

expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
'.',
process.cwd(),
expect.objectContaining({
headerText: 'I am a good header text',
}),
);
});

test('should handle --instruction-file-path flag', async () => {
await executeAction('.', process.cwd(), { instructionFilePath: 'path/to/instruction.txt' });

expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
'.',
process.cwd(),
expect.objectContaining({
instructionFilePath: 'path/to/instruction.txt',
}),
);
});

test('should handle --include-empty-directories flag', async () => {
await executeAction('.', process.cwd(), { includeEmptyDirectories: true });

expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(
'.',
process.cwd(),
expect.objectContaining({
includeEmptyDirectories: true,
}),
);
});
});
});

0 comments on commit 3eff6ea

Please sign in to comment.