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 +44 -14
- package/commands/fetch.js +21 -0
- package/commands/init.js +27 -6
- package/commands/pull.js +21 -24
- package/commands/scan.js +2 -3
- package/core/config.js +30 -13
- package/core/workerPool.js +22 -0
- package/package.json +9 -6
- package/readme.md +233 -27
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
|
|
12
|
-
const 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
|
|
22
|
+
program
|
|
23
|
+
.command("init")
|
|
24
|
+
.option("--scan", "Scan workspace for git repos")
|
|
25
|
+
.action((options) => init(options));
|
|
22
26
|
|
|
23
|
-
program
|
|
27
|
+
program
|
|
28
|
+
.command("add <path>")
|
|
29
|
+
.description("Add repository to fleet")
|
|
30
|
+
.action(add);
|
|
24
31
|
|
|
25
|
-
program
|
|
32
|
+
program
|
|
33
|
+
.command("status")
|
|
34
|
+
.description("Show repo status")
|
|
35
|
+
.action(status);
|
|
26
36
|
|
|
27
|
-
program
|
|
37
|
+
program
|
|
38
|
+
.command("pull")
|
|
39
|
+
.description("Pull all repositories")
|
|
40
|
+
.action(pull);
|
|
28
41
|
|
|
29
|
-
program
|
|
42
|
+
program
|
|
43
|
+
.command("scan <path>")
|
|
44
|
+
.description("Scan directory for git repositories")
|
|
45
|
+
.action(scan);
|
|
30
46
|
|
|
31
|
-
program
|
|
47
|
+
program
|
|
48
|
+
.command("exec <command>")
|
|
49
|
+
.description("Run command across all repos")
|
|
50
|
+
.action(exec);
|
|
32
51
|
|
|
33
|
-
program
|
|
52
|
+
program
|
|
53
|
+
.command("list")
|
|
54
|
+
.description("List all repos in fleet")
|
|
55
|
+
.action(list);
|
|
34
56
|
|
|
35
|
-
program
|
|
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
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
const scan = require("./scan");
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
function init(args = []) {
|
|
6
7
|
|
|
7
|
-
|
|
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 {
|
|
2
|
-
const {
|
|
1
|
+
const { runWorkerPool } = require("../core/workerPool");
|
|
2
|
+
const { exec } = require("child_process");
|
|
3
3
|
|
|
4
|
-
function
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
6
|
-
|
|
5
|
+
function findWorkspaceConfig(start = process.cwd()) {
|
|
6
|
+
let dir = start;
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function globalConfigPath() {
|
|
22
|
+
return path.join(os.homedir(), ".gitfleet", "config.json");
|
|
14
23
|
}
|
|
15
24
|
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
38
|
+
return { repos: [] };
|
|
22
39
|
}
|
|
23
40
|
|
|
24
41
|
module.exports = {
|
|
25
42
|
loadConfig,
|
|
26
|
-
|
|
27
|
-
|
|
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.
|
|
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": [
|
|
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
|
-
|
|
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
|
-
|
|
3
|
+
GitFleet is a CLI tool to **manage multiple Git repositories from one place**.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It allows developers working with many repositories (microservices, multi-repo projects, etc.) to run Git commands across all repositories quickly.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
---
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
# Features
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
28
|
+
Verify installation:
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
```bash
|
|
31
|
+
gitfleet --version
|
|
32
|
+
```
|
|
24
33
|
|
|
25
|
-
|
|
34
|
+
---
|
|
26
35
|
|
|
27
|
-
|
|
36
|
+
# Workspace Configuration
|
|
28
37
|
|
|
29
|
-
|
|
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
|
-
|
|
88
|
+
```bash
|
|
89
|
+
gitfleet init --scan
|
|
90
|
+
```
|
|
32
91
|
|
|
33
|
-
|
|
92
|
+
or
|
|
34
93
|
|
|
35
|
-
|
|
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
|
-
|
|
148
|
+
# Check Repository Status
|
|
40
149
|
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
256
|
+
GitFleet helps automate those workflows and manage repositories as a single fleet.
|
|
50
257
|
|
|
51
|
-
|
|
258
|
+
---
|
|
52
259
|
|
|
53
|
-
|
|
260
|
+
# License
|
|
54
261
|
|
|
55
|
-
|
|
56
|
-
Full-Stack / Web3 Developer
|
|
262
|
+
MIT
|