diff --git a/.github/scripts/launch-smoke.sh b/.github/scripts/launch-smoke.sh index 94f9bf8..38b624a 100644 --- a/.github/scripts/launch-smoke.sh +++ b/.github/scripts/launch-smoke.sh @@ -26,5 +26,28 @@ for attempt in 1 2 3; do sleep 5 done +# `adb install` returns when the install session commits, which is before the +# package manager has the app indexed. Starting the activity in that window +# fails with "Error type 3 / Activity class does not exist" -- the app is on +# disk, the launcher just cannot see it yet. That failure looks identical to a +# genuinely broken build, and it is what the job's reputation as a flake was +# partly built on (#247, #252, #262). +# +# Wait for the package manager to answer instead of sleeping a fixed amount: +# a slow CI emulator can take several seconds, a fast one none at all. +echo "Waiting for the package manager to see the app" +for _ in $(seq 1 30); do + if adb shell pm path com.markleaf.notes 2>/dev/null | tr -d '\r' | grep -q '^package:'; then + echo "Package indexed." + break + fi + sleep 2 +done + +if ! adb shell pm path com.markleaf.notes 2>/dev/null | tr -d '\r' | grep -q '^package:'; then + echo "Package manager never listed com.markleaf.notes after a successful install" + exit 1 +fi + adb shell am start -W -n com.markleaf.notes/.MainActivity adb shell pidof com.markleaf.notes diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index 21a3c6b..2d80588 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml @@ -74,6 +74,10 @@ jobs: app/build/outputs/roborazzi/ app/build/reports/roborazzi/ if-no-files-found: ignore + # Only uploaded when the visual check fails, and only useful while + # someone is looking at that failure. A week outlives any run worth + # re-opening; the goldens themselves live in the repository (#247). + retention-days: 7 - name: Run release lint (hard gate) run: ./gradlew :app:lintRelease @@ -85,6 +89,9 @@ jobs: name: lint-report-release path: app/build/reports/lint-results-release.html if-no-files-found: ignore + # Same reasoning as the Roborazzi diffs: a failure-only report that is + # read while the failure is fresh, or not at all (#247). + retention-days: 7 - name: Build release APK with R8 (hard gate, unsigned ok) run: ./gradlew :app:assembleRelease @@ -245,6 +252,11 @@ jobs: name: roborazzi-goldens-linux path: app/src/test/snapshots/roborazzi/ if-no-files-found: error + # Longer than the failure-only artifacts: this one is downloaded and + # committed by hand, so it has to survive the gap between dispatching + # the run and getting round to the commit. Still not 90 days — once + # committed the goldens are in the repository (#247). + retention-days: 30 release: if: startsWith(github.ref, 'refs/tags/v') diff --git a/docs/assets/README.md b/docs/assets/README.md new file mode 100644 index 0000000..04dba72 --- /dev/null +++ b/docs/assets/README.md @@ -0,0 +1,52 @@ +# Public assets + +What each file here is for, and — for the ones recorded from a running build — +which version they show. Two things went unrecorded before this file existed: +why unreferenced files are kept, and how anyone would notice a clip has gone +stale (#258). + +## Demo clips + +| File | Surface | Recorded on | +|---|---|---| +| `markleaf-tablet-.gif` (6) | Landing story 01 + README hero, one per language | v2.30.0 | +| `markleaf-demo.gif` | Older single-language demo | v2.23.0 | + +`scripts/verify-landing-versions.ps1` asserts that each language surface points +at its **own** clip and that the file exists — a page referencing another +language's GIF renders fine and would otherwise ship silently. + +Nothing asserts that a clip still matches the current UI. That is a judgement +call, not a check: re-record when a change would make the clip misleading, and +update the version above when you do. A clip showing an older layout is only a +problem once the layout it shows is gone. + +## Screenshots + +`markleaf-editor-*.webp`, `markleaf-privacy-*.webp`, `markleaf-tags-*.webp` — +the landing page screenshots, in 720px and 1280px variants. The version they +show is carried in each page's `
`, which +`verify-landing-versions.ps1` requires to agree across the six languages. + +### `markleaf-preview-720.webp` / `markleaf-preview-1280.webp` — kept deliberately + +**Nothing in this repository references these two.** They are kept anyway, and +this is the record of that decision so a future cleanup does not have to guess. + +They were served from GitHub Pages under stable URLs +(`https://jeiel85.github.io/markleaf-android/assets/markleaf-preview-1280.webp`) +while they were in use, and those URLs may be linked from places outside this +repository — a store listing draft, a forum post, a bookmark. Deleting the +files breaks those links for no benefit: together they are ~93 KB and cost +nothing to keep. + +Remove them only if the Pages site itself moves or is retired, which breaks the +URLs regardless. + +## Store and brand + +| File | Use | +|---|---| +| `markleaf-feature-graphic-1024x500.png` | Play Console feature graphic | +| `markleaf-playstore-icon-512.png` | Play Console app icon | +| `logo.svg` | Landing header | diff --git a/scripts/verify-landing-versions.ps1 b/scripts/verify-landing-versions.ps1 index a352c2b..6bab429 100644 --- a/scripts/verify-landing-versions.ps1 +++ b/scripts/verify-landing-versions.ps1 @@ -149,6 +149,57 @@ foreach ($file in $readmeFiles) { } } +# ---- 언어별 데모 GIF: 각 페이지가 자기 언어 클립을 가리키는지 ---- +# +# README.ko.md 가 markleaf-tablet-en.gif 를 가리켜도 렌더링은 멀쩡하므로 조용히 +# 나간다 — 버전 표기에서 이 검사가 막아 주는 것과 같은 종류의 구멍이다 (#258). +# 언어 코드는 파일명 규칙에서 끌어온다: index.html/README.md 는 en, 나머지는 접미사. +$assetPairs = @( + @{ File = "docs/index.html"; Lang = "en" } + @{ File = "docs/index.ko.html"; Lang = "ko" } + @{ File = "docs/index.ja.html"; Lang = "ja" } + @{ File = "docs/index.de.html"; Lang = "de" } + @{ File = "docs/index.es.html"; Lang = "es" } + @{ File = "docs/index.fr.html"; Lang = "fr" } + @{ File = "README.md"; Lang = "en" } + @{ File = "README.ko.md"; Lang = "ko" } + @{ File = "README.ja.md"; Lang = "ja" } + @{ File = "README.de.md"; Lang = "de" } + @{ File = "README.es.md"; Lang = "es" } + @{ File = "README.fr.md"; Lang = "fr" } +) + +Write-Host "`n데모 GIF ($($assetPairs.Count)개 표면)" +foreach ($pair in $assetPairs) { + $path = Resolve-UnderRoot $pair.File + if (-not (Test-Path -LiteralPath $path)) { + Add-Failure (" FAIL {0,-20} 파일이 없습니다." -f $pair.File) + continue + } + $text = Get-Content -Raw -Encoding utf8 -LiteralPath $path + $expected = "markleaf-tablet-$($pair.Lang).gif" + + # 이 표면이 참조하는 태블릿 GIF 를 전부 모아, 자기 언어 것만 있는지 본다. + $referenced = @( + [regex]::Matches($text, 'markleaf-tablet-([a-z]{2})\.gif') | + ForEach-Object { $_.Value } | Sort-Object -Unique + ) + + if ($referenced.Count -eq 0) { + Add-Failure (" FAIL {0,-20} 태블릿 데모 GIF 참조가 없습니다 (기대 {1})." -f $pair.File, $expected) + } elseif ($referenced -contains $expected -and $referenced.Count -eq 1) { + # 에셋 자체가 있어야 참조가 의미를 갖는다. + $assetPath = Join-Path $docsPath "assets/$expected" + if (Test-Path -LiteralPath $assetPath) { + Write-Host (" OK {0,-20} {1}" -f $pair.File, $expected) -ForegroundColor Green + } else { + Add-Failure (" FAIL {0,-20} {1} 을 가리키는데 docs/assets 에 그 파일이 없습니다." -f $pair.File, $expected) + } + } else { + Add-Failure (" FAIL {0,-20} 기대 {1}, 실제 -> {2}" -f $pair.File, $expected, ($referenced -join ', ')) + } +} + # ---- 스크린샷(figcaption): 릴리스 버전과 별개, 언어 간 일치만 확인 ---- $screenshotUnique = @($screenshotVersions | Sort-Object -Unique) if ($screenshotUnique.Count -le 1) {