Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/brown-chicken-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'dotenv-diff': patch
'@repo/eslint-config': patch
'@repo/tsconfig': patch
---

Added support for lint-staged
10 changes: 10 additions & 0 deletions docs/git_hooks_ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ Running `dotenv-diff` before each commit helps catch missing, unused, and misuse

A common setup is Husky + lint-staged, where `dotenv-diff` runs automatically on commit.

### Example lint-staged config

```json
{
"*.{js,ts,tsx,svelte}": [
"dotenv-diff --example .env.example"
]
}
```

## Running dotenv-diff in GitHub Actions

Use `dotenv-diff` in CI to validate environment variable consistency on pull requests.
Expand Down
169 changes: 88 additions & 81 deletions packages/cli/src/cli/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,85 +5,92 @@ import { Command } from 'commander';
* @returns The configured commander program instance
*/
export function createProgram() {
return new Command()
.name('dotenv-diff')
.description('Compare .env and .env.example files')
.option('--check-values', 'Compare actual values if example has values')
.option('--ci', 'Run non-interactively and never create files')
.option('-y, --yes', 'Run non-interactively and answer Yes to prompts')
.option('--env <file>', 'Path to a specific .env file')
.option('--example <file>', 'Path to a specific .env.example file')
.option(
'--allow-duplicates',
'Do not warn about duplicate keys in .env* files',
)
.option('--ignore <keys>', 'Comma-separated list of keys to ignore')
.option('--ignore-regex <pattern>', 'Regex pattern to ignore matching keys')
.option(
'--fix',
'Automatically fix common issues: remove duplicates, add missing keys',
)
.option('--json', 'Output results in JSON format')
.option('--color', 'Enable colored output')
.option('--no-color', 'Disable colored output')
.option(
'--only <list>',
'Comma-separated categories to only run (missing,extra,empty,duplicate,gitignore)',
)
.option('--scan-usage', 'Scan codebase for environment variable usage')
.option('--compare', 'Compare .env and .env.example files')
.option(
'--include-files <patterns>',
'Comma-separated file patterns to ADD to default scan patterns (extends default)',
)
.option(
'--files <patterns>',
'Comma-separated file patterns to scan (completely replaces default patterns)',
)
.option(
'--exclude-files <patterns>',
'Comma-separated file patterns to exclude from scan',
)
.option(
'--show-unused',
'List variables that are defined in .env but not used in code',
)
.option(
'--no-show-unused',
'Do not list variables that are defined in .env but not used in code',
)
.option('--show-stats', 'Show statistics')
.option('--no-show-stats', 'Do not show statistics')
.option('--strict', 'Enable fail on warnings')
.option(
'--secrets',
'Enable secret detection during scan (enabled by default)',
)
.option(
'--no-secrets',
'Disable secret detection during scan (enabled by default)',
)
.option(
'--ignore-urls <list>',
'Comma-separated URLs to ignore in secret scan',
)
.option(
'--uppercase-keys',
'Enable uppercase key validation (enabled by default)',
)
.option('--no-uppercase-keys', 'Disable uppercase key validation')
.option(
'--expire-warnings',
'Enable expiration date warnings for environment variables (enabled by default)',
)
.option('--no-expire-warnings', 'Disable expiration date warnings')
.option(
'--inconsistent-naming-warnings',
'Enable inconsistent naming pattern warnings (enabled by default)',
)
.option(
'--no-inconsistent-naming-warnings',
'Disable inconsistent naming pattern warnings',
)
.option('--init', 'Create a sample dotenv-diff.config.json file');
return (
new Command()
.name('dotenv-diff')
.description('Compare .env and .env.example files')
// Ignore extra positional args
.allowExcessArguments(true)
.option('--check-values', 'Compare actual values if example has values')
.option('--ci', 'Run non-interactively and never create files')
.option('-y, --yes', 'Run non-interactively and answer Yes to prompts')
.option('--env <file>', 'Path to a specific .env file')
.option('--example <file>', 'Path to a specific .env.example file')
.option(
'--allow-duplicates',
'Do not warn about duplicate keys in .env* files',
)
.option('--ignore <keys>', 'Comma-separated list of keys to ignore')
.option(
'--ignore-regex <pattern>',
'Regex pattern to ignore matching keys',
)
.option(
'--fix',
'Automatically fix common issues: remove duplicates, add missing keys',
)
.option('--json', 'Output results in JSON format')
.option('--color', 'Enable colored output')
.option('--no-color', 'Disable colored output')
.option(
'--only <list>',
'Comma-separated categories to only run (missing,extra,empty,duplicate,gitignore)',
)
.option('--scan-usage', 'Scan codebase for environment variable usage')
.option('--compare', 'Compare .env and .env.example files')
.option(
'--include-files <patterns>',
'Comma-separated file patterns to ADD to default scan patterns (extends default)',
)
.option(
'--files <patterns>',
'Comma-separated file patterns to scan (completely replaces default patterns)',
)
.option(
'--exclude-files <patterns>',
'Comma-separated file patterns to exclude from scan',
)
.option(
'--show-unused',
'List variables that are defined in .env but not used in code',
)
.option(
'--no-show-unused',
'Do not list variables that are defined in .env but not used in code',
)
.option('--show-stats', 'Show statistics')
.option('--no-show-stats', 'Do not show statistics')
.option('--strict', 'Enable fail on warnings')
.option(
'--secrets',
'Enable secret detection during scan (enabled by default)',
)
.option(
'--no-secrets',
'Disable secret detection during scan (enabled by default)',
)
.option(
'--ignore-urls <list>',
'Comma-separated URLs to ignore in secret scan',
)
.option(
'--uppercase-keys',
'Enable uppercase key validation (enabled by default)',
)
.option('--no-uppercase-keys', 'Disable uppercase key validation')
.option(
'--expire-warnings',
'Enable expiration date warnings for environment variables (enabled by default)',
)
.option('--no-expire-warnings', 'Disable expiration date warnings')
.option(
'--inconsistent-naming-warnings',
'Enable inconsistent naming pattern warnings (enabled by default)',
)
.option(
'--no-inconsistent-naming-warnings',
'Disable inconsistent naming pattern warnings',
)
.option('--init', 'Create a sample dotenv-diff.config.json file')
);
}
20 changes: 20 additions & 0 deletions packages/cli/test/unit/cli/program.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,24 @@ describe('createProgram', () => {
expect(opts.color).toBe(false);
expect(opts.strict).toBe(true);
});

it('ignores extra positional arguments', () => {
const program = createProgram();

expect(() => {
program.parse([
'node',
'dotenv-diff',
'--compare',
'--example',
'.env.example',
'file1.ts',
'file2.ts',
]);
}).not.toThrow();

const opts = program.opts();
expect(opts.compare).toBe(true);
expect(opts.example).toBe('.env.example');
});
});
Loading