From c57909ae670b5d5e9d7e97c03aca8bce36dacf0c Mon Sep 17 00:00:00 2001 From: Lectom C Han Date: Mon, 15 Dec 2025 18:04:38 +0900 Subject: [PATCH] =?UTF-8?q?Codex=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/mirror.yml | 84 ++++++++++++++++++++++++++++++------- AGENTS.md | 28 +++++++++++++ to-do.md | 15 ++++--- 3 files changed, 105 insertions(+), 22 deletions(-) create mode 100644 AGENTS.md diff --git a/.gitea/workflows/mirror.yml b/.gitea/workflows/mirror.yml index 1503cc0..7eca5b8 100644 --- a/.gitea/workflows/mirror.yml +++ b/.gitea/workflows/mirror.yml @@ -34,13 +34,32 @@ jobs: BASE_GITEA_USER: ${{ vars.BASE_GITEA_USER }} # The user who owns the token INPUT_BRANCHES: ${{ github.event.inputs.branches }} run: | - set -e # Exit immediately if a command exits with a non-zero status. + set -euo pipefail - # Gitea API Header + CENTER_ORG="center_dev" AUTH_HEADER="Authorization: token ${BASE_GITEA_TOKEN}" + set_default_branch_main() { + local repo_name="$1" + local response http_status body + response=$(curl -s -w "\n%{http_code}" -X PATCH -H "Content-Type: application/json" -H "${AUTH_HEADER}" -d "{\"default_branch\":\"main\"}" "${BASE_GITEA_URL}/api/v1/repos/${CENTER_ORG}/${repo_name}") + http_status=$(echo "${response}" | tail -n1) + body=$(echo "${response}" | sed '$d') + + if [[ "${http_status}" != "200" ]]; then + echo "::warning::Failed to set default branch to 'main' for ${CENTER_ORG}/${repo_name} (status ${http_status})" + if [[ -n "${body}" ]]; then + echo "${body}" + fi + else + echo "Default branch set to 'main' for ${CENTER_ORG}/${repo_name}" + fi + } + process_branch() { - local branch_name=$1 + local branch_name + branch_name="$(echo "$1" | xargs)" # trim whitespace + if [[ -z "$branch_name" ]]; then return fi @@ -51,18 +70,21 @@ jobs: repo_name="" if [ "${branch_name}" == "Develop_Net8" ]; then repo_name="base" + elif [[ "${branch_name}" == Develop_Net8_* ]]; then + repo_name="${branch_name#Develop_Net8_}" else - repo_name=$(echo "${branch_name}" | sed 's/^Develop_Net8_//') + repo_name="${branch_name}" fi - + echo "Target repository name: ${repo_name}" # Check if repository exists on Gitea - http_status=$(curl -s -o /dev/null -w "%{http_code}" -H "${AUTH_HEADER}" "${BASE_GITEA_URL}/api/v1/repos/center_dev/${repo_name}") + repo_exists=false + http_status=$(curl -s -o /dev/null -w "%{http_code}" -H "${AUTH_HEADER}" "${BASE_GITEA_URL}/api/v1/repos/${CENTER_ORG}/${repo_name}") if [ "${http_status}" == "404" ]; then echo "Repository 'center_dev/${repo_name}' does not exist. Creating it..." - create_repo_response=$(curl -s -w "%{http_code}" -X POST -H "Content-Type: application/json" -H "${AUTH_HEADER}" -d "{\"name\":\"${repo_name}\",\"private\":true}" "${BASE_GITEA_URL}/api/v1/orgs/center_dev/repos") + create_repo_response=$(curl -s -w "%{http_code}" -X POST -H "Content-Type: application/json" -H "${AUTH_HEADER}" -d "{\"name\":\"${repo_name}\",\"private\":true,\"default_branch\":\"main\"}" "${BASE_GITEA_URL}/api/v1/orgs/${CENTER_ORG}/repos") create_status=$(echo "${create_repo_response}" | tail -c 3) if [[ "${create_status}" -ne "201" ]]; then echo "::error::Failed to create repository. API response:" @@ -75,30 +97,60 @@ jobs: exit 1 else echo "Repository 'center_dev/${repo_name}' already exists." + repo_exists=true fi # Define remote URL's hostname, stripping protocol - GITEA_HOSTNAME=$(echo "${BASE_GITEA_URL}" | sed -e 's,^\(https*://\)\\,\\",g') - GITEA_REMOTE="https://${BASE_GITEA_USER}:${BASE_GITEA_TOKEN}@${GITEA_HOSTNAME}/center_dev/${repo_name}.git" + GITEA_HOSTNAME=$(echo "${BASE_GITEA_URL}" | sed -e 's~^https*://~~' -e 's~/$~~') + GITEA_REMOTE="https://${BASE_GITEA_USER}:${BASE_GITEA_TOKEN}@${GITEA_HOSTNAME}/${CENTER_ORG}/${repo_name}.git" SOURCE_REPO="ssh://engdev@172.16.42.118/dev_Net8.git" # Create a temporary directory for cloning CLONE_DIR=$(mktemp -d) - echo "Cloning source into ${CLONE_DIR}..." + echo "Working directory: ${CLONE_DIR}" - git clone --bare "${SOURCE_REPO}" "${CLONE_DIR}" - - cd "${CLONE_DIR}" + if ${repo_exists}; then + echo "Cloning existing target repository for update..." + if ! git clone --mirror "${GITEA_REMOTE}" "${CLONE_DIR}"; then + echo "::error::Failed to clone existing target repository ${GITEA_REMOTE}" + rm -rf "${CLONE_DIR}" + return + fi + cd "${CLONE_DIR}" + git remote add source "${SOURCE_REPO}" + echo "Fetching latest branch '${branch_name}' from source..." + if ! git fetch source "+refs/heads/${branch_name}:refs/heads/${branch_name}"; then + echo "::error::Failed to fetch branch '${branch_name}' from source repo" + cd .. + rm -rf "${CLONE_DIR}" + return + fi + else + echo "Cloning source repository for first-time push..." + if ! git clone --mirror "${SOURCE_REPO}" "${CLONE_DIR}"; then + echo "::error::Failed to clone source repository ${SOURCE_REPO}" + rm -rf "${CLONE_DIR}" + return + fi + cd "${CLONE_DIR}" + fi + + git remote set-url origin "${GITEA_REMOTE}" echo "Pushing '${branch_name}' to Gitea repository '${repo_name}'..." - # Push the specific branch to the main branch of the target repository - git push --force "${GITEA_REMOTE}" "refs/heads/${branch_name}:refs/heads/main" + if ! git push --force origin "refs/heads/${branch_name}:refs/heads/main"; then + echo "::error::Failed to push branch '${branch_name}' to target repository" + cd .. + rm -rf "${CLONE_DIR}" + return + fi # Cleanup cd .. rm -rf "${CLONE_DIR}" echo "Successfully mirrored ${branch_name} to center_dev/${repo_name}" + set_default_branch_main "${repo_name}" echo "=================================================" echo "" } @@ -117,4 +169,4 @@ jobs: while IFS= read -r branch_name || [[ -n "$branch_name" ]]; do process_branch "${branch_name}" done < branch_list - fi \ No newline at end of file + fi diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..ec32a27 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,28 @@ +# AGENTS + +## 목적 +- 외부 SSH Git 저장소(`engdev@172.16.42.118:dev_Net8.git`)의 특정 브랜치를 Gitea `center_dev` 조직으로 순차 미러링하는 워크플로우를 관리합니다. +- 데이터가 크므로 병렬 대신 순차 처리하며, 브랜치별로 대응되는 Gitea 저장소에 강제 푸시합니다. + +## 주요 흐름 (mirror.yml 설계 요약) +- 트리거: cron `0 2 * * *` 및 `workflow_dispatch`. +- 기본 데이터 소스: `branch_list` 파일을 한 줄씩 읽어 순차 처리. +- 브랜치→저장소 매핑 규칙: `Develop_Net8` → `base`, `Develop_Net8_*` → `*` 부분을 저장소 이름으로 사용하며, 그 외 브랜치는 브랜치명을 그대로 저장소 이름으로 사용. +- 실행 단계: 워크플로우 리포지토리 체크아웃 → SSH 키 저장/권한 설정 후 `ssh-keyscan 172.16.42.118` → 각 브랜치마다 Gitea API로 `center_dev` 조직에 저장소 존재 여부 확인(있으면 대상 저장소를 mirror clone 후 source 브랜치를 fetch/pull해 업데이트만, 없으면 저장소 생성 시 기본 브랜치를 `main`으로 설정) → 소스 브랜치를 대상 저장소 `main`으로 강제 푸시 → 푸시 후에도 기본 브랜치를 `main`으로 패치 → 임시 폴더 정리. 오류가 나도 다음 브랜치로 계속 진행하도록 처리. + +## 시크릿/변수 +- 현재 요구: `SSH_PRIVATE_KEY`(소스 접근), `GITEA_TOKEN`(Gitea API/푸시), `GITEA_URL`(Gitea 인스턴스 URL). +- to-do 예정 변경: Gitea 관련 항목을 `BASE_GITEA_` 접두사로 통일(`secrets.BASE_GITEA_TOKEN`, `vars.BASE_GITEA_URL`, `vars.BASE_GITEA_USER`). + +## 남은 작업(to-do.md 기준) +- `mirror.yml`: timeout 설정 추가. +- `mirror.yml`: `workflow_dispatch` 입력으로 단일 브랜치 지정 기능 추가. +- `mirror.yml`: 입력 브랜치가 있으면 우선 처리, 없으면 `branch_list` 사용하도록 로직 변경. +- `mirror.yml`: Gitea 시크릿/변수 이름 `BASE_GITEA_` 접두사로 교체. +- `to-do.md`: 작업 완료 후 KST 기준 완료 시간 기록. +- 참고: to-do 하단에 "모든 작업이 완료되었습니다. (2025-12-15 17:42:52 KST)" 문구가 있으니 실제 완료 여부를 확인 필요. + +## 추가 주의사항 +- 초기 미러링은 시간이 오래 걸릴 수 있음. +- 보안: Gitea 토큰과 SSH 키는 최소 권한/노출 최소화. +- 기본 브랜치명이 `main`과 다를 경우 push 대상 브랜치명 확인 필요. diff --git a/to-do.md b/to-do.md index a8d40b9..980e52d 100644 --- a/to-do.md +++ b/to-do.md @@ -1,11 +1,14 @@ # Git Mirroring Workflow 개선 작업 목록 -- [ ] `mirror.yml`: 작업 시간 초과(timeout) 설정 추가 -- [ ] `mirror.yml`: 수동 실행 시 특정 브랜치를 지정할 수 있는 입력(input) 기능 추가 -- [ ] `mirror.yml`: Gitea 관련 시크릿 및 변수 이름을 `BASE_GITEA_` 접두사로 변경 (`secrets.BASE_GITEA_TOKEN`, `vars.BASE_GITEA_URL`, `vars.BASE_GITEA_USER`) -- [ ] `mirror.yml`: 스크립트 로직을 수정하여 수동 입력된 브랜치를 처리하거나, 입력이 없을 경우 `branch_list` 파일을 사용하도록 변경 -- [ ] `to-do.md`: 모든 작업 완료 후 KST 시간 기준으로 완료 시간 기록 +- [x] `mirror.yml`: 작업 시간 초과(timeout) 설정 추가 +- [x] `mirror.yml`: 수동 실행 시 특정 브랜치를 지정할 수 있는 입력(input) 기능 추가 +- [x] `mirror.yml`: Gitea 관련 시크릿 및 변수 이름을 `BASE_GITEA_` 접두사로 변경 (`secrets.BASE_GITEA_TOKEN`, `vars.BASE_GITEA_URL`, `vars.BASE_GITEA_USER`) +- [x] `mirror.yml`: 스크립트 로직을 수정하여 수동 입력된 브랜치를 처리하거나, 입력이 없을 경우 `branch_list` 파일을 사용하도록 변경 +- [x] `mirror.yml`: 대상 저장소가 이미 있으면 재생성 대신 pull/fetch 후 업데이트만 수행하도록 변경 +- [x] `mirror.yml`: 브랜치명이 `Develop_Net8`로 시작하지 않으면 브랜치명을 그대로 저장소 이름으로 사용하도록 로직 추가 +- [x] `to-do.md`: 모든 작업 완료 후 KST 시간 기준으로 완료 시간 기록 +- [x] 문서: AGENTS.md 생성 및 최신 요구사항(기존 저장소 업데이트, 비-Develop_Net8 브랜치 저장소명 규칙) 반영 --- -* 모든 작업이 완료되었습니다. (2025-12-15 17:42:52 KST) +* 모든 작업 완료 (2025-12-15 18:01:51 KST, KST 기준)