batch-exec-cli 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # batch-exec
1
+ # batch-exec-cli
2
2
 
3
3
  高效批量命令执行工具,能够遍历目录内所有直接子目录并执行命令。
4
4
 
@@ -17,14 +17,14 @@
17
17
  ## 安装
18
18
 
19
19
  ```bash
20
- npm install -g batch-exec
20
+ npm install -g batch-exec-cli
21
21
  ```
22
22
 
23
23
  或者克隆项目后本地安装:
24
24
 
25
25
  ```bash
26
26
  git clone <repository-url>
27
- cd batch-exec
27
+ cd batch-exec-cli
28
28
  npm install
29
29
  npm link
30
30
  ```
@@ -128,7 +128,7 @@ temp-*
128
128
  你也可以作为库使用:
129
129
 
130
130
  ```javascript
131
- import { batchExecute } from 'batch-exec';
131
+ import { batchExecute } from 'batch-exec-cli';
132
132
 
133
133
  const results = await batchExecute('./my-projects', 'git', ['pull'], {
134
134
  verbose: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "batch-exec-cli",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Efficiently iterate through directories and execute commands with progress display",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -11,6 +11,9 @@
11
11
  "test": "echo 'Tests require Node.js >= 18.0.0 with --test support'",
12
12
  "lint": "eslint src/ test/"
13
13
  },
14
+ "files": [
15
+ "src"
16
+ ],
14
17
  "keywords": [
15
18
  "batch-exec",
16
19
  "batchexec",
package/.batchexecignore DELETED
@@ -1,9 +0,0 @@
1
- # Directories to ignore
2
- node_modules
3
- dist
4
- build
5
- .git
6
- .idea
7
- .vscode
8
- *.tmp
9
- temp-*
package/CHANGELOG.md DELETED
@@ -1,13 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
-
5
- ### [1.2.1](https://github.com/chandq/batch-exec/compare/v1.2.0...v1.2.1) (2026-03-01)
6
-
7
- ## 1.2.0 (2026-03-01)
8
-
9
-
10
- ### Features
11
-
12
- * add colors highlight 240bf16
13
- * add progress display by using --no-progress 320a372
package/test/cli.test.js DELETED
@@ -1,70 +0,0 @@
1
- import { describe, it, beforeEach, afterEach } from 'node:test';
2
- import assert from 'node:assert';
3
- import fs from 'fs/promises';
4
- import path from 'path';
5
- import os from 'os';
6
- import { $ } from 'zx';
7
-
8
- describe('CLI Integration', () => {
9
- let tempDir;
10
- let testProjectsDir;
11
-
12
- beforeEach(async () => {
13
- tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'batch-exec-cli-test-'));
14
- testProjectsDir = path.join(tempDir, 'test-projects');
15
-
16
- await fs.mkdir(testProjectsDir);
17
- await fs.mkdir(path.join(testProjectsDir, 'project1'));
18
- await fs.mkdir(path.join(testProjectsDir, 'project2'));
19
- await fs.mkdir(path.join(testProjectsDir, 'node_modules'));
20
-
21
- await fs.writeFile(path.join(tempDir, '.batchexecignore'), 'node_modules');
22
- });
23
-
24
- afterEach(async () => {
25
- await fs.rm(tempDir, { recursive: true, force: true });
26
- });
27
-
28
- it('should show help message with --help', async () => {
29
- const result = await $`node ${path.join(process.cwd(), 'src/cli.js')} --help`;
30
- assert(result.stdout.includes('Usage:'));
31
- assert(result.stdout.includes('batch-exec'));
32
- });
33
-
34
- it('should execute command in subdirectories', async () => {
35
- const result = await $`node ${path.join(process.cwd(), 'src/cli.js')} ${testProjectsDir} echo test`;
36
- assert(result.stdout.includes('Summary:'));
37
- assert(result.stdout.includes('Total directories: 2'));
38
- });
39
-
40
- it('should respect .batchexecignore file', async () => {
41
- const result = await $`node ${path.join(process.cwd(), 'src/cli.js')} ${testProjectsDir} pwd`;
42
- assert(result.stdout.includes('Total directories: 2'));
43
- assert(!result.stdout.includes('node_modules'));
44
- });
45
-
46
- it('should work with custom ignore file using --skip', async () => {
47
- const customIgnore = path.join(tempDir, 'custom-ignore');
48
- await fs.writeFile(customIgnore, 'project1\nnode_modules');
49
-
50
- const result = await $`node ${path.join(
51
- process.cwd(),
52
- 'src/cli.js'
53
- )} --skip ${customIgnore} ${testProjectsDir} pwd`;
54
- assert(result.stdout.includes('Total directories: 1'));
55
- assert(!result.stdout.includes('project1'));
56
- });
57
-
58
- it('should show verbose output with --verbose', async () => {
59
- const result = await $`node ${path.join(process.cwd(), 'src/cli.js')} --verbose ${testProjectsDir} echo hello`;
60
- assert(result.stdout.includes('Target directory:'));
61
- assert(result.stdout.includes('Command:'));
62
- });
63
-
64
- it('should fail with error message when missing arguments', async () => {
65
- await assert.rejects($`node ${path.join(process.cwd(), 'src/cli.js')}`, error => {
66
- assert(error.stderr.includes('Missing required arguments'));
67
- return true;
68
- });
69
- });
70
- });
@@ -1,68 +0,0 @@
1
- import { describe, it, beforeEach, afterEach } from 'node:test';
2
- import assert from 'node:assert';
3
- import fs from 'fs/promises';
4
- import path from 'path';
5
- import os from 'os';
6
- import { listDirectSubdirectories } from '../src/directoryLister.js';
7
-
8
- describe('directoryLister', () => {
9
- let tempDir;
10
-
11
- beforeEach(async () => {
12
- tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'batch-exec-test-'));
13
-
14
- await fs.mkdir(path.join(tempDir, 'dir1'));
15
- await fs.mkdir(path.join(tempDir, 'dir2'));
16
- await fs.mkdir(path.join(tempDir, 'node_modules'));
17
- await fs.mkdir(path.join(tempDir, '.git'));
18
-
19
- await fs.writeFile(path.join(tempDir, 'file1.txt'), 'content');
20
- await fs.writeFile(path.join(tempDir, 'file2.js'), 'content');
21
- });
22
-
23
- afterEach(async () => {
24
- await fs.rm(tempDir, { recursive: true, force: true });
25
- });
26
-
27
- describe('listDirectSubdirectories', () => {
28
- it('should list only direct subdirectories', async () => {
29
- const subdirs = await listDirectSubdirectories(tempDir);
30
- assert.deepStrictEqual(subdirs.sort(), ['.git', 'dir1', 'dir2', 'node_modules'].sort());
31
- });
32
-
33
- it('should skip directories matching patterns', async () => {
34
- const subdirs = await listDirectSubdirectories(tempDir, ['node_modules', '.git']);
35
- assert.deepStrictEqual(subdirs, ['dir1', 'dir2']);
36
- });
37
-
38
- it('should skip directories with wildcard patterns', async () => {
39
- const subdirs = await listDirectSubdirectories(tempDir, ['dir*']);
40
- assert.deepStrictEqual(subdirs.sort(), ['.git', 'node_modules'].sort());
41
- });
42
-
43
- it('should return sorted directory names', async () => {
44
- const subdirs = await listDirectSubdirectories(tempDir);
45
- assert.deepStrictEqual(subdirs, subdirs.slice().sort());
46
- });
47
-
48
- it('should throw error for non-existent directory', async () => {
49
- await assert.rejects(
50
- listDirectSubdirectories(path.join(tempDir, 'non-existent')),
51
- { message: /Directory not found/ }
52
- );
53
- });
54
-
55
- it('should throw error for file path', async () => {
56
- await assert.rejects(
57
- listDirectSubdirectories(path.join(tempDir, 'file1.txt')),
58
- { message: /Not a directory/ }
59
- );
60
- });
61
-
62
- it('should work with relative paths', async () => {
63
- const relativePath = path.relative(process.cwd(), tempDir);
64
- const subdirs = await listDirectSubdirectories(relativePath);
65
- assert.deepStrictEqual(subdirs.sort(), ['.git', 'dir1', 'dir2', 'node_modules'].sort());
66
- });
67
- });
68
- });
@@ -1,93 +0,0 @@
1
- import { describe, it, beforeEach, afterEach } from 'node:test';
2
- import assert from 'node:assert';
3
- import fs from 'fs/promises';
4
- import path from 'path';
5
- import os from 'os';
6
- import { parseIgnoreFile, shouldSkipDirectory } from '../src/ignoreParser.js';
7
-
8
- describe('ignoreParser', () => {
9
- let tempDir;
10
-
11
- beforeEach(async () => {
12
- tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'batch-exec-test-'));
13
- });
14
-
15
- afterEach(async () => {
16
- await fs.rm(tempDir, { recursive: true, force: true });
17
- });
18
-
19
- describe('parseIgnoreFile', () => {
20
- it('should parse ignore file correctly', async () => {
21
- const ignoreFilePath = path.join(tempDir, '.testignore');
22
- await fs.writeFile(ignoreFilePath, `
23
- # This is a comment
24
- node_modules
25
- dist/
26
- *.tmp
27
- test-*
28
-
29
- # Another comment
30
- build
31
- `.trim());
32
-
33
- const patterns = await parseIgnoreFile(ignoreFilePath);
34
- assert.deepStrictEqual(patterns, [
35
- 'node_modules',
36
- 'dist/',
37
- '*.tmp',
38
- 'test-*',
39
- 'build'
40
- ]);
41
- });
42
-
43
- it('should return empty array for non-existent file', async () => {
44
- const patterns = await parseIgnoreFile(path.join(tempDir, 'non-existent'));
45
- assert.deepStrictEqual(patterns, []);
46
- });
47
-
48
- it('should return empty array for null or undefined', async () => {
49
- const patterns1 = await parseIgnoreFile(null);
50
- const patterns2 = await parseIgnoreFile(undefined);
51
- assert.deepStrictEqual(patterns1, []);
52
- assert.deepStrictEqual(patterns2, []);
53
- });
54
- });
55
-
56
- describe('shouldSkipDirectory', () => {
57
- it('should return false when no patterns provided', () => {
58
- assert.strictEqual(shouldSkipDirectory('dir1', []), false);
59
- assert.strictEqual(shouldSkipDirectory('dir1', null), false);
60
- assert.strictEqual(shouldSkipDirectory('dir1', undefined), false);
61
- });
62
-
63
- it('should match exact directory names', () => {
64
- assert.strictEqual(shouldSkipDirectory('node_modules', ['node_modules']), true);
65
- assert.strictEqual(shouldSkipDirectory('dist', ['node_modules']), false);
66
- });
67
-
68
- it('should match directory names with trailing slash', () => {
69
- assert.strictEqual(shouldSkipDirectory('dist', ['dist/']), true);
70
- assert.strictEqual(shouldSkipDirectory('node_modules', ['dist/']), false);
71
- });
72
-
73
- it('should match wildcard patterns', () => {
74
- assert.strictEqual(shouldSkipDirectory('test-123', ['test-*']), true);
75
- assert.strictEqual(shouldSkipDirectory('test-abc', ['test-*']), true);
76
- assert.strictEqual(shouldSkipDirectory('other', ['test-*']), false);
77
- });
78
-
79
- it('should match extension wildcards', () => {
80
- assert.strictEqual(shouldSkipDirectory('file.tmp', ['*.tmp']), true);
81
- assert.strictEqual(shouldSkipDirectory('test.tmp', ['*.tmp']), true);
82
- assert.strictEqual(shouldSkipDirectory('test.txt', ['*.tmp']), false);
83
- });
84
-
85
- it('should match any of the patterns', () => {
86
- const patterns = ['node_modules', 'dist/', '*.tmp'];
87
- assert.strictEqual(shouldSkipDirectory('node_modules', patterns), true);
88
- assert.strictEqual(shouldSkipDirectory('dist', patterns), true);
89
- assert.strictEqual(shouldSkipDirectory('test.tmp', patterns), true);
90
- assert.strictEqual(shouldSkipDirectory('src', patterns), false);
91
- });
92
- });
93
- });
@@ -1,70 +0,0 @@
1
- import { describe, it, beforeEach, afterEach } from 'node:test';
2
- import assert from 'node:assert';
3
- import fs from 'fs/promises';
4
- import path from 'path';
5
- import os from 'os';
6
- import { batchExecute } from '../src/index.js';
7
-
8
- describe('batchExecute', () => {
9
- let tempDir;
10
-
11
- beforeEach(async () => {
12
- tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'batch-exec-test-'));
13
-
14
- await fs.mkdir(path.join(tempDir, 'dir1'));
15
- await fs.mkdir(path.join(tempDir, 'dir2'));
16
- await fs.mkdir(path.join(tempDir, 'skip-me'));
17
- });
18
-
19
- afterEach(async () => {
20
- await fs.rm(tempDir, { recursive: true, force: true });
21
- });
22
-
23
- it('should execute command in all subdirectories', async () => {
24
- const results = await batchExecute(tempDir, 'pwd', []);
25
-
26
- assert.strictEqual(results.length, 3);
27
-
28
- results.forEach(result => {
29
- assert.strictEqual(result.success, true);
30
- });
31
- });
32
-
33
- it('should skip specified directories', async () => {
34
- const results = await batchExecute(tempDir, 'pwd', [], {
35
- skipPaths: ['skip-me']
36
- });
37
-
38
- assert.strictEqual(results.length, 2);
39
-
40
- const dirs = results.map(r => r.directory);
41
- assert.deepStrictEqual(dirs.sort(), ['dir1', 'dir2'].sort());
42
- });
43
-
44
- it('should capture command output', async () => {
45
- const results = await batchExecute(tempDir, 'echo', ['hello']);
46
-
47
- results.forEach(result => {
48
- assert.strictEqual(result.success, true);
49
- assert(result.stdout.includes('hello'));
50
- });
51
- });
52
-
53
- it('should handle command failures gracefully', async () => {
54
- const results = await batchExecute(tempDir, 'this-command-does-not-exist', []);
55
-
56
- results.forEach(result => {
57
- assert.strictEqual(result.success, false);
58
- assert(result.error);
59
- });
60
- });
61
-
62
- it('should work with multiple arguments', async () => {
63
- const results = await batchExecute(tempDir, 'echo', ['hello', 'world']);
64
-
65
- results.forEach(result => {
66
- assert.strictEqual(result.success, true);
67
- assert(result.stdout.includes('hello world'));
68
- });
69
- });
70
- });