@dafish/gogo-meta 1.1.0 → 1.1.1
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/dist/cli.js +91 -0
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +36 -1
- package/dist/index.js +90 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import { dirname, join, basename } from 'path';
|
|
|
6
6
|
import { mkdir, appendFile, access, writeFile, readFile, unlink, symlink } from 'fs/promises';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import pc from 'picocolors';
|
|
9
|
+
import { homedir } from 'os';
|
|
9
10
|
|
|
10
11
|
var __defProp = Object.defineProperty;
|
|
11
12
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -635,6 +636,81 @@ function registerRunCommand(program) {
|
|
|
635
636
|
|
|
636
637
|
// src/commands/git/clone.ts
|
|
637
638
|
init_executor();
|
|
639
|
+
|
|
640
|
+
// src/core/ssh.ts
|
|
641
|
+
init_executor();
|
|
642
|
+
function extractSshHost(url) {
|
|
643
|
+
if (url.startsWith("https://") || url.startsWith("http://") || url.startsWith("file://")) {
|
|
644
|
+
return null;
|
|
645
|
+
}
|
|
646
|
+
const sshMatch = url.match(/^ssh:\/\/[^@]+@([^/:]+)/);
|
|
647
|
+
if (sshMatch) {
|
|
648
|
+
return sshMatch[1] ?? null;
|
|
649
|
+
}
|
|
650
|
+
const gitMatch = url.match(/^[^@]+@([^:]+):/);
|
|
651
|
+
if (gitMatch) {
|
|
652
|
+
return gitMatch[1] ?? null;
|
|
653
|
+
}
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
656
|
+
function extractUniqueSshHosts(urls) {
|
|
657
|
+
const hosts = /* @__PURE__ */ new Set();
|
|
658
|
+
for (const url of urls) {
|
|
659
|
+
const host = extractSshHost(url);
|
|
660
|
+
if (host) {
|
|
661
|
+
hosts.add(host);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
return Array.from(hosts);
|
|
665
|
+
}
|
|
666
|
+
async function isHostKnown(host) {
|
|
667
|
+
const knownHostsPath = join(homedir(), ".ssh", "known_hosts");
|
|
668
|
+
try {
|
|
669
|
+
const content = await readFile(knownHostsPath, "utf-8");
|
|
670
|
+
const hostPatterns = [
|
|
671
|
+
new RegExp(`^${escapeRegex(host)}[,\\s]`, "m"),
|
|
672
|
+
new RegExp(`^\\[${escapeRegex(host)}\\]:\\d+[,\\s]`, "m")
|
|
673
|
+
];
|
|
674
|
+
return hostPatterns.some((pattern) => pattern.test(content));
|
|
675
|
+
} catch {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
function escapeRegex(str) {
|
|
680
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
681
|
+
}
|
|
682
|
+
function addHostKey(host) {
|
|
683
|
+
const knownHostsPath = join(homedir(), ".ssh", "known_hosts");
|
|
684
|
+
const result = executeSync(`ssh-keyscan -H "${host}" >> "${knownHostsPath}" 2>/dev/null`, {
|
|
685
|
+
cwd: process.cwd()
|
|
686
|
+
});
|
|
687
|
+
return result.exitCode === 0;
|
|
688
|
+
}
|
|
689
|
+
async function ensureSshHostsKnown(urls) {
|
|
690
|
+
const hosts = extractUniqueSshHosts(urls);
|
|
691
|
+
const added = [];
|
|
692
|
+
const failed = [];
|
|
693
|
+
if (hosts.length === 0) {
|
|
694
|
+
return { added, failed };
|
|
695
|
+
}
|
|
696
|
+
for (const host of hosts) {
|
|
697
|
+
const known = await isHostKnown(host);
|
|
698
|
+
if (!known) {
|
|
699
|
+
info(`Adding SSH host key for ${host}...`);
|
|
700
|
+
const success2 = addHostKey(host);
|
|
701
|
+
if (success2) {
|
|
702
|
+
success(`Added host key for ${host}`);
|
|
703
|
+
added.push(host);
|
|
704
|
+
} else {
|
|
705
|
+
error(`Failed to add host key for ${host}`);
|
|
706
|
+
failed.push(host);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return { added, failed };
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// src/commands/git/clone.ts
|
|
638
714
|
function extractRepoName(url) {
|
|
639
715
|
const match = url.match(/\/([^/]+?)(\.git)?$/);
|
|
640
716
|
return match?.[1] ?? "repo";
|
|
@@ -646,6 +722,7 @@ async function cloneCommand(url, options = {}) {
|
|
|
646
722
|
if (await fileExists(targetDir)) {
|
|
647
723
|
throw new Error(`Directory "${repoName}" already exists`);
|
|
648
724
|
}
|
|
725
|
+
await ensureSshHostsKnown([url]);
|
|
649
726
|
info(`Cloning meta repository: ${url}`);
|
|
650
727
|
const cloneResult = await execute(`git clone "${url}" "${repoName}"`, { cwd });
|
|
651
728
|
if (cloneResult.exitCode !== 0) {
|
|
@@ -666,6 +743,13 @@ async function cloneCommand(url, options = {}) {
|
|
|
666
743
|
info("No child repositories defined in .gogo");
|
|
667
744
|
return;
|
|
668
745
|
}
|
|
746
|
+
const urls = projects.map(([, url2]) => url2);
|
|
747
|
+
const { failed: failedHosts } = await ensureSshHostsKnown(urls);
|
|
748
|
+
if (failedHosts.length > 0) {
|
|
749
|
+
warning(
|
|
750
|
+
`Could not verify SSH host keys for: ${failedHosts.join(", ")}. Clone may fail.`
|
|
751
|
+
);
|
|
752
|
+
}
|
|
669
753
|
info(`Cloning ${projects.length} child repositories...`);
|
|
670
754
|
let successCount = 0;
|
|
671
755
|
let failCount = 0;
|
|
@@ -725,6 +809,13 @@ async function updateCommand(options = {}) {
|
|
|
725
809
|
success("All repositories are already cloned");
|
|
726
810
|
return;
|
|
727
811
|
}
|
|
812
|
+
const urls = missing.map(([, url]) => url);
|
|
813
|
+
const { failed: failedHosts } = await ensureSshHostsKnown(urls);
|
|
814
|
+
if (failedHosts.length > 0) {
|
|
815
|
+
warning(
|
|
816
|
+
`Could not verify SSH host keys for: ${failedHosts.join(", ")}. Clone may fail.`
|
|
817
|
+
);
|
|
818
|
+
}
|
|
728
819
|
info(`Cloning ${missing.length} missing repositories...`);
|
|
729
820
|
let successCount = 0;
|
|
730
821
|
let failCount = 0;
|