gitfleet 1.0.1 → 1.0.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/bin/gitfleet.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  const { Command } = require("commander");
4
4
 
@@ -8,30 +8,60 @@ const status = require("../commands/status");
8
8
  const pull = require("../commands/pull");
9
9
  const exec = require("../commands/exec");
10
10
  const scan = require("../commands/scan");
11
- const list = require("../commands/list")
12
- const branch = require("../commands/branch")
13
-
11
+ const list = require("../commands/list");
12
+ const branch = require("../commands/branch");
13
+ const fetch = require("../commands/fetch");
14
14
 
15
15
  const program = new Command();
16
16
 
17
17
  program
18
- .name("gitfleet")
19
- .description("Manage multiple git repositories");
18
+ .name("gitfleet")
19
+ .description("Manage multiple git repositories")
20
+ .version("1.0.0");
20
21
 
21
- program.command("init").action(init);
22
+ program
23
+ .command("init")
24
+ .option("--scan", "Scan workspace for git repos")
25
+ .action((options) => init(options));
22
26
 
23
- program.command("add <path>").action(add);
27
+ program
28
+ .command("add <path>")
29
+ .description("Add repository to fleet")
30
+ .action(add);
24
31
 
25
- program.command("status").action(status);
32
+ program
33
+ .command("status")
34
+ .description("Show repo status")
35
+ .action(status);
26
36
 
27
- program.command("pull").action(pull);
37
+ program
38
+ .command("pull")
39
+ .description("Pull all repositories")
40
+ .action(pull);
28
41
 
29
- program.command("scan <path>").action(scan);
42
+ program
43
+ .command("scan <path>")
44
+ .description("Scan directory for git repositories")
45
+ .action(scan);
30
46
 
31
- program.command("exec <command>").action(exec)
47
+ program
48
+ .command("exec <command>")
49
+ .description("Run command across all repos")
50
+ .action(exec);
32
51
 
33
- program.command("list").action(list)
52
+ program
53
+ .command("list")
54
+ .description("List all repos in fleet")
55
+ .action(list);
34
56
 
35
- program.command("branch").action(branch)
57
+ program
58
+ .command("branch")
59
+ .description("Show branches across repos")
60
+ .action(branch);
61
+
62
+ program
63
+ .command("fetch")
64
+ .description("Fetch updates from all repos")
65
+ .action(fetch);
36
66
 
37
67
  program.parse();
@@ -0,0 +1,21 @@
1
+ const { loadConfig } = require("../core/config");
2
+
3
+ const { execSync } = require("child_process");
4
+
5
+
6
+
7
+ module.exports = function () {
8
+
9
+ const config = loadConfig();
10
+
11
+ for(const repo of config.repos){
12
+ try{
13
+
14
+ console.log(`\n▶ Running Fetch in ${repo}`);
15
+
16
+ execSync("git fetch", { cwd: repo, stdio: "inherit" });
17
+ }catch(e){
18
+ console.log("Error:",e)
19
+ }
20
+ }
21
+ }
package/commands/init.js CHANGED
@@ -1,10 +1,31 @@
1
- const { saveConfig, configFile } = require("../core/config");
1
+ const fs = require("fs");
2
+ const path = require("path");
2
3
 
3
- module.exports = function () {
4
+ const scan = require("./scan");
4
5
 
5
- saveConfig({ repos: [] });
6
+ function init(args = []) {
6
7
 
7
- console.log("GitFleet initialized");
8
- console.log("Config file:", configFile);
8
+ const dir = path.join(process.cwd(), ".gitfleet");
9
9
 
10
- };
10
+ if (!fs.existsSync(dir)) {
11
+ fs.mkdirSync(dir);
12
+ }
13
+
14
+ const configPath = path.join(dir, "config.json");
15
+
16
+ if (!fs.existsSync(configPath)) {
17
+ fs.writeFileSync(
18
+ configPath,
19
+ JSON.stringify({ repos: [] }, null, 2)
20
+ );
21
+ }
22
+
23
+ console.log("✔ GitFleet workspace initialized");
24
+
25
+ if (args.includes("--scan")) {
26
+ console.log("\n🔎 Scanning for git repositories...\n");
27
+ scan(process.cwd());
28
+ }
29
+ }
30
+
31
+ module.exports = init;
package/commands/pull.js CHANGED
@@ -1,29 +1,26 @@
1
- const { loadConfig } = require("../core/config");
2
- const { execSync } = require("child_process");
1
+ const { runWorkerPool } = require("../core/workerPool");
2
+ const { exec } = require("child_process");
3
3
 
4
- function isRepoDirty(repo) {
5
-
6
- const status = execSync("git status --porcelain", { cwd: repo })
7
- .toString()
8
- .trim();
9
-
10
- return status.length > 0;
4
+ function runGit(repo, command) {
5
+ return new Promise((resolve, reject) => {
6
+ exec(`git -C "${repo}" ${command}`, (err, stdout, stderr) => {
7
+ if (err) {
8
+ console.error(`❌ ${repo}`);
9
+ return reject(err);
10
+ }
11
11
 
12
+ console.log(`✔ ${repo}`);
13
+ resolve(stdout);
14
+ });
15
+ });
12
16
  }
13
17
 
14
- module.exports = function () {
15
- const config = loadConfig();
16
- for (const repo of config.repos) {
17
- try {
18
- if (isRepoDirty(repo)) {
19
- console.log(`⚠ Skipping ${repo} (local changes)`);
20
- continue;
21
- }
22
- console.log(`⬇ Pulling ${repo}`);
23
- execSync("git pull", { cwd: repo, stdio: "inherit" });
24
- } catch (err) {
25
- console.log(`Failed for ${repo}`);
26
- }
27
- }
18
+ async function pullRepos(repos) {
19
+ await runWorkerPool(
20
+ repos,
21
+ (repo) => runGit(repo, "pull"),
22
+ 4
23
+ );
24
+ }
28
25
 
29
- };
26
+ module.exports = pullRepos;
package/commands/scan.js CHANGED
@@ -11,10 +11,9 @@ function findRepos(dir, repos = []) {
11
11
 
12
12
  const fullPath = path.join(dir, item.name);
13
13
 
14
- // if .git folder found
15
14
  if (item.name === ".git") {
16
- repos.push(dir);
17
- continue;
15
+ repos.push(dir);
16
+ return repos;
18
17
  }
19
18
 
20
19
  if (item.isDirectory() && item.name !== "node_modules") {
package/core/config.js CHANGED
@@ -1,28 +1,45 @@
1
1
  const fs = require("fs");
2
- const os = require("os");
3
2
  const path = require("path");
3
+ const os = require("os");
4
4
 
5
- const configDir = path.join(os.homedir(), ".gitfleet");
6
- const configFile = path.join(configDir, "config.json");
5
+ function findWorkspaceConfig(start = process.cwd()) {
6
+ let dir = start;
7
7
 
8
- function loadConfig() {
9
- if (!fs.existsSync(configFile)) {
10
- return { repos: [] };
8
+ while (dir !== path.dirname(dir)) {
9
+ const configDir = path.join(dir, ".gitfleet");
10
+
11
+ if (fs.existsSync(configDir)) {
12
+ return path.join(configDir, "config.json");
13
+ }
14
+
15
+ dir = path.dirname(dir);
11
16
  }
12
17
 
13
- return JSON.parse(fs.readFileSync(configFile));
18
+ return null;
19
+ }
20
+
21
+ function globalConfigPath() {
22
+ return path.join(os.homedir(), ".gitfleet", "config.json");
14
23
  }
15
24
 
16
- function saveConfig(config) {
17
- if (!fs.existsSync(configDir)) {
18
- fs.mkdirSync(configDir);
25
+ function loadConfig() {
26
+ const workspace = findWorkspaceConfig();
27
+
28
+ if (workspace && fs.existsSync(workspace)) {
29
+ return JSON.parse(fs.readFileSync(workspace));
30
+ }
31
+
32
+ const global = globalConfigPath();
33
+
34
+ if (fs.existsSync(global)) {
35
+ return JSON.parse(fs.readFileSync(global));
19
36
  }
20
37
 
21
- fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
38
+ return { repos: [] };
22
39
  }
23
40
 
24
41
  module.exports = {
25
42
  loadConfig,
26
- saveConfig,
27
- configFile,
43
+ findWorkspaceConfig,
44
+ globalConfigPath
28
45
  };
@@ -0,0 +1,22 @@
1
+ const pLimit = require("p-limit");
2
+
3
+ const os = require("os");
4
+ const workers = os.cpus().length * 2;
5
+
6
+ /**
7
+ * Run tasks in parallel with limited concurrency
8
+ * @param {Array} items - list of items (repos)
9
+ * @param {Function} task - async function to run per item
10
+ * @param {number} workers - number of parallel workers
11
+ */
12
+ async function runWorkerPool(items, task, workers=4) {
13
+ const limit = pLimit(workers);
14
+
15
+ const tasks = items.map(item =>
16
+ limit(() => task(item))
17
+ );
18
+
19
+ return Promise.allSettled(tasks);
20
+ }
21
+
22
+ module.exports = { runWorkerPool };
package/package.json CHANGED
@@ -1,23 +1,26 @@
1
1
  {
2
2
  "name": "gitfleet",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
7
7
  },
8
- "keywords": ["git",
8
+ "keywords": [
9
+ "git",
9
10
  "cli",
10
11
  "developer-tools",
11
- "git-manager"],
12
+ "git-manager"
13
+ ],
12
14
  "description": "",
13
15
  "dependencies": {
14
16
  "chalk": "^5.6.2",
15
17
  "commander": "^14.0.3",
16
- "ora": "^9.3.0"
18
+ "ora": "^9.3.0",
19
+ "p-limit": "^7.3.0"
17
20
  },
18
21
  "bin": {
19
- "gitfleet": "./bin/gitfleet.js"
22
+ "gitfleet": "./bin/gitfleet.js"
20
23
  },
21
- "author": "Kartik Singla",
24
+ "author": "Kartik Singla",
22
25
  "license": "MIT"
23
26
  }
package/readme.md CHANGED
@@ -1,56 +1,262 @@
1
1
  # GitFleet
2
2
 
3
- Manage multiple Git repositories from a single command.
3
+ GitFleet is a CLI tool to **manage multiple Git repositories from one place**.
4
4
 
5
- Stop manually pulling, pushing, and checking repos one by one.
5
+ It allows developers working with many repositories (microservices, multi-repo projects, etc.) to run Git commands across all repositories quickly.
6
6
 
7
- GitFleet lets you manage your entire repo fleet in seconds.
7
+ ---
8
8
 
9
- ## Features
9
+ # Features
10
10
 
11
- - Add multiple repositories
12
- - Run commands across all repos
13
- - Pull/push everything instantly
14
- - Clean CLI output
15
- - Lightweight config system
11
+ * Manage multiple Git repositories as a **fleet**
12
+ * Pull updates across all repos
13
+ * Check repository status
14
+ * Run commands across multiple repos
15
+ * Automatically scan and detect Git repositories
16
+ * Workspace-based configuration
16
17
 
17
- ## Install
18
+ ---
18
19
 
20
+ # Installation
21
+
22
+ Install GitFleet globally using npm:
23
+
24
+ ```bash
19
25
  npm install -g gitfleet
26
+ ```
20
27
 
21
- ## Usage
28
+ Verify installation:
22
29
 
23
- Add repository
30
+ ```bash
31
+ gitfleet --version
32
+ ```
24
33
 
25
- gitfleet add /path/to/repo
34
+ ---
26
35
 
27
- Pull all repos
36
+ # Workspace Configuration
28
37
 
29
- gitfleet pull
38
+ GitFleet stores repository information in a **workspace configuration file**.
39
+
40
+ ```
41
+ .gitfleet/config.json
42
+ ```
43
+
44
+ Example:
45
+
46
+ ```json
47
+ {
48
+ "repos": [
49
+ "./auth-service",
50
+ "./payment-service",
51
+ "./dashboard"
52
+ ]
53
+ }
54
+ ```
55
+
56
+ This file tracks all repositories that belong to the fleet.
57
+
58
+ ---
59
+
60
+ # Getting Started
61
+
62
+ Navigate to a directory that contains your repositories.
63
+
64
+ Example:
65
+
66
+ ```bash
67
+ cd ~/projects/microservices
68
+ ```
69
+
70
+ Initialize GitFleet workspace:
71
+
72
+ ```bash
73
+ gitfleet init
74
+ ```
75
+
76
+ This creates:
77
+
78
+ ```
79
+ .gitfleet/config.json
80
+ ```
81
+
82
+ ---
83
+
84
+ # Automatically Scan Repositories
85
+
86
+ To automatically detect Git repositories in your workspace:
30
87
 
31
- Push all repos
88
+ ```bash
89
+ gitfleet init --scan
90
+ ```
32
91
 
33
- gitfleet push
92
+ or
34
93
 
35
- List repos
94
+ ```bash
95
+ gitfleet scan .
96
+ ```
36
97
 
98
+ Example output:
99
+
100
+ ```
101
+ ✔ GitFleet workspace initialized
102
+
103
+ Scanning workspace...
104
+
105
+ Added: auth-service
106
+ Added: payment-service
107
+ Added: dashboard
108
+ ```
109
+
110
+ ---
111
+
112
+ # List Repositories
113
+
114
+ Show all repositories in the fleet:
115
+
116
+ ```bash
37
117
  gitfleet list
118
+ ```
119
+
120
+ Example output:
121
+
122
+ ```
123
+ auth-service
124
+ payment-service
125
+ dashboard
126
+ ```
127
+
128
+ ---
129
+
130
+ # Pull All Repositories
131
+
132
+ Pull updates across every repository:
133
+
134
+ ```bash
135
+ gitfleet pull
136
+ ```
137
+
138
+ This runs:
139
+
140
+ ```
141
+ git pull
142
+ ```
143
+
144
+ in every repository in the fleet.
145
+
146
+ ---
38
147
 
39
- ## Example
148
+ # Check Repository Status
40
149
 
41
- Managing 20+ microservices becomes easy:
150
+ ```bash
151
+ gitfleet status
152
+ ```
153
+
154
+ Example output:
155
+
156
+ ```
157
+ auth-service ✔ clean
158
+ payment-service ⚠ uncommitted changes
159
+ dashboard ↓ 2 commits behind
160
+ ```
161
+
162
+ ---
163
+
164
+ # Execute Commands Across Repositories
165
+
166
+ Run any command across all repositories.
167
+
168
+ Example:
169
+
170
+ ```bash
171
+ gitfleet exec "npm install"
172
+ ```
173
+
174
+ Another example:
175
+
176
+ ```bash
177
+ gitfleet exec "git checkout main"
178
+ ```
179
+
180
+ ---
181
+
182
+ # Fetch Updates
183
+
184
+ Fetch updates from all repositories without merging.
185
+
186
+ ```bash
187
+ gitfleet fetch
188
+ ```
189
+
190
+ ---
191
+
192
+ # Show Current Branch
193
+
194
+ Display the active branch of each repository:
195
+
196
+ ```bash
197
+ gitfleet branch
198
+ ```
199
+
200
+ Example output:
201
+
202
+ ```
203
+ auth-service main
204
+ payment-service develop
205
+ dashboard main
206
+ ```
207
+
208
+ ---
209
+
210
+ # Add Repository Manually
211
+
212
+ Add a repository manually to the fleet.
213
+
214
+ ```bash
215
+ gitfleet add ../new-service
216
+ ```
217
+
218
+ ---
219
+
220
+ # Example Workflow
221
+
222
+ Typical workflow for a developer managing multiple repositories:
223
+
224
+ ```bash
225
+ cd ~/projects/microservices
226
+
227
+ gitfleet init --scan
42
228
 
43
229
  gitfleet pull
230
+
44
231
  gitfleet status
45
- gitfleet push
46
232
 
47
- ## Why GitFleet?
233
+ gitfleet exec "npm install"
234
+ ```
235
+
236
+ ---
237
+
238
+ # Example Project Structure
239
+
240
+ ```
241
+ microservices/
242
+ .gitfleet/
243
+ config.json
244
+
245
+ auth-service/
246
+ payment-service/
247
+ dashboard/
248
+ ```
249
+
250
+ ---
251
+
252
+ # Why GitFleet?
253
+
254
+ Developers working with microservices or multiple repositories often run the same commands repeatedly.
48
255
 
49
- Developers working with multiple repositories waste time repeating commands.
256
+ GitFleet helps automate those workflows and manage repositories as a single fleet.
50
257
 
51
- GitFleet automates it.
258
+ ---
52
259
 
53
- ## Author
260
+ # License
54
261
 
55
- Kartik Singla
56
- Full-Stack / Web3 Developer
262
+ MIT