feat(make): add install-android-app target and default help listing

- add `help` target and make it the default goal (bare `make` lists targets)
- add `install-android-app`: build debug APK and install on the selected device
- device selection via SERIAL/$ANDROID_SERIAL; several devices list and stop
- document the target in android/README.md
This commit is contained in:
iu
2026-10-13 12:06:34 +03:00
parent 43f5520236
commit d9f6a163e5
6 changed files with 172 additions and 1 deletions
+41 -1
View File
@@ -1,8 +1,19 @@
.PHONY: build build-release frontend backend android run migrate reconcile reconcile-delete tidy test testdata clean .PHONY: help build build-release frontend backend android install-android-app run migrate reconcile reconcile-delete tidy test testdata clean
# Default goal: print the list of available targets.
.DEFAULT_GOAL := help
# Android SDK location. Override when the SDK lives elsewhere. # Android SDK location. Override when the SDK lives elsewhere.
ANDROID_SDK ?= $(HOME)/Android/sdk ANDROID_SDK ?= $(HOME)/Android/sdk
# adb from the Android SDK's platform-tools (matches the SDK we build against).
ADB ?= $(ANDROID_SDK)/platform-tools/adb
# Device serial for `install-android-app` (falls back to $ANDROID_SERIAL). When
# empty, the sole connected device is used; with several connected devices the
# target lists them and stops instead of guessing. Override with SERIAL=<serial>.
SERIAL ?= $(ANDROID_SERIAL)
# Release version stamped into the binary (-X main.version). Override with VERSION=... # Release version stamped into the binary (-X main.version). Override with VERSION=...
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev) VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
@@ -14,6 +25,13 @@ PHOTOS ?= 10
SEED ?= 0 SEED ?= 0
TIMEOUT ?= 30 TIMEOUT ?= 30
# Print the list of available targets.
help:
@echo "Usage: make <target>"
@echo
@echo "Available targets:"
@grep -hE '^[a-zA-Z0-9_-]+:' $(MAKEFILE_LIST) | cut -d: -f1 | sed 's/^/ /'
frontend: frontend:
cd frontend && npm ci && npm run build cd frontend && npm ci && npm run build
rm -rf backend/static/* rm -rf backend/static/*
@@ -32,6 +50,28 @@ build: frontend backend
android: android:
cd android && ANDROID_HOME=$(ANDROID_SDK) ./gradlew :app:assembleDebug cd android && ANDROID_HOME=$(ANDROID_SDK) ./gradlew :app:assembleDebug
# Install the debug Android client on a connected device. Builds the APK via the
# `android` target first; only devices in the `device` state are considered.
install-android-app: android
@devices="$$($(ADB) devices | awk 'NR>1 && $$2 == "device" {print $$1}')"; \
if [ -n "$(SERIAL)" ]; then \
target="$(SERIAL)"; \
else \
count=$$(printf '%s\n' "$$devices" | grep -c .); \
if [ "$$count" -eq 0 ]; then \
echo "install-android-app: no connected device (see '$(ADB) devices')" >&2; \
exit 1; \
elif [ "$$count" -gt 1 ]; then \
echo "install-android-app: several devices connected; set SERIAL=<serial>:" >&2; \
printf '%s\n' "$$devices" | sed 's/^/ /' >&2; \
exit 1; \
else \
target="$$devices"; \
fi; \
fi; \
echo "Installing app-debug.apk on $$target"; \
$(ADB) -s "$$target" install -r android/app/build/outputs/apk/debug/app-debug.apk
# Release build: full static, stripped and (if available) UPX-compressed binary # Release build: full static, stripped and (if available) UPX-compressed binary
# with the version embedded. Produces bin/galo and a copy at bin/galo-$(VERSION). # with the version embedded. Produces bin/galo and a copy at bin/galo-$(VERSION).
build-release: frontend build-release: frontend
+13
View File
@@ -29,8 +29,21 @@ From the repository root:
```sh ```sh
make android # runs :app:assembleDebug (ANDROID_SDK=... to override) make android # runs :app:assembleDebug (ANDROID_SDK=... to override)
make install-android-app # build and install the debug APK on a device
``` ```
`install-android-app` builds the debug APK and installs it onto the sole connected
device. To choose a device explicitly, pass its serial number:
```sh
make install-android-app SERIAL=emulator-5554
```
`SERIAL` also falls back to `$ANDROID_SERIAL`. When several devices are connected and
`SERIAL` is not set, the target prints the list of devices (only those in the `device`
state) and stops without installing. `ADB=...` overrides the `adb` binary (defaults to
`$(ANDROID_SDK)/platform-tools/adb`).
Debug output: `android/app/build/outputs/apk/debug/app-debug.apk`. Debug output: `android/app/build/outputs/apk/debug/app-debug.apk`.
## Signing (release) ## Signing (release)
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-10-13
@@ -0,0 +1,41 @@
# Proposal
## Why
Разработчику нужно ставить Android-клиент на подключённое устройство, но сегодня в
`Makefile` есть только `make android`, который собирает debug-APK и никуда его не
устанавливает. При этом голый `make` по умолчанию запускает цель `frontend`
(`cd frontend && npm ci && npm run build`), что неочевидно и тянет `npm ci`.
## What Changes
- Новая Make-цель `install-android-app`: собирает debug-APK клиента и устанавливает его
на устройство.
- Выбор устройства: явный серийный номер (`SERIAL`/`ANDROID_SERIAL`) либо автоматически,
если подключено ровно одно устройство.
- Если устройств несколько и серийный номер не задан — цель печатает список устройств и
**не** выполняет установку, завершаясь ненулевым кодом.
- **BREAKING** (изменение поведения по умолчанию): голый `make` теперь печатает список
доступных целей и больше не собирает фронтенд; сборка фронтенда остаётся за целями
`frontend` и `build`.
- Обновление `android/README.md`: документировать установку на устройство.
## Capabilities
### New Capabilities
- `dev-make-workflow`: Make-интерфейс разработчика — установка Android-клиента на
выбранное устройство и обзор доступных Make-целей.
### Modified Capabilities
<!-- Нет: спеки продукта (android-client и др.) не меняются, изменение — только dev-инструмент. -->
## Impact
- `Makefile`: новая цель `install-android-app`, новая цель `help`, смена `.DEFAULT_GOAL`
с `frontend` на `help`.
- `android/README.md`: раздел «Build» дополняется установкой на устройство.
- Код сервера и Android-приложения не затрагивается.
- Новых внешних зависимостей нет: используется уже требуемый Android SDK и `adb` из
`platform-tools`.
@@ -0,0 +1,55 @@
# Spec Delta
## Purpose
Make-интерфейс разработчика: установка Android-клиента на выбранное устройство и обзор
доступных целей сборки.
## ADDED Requirements
### Requirement: Установка Android-приложения через Make-цель
Проект SHALL предоставлять Make-цель `install-android-app`, которая собирает debug-APK
Android-клиента и устанавливает его на выбранное устройство. Повторный запуск SHALL
переустанавливать приложение без ручного удаления.
#### Scenario: Установка на устройство
- **WHEN** цель запущена и устройство выбрано
- **THEN** собирается debug-APK и устанавливается на это устройство
#### Scenario: Повторная установка
- **WHEN** приложение уже установлено и цель запущена снова
- **THEN** установка завершается успешно без ручного удаления приложения
### Requirement: Выбор устройства для установки
Цель установки SHALL брать устройство из явно заданного серийного номера, а при его
отсутствии — из единственного подключённого устройства. Если подключено несколько
устройств и серийный номер не задан, цель SHALL напечатать список устройств и SHALL не
выполнять установку.
#### Scenario: Серийный номер задан
- **WHEN** задан серийный номер устройства
- **THEN** приложение устанавливается именно на это устройство
#### Scenario: Единственное устройство
- **WHEN** серийный номер не задан и подключено ровно одно устройство
- **THEN** приложение устанавливается на него
#### Scenario: Несколько устройств без выбора
- **WHEN** серийный номер не задан и подключено несколько устройств
- **THEN** цель печатает список устройств, не выполняет установку и завершается ненулевым кодом
#### Scenario: Нет устройств
- **WHEN** не подключено ни одного устройства
- **THEN** цель сообщает об ошибке и завершается ненулевым кодом
### Requirement: Обзор доступных Make-целей
Голый `make` (без цели) SHALL печатать список доступных целей и SHALL не запускать
сборку. Любая цель, включая сборку фронтенда, SHALL оставаться доступной по явному имени.
#### Scenario: Голый make
- **WHEN** `make` запущен без цели
- **THEN** печатается список доступных целей, сборка не запускается
#### Scenario: Явная цель
- **WHEN** `make` запущен с именем цели, например `make frontend`
- **THEN** выполняется именно эта цель
@@ -0,0 +1,20 @@
# Tasks
## 1. Список Make-целей по умолчанию
- [x] 1.1 Добавить цель `help`, печатающую список доступных целей, и включить `help` в строку `.PHONY`; проверка — `make help` выводит все цели, перечисленные в `.PHONY`.
- [x] 1.2 Переключить `.DEFAULT_GOAL` с `frontend` на `help`; проверка — голый `make` печатает список целей и не выполняет ни одной рецептуры (в частности, не запускает `npm ci`).
- [x] 1.3 Подтвердить, что явные цели не изменились; проверка — `make -n frontend`, `make -n backend`, `make -n testdata` печатают те же команды, что и до правки.
## 2. Установка Android-приложения
- [x] 2.1 Задать переменную выбора устройства `SERIAL` и источник `adb` из `$(ANDROID_SDK)/platform-tools/adb`; проверка — `make -n install-android-app` подставляет путь к SDK-`adb`.
- [x] 2.2 Добавить цель `install-android-app`, которая собирает debug-APK (переиспользуя цель `android`, без дублирования gradle-вызова) и ставит его через `adb install -r` на `android/app/build/outputs/apk/debug/app-debug.apk`; проверка — при заданном `SERIAL` приложение устанавливается на указанное устройство.
- [x] 2.3 Реализовать разбор устройства до установки: задан `SERIAL` — ставим на него; ровно одно подключённое — ставим на него; несколько без `SERIAL` — печатаем список устройств, установку не выполняем и выходим с ненулевым кодом; ноль устройств — сообщаем об ошибке и выходим с ненулевым кодом; проверка — каждый сценарий воспроизводится и его исход совпадает со спекой.
- [x] 2.4 Учитывать только устройства в состоянии `device`; проверка — устройство `offline`/`unauthorized` не попадает в список выбора и не выбирается автоматически.
- [x] 2.5 Обновить `android/README.md`: документировать `make install-android-app`, переменную `SERIAL` и поведение при нескольких устройствах; проверка — документированные команды дословно совпадают с `Makefile`.
## Workflow follow-up
- Прогнать `openspec validate add-make-install-android --strict` после реализации.
- Архивация change после проверки.