|
1 | 1 | name: build |
2 | 2 |
|
3 | | -# Тестов в проекте нет, поэтому проверка ровно одна и честно названа: собирается |
4 | | -# ли то, что лежит в main. Половина поломок в таком приложении — это сломанный |
5 | | -# скрипт сборки бандла, а не код, поэтому гоняется весь путь до .app, а не |
6 | | -# только swift build. |
7 | 3 | on: |
8 | 4 | push: |
9 | 5 | branches: [main] |
10 | | - paths-ignore: ['**.md', 'docs/**'] |
| 6 | + paths-ignore: |
| 7 | + - "**.md" |
| 8 | + - "docs/**" |
11 | 9 | pull_request: |
12 | 10 | branches: [main] |
13 | 11 | workflow_dispatch: |
14 | 12 |
|
| 13 | +permissions: |
| 14 | + contents: read |
| 15 | + |
| 16 | +concurrency: |
| 17 | + group: build-${{ github.workflow }}-${{ github.ref }} |
| 18 | + cancel-in-progress: true |
| 19 | + |
15 | 20 | jobs: |
16 | | - build: |
17 | | - # macOS 15 — минимум приложения: Translation.framework младше не бывает. |
| 21 | + test-and-build: |
| 22 | + name: Test and build app |
18 | 23 | runs-on: macos-15 |
| 24 | + timeout-minutes: 20 |
| 25 | + |
19 | 26 | steps: |
20 | | - - uses: actions/checkout@v5 |
| 27 | + - name: Check out repository |
| 28 | + uses: actions/checkout@v5 |
21 | 29 |
|
22 | | - - name: Версия Swift |
| 30 | + - name: Show Swift version |
23 | 31 | run: swift --version |
24 | 32 |
|
25 | | - - name: Сборка приложения |
| 33 | + - name: Run unit tests |
| 34 | + run: swift test |
| 35 | + |
| 36 | + - name: Build release app bundle |
26 | 37 | run: ./Scripts/bundle.sh release |
27 | 38 |
|
28 | | - - name: Проверить, что в бандле лежит то, что нужно |
| 39 | + - name: Validate app bundle |
| 40 | + shell: bash |
29 | 41 | run: | |
30 | | - APP=build/VoidBar.app |
| 42 | + set -euo pipefail |
| 43 | + APP="build/VoidBar.app" |
31 | 44 | VERSION="$(sed -n 's/^VERSION=//p' Scripts/version)" |
| 45 | +
|
32 | 46 | test -x "$APP/Contents/MacOS/VoidBar" |
33 | | - # Локализации кладет тот же скрипт, и молча потерять их проще всего: |
34 | | - # приложение с пропавшей таблицей запускается и выглядит целым. |
| 47 | + test -f "$APP/Contents/Resources/AppIcon.icns" |
35 | 48 | test -f "$APP/Contents/Resources/en.lproj/Localizable.strings" |
36 | 49 | test -f "$APP/Contents/Resources/uk.lproj/Localizable.strings" |
| 50 | +
|
37 | 51 | INSIDE="$(/usr/libexec/PlistBuddy -c 'Print CFBundleShortVersionString' "$APP/Contents/Info.plist")" |
38 | | - test "$INSIDE" = "$VERSION" || { echo "версия в бандле $INSIDE, в Scripts/version $VERSION"; exit 1; } |
| 52 | + test "$INSIDE" = "$VERSION" || { |
| 53 | + echo "Bundle version $INSIDE does not match Scripts/version $VERSION" |
| 54 | + exit 1 |
| 55 | + } |
39 | 56 |
|
40 | | - - name: Ключи перевода совпадают с кодом |
41 | | - # Строка, для которой нет ключа, не ломает сборку — она просто |
42 | | - # показывается идентификатором тому, у кого этот язык. |
| 57 | + - name: Validate localization keys |
43 | 58 | run: | |
44 | 59 | python3 - <<'PY' |
45 | | - import re, io, pathlib, sys |
| 60 | + import io |
| 61 | + import pathlib |
| 62 | + import re |
| 63 | + import sys |
| 64 | +
|
46 | 65 | code = set() |
47 | | - for p in pathlib.Path("Sources").rglob("*.swift"): |
48 | | - code |= set(re.findall(r'localized\("([^"]+)"', io.open(p, encoding="utf-8").read())) |
49 | | - bad = False |
| 66 | + for path in pathlib.Path("Sources").rglob("*.swift"): |
| 67 | + source = io.open(path, encoding="utf-8").read() |
| 68 | + code |= set(re.findall(r'localized\("([^"]+)"', source)) |
| 69 | +
|
| 70 | + invalid = False |
50 | 71 | for table in pathlib.Path("Resources").glob("*.lproj/Localizable.strings"): |
51 | | - text = io.open(table, encoding="utf-8").read() |
52 | | - keys = {k.replace("\\n", "\n") for k in re.findall(r'^"((?:[^"\\]|\\.)*)"\s*=', text, re.M)} |
| 72 | + source = io.open(table, encoding="utf-8").read() |
| 73 | + keys = { |
| 74 | + key.replace("\\n", "\n") |
| 75 | + for key in re.findall(r'^"((?:[^"\\]|\\.)*)"\s*=', source, re.M) |
| 76 | + } |
53 | 77 | missing = code - keys |
54 | 78 | if missing: |
55 | | - bad = True |
56 | | - print(f"{table}: нет ключей: {sorted(missing)}") |
57 | | - sys.exit(1 if bad else 0) |
| 79 | + invalid = True |
| 80 | + print(f"{table}: missing keys: {sorted(missing)}") |
| 81 | +
|
| 82 | + sys.exit(1 if invalid else 0) |
58 | 83 | PY |
0 commit comments