gitshift 2.0.0 → 2.1.0
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/package.json +1 -1
- package/src/commands/auto.js +51 -0
- package/src/commands/link.js +146 -0
- package/src/commands/links.js +20 -0
- package/src/commands/unlink.js +17 -0
- package/src/server.js +35 -1
- package/src/services/profile.js +35 -0
package/package.json
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
|
|
2
|
+
import {
|
|
3
|
+
getFolderMappings,
|
|
4
|
+
getProfile,
|
|
5
|
+
setCurrentProfile,
|
|
6
|
+
} from "../services/profile.js";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
setGitUser,
|
|
10
|
+
} from "../services/git.js";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
success,
|
|
14
|
+
} from "../utils/logger.js";
|
|
15
|
+
|
|
16
|
+
export async function autoCommand() {
|
|
17
|
+
const cwd = process.cwd();
|
|
18
|
+
|
|
19
|
+
const mappings = getFolderMappings();
|
|
20
|
+
|
|
21
|
+
const matched =
|
|
22
|
+
mappings
|
|
23
|
+
.sort(
|
|
24
|
+
(a, b) =>
|
|
25
|
+
b.path.length -
|
|
26
|
+
a.path.length
|
|
27
|
+
)
|
|
28
|
+
.find((mapping) =>
|
|
29
|
+
cwd.startsWith(
|
|
30
|
+
mapping.path
|
|
31
|
+
)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
if (!matched) {
|
|
35
|
+
console.log("\nNo matching profile\n");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const profile =
|
|
40
|
+
getProfile(matched.profile);
|
|
41
|
+
|
|
42
|
+
if (!profile) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await setGitUser(profile.username, profile.email);
|
|
47
|
+
|
|
48
|
+
setCurrentProfile(profile.name);
|
|
49
|
+
|
|
50
|
+
success(`Switched to ${profile.name}`);
|
|
51
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
confirm,
|
|
6
|
+
input,
|
|
7
|
+
select,
|
|
8
|
+
} from "@inquirer/prompts";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
addFolderMapping,
|
|
12
|
+
getProfiles,
|
|
13
|
+
saveProfile,
|
|
14
|
+
} from "../services/profile.js";
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
generateSSHKey,
|
|
18
|
+
} from "../services/ssh.js";
|
|
19
|
+
|
|
20
|
+
import ora from "ora";
|
|
21
|
+
import {
|
|
22
|
+
error,
|
|
23
|
+
success,
|
|
24
|
+
} from "../utils/logger.js";
|
|
25
|
+
|
|
26
|
+
export async function linkCommand(
|
|
27
|
+
folder
|
|
28
|
+
) {
|
|
29
|
+
const fullPath = path.resolve(folder);
|
|
30
|
+
|
|
31
|
+
const exists = await fs.pathExists(fullPath);
|
|
32
|
+
|
|
33
|
+
if (!exists) {
|
|
34
|
+
error("Folder does not exist");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let profiles = getProfiles();
|
|
39
|
+
|
|
40
|
+
let selectedProfile;
|
|
41
|
+
|
|
42
|
+
if (profiles.length === 0) {
|
|
43
|
+
console.log("\nNo profiles found.\n");
|
|
44
|
+
|
|
45
|
+
selectedProfile = await createProfile();
|
|
46
|
+
} else {
|
|
47
|
+
const choice =
|
|
48
|
+
await select({
|
|
49
|
+
message: "Select Profile",
|
|
50
|
+
choices: [
|
|
51
|
+
...profiles.map(
|
|
52
|
+
(
|
|
53
|
+
profile
|
|
54
|
+
) => ({
|
|
55
|
+
name: `${profile.name} (${profile.username})`,
|
|
56
|
+
value:
|
|
57
|
+
profile.name,
|
|
58
|
+
})
|
|
59
|
+
),
|
|
60
|
+
{
|
|
61
|
+
name: "+ Create New Profile",
|
|
62
|
+
value: "__create__",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (choice === "__create__") {
|
|
68
|
+
selectedProfile = await createProfile();
|
|
69
|
+
} else {
|
|
70
|
+
selectedProfile = choice;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
addFolderMapping(selectedProfile, fullPath);
|
|
76
|
+
|
|
77
|
+
success(`Linked ${fullPath}`);
|
|
78
|
+
|
|
79
|
+
success(`Profile: ${selectedProfile}`);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
error(err.message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function createProfile() {
|
|
86
|
+
const name =
|
|
87
|
+
await input({
|
|
88
|
+
message: "Profile Name",
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const username =
|
|
92
|
+
await input({
|
|
93
|
+
message: "GitHub Username",
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const email =
|
|
97
|
+
await input({
|
|
98
|
+
message: "Email",
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const shouldCreateSSH =
|
|
102
|
+
await confirm({
|
|
103
|
+
message: "Generate SSH Key?",
|
|
104
|
+
default: true,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
let sshKey = null;
|
|
108
|
+
|
|
109
|
+
if (shouldCreateSSH) {
|
|
110
|
+
const spinner = ora("Generating SSH key...").start();
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
sshKey = await generateSSHKey(name, email);
|
|
114
|
+
|
|
115
|
+
spinner.succeed("SSH key generated");
|
|
116
|
+
} catch (err) {
|
|
117
|
+
spinner.fail("Unable to generate SSH key");
|
|
118
|
+
|
|
119
|
+
error("Could not create SSH key. Ensure OpenSSH is installed and available.");
|
|
120
|
+
|
|
121
|
+
if (
|
|
122
|
+
err &&
|
|
123
|
+
typeof err === "object" &&
|
|
124
|
+
"shortMessage" in err &&
|
|
125
|
+
err.shortMessage
|
|
126
|
+
) {
|
|
127
|
+
error(String(err.shortMessage));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
saveProfile({
|
|
136
|
+
name,
|
|
137
|
+
username,
|
|
138
|
+
email,
|
|
139
|
+
sshKey,
|
|
140
|
+
source: "manual",
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
success(`Profile "${name}" created`);
|
|
144
|
+
|
|
145
|
+
return name;
|
|
146
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getFolderMappings,
|
|
3
|
+
} from "../services/profile.js";
|
|
4
|
+
|
|
5
|
+
export async function linksCommand() {
|
|
6
|
+
const mappings = getFolderMappings();
|
|
7
|
+
|
|
8
|
+
if (!mappings.length) {
|
|
9
|
+
console.log("\nNo folder mappings\n");
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
console.log();
|
|
14
|
+
|
|
15
|
+
mappings.forEach((mapping) => {
|
|
16
|
+
console.log(`${mapping.profile} → ${mapping.path}`);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
console.log();
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
removeFolderMapping,
|
|
5
|
+
} from "../services/profile.js";
|
|
6
|
+
|
|
7
|
+
import { success } from "../utils/logger.js";
|
|
8
|
+
|
|
9
|
+
export async function unlinkCommand(
|
|
10
|
+
folder
|
|
11
|
+
) {
|
|
12
|
+
const fullPath = path.resolve(folder);
|
|
13
|
+
|
|
14
|
+
removeFolderMapping(fullPath);
|
|
15
|
+
|
|
16
|
+
success(`Removed ${fullPath}`);
|
|
17
|
+
}
|
package/src/server.js
CHANGED
|
@@ -5,11 +5,15 @@ import chalk from "chalk";
|
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { addCommand } from "./commands/add.js";
|
|
8
|
+
import { autoCommand } from "./commands/auto.js";
|
|
8
9
|
import { currentCommand } from "./commands/current.js";
|
|
9
10
|
import { doctorCommand } from "./commands/doctor.js";
|
|
11
|
+
import { linkCommand } from "./commands/link.js";
|
|
12
|
+
import { linksCommand } from "./commands/links.js";
|
|
10
13
|
import { listCommand } from "./commands/list.js";
|
|
11
14
|
import { removeCommand } from "./commands/remove.js";
|
|
12
15
|
import { scanCommand } from "./commands/scan.js";
|
|
16
|
+
import { unlinkCommand } from "./commands/unlink.js";
|
|
13
17
|
import { useCommand } from "./commands/use.js";
|
|
14
18
|
|
|
15
19
|
const require = createRequire(import.meta.url);
|
|
@@ -113,7 +117,7 @@ async function main() {
|
|
|
113
117
|
program
|
|
114
118
|
.command("remove <profile>")
|
|
115
119
|
.description(
|
|
116
|
-
"
|
|
120
|
+
"Remove profile"
|
|
117
121
|
)
|
|
118
122
|
.action(removeCommand);
|
|
119
123
|
|
|
@@ -124,6 +128,36 @@ async function main() {
|
|
|
124
128
|
)
|
|
125
129
|
.action(scanCommand);
|
|
126
130
|
|
|
131
|
+
program
|
|
132
|
+
.command(
|
|
133
|
+
"link <folder>"
|
|
134
|
+
)
|
|
135
|
+
.description(
|
|
136
|
+
"Link folder to profile"
|
|
137
|
+
)
|
|
138
|
+
.action(linkCommand);
|
|
139
|
+
|
|
140
|
+
program
|
|
141
|
+
.command("unlink <folder>")
|
|
142
|
+
.description(
|
|
143
|
+
"Remove folder mapping"
|
|
144
|
+
)
|
|
145
|
+
.action(unlinkCommand);
|
|
146
|
+
|
|
147
|
+
program
|
|
148
|
+
.command("links")
|
|
149
|
+
.description(
|
|
150
|
+
"List folder mappings"
|
|
151
|
+
)
|
|
152
|
+
.action(linksCommand);
|
|
153
|
+
|
|
154
|
+
program
|
|
155
|
+
.command("auto")
|
|
156
|
+
.description(
|
|
157
|
+
"Auto switch profile"
|
|
158
|
+
)
|
|
159
|
+
.action(autoCommand);
|
|
160
|
+
|
|
127
161
|
program
|
|
128
162
|
.command("doctor")
|
|
129
163
|
.description(
|
package/src/services/profile.js
CHANGED
|
@@ -57,4 +57,39 @@ export function setCurrentProfile(
|
|
|
57
57
|
|
|
58
58
|
export function getCurrentProfile() {
|
|
59
59
|
return config.get("current", null);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function getFolderMappings() {
|
|
63
|
+
return config.get("folderMappings", []);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function addFolderMapping(
|
|
67
|
+
profile,
|
|
68
|
+
folderPath
|
|
69
|
+
) {
|
|
70
|
+
const mappings = getFolderMappings();
|
|
71
|
+
|
|
72
|
+
const exists = mappings.find((item) => item.path === folderPath);
|
|
73
|
+
|
|
74
|
+
if (exists) {
|
|
75
|
+
throw new Error("Folder already mapped");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
mappings.push({ profile, path: folderPath, });
|
|
79
|
+
|
|
80
|
+
config.set("folderMappings", mappings);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function removeFolderMapping(
|
|
84
|
+
folderPath
|
|
85
|
+
) {
|
|
86
|
+
const mappings = getFolderMappings();
|
|
87
|
+
|
|
88
|
+
config.set(
|
|
89
|
+
"folderMappings",
|
|
90
|
+
mappings.filter(
|
|
91
|
+
(item) =>
|
|
92
|
+
item.path !== folderPath
|
|
93
|
+
)
|
|
94
|
+
);
|
|
60
95
|
}
|