Files
Gnuboard7/tests/scenarios/installer-composer-skip-dev-vendor.yaml
T
HeuJung ffab451b4a fix(core,installer): dev vendor 설치본의 코어 업데이트 중단 수정 — stale 패키지 매니페스트 3계층
Laravel PackageManifest 는 bootstrap/cache/packages.php 가 있으면 stale 여부를 검사하지
않고 그대로 읽어 등재된 provider 를 new 한다. 코어 업데이트는 Step 6/8 에서 vendor 를
--no-dev 로 교체하지만 그 파일은 Step 11 까지 이전 설치본의 것이 남으므로, 옵션 없는
`composer install` 로 깔린 사이트에서는 Step 10 spawn 자식이 새 vendor 에 없는 provider 를
찾다 부팅 단계에서 죽는다. 부팅 전이라 앱 로그에 흔적이 없고 부모에게는 자식의 비정상
종료로만 보여, 운영자에게는 「Class ... not found」 와 수동 재개 안내만 남는다.
(sir.kr 커뮤니티 제보, 7.0.9 → 7.0.10)

3계층으로 막는다.

 1. 부모 — spawn 직전 PackageManifestCacheHelper::clear
 2. 자식 — bootstrap/app.php 가 G7_UPDATE_IN_PROGRESS 를 보고 스스로 정리한다.
 이미 배포된 7.0.9·7.0.10 부모는 고칠 수 없으므로 그 아래에서 도는 신버전
 자식의 유일한 방어다. App\ 클래스를 참조하지 않고 실패는 무시한다.
 3. 범위 — CoreVersionChecker 의 env APP_VERSION 우선을 CoreUpdateContext 트리 안으로
 축소한다. 업데이트 전에 뜬 artisan serve·큐 워커가 옛 값을 물고 확장을
 incompatible_core 로 끄던 경로를 닫는다(관리자 템플릿이 대상이면 복구 UI
 자체에 도달할 수 없다).

업데이트 트리 판정은 App\Support\CoreUpdateContext 가 단독 소유하고
CoreServiceProvider::isCoreUpdateInProgress 는 위임으로 남는다. bootstrap/app.php 의
복제본은 부팅 전이라 불가피한 예외이며, 두 조건의 동형성을 테스트가 단언한다.

실측 중 드러난 결함 2건을 함께 고쳤다.

 - ConfigCacheHelper::withPreservedContainer 가 파사드 애플리케이션을 되돌리지 않아
 Step 11 이 `Target class [command.tinker] does not exist` 로 실패·롤백했다.
 - updateVersionInEnv 가 프로세스 환경을 갱신하지 않아 config 캐시에 이전 버전이 구워졌다
 (Laravel env 저장소가 불변이라 재부팅으로도 덮이지 않는다).

인스톨러는 재사용 vendor 의 개발용 패키지를 installed.json 으로 감지해 설치 환경 확인
카드·설치 로그로 알리되 설치를 차단하지 않고( 결정 D1), 재사용 경로에서도 컴파일 캐시를
정리한다. 실행되는 명령만이 아니라 실패 시 안내하는 수동 명령까지 --no-dev 로 맞췄다.
코어 업데이트 완료·핸드오프·단독 재개 사후 단계에서 queue:restart 신호를 보낸다(D3).

코어 7.0.10 → 7.0.11.
2026-09-08 09:46:57 +09:00

72 lines
5.0 KiB
YAML

# audit:allow test-scenario-coverage [cross_product] reason: task-runner.php 는 진입과 함께 SSE 를 실행하는 파일이라 include 불가 — 조합은 순수 함수 단위 effect 로 검증하고, 분기 순서는 소스 문자열로 잠근다.
feature: 인스톨러 vendor 재사용 경로의 개발용(require-dev) 패키지 감지·안내와 컴파일 캐시 정리
description: |
인스톨러는 `vendor/autoload.php` 와 `composer.lock` 이 둘 다 있으면 composer 단계를 통째로
건너뛰고 그 vendor 를 그대로 쓴다. 그런데 그 vendor 가 `composer install`(옵션 없음)의
결과면 require-dev 와 그 전이 의존성까지 들어 있고, 그 목록이 `bootstrap/cache/packages.php`
에 provider 로 등재된다. 종전에는 이 사실을 아무 데도 표시하지 않았다.
그 상태로 운영하면 이후 코어 업데이트가 vendor 를 `--no-dev` 로 교체할 때 매니페스트에만
남은 provider 를 찾다 spawn 자식이 부팅 단계에서 죽고, 업데이트가 「Class ... not found」
와 수동 재개 안내로 멈춘다 (sir.kr 제보, 7.0.9 → 7.0.10).
같은 재사용 분기가 컴파일 캐시도 정리하지 않고 return 했다. `key_generate` 가 이미 완료된
재개 설치에서는 인스톨러 어느 지점에서도 정리가 일어나지 않아, 이전 환경의 캐시가 그대로
남았다.
처치 (PO 결정 D1 — 설치를 차단하지 않는다):
1. 설치 환경 확인(Step 2) 에 「Composer 의존성 구성」 카드를 **선택 항목**으로 추가.
경고 상태여도 `isAllRequiredPassed()` 는 이를 보지 않고 `다음` 버튼도 활성이다.
2. 설치 로그(Step 5) 에 감지 사실과 정리 명령 안내를 남긴다.
3. 재사용 경로에서도 `clearLaravelCompiledCache()` 를 호출한다.
판정은 코어와 공유하는 `App\Support\ComposerInstallInfo` 가 단독으로 소유한다 — 인스톨러와
코어 업데이트가 같은 vendor 를 두고 서로 다른 답을 내놓으면 화면과 로그가 어긋난다.
"판정 불가"(installed.json 부재·JSON 오류·Composer 1 형식)는 "개발용 아님" 과 구분한다.
axes:
vendor_state: [absent, present_no_dev, present_dev, present_without_lock]
composer_available: [yes, no]
install_resume_state: [fresh, resumed_key_generate_done]
surface: [env_check_card, install_log]
exclusions:
- { vendor_state: absent, surface: env_check_card, reason: "vendor 가 없으면 카드를 그리지 않는다 — 마법사가 운영용 구성으로 자동 설치하므로 안내할 것이 없다" }
- { vendor_state: absent, install_resume_state: resumed_key_generate_done, reason: "vendor 가 없는 상태로 key_generate 까지 도달하는 흐름이 없다 — composer 단계가 선행한다" }
- { vendor_state: present_without_lock, surface: env_check_card, reason: "lock 부재는 재사용 분기에 들어가지 않고 vendor 삭제 후 재설치로 간다 (기존 경로, 이번 변경 대상 아님)" }
- { vendor_state: present_without_lock, install_resume_state: resumed_key_generate_done, reason: "동일 — 재사용 분기 밖" }
- { vendor_state: present_no_dev, composer_available: no, reason: "이미 준비된 vendor 를 재사용하므로 composer 실행 가능 여부가 분기를 바꾸지 않는다" }
- { vendor_state: present_dev, composer_available: no, reason: "동일 — 재사용 분기는 composer 를 실행하지 않는다" }
effects:
# 판정 SSoT (App\Support\ComposerInstallInfo)
- core_detects_dev_vendor_from_installed_json
- core_reports_no_dev_packages_for_no_dev_vendor
- core_returns_unknown_when_installed_json_missing
# 인스톨러 shim (순수 PHP — Laravel 오토로드 없이 로드)
- installer_detects_dev_vendor_from_installed_json
- installer_treats_missing_installed_json_as_unknown
- installer_shim_matches_core_composer_install_info
# 재사용 분기 — 경고하되 설치는 계속하고, 캐시를 정리한다
- installer_warns_and_keeps_dev_vendor
- installer_clears_compiled_cache_on_reuse_path
# 설치 환경 확인 카드 — 선택 항목이며 게이트로 승격되지 않는다
- installer_env_check_shows_dev_vendor_card_without_gating
# 다국어 — ko/en 쌍과 치환 자리
- installer_lang_keys_exist_in_both_locales
# 실행되는 명령만이 아니라 실패 시 안내하는 명령까지 --no-dev 를 갖는다
- installer_composer_commands_all_carry_no_dev
test_files:
- tests/Feature/Installer/DevVendorDetectionTest.php
- tests/Unit/Support/ComposerInstallInfoTest.php
- tests/Unit/Installer/RequirementsVendorDevPackagesTest.php
manual_verification: |
브라우저 실측 매트릭스는 구현 계획서 §7.3 (T1 환경 확인 카드 / T3 설치 로그 / T10(a) 재개 설치
캐시 정리 / T10(b) vendor 없는 신규 설치) 를 따른다. 인스톨러는 SSE 스트림으로 진행하므로
로그 문구·카드 배지는 실제 브라우저에서만 최종 확인된다.