From 546a1337fdc94ece102ab8f57c0a8598b0b9f4bd Mon Sep 17 00:00:00 2001 From: Lectom C Han Date: Mon, 15 Dec 2025 17:48:21 +0900 Subject: [PATCH] =?UTF-8?q?=EC=B5=9C=EC=B4=88=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/mirror.yml | 120 ++++++++++++++++++++++++++++++++++++ .gitignore | 2 + GEMINI.md | 77 +++++++++++++++++++++++ branch_list | 11 ++++ to-do.md | 11 ++++ 5 files changed, 221 insertions(+) create mode 100644 .gitea/workflows/mirror.yml create mode 100644 .gitignore create mode 100644 GEMINI.md create mode 100644 branch_list create mode 100644 to-do.md diff --git a/.gitea/workflows/mirror.yml b/.gitea/workflows/mirror.yml new file mode 100644 index 0000000..1503cc0 --- /dev/null +++ b/.gitea/workflows/mirror.yml @@ -0,0 +1,120 @@ +name: Git Repository Mirroring + +on: + workflow_dispatch: + inputs: + branches: + description: 'Comma-separated list of branches to mirror (e.g., Develop_Net8,Develop_Net8_box). If empty, all branches from branch_list file will be mirrored.' + required: false + default: '' + schedule: + - cron: '0 2 * * *' # Runs every day at 2:00 AM + +jobs: + mirror: + runs-on: ubuntu-latest + timeout-minutes: 360 # 6 hours timeout + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up SSH + env: + SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} + run: | + mkdir -p ~/.ssh + echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + ssh-keyscan -p 22 172.16.42.118 >> ~/.ssh/known_hosts + + - name: Mirror Branches + env: + BASE_GITEA_TOKEN: ${{ secrets.BASE_GITEA_TOKEN }} + BASE_GITEA_URL: ${{ vars.BASE_GITEA_URL }} # e.g., https://gitea.example.com + 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. + + # Gitea API Header + AUTH_HEADER="Authorization: token ${BASE_GITEA_TOKEN}" + + process_branch() { + local branch_name=$1 + if [[ -z "$branch_name" ]]; then + return + fi + + echo "=================================================" + echo "Processing branch: ${branch_name}" + + repo_name="" + if [ "${branch_name}" == "Develop_Net8" ]; then + repo_name="base" + else + repo_name=$(echo "${branch_name}" | sed 's/^Develop_Net8_//') + 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}") + + 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_status=$(echo "${create_repo_response}" | tail -c 3) + if [[ "${create_status}" -ne "201" ]]; then + echo "::error::Failed to create repository. API response:" + echo "${create_repo_response}" | head -c -3 + exit 1 + fi + echo "Repository created successfully." + elif [ "${http_status}" != "200" ]; then + echo "::error::Error checking repository. HTTP status: ${http_status}" + exit 1 + else + echo "Repository 'center_dev/${repo_name}' already exists." + 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" + 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}..." + + git clone --bare "${SOURCE_REPO}" "${CLONE_DIR}" + + cd "${CLONE_DIR}" + + 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" + + # Cleanup + cd .. + rm -rf "${CLONE_DIR}" + + echo "Successfully mirrored ${branch_name} to center_dev/${repo_name}" + echo "=================================================" + echo "" + } + + if [[ -n "${INPUT_BRANCHES}" ]]; then + echo "Processing manually specified branches: ${INPUT_BRANCHES}" + # Split comma-separated string into an array + IFS=',' read -r -a branches_to_process <<< "${INPUT_BRANCHES}" + for branch in "${branches_to_process[@]}"; do + # Trim whitespace + trimmed_branch=$(echo "$branch" | xargs) + process_branch "${trimmed_branch}" + done + else + echo "Processing all branches from branch_list file." + while IFS= read -r branch_name || [[ -n "$branch_name" ]]; do + process_branch "${branch_name}" + done < branch_list + fi \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f4bdac0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +engdev* +engdev/** \ No newline at end of file diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..58c65d1 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,77 @@ +# Gitea Action을 이용한 Git 저장소 미러링 계획 + +## 1. 개요 + +이 문서는 외부 SSH 프로토콜 기반의 Git 저장소를 Gitea로 미러링하는 Gitea Action 워크플로우의 설계 및 구현 계획을 정의합니다. + +소스 저장소의 특정 브랜치들을 각각 별개의 Gitea 저장소로 매핑하고, 주기적으로 (Cron) 소스 저장소의 변경 사항을 가져와 Gitea 저장소에 반영하는 것을 목표로 합니다. 데이터의 크기가 크다는 점을 감안하여 모든 작업은 순차적으로 진행되도록 설계합니다. + +## 2. 주요 요구사항 + +- **소스 저장소**: `engdev@172.16.42.118:dev_Net8.git` (SSH 프로토콜) +- **인증**: SSH 비공개 키 (`engdev` -> Gitea Secret `SSH_PRIVATE_KEY`로 저장) +- **대상**: Gitea `center_dev` 조직 (Organization) +- **작업 트리거**: 스케줄링 (Cron) 및 수동 실행 (workflow_dispatch) +- **처리 방식**: `branch_list` 파일에 명시된 브랜치 목록을 순차적으로 처리 +- **저장소 매핑 규칙**: + - `Develop_Net8` 브랜치 -> `base` 저장소 + - `Develop_Net8_*` 브랜치 -> `*` 이름의 저장소 (예: `Develop_Net8_box` -> `box`) +- **제약 조건**: 대용량 데이터를 고려하여 병렬 처리를 지양하고 순차적으로 미러링을 수행합니다. + +## 3. Gitea Action 설계 + +워크플로우는 하나의 Job으로 구성되며, 해당 Job 안에서 스크립트를 통해 브랜치 목록을 순회하며 미러링 작업을 순차적으로 수행합니다. + +### 워크플로우 트리거 + +```yaml +on: + workflow_dispatch: # 수동 실행 + schedule: + - cron: '0 2 * * *' # 매일 새벽 2시에 실행 (주기는 추후 변경 가능) +``` + +### 필요한 Gitea Secrets + +Gitea 저장소의 `Settings > Secrets`에 다음 정보들을 추가해야 합니다. + +1. **`SSH_PRIVATE_KEY`**: 소스 Git 저장소(`engdev@172.16.42.118`)에 접근하기 위한 SSH 비공개 키. +2. **`GITEA_TOKEN`**: Gitea 저장소를 생성하고 코드를 Push 하기 위한 Gitea 개인용 액세스 토큰. 이 토큰은 `center_dev` 조직에 저장소를 생성하고 코드를 쓸 수 있는 권한을 가져야 합니다. +3. **`GITEA_URL`**: Gitea 인스턴스의 전체 URL (예: `https://gitea.yourdomain.com`) + +### 워크플로우 주요 단계 (Steps) + +1. **워크플로우 실행 환경 준비**: + - `actions/checkout@v4`를 사용하여 현재 워크플로우가 포함된 저장소의 코드를 체크아웃합니다. (`branch_list` 파일을 읽기 위함) + +2. **SSH 환경 설정**: + - Gitea Secret으로 등록된 `SSH_PRIVATE_KEY`를 runner의 특정 파일(`~/.ssh/id_rsa`)에 저장합니다. + - 저장된 키 파일의 권한을 `600`으로 설정하여 SSH 클라이언트가 사용할 수 있도록 합니다. + - `ssh-keyscan`을 사용하여 소스 Git 서버(`172.16.42.118`)의 호스트 키를 `~/.ssh/known_hosts`에 추가하여, "man-in-the-middle" 공격 경고 없이 SSH 접속이 가능하도록 설정합니다. + +3. **미러링 스크립트 실행**: + - `branch_list` 파일을 한 줄씩 읽어 반복문을 실행합니다. + - **저장소 이름 결정**: 각 브랜치 이름에 따라 위 "저장소 매핑 규칙"에 맞게 Gitea에 생성될 저장소 이름을 결정합니다. + - **Gitea 저장소 확인 및 생성 (API)**: + - Gitea API를 사용하여 `center_dev` 조직 아래에 해당 이름의 저장소가 있는지 확인합니다. + - 저장소가 없다면 Gitea API를 통해 새로 생성합니다. (`GITEA_TOKEN` 사용) + - **소스 코드 클론 및 푸시**: + - `git clone --mirror`를 사용하여 소스 저장소의 모든 레퍼런스를 가져옵니다. (최초 한 번만 실행되거나, 매번 새로 실행할 수 있음. 효율성을 위해 `git fetch`를 사용하는 방향으로 최적화) + - 클론된 로컬 저장소에서 현재 처리 중인 브랜치를 Gitea의 대상 저장소로 `git push --force` 명령어를 사용하여 푸시합니다. 이때 브랜치의 내용을 Gitea 저장소의 `main` (또는 다른 기본) 브랜치로 덮어쓰게 됩니다. + - 예시: `git push --force https://:${GITEA_TOKEN}@${GITEA_URL}/center_dev/${repo_name}.git refs/remotes/origin/${branch_name}:refs/heads/main` + - **임시 파일 정리**: 각 브랜치 처리 후 생성된 임시 클론 저장소를 삭제하여 디스크 공간을 관리합니다. + +## 4. 구현 단계 + +1. Gitea 저장소에 `SSH_PRIVATE_KEY`, `GITEA_TOKEN`, `GITEA_URL` 시크릿을 추가합니다. +2. `.gitea/workflows/` 디렉터리 아래에 `mirror.yml` (또는 원하는 이름) 파일을 생성합니다. +3. 위 설계에 따라 워크플로우 YAML 파일의 내용을 작성합니다. +4. 작성된 워크플로우 파일을 Gitea 저장소에 푸시하여 활성화합니다. +5. Gitea Actions 탭에서 `workflow_dispatch`를 통해 수동으로 실행하여 정상 동작하는지 테스트합니다. + +## 5. 고려사항 + +- **초기 실행 시간**: 첫 미러링 시에는 모든 Git 데이터를 가져와야 하므로 상당한 시간이 소요될 수 있습니다. +- **오류 처리**: 특정 브랜치 미러링에 실패하더라도 다음 브랜치 작업은 계속 진행되도록 스크립트를 구성해야 합니다. +- **Gitea API**: Gitea API를 사용하는 부분은 Gitea 버전에 따라 endpoint나 요청 방식이 다를 수 있으므로, 사용 중인 Gitea 버전에 맞는 API 문서를 참고해야 합니다. +- **보안**: `GITEA_TOKEN`은 저장소 생성 및 쓰기 권한을 가지므로 안전하게 관리되어야 합니다. diff --git a/branch_list b/branch_list new file mode 100644 index 0000000..aa995c2 --- /dev/null +++ b/branch_list @@ -0,0 +1,11 @@ +Develop_Net8 +Develop_Net8_box +Develop_Net8_bridge +Develop_Net8_Graphics +Develop_Net8_Graphics_ModelerUI +Develop_Net8_heh +Develop_Net8_Strana +Develop_Net8_tunnel +Develop_Net8_wall +Develop_Net8_way +Develop_Net8_way_bridge \ No newline at end of file diff --git a/to-do.md b/to-do.md new file mode 100644 index 0000000..a8d40b9 --- /dev/null +++ b/to-do.md @@ -0,0 +1,11 @@ +# 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 시간 기준으로 완료 시간 기록 + +--- + +* 모든 작업이 완료되었습니다. (2025-12-15 17:42:52 KST)