<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>화향 :: 블로그</title>
    <link>https://hwahyang.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 17 Aug 2026 10:58:55 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>화향_</managingEditor>
    <image>
      <title>화향 :: 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/6310552/attach/a3353ca40efe4a3f968d6e778a6697ce</url>
      <link>https://hwahyang.tistory.com</link>
    </image>
    <item>
      <title>GameCI를 활용하여 Unity 빌드 자동화하기</title>
      <link>https://hwahyang.tistory.com/7</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;0. 계기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2~3년 전쯤부터 GitHub를 사용하는 Node.js 프로젝트에 GitHub Actions를 활용하여 Push 시마다 빌드 테스트를 수행하도록 만들었었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 Push하기 이전에 직접 빌드 테스트를 할 수는 없었기에, 혹시나 Lint에서 잡아내지 못한 문제가 있다면 자동화된 빌드 테스트가 문제를 잡아낼 수 있어 유용하게 사용하였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 19.04.01.png&quot; data-origin-width=&quot;2358&quot; data-origin-height=&quot;1582&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpygKA/dJMcabQVM1G/QyRSmRn1XJ14A4ETBq5kkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpygKA/dJMcabQVM1G/QyRSmRn1XJ14A4ETBq5kkK/img.png&quot; data-alt=&quot;이전에 적용한 프로젝트의 Actions 빌드 테스트 기록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpygKA/dJMcabQVM1G/QyRSmRn1XJ14A4ETBq5kkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpygKA%2FdJMcabQVM1G%2FQyRSmRn1XJ14A4ETBq5kkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;748&quot; height=&quot;502&quot; data-filename=&quot;스크린샷 2026-03-11 19.04.01.png&quot; data-origin-width=&quot;2358&quot; data-origin-height=&quot;1582&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이전에 적용한 프로젝트의 Actions 빌드 테스트 기록&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 19.06.41.png&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;1232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfLFUu/dJMcaiP1poU/dz1OdNVeI6vOL7SoCKlZi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfLFUu/dJMcaiP1poU/dz1OdNVeI6vOL7SoCKlZi0/img.png&quot; data-alt=&quot;실행에 실패하면 이메일로 알림을 받을 수 있어 좋다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfLFUu/dJMcaiP1poU/dz1OdNVeI6vOL7SoCKlZi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfLFUu%2FdJMcaiP1poU%2Fdz1OdNVeI6vOL7SoCKlZi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;431&quot; height=&quot;476&quot; data-filename=&quot;스크린샷 2026-03-11 19.06.41.png&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;1232&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실행에 실패하면 이메일로 알림을 받을 수 있어 좋다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity 프로젝트에도 이를 적용해보고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub에는 .NET Actions 템플릿이 있지만, Unity는 많은 양의 자체 라이브러리를 사용하기 때문에 이 템플릿을 활용하기에는 무리가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누군가는 Unity용 Actions 라이브러리를 만들었을 것 같아, 찾아보니 진짜 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 19.09.22.png&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;1410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rjgAE/dJMcacCkl38/1kSqpotChTqKzoagHpK7g1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rjgAE/dJMcacCkl38/1kSqpotChTqKzoagHpK7g1/img.png&quot; data-alt=&quot;game.ci 홈페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rjgAE/dJMcacCkl38/1kSqpotChTqKzoagHpK7g1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrjgAE%2FdJMcacCkl38%2F1kSqpotChTqKzoagHpK7g1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;588&quot; height=&quot;499&quot; data-filename=&quot;스크린샷 2026-03-11 19.09.22.png&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;1410&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;game.ci 홈페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. ubuntu-latest Runner를 이용하여 빌드하기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 19.24.29.png&quot; data-origin-width=&quot;1814&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1dr8h/dJMcadgVdzh/xFribm0cN31oNXKmSmIcxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1dr8h/dJMcadgVdzh/xFribm0cN31oNXKmSmIcxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1dr8h/dJMcadgVdzh/xFribm0cN31oNXKmSmIcxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1dr8h%2FdJMcadgVdzh%2FxFribm0cN31oNXKmSmIcxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;632&quot; height=&quot;261&quot; data-filename=&quot;스크린샷 2026-03-11 19.24.29.png&quot; data-origin-width=&quot;1814&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서 내용에 따라 라이선스 파일을 추출하고, GitHub Repository에 Secrets를 등록했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 19.24.18.png&quot; data-origin-width=&quot;1566&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA017A/dJMcagEJ0ea/2aPt5sEqQj3ADhLxEBsph0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA017A/dJMcagEJ0ea/2aPt5sEqQj3ADhLxEBsph0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA017A/dJMcagEJ0ea/2aPt5sEqQj3ADhLxEBsph0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA017A%2FdJMcagEJ0ea%2F2aPt5sEqQj3ADhLxEBsph0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;646&quot; height=&quot;199&quot; data-filename=&quot;스크린샷 2026-03-11 19.24.18.png&quot; data-origin-width=&quot;1566&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Actions 파일도 작성했다. 가장 저렴한 ubuntu-latest로 구동하려 하니, IL2CPP 프로젝트에서는 빌드하는 기기와 다른 OS PC를 타겟으로 빌드할 수 없다는 것을 깨달았다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 빌드본 업로드를 생략하고 빌드가 되는지만 테스트하기로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시나 안드로이드나 WebGL로의 빌드를 계획하고 있다면, 그런 경우는 ubuntu-latest에서도 IL2CPP 빌드가 가능하니 업로드까지 구현해봐도 괜찮을 것 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1773226896587&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;name: Unity Linux IL2CPP Build

on:
  push:
    branches: [ &quot;main&quot; ] # main 브랜치에 푸시될 때마다 실행
  pull_request:
    branches: [ &quot;main&quot; ] # main 브랜치로의 PR이 생성될 때마다 실행
  workflow_dispatch: # 수동 실행 버튼 활성화

jobs:
  build:
    name: Build for Linux IL2CPP
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          lfs: true # Git LFS 파일도 체크아웃

      - name: Cache Library
        uses: actions/cache@v3
        with: # 캐시 설정(파일이 변경되지 않는 한 Library와 같은 캐시 폴더 재사용)
          path: Library
          key: Library-Linux-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }}
          restore-keys: |
            Library-Linux-
            Library-

      - name: Unity Build
        uses: game-ci/unity-builder@v4
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
        with:
          targetPlatform: StandaloneLinux64 # 빌드 타겟 설정
          unityVersion: 6000.0.67f1 # Unity 버전 설정&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. Self-hosted Windows Runner로 이전하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열심히 세팅하고 빌드를 돌려보니, 문제가 생겼다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1854&quot; data-origin-height=&quot;606&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tFryr/dJMcacCknQB/8bGyxCK9aw8AaJJTOsA1Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tFryr/dJMcacCknQB/8bGyxCK9aw8AaJJTOsA1Xk/img.png&quot; data-alt=&quot;너무 오래 걸려서 도중에 취소시켰다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tFryr/dJMcacCknQB/8bGyxCK9aw8AaJJTOsA1Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtFryr%2FdJMcacCknQB%2F8bGyxCK9aw8AaJJTOsA1Xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1854&quot; height=&quot;606&quot; data-origin-width=&quot;1854&quot; data-origin-height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;너무 오래 걸려서 도중에 취소시켰다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빌드가 너무 오래 걸린다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 세팅하고 아직 아무것도 안해서 프로젝트도 URP 3D 템플릿 그대로인데, 이대로면 나중에는 3시간동안 빌드하게 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, 본가에 놀고있는 Windows 게이밍 노트북을 활용하기로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GameCI는 Docker 기반이기에, 노트북에 있는 Docker Desktop을 점검하고 self-hosted로 실행시켜봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 20.20.10.png&quot; data-origin-width=&quot;1888&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9MA4a/dJMcacbfqmk/YdMCYFTdGwVP6ckvrGF1ZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9MA4a/dJMcacbfqmk/YdMCYFTdGwVP6ckvrGF1ZK/img.png&quot; data-alt=&quot;나한테 왜그래&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9MA4a/dJMcacbfqmk/YdMCYFTdGwVP6ckvrGF1ZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9MA4a%2FdJMcacbfqmk%2FYdMCYFTdGwVP6ckvrGF1ZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1888&quot; height=&quot;250&quot; data-filename=&quot;스크린샷 2026-03-11 20.20.10.png&quot; data-origin-width=&quot;1888&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;나한테 왜그래&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얘가 계속 이상한 경로를 참조한다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어짜피 노트북에 백업으로 Unity와 Git 등 필요한 프로그램은 다 설치해놨어서, 커맨드라인을 활용해 직접 빌드하는 방식을 사용하기로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Actions 파일을 수정하는 김에 GitHub Artifacts에 빌드파일 업로드도 구현해보려 했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 20.22.14.png&quot; data-origin-width=&quot;1324&quot; data-origin-height=&quot;1262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nUt5N/dJMcaibt4MC/SLDTZchliYyCdEjf5uhcpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nUt5N/dJMcaibt4MC/SLDTZchliYyCdEjf5uhcpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nUt5N/dJMcaibt4MC/SLDTZchliYyCdEjf5uhcpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnUt5N%2FdJMcaibt4MC%2FSLDTZchliYyCdEjf5uhcpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;477&quot; data-filename=&quot;스크린샷 2026-03-11 20.22.14.png&quot; data-origin-width=&quot;1324&quot; data-origin-height=&quot;1262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 GitHub Artifacts의 기본 용량이 너무 적었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub Student Developer Pack을 가지고 있어서 2GB까지 사용이 가능했지만, 그래도 너무 적은 용량이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 결국 Artifacts 업로드를 제외하고 Windows IL2CPP 빌드만 테스트하도록 Gemini 도움을 받아 수정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시나 노트북이 사용 불가할 때를 대비해, ubuntu-latest 빌드도 남겨두었다.&lt;/p&gt;
&lt;pre id=&quot;code_1773228569767&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;name: Unity Build (Optimized Fallback)

on:
  pull_request:
    branches: [ &quot;main&quot; ]
    types: [ opened, synchronize, reopened ]

jobs:
  build-windows-self-hosted:
    name: Build for Windows (Self-hosted Direct)
    runs-on: [self-hosted, windows, x64]
    timeout-minutes: 120 # 2시간동안 완료하지 못하면 타임아웃을 시킨다. (Self-hosted가 꺼져있을 때를 대비)
    continue-on-error: true
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          lfs: true

      - name: Cache Library
        uses: actions/cache@v4
        with:
          path: Library
          key: Library-Windows-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }}
          restore-keys: |
            Library-Windows-
            Library-

      - name: Unity Build (Direct Command Line)
        # Unity 경로는 본인 환경에 맞는 경로로 바꿔준다.
        run: |
          $UnityPath = &quot;C:\Program Files\Unity\Hub\Editor\6000.0.67f1\Editor\Unity.exe&quot;
          &amp;amp; $UnityPath -batchmode -quit -nographics -projectPath &quot;${{ github.workspace }}&quot; -buildWindows64Player &quot;build\StandaloneWindows64\Build.exe&quot; -logFile - | Write-Output
          if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

  build-linux-fallback: # Windows Self-hosted 빌드가 실패할 경우에만 실행되는 Linux 빌드
    name: Build for Linux (Ubuntu Fallback)
    needs: [build-windows-self-hosted]
    if: always() &amp;amp;&amp;amp; needs.build-windows-self-hosted.result != 'success'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          lfs: true

      - name: Cache Library
        uses: actions/cache@v4
        with:
          path: Library
          key: Library-Linux-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }}
          restore-keys: |
            Library-Linux-
            Library-

      - name: Unity Build (Linux)
        uses: game-ci/unity-builder@v4
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
        with:
          targetPlatform: StandaloneLinux64
          unityVersion: 6000.0.67f1
          versioning: None # 이러면 프로젝트 세팅에서 설정한 버전으로 빌드한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 잘 동작한다. 이대로 당분간 사용하기로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. IaaS로 이전하고, 빌드본을 구글 드라이브에 업로드하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 문제가 생겼다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 19.17.57.png&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;1266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/StFjb/dJMb99S7oyO/CsWDmgoK5bzfaZ5csOJB9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/StFjb/dJMb99S7oyO/CsWDmgoK5bzfaZ5csOJB9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/StFjb/dJMb99S7oyO/CsWDmgoK5bzfaZ5csOJB9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FStFjb%2FdJMb99S7oyO%2FCsWDmgoK5bzfaZ5csOJB9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;151&quot; height=&quot;434&quot; data-filename=&quot;스크린샷 2026-03-11 19.17.57.png&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;1266&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 작업이 몰리니 소요 시간이 말도 안되게 불어났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 원인을 파악하기 위해, 아무 작업이나 하나 열어봤다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1964&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AYYhB/dJMcah4HBqc/PEGXg1KKWcZJNBKKSZcGi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AYYhB/dJMcah4HBqc/PEGXg1KKWcZJNBKKSZcGi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AYYhB/dJMcah4HBqc/PEGXg1KKWcZJNBKKSZcGi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAYYhB%2FdJMcah4HBqc%2FPEGXg1KKWcZJNBKKSZcGi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;675&quot; height=&quot;223&quot; data-origin-width=&quot;1964&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y6KX8/dJMcach1ulG/DSmtkCln0UdW085MzK4ip0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y6KX8/dJMcach1ulG/DSmtkCln0UdW085MzK4ip0/img.png&quot; data-alt=&quot;아...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y6KX8/dJMcach1ulG/DSmtkCln0UdW085MzK4ip0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy6KX8%2FdJMcach1ulG%2FDSmtkCln0UdW085MzK4ip0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;393&quot; height=&quot;144&quot; data-origin-width=&quot;928&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;아...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;본가 인터넷이 100Mbps 회선&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unity 프로젝트 캐시는 기본 GB 단위이기 때문에, 캐시 업로드에만 한참이 걸렸던 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 캐시 업/다운로드를 비활성화 하면 되지만, 나중에 프로젝트 용량이 커지면 동일한 문제가 발생할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, IaaS로의 이전을 결정하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IaaS로 이전하기 위해, 다음과 같은 조건을 검토했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. CPU 2코어 이상 (1코어에서 윈도우가 너무 버벅거림)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. RAM 8GB 이상 (Unity 최소 실행요건)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Custom ISO 마운트가 가능해야 함. (Windows 수동설치)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. SSD 128GB 이상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 되도록 1만원/월 이하의 요금 (학생이라 돈이 없다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾다가, netcup이라는 업체의 VPS를 찾았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 19.19.41.png&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;1180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6AcrM/dJMcaiCvHGh/DlaqiUyUb2niuuBCwfj6VK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6AcrM/dJMcaiCvHGh/DlaqiUyUb2niuuBCwfj6VK/img.png&quot; data-alt=&quot;놀라운 가격 7유로&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6AcrM/dJMcaiCvHGh/DlaqiUyUb2niuuBCwfj6VK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6AcrM%2FdJMcaiCvHGh%2FDlaqiUyUb2niuuBCwfj6VK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;268&quot; height=&quot;462&quot; data-filename=&quot;스크린샷 2026-03-11 19.19.41.png&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;1180&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;놀라운 가격 7유로&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유럽권 리전에 VPS를 설치할 때 이렇게 저렴한 요금이 나오는 업체였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어짜피 빌드 테스트용으로만 사용할것이라, VPS 리전보다는 대역폭과 트래픽 한도가 더 중요했기에 netcup으로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1850&quot; data-origin-height=&quot;328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch8obn/dJMcabQVPPo/2vZvHKmhiAsYjnqpKA7Oy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch8obn/dJMcabQVPPo/2vZvHKmhiAsYjnqpKA7Oy1/img.png&quot; data-alt=&quot;IPv4와 스냅샷까지 붙이니 8유로가 나왔지만, 어쨌든 저렴하다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch8obn/dJMcabQVPPo/2vZvHKmhiAsYjnqpKA7Oy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch8obn%2FdJMcabQVPPo%2F2vZvHKmhiAsYjnqpKA7Oy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1850&quot; height=&quot;328&quot; data-origin-width=&quot;1850&quot; data-origin-height=&quot;328&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;IPv4와 스냅샷까지 붙이니 8유로가 나왔지만, 어쨌든 저렴하다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선결제 구조라 한달치를 결제하고, 윈도우를 직접 설치했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거에 다른 IaaS 사용할 때도 윈도우 수동설치를 해봤는데, 다시해도 너무 복잡했다. 이렇게 특수한 상황이 아니고서는 그냥 기본 탑재 OS를 사용하고 싶을 정도로.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IaaS로 이전하는 김에 VPS를 최대한 활용하고 싶었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서, 빌드본도 업로드하게 수정하여 팀원들이 게임 개발에만 집중하게 만들고 싶었다. (사실 이게 CI/CD의 목적이기도 하고)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 GitHub Artifacts의 용량 제한은 너무 적다. 돈을 내자니 돈이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 스토리지에 업로드 하는 방안이 없을까 싶어 찾아봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 방법이 있었다. 내가 고민하는 것들은 다른 사람들도 고민하나보다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마침 개발팀에서 공용으로 사용하는 구글드라이브 폴더가 있었기에, 거기에 업로드를 하기로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 업로드할 폴더의 ID를 추출해내고, VPS에 rclone을 설치 및 구글 계정으로 로그인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(또) Gemini의 도움을 받아 Actions 파일을 수정했다.&lt;/p&gt;
&lt;pre id=&quot;code_1773230441604&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;name: Unity Build and Upload

on:
  push:
    tags: # 태그 푸시 시에도 빌드 및 업로드 하도록 수정했다. 보통 태그를 푸시할 때는 빌드본이 필요한 경우이기 때문이다.
      - '*'
  pull_request:
    branches: [ &quot;main&quot; ]
    types: [ opened, synchronize ]

jobs:
  build-and-upload:
    name: Build for Windows &amp;amp; Upload to GDrive
    runs-on: [self-hosted, windows, x64]
    timeout-minutes: 120
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          lfs: true

      - name: Cache Library
        uses: actions/cache@v4
        with:
          path: Library
          key: Library-Windows-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }}
          restore-keys: |
            Library-Windows-
            Library-

      - name: Extract Project Name
        id: extract # 빌드 설정에서 프로젝트명을 빼내어 Unity 빌드 시 exe 파일명과 zip 파일명에 활용한다.
        run: |
          $productName = &quot;Build&quot;
          if (Test-Path &quot;ProjectSettings\ProjectSettings.asset&quot;) {
              $line = Get-Content &quot;ProjectSettings\ProjectSettings.asset&quot; | Select-String -Pattern &quot;^\s*productName:\s*(.*)$&quot;
              if ($line) {
                  $productName = $line.Matches[0].Groups[1].Value.Trim()
              }
          }
          # Windows 파일명에서 금지된 문자 제거
          $productName = $productName -replace '[&amp;lt;&amp;gt;:&quot;/\\|?*]', '_'
          Add-Content -Path $env:GITHUB_ENV -Value &quot;PRODUCT_NAME=$productName&quot;
          Write-Output &quot;Extracted product name: $productName&quot;

      - name: Unity Build (Direct Command Line)
        run: |
          $UnityPath = &quot;C:\Program Files\Unity\Hub\Editor\6000.0.67f1\Editor\Unity.exe&quot;
          $ExeName = &quot;$env:PRODUCT_NAME.exe&quot;
          &amp;amp; $UnityPath -batchmode -quit -nographics -projectPath &quot;${{ github.workspace }}&quot; -buildWindows64Player &quot;build\StandaloneWindows64\$ExeName&quot; -logFile - | Write-Output
          if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

      - name: Determine Zip Name # 상황에 따라 적합한 파일명을 생성한다.
        run: |
          $eventName = &quot;${{ github.event_name }}&quot;
          if ($eventName -eq &quot;pull_request&quot;) {
              $prNumber = &quot;${{ github.event.pull_request.number }}&quot;
              $sha = &quot;${{ github.event.pull_request.head.sha }}&quot;
              $shortSha = if ($sha.Length -ge 7) { $sha.Substring(0, 7) } else { $sha }
              $zipFile = &quot;${env:PRODUCT_NAME}-windows-pr${prNumber}-${shortSha}.zip&quot;
          } elseif ($eventName -eq &quot;push&quot; -and &quot;${{ github.ref }}&quot; -like &quot;refs/tags/*&quot;) {
              $tag = &quot;${{ github.ref_name }}&quot;
              $zipFile = &quot;${env:PRODUCT_NAME}-windows-tag-${tag}.zip&quot;
          } else {
              $sha = &quot;${{ github.sha }}&quot;
              $shortSha = if ($sha.Length -ge 7) { $sha.Substring(0, 7) } else { $sha }
              $zipFile = &quot;${env:PRODUCT_NAME}-windows-${shortSha}.zip&quot;
          }
          # 정규식으로 파일명 금지 문자 최종 제거
          $zipFile = $zipFile -replace '[&amp;lt;&amp;gt;:&quot;/\\|?*]', '_'
          Add-Content -Path $env:GITHUB_ENV -Value &quot;ZIP_NAME=$zipFile&quot;
          Write-Output &quot;Generated Zip Name: $zipFile&quot;

      - name: Compress Build Output # 불필요한 파일을 제거하고 빌드본을 압축한다.
        run: |
          $BuildDir = &quot;build\StandaloneWindows64&quot;
          $ZipName = $env:ZIP_NAME
          if (Test-Path $BuildDir) {
              Write-Output &quot;Removing DoNotShip folders...&quot;
              # 유니티 빌드 후 배포 시 제외해야 하는 폴더 삭제 (ex: *_BurstDebugInformation_DoNotShip, *_BackUpThisFolder_ButDontShipItWithYourGame)
              Get-ChildItem -Path $BuildDir -Directory | Where-Object { $_.Name -match &quot;DoNotShip|ButDontShipItWithYourGame&quot; } | Remove-Item -Recurse -Force
              
              Write-Output &quot;Compressing $BuildDir to $ZipName...&quot;
              Compress-Archive -Path &quot;$BuildDir\*&quot; -DestinationPath $ZipName -Force
              Write-Output &quot;Compression finished: $ZipName&quot;
          } else {
              Write-Error &quot;Build directory ($BuildDir) not found!&quot;
              exit 1
          }

      - name: Setup Rclone # Actions Runner가 서비스 계정으로 실행되면 rclone이 PATH에 없을 수 있으므로, 자동으로 다운로드하여 사용할 수 있도록 한다. (rclone 버전 고정)
        run: |
          # 서비스 계정으로 동작할 때를 대비하여 rclone이 PATH에 없는 경우 자동 다운로드 및 구성
          if (Get-Command &quot;rclone&quot; -ErrorAction SilentlyContinue) {
              Write-Output &quot;rclone is already in PATH.&quot;
          } else {
              Write-Output &quot;rclone not found. Downloading standalone version...&quot;
              # 특정 rclone 버전 고정
              $RcloneVersion = &quot;1.65.2&quot;
              $RcloneBaseUrl = &quot;https://downloads.rclone.org/v$RcloneVersion&quot;
              $RcloneZip = &quot;rclone-v$RcloneVersion-windows-amd64.zip&quot;
              $RcloneZipUrl = &quot;$RcloneBaseUrl/$RcloneZip&quot;
              
              Write-Output &quot;Downloading rclone $RcloneVersion from $RcloneZipUrl&quot;
              Invoke-WebRequest -Uri $RcloneZipUrl -OutFile &quot;rclone.zip&quot;
              Expand-Archive -Path &quot;rclone.zip&quot; -DestinationPath &quot;rclone_bin&quot; -Force
              
              $RcloneDir = (Get-ChildItem -Path &quot;rclone_bin&quot; -Directory -Filter &quot;rclone-*-windows-amd64&quot;).FullName
              if ($RcloneDir) {
                  Add-Content -Path $env:GITHUB_PATH -Value $RcloneDir
                  Write-Output &quot;Added $RcloneDir to GITHUB_PATH.&quot;
              } else {
                  Write-Error &quot;Failed to extract standalone rclone.&quot;
                  exit 1
              }
          }

      - name: Upload to Google Drive via Rclone # Rclone을 사용하여 Google Drive에 파일을 업로드한다.
        env:
          RCLONE_CONF_CONTENT: ${{ secrets.RCLONE_CONF }}
          RCLONE_CONFIG_GDRIVE_TYPE: drive
          RCLONE_CONFIG_GDRIVE_ROOT_FOLDER_ID: ${{ secrets.GDRIVE_FOLDER_ID }}
        run: |
          # 1. OAuth 인증 정보가 담긴 설정 파일(rclone.conf) 생성
          # (줄바꿈이 정상적으로 유지되도록 PowerShell의 Set-Content를 사용합니다.)
          $Env:RCLONE_CONF_CONTENT | Set-Content -Path &quot;rclone.conf&quot; -NoNewline -Encoding utf8
          
          try {
              $ZipName = $env:ZIP_NAME
              Write-Output &quot;Uploading $ZipName to Google Drive...&quot;
              
              # 2. Rclone을 이용한 대용량 파일 업로드 처리
              rclone copy $ZipName gdrive: --config rclone.conf --retries 5 --retries-sleep 10s --timeout 15m -v
              $RcloneExitCode = $LASTEXITCODE
              
              if ($RcloneExitCode -eq 0) {
                  Write-Output &quot;======================================&quot;
                  Write-Output &quot;✅ Upload completed successfully!&quot;
                  Write-Output &quot;======================================&quot;
              } else {
                  Write-Error &quot;❌ Upload failed with exit code $RcloneExitCode&quot;
                  exit $RcloneExitCode
              }
          } finally {
              # 3. 예외 발생 시에도 설정 파일 안전하게 삭제
              if (Test-Path &quot;rclone.conf&quot;) {
                  Remove-Item -Path &quot;rclone.conf&quot; -Force
                  Write-Output &quot;Cleaned up rclone.conf in finally block.&quot;
              }
          }

      - name: Fallback Cleanup Secrets
        if: always()
        run: |
          if (Test-Path &quot;rclone.conf&quot;) {
              Remove-Item -Path &quot;rclone.conf&quot; -Force
              Write-Output &quot;Cleaned up rclone.conf in fallback step.&quot;
          }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 진짜로 마지막 테스트를 돌려보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 19.20.47.png&quot; data-origin-width=&quot;2360&quot; data-origin-height=&quot;1278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rUO45/dJMcaiP1sAd/CMdci2XTTu9rawe80ofwkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rUO45/dJMcaiP1sAd/CMdci2XTTu9rawe80ofwkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rUO45/dJMcaiP1sAd/CMdci2XTTu9rawe80ofwkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrUO45%2FdJMcaiP1sAd%2FCMdci2XTTu9rawe80ofwkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2360&quot; height=&quot;1278&quot; data-filename=&quot;스크린샷 2026-03-11 19.20.47.png&quot; data-origin-width=&quot;2360&quot; data-origin-height=&quot;1278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yaz6L/dJMcafsgqGG/ckQUfud7K9fNRPB1AP91i0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yaz6L/dJMcafsgqGG/ckQUfud7K9fNRPB1AP91i0/img.png&quot; data-alt=&quot;속도 잘나온다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yaz6L/dJMcafsgqGG/ckQUfud7K9fNRPB1AP91i0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYaz6L%2FdJMcafsgqGG%2FckQUfud7K9fNRPB1AP91i0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;479&quot; height=&quot;123&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;속도 잘나온다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-11 19.21.21.png&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVzB8S/dJMcabpTTO6/jbJsk3I1WkKvwKRIB2Rtvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVzB8S/dJMcabpTTO6/jbJsk3I1WkKvwKRIB2Rtvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVzB8S/dJMcabpTTO6/jbJsk3I1WkKvwKRIB2Rtvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVzB8S%2FdJMcabpTTO6%2FjbJsk3I1WkKvwKRIB2Rtvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;502&quot; height=&quot;145&quot; data-filename=&quot;스크린샷 2026-03-11 19.21.21.png&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjuiBD/dJMcaiCvIdx/WiiKeKW0HogyzyDT1dIk0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjuiBD/dJMcaiCvIdx/WiiKeKW0HogyzyDT1dIk0K/img.png&quot; data-alt=&quot;구글 드라이브에 업로드도 빠르게 잘 된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjuiBD/dJMcaiCvIdx/WiiKeKW0HogyzyDT1dIk0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjuiBD%2FdJMcaiCvIdx%2FWiiKeKW0HogyzyDT1dIk0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;679&quot; height=&quot;86&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;구글 드라이브에 업로드도 빠르게 잘 된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 진짜 다 작업했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PR 또는 태그 푸시가 발생하면 자동으로 빌드 및 구글 드라이브에 결과물 업로드를 하게 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로써 PR 병합 전에 빌드에 문제가 없는지 확인할 수 있고, 중간 빌드본이 필요할 때도 구글 드라이브에서 바로 찾아 공유할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 마치며&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 기술을 배우는 것은 언제나 재밌다. 내가 몰랐던 것들도 알게 되고, 이렇게 두고두고 사용할 수 있는 기술들은 배우는 보람도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그만큼 시간이 많이 소요되긴 했다. 1~3단계 과정에만 누적 9시간은 넘게 투자했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GameCI를 완전히 이해하기 위해 시간을 사용한 것도 있고, 중간중간 문제를 해결하지 못해 1시간 넘게 머리를 싸매다가 다음날 다시하기도 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 생각해보면, 이전까지의 프로젝트에서 빌드에 사용한 시간이 결코 적지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 한 번에 5분은 거뜬히 넘겼고, 주차마자 빌드본을 공유했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 도중에는 다른 일을 하기도 어려워서 항상 유튜브나 보며 20분 이상을 허비했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 이 환경을 구축하는 데에 9시간이라는 긴 시간을 사용했지만, 이 환경을 구축하지 않았을 때의 허비될 시간을 생각하면 의미있는 투자라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'DevOps와 CI/CD라는 개념이 결코 가볍지 않구나'라는 생각이 들었다.&lt;/p&gt;</description>
      <category>연구/Unity</category>
      <author>화향_</author>
      <guid isPermaLink="true">https://hwahyang.tistory.com/7</guid>
      <comments>https://hwahyang.tistory.com/7#entry7comment</comments>
      <pubDate>Wed, 11 Mar 2026 21:14:21 +0900</pubDate>
    </item>
    <item>
      <title>ABOUT ME</title>
      <link>https://hwahyang.tistory.com/notice/5</link>
      <description>&lt;p style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;김강현 / 화향&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;청강문화산업대학교 게임콘텐츠스쿨 (게임프로그래밍)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-313ba697-fdef-455a-8477-0ce23a25007a&quot; style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Email: &lt;a href=&quot;mailto:hwahyang@meowlabs.kr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;hwahyang@meowlabs.kr&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e7ff0d46-f732-4541-8854-01a7087189c9&quot; style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Homepage: &lt;/span&gt;&lt;a href=&quot;https://hwahyang.space&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-href=&quot;https://hwahyang.space&quot;&gt;hwahyang.space&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1d756449-992f-4bb7-ae22-c266055c76d8&quot; style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Github:&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/hwahyang1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-href=&quot;https://github.com/hwahyang1&quot;&gt;hwahyang1&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-295ae66d-891f-47ee-b16f-ad3fbd7c07fa&quot; style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Twitter:&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://twitter.com/_hwahyang_&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #000000;&quot; data-href=&quot;https://twitter.com/_hwahyang_&quot;&gt;@_hwahyang_&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <author>화향_</author>
      <guid isPermaLink="true">https://hwahyang.tistory.com/notice/5</guid>
      <pubDate>Sun, 30 Apr 2023 01:39:12 +0900</pubDate>
    </item>
  </channel>
</rss>