@spfn/cli 0.0.2 → 0.0.4

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.
Files changed (2) hide show
  1. package/lib/login.js +115 -67
  2. package/package.json +1 -1
package/lib/login.js CHANGED
@@ -3,93 +3,134 @@ import open from "open";
3
3
  import fs from "fs";
4
4
  import os from "os";
5
5
  import path from "path";
6
+ import { execSync } from "child_process";
6
7
 
7
8
  const PORT = 5678;
8
9
 
9
- /**
10
- * templates 폴더에서 templateName 파일을 읽고,
11
- * {{KEY}} 플레이스홀더를 vars[KEY]로 치환하여 outputPath에 씁니다.
12
- */
13
- function applyTemplate(
14
- templateName,
15
- outputPath,
16
- vars
17
- ) {
18
- const src = path.join(process.cwd(), "templates", templateName);
19
- if (!fs.existsSync(src)) {
20
- throw new Error(`Template not found: ${src}`);
10
+ function installGitCredentials(username, token) {
11
+ // 1) credential helper 설정
12
+ if (process.platform === "win32") {
13
+ // Git Credential Manager (Windows)
14
+ execSync("git config --global credential.helper manager-core");
15
+ } else {
16
+ // 단순 파일 저장소
17
+ execSync("git config --global credential.helper store");
21
18
  }
22
- const template = fs.readFileSync(src, "utf-8");
23
- const result = template.replace(/\{\{(\w+)\}\}/g, (_, key) =>
24
- vars[key] ?? ""
25
- );
26
-
27
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
28
- fs.writeFileSync(outputPath, result, "utf-8");
29
- console.log(`✔️ Applied template ${templateName} → ${outputPath}`);
19
+
20
+ // 2) 승인 명령어로 크리덴셜 저장
21
+ // git credential approve 는 stdin으로 프로토콜/호스트/유저/패스워드를 받습니다.
22
+ const cred = [
23
+ "protocol=https",
24
+ "host=git.superfunctions.ai",
25
+ `username=${username}`,
26
+ `password=${token}`,
27
+ "" // 빈 줄로 끝내야 인풋 종료
28
+ ].join("\n");
29
+
30
+ execSync("git credential approve", {
31
+ input: cred,
32
+ stdio: ["pipe", "ignore", "inherit"]
33
+ });
34
+
35
+ console.log("✔️ Git credentials stored via credential helper");
36
+ }
37
+
38
+ function mergeGradleInit()
39
+ {
40
+ const dir = path.join(os.homedir(), ".gradle");
41
+ const file = path.join(dir, "init.gradle");
42
+ const startMarker = "// sf-cli start";
43
+ const endMarker = "// sf-cli end";
44
+
45
+ let content = "";
46
+ if (fs.existsSync(file))
47
+ {
48
+ content = fs.readFileSync(file, "utf-8");
49
+ const regex = new RegExp(
50
+ `${startMarker}[\\s\\S]*?${endMarker}\n?`,
51
+ "m"
52
+ );
53
+ content = content.replace(regex, "");
54
+ }
55
+
56
+ const block = [
57
+ startMarker,
58
+ "allprojects {",
59
+ " repositories {",
60
+ " maven {",
61
+ " name = 'Gitea'",
62
+ " url = uri('https://git.superfunctions.ai/api/packages/sf/maven')",
63
+ " credentials {",
64
+ " username = System.getenv('SF_USERNAME')",
65
+ " password = System.getenv('SF_AUTH_TOKEN')'",
66
+ " }",
67
+ " }",
68
+ " mavenCentral()",
69
+ " }",
70
+ "}",
71
+ endMarker,
72
+ ""
73
+ ].join("\n");
74
+
75
+ fs.mkdirSync(dir, { recursive: true });
76
+ fs.writeFileSync(file, content + "\n" + block, "utf-8");
77
+ console.log(`✔️ Merged Gradle init script: ${file}`);
30
78
  }
31
79
 
32
- export function login() {
33
- try {
34
- const server = http.createServer((req, res) => {
35
- // CORS headers
80
+ export function login()
81
+ {
82
+ try
83
+ {
84
+ const server = http.createServer((req, res) =>
85
+ {
36
86
  res.setHeader("Access-Control-Allow-Origin", "*");
37
87
  res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
38
88
  res.setHeader("Access-Control-Allow-Headers", "Content-Type");
39
89
 
40
- if (req.method === "OPTIONS") {
90
+ if (req.method === "OPTIONS")
91
+ {
41
92
  res.writeHead(200);
42
93
  res.end();
43
94
  return;
44
95
  }
45
96
 
46
- if (req.url === "/callback" && req.method === "POST") {
97
+ if (req.url === "/callback" && req.method === "POST")
98
+ {
47
99
  let body = "";
48
100
  req.on("data", (chunk) => (body += chunk));
49
- req.on("end", () => {
50
- try {
101
+ req.on("end", () =>
102
+ {
103
+ try
104
+ {
51
105
  const { username, token, projectSlug } = JSON.parse(body);
52
- if (!username || !token) {
106
+ if (!username || !token)
107
+ {
53
108
  res.writeHead(400).end("Missing username or token");
54
109
  return;
55
110
  }
56
111
 
57
- // 1) 템플릿 적용
58
- // 1-1) Gradle init
59
- const gradleDest = path.join(
60
- os.homedir(),
61
- ".gradle",
62
- "init.gradle"
63
- );
64
- applyTemplate("gradle.tmpl", gradleDest, {
65
- SF_USERNAME: username,
66
- SF_AUTH_TOKEN: token,
67
- });
68
-
69
- // 1-2) npmrc
70
- const npmDest = path.join(os.homedir(), ".npmrc");
71
- applyTemplate("npm.tmpl", npmDest, {
72
- SF_AUTH_TOKEN: token,
73
- });
74
- if (process.platform !== "win32") {
75
- try {
76
- fs.chmodSync(npmDest, 0o600);
77
- } catch {}
112
+ mergeGradleInit();
113
+ try
114
+ {
115
+ execSync(
116
+ `npm config set @sf:registry https://git.superfunctions.ai/api/packages/sf/npm/`,
117
+ { stdio: "inherit", env: process.env }
118
+ );
119
+ execSync(
120
+ `npm config set //git.superfunctions.ai/api/packages/sf/npm/:_authToken "${token}"`,
121
+ { stdio: "inherit", env: process.env }
122
+ );
123
+ console.log(
124
+ "✔️ npm registry and authToken set via npm config"
125
+ );
78
126
  }
79
-
80
- // 1-3) netrc (_netrc on Windows)
81
- const netrcName =
82
- process.platform === "win32" ? "_netrc" : ".netrc";
83
- const netrcDest = path.join(os.homedir(), netrcName);
84
- applyTemplate("netrc.tmpl", netrcDest, {
85
- SF_USERNAME: username,
86
- SF_AUTH_TOKEN: token,
87
- });
88
- if (process.platform !== "win32") {
89
- fs.chmodSync(netrcDest, 0o600);
127
+ catch (e)
128
+ {
129
+ console.error("❌ npm config set failed:", e);
90
130
  }
91
131
 
92
- // 3) 응답 & 팁
132
+ installGitCredentials(username, token);
133
+
93
134
  res.writeHead(200, { "Content-Type": "text/plain" });
94
135
  res.end("✅ Login successful! You can now close this window.");
95
136
 
@@ -104,22 +145,29 @@ export function login() {
104
145
  console.log();
105
146
 
106
147
  server.close();
107
- } catch (err) {
148
+ }
149
+ catch (err)
150
+ {
108
151
  console.error(err);
109
152
  res.writeHead(500).end("Error during login callback");
110
153
  server.close();
111
154
  }
112
155
  });
113
- } else {
156
+ }
157
+ else
158
+ {
114
159
  res.writeHead(404).end("Not Found");
115
160
  }
116
161
  });
117
162
 
118
- server.listen(PORT, () => {
163
+ server.listen(PORT, () =>
164
+ {
119
165
  console.log("🌐 Opening browser for login...");
120
166
  open(`https://console.superfunctions.ai/cli-login?port=${PORT}`);
121
167
  });
122
- } catch (err) {
168
+ }
169
+ catch (err)
170
+ {
123
171
  console.error(err);
124
172
  }
125
- }
173
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spfn/cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Superfunction CLI",
5
5
  "keywords": [
6
6
  "cli",