From 4adb42acadbedd4333d712b29b1678cfe3608dd0 Mon Sep 17 00:00:00 2001 From: swift-man Date: Tue, 7 Jul 2026 02:23:07 +0900 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20=EB=A6=B4=EB=A6=AC=EC=A6=88=20?= =?UTF-8?q?=EB=A9=94=ED=83=80=EB=8D=B0=EC=9D=B4=ED=84=B0=20=ED=9B=84?= =?UTF-8?q?=EC=86=8D=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VERSION.txt를 추가해 현재 릴리즈 버전을 파일로 추적하도록 했습니다. CHANGELOG.md를 생성해 0.9.0과 0.9.1 릴리즈 변경 사항을 정리했습니다. GeneratingDocumentationSite가 VERSION.txt를 DocC bundle version의 기본값으로 읽도록 하고, symbol graph 생성 단계에 timeout과 기존 symbol graph 정리를 추가해 오래된 산출물을 사용하지 않도록 보강했습니다. .reviewbot.yml에 CHANGELOG.md와 VERSION.txt를 포함해 릴리즈 메타데이터도 코드리뷰 대상에서 빠지지 않도록 했습니다. --- .reviewbot.yml | 4 ++++ CHANGELOG.md | 39 +++++++++++++++++++++++++++++++ GeneratingDocumentationSite | 46 +++++++++++++++++++++++++++++++++++-- VERSION.txt | 1 + 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 VERSION.txt diff --git a/.reviewbot.yml b/.reviewbot.yml index 525aefbc..581ca7c3 100644 --- a/.reviewbot.yml +++ b/.reviewbot.yml @@ -11,6 +11,8 @@ review: - ".gitignore" - "AGENTS.md" - "README.md" + - "CHANGELOG.md" + - "VERSION.txt" - "GeneratingDocumentationSite" - "Sources/**/*.docc/**/*.md" @@ -83,6 +85,8 @@ review: - "AGENTS.md" - ".gitignore" - "README.md" + - "CHANGELOG.md" + - "VERSION.txt" - "GeneratingDocumentationSite" - "Package.swift" - ".github/workflows/**/*.yml" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..8c99b584 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,39 @@ +# Changelog + +이 문서는 LaunchingView의 릴리즈 변경 사항을 기록합니다. + +## Unreleased + +- 아직 릴리즈되지 않은 변경 사항은 여기에 기록합니다. + +## 0.9.1 - 2026-05-17 + +### Added + +- 강제 업데이트와 종료형 공지를 앱 종료 대신 차단 화면으로 표시하는 `BlockingLaunchView` 흐름을 추가했습니다. +- fetch 취소, fetch error dismiss 후 재조회, optional update action, notice dismiss URL open 흐름을 Swift Testing 테스트로 보강했습니다. +- README에 LaunchingView의 목적, 동작 방식, 주요 컴포넌트, 설정 포인트를 한글로 보강했습니다. + +### Changed + +- `LaunchingService` 의존성을 `0.9.2`로 업데이트했습니다. +- The Composable Architecture를 `1.25.5`로 업데이트했습니다. +- Swift tools를 `6.1`로 올렸습니다. +- 최소 지원 플랫폼을 iOS 16.0, macOS 13.0으로 상향했습니다. +- `ViewStore` 기반 관찰을 제거하고 `@ObservableState`, `@Presents`, `Perception` 기반 Store 관찰로 전환했습니다. +- DocC 배포 워크플로가 `swift-man/docs` 저장소의 `main` 브랜치에 `LaunchingView/` 경로로 배포하도록 정리했습니다. + +### Fixed + +- fetch 실패 alert를 표시하기 전에 optional update alert와 notice alert 상태를 정리해 여러 alert binding이 동시에 활성화될 수 있는 문제를 방지했습니다. +- fetch 작업 취소 시 사용자에게 fetch error alert가 표시되지 않도록 취소 경로를 별도로 처리했습니다. +- SwiftUI view 재생성 중 Store 상태가 유실되지 않도록 Store 소유권을 안정화했습니다. + +## 0.9.0 - 2026-05-17 + +### Changed + +- Launching reducer의 부수 효과를 TCA dependency 기반으로 분리했습니다. +- URL open 동작을 `@Dependency(\.openURL)`로 주입하도록 정리했습니다. +- `LaunchingService` 테스트 의존성을 안전하게 격리했습니다. +- XCTest 기반 테스트를 Swift Testing 기반으로 전환했습니다. diff --git a/GeneratingDocumentationSite b/GeneratingDocumentationSite index 8a3f0107..ac993bfc 100755 --- a/GeneratingDocumentationSite +++ b/GeneratingDocumentationSite @@ -9,15 +9,57 @@ DOCC_ARCHIVE_PATH="${DOCC_ARCHIVE_PATH:-./$TARGET_NAME.doccarchive}" DOCS_OUTPUT_PATH="${DOCS_OUTPUT_PATH:-./docs}" HOSTING_BASE_PATH="${HOSTING_BASE_PATH:-$TARGET_NAME}" BUNDLE_IDENTIFIER="${BUNDLE_IDENTIFIER:-com.swift-man.$TARGET_NAME}" -BUNDLE_VERSION="${BUNDLE_VERSION:-0.9.1}" +VERSION_FILE="${VERSION_FILE:-VERSION.txt}" +if [ -z "${BUNDLE_VERSION+x}" ] && [ -f "$VERSION_FILE" ]; then + BUNDLE_VERSION="$(tr -d '[:space:]' < "$VERSION_FILE")" +else + BUNDLE_VERSION="${BUNDLE_VERSION:-0.9.1}" +fi +if [ -z "$BUNDLE_VERSION" ]; then + echo "error: bundle version is empty" >&2 + exit 1 +fi MINIMUM_ACCESS_LEVEL="${MINIMUM_ACCESS_LEVEL:-public}" +DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS="${DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS:-300}" DOCC="$(xcrun --find docc)" +run_with_timeout() { + timeout_seconds="$1" + shift + + if [ "$timeout_seconds" -le 0 ]; then + "$@" + return $? + fi + + "$@" & + command_pid=$! + elapsed_seconds=0 + + while kill -0 "$command_pid" 2>/dev/null; do + if [ "$elapsed_seconds" -ge "$timeout_seconds" ]; then + echo "error: command timed out after ${timeout_seconds}s: $*" >&2 + kill "$command_pid" 2>/dev/null || true + wait "$command_pid" 2>/dev/null || true + return 124 + fi + + sleep 1 + elapsed_seconds=$((elapsed_seconds + 1)) + done + + wait "$command_pid" +} + rm -rf "$SYMBOL_GRAPH_PATH" "$DOCS_OUTPUT_PATH" "$DOCC_ARCHIVE_PATH" mkdir -p "$SYMBOL_GRAPH_PATH" swift build -if ! swift package dump-symbol-graph --minimum-access-level "$MINIMUM_ACCESS_LEVEL"; then +find "$PACKAGE_BUILD_PATH" -path "*/symbolgraph/$TARGET_NAME*.symbols.json" \ + -exec rm -f {} \; + +if ! run_with_timeout "$DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS" \ + swift package dump-symbol-graph --minimum-access-level "$MINIMUM_ACCESS_LEVEL"; then echo "warning: dump-symbol-graph exited non-zero; continuing if $TARGET_NAME symbols were emitted" >&2 fi diff --git a/VERSION.txt b/VERSION.txt new file mode 100644 index 00000000..f374f666 --- /dev/null +++ b/VERSION.txt @@ -0,0 +1 @@ +0.9.1 From 40fc95ca1c1a80a45d024e322edd765e16bd46fd Mon Sep 17 00:00:00 2001 From: swift-man Date: Tue, 7 Jul 2026 13:59:59 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20DocC=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8=20timeout=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=20=EB=B3=B4=EA=B0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit reviewbot이 지적한 timeout 시 하위 프로세스 잔존 가능성을 줄이기 위해 background job을 별도 process group으로 실행하고, timeout 발생 시 TERM 후 KILL 순서로 group 종료를 시도하도록 보강했습니다. DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS가 숫자가 아닐 때 명확한 오류를 출력하도록 검증을 추가했습니다. Package.swift와 DocC catalog 존재 여부를 확인해 스크립트가 패키지 루트가 아닌 경로에서 출력물을 삭제하거나 생성하지 않도록 방지했습니다. HOSTING_BASE_PATH=/ 입력 시 정적 리소스 경로가 //로 변하지 않도록 정규화하고, JS trailing whitespace 정리는 행 단위 perl 처리로 변경했습니다. --- GeneratingDocumentationSite | 49 +++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/GeneratingDocumentationSite b/GeneratingDocumentationSite index ac993bfc..de3dbb74 100755 --- a/GeneratingDocumentationSite +++ b/GeneratingDocumentationSite @@ -23,6 +23,40 @@ MINIMUM_ACCESS_LEVEL="${MINIMUM_ACCESS_LEVEL:-public}" DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS="${DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS:-300}" DOCC="$(xcrun --find docc)" +case "$DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS" in + ''|*[!0-9]*) + echo "error: DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS must be a non-negative integer" >&2 + exit 1 + ;; +esac + +if [ ! -f Package.swift ]; then + echo "error: Package.swift not found; run this script from the package root" >&2 + exit 1 +fi + +if [ ! -d "$DOCC_CATALOG_PATH" ]; then + echo "error: DocC catalog not found at $DOCC_CATALOG_PATH" >&2 + exit 1 +fi + +if (set -m) 2>/dev/null; then + set -m +fi + +terminate_command() { + signal="$1" + command_pid="$2" + command_pgid="$(ps -o pgid= -p "$command_pid" 2>/dev/null | tr -d ' ')" + shell_pgid="$(ps -o pgid= -p $$ 2>/dev/null | tr -d ' ')" + + if [ -n "$command_pgid" ] && [ "$command_pgid" != "$shell_pgid" ]; then + kill -"$signal" "-$command_pgid" 2>/dev/null || kill -"$signal" "$command_pid" 2>/dev/null || true + else + kill -"$signal" "$command_pid" 2>/dev/null || true + fi +} + run_with_timeout() { timeout_seconds="$1" shift @@ -39,7 +73,9 @@ run_with_timeout() { while kill -0 "$command_pid" 2>/dev/null; do if [ "$elapsed_seconds" -ge "$timeout_seconds" ]; then echo "error: command timed out after ${timeout_seconds}s: $*" >&2 - kill "$command_pid" 2>/dev/null || true + terminate_command TERM "$command_pid" + sleep 2 + terminate_command KILL "$command_pid" wait "$command_pid" 2>/dev/null || true return 124 fi @@ -84,10 +120,13 @@ fi --output-path "$DOCS_OUTPUT_PATH" \ --hosting-base-path "$HOSTING_BASE_PATH" -HOSTING_BASE_PATH="/${HOSTING_BASE_PATH#/}" -export HOSTING_BASE_PATH +STATIC_HOSTING_BASE_PATH="/${HOSTING_BASE_PATH#/}" +if [ "$STATIC_HOSTING_BASE_PATH" = "/" ]; then + STATIC_HOSTING_BASE_PATH="" +fi +export STATIC_HOSTING_BASE_PATH perl -0pi -e ' - my $base = $ENV{"HOSTING_BASE_PATH"}; + my $base = $ENV{"STATIC_HOSTING_BASE_PATH"}; s#href="/favicon\.ico"#href="$base/favicon.ico"#g; s#href="/favicon\.svg"#href="$base/favicon.svg"#g; s#var baseUrl = "/"#var baseUrl = "$base/"#g; @@ -96,6 +135,6 @@ perl -0pi -e ' ' "$DOCS_OUTPUT_PATH/index.html" find "$DOCS_OUTPUT_PATH" -type f -name '*.js' \ - -exec perl -0pi -e 's/[ \t]+$//mg' {} + + -exec perl -pi -e 's/[ \t]+$//g' {} + rm -rf "$DOCC_ARCHIVE_PATH" "$SYMBOL_GRAPH_PATH" From c5b32114b88643821fccdb690347cf6118e4852b Mon Sep 17 00:00:00 2001 From: swift-man Date: Tue, 7 Jul 2026 14:07:30 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20DocC=20symbol=20graph=20timeout=20?= =?UTF-8?q?=EC=8B=A4=ED=8C=A8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dump-symbol-graph timeout은 불완전한 symbol graph를 만들 수 있는 상태이므로 경고로 넘기지 않고 즉시 실패하도록 변경했습니다. timeout 감시 대상 명령은 Perl setsid를 통해 별도 session/process group에서 실행해 하위 프로세스 종료 대상이 명확하도록 정리했습니다. DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS=1 검증에서 exit 124 반환과 SwiftPM 관련 프로세스 미잔존을 확인했고, 정상 ./GeneratingDocumentationSite 실행도 통과했습니다. --- GeneratingDocumentationSite | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/GeneratingDocumentationSite b/GeneratingDocumentationSite index de3dbb74..8da8919c 100755 --- a/GeneratingDocumentationSite +++ b/GeneratingDocumentationSite @@ -40,10 +40,6 @@ if [ ! -d "$DOCC_CATALOG_PATH" ]; then exit 1 fi -if (set -m) 2>/dev/null; then - set -m -fi - terminate_command() { signal="$1" command_pid="$2" @@ -57,6 +53,10 @@ terminate_command() { fi } +start_command() { + perl -MPOSIX=setsid -e 'setsid() or die "setsid: $!"; exec @ARGV or die "exec: $!"' -- "$@" & +} + run_with_timeout() { timeout_seconds="$1" shift @@ -66,7 +66,7 @@ run_with_timeout() { return $? fi - "$@" & + start_command "$@" command_pid=$! elapsed_seconds=0 @@ -94,8 +94,14 @@ swift build find "$PACKAGE_BUILD_PATH" -path "*/symbolgraph/$TARGET_NAME*.symbols.json" \ -exec rm -f {} \; -if ! run_with_timeout "$DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS" \ - swift package dump-symbol-graph --minimum-access-level "$MINIMUM_ACCESS_LEVEL"; then +dump_symbol_graph_status=0 +run_with_timeout "$DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS" \ + swift package dump-symbol-graph --minimum-access-level "$MINIMUM_ACCESS_LEVEL" || dump_symbol_graph_status=$? + +if [ "$dump_symbol_graph_status" -eq 124 ]; then + echo "error: dump-symbol-graph timed out; aborting DocC generation" >&2 + exit 124 +elif [ "$dump_symbol_graph_status" -ne 0 ]; then echo "warning: dump-symbol-graph exited non-zero; continuing if $TARGET_NAME symbols were emitted" >&2 fi