gitfleet 1.0.0 → 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.0",
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 ADDED
@@ -0,0 +1,262 @@
1
+ # GitFleet
2
+
3
+ GitFleet is a CLI tool to **manage multiple Git repositories from one place**.
4
+
5
+ It allows developers working with many repositories (microservices, multi-repo projects, etc.) to run Git commands across all repositories quickly.
6
+
7
+ ---
8
+
9
+ # Features
10
+
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
17
+
18
+ ---
19
+
20
+ # Installation
21
+
22
+ Install GitFleet globally using npm:
23
+
24
+ ```bash
25
+ npm install -g gitfleet
26
+ ```
27
+
28
+ Verify installation:
29
+
30
+ ```bash
31
+ gitfleet --version
32
+ ```
33
+
34
+ ---
35
+
36
+ # Workspace Configuration
37
+
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:
87
+
88
+ ```bash
89
+ gitfleet init --scan
90
+ ```
91
+
92
+ or
93
+
94
+ ```bash
95
+ gitfleet scan .
96
+ ```
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
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
+ ---
147
+
148
+ # Check Repository Status
149
+
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
228
+
229
+ gitfleet pull
230
+
231
+ gitfleet status
232
+
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.
255
+
256
+ GitFleet helps automate those workflows and manage repositories as a single fleet.
257
+
258
+ ---
259
+
260
+ # License
261
+
262
+ MIT