Skip to content

release: develop 변경을 배포 브랜치에 반영한다 - #98

Merged
Roy-wonji merged 126 commits into
releasefrom
develop
Sep 23, 2026
Merged

Roy-wonji merged 126 commits into
releasefrom
develop

Conversation

@Roy-wonji

Copy link
Copy Markdown
Collaborator

변경 범위

  • develop의 release 대비 변경 전체를 Squash 머지합니다.
  • 앱 테스트 런타임 충돌 수정 및 앱 직접 IssueReporting 연결 제거를 포함합니다.
  • CI 배포 Slack 알림과 runner 컨텍스트 오류 수정을 포함합니다.

검증

  • 로컬 DDDAttendanceTests 8개 통과(기존 실패 7개 포함).
  • 워크플로 구조 테스트 8개 통과.
  • Slack 상태 경로의 환경변수 전달 검증 통과.
  • 전체 CI 및 Prod archive 성공은 아직 확인하지 않았습니다.

배포 영향

release 머지로 App Store 배포 및 심사 제출 워크플로가 트리거됩니다.

Roy and others added 30 commits June 20, 2026 20:28
- release lane에서 version 옵션 미지정 시 Extension+String.swift의
  appVersion에서 마케팅 버전 자동 추출
- 불필요한 version 분기 제거로 lane 로직 단순화
- en-US/ko 릴리스 노트를 v1.0.8(MVP 팀 투표 기능)로 갱신
- 회원가입(POST /users) 성공 후 토큰 재발급은 best-effort로 변경
  (login 실패해도 에러로 막지 않고 로그만 남김 — 가입 누락 방지)
- VoteFeedbackView: 마지막 문항 선택 시 ScrollViewReader로 해당
  문항이 시야에 보이도록 자동 스크롤
…ist clean — CasePathsMacrosSupport 스캐너 실패 해결
…modules 스캐너 레이스 해결 + DerivedData 삭제 제거
…osSupport) Clang 스캐너 레이스 근본 해결 (xcargs 미전파 보완)
…age config 미생성으로 매크로 archive 정상화
Roy-wonji and others added 25 commits September 7, 2026 12:49
- App Store에서 이전 빌드번호 조회
- max(이전번호+1, 날짜형) 으로 설정
- 같은 시간에 여러 번 빌드해도 서로 다른 번호 생성
- 형식: YYMMDDHHMM으로 원래대로 복구
- App Store에서 이전 빌드번호 조회하여 항상 증가 보장
- max(이전번호+1, 날짜형) 으로 설정
- export_options에 stripSymbols: false 추가 (symbol 제거 방지)
- xcargs에 STRIP_SWIFT_SYMBOLS=NO 추가 (Swift symbol 보존)
- EMBEDDED_CONTENT_CONTAINS_SWIFT=YES 추가 (embedded framework 설정)

App Store의 새로운 code signature 검증 정책 대응
테스트 워크플로에서 시뮬레이터 앱을 공유하니 업로드가 계속 거부됐다. appBuildVersion 리터럴이 저장소에 고정돼 있어 CI 테스트 빌드의 CFBundleVersion 이 매번 같았기 때문이다. fastlane 은 배포 시 그 리터럴을 러너 워크스페이스에서만 갱신하고 커밋해 되돌리지 않아, 사람이 직접 올리기 전까지 테스트 빌드는 같은 번호를 쓴다.

실제 실패: An app build with the same binary ID '286E9169...' and build version '2609071448' already exists. 그런데 continue-on-error 로 덮여 있어 잡은 초록불이었고, 배지 없는 빈 프리뷰가 쌓이는 것을 알아채지 못했다.

배포 잡의 IPA 는 fastlane 이 빌드번호를 올려 만든 것이라 중복이 없고 별도 빌드도 필요 없다. 경로를 직접 주면 --configuration / --platforms 는 무시된다. continue-on-error 도 제거해 업로드 실패가 드러나게 했다.
Swift 언어 모드는 6.0으로 유지하면서 앱과 모듈의 explicit module 설정을 소스 구성에 고정한다.

Constraint: Swift 6.4 컴파일러와 Tuist 생성 환경에서 동일한 모듈 추적 설정을 사용한다
Rejected: 구형 modulewrap 및 add_ast_path 플래그 직접 전달 | Swift 6.4의 precise module tracking과 충돌한다
Confidence: high
Scope-risk: narrow
Directive: SWIFT_VERSION 6.0과 컴파일러 릴리스 버전을 혼동하지 않는다
Tested: Tuist 생성, Stage 시뮬레이터 전체 빌드, Node 회귀 테스트 22개
Not-tested: 실제 기기 설치 및 실행
release 브랜치 배포에서 현재 앱 버전과 한영 문구 풀을 사용해 App Store 노트를 자동 생성한다.

Constraint: 바이너리 업로드와 후속 심사 제출은 같은 버전에 같은 문구를 사용한다
Rejected: 실행마다 완전 무작위 선택 | 재시도 시 메타데이터가 달라질 수 있다
Confidence: high
Scope-risk: moderate
Directive: release 브랜치 조건과 ko 및 en-US 메타데이터를 함께 유지한다
Tested: Node 회귀 테스트 22개, Ruby 문법, workflow YAML 파싱, 생성 metadata 일치, diff check
Not-tested: 실제 App Store 업로드, 로컬 Ruby 및 Bundler 충돌로 인한 Fastlane 전체 로딩
리다이렉트된 호환 패키지 대신 자기참조가 없는 마지막 버전을 명시적으로 고정하고 회귀 테스트로 보호한다.

Constraint: Tuist 4.206이 xctest-dynamic-overlay 호환 타깃을 자기 자신으로 해석함
Rejected: 전역 패키지 캐시 삭제 | self-hosted runner 상태에 의존해 재발을 막지 못함
Confidence: high
Scope-risk: narrow
Directive: Tuist 또는 의존 패키지가 리다이렉트 identity를 안전하게 처리할 때 버전 고정을 재검토할 것
Tested: node --test Scripts/package-linkage.test.js; tuist install; cache warm graph generation; simulator external cache build
Not-tested: device external cache build는 10분 비용 제한으로 중단됨
Constraint: IssueReporter existential에서 deprecated runtimeWarning 정적 멤버를 추론할 수 없음
Rejected: .runtimeWarning 유지 | IssueReporting 1.11에서 컴파일 오류가 발생함
Confidence: high
Scope-risk: narrow
Directive: 필터링되지 않은 이슈는 _DefaultReporter.default로 전달할 것
Tested: DDDAttendance-Workspace simulator build succeeded; git diff --cached --check
Not-tested: 런타임 경고 UI 수동 확인
install과 build 경로에서 Xcode Compilation Cache를 설정하고 외부 바이너리 캐시를 로컬 전용으로 준비한 뒤 프로젝트를 생성한다.

Constraint: CI에서는 로컬 캐시 준비를 건너뛰고 --no-binary-cache 선택을 보존해야 함
Rejected: 컴파일된 make 실행 파일 유지 | TuistTool.swift 변경이 즉시 반영되지 않아 실행 동작이 오래될 수 있음
Confidence: high
Scope-risk: moderate
Directive: make는 TuistTool.swift를 실행하는 얇은 래퍼로 유지하고 캐시 준비 순서의 회귀 테스트를 함께 갱신할 것
Tested: python3 Scripts/tuist-cache-commands.test.py (10 passed); swiftc -typecheck TuistTool.swift; git diff --cached --check
Not-tested: 실제 Tuist 계정으로 원격 캐시 다운로드 및 업로드
진단 수집을 생략하되 결과 번들은 유지한다.

Constraint: 기존 크래시 이후 진단 수집이 600초 동안 대기했다.
Tested: CI 구조 및 패키지 링크 스크립트 테스트 9개 통과, git diff --check 통과
Not-tested: 원격 CI 재실행 미검증. 로컬 앱 테스트의 ProfileCoordinator CasePathable 크래시는 해결하지 않음.
Scope-risk: narrow
Constraint: 사용자가 IssueReporting 관련 테스트 제거를 요청했다.
Tested: 남은 패키지 링크 및 CI 구조 테스트 9개 통과
Not-tested: 앱 런타임 크래시는 별도 미해결 상태다.
Scope-risk: narrow
시작 메시지에 최신 상태를 갱신하고 단계 이력은 스레드에 남긴다.
최종 결과는 채널 메시지로 전송하며 로컬 deploy-bot 서버에 의존하지 않는다.

Constraint: Slack 토큰 누락이나 전송 실패가 배포를 중단하면 안 된다.
Directive: Slack 토큰은 GitHub 시크릿으로만 제공하고 로그에 출력하지 않는다.
Tested: Ruby 문법 검사와 git diff --check 통과. 앞선 알림·CI·릴리스 노트 검증 15개 통과.
Not-tested: 실제 GitHub Actions 실행과 Slack 전송은 미검증. 전용 알림 테스트 파일은 사용자 요청으로 제외했다.
Scope-risk: narrow
Stage에서는 CasePaths와 SwiftNavigation을 동적 소비자 사이에서 공유한다.
배포 빌드는 기존 정적 링크를 유지하고 매크로 지원 모듈은 정적으로 둔다.

Constraint: Tuist 매크로 실행 파일은 동적 지원 모듈을 사용할 수 없다
Tested: Tuist install 및 generate 성공; DDDAttendanceTests 8개와 구조 검증 9개 통과
Not-tested: 전체 CI shard 및 Prod archive
Scope-risk: moderate
앱의 IssueReporting 직접 연결과 사용자 정의 필터를 제거한다.
실제 앱 Store에는 ContinuousClock을 주입하여 호스트 실행 중 테스트용
UnimplementedClock이 XCTest를 호출하지 않도록 한다.

Constraint: isTesting 분기와 테스트 타깃 구조를 변경하지 않는다
Directive: TCA의 전이 IssueReporting 의존성은 유지한다
Tested: 실패했던 Splash 및 로그아웃 7개를 포함한 앱 테스트 8개 통과; 구조 검증 9개 통과
Not-tested: 전체 CI shard 및 Prod archive
Scope-risk: narrow
Slack 상태 파일 경로를 실행 단계에서 RUNNER_TEMP로 설정하고
GITHUB_ENV로 후속 단계에 전달한다.

Constraint: job-level env에서는 runner 컨텍스트를 사용할 수 없다
Tested: 워크플로 구조 테스트 8개 통과; YAML 파싱 및 환경변수 전달 검증
Not-tested: 수정 후 GitHub Actions 배포 실행
Scope-risk: narrow
@github-actions
github-actions Bot requested a review from honghoker September 23, 2026 03:12
@Roy-wonji
Roy-wonji merged commit 6f3d65d into release Sep 23, 2026
6 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-23T03:19:12.612871Z 54760a3 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 54760a39ae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


func sendResponse<R: DDDDataRequest>(_ request: R) async throws(DDDNetworkError) -> DDDHTTPResponse {
let dataRequest = try makeDataRequest(request)
let response = await dataRequest.serializingData(emptyResponseCodes: Self.emptyResponseCodes).response

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate raw responses so authentication retries can run

When an access token is rejected with 401 without being preemptively identified as expired—for example, after server-side revocation—this raw serializer does not call validate(), so Alamofire treats the HTTP exchange as successful and never invokes AuthenticationInterceptor.retry. Consequently, every sendResponse caller, including vote writes, attendance edits, QR validation, logout, and withdrawal, receives the 401 instead of refreshing and replaying the request; preserve the final raw response while still passing failed statuses through the interceptor.

Useful? React with 👍 / 👎.

fi

ruby fastlane/ci_slack.rb uploaded
bundle exec fastlane ios submit_for_review version:"$VERSION" > fastlane-submit.log 2>&1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Propagate review-submission failures

On release pushes, this workflow relies on the command's exit status to decide whether to announce submission and fail the deployment, but the submit_for_review lane catches every exception at fastlane/Fastfile:430-439 and returns normally. Any App Store review-submission failure therefore produces exit code 0, sends the submitted Slack update, and leaves the release job green even though the build was never submitted; rethrow the exception or otherwise return a nonzero status.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants