데스크탑 앱 추가수정
This commit is contained in:
@@ -15,3 +15,9 @@ BACKEND_PORT=8080
|
|||||||
|
|
||||||
# Frontend (외부 노출 포트)
|
# Frontend (외부 노출 포트)
|
||||||
FRONTEND_PORT=80
|
FRONTEND_PORT=80
|
||||||
|
|
||||||
|
# Desktop Jenkins (웹 UI 「앱 빌드」 — exdev 서버 .env에 설정)
|
||||||
|
# GC_DESKTOP_JENKINS_URL=http://host.docker.internal:8090
|
||||||
|
# GC_DESKTOP_JENKINS_USER=aidev
|
||||||
|
# GC_DESKTOP_JENKINS_TOKEN=jenkins-api-token-here
|
||||||
|
# GC_DESKTOP_JENKINS_TRIGGER_TOKEN=goldenchart-desktop-build
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.goldenchart.service;
|
package com.goldenchart.service;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.goldenchart.dto.DesktopAppBuildStatusDto;
|
import com.goldenchart.dto.DesktopAppBuildStatusDto;
|
||||||
import com.goldenchart.dto.DesktopAppBuildTriggerDto;
|
import com.goldenchart.dto.DesktopAppBuildTriggerDto;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -15,9 +16,16 @@ import org.springframework.web.reactive.function.client.WebClientResponseExcepti
|
|||||||
import org.springframework.web.server.ResponseStatusException;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
import org.springframework.web.util.UriUtils;
|
import org.springframework.web.util.UriUtils;
|
||||||
|
|
||||||
|
import java.net.CookieManager;
|
||||||
|
import java.net.CookiePolicy;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -29,6 +37,7 @@ public class DesktopAppBuildService {
|
|||||||
|
|
||||||
private final WebClient.Builder webClientBuilder;
|
private final WebClient.Builder webClientBuilder;
|
||||||
private final RolePermissionService rolePermissionService;
|
private final RolePermissionService rolePermissionService;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
@Value("${goldenchart.desktop-app.jenkins.enabled:true}")
|
@Value("${goldenchart.desktop-app.jenkins.enabled:true}")
|
||||||
private boolean jenkinsEnabled;
|
private boolean jenkinsEnabled;
|
||||||
@@ -195,23 +204,120 @@ public class DesktopAppBuildService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void triggerJenkinsBuild() {
|
private void triggerJenkinsBuild() {
|
||||||
|
if (hasBasicAuth()) {
|
||||||
|
try {
|
||||||
|
triggerJenkinsBuildWithSession();
|
||||||
|
return;
|
||||||
|
} catch (ResponseStatusException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[desktop-build] session trigger failed: {}", e.getMessage());
|
||||||
|
throw new ResponseStatusException(HttpStatus.BAD_GATEWAY,
|
||||||
|
"Jenkins 빌드 요청 실패: " + rootMessage(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
triggerJenkinsBuildWebClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Jenkins CSRF는 세션 쿠키 + crumb 조합이 필요 — java.net.http CookieManager 사용 */
|
||||||
|
private void triggerJenkinsBuildWithSession() throws Exception {
|
||||||
|
CookieManager cookieManager = new CookieManager(null, CookiePolicy.ACCEPT_ALL);
|
||||||
|
HttpClient httpClient = HttpClient.newBuilder()
|
||||||
|
.cookieHandler(cookieManager)
|
||||||
|
.connectTimeout(Duration.ofSeconds(15))
|
||||||
|
.build();
|
||||||
|
String base = normalizeBase(jenkinsUrl);
|
||||||
|
String auth = Base64.getEncoder().encodeToString(
|
||||||
|
(jenkinsUser.trim() + ":" + jenkinsToken.trim()).getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
String crumbField = "Jenkins-Crumb";
|
||||||
|
String crumbValue = null;
|
||||||
|
HttpRequest crumbReq = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(base + "/crumbIssuer/api/json"))
|
||||||
|
.header("Authorization", "Basic " + auth)
|
||||||
|
.header("Accept", MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.timeout(Duration.ofSeconds(10))
|
||||||
|
.GET()
|
||||||
|
.build();
|
||||||
|
HttpResponse<String> crumbResp = httpClient.send(crumbReq, HttpResponse.BodyHandlers.ofString());
|
||||||
|
if (crumbResp.statusCode() == 200 && StringUtils.hasText(crumbResp.body())) {
|
||||||
|
JsonNode node = objectMapper.readTree(crumbResp.body());
|
||||||
|
crumbField = node.path("crumbRequestField").asText("Jenkins-Crumb");
|
||||||
|
crumbValue = textOrNull(node.path("crumb"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int lastCode = 0;
|
||||||
|
for (String path : buildTriggerUrlCandidates()) {
|
||||||
|
HttpRequest.Builder req = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(base + path))
|
||||||
|
.header("Authorization", "Basic " + auth)
|
||||||
|
.header("Content-Type", MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||||
|
.timeout(Duration.ofSeconds(20))
|
||||||
|
.POST(HttpRequest.BodyPublishers.noBody());
|
||||||
|
if (StringUtils.hasText(crumbValue)) {
|
||||||
|
req.header(crumbField, crumbValue);
|
||||||
|
}
|
||||||
|
HttpResponse<Void> resp = httpClient.send(req.build(), HttpResponse.BodyHandlers.discarding());
|
||||||
|
lastCode = resp.statusCode();
|
||||||
|
if (lastCode >= 200 && lastCode < 400) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastCode == 401 || lastCode == 403) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.BAD_GATEWAY, jenkinsHttpErrorForCode(lastCode));
|
||||||
|
}
|
||||||
|
throw new ResponseStatusException(HttpStatus.BAD_GATEWAY, "Jenkins HTTP " + lastCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void triggerJenkinsBuildWebClient() {
|
||||||
WebClient client = jenkinsClient();
|
WebClient client = jenkinsClient();
|
||||||
String buildUrl = buildTriggerUrl();
|
WebClientResponseException lastAuthError = null;
|
||||||
|
|
||||||
|
for (String buildUrl : buildTriggerUrlCandidates()) {
|
||||||
Map<String, String> crumb = fetchCrumbOptional(client);
|
Map<String, String> crumb = fetchCrumbOptional(client);
|
||||||
try {
|
try {
|
||||||
postBuild(client, buildUrl, crumb);
|
postBuild(client, buildUrl, crumb);
|
||||||
|
return;
|
||||||
} catch (WebClientResponseException.Forbidden e) {
|
} catch (WebClientResponseException.Forbidden e) {
|
||||||
if (crumb != null) throw e;
|
lastAuthError = e;
|
||||||
|
if (crumb == null) {
|
||||||
|
try {
|
||||||
postBuild(client, buildUrl, fetchCrumb(client));
|
postBuild(client, buildUrl, fetchCrumb(client));
|
||||||
|
return;
|
||||||
|
} catch (WebClientResponseException.Forbidden e2) {
|
||||||
|
lastAuthError = e2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildTriggerUrl() {
|
if (lastAuthError != null) {
|
||||||
String url = jobApiPath() + "/build";
|
throw lastAuthError;
|
||||||
if (hasTriggerToken()) {
|
|
||||||
url += "?token=" + UriUtils.encodeQueryParam(jenkinsTriggerToken.trim(), StandardCharsets.UTF_8);
|
|
||||||
}
|
}
|
||||||
return url;
|
throw new ResponseStatusException(HttpStatus.BAD_GATEWAY, "Jenkins 빌드 트리거 URL을 구성할 수 없습니다.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 인증+토큰 조합을 순서대로 시도 (대부분의 Jenkins는 USER/TOKEN 없이 token만으로는 403). */
|
||||||
|
private List<String> buildTriggerUrlCandidates() {
|
||||||
|
String base = jobApiPath() + "/build";
|
||||||
|
String tokenQuery = hasTriggerToken()
|
||||||
|
? "?token=" + UriUtils.encodeQueryParam(jenkinsTriggerToken.trim(), StandardCharsets.UTF_8)
|
||||||
|
: "";
|
||||||
|
|
||||||
|
List<String> urls = new ArrayList<>();
|
||||||
|
if (hasBasicAuth() && hasTriggerToken()) {
|
||||||
|
urls.add(base + tokenQuery);
|
||||||
|
}
|
||||||
|
if (hasBasicAuth()) {
|
||||||
|
urls.add(base);
|
||||||
|
}
|
||||||
|
if (hasTriggerToken()) {
|
||||||
|
urls.add(base + tokenQuery);
|
||||||
|
}
|
||||||
|
if (urls.isEmpty()) {
|
||||||
|
urls.add(base);
|
||||||
|
}
|
||||||
|
return urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, String> fetchCrumbOptional(WebClient client) {
|
private Map<String, String> fetchCrumbOptional(WebClient client) {
|
||||||
@@ -293,15 +399,24 @@ public class DesktopAppBuildService {
|
|||||||
return t == null || t.isBlank() ? null : t;
|
return t == null || t.isBlank() ? null : t;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String jenkinsHttpError(WebClientResponseException e) {
|
private String jenkinsHttpError(WebClientResponseException e) {
|
||||||
int code = e.getStatusCode().value();
|
return jenkinsHttpErrorForCode(e.getStatusCode().value());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String jenkinsHttpErrorForCode(int code) {
|
||||||
if (code == 401 || code == 403) {
|
if (code == 401 || code == 403) {
|
||||||
return "Jenkins 인증 실패 — GC_DESKTOP_JENKINS_TRIGGER_TOKEN 또는 USER/TOKEN·Job 원격 트리거 토큰을 확인하세요.";
|
if (!hasBasicAuth()) {
|
||||||
|
return "Jenkins 인증 실패 — 서버 .env에 GC_DESKTOP_JENKINS_USER·GC_DESKTOP_JENKINS_TOKEN(Jenkins API Token)을 설정하고 "
|
||||||
|
+ "GC_DESKTOP_JENKINS_TRIGGER_TOKEN(기본 goldenchart-desktop-build)과 Job authToken이 일치하는지 확인하세요. "
|
||||||
|
+ "설정: ./scripts/configure-desktop-jenkins-backend.sh";
|
||||||
|
}
|
||||||
|
return "Jenkins 인증 실패 — GC_DESKTOP_JENKINS_USER/TOKEN·GC_DESKTOP_JENKINS_TRIGGER_TOKEN·Job authToken을 확인하세요. "
|
||||||
|
+ "Job 재등록: ./scripts/server-install-desktop-jenkins.sh";
|
||||||
}
|
}
|
||||||
if (code == 404) {
|
if (code == 404) {
|
||||||
return "Jenkins Job을 찾을 수 없습니다 — ./scripts/server-install-desktop-jenkins.sh 로 Job을 등록하세요.";
|
return "Jenkins Job을 찾을 수 없습니다 — ./scripts/server-install-desktop-jenkins.sh 로 Job을 등록하세요.";
|
||||||
}
|
}
|
||||||
return "Jenkins HTTP " + code + ": " + e.getStatusText();
|
return "Jenkins HTTP " + code;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String rootMessage(Throwable e) {
|
private static String rootMessage(Throwable e) {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ goldenchart:
|
|||||||
job: ${GC_DESKTOP_JENKINS_JOB:goldenChart-Desktop-Pipeline}
|
job: ${GC_DESKTOP_JENKINS_JOB:goldenChart-Desktop-Pipeline}
|
||||||
user: ${GC_DESKTOP_JENKINS_USER:}
|
user: ${GC_DESKTOP_JENKINS_USER:}
|
||||||
token: ${GC_DESKTOP_JENKINS_TOKEN:}
|
token: ${GC_DESKTOP_JENKINS_TOKEN:}
|
||||||
trigger-token: ${GC_DESKTOP_JENKINS_TRIGGER_TOKEN:}
|
trigger-token: ${GC_DESKTOP_JENKINS_TRIGGER_TOKEN:goldenchart-desktop-build}
|
||||||
cors:
|
cors:
|
||||||
allowed-origins:
|
allowed-origins:
|
||||||
- http://localhost:5173
|
- http://localhost:5173
|
||||||
|
|||||||
Executable
+75
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# exdev 서버 — backend Docker가 Jenkins 빌드를 트리거하도록 .env 설정
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
ENV_FILE="${ENV_FILE:-$REPO_ROOT/.env}"
|
||||||
|
|
||||||
|
JENKINS_URL="${GC_DESKTOP_JENKINS_URL:-http://127.0.0.1:8090}"
|
||||||
|
JENKINS_JOB="${GC_DESKTOP_JENKINS_JOB:-goldenChart-Desktop-Pipeline}"
|
||||||
|
JENKINS_TRIGGER_TOKEN="${GC_DESKTOP_JENKINS_TRIGGER_TOKEN:-goldenchart-desktop-build}"
|
||||||
|
|
||||||
|
log() { echo "[configure-jenkins] $*"; }
|
||||||
|
|
||||||
|
upsert_env() {
|
||||||
|
local key="$1" val="$2"
|
||||||
|
if [[ -f "$ENV_FILE" ]] && grep -q "^${key}=" "$ENV_FILE" 2>/dev/null; then
|
||||||
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
sed -i '' "s|^${key}=.*|${key}=${val}|" "$ENV_FILE"
|
||||||
|
else
|
||||||
|
sed -i "s|^${key}=.*|${key}=${val}|" "$ENV_FILE"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "${key}=${val}" >> "$ENV_FILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
log "GoldenChart backend → Jenkins 연동 설정"
|
||||||
|
log "env file: $ENV_FILE"
|
||||||
|
|
||||||
|
if [[ -z "${GC_DESKTOP_JENKINS_USER:-}" ]]; then
|
||||||
|
read -r -p "Jenkins 사용자명 (예: aidev): " GC_DESKTOP_JENKINS_USER
|
||||||
|
fi
|
||||||
|
if [[ -z "${GC_DESKTOP_JENKINS_TOKEN:-}" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "Jenkins API Token 생성:"
|
||||||
|
echo " 1) ${JENKINS_URL} → 로그인"
|
||||||
|
echo " 2) 사용자 이름 클릭 → Configure → API Token → Add new Token → Generate"
|
||||||
|
echo ""
|
||||||
|
read -r -s -p "생성한 API Token: " GC_DESKTOP_JENKINS_TOKEN
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$GC_DESKTOP_JENKINS_USER" || -z "$GC_DESKTOP_JENKINS_TOKEN" ]]; then
|
||||||
|
echo "ERROR: USER/TOKEN이 필요합니다." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$ENV_FILE")"
|
||||||
|
touch "$ENV_FILE"
|
||||||
|
|
||||||
|
upsert_env "GC_DESKTOP_JENKINS_ENABLED" "true"
|
||||||
|
upsert_env "GC_DESKTOP_JENKINS_URL" "http://host.docker.internal:8090"
|
||||||
|
upsert_env "GC_DESKTOP_JENKINS_JOB" "$JENKINS_JOB"
|
||||||
|
upsert_env "GC_DESKTOP_JENKINS_USER" "$GC_DESKTOP_JENKINS_USER"
|
||||||
|
upsert_env "GC_DESKTOP_JENKINS_TOKEN" "$GC_DESKTOP_JENKINS_TOKEN"
|
||||||
|
upsert_env "GC_DESKTOP_JENKINS_TRIGGER_TOKEN" "$JENKINS_TRIGGER_TOKEN"
|
||||||
|
|
||||||
|
log "Job authToken 동기화…"
|
||||||
|
GC_DESKTOP_JENKINS_TRIGGER_TOKEN="$JENKINS_TRIGGER_TOKEN" \
|
||||||
|
"$SCRIPT_DIR/server-install-desktop-jenkins.sh"
|
||||||
|
|
||||||
|
log "트리거 검증…"
|
||||||
|
export GC_DESKTOP_JENKINS_URL="$JENKINS_URL"
|
||||||
|
export GC_DESKTOP_JENKINS_USER GC_DESKTOP_JENKINS_TOKEN GC_DESKTOP_JENKINS_TRIGGER_TOKEN
|
||||||
|
DRY_RUN=1 "$SCRIPT_DIR/verify-desktop-jenkins-trigger.sh"
|
||||||
|
|
||||||
|
if command -v docker >/dev/null 2>&1 && [[ -f "$REPO_ROOT/docker-compose.yml" ]]; then
|
||||||
|
log "backend 컨테이너 재시작…"
|
||||||
|
(cd "$REPO_ROOT" && docker compose up -d backend)
|
||||||
|
sleep 3
|
||||||
|
log "완료. 웹 UI에서 「앱 빌드」를 다시 시도하세요."
|
||||||
|
else
|
||||||
|
log "완료. docker compose up -d backend 로 backend를 재시작하세요."
|
||||||
|
fi
|
||||||
@@ -83,6 +83,13 @@ log "완료: http://127.0.0.1:8090/job/${JENKINS_JOB}/"
|
|||||||
log "원격 트리거 토큰: $JENKINS_TRIGGER_TOKEN"
|
log "원격 트리거 토큰: $JENKINS_TRIGGER_TOKEN"
|
||||||
log "backend env: GC_DESKTOP_JENKINS_TRIGGER_TOKEN=$JENKINS_TRIGGER_TOKEN"
|
log "backend env: GC_DESKTOP_JENKINS_TRIGGER_TOKEN=$JENKINS_TRIGGER_TOKEN"
|
||||||
log ""
|
log ""
|
||||||
|
log "Jenkins JVM (file:// bare checkout 허용, launchd plist 또는 nohup java -D):"
|
||||||
|
log " -Dhudson.plugins.git.GitSCM.ALLOW_LOCAL_CHECKOUT=true"
|
||||||
|
log ""
|
||||||
|
log "웹 UI 「앱 빌드」를 쓰려면 Jenkins API Token 필수:"
|
||||||
|
log " ./scripts/configure-desktop-jenkins-backend.sh"
|
||||||
|
log " (또는 .env에 GC_DESKTOP_JENKINS_USER / GC_DESKTOP_JENKINS_TOKEN 설정 후 docker compose up -d backend)"
|
||||||
|
log ""
|
||||||
log "Jenkins Credentials (Secret file):"
|
log "Jenkins Credentials (Secret file):"
|
||||||
log " ID: tauri-signer-key → \$HOME/.tauri/goldenchart.key"
|
log " ID: tauri-signer-key → \$HOME/.tauri/goldenchart.key"
|
||||||
log ""
|
log ""
|
||||||
|
|||||||
Executable
+88
@@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Jenkins desktop 빌드 트리거 연결·인증 검증 (exdev 서버에서 실행)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:${PATH:-/usr/bin:/bin}"
|
||||||
|
|
||||||
|
JENKINS_URL="${GC_DESKTOP_JENKINS_URL:-http://127.0.0.1:8090}"
|
||||||
|
JENKINS_JOB="${GC_DESKTOP_JENKINS_JOB:-goldenChart-Desktop-Pipeline}"
|
||||||
|
JENKINS_USER="${GC_DESKTOP_JENKINS_USER:-}"
|
||||||
|
JENKINS_TOKEN="${GC_DESKTOP_JENKINS_TOKEN:-}"
|
||||||
|
JENKINS_TRIGGER_TOKEN="${GC_DESKTOP_JENKINS_TRIGGER_TOKEN:-goldenchart-desktop-build}"
|
||||||
|
DOCKER_JENKINS_URL="${DOCKER_JENKINS_URL:-http://host.docker.internal:8090}"
|
||||||
|
DRY_RUN="${DRY_RUN:-1}"
|
||||||
|
|
||||||
|
JENKINS_URL="${JENKINS_URL%/}"
|
||||||
|
JOB_API="${JENKINS_URL}/job/${JENKINS_JOB// /%20}"
|
||||||
|
|
||||||
|
log() { echo "[verify-jenkins] $*"; }
|
||||||
|
fail() { log "FAIL: $*"; exit 1; }
|
||||||
|
|
||||||
|
curl_get() {
|
||||||
|
if [[ -n "$JENKINS_USER" && -n "$JENKINS_TOKEN" ]]; then
|
||||||
|
curl -sS -u "${JENKINS_USER}:${JENKINS_TOKEN}" "$@"
|
||||||
|
else
|
||||||
|
curl -sS "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_post() {
|
||||||
|
local extra=()
|
||||||
|
if [[ -n "$JENKINS_USER" && -n "$JENKINS_TOKEN" ]]; then
|
||||||
|
extra=(-u "${JENKINS_USER}:${JENKINS_TOKEN}")
|
||||||
|
fi
|
||||||
|
curl -sS -o /tmp/gc-jenkins-trigger-body.txt -w "%{http_code}" "${extra[@]}" -X POST \
|
||||||
|
-H "Content-Type: application/x-www-form-urlencoded" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
log "Jenkins URL (host): $JENKINS_URL"
|
||||||
|
log "Job: $JENKINS_JOB"
|
||||||
|
log "Trigger token: $JENKINS_TRIGGER_TOKEN"
|
||||||
|
log "API user: ${JENKINS_USER:-<not set>}"
|
||||||
|
log "DRY_RUN=$DRY_RUN (실제 빌드 트리거 없음, HTTP 코드만 확인)"
|
||||||
|
|
||||||
|
if ! curl -sf -o /dev/null "${JENKINS_URL}/login"; then
|
||||||
|
fail "Jenkins에 연결할 수 없습니다 ($JENKINS_URL). Jenkins가 8090에서 실행 중인지 확인하세요."
|
||||||
|
fi
|
||||||
|
log "OK: Jenkins login page reachable"
|
||||||
|
|
||||||
|
if [[ -z "$JENKINS_USER" || -z "$JENKINS_TOKEN" ]]; then
|
||||||
|
log "WARN: GC_DESKTOP_JENKINS_USER/TOKEN 미설정 — 웹 UI 빌드 트리거는 대부분 403으로 실패합니다."
|
||||||
|
log " Jenkins → 사용자 → Configure → API Token 생성 후:"
|
||||||
|
log " ./scripts/configure-desktop-jenkins-backend.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$DRY_RUN" == "1" ]]; then
|
||||||
|
job_code="$(curl_get -o /tmp/gc-jenkins-job.json -w "%{http_code}" "${JOB_API}/api/json?tree=name" || true)"
|
||||||
|
log "GET job api → HTTP $job_code"
|
||||||
|
if [[ "$job_code" == "404" ]]; then
|
||||||
|
fail "Job 없음 (HTTP 404). ./scripts/server-install-desktop-jenkins.sh 실행."
|
||||||
|
fi
|
||||||
|
if [[ "$job_code" == "401" || "$job_code" == "403" ]]; then
|
||||||
|
fail "Jenkins API 인증 실패 (HTTP $job_code). GC_DESKTOP_JENKINS_USER/TOKEN 확인."
|
||||||
|
fi
|
||||||
|
if [[ ! "$job_code" =~ ^2 ]]; then
|
||||||
|
fail "Job API 오류 (HTTP $job_code)"
|
||||||
|
fi
|
||||||
|
log "OK: Job API 접근 가능 (빌드 트리거는 DRY_RUN으로 생략)"
|
||||||
|
else
|
||||||
|
log "실제 빌드 트리거 — ./scripts/trigger-desktop-jenkins-build.sh 호출"
|
||||||
|
GC_DESKTOP_JENKINS_URL="$JENKINS_URL" \
|
||||||
|
GC_DESKTOP_JENKINS_USER="$JENKINS_USER" \
|
||||||
|
GC_DESKTOP_JENKINS_TOKEN="$JENKINS_TOKEN" \
|
||||||
|
GC_DESKTOP_JENKINS_TRIGGER_TOKEN="$JENKINS_TRIGGER_TOKEN" \
|
||||||
|
"$(cd "$(dirname "$0")" && pwd)/trigger-desktop-jenkins-build.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v docker >/dev/null 2>&1 && docker ps --format '{{.Names}}' 2>/dev/null | grep -qx 'gc-backend'; then
|
||||||
|
log "Docker backend → host Jenkins 연결 테스트 ($DOCKER_JENKINS_URL)"
|
||||||
|
if docker exec gc-backend wget -qO- --timeout=5 "${DOCKER_JENKINS_URL}/login" >/dev/null 2>&1; then
|
||||||
|
log "OK: gc-backend 컨테이너에서 host Jenkins 접근 가능"
|
||||||
|
else
|
||||||
|
fail "gc-backend에서 $DOCKER_JENKINS_URL 접근 불가. docker-compose extra_hosts·GC_DESKTOP_JENKINS_URL 확인 후 docker compose up -d backend"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "SKIP: gc-backend 컨테이너 없음 — Docker 연결 테스트 생략"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "검증 완료"
|
||||||
Reference in New Issue
Block a user