Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .reviewbot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ review:
- ".gitignore"
- "AGENTS.md"
- "README.md"
- "CHANGELOG.md"
- "VERSION.txt"
- "GeneratingDocumentationSite"
- "Sources/**/*.docc/**/*.md"

Expand Down Expand Up @@ -83,6 +85,8 @@ review:
- "AGENTS.md"
- ".gitignore"
- "README.md"
- "CHANGELOG.md"
- "VERSION.txt"
- "GeneratingDocumentationSite"
- "Package.swift"
- ".github/workflows/**/*.yml"
Expand Down
39 changes: 39 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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 기반으로 전환했습니다.
99 changes: 93 additions & 6 deletions GeneratingDocumentationSite
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,99 @@ 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)"

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

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
}

start_command() {
perl -MPOSIX=setsid -e 'setsid() or die "setsid: $!"; exec @ARGV or die "exec: $!"' -- "$@" &
}

run_with_timeout() {
timeout_seconds="$1"
shift

if [ "$timeout_seconds" -le 0 ]; then
"$@"
return $?
fi

start_command "$@"
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
terminate_command TERM "$command_pid"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Major] Problem: terminate_command TERM 이후 sleep 2terminate_command KILL를 호출하지만, 이는 run_with_timeout 내부에서 kill -TERM을 실행한 후 바로 kill -KILL를 시도하는 방식과 동일합니다. 그러나 run_with_timeoutcommand_pid를 직접 종료하는 것이 아니라, kill -TERM을 실행한 후 wait를 통해 종료를 기다리며, sleep 2kill -KILL를 실행합니다. 이는 kill -KILLcommand_pid의 자식 프로세스를 포함하지 않으며, swift package dump-symbol-graph가 내부적으로 띄운 하위 프로세스가 남아 있을 수 있음을 의미합니다. Why it matters: 하위 프로세스가 남아 있으면 CI 환경이나 로컬 머신에서 리소스 경합, 메모리 누수, 빌드 실패 등의 문제가 발생할 수 있으며, 이는 지속적인 빌드 실패나 시스템 불안정을 초래할 수 있습니다. Suggested fix: run_with_timeout 내부에서 command_pid를 포함한 프로세스 그룹 전체를 종료하도록 kill -TERMkill -KILL-$command_pgid로 실행해야 하며, set -m이 활성화된 상태에서 command_pgid를 정확히 추출하는 것이 중요합니다. 현재 terminate_commandcommand_pgidps -o pgid= -p로 추출하고 있으나, set -m이 활성화된 상태에서 command_pid의 프로세스 그룹 ID를 정확히 얻을 수 있도록 보장해야 합니다. Confidence: High

Confidence score: 0.95

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

검토 후 추가 수정했습니다. c5b3211에서 job control 기반 실행을 제거하고, perl -MPOSIX=setsid로 감시 대상 명령을 별도 session/process group에서 실행하도록 변경했습니다. terminate_commandps -o pgid= -p "$command_pid"로 얻은 PGID에 대해 TERM/KILL을 보내므로 하위 프로세스 정리 대상이 명확해졌습니다. DUMP_SYMBOL_GRAPH_TIMEOUT_SECONDS=1로 timeout 124 반환 및 관련 SwiftPM 프로세스 미잔존도 확인했습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

이 지적은 현재 코드에는 맞지 않는 것으로 보입니다. start_commandsetsid() 후 명령을 실행하고, terminate_commandps -o pgid=로 얻은 프로세스 그룹에 kill -TERM "-$command_pgid"kill -KILL "-$command_pgid"를 보내므로 직접 자식만 종료한다는 전제는 현재 구현과 다릅니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

이 지적은 terminate_command의 동작 흐름을 오해한 것으로 보입니다. 현재 스크립트는 start_command 실행 시 setsid()를 사용해 독립된 세션을 구성하며, ps 명령으로 추출한 command_pgid를 이용해 그룹 전체(-$command_pgid)에 TERM 및 KILL 시그널을 정상 전달하고 있습니다. 따라서 자식/하위 프로세스가 유실되지 않고 안전하게 종료되므로 추가 조치 없이 유지해도 괜찮습니다.

sleep 2
terminate_command KILL "$command_pid"
wait "$command_pid" 2>/dev/null || true
return 124
fi

sleep 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.

[Minor] sleep 1 명령을 반복 호출하는 루프 기반의 시간 측정 방식은 프로세스 스케줄링 오버헤드로 인해 실제 설정된 timeout 시간보다 다소 늦게 감지가 이루어질 수 있습니다. 엄밀한 정밀도가 요구되는 작업은 아니나, 실제 대기 시간과 약간의 오차가 발생할 수 있음을 인지할 필요가 있습니다.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

검토했습니다. 지적 자체는 맞지만 이 스크립트의 timeout은 strict real-time 보장이 아니라 무한 대기 방지 목적이라 sleep 1 루프의 소폭 지연은 수용 가능한 수준으로 판단했습니다. 대신 timeout 값 검증과 process group 종료를 추가해 실제 운영 리스크가 있는 부분을 수정했습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[Minor] Problem: while kill -0 "$command_pid" 2>/dev/null; do 루프 내에서 sleep 1을 반복 호출하는 방식은 프로세스 스케줄링 오버헤드로 인해 실제 설정된 타임아웃 시간보다 다소 늦게 종료가 감지될 수 있습니다. Why it matters: 이는 타임아웃 정밀도에 약간의 오차를 초래하며, 특히 빌드 시간이 중요한 CI 환경에서 지연된 종료가 누적될 수 있습니다. Suggested fix: timeout 명령어를 사용하거나, sleep 대신 usleep 또는 nanosleep을 사용해 더 정밀한 지연을 구현하는 것이 가능합니다. 그러나 현재 스크립트는 macOS 기반 환경에서 timeout 명령어를 사용할 수 없으므로, usleep를 사용하는 것이 현실적인 대안입니다. Confidence: Medium

Confidence score: 0.85

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

검토했습니다. timeout 정밀도 지적은 사실이지만 이 스크립트의 목적은 초 단위 hard real-time 제어가 아니라 DocC 생성이 무한 대기하지 않도록 막는 것입니다. macOS 기본 환경에 없는 timeout/gtimeout 의존성을 추가하지 않는 쪽이 더 낫다고 판단해 유지했습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

동의합니다. 작성자분께서 남겨주신 것처럼 해당 타임아웃 처리는 실시간 수준의 정밀한 스케줄링을 위함이 아니라 무한 루프나 블로킹 현상을 방지하는 목적이 크기 때문에, 단순한 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 {} \;

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

Expand All @@ -42,10 +126,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;
Expand All @@ -54,6 +141,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"
1 change: 1 addition & 0 deletions VERSION.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.9.1
Loading