241120 TIL

나고수·2024년 11월 20일
0

2024 TIL

목록 보기
84/94
post-thumbnail

① 배운 것
지금까지는 안드로이드, ios를 각각의 workflow로 빌드 및 앱 디스트리뷰션에 배포했습니다.
이제는 두개의 workflow를 하나로 합치고 플러터를 다운 받은 후 깃헙액션 캐시에 저장해서 다음에 캐시에서 플러터를 가져와서 사용할 수 있게 해봅시다

지금까지의 안드로이드 앱 디스트리뷰션 코드

name: Android CD to Firebase App distribution [flutter build apk --release --flavor dev]

env:
  GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon=false"
  GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true

on:
  workflow_dispatch:
  push:
    branches:
      - develop_test
    paths:
      - '.github/workflows/firebase_app_distribution_dev.yml'

permissions:
  contents: write

jobs:
  cd-build:
    runs-on: ubuntu-latest

    steps:
      # 디스크 공간 확보를 위한 cleanup steps
      - name: Cleanup Disk Space
        run: |
          # 사용하지 않는 큰 패키지들 제거
          sudo rm -rf /usr/share/dotnet
          sudo rm -rf /opt/ghc
          sudo rm -rf /usr/local/share/boost
          # 패키지 캐시 정리
          sudo apt-get clean
          # 디스크 사용량 확인
          df -h

      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          distribution: 'corretto'
          java-version: 17

      - name: Generate key.properties
        run: |
          echo '${{ secrets.KEY_PROPERTIES }}' | base64 --d >> ./android/key.properties

      - name: Generate local.properties
        run: |
          echo '${{ secrets.LOCAL_PROPERTIES }}' | base64 --d >> ./android/local.properties

      - name: Generate google-services.json
        run: echo '${{ secrets.GOOGLE_SERVICE_JSON }}' | base64 --d > ./android/app/google-services.json

      - name: Generate keystore.jks
        run: echo '${{ secrets.JKS }}' | base64 --d > ./android/app/hiing-keystore.jks

      - name: Extract Version
        run: |
          VERSION_NAME=$(grep 'version:' pubspec.yaml | sed -e 's/version: //' -e 's/+.*//')
          VERSION_CODE=$(grep 'version:' pubspec.yaml | sed -e 's/version: //' -e 's/.*+//')
          echo "VERSION_NAME=$VERSION_NAME" >> $GITHUB_ENV
          echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV
        id: extract_version

      - name: setup flutter
        uses: subosito/flutter-action@v1
        with:
          channel: 'stable'

      - name: setup flutter jdk directory
        run: |
          flutter config --jdk-dir /opt/hostedtoolcache/Java_Corretto_jdk/17.0.13-11.1/x64     

      - name: Configure Git
        run: |
          git config --global url."https://${{ vars.USER_NAME }}:${{ secrets.TOKEN_GITHUB }}@github.com/".insteadOf "https://github.com/"                    

      - name: install dependecies
        run: flutter pub get

      - name: Generate config
        run: |
          echo '${{ secrets.CONFIG }}' | base64 --d >> ./lib/common/config.dart

      - name: Build Release APK
        run: |
          flutter build apk --release --flavor dev

      - name: Upload Release Build to Artifacts
        uses: actions/upload-artifact@v3
        with:
          name: debug-artifacts
          path: build/app/outputs/flutter-apk/app-dev-release.apk
          if-no-files-found: error

      - name: Create Github Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: "${{ env.VERSION_NAME }}(${{ env.VERSION_CODE }})"
          release_name: "${{ env.VERSION_NAME }}(${{ env.VERSION_CODE }})"
          generate_release_notes: true
          files: |
            build/app/outputs/flutter-apk/app-dev-release.apk

      - name: Upload artifact to Firebase App Distribution
        uses: wzieba/Firebase-Distribution-Github-Action@v1
        id: upload
        with:
          appId: ${{secrets.FIREBASE_APP_ID_ANDROID_DEV}}
          serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}
          groups: ${{ vars.APP_DISTRIBUTION_GROUPS }}
          file: build/app/outputs/flutter-apk/app-dev-release.apk

      - name: notify
        if: always()
        run: |
          STATUS="${{ job.status }}"
          VERSION="${{ env.VERSION_NAME }}(${{ env.VERSION_CODE }})"
          
          if [[ "$STATUS" == "success" ]] ; then
            EMOJI="🎉"
          else
            EMOJI="😵‍💫"
          fi  
          
          curl -X POST https://slack.com/api/chat.postMessage \
            -H "Authorization: ${{ secrets.SLACK_TOKEN }}" \
            -H "Content-Type: application/json" \
            -d '{
              "channel": "${{ vars.SLACK_CHANNEL_ID }}",
              "text": "[App distribution] 안드로이드 배포 '"${STATUS}"''"${EMOJI}"'\n버전 👉 '"${VERSION}"'"
            }'

지금까지의 ios 앱 디스트리뷰션 코드

name: "[DEV] Build and Publish iOS"
on:
  workflow_dispatch:
  push:
    branches:
      - develop_test
    paths:
      - '.github/workflows/ios_firebase_cd.yml'

permissions:
  contents: write

jobs:
  build:
    runs-on: macos-latest
    outputs:
      version_name: ${{ env.VERSION_NAME }}
      version_code: ${{ env.VERSION_CODE }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      # Install the Apple certificate and provisioning profile
      - name: Install the Apple certificate and provisioning profile
        env:
          BUILD_CERTIFICATE_BASE64: ${{ secrets.APPSTORE_CERT_BASE64 }}
          P12_PASSWORD: ${{ secrets.APPSTORE_CERT_PASSWORD }}
          BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.MOBILEPROVISION_BASE64 }}
          BUILD_PROVISION_NOTI_PROFILE_BASE64: ${{ secrets.NOTI_MOBILEPROVISION_BASE64 }}
          KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}

        run: |
          # 변수 생성 
          CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
          PP_PATH=$RUNNER_TEMP/hiing_github_action_2.mobileprovision
          PP_NOTI_PATH=$RUNNER_TEMP/hiing_github_action_noti_2.mobileprovision
          KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
          
          #secrets으로 부터 인증서와 프로비저닝 프로파일 가져오기
          echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH
          echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode --output $PP_PATH
          echo -n "$BUILD_PROVISION_NOTI_PROFILE_BASE64" | base64 --decode --output $PP_NOTI_PATH
          
          # 키체인 초기화 - 임시 키체인 생성
          security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
          security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
          security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
          
          # import certificate to keychain
          security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
          security list-keychain -d user -s $KEYCHAIN_PATH

          # provisioning profile 적용
          mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
          mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
          cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
          cp $PP_NOTI_PATH ~/Library/MobileDevice/Provisioning\ Profiles
          
          # 디버깅
          echo "Listing provisioning profiles:"
          ls -l "$HOME/Library/MobileDevice/Provisioning Profiles/"

      - name: Extract Version
        run: |
          VERSION_NAME=$(grep 'version:' pubspec.yaml | sed -e 's/version: //' -e 's/+.*//')
          VERSION_CODE=$(grep 'version:' pubspec.yaml | sed -e 's/version: //' -e 's/.*+//')
          echo "VERSION_NAME=$VERSION_NAME" >> $GITHUB_ENV
          echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV
        id: extract_version

      # Install flutter
      - name: Flutter get
        uses: subosito/flutter-action@v1
        with:
          channel: 'stable'

      - name: Configure Git
        run: |
          git config --global url."https://${{ vars.USER_NAME }}:${{ secrets.TOKEN_GITHUB }}@github.com/".insteadOf "https://github.com/"                    

      # Install your project's dependencies
      - run: flutter pub get

      # Make config.dart
      - name: Generate config
        run: |
          echo '${{ secrets.CONFIG }}' | base64 --d >> ./lib/common/config.dart

      # Build and sign the ipa using a single flutter command
      - name: Building IPA
        run: flutter build ipa --export-options-plist=ios/Runner/ExportOptions.plist --flavor dev

      # Collect the file and upload as artifact
      - name: collect ipa artifacts
        uses: actions/upload-artifact@v4
        with:
          name: debug-ipa
          path: build/ios/ipa/*.ipa
          if-no-files-found: error

      # Important! Cleanup: remove the certificate and provisioning profile from the runner!
      - name: Clean up keychain and provisioning profile
        if: ${{ always() }}
        run: |
          security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
          rm ~/Library/MobileDevice/Provisioning\ Profiles/hiing_github_action_2.mobileprovision
          rm ~/Library/MobileDevice/Provisioning\ Profiles/hiing_github_action_noti_2.mobileprovision

      - name: Create Github Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: "${{ env.VERSION_NAME }}(${{ env.VERSION_CODE }})"
          release_name: "${{ env.VERSION_NAME }}(${{ env.VERSION_CODE }})"
          generate_release_notes: true
          files: |
            build/ios/ipa/*.ipa

  # Release job, upload the ipa to Firebase App Distribution
  # Container action is only supported on Linux
  release:
    name: Release ipa to Firebase
    needs: [ build ]
    runs-on: ubuntu-latest
    steps:

      # Retrieve ipa file from GitHub artifacts
      - uses: actions/checkout@v4
      - name: Get release-ipa from artifacts
        uses: actions/download-artifact@v4
        with:
          name: debug-ipa

      # Upload ipa file to Firebase app distribution.
      - name: Upload artifact to Firebase App Distribution
        uses: wzieba/Firebase-Distribution-Github-Action@v1
        with:
          appId: ${{secrets.FIREBASE_APP_ID_IOS_DEV}}
          serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}
          groups: ${{ vars.APP_DISTRIBUTION_GROUPS }}
          file: hiing.ipa

  notify:
    name: Slack Notification
    needs: [ build, release ]
    if: always()
    runs-on: ubuntu-latest
    steps:
      - name: Send Slack Notification
        run: |
          BUILD_STATUS="${{ needs.build.result }}"
          RELEASE_STATUS="${{ needs.release.result }}"
          VERSION="${{ needs.build.outputs.version_name }}(${{ needs.build.outputs.version_code }})"

          # 전체 상태 확인 (하나라도 실패하면 failure)
          if [[ "$BUILD_STATUS" == "success" ]] && [[ "$RELEASE_STATUS" == "success" ]]; then
            FINAL_STATUS="SUCCESS"
          else
            FINAL_STATUS="FAILURE"
          fi

          if [[ "$FINAL_STATUS" == "SUCCESS" ]] ; then
            EMOJI="🎉"
          else
            EMOJI="😵‍💫"
          fi

          curl -X POST https://slack.com/api/chat.postMessage \
            -H "Authorization: ${{ secrets.SLACK_TOKEN}}" \
            -H "Content-Type: application/json" \
            -d '{
              "channel": "${{ vars.SLACK_CHANNEL_ID }}",
              "text": "[IOS distribution] IOS 배포 '"${FINAL_STATUS}"''"${EMOJI}"'\n버전 👉 '"${VERSION}"'"
            }'

안드로이드, ios 합친 workflow

name: Android, IOS Build and Deploy to Firebase App Distribution

on:
  workflow_dispatch:
  push:
    branches:
      - develop_test

permissions:
  contents: write

jobs:
  build:
    strategy:
      matrix:
        platform: [android, ios]
        include:
          - platform: android
            runs-on: ubuntu-latest
            flutter_path: /opt/hostedtoolcache/flutter
          - platform: ios
            runs-on: macos-latest
            flutter_path: /Users/runner/hostedtoolcache/flutter
      fail-fast: false

    runs-on: ${{ matrix.runs-on }}
    outputs:
      version_name: ${{ env.VERSION_NAME }}
      version_code: ${{ env.VERSION_CODE }}
      android_build_status: ${{ matrix.platform == 'android' && job.status || '' }}
      ios_build_status: ${{ matrix.platform == 'ios' && job.status || '' }}

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Cache Flutter dependencies
        uses: actions/cache@v3
        with:
          path: ${{ matrix.flutter_path }}
          key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.lock') }}
          restore-keys: |
            ${{ runner.os }}-flutter-

      - name: Extract Version
        run: |
          VERSION_NAME=$(grep 'version:' pubspec.yaml | sed -e 's/version: //' -e 's/+.*//')
          VERSION_CODE=$(grep 'version:' pubspec.yaml | sed -e 's/version: //' -e 's/.*+//')
          echo "VERSION_NAME=$VERSION_NAME" >> $GITHUB_ENV
          echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV

      - name: Setup Android Environment
        if: matrix.platform == 'android'
        run: |
          # Cleanup Disk Space
          sudo rm -rf /usr/share/dotnet
          sudo rm -rf /opt/ghc
          sudo rm -rf /usr/local/share/boost
          sudo apt-get clean
          
          # Generate required files
          echo '${{ secrets.KEY_PROPERTIES }}' | base64 --d >> ./android/key.properties
          echo '${{ secrets.LOCAL_PROPERTIES }}' | base64 --d >> ./android/local.properties
          echo '${{ secrets.GOOGLE_SERVICE_JSON }}' | base64 --d > ./android/app/google-services.json
          echo '${{ secrets.JKS }}' | base64 --d > ./android/app/hiing-keystore.jks

      - name: Setup JDK 17 for Android
        if: matrix.platform == 'android'
        uses: actions/setup-java@v3
        with:
          distribution: 'corretto'
          java-version: 17

      - name: Setup iOS Environment
        if: matrix.platform == 'ios'
        env:
          BUILD_CERTIFICATE_BASE64: ${{ secrets.APPSTORE_CERT_BASE64 }}
          P12_PASSWORD: ${{ secrets.APPSTORE_CERT_PASSWORD }}
          BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.MOBILEPROVISION_BASE64 }}
          BUILD_PROVISION_NOTI_PROFILE_BASE64: ${{ secrets.NOTI_MOBILEPROVISION_BASE64 }}
          KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
        run: |
          # 변수 생성 
          CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
          PP_PATH=$RUNNER_TEMP/hiing_github_action_2.mobileprovision
          PP_NOTI_PATH=$RUNNER_TEMP/hiing_github_action_noti_2.mobileprovision
          KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
          
          #secrets으로 부터 인증서와 프로비저닝 프로파일 가져오기
          echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH
          echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode --output $PP_PATH
          echo -n "$BUILD_PROVISION_NOTI_PROFILE_BASE64" | base64 --decode --output $PP_NOTI_PATH
          
          # 키체인 초기화 - 임시 키체인 생성
          security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
          security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
          security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
          
          # import certificate to keychain
          security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
          security list-keychain -d user -s $KEYCHAIN_PATH
          
          # provisioning profile 적용
          mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
          cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
          cp $PP_NOTI_PATH ~/Library/MobileDevice/Provisioning\ Profiles
          
          # 디버깅
          echo "Listing provisioning profiles:"
          ls -l "$HOME/Library/MobileDevice/Provisioning Profiles/"

      - name: Setup Flutter
        uses: subosito/flutter-action@v1
        with:
          channel: 'stable'

      - name: Setup Flutter JDK Directory
        if: matrix.platform == 'android'
        run: |
          flutter config --jdk-dir /opt/hostedtoolcache/Java_Corretto_jdk/17.0.13-11.1/x64

      - name: Configure Git
        run: |
          git config --global url."https://${{ vars.USER_NAME }}:${{ secrets.TOKEN_GITHUB }}@github.com/".insteadOf "https://github.com/"

      - name: Install Dependencies
        run: flutter pub get

      - name: Generate Config
        run: |
          echo '${{ secrets.CONFIG }}' | base64 --d >> ./lib/common/config.dart

      - name: Build Android
        if: matrix.platform == 'android'
        run: flutter build apk --release --flavor dev

      - name: Build iOS
        if: matrix.platform == 'ios'
        run: flutter build ipa --export-options-plist=ios/Runner/ExportOptions.plist --flavor dev

      - name: Upload Build Artifacts
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.platform }}-artifacts
          path: |
            ${{ matrix.platform == 'android' && 'build/app/outputs/flutter-apk/app-dev-release.apk' || 'build/ios/ipa/*.ipa' }}
          if-no-files-found: error

      - name: Create Github Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: "${{ env.VERSION_NAME }}(${{ env.VERSION_CODE }})"
          release_name: "${{ env.VERSION_NAME }}(${{ env.VERSION_CODE }})"
          generate_release_notes: true
          files: |
            ${{ matrix.platform == 'android' && 'build/app/outputs/flutter-apk/app-dev-release.apk' || 'build/ios/ipa/*.ipa' }}

      - name: Clean up iOS keychain
        if: matrix.platform == 'ios' && always()
        run: |
          security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
          rm ~/Library/MobileDevice/Provisioning\ Profiles/hiing_github_action_2.mobileprovision
          rm ~/Library/MobileDevice/Provisioning\ Profiles/hiing_github_action_noti_2.mobileprovision

  deploy:
    needs: build
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        platform: [android, ios]
        include:
          - platform: android
            file_path: app-dev-release.apk
          - platform: ios
            file_path: hiing.ipa
    outputs:
      android_deploy_status: ${{ matrix.platform == 'android' && job.status || '' }}
      ios_deploy_status: ${{ matrix.platform == 'ios' && job.status || '' }}

    steps:
      - name: Check Build Status
        id: check
        if: |
          (matrix.platform == 'android' && needs.build.outputs.android_build_status == 'success') ||
          (matrix.platform == 'ios' && needs.build.outputs.ios_build_status == 'success')
        run: echo "proceed=true" >> $GITHUB_OUTPUT

      - name: Download Artifacts
        if: steps.check.outputs.proceed == 'true'
        uses: actions/download-artifact@v4
        with:
          name: ${{ matrix.platform }}-artifacts

      - name: Upload to Firebase App Distribution
        if: steps.check.outputs.proceed == 'true'
        uses: wzieba/Firebase-Distribution-Github-Action@v1
        with:
          appId: ${{ matrix.platform == 'android' && secrets.FIREBASE_APP_ID_ANDROID_DEV || secrets.FIREBASE_APP_ID_IOS_DEV }}
          serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}
          groups: ${{ vars.APP_DISTRIBUTION_GROUPS }}
          file: ${{ matrix.file_path }}

  notify:
    needs: [build, deploy]
    if: always()
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        platform: [android, ios]
    steps:
      - name: Send ${{ matrix.platform }} Notification
        run: |
          VERSION="${{ needs.build.outputs.version_name }}(${{ needs.build.outputs.version_code }})"
          BUILD_STATUS="${{ matrix.platform == 'android' && needs.build.outputs.android_build_status || needs.build.outputs.ios_build_status }}"
          DEPLOY_STATUS="${{ matrix.platform == 'android' && needs.deploy.outputs.android_deploy_status || needs.deploy.outputs.ios_deploy_status }}"
          
          if [[ "$BUILD_STATUS" == "success" ]] && [[ "$DEPLOY_STATUS" == "success" ]]; then
            FINAL_STATUS="SUCCESS 🎉"
          else
            FINAL_STATUS="FAILURE 😵‍💫"
          fi
  
          PLATFORM_NAME="${{ matrix.platform == 'ios' && 'IOS' || '안드로이드' }}"
          
          curl -X POST https://slack.com/api/chat.postMessage \
            -H "Authorization: ${{ secrets.SLACK_TOKEN }}" \
            -H "Content-Type: application/json" \
            -d '{
              "channel": "${{ vars.SLACK_CHANNEL_ID }}",
              "text": "[App Distribution] '"${PLATFORM_NAME}"' 배포 '"${FINAL_STATUS}"'\n버전 👉 '"${VERSION}"'"
            }'
  1. matrix를 이용해 안드로이드는 리눅스, ios는 mac os를 이용하도록 했습니다.
  2. fail-fast: false 을 이용해 하나의 job에서 한 matrix가 실패해도 다른 matrix는 여전히 실행되도록 합니다.
  3. matrix내에서는 secrets나 vars를 참조할 수 없기 때문에 아래와 같은 방식으로 matrix를 이용합니다.
appId: ${{ matrix.platform == 'android' && secrets.FIREBASE_APP_ID_ANDROID_DEV || secrets.FIREBASE_APP_ID_IOS_DEV }}

👇이런식으로는 쓸 수 없음

사실 위의 코드는 잘 작동하는지 아직 확인을 못해봤습니다 ㅠㅠ
이유는 깃헙액션이 제공하는 기본 무료 리밋을 다 썼기 때문입니다 ㅠㅠ
한달에 2천 minutes를 제공하는데, 제가 삽질을 너무 많이해버려서 다 써버렸습니다 ㅠㅠ
그리고 리눅스는 실제 1분에 1분이 차감되는데, mac os는 실제 1분에 10분이 차감되다고 합니다 ㅠㅠ
ios 배포에 삽질을 매우 많이 했기 때문에 무료 제공되는 시간을 다 써버리고말았습니다 ㅠ
그래서 12월에 다시 돌려보고 문제가 있으면 포스팅을 고치도록 하겠습니다.

② 회고 (restropective)

③ 개선을 위한 방법
깃헙에서 제공하는 runner말고 로컬이나 클라우드를 runner로 지정할 수도 있던데
그걸 하다가 삽질을 또해서 ios 키체인을 다 날려버리고 인증서를 다 다시 설정했다 ㅠㅠ
self host runner를 설정하려면 또 엄청난 삽질을 해봐야할것 같은데
일이 다시 바빠지기도했고, 테스트 할때 말고 실제로는 2천분을 다 쓸일이 없을 것 같기 때문에
일단 다음달에 다시 츄라이 해보기로하고 self host runner 설정하는건 나~중에 기회가 될때 해보기로 함

profile
되고싶다

1개의 댓글

comment-user-thumbnail
2024년 12월 2일

문제가없엇다고합니다~

답글 달기