@spfn/cli 0.0.7 → 0.0.9
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/lib/index.js +1 -1
- package/lib/login.js +86 -75
- package/package.json +7 -5
package/lib/index.js
CHANGED
package/lib/login.js
CHANGED
@@ -5,7 +5,9 @@ import os from "os";
|
|
5
5
|
import path from "path";
|
6
6
|
import { execSync } from "child_process";
|
7
7
|
|
8
|
-
const
|
8
|
+
const isDev = process.env.NODE_ENV === "development" || process.env.SF_ENV === "local";
|
9
|
+
const GIT_HOST = isDev ? "gitea:13000" : "git.superfunctions.ai";
|
10
|
+
const GIT_PROTOCOL = isDev ? "http" : "https";
|
9
11
|
|
10
12
|
/**
|
11
13
|
* Git credential helper를 이용해 특정 레포에 대한 인증 정보를 저장합니다.
|
@@ -16,10 +18,14 @@ const PORT = 5678;
|
|
16
18
|
function installGitCredentials(
|
17
19
|
username,
|
18
20
|
token,
|
19
|
-
|
21
|
+
{
|
22
|
+
protocol = "https",
|
23
|
+
host,
|
24
|
+
path // optional
|
25
|
+
}
|
20
26
|
)
|
21
27
|
{
|
22
|
-
// credential helper 설정
|
28
|
+
// credential helper 설정 (글로벌, 1회면 충분)
|
23
29
|
if (process.platform === "win32")
|
24
30
|
{
|
25
31
|
execSync("git config --global credential.helper manager-core");
|
@@ -31,73 +37,64 @@ function installGitCredentials(
|
|
31
37
|
|
32
38
|
// git credential approve 입력 생성
|
33
39
|
const cred = [
|
34
|
-
|
35
|
-
|
36
|
-
`path=${
|
40
|
+
`protocol=${protocol}`,
|
41
|
+
`host=${host}`,
|
42
|
+
path ? `path=${path}` : null,
|
37
43
|
`username=${username}`,
|
38
44
|
`password=${token}`,
|
39
45
|
""
|
40
|
-
].join("\n");
|
46
|
+
].filter(Boolean).join("\n");
|
41
47
|
|
42
48
|
execSync("git credential approve", {
|
43
49
|
input: cred,
|
44
50
|
stdio: ["pipe", "ignore", "inherit"]
|
45
51
|
});
|
46
52
|
|
47
|
-
|
53
|
+
if (path)
|
54
|
+
{
|
55
|
+
console.log(`✔️ Stored credentials for ${protocol}://${host}/${path}`);
|
56
|
+
}
|
57
|
+
else
|
58
|
+
{
|
59
|
+
console.log(`✔️ Stored credentials for ${protocol}://${host}`);
|
60
|
+
}
|
48
61
|
}
|
49
62
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
// Windows 환경변수 등록(기존 값이 있으면 덮어쓰기)
|
59
|
-
execSync(`setx SF_USERNAME "${username}"`);
|
60
|
-
execSync(`setx SF_ACCESS_TOKEN "${token}"`);
|
61
|
-
console.log("✔️ Windows 환경변수에 SF_USERNAME, SF_ACCESS_TOKEN 등록/갱신 완료");
|
62
|
-
} else {
|
63
|
-
// macOS/Linux: 사용자 쉘 RC 파일 선택
|
64
|
-
const shell = process.env.SHELL || "";
|
65
|
-
const rcFile = shell.includes("zsh") ? ".zshrc" : ".bash_profile";
|
66
|
-
const rcPath = path.join(os.homedir(), rcFile);
|
67
|
-
|
68
|
-
// RC 파일 내용을 읽어서 기존 export 라인 제거
|
69
|
-
const existing = fs.existsSync(rcPath)
|
70
|
-
? fs.readFileSync(rcPath, "utf8").split(/\r?\n/)
|
71
|
-
: [];
|
72
|
-
|
73
|
-
const filtered = existing.filter(
|
74
|
-
(line) =>
|
75
|
-
!/^export\s+SF_USERNAME=/.test(line) &&
|
76
|
-
!/^export\s+SF_ACCESS_TOKEN=/.test(line) &&
|
77
|
-
!/^# Superfunctions CLI 로그인/.test(line)
|
78
|
-
);
|
79
|
-
|
80
|
-
// 새 export 라인 추가
|
81
|
-
const exportBlock = [
|
82
|
-
"",
|
83
|
-
"# Superfunctions CLI 로그인",
|
84
|
-
`export SF_USERNAME="${username}"`,
|
85
|
-
`export SF_ACCESS_TOKEN="${token}"`,
|
86
|
-
""
|
87
|
-
];
|
88
|
-
|
89
|
-
const updated = filtered.concat(exportBlock);
|
90
|
-
fs.writeFileSync(rcPath, updated.join(os.EOL), { encoding: "utf8" });
|
91
|
-
|
92
|
-
console.log(`✔️ ${rcFile}에 SF_USERNAME, SF_ACCESS_TOKEN export 추가/갱신 완료`);
|
93
|
-
console.log(` 적용하려면: source ~/${rcFile} 또는 터미널 재시작`);
|
94
|
-
}
|
95
|
-
} catch (e) {
|
96
|
-
console.error("❌ 전역 환경변수 등록/갱신 실패:", e);
|
63
|
+
function persistGradleCredentials(SF_CI_BOT_USER, SF_CI_BOT_TOKEN)
|
64
|
+
{
|
65
|
+
const gradlePropsPath = path.join(os.homedir(), ".gradle", "gradle.properties");
|
66
|
+
|
67
|
+
// 기존 내용 읽기
|
68
|
+
let lines = [];
|
69
|
+
if (fs.existsSync(gradlePropsPath)) {
|
70
|
+
lines = fs.readFileSync(gradlePropsPath, "utf8").split(/\r?\n/);
|
97
71
|
}
|
72
|
+
|
73
|
+
// 기존 SF_CI_BOT_USER, SF_CI_BOT_TOKEN 라인 삭제
|
74
|
+
const filtered = lines.filter(line =>
|
75
|
+
!line.startsWith("SF_CI_BOT_USER=") &&
|
76
|
+
!line.startsWith("SF_CI_BOT_TOKEN=") &&
|
77
|
+
!line.startsWith("# Superfunctions CLI")
|
78
|
+
);
|
79
|
+
|
80
|
+
// 새 라인 추가
|
81
|
+
const exportBlock = [
|
82
|
+
"",
|
83
|
+
"# Superfunctions CLI - Gitea Maven Auth",
|
84
|
+
`SF_CI_BOT_USER=${SF_CI_BOT_USER}`,
|
85
|
+
`SF_CI_BOT_TOKEN=${SF_CI_BOT_TOKEN}`,
|
86
|
+
""
|
87
|
+
];
|
88
|
+
|
89
|
+
const updated = filtered.concat(exportBlock);
|
90
|
+
fs.mkdirSync(path.dirname(gradlePropsPath), { recursive: true });
|
91
|
+
fs.writeFileSync(gradlePropsPath, updated.join(os.EOL), { encoding: "utf8" });
|
92
|
+
|
93
|
+
console.log(`✔️ ~/.gradle/gradle.properties에 SF_CI_BOT_USER, SF_CI_BOT_TOKEN 등록/갱신 완료`);
|
94
|
+
console.log(` 모든 Gradle 프로젝트에서 Superfunction Maven 인증 자동 적용`);
|
98
95
|
}
|
99
96
|
|
100
|
-
export function login()
|
97
|
+
export async function login()
|
101
98
|
{
|
102
99
|
try
|
103
100
|
{
|
@@ -122,24 +119,24 @@ export function login()
|
|
122
119
|
{
|
123
120
|
try
|
124
121
|
{
|
125
|
-
const { username, token
|
122
|
+
const { username, token } = JSON.parse(body);
|
126
123
|
if (!username || !token)
|
127
124
|
{
|
128
125
|
res.writeHead(400).end("Missing username or token");
|
129
126
|
return;
|
130
127
|
}
|
131
128
|
|
132
|
-
|
129
|
+
persistGradleCredentials(username, token);
|
133
130
|
|
134
131
|
// npm registry 설정 (생략)
|
135
132
|
try
|
136
133
|
{
|
137
134
|
execSync(
|
138
|
-
`npm config set @
|
135
|
+
`npm config set @spfn:registry ${GIT_PROTOCOL}://${GIT_HOST}/api/packages/spfn/npm/`,
|
139
136
|
{ stdio: "inherit", env: process.env }
|
140
137
|
);
|
141
138
|
execSync(
|
142
|
-
`npm config set
|
139
|
+
`npm config set //${GIT_HOST}/api/packages/spfn/npm/:_authToken \"${token}\"`,
|
143
140
|
{ stdio: "inherit", env: process.env }
|
144
141
|
);
|
145
142
|
console.log("✔️ npm registry and authToken set via npm config");
|
@@ -150,22 +147,14 @@ export function login()
|
|
150
147
|
}
|
151
148
|
|
152
149
|
// 2개 레포에 대해 각각 자격증명 저장
|
153
|
-
installGitCredentials(username, token,
|
154
|
-
|
150
|
+
installGitCredentials(username, token, {
|
151
|
+
protocol: GIT_PROTOCOL,
|
152
|
+
host: GIT_HOST
|
153
|
+
});
|
155
154
|
|
156
155
|
res.writeHead(200, { "Content-Type": "text/plain" });
|
157
156
|
res.end("✅ Login successful! You can now close this window.");
|
158
157
|
|
159
|
-
console.log();
|
160
|
-
console.log("💡 Tips:");
|
161
|
-
console.log(
|
162
|
-
` git clone https://git.superfunctions.ai/${projectSlug}/${projectSlug}-server`
|
163
|
-
);
|
164
|
-
console.log(
|
165
|
-
` git clone https://git.superfunctions.ai/${projectSlug}/${projectSlug}-app`
|
166
|
-
);
|
167
|
-
console.log();
|
168
|
-
|
169
158
|
server.close();
|
170
159
|
}
|
171
160
|
catch (err)
|
@@ -182,14 +171,36 @@ export function login()
|
|
182
171
|
}
|
183
172
|
});
|
184
173
|
|
185
|
-
|
174
|
+
const port = await getAvailablePort();
|
175
|
+
|
176
|
+
// 로그인 UI 주소도 분기
|
177
|
+
const isDev = process.env.NODE_ENV === "development" || process.env.SF_ENV === "local";
|
178
|
+
const LOGIN_UI_URL = isDev
|
179
|
+
? `http://localhost:3000/cli-login?port=${port}`
|
180
|
+
: `https://console.superfunctions.ai/cli-login?port=${port}`;
|
181
|
+
|
182
|
+
server.listen(port, () =>
|
186
183
|
{
|
187
184
|
console.log("🌐 Opening browser for login...");
|
188
|
-
open(
|
185
|
+
open(LOGIN_UI_URL);
|
189
186
|
});
|
190
187
|
}
|
191
188
|
catch (err)
|
192
189
|
{
|
193
190
|
console.error(err);
|
194
191
|
}
|
195
|
-
}
|
192
|
+
}
|
193
|
+
|
194
|
+
function getAvailablePort(defaultPort = 5678) {
|
195
|
+
return new Promise((resolve) => {
|
196
|
+
const srv = http.createServer();
|
197
|
+
srv.listen(defaultPort, () => {
|
198
|
+
srv.close(() => resolve(defaultPort));
|
199
|
+
});
|
200
|
+
srv.on("error", () => {
|
201
|
+
// 사용 중이면 10000~20000 사이 랜덤 포트
|
202
|
+
const randomPort = Math.floor(Math.random() * 10000) + 10000;
|
203
|
+
resolve(randomPort);
|
204
|
+
});
|
205
|
+
});
|
206
|
+
}
|
package/package.json
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"name": "@spfn/cli",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.9",
|
4
4
|
"description": "Superfunction CLI",
|
5
|
+
"scripts": {
|
6
|
+
"start": "node lib/index.js",
|
7
|
+
"start:dev": "NODE_ENV=development node lib/index.js",
|
8
|
+
"start:prod": "NODE_ENV=production node lib/index.js"
|
9
|
+
},
|
5
10
|
"keywords": [
|
6
11
|
"cli",
|
7
12
|
"superfunction",
|
@@ -12,7 +17,7 @@
|
|
12
17
|
"homepage": "https://console.superfunctions.ai",
|
13
18
|
"repository": {
|
14
19
|
"type": "git",
|
15
|
-
"url": "https://git.superfunctions.ai/
|
20
|
+
"url": "https://git.superfunctions.ai/spfn/sf-cli.git"
|
16
21
|
},
|
17
22
|
"license": "MIT",
|
18
23
|
"author": "Superfunction Ray <rayim@superfunctions.ai>",
|
@@ -27,9 +32,6 @@
|
|
27
32
|
"files": [
|
28
33
|
"lib/**/*"
|
29
34
|
],
|
30
|
-
"scripts": {
|
31
|
-
"start": "node lib/index.js"
|
32
|
-
},
|
33
35
|
"dependencies": {
|
34
36
|
"commander": "^13.1.0",
|
35
37
|
"open": "^10.1.1"
|