@yoonion/mimi-seed-mcp 0.15.2 → 0.15.3
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.
|
@@ -10,11 +10,39 @@ function storeBase(url) {
|
|
|
10
10
|
function credentialBase(url, id) {
|
|
11
11
|
return `${storeBase(url)}/credential/${encodeURIComponent(id)}`;
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* 기존 credential 의 Java class. 없으면 null, 있는데 메타데이터를 못 읽으면 빈 문자열.
|
|
15
|
+
*
|
|
16
|
+
* boolean(존재 여부)만으로는 부족하다 — id 가 같고 **종류가 다른** credential 을
|
|
17
|
+
* upsert 하면 기존 값이 통째로 사라진다. 예: Secret text 로 앱 키를 넣어둔 id 에
|
|
18
|
+
* Play SA 파일을 올리면 앱 키가 소멸한다. `_class` 는 Jenkins 가 주는 Java 클래스명이라
|
|
19
|
+
* 표시 이름(typeName)과 달리 로케일에 흔들리지 않는다.
|
|
20
|
+
*/
|
|
21
|
+
async function credentialClass(cfg, id) {
|
|
14
22
|
const res = await fetchWithTimeout(`${credentialBase(cfg.url, id)}/api/json`, {
|
|
15
23
|
headers: authHeaders(cfg),
|
|
16
24
|
});
|
|
17
|
-
|
|
25
|
+
if (!res.ok)
|
|
26
|
+
return null;
|
|
27
|
+
try {
|
|
28
|
+
return (await res.json())._class ?? '';
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return '';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** id 가 이미 **다른 종류**로 쓰이고 있으면 덮어쓰지 않고 멈춘다. */
|
|
35
|
+
function assertSameKind(id, existing, wanted, label) {
|
|
36
|
+
if (existing === null || existing === '' || existing === wanted)
|
|
37
|
+
return;
|
|
38
|
+
throw new Error([
|
|
39
|
+
`Jenkins credential "${id}" 가 이미 다른 종류로 존재합니다.`,
|
|
40
|
+
` 기존: ${existing}`,
|
|
41
|
+
` 요청: ${label}`,
|
|
42
|
+
'',
|
|
43
|
+
'덮어쓰면 기존 값이 사라집니다. 다른 id 를 쓰거나, 정말 교체하려면 먼저 삭제하세요.',
|
|
44
|
+
'jenkins_list_credentials 로 현재 목록을 확인할 수 있습니다.',
|
|
45
|
+
].join('\n'));
|
|
18
46
|
}
|
|
19
47
|
export async function listCredentials(cfg) {
|
|
20
48
|
const res = await fetchWithTimeout(`${storeBase(cfg.url)}/api/json?depth=1`, {
|
|
@@ -30,7 +58,9 @@ export async function listCredentials(cfg) {
|
|
|
30
58
|
}));
|
|
31
59
|
}
|
|
32
60
|
export async function upsertSecretText(cfg, id, secret, description = '') {
|
|
33
|
-
const
|
|
61
|
+
const existingClass = await credentialClass(cfg, id);
|
|
62
|
+
assertSameKind(id, existingClass, TEXT_CLASS, 'Secret text');
|
|
63
|
+
const exists = existingClass !== null;
|
|
34
64
|
const payload = {
|
|
35
65
|
credentials: {
|
|
36
66
|
scope: 'GLOBAL',
|
|
@@ -64,7 +94,9 @@ export async function upsertSecretText(cfg, id, secret, description = '') {
|
|
|
64
94
|
* json 본문이 "file": "<필드명>" 으로 참조한다 (secretBytes JSON 직접 입력은 불가).
|
|
65
95
|
*/
|
|
66
96
|
export async function upsertSecretFile(cfg, id, fileBase64, fileName, description = '') {
|
|
67
|
-
const
|
|
97
|
+
const existingClass = await credentialClass(cfg, id);
|
|
98
|
+
assertSameKind(id, existingClass, FILE_CLASS, 'Secret file');
|
|
99
|
+
const exists = existingClass !== null;
|
|
68
100
|
const payload = {
|
|
69
101
|
credentials: {
|
|
70
102
|
scope: 'GLOBAL',
|
|
@@ -90,7 +90,7 @@ export function registerAndroidTools(server) {
|
|
|
90
90
|
` 2. jenkins_create_credential(id="${prefix}-android-store-password", secret=...)`,
|
|
91
91
|
` 3. jenkins_create_credential(id="${prefix}-android-key-alias", secret=...)`,
|
|
92
92
|
` 4. jenkins_create_credential(id="${prefix}-android-key-password", secret=...)`,
|
|
93
|
-
` 5. jenkins_upload_playstore_sa(package_name="${package_name}", credential_id="${prefix}-
|
|
93
|
+
` 5. jenkins_upload_playstore_sa(package_name="${package_name}", credential_id="${prefix}-playstore-sa")`,
|
|
94
94
|
` └ SA JSON이 없으면 먼저: setup_playstore_connection(packageName="${package_name}", projectId="...")`,
|
|
95
95
|
].join('\n'),
|
|
96
96
|
}],
|
|
@@ -122,7 +122,7 @@ export function registerAndroidTools(server) {
|
|
|
122
122
|
? ` 6. setup_playstore_connection(packageName="${package_name}", projectId="${project_id}")`
|
|
123
123
|
: ` 6. setup_playstore_connection(packageName="${package_name}", projectId="<GCP 프로젝트 ID>")`,
|
|
124
124
|
' └ GCP 프로젝트 ID를 모르면 사용자에게 확인하세요.',
|
|
125
|
-
` 7. jenkins_upload_playstore_sa(package_name="${package_name}", credential_id="${prefix}-
|
|
125
|
+
` 7. jenkins_upload_playstore_sa(package_name="${package_name}", credential_id="${prefix}-playstore-sa")`,
|
|
126
126
|
' 8. Play Console에서 서비스 계정 초대 (수동, 1회)',
|
|
127
127
|
' → Play Console → 사용자 및 권한 → SA 이메일 → 릴리즈 관리자 권한 부여',
|
|
128
128
|
' 9. 첫 AAB 빌드 후 Play Console에 내부 테스트용으로 수동 업로드 (신규 앱 첫 번째만)',
|
|
@@ -203,9 +203,9 @@ export function registerAndroidTools(server) {
|
|
|
203
203
|
package_name: z.string().describe('Android 패키지명 (예: com.example.app)'),
|
|
204
204
|
// 기본값을 하드코딩 문자열에서 패키지명 파생으로 바꿨다 — 예전 기본값은 한 사설 앱
|
|
205
205
|
// 이름이었고, 여러 앱을 쓰는 사용자는 모든 SA 가 그 이름 하나로 덮였다.
|
|
206
|
-
credential_id: z.string().optional().describe('Jenkins Credential ID (생략 시 "<앱>-
|
|
206
|
+
credential_id: z.string().optional().describe('Jenkins Credential ID (생략 시 "<앱>-playstore-sa")'),
|
|
207
207
|
}, async ({ package_name, credential_id: credentialIdInput }) => {
|
|
208
|
-
const credential_id = credentialIdInput ?? `${credentialPrefix(package_name)}-
|
|
208
|
+
const credential_id = credentialIdInput ?? `${credentialPrefix(package_name)}-playstore-sa`;
|
|
209
209
|
const saPath = join(SA_DIR, `${package_name}.json`);
|
|
210
210
|
if (!existsSync(saPath)) {
|
|
211
211
|
return {
|
package/package.json
CHANGED