Skip to content

GitHub Actions 기반 ThirdParty 의존성 자동 갱신 workflow를 구성한다 #821

Description

@opficdev

배경

외부 의존성의 package 선언과 product 링크는 Libraries/ThirdParty/Project.swift에 모여 있음. 같은 메이저 버전 안의 마이너·패치 갱신을 주기적으로 제안하되, 변경 이력과 실제 빌드 결과를 근거로 사용자가 병합 여부를 판단할 수 있는 흐름 필요.

선행 결정

  • GoogleSignIn-iOS의 현재 .revision("02616ac6…")은 정식 태그가 아닌 개발 커밋임
  • 해당 커밋을 포함하는 첫 정식 배포 버전인 .exact("9.2.0")으로 전환함
  • GoogleSignIn 9.2.0의 upstream release CI에서는 SPM build/test와 pod 검증이 성공했고, 샘플 앱의 로그인 UI 테스트만 실패했음
  • DevLog 반영 여부의 기준은 upstream UI 테스트 상태가 아니라 tuist generate --no-open과 DevLog 앱 build 성공으로 둠
  • .mise.toml의 Tuist는 갱신 대상에서 제외함

작업 범위

실행과 권한

  • 새 의존성 갱신 workflow를 추가함
  • 매주 월요일 00:00 KST에 실행함
    • schedule: "0 15 * * 0"
    • workflow_dispatch 지원
  • 기준·PR 대상 브랜치는 develop으로 고정함
  • concurrency로 실행을 직렬화함
  • workflow 권한은 contents: write, pull-requests: write으로 제한함
  • GITHUB_TOKEN으로 생성한 PR이 기존 pull_request CI를 다시 시작하지 않는 점을 전제로, 이 workflow 안에서 검증 build를 완료한 뒤에만 PR을 갱신함

갱신 대상과 판정

  • Libraries/ThirdParty/Project.swift에 직접 선언된 package만 대상으로 함
  • 전이 의존성, Tuist, .mise.toml, Workspace.swift, 생성된 workspace와 Package.resolved는 제외함
  • GoogleSignIn은 위 선행 결정에 따라 .exact("9.2.0")으로 정규화한 뒤, 이후 9.x 안의 마이너·패치만 후보로 다룸
  • 다른 versioned package도 현재 메이저 안의 정식 마이너·패치 태그만 후보로 다룸
  • pre-release 태그는 제외함
  • 후보별 release note와 변경 URL을 수집함

AI 기반 반영 여부 결정

  • Watcher@0.3.1openAiPredictionClient 구조를 참고해 OpenAI Responses API를 호출함
    • OPENAI_API_KEY
    • developer·user 입력 분리
    • text.format의 strict JSON Schema
    • output_text JSON 파싱
  • Watcher 기본 모델인 gpt-5.4-mini 대신 gpt-5.6-lunareasoning.effort: "medium"을 사용함
  • AI는 release note에서 확인한 근거와 URL을 함께 반환하며, package별 결론을 apply, manual_review, skip 중 하나로 제한함
  • apply 항목만 manifest에 반영하고 build 대상으로 사용함
  • release note를 찾지 못했거나 OpenAI API·응답 형식 처리에 실패한 항목은 manual_review로 기록하며, manifest에 반영하지 않음
  • AI 판단은 근거 있는 후보 선별에만 사용하며, 빌드와 사용자의 PR 병합 판단을 대체하지 않음

검증·브랜치·PR 정책

  • apply 변경 뒤 tuist generate --no-open과 기존 CI와 같은 DevLog 앱 build를 수행함
  • package resolve, Tuist 생성, build 실패 시 workflow를 실패 처리하고 branch push·PR 변경을 하지 않음
  • dry-run은 탐색·AI 판정·Tuist 생성·build까지만 수행하고, commit·push·PR 생성 또는 수정은 하지 않음
  • 열린 자동 갱신 PR이 있으면 chore/dependency-updates 브랜치를 이어서 사용함
    • 최신 develop을 로컬에서 병합한 뒤 증분 버전 갱신 커밋을 추가함
    • build 성공 뒤 Libraries/ThirdParty/Project.swift만 commit·push함
    • branch에 수동 코드 변경이 있거나 develop 병합 충돌이 나면 remote branch를 변경하지 않고 실패 처리함
  • 열린 PR의 본문은 사용자 작성 내용과 이전 실행 기록을 유지하고, 이번 실행 섹션만 추가함
  • release note/API 실패 항목은 해당 실행 섹션에 수동 확인 사유와 URL을 추가함
  • 모든 후보가 manual_review 또는 skip이면 새 PR은 만들지 않고 workflow summary에 남김

디버깅과 보안

  • 매 실행의 version 탐색 결과, manifest diff, Tuist 생성 로그, build 로그, AI 판정 상태를 artifact와 workflow summary에 남김
  • build 실패 시에만 .xcresult를 추가로 보관함
  • pr-body-section.md는 임시 파일로만 사용하며 Git push 또는 artifact 업로드 대상이 아님
  • API key, 인증 헤더, 비공개 설정 값, OpenAI 원문 오류 응답은 로그·artifact·PR 본문에 남기지 않음
  • 앱 실행, 설치, Simulator boot·조작은 수행하지 않음

수락 조건

  • 월요일 00:00 KST schedule과 workflow_dispatch가 동작함
  • develop 대상의 단일 chore/dependency-updates PR과 증분 커밋이 유지됨
  • GoogleSignIn-iOS.exact("9.2.0")으로 전환되고 이후 9.x 마이너·패치만 후보가 됨
  • 직접 선언된 package의 같은 메이저 버전 마이너·패치만 후보가 됨
  • AI가 release note 근거로 apply·manual_review·skip을 구분함
  • apply 항목만 tuist generate --no-open과 DevLog 앱 build를 통과한 뒤 PR에 반영됨
  • release note·OpenAI API 실패는 수동 확인 정보로 남고, 빌드 실패만 push·PR 변경을 막음
  • dry-run에서 GitHub 쓰기가 발생하지 않음
  • 비밀값과 PR 본문 임시 파일이 Git·artifact·로그에 남지 않음

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions